Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correctly using C++20 `[likely]]`/`[[unlikely]]` in `switch` statements

C++20 has handy [[likely]]/[[unlikely]] attributes which guide code generation. For example, you can specify a branch is likely to be taken by:

if (b) [[likely]] { /*...*/ }

Similarly, it is possible to use these attributes in switch statements . . . somehow? The documentation suggests the following example (slightly formatted):

switch (i) {
    case 1:
        [[fallthrough]];
    [[likely]] case 2:
        return 1;
}

The implication is clearly that the [[likely]]/[[unlikely]] goes before the case statement. The internet seems to almost universally promulgate this usage.

However, consider the following similar code (all I've done is move the [[likely]] to the other case):

switch (i) {
    [[likely]] case 1:
        [[fallthrough]];
    case 2:
        return 1;
}

This fails to compile on clang! While that may be related to a compiler bug with [[fallthrough]], it got me looking at the standards. The relevant standard has the following example (see §VII):

implementations are encouraged to optimize for that case being executed (eg. a having the value 1 in the following code):

switch (a) {
    case 1: [[likely]]
        foo();
        break;
    //...
}

That is, the attribute comes after the case label, not before.

So . . . which is it? Offhand, I'd expect the standard to be correct, but that is actually a proposal, not the real standard AFAICT—it could have been changed since. And, I'd expect the documentation, if nothing else, to be correct at least about the fundamental syntax—except that it doesn't even compile.

like image 534
imallett Avatar asked Mar 05 '21 16:03

imallett


People also ask

What Cannot be used in a switch statement?

The switch/case statement in the c language is defined by the language specification to use an int value, so you can not use a float value. The value of the 'expression' in a switch-case statement must be an integer, char, short, long. Float and double are not allowed.

Which of the following is true for switch statement in C++?

A switch statement can have an optional default case, which must appear at the end of the switch. The default case can be used for performing a task when none of the cases is true. No break is needed in the default case.

Which keyword is used in switch statement in C?

1) Break: This keyword is used to stop the execution inside a switch block. It helps to terminate the switch block and break out of it. 2) Default: This keyword is used to specify the set of statements to execute if there is no case match.

Is it possible to use [ likely] and [unlikely] in switch statements?

Similarly, it is possible to use these attributes in switch statements . . . somehow? The documentation suggests the following example (slightly formatted): switch (i) { case 1: [ [fallthrough]]; [ [likely]] case 2: return 1; } The implication is clearly that the [ [likely]] / [ [unlikely]] goes before the case statement.

What is the syntax for a switch statement in C?

Syntax. The syntax for a switch statement in C programming language is as follows −. The expression used in a switch statement must have an integral or enumerated type, or be of a class type in which the class has a single conversion function to an integral or enumerated type. You can have any number of case statements within a switch.

Is it possible to use SWITCH-CASE statements in C++?

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.

What are the likely and unlikely macros in c++ 20?

If the use of the likely and unlikely macros seemed a bit ad hoc, watch out for the C++ 20 [ [likely]] and [ [unlikely]] attributes. These attributes would also be supported in switch-statement. The C++ 20 proposal for the [ [likely]] and [ [unlikely]] describes the advantages of giving direct hints to the compiler.


1 Answers

Both examples are valid, and Clang is exhibiting a bug. The relevant verbiage from the last standard draft for C++20 is

[dcl.attr.likelihood]

1 The attribute-tokens likely and unlikely may be applied to labels or statements.

Where the relevant grammar productions for statements and labeled statements have an attribute specifier sequence at the appropriate locations.

[stmt.pre]

statement:
  labeled-statement
  attribute-specifier-seq expression-statement
  attribute-specifier-seq compound-statement
  attribute-specifier-seq selection-statement
  attribute-specifier-seq iteration-statement
  attribute-specifier-seq jump-statement
  declaration-statement
  attribute-specifier-seq try-block

[stmt.label]

labeled-statement:
  attribute-specifier-seq identifier : statement
  attribute-specifier-seq case constant-expression : statement
  attribute-specifier-seq default : statement

In

switch (i) {
    case 1:
        [[fallthrough]];
    [[likely]] case 2:
        return 1;
}

The attribute applies to case 2: wheras in

switch (a) {
    case 1: [[likely]]
        foo();
        break;
    //...
}

it applies to the statement foo();.

like image 104
StoryTeller - Unslander Monica Avatar answered Oct 20 '22 05:10

StoryTeller - Unslander Monica