[[likely]] 和 [[unlikely]] 影响程序汇编的简单示例?
Simple example where [[likely]] and [[unlikely]] affect program assembly?
C++20在语言中引入了属性[[likely]]
和[[unlikely]]
,可以用来让编译器针对一个执行路径是much [=26]的情况进行优化=]更多可能或比其他人更更少可能。
考虑到错误分支预测的代价,这似乎是一个在代码的性能关键部分可能非常有用的功能,但我不知道它实际上会导致编译器做什么。
是否有一段简单的代码可以添加 [[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 生成代码,其中条件跳转发生在不太可能的路径中。
C++20在语言中引入了属性[[likely]]
和[[unlikely]]
,可以用来让编译器针对一个执行路径是much [=26]的情况进行优化=]更多可能或比其他人更更少可能。
考虑到错误分支预测的代价,这似乎是一个在代码的性能关键部分可能非常有用的功能,但我不知道它实际上会导致编译器做什么。
是否有一段简单的代码可以添加 [[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 生成代码,其中条件跳转发生在不太可能的路径中。