16

C++20 将属性[[likely]]和语言引入[[unlikely]]了语言,可用于允许编译器针对一个执行路径比其他执行路径可能或不太可能的情况进行优化。

考虑到不正确的分支预测的代价,这似乎是一个在性能关键的代码部分中可能非常有用的功能,但我不知道它实际上会导致编译器做什么。

是否有一段简单的代码可以添加[[likely]][[unlikely]]属性更改编译器的程序集输出?也许更重要的是,这些变化有什么作用?

我创建了一个简单的示例以供自己理解,以查看程序集是否有任何差异,但似乎此示例过于简单,无法实际显示程序集的任何更改:

void true_path();
void false_path();

void foo(int i) {
    if(i) {
        true_path();
    } else {
        false_path();
    }
}
void bar(int i) {
    if(i) [[likely]] {
        true_path();
    } else [[unlikely]] {
        false_path();
    }
}

在此处查看已编译的程序集。

4

1 回答 1

6

看起来,gcc 中有一个错误。如果你有两个相同的函数,除了[[likely]]属性,gcc 会错误地折叠它们。

[[likely]]但是如果你只使用一个函数,并在/之间切换[[unlikely]],程序集就会改变。

所以,这个函数:

void bar(int i) {
    if(i) [[unlikely]] {
        true_path();
    } else [[likely]] {
        false_path();
    }
}

编译为:

bar(int):
        test    edi, edi
        jne     .L4
        jmp     false_path()
.L4:
        jmp     true_path()

和这个:

void bar(int i) {
    if(i) [[likely]] {
        true_path();
    } else [[unlikely]] {
        false_path();
    }
}

编译为:

bar(int):
        test    edi, edi
        je      .L2
        jmp     true_path()
.L2:
        jmp     false_path()

请注意,条件已更改:第一个版本如果i非零则跳转,而第二个版本如果为零则跳转i

这与属性一致:gcc 生成代码,其中条件跳转发生在不太可能的路径中。

于 2020-06-05T20:09:01.630 回答