在 Long 模式下使用 64/32 位寄存器时可能会有任何惩罚吗?
May there be any penalties when using 64/32-bit registers in Long mode?
可能这甚至不是微优化而是纳米优化,但我对这个主题很感兴趣,我想知道在长模式下使用非本机寄存器大小时是否有任何惩罚?
我从各种来源了解到,部分寄存器更新(如 ax
而不是 eax
)会导致 eflags
停顿并降低性能。但我不确定长模式。对于这种处理器操作模式,什么寄存器大小被认为是本机的? x86-64 仍然是 x86 架构的扩展,因此我相信 32 位仍然是原生的。还是我错了?
例如,指令如
sub eax, r14d
或
sub rax, r14
具有相同的大小,但使用其中任何一个时可能会有任何处罚吗?
在像下面这样的连续指令中混合寄存器大小时可能会有任何惩罚吗? (假设高位双字在所有情况下均为零)
sub ecx, eax
sub r14, rax
May there be any penalties when mixing 32 and 64-bit register sizes in consecutive instructions?
No, writing to a 32-bit register always zero-extends to the full register,因此 x86-64 避免了 32 位和 64 位指令的任何部分寄存器惩罚。
thus I believe 32 bits are still native.
是的,大多数指令的默认操作数大小为 32 位 (other than PUSH/POP)。 64 位需要 W 位设置为 1 的 REX 前缀。因此出于代码大小的原因更喜欢 32 位。这就是编译器使用 mov r32, imm32
作为静态数据地址的原因(因为默认代码模型要求代码和静态数据地址位于虚拟地址 space 的低 2GiB 中)。
这是 AMD 的设计选择。他们本可以选择其他方式,并需要一个前缀来获得 32 位操作数大小。由于长模式是一种单独的模式,因此 x86-64 机器代码可以与 x86-32 机器代码不同,但它需要。 AMD 选择最小化差异,以便他们可以在解码器中共享尽可能多的晶体管。你的结论是正确的,但是你的推理完全是假的。
partial register updates (like ax instead of eax) can cause eflags stall and degrade performance.
部分标志停顿与部分寄存器停顿分开。它们在内部的处理方式类似(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
。 (Core2/Nehalem 停顿的周期比早期的 CPU 少,但在插入合并 uop 时仍会停顿 2 或 3c。Sandybridge 在插入合并 uop 时根本不会停顿。
(不同CPU上部分寄存器惩罚的另一个总结:,说的基本一样)。
AMD 在稍后读取完整寄存器时不会遭受部分寄存器停顿,而是部分寄存器写入和读取对完整寄存器有错误的依赖性。 (AMD CPU 本来就不单独重命名子寄存器。Intel P4 和 Silvermont / Knight's Landing 都是一样的。)
Intel Haswell/Skylake(也许还有 Ivybridge)根本不会将 al
与 rax
分开重命名 ,因此他们永远不需要合并 low8 / low16 寄存器。但是 setcc al
对旧值有错误的依赖。他们仍然重命名并合并 ah
。 ( .)
# 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
有关 Intel pre-Sandybridge 与 Sandybridge 的部分标志问题的更多讨论,请参阅 。
另请参阅 Agner Fog's microarch pdf, and other links in the x86 标签 wiki,了解有关所有这些的更多详细信息。
可能这甚至不是微优化而是纳米优化,但我对这个主题很感兴趣,我想知道在长模式下使用非本机寄存器大小时是否有任何惩罚?
我从各种来源了解到,部分寄存器更新(如 ax
而不是 eax
)会导致 eflags
停顿并降低性能。但我不确定长模式。对于这种处理器操作模式,什么寄存器大小被认为是本机的? x86-64 仍然是 x86 架构的扩展,因此我相信 32 位仍然是原生的。还是我错了?
例如,指令如
sub eax, r14d
或
sub rax, r14
具有相同的大小,但使用其中任何一个时可能会有任何处罚吗? 在像下面这样的连续指令中混合寄存器大小时可能会有任何惩罚吗? (假设高位双字在所有情况下均为零)
sub ecx, eax
sub r14, rax
May there be any penalties when mixing 32 and 64-bit register sizes in consecutive instructions?
No, writing to a 32-bit register always zero-extends to the full register,因此 x86-64 避免了 32 位和 64 位指令的任何部分寄存器惩罚。
thus I believe 32 bits are still native.
是的,大多数指令的默认操作数大小为 32 位 (other than PUSH/POP)。 64 位需要 W 位设置为 1 的 REX 前缀。因此出于代码大小的原因更喜欢 32 位。这就是编译器使用 mov r32, imm32
作为静态数据地址的原因(因为默认代码模型要求代码和静态数据地址位于虚拟地址 space 的低 2GiB 中)。
这是 AMD 的设计选择。他们本可以选择其他方式,并需要一个前缀来获得 32 位操作数大小。由于长模式是一种单独的模式,因此 x86-64 机器代码可以与 x86-32 机器代码不同,但它需要。 AMD 选择最小化差异,以便他们可以在解码器中共享尽可能多的晶体管。你的结论是正确的,但是你的推理完全是假的。
partial register updates (like ax instead of eax) can cause eflags stall and degrade performance.
部分标志停顿与部分寄存器停顿分开。它们在内部的处理方式类似(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
(不同CPU上部分寄存器惩罚的另一个总结:
AMD 在稍后读取完整寄存器时不会遭受部分寄存器停顿,而是部分寄存器写入和读取对完整寄存器有错误的依赖性。 (AMD CPU 本来就不单独重命名子寄存器。Intel P4 和 Silvermont / Knight's Landing 都是一样的。)
Intel Haswell/Skylake(也许还有 Ivybridge)根本不会将 al
与 rax
分开重命名 ,因此他们永远不需要合并 low8 / low16 寄存器。但是 setcc al
对旧值有错误的依赖。他们仍然重命名并合并 ah
。 (
# 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
有关 Intel pre-Sandybridge 与 Sandybridge 的部分标志问题的更多讨论,请参阅
另请参阅 Agner Fog's microarch pdf, and other links in the x86 标签 wiki,了解有关所有这些的更多详细信息。