Consider the following code:
void f1(bool ok) {
if (ok) [[likely]] {
// ...
} else [[unlikely]] {
// ...
}
}
void f2(bool ok) {
if (ok) [[likely]] {
// ...
} else {
// ...
}
}
void f3(bool ok) {
if (ok) {
// ...
} else [[unlikely]] {
// ...
}
}
Are
f1
,f2
, andf3
equivalent from the view of compiler?
Is
[[likely]]
redundant if[[unlikely]]
exists in if-else branches in C++20?
Basically yes, it is redundant, except for one case that MSVC doesn't handle properly.
If you apply just one of the attributes to the true branch of an if
statement, all compilers work as expected and don't require an opposite attribute on the else
branch.
The C++ standard under [dcl.attr.likelihood] provides no clear usage guidance for this case, and neither do any of the compiler manuals.
if (b) [[likely]] { // Placement on the first statement in the branch. // The compiler will optimize to execute the code here. } else { }
An example where both [[unlikely]]
and [[likely]]
are used (in a non-contradictory or non-ignored way) doesn't exist in the documentation.
GCC seems to contain no documentation at all under Statement Attributes and Label Attributes, but one would expect that it works similarly to Clang.
MSVC documentation is also vague and just explains that the attributes are optimization hints, but doesn't say much about these usage edge cases.
If you flip [[likely]]
and [[unlikely]]
in your code, then it's possible to get some compiler divergence for f3
(https://godbolt.org/z/dffYv1E7r):
int t, f;
void f3(bool ok) {
if (ok) {
t = 0;
} else [[likely]] {
f = 0;
}
}
GCC and Clang are biased towards f = 0
and jump to t = 0
, but MSVC does the unexpected:
void f3(bool) PROC ; f3, COMDAT
test cl, cl
je SHORT $LN2@f3
mov DWORD PTR int t, 0 ; t
ret 0
$LN2@f3:
mov DWORD PTR int f, 0 ; f
ret 0
void f3(bool) ENDP ; f3
This output is biased towards t = 0
even though f = 0
is likely.
Perhaps the MSVC bug here is that [[likely]]
and [[unlikely]]
attributes on else
branches are ignored completely, and only the attributes after the condition of the if statement matter.
I've reported this at https://developercommunity.visualstudio.com/t/likely-and-unlikely-attributes-a/10845089
Note: the fact that GCC emits slightly worse code than Clang and MSVC in the example is a known GCC Bug 47253. The output is still equivalent in behavior to Clang.