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?
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]] {
// ...
}
}
Share Improve this question edited 2 days ago xmllmx asked Feb 8 at 8:09 xmllmxxmllmx 42.4k32 gold badges180 silver badges351 bronze badges 4 |Are
f1
,f2
, andf3
equivalent from the view of compiler?
1 Answer
Reset to default 5Is
[[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.
Lack of documentation
The C++ standard under [dcl.attr.likelihood] provides no clear usage guidance for this case, and neither do any of the compiler manuals.
Clang has this example:
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.
Compiler output
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.
[[likely]]
or[[unlikely]]
will help it by changing its heuristics, but it is up to the compiler how to interpret them or modify its internal heuristics, it may just ignore them entirely, see C++20’s likely Attribute - Optimizations, Pessimizations, and unlikely Consequences - CppCon – Ahmed AEK Commented Feb 8 at 8:13[likely]
, some[unlikely]
, and some unannotated) possibly not. Practically, it will depend on quality of implementation of the compiler, and if/ how it responds to (or even ignores) such annotations. – Peter Commented 2 days ago