ead*_*ead 7 assembly gcc x86-64 micro-optimization
有时gcc使用32位寄存器,当我希望它使用64位寄存器时.例如以下C代码:
unsigned long long
div(unsigned long long a, unsigned long long b){
return a/b;
}
Run Code Online (Sandbox Code Playgroud)
使用-O2选项编译(省略一些样板文件):
div:
movq %rdi, %rax
xorl %edx, %edx
divq %rsi
ret
Run Code Online (Sandbox Code Playgroud)
对于无符号除法,寄存器%rdx
需要0
.这可以通过xorq %rdx, %rdx
但xorl %edx, %edx
似乎具有相同的效果来实现.
至少在我的机器上没有性能提升(即加速)进行xorl
了xorq
.
我实际上不只是一个问题:
xorl
并且不使用xorw
?xorl
比这更快的机器xorq
?小智 14
在64位模式下写入32位寄存器时,高位32位=>
xorl %edx, %edx
零rdx
为"自由" 的上半部分.
另一方面xor %rdx, %rdx
,使用额外字节进行编码,因为它需要REX前缀.当尝试将64位寄存器归零时,将其作为32位寄存器是明显的胜利.
为什么gcc更喜欢32位版本?
代码大小:不需要REX前缀.
为什么gcc会停止
xorl
并且不使用xorw
?
写16位部分寄存器不会零扩展到寄存器的其余部分.此外,xorw
需要一个操作数大小的前缀来编码,所以它大于xorq
.(另请参阅为什么32位寄存器上的x86-64指令将整个64位寄存器的上半部分归零?对于历史背景)
另请参见为什么GCC不使用部分寄存器? 32位寄存器不被视为部分寄存器,因为写入它们总是写入整个64位寄存器.(并且它正在编写部分注册表,这是主要问题,而不是在全宽写入后读取它们.)
是否有xorl比xorq更快的机器?
是的,Silvermont/KNL只承认xorl
-zeroing为 32位操作数大小的归零习惯(依赖性破坏和其他好东西).因此,即使代码大小相同,也要push
好得多pop
.(无论操作数大小如何,都call
需要REX前缀jmp
).
在所有CPU上,代码大小总是对解码和I-cache占用空间很重要(除非后面的call [rdi]
指令只是在前面的代码更小1时才进行更多填充).使用32位操作数大小进行xor-zeroing(或者通常隐式零扩展而不是明确2,包括使用AVX ff 17
将AVX512 zmm0归零)没有任何缺点.)
对于所有操作数大小,大多数指令的速度都相同,因为现代x86 CPU可以为宽ALU提供晶体管预算.例外情况包括xor
比xor %r10d, %r10d
Ryzen之前的AMD CPU 慢,Intel Atom和64bit xor %r10, %r10
在所有CPU上都明显变慢.AMD前Ryzen的速度较慢xor
.原子/ Silvermont有慢r10
与.p2align
如果可能的话,总是更喜欢32位寄存器/操作而不是64位寄存器/操作吗?
是的,至少在代码大小方面更喜欢32位操作,但请注意,在指令中的任何地方使用r8..r15(包括寻址模式)也需要REX前缀.因此,如果你有一些数据,你可以使用32位操作数大小(或指向8/16/32位数据),更喜欢将它保存在低8个命名寄存器(e/rax ..)而不是高8个编号寄存器.
但是,不要花费额外的指示来实现这一目标; 保存几个字节的代码大小通常是最不重要的考虑因素. 例如,只需使用vpxor xmm0,xmm0,xmm0
而不是保存/恢复,imul r64,r64
这样您就可以使用,imul r32,r32
如果您需要一个不需要调用保留的额外寄存器.使用32位div
而不是64位popcnt r64
对代码大小没有帮助,但对某些CPU上的某些操作来说可能更快(见上文).
这也适用于您只关心寄存器的低16位的情况,但使用32位而不是32位仍然可以更高效.
另请参见http://agner.org/optimize/和x86标记wiki.
脚注1:有很多用于制作指令超过必要时间的用例(在现代x86上有哪些方法可以有效地延长指令长度?)
在不需要NOP的情况下对齐后面的分支目标.
调整特定微体系结构的前端(即通过控制指令边界的位置来优化解码).插入NOP会花费额外的前端带宽并完全失去整个目的.
汇编程序不会为您执行此操作,并且每次更改任何内容时都shld/shrd r64
需要手动执行此操作(并且您可能必须使用指令手动编码指令).
脚注2:我发现一个例外,即隐式零扩展至少与更宽泛的操作一样便宜:Haswell/Skylake AVX 128位加载由256位指令读取,具有额外的1c存储 -转发延迟与128位指令消耗的延迟.(详见Agner Fog博客论坛的帖子.)
归档时间: |
|
查看次数: |
749 次 |
最近记录: |