C++ [[likely]] and [[unlikely]] aren’t always symmetric
I assumed annotating one branch with [[likely]] would make the compiler infer [[unlikely]] on the other. After all, in a plain if/else the other branch is the inverse.
if (ok) [[likely]] {
fast_path();
} else {
slow_path();
}
vs.
if (ok) [[likely]] {
fast_path();
} else [[unlikely]] {
slow_path();
}
Building with arm-none-eabi-gcc, the second version sometimes produced less code and a smaller stack frame than the first. Same optimization level, same sources.
- One hint tells the compiler one branch’s weight; it still has to pick a reasonable default for the other.
- Two hints pin both weights, so block layout, register allocation, and spill decisions can skew harder toward the hot path.
- The extra instructions I saw looked like the cold path getting treated as merely “less likely” instead of “cold,” so it stayed close enough to cost the fast path a few spills.
Haven’t fully chased down why yet. For now: if you care enough to annotate one side, annotate both.