在长模式下使用64/32位寄存器可能会有任何处罚吗?

Ale*_*hak 8 optimization x86 assembly micro-optimization

可能这甚至都不是微观但纳米优化,但主题让我感兴趣,我想知道在长模式下使用非本机寄存器大小时是否存在任何惩罚?

我从各种来源了解到,部分寄存器更新(比如ax代替eax)会导致eflags停顿并降低性能.但我不确定长模式.对于此处理器操作模式,哪个寄存器大小被视为原生?x86-64仍然是x86架构的扩展,因此我相信32位仍然是原生的.还是我错了?

例如,像

sub eax, r14d
Run Code Online (Sandbox Code Playgroud)

要么

sub rax, r14
Run Code Online (Sandbox Code Playgroud)

具有相同的尺寸,但在使用其中任何一种时可能会有任何处罚吗?在如下连续指令中混合寄存器大小时可能会有任何处罚吗?(假设高dword在所有情况下均为零)

sub ecx, eax
sub r14, rax
Run Code Online (Sandbox Code Playgroud)

Pet*_*des 9

在连续指令中混合32位和64位寄存器大小时可能有任何处罚吗?

不,写入32位寄存器始终为零 - 扩展到完整寄存器,因此x86-64避免了对32位和64位指令的任何部分寄存器处罚.

因此我相信32位仍然是原生的.

是的,对于大多数指令(除了PUSH/POP),默认操作数大小为32位.64位需要一个REX前缀,W位设置为1.因此,出于代码大小的原因,首选32位.这就是编译器mov r32, imm32用于静态数据地址的原因(因为默认代码模型要求代码和静态数据地址位于虚拟地址空间的低2GiB中).

这是AMD的设计选择.他们可以选择其他方式,并需要一个前缀来获得32位操作数大小.由于长模式是一种单独的模式,因此x86-64机器代码可能与x86-32机器代码不同.AMD选择最小化差异,以便他们可以在解码器中共享尽可能多的晶体管.你的结论是正确的,但你的推理完全是假的.


部分寄存器更新(如ax而不是eax)可能导致eflags停滞并降低性能.

部分标志档位与部分档案档位分开.它们在内部处理相似(EFLAGS的单独重命名部分必须合并,因为修改后的AX必须与未修改的EAX上部字节合并). 但是一个不会导致另一个.

# partial-reg stall
setcc   al           # leaves the upper 3 (or 7) bytes unmodified
add     edx, eax     # reads full EAX.  Older CPUs stall while merging
Run Code Online (Sandbox Code Playgroud)

在标志设置和setcc之前将EAX归零xor eax,eax可以完全避免部分寄存器惩罚.(Core2/Nehalem比早期的CPU停顿的周期更少,但在插入合并的uop时仍然会停止2或3c.Sandybridge在插入合并uop时根本不会失速).

(对不同CPU的部分寄存器处罚的另一个总结: 为什么GCC不使用部分寄存器?,基本上说同样的事情).

AMD在以后读取完整寄存器时不会遭受部分寄存器停顿,而是部分寄存器写入和读取对整个寄存器具有错误的依赖性.(AMD CPU首先不单独重命名子寄存器.英特尔P4和Silvermont/Knight的登陆方式相同.)

英特尔的Haswell/SKYLAKE微架构(也许IvyBridge的)不重命名al分开rax所有,所以他们从来没有需要合并low8/low16寄存器.但是setcc al对旧价值的依赖是错误的.他们仍然重命名和合并ah.(有关HSW/SKL部分注册表现的详细信息.)


# partial flag stall when reading a flag that didn't come from
# the last instruction to write any flags.
clc
# edi and esi = one-past-the-end of dst and src
# ecx = -count
bigInt_add:
    mov   eax, [esi+ecx*4]
    adc   [edi+ecx*4], eax   # reads CF, partial flag stall on 2nd and later iterations
    inc   ecx                # writes all flags except CF
    jl    bitInt_add         # loop upwards towards zero
Run Code Online (Sandbox Code Playgroud)

有关英特尔预Sandybridge与Sandybridge之间部分标记问题的更多讨论,请参阅此问答.


另请参阅Agner Fog的microarch pdf以及标签wiki 中的其他链接,了解有关所有这些内容的更多详细信息.


归档时间:

查看次数:

186 次

最近记录:

7 年,11 月 前