我知道这movzx
可以用于打破依赖关系,但我偶然发现了movzx
Clang 和 GCC 的一些用途,我真的看不出它们有什么用处。这是我在 Godbolt 编译器浏览器上尝试的一个简单示例:
#include <stdint.h>
int add2bytes(uint8_t* a, uint8_t* b) {
return uint8_t(*a + *b);
}
Run Code Online (Sandbox Code Playgroud)
与海湾合作委员会 12 -O3
:
add2bytes(unsigned char*, unsigned char*):
movzx eax, BYTE PTR [rsi]
add al, BYTE PTR [rdi]
movzx eax, al
ret
Run Code Online (Sandbox Code Playgroud)
如果我理解正确的话,这里的第一个movzx
打破了对先前eax
值的依赖,但第二个是什么movzx
做什么?我认为它不会破坏任何依赖关系,也不应该影响结果。
使用 clang 14 -O3
,情况更加奇怪:
add2bytes(unsigned char*, unsigned char*): # @add2bytes(unsigned char*, unsigned char*)
mov al, byte ptr [rsi]
add al, byte ptr [rdi]
movzx eax, al
ret …
Run Code Online (Sandbox Code Playgroud) 我正在使用 Google Benchmark 优化一个函数,并遇到了我的代码在某些情况下意外变慢的情况。我开始试验它,查看编译后的程序集,并最终想出了一个最小的测试用例来展示这个问题。这是我想出的展示这种放缓的程序集:
.text
test:
#xorps %xmm0, %xmm0
cvtsi2ss %edi, %xmm0
addss %xmm0, %xmm0
addss %xmm0, %xmm0
addss %xmm0, %xmm0
addss %xmm0, %xmm0
addss %xmm0, %xmm0
addss %xmm0, %xmm0
addss %xmm0, %xmm0
addss %xmm0, %xmm0
retq
.global test
Run Code Online (Sandbox Code Playgroud)
此函数遵循 GCC/Clang 的 x86-64 函数声明调用约定extern "C" float test(int);
注意注释掉的xorps
指令。取消注释此指令可显着提高函数的性能。用我的机器有i7-8700K,谷歌基准测试显示的功能测试它,而不该xorps
指令需要8.54ns(CPU),而功能与该xorps
指令需要1.48ns。我已经在具有不同操作系统、处理器、处理器世代和不同处理器制造商(英特尔和 AMD)的多台计算机上对此进行了测试,它们都表现出类似的性能差异。重复addss
指令使减速更加明显(在某种程度上),并且这种减速仍然使用此处的其他指令(例如mulss
)或什至混合指令发生,只要它们都%xmm0
以某种方式依赖于值。值得指出的是,只调用xorps
每个函数调用会导致性能提升。使用循环对性能进行采样(如 Google Benchmark 所做的那样)和xorps
循环外的调用仍然显示出较慢的性能。
由于这是一种专门添加指令可以提高性能的情况,因此这似乎是由 CPU 中的一些非常低级的东西引起的。由于它发生在各种 CPU …