C++20 introduced the attributes [[likely]]
and [[unlikely]]
to the language, which can be used to allow the compiler to optimize for the case where one execution path is either much more likely or much less likely than the other ones.
Given the cost of an incorrect branch prediction, this seems like a feature that's potentially extremely useful in performance-critical sections of code, but I don't know what it would actually cause the compiler to do.
Is there a simple piece of code for which adding [[likely]]
and [[unlikely]]
attributes changes the assembly output by the compiler? And perhaps more importantly, what do these changes do?
I created a simple example for my own understanding to see if there was any difference in the assembly, but it appears that this example is too simple to actually show any changes to the assembly:
void true_path();
void false_path();
void foo(int i) {
if(i) {
true_path();
} else {
false_path();
}
}
void bar(int i) {
if(i) [[likely]] {
true_path();
} else [[unlikely]] {
false_path();
}
}
2Eh
(Branch not taken (used only with Jcc instructions)) and3Eh
(—Branch taken (used only with Jcc instructions)) from Vol 2A, Chapter 2.1.1 of the current Intel manual. Intel's comment on these: "Some earlier microarchitectures used these as branch hints, but recent generations have not and they are reserved for future hint usage." – Cyanogencmov
. It's only overriding anything if the compiler was using profile-guided optimization based on actual runtime data. (And in that case IIRC gcc uses the PGO data, ignoring hints). – Marcelinelikely
tounlikely
. The funny thing is, if you duplicate that function, and one of them haslikely
, and the otherunlikely
, the assembly will be the same for both functions (the attribute of the first function will affect the second function, weird). It's like quantummechanics :) – Meagher__builtin_expect
)? Or are you saying that the latter are also not used to override PGO? Because that was my understanding, based also on the (admittedly, somewhat vague) GCC documentation. – Berthold[[likely]]
/[[unlikely]]
were added to ISO C++ to expose that existing compiler behaviour in a portable way. And yes, I'd guess that GCC probably ignores either way of writing it when PGO data is available. – Marceline[[likely]]
annotation is going to make virtually no difference (or it might actually make performance worse). – Berthold[[likely]]
to compile to an asm hint, like for Pentium 4 when Intel experimented with that for x86. And I think MIPS has some branch-likely instructions, and PowerPC has something. But on modern x86, and ARM/AArch64, all you can do at compile time is lay out branches so the fast path is the not-taken one. See Is it possible to tell the branch predictor how likely it is to follow the branch? – Marceline