Ign*_*tov 58 c++ compiler-construction clang
有时编译器生成具有奇怪的指令重复的代码,可以安全地删除.考虑以下代码:
int gcd(unsigned x, unsigned y) {
return x == 0 ? y : gcd(y % x, x);
}
Run Code Online (Sandbox Code Playgroud)
这是汇编代码(由clang 5.0生成并启用了优化):
gcd(unsigned int, unsigned int): # @gcd(unsigned int, unsigned int)
mov eax, esi
mov edx, edi
test edx, edx
je .LBB0_1
.LBB0_2: # =>This Inner Loop Header: Depth=1
mov ecx, edx
xor edx, edx
div ecx
test edx, edx
mov eax, ecx
jne .LBB0_2
mov eax, ecx
ret
.LBB0_1:
ret
Run Code Online (Sandbox Code Playgroud)
在以下代码段中:
mov eax, ecx
jne .LBB0_2
mov eax, ecx
Run Code Online (Sandbox Code Playgroud)
如果跳转没有发生,eax则重新分配没有明显的原因.
另一个例子是函数末尾的两个ret:一个也可以完美地工作.
编译器是不是足够聪明,还是没有理由不删除重复?
jan*_*anm 40
编译器可以执行对人们来说不明显的优化,并且删除指令并不总能使事情变得更快.
少量搜索表明,当RET紧跟在条件分支之后,各种AMD处理器都存在分支预测问题.通过用基本上无操作的方式填充该插槽,可以避免性能问题.
更新:
示例参考,"AMD64处理器软件优化指南"的6.2节(参见http://support.amd.com/TechDocs/25112.PDF)说:
具体来说,避免以下两种情况:
任何类型的分支(有条件或无条件),其具有单字节近返返RET指令作为其目标.请参阅"示例".
直接在单字节近返RET指令之前出现在代码中的条件分支.
它还详细说明了为什么跳转目标应该具有对齐,这也可能解释函数末尾的重复RET.
| 归档时间: |
|
| 查看次数: |
1576 次 |
| 最近记录: |