Can the effects of [[likely]] and [[unlikely]] be transitive/inferred?

Viewed 81

C++20 introduced the attributes [[likely]] and [[unlikely]] for signalling statements that may be either likely or unlikely executed to help with optimizations. Historically, such attributes were compiler-specific, and were hidden behind __likely and __unlikely macro function to help optimize branching statements; however C++20 takes this a step further by allowing them on any statements.

In theory, this should allow for [[likely]] and [[unlikely]] inference, based on context and visibility -- such as:

// Just an opaque function to call so we see it in the generated assembly
void something_expensive();

// Something we know to always be unlikely
[[gnu::always_inline]]
inline void unlikely_code_path() {
    [[unlikely]] something_expensive();
}

void test_unlikely(bool x) {
    if (x) /* [[unlikely]] inferred? */ { unlikely_code_path(); }
}

I use an inlined/visible function-call in this example since I can see this being useful for error-managing functions like assert, which are never meant to be tripped in practice and thus we don't want paths leading to these cases to be optimized for. However, I'm not seeing any compiler actually take advantage of this.

Live Example

Both GCC and Clang are generating identical assembly outputs, neither of which take advantage of the [[unlikely]] (or [[likely]]) knowledge:

test_unlikely(bool):
        test    dil, dil
        je      .L4
        jmp     something_expensive()
.L4:
        ret

My expectation is that test_unlikely would be aware of the [[unlikely]] branch and generate something similar to what would be generated if this were if (b) [[unlikely]] { ...}, which is:

test_unlikely(bool):
        test    dil, dil
        jne     .L6
        ret
.L6:
        jmp     something_expensive()

Is this a missed opportunity for compilers to label the "hot" and likely paths? Or is there something I am missing about the C++ language that may actually prevent such optimizations from being realistic using attributes alone in practice?

(Note: I know that attributes in C++ are effectively non-binding contracts, and thus the compiler does not need to honor them; but the compilers here clearly are honoring some cases which makes me think this is just a missed optimization)

0 Answers
Related