[[可能]]和[[不太可能]]影响程序汇编的简单示例?

Simple example where [[likely]] and [[unlikely]] affect program assembly?

本文关键字:汇编 简单 程序 可能 影响      更新时间:2023-10-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();
}
}

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

看起来,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 生成代码,其中条件跳转发生在不太可能的路径中。