繁体   English   中英

一些通用寄存器比其他寄存器快吗?

[英]Are some general purpose registers faster than others?

在 x86-64 中,如果某些通用寄存器优先于其他寄存器,某些指令会执行得更快吗?

例如, mov eax, ecx会比mov r8d, ecx ecx 执行得更快吗? 我可以想象后者需要一个 REX 前缀,这会使指令获取速度变慢?

使用rax代替rcx怎么样? 那么addxor呢? 其他操作? r15bal这样的较小寄存器? al vs ah

AMD 与英特尔? 较新的处理器? 旧处理器? 指令组合?

澄清:是否应该优先使用某些通用寄存器而不是其他寄存器,它们是哪些?

以 EBP、RBP 或 R13 为基础时,LEA 会变慢(PDF 警告,第 3-22 页)。 但一般来说答案是否定的。

退后一步,重要的是要意识到自从寄存器重命名出现以来,架构寄存器不处理大多数微架构上的实际物理寄存器。 例如,每个 Cascade Lake 内核都有一个 180 个 integer 和 168 个 FP 寄存器的寄存器文件。

一般来说,架构寄存器都是平等的,并被重命名为大量的物理寄存器。

(除了部分寄存器可能会更慢,特别是高字节 AH/BH/CH/DH 在写入完整寄存器后读取速度很慢,在 Haswell 及更高版本上。请参阅Haswell/Skylake 上的部分寄存器究竟是如何执行的?写 AL 似乎对 RAX 有错误的依赖,并且 AH 不一致,以及为什么 GCC 不使用部分寄存器?写 8 位和 16 位寄存器时出现问题)。 这个答案的 rest 只是考虑 32/64-bit operand-size 。)

但是有些指令需要特定的寄存器,例如传统的可变计数移位(没有 BMI2 shrx 等)需要 CL 中的计数。 除法需要 EDX:EAX(或 RDX:RAX 用于较慢的 64 位版本)中的除数。

使用像 RBX 这样的调用保留寄存器意味着您的 function 必须花费额外的指令来保存/恢复它。

但是,如果您需要更多说明,当然会有性能差异。 因此,让我们假设所有其他条件都相同,仅通过更改用于其中一个操作数的寄存器来讨论单个指令的微指令、延迟和代码大小。 TL:DR:唯一的性能差异是由于指令编码限制/差异。 有时不同的寄存器将允许/要求(或让汇编器选择)不同的编码,作为特殊情况,通常会更小/更大,有时甚至会以不同的方式执行。

通常,较小的代码速度更快,并且在 uop 缓存和 I-cache 中打包得更好,因此除非您分析了特定情况并发现了问题,否则倾向于使用较小的编码。 这通常意味着在 AL 中保留一个字节值,以便您可以使用这些特殊情况指令,并避免 RBP / R13 用于指针。


特定编码特别慢的特殊情况,而不仅仅是大小

如果寻址模式还没有+displacement常数,则以 RBP 或 R13 作为基础的 LEA 在 Intel 上可能会更慢。

例如lea eax, [rbp + 12]是可编码的,并且与lea eax, [rcx + 12]一样快。

但是lea eax, [rbp + rcx*4]只能在机器码中编码为lea eax, [rbp + rcx*4 + 0] (因为寻址模式 escape-code stuff ),它是一个 3-component LEA,因此在 Intel 上较慢(Sandybridge 系列的 3 个周期延迟而不是 1 个周期,请参阅https://agner.org/optimize/指令表和 microarch PDF)。 在 AMD 上,即使使用lea eax, [rdx + rcx*4]

在 LEA 之外,在任何寻址模式中使用 RBP / R13 作为基础总是需要一个disp8/32字节或 dword,但我认为实际的 AGU 对于 3 组件寻址模式并不慢。 所以这只是代码大小的影响。


其他案例包括哪个英特尔微架构引入了 ADC reg,0 单微指令特殊案例? 其中, adc al, imm8的短格式 2 字节编码是 2 uop,即使在像 Skylake 这样的现代 uarches 上,其中adc bl, imm8是 1 uop。

因此, adc reg,0的特殊情况不仅不适用于 Sandybridge 上的adc al,0通过 Haswell、Broadwell 和更新的人忘记(或选择不)优化编码解码到 uops 的方式。 (当然,您可以使用 3 字节 Mod/RM 编码手动编码adc al,0 ,但汇编程序将始终选择最短的编码,因此默认情况下adc al,0将汇编为短格式。)只有字节寄存器有问题; adc eax,0将使用opcode ModRM imm8 3 字节编码,而不是 5 字节opcode imm32

对于op al,imm8的其他情况,唯一的区别是代码大小,这只是间接影响性能。 (因为解码、uop-cache 打包和 I-cache 未命中)。

有关代码大小特殊情况的更多信息,请参阅使用 x86/x64 机器代码打高尔夫球的技巧,例如xchg eax, ecx为 1 字节与xchg edx, ecx为 2 字节。


add rsp, 8可能需要额外的堆栈同步 uop(当然,沿着执行路径,不在 static 代码布局中)。 什么是 Sandybridge 微架构中的堆栈引擎? )。 这就是为什么像clang这样的编译器使用虚拟推送或弹出来保留/释放单个堆栈槽的原因: 为什么这个 function 将 RAX 推送到堆栈作为第一个操作?

您总共提出了太多问题,但是,如果我很好地理解了这个问题,您就会将处理器架构与小而快的寄存器文件混淆,它填补了处理器和 memory 技术之间的速度差距。 寄存器文件足够小,一次只能支持一条指令,即当前指令,并且足够快,几乎可以赶上处理器的速度。

我想建立一个简短的背景,这些寄存器的命名约定有两个目的:第一,它使旧版本的 x86 ISA 实现兼容至今,第二,这些寄存器的每个名称都有其特殊用途除了它的一般用途。 例如,ECX 寄存器用作计数器来实现循环,即 JECXZ 和 LOOP 等指令仅使用 ECX 寄存器。 尽管您需要注意一些您不想丢失的标志。

现在你的问题的答案源于第二个目的。 所以一些寄存器似乎更快,因为这些特殊寄存器被硬编码到处理器中并且可以更快地访问,但是,差异应该不大。

您可能知道的第二件事,并非所有指令都具有相同的复杂性,尤其是在 x86 中,指令的操作码可以是 1-3 个字节,并且随着越来越多的功能被添加到指令中,前缀,寻址模式等这些指令开始变得更慢,所以并不是某些寄存器比其他寄存器慢,只是某些寄存器被编码到指令中,因此这些指令在该寄存器组合下运行得更快。 如果以其他方式使用,它似乎会更慢。 我希望这会有所帮助。 谢谢

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM