58

This question is about C++20's [[likely]]/[[unlikely]] feature, not compiler-defined macros.

This documents (cppreference) only gave an example on applying them to a switch-case statement. This switch-case example compiles perfectly with my compiler (g++-7.2) so I assume the compiler has implemented this feature, though it's not yet officially introduced in current C++ standards.

But when I use them like this: if (condition) [[likely]] { ... } else { ... }, I got a warning:

"warning: attributes at the beginning of statement are ignored [-Wattributes]".

So how should I use these attributes in an if-else statement?

5
  • 5
    @Mercer I know; but it's not what I'm asking.. Commented Aug 11, 2018 at 8:47
  • 3
    It could be just partially implemented. Start with checking the g++ documentation and see if it should be supported. Commented Aug 11, 2018 at 8:53
  • 1
    As molbdnillo said; since the c++20 standard isn't complete let alone published it's up to the compiler to integrate new features how it likes. Commented Aug 11, 2018 at 8:59
  • Do you have an example you can show us? Commented Sep 3, 2018 at 10:10
  • @Mercer Putting the mostly likely condition to the first statement is not equivalent to using [[likely]]. Sometimes the compiler will change if(...) A else B to if (not ...) B else A. And this will break the pipeline, then it would be slow.Here is an example: godbolt.org/z/WcPbPv Commented Dec 28, 2019 at 11:19

3 Answers 3

31

Based on example from Jacksonville’18 ISO C++ Report the syntax is correct, but it seems that it is not implemented yet:

if (a>b) [[likely]] {

See Likelihood attributes [dcl.attr.likelihood]:

void g(int);
int f(int n) {
  if (n > 5) [[unlikely]] { // n > 5 is considered to be arbitrarily unlikely
    g(0);
    return n * 2 + 1;
  }

  switch (n) {
  case 1:
    g(1);
    [[fallthrough]];

  [[likely]] case 2:        // n == 2 is considered to be arbitrarily more
    g(2);                   // likely than any other value of n
    break;
  }
  return 3;
}
Sign up to request clarification or add additional context in comments.

6 Comments

Ok.. so currently the compiler just partially implemented this attribute.
@Leedehai I would say that in general support for features from upcoming C++20 standard is purely experimental at this point.
I find it peculiar that the while loop example provided within that link has the likely token placed after the brace rather than before like it is in the rest of the examples.
@Mercer, the latest ISO draft just states that the attributes can be assigned to a label or statement so it appears that while (cond) [[likely]] { x(); y(); } and while (cond) { [[likely]] x(); y(); } are equally valid. I'm not sure if it makes much sense to only mark the first statement as a compound statement as likely but maybe the committee knows more than I - actually that seems likely, know that I think about it :-)
I just had a look at the examples in the provided draft and it omits an example for a while loop entirely. Time will tell.
|
10

As of today, cppreference states that, for example, likely (emphasis mine):

Applies to a statement to allow the compiler to optimize for the case where paths of execution including that statement are more likely than any alternative path of execution that does not include such a statement.

That suggests that the place to put the attribute is in the statement that is most likely, i.e.:

if (condition) { [[likely]] ... } else { ... }

This syntax is accepted, for example, by Visual Studio 2019 16.7.0 when compiling with /std:c++latest.

2 Comments

What is the result of this: if (cond) { if (cond2) [[likely]] { f(); } else { g(); } } else { h(); } ? Honestly, it's hard to get which one is understood as likely ? The outer true branch ? The inner true branch ?
Indeed, GCC 15.1 (and probably earlier) accepts this without warning, but warns with [[likely]] outside the braces. With -fno-tree-vectorize -fno-if-conversion, [[likely]] vs. [[unlikely]] even has an effect on branch layout gcc.godbolt.org/z/s4YcdEq5T , proving that GCC is understanding the hint. (Without those optimization options, GCC makes branchless scalar or SIMD asm for if(data[i] >= 128) { sum += data[i]; } when targeting x86-64. Which is normally what you want.)
5

So how should I use these attributes in an if-else statement?

Exactly as you are doing, your syntax is correct as per the example given in the draft standard (simplified to show relevant bits only):

int f(int n) {
    if (n > 5) [[unlikely]] {
        g(0);
        return n * 2 + 1;
    }

    return 3;
}

But you should understand that this feature is a relatively new one, so may only have placeholders in implementations to allow you to set the attributes. This appears apparent from your warning message.


You should also understand that, unless certain wording changes between the latest draft and the final product, even compliant implementations are able to ignore these attributes. They are very much suggestions to the compiler, like inline in C. From that latest draft n4762 (at the time of this answer, and with my emphasis):

Note: The use of the likely attribute is intended to allow implementations to optimize for the case where paths of execution including it are arbitrarily more likely than any alternative path of execution that does not include such an attribute on a statement or label.

Note the word "allow" rather than "force", "require" or "mandate".

2 Comments

It would have been A LOT easier to port existing code based on __builtin_expect, e.g. if (likely(a>b)) { if we could specify the attribute inside the if-statement: if ([[likely]] a>b) {.
@rustyx But the syntax also works for switch case where it's even more useful than the if. I'm getting nice performance improvements with it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.