David Park

C++ [[likely]] and [[unlikely]] aren’t always symmetric

· c++, compiler

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.