在x86-64中,如果某些通用寄存器比其他寄存器更受欢迎,某些指令会执行得更快吗?
例如,mov eax, ecx
会比mov r8d, ecx
执行得更快吗?我可以想象后者需要一个REX前缀,这会使指令获取速度变慢?
使用rax
代替rcx
怎么样?add
或xor
呢?其他操作?更小的寄存器,如r15b
vsal
?al
vsah
?
AMD vs Intel?更新的处理器?较旧的处理器?指令的组合?
澄清:某些通用登记册是否应该优先于其他登记册,它们是哪些?
你总共塞了太多的问题,但是,如果我很好地理解这个问题,你将处理器架构与小而快的寄存器文件混淆了,它填补了处理器和内存技术之间的速度差距。寄存器文件足够小,一次只能支持一条指令,即当前指令,并且足够快,几乎可以赶上处理器速度。
我想建立一个简短的背景,这些寄存器的命名约定有两个目的:一,它使x86 ISA实现的旧版本到目前为止兼容,二,这些寄存器的每个名称除了其通用用途外都有特殊用途。例如,ECX寄存器用作实现循环的计数器,即JECXZ和LOOP等指令专门使用ECX寄存器。尽管您需要注意一些您不想丢失的标志。
现在,你问题的答案来自第二个目的。因此,一些寄存器似乎更快,因为这些特殊寄存器是硬编码到处理器中的,可以更快地访问,然而,差别应该不大。
你可能知道的第二件事,不是所有的指令都具有相同的复杂性,尤其是在x86中,指令的操作码可以从1-3个字节开始,随着越来越多的功能被html" target="_blank">添加到指令中,如前缀、寻址模式等,这些指令开始变得更慢,所以不是一些寄存器比其他寄存器慢,而是一些寄存器被编码到指令中,因此这些指令在寄存器的组合下运行得更快。如果另有使用,它看起来会更慢。我希望这有所帮助。谢谢
以EBP、RBP或R13为基础的LEA速度较慢(PDF警告,第3-22页)。但总的来说,答案是否定的。
退一步说,重要的是要认识到,自从寄存器重命名的出现以来,架构寄存器并不能处理大多数微架构上的实际物理寄存器。例如,每个级联Lake核心都有一个包含180个整数和168个浮点寄存器的寄存器文件。
一般来说,架构寄存器都是相等的,并重命名为大量物理寄存器。
(除了部分寄存器可能较慢,尤其是高字节AH/BH/CH/DH,在Haswell和更高版本上写入完整寄存器后读取速度较慢。请参阅Haswell/Skylake上的部分寄存器具体如何执行?写入AL似乎对RAX有错误依赖,AH不一致,为什么GCC不使用部分寄存器?用于解决写入8位和16位寄存器时的问题)。这个答案的其余部分只考虑32/64位操作数大小。)
但是一些指令需要特定的寄存器,例如传统的变量计数移位(没有BMI2收缩等)需要CL中的计数。部门需要EDX: EAX(或较慢的64位版本的RDX: RAX)中的红利。
使用像RBX这样的调用保留寄存器意味着您的函数必须花费额外的指令来保存/恢复它。
但是如果你需要更多的指导,当然会有性能上的差异。因此,让我们假设所有其他条件都相等,只需通过更改其操作数之一使用的寄存器来讨论单个指令的UOP、延迟和代码大小。TL:DR:唯一的性能差异是由于指令编码限制/差异。有时,不同的寄存器将允许/要求(或让汇编器选择)不同的编码,作为特例,通常较小/较大,有时甚至执行不同。
一般来说,较小的代码更快,并且在uop缓存和I-cache中打包得更好,因此除非您分析了特定情况并发现问题,否则最好使用较小的编码。通常这意味着在AL中保留一个字节值,以便您可以使用那些特殊情况指令,并避免RBP/R13作为指针。
如果寻址模式没有位移常数,以RBP或R13为基础的LEA在Intel上可能会较慢。
e、 g.lea-eax,[rbp 12]
可按写进行编码,速度与lea-eax,[rcx 12]一样快。
但是,lea eax,[rbp rcx*4]只能在机器代码中编码为lea eax,[rbp rcx*4 0](因为寻址模式转义码),这是一种三分量lea,因此在Intel上较慢(Sandybridge系列上的3个周期延迟,而不是1个周期,请参阅https://agner.org/optimize/指令表和微阵列PDF)。在AMD上,即使使用LEA eax,[rdx rcx*4]
在LEA之外,在任何寻址模式下使用RBP/R13作为基础总是需要disc 8/32
字节或dword,但我认为对于3分量寻址模式,实际的AGU并不慢。所以这只是代码大小的影响。
其他案例包括哪个英特尔微架构引入了ADC reg,0单uop特例?其中adc al, im8
的短格式2字节编码即使在像Skylake这样的现代uarch上也是2 uops,其中adc bl, im8
是1 uop。
因此,不仅adc reg,0
特例不适用于Sandybridge上的adc al,0
,通过Haswell、Broadwell和更新版本忘记(或选择不)优化编码解码到uops的方式。(当然,您可以使用3字节的Mod/RM编码手动编码adc al,0
,但html" target="_blank">汇编器将始终选择最短的编码,因此adc al,0
将默认组装为短形式。)只有字节寄存器的问题;adc eax,0
将使用操作码ModRM im8
3字节编码,而不是5字节操作码im32
。
对于op al、imm8的其他情况,唯一的区别是代码大小,它仅间接影响性能。(由于解码、uop缓存打包和I-cache未命中)。
有关代码大小的特殊情况的更多信息,请参阅x86/x64机器代码中的高尔夫技巧,如1字节的ecx与2字节的xchg edx、ecx。
添加rsp,8
可能需要额外的堆栈同步uop,如果自上次推送/pop/call/ret以来没有显式使用RSP或ESP(当然是沿着执行路径,而不是在静态代码布局中)。(Sandybridge微架构中的堆栈引擎是什么?)。这就是为什么像clang
这样的编译器使用虚拟推送或弹出来保留/释放单个堆栈插槽:为什么这个函数将RAX作为第一个操作推送到堆栈?
具体是: 注意,我关心的是旧的x86 linux CPU,而不是现代的x86_64 CPU,那里的分段工作方式不同。
2.1 通用 CPU 寄存器 CPU 的寄存器能够对少量的数据进行快速的存取访问。在 x86 指令集里,一个 CPU 有 八个通用寄存器:EAX, EDX, ECX, ESI, EDI, EBP, ESP 和 EBX。还有很多别的寄存器,遇 到的时候具体讲解。这八个通用寄存器各有不同的用途,了解它们的作用对于我们设计调试 器是至关重要的。让我们先简略的看一看每个寄存器和功能。最后我们将通过一个简单
我一直在学习汇编,并且我读到四个主要的x86通用寄存器(eax,ebx,ecx和edx)都有一个预期或建议的目的。例如,eax 是累加器寄存器,ecx 用作循环的计数器,依此类推。大多数编译器是否尝试将寄存器用于建议的目的,或者他们是否忽略了寄存器“应该”用于什么,而只是将值分配给下一个可用的寄存器? 此外,在查看x64寄存器时,我注意到额外添加了8个通用寄存器,如果忽略rbp、rsp、rsi和r
Vim提供了许多寄存器。可以将这些寄存器用作多个剪贴板。使用多个文件时,此功能非常有用。在本章中,将讨论以下主题内容 - 复制寄存器中的文本 粘贴寄存器中的文本 列出可用的寄存器 寄存器类型 1. 复制寄存器中的文本 对于复制,可以使用普通的命令,即并将其存储在寄存器中,可以使用以下语法 - 例如,要复制寄存器中的文本,请使用以下命令 - 2. 粘贴寄存器中的文本 从寄存器粘贴文本 - 例如,下面
当前的Perl 5虚拟机是一台堆栈机器。 它通过将操作保持在堆栈上来传递操作之间的值。 操作将值加载到堆栈上,执行他们需要执行的操作并将结果放回堆栈。 这很容易使用,但速度很慢。 要将两个数字相加,您需要执行三次堆栈推送和两次堆栈弹出。 更糟糕的是,堆栈必须在运行时增长,这意味着在您不想分配内存时分配内存。 因此,Parrot将打破虚拟机的既定传统,并使用寄存器架构,更类似于真实硬件CPU的架构。
处理器操作主要涉及处理数据。 该数据可以存储在存储器中并从其上访问。 然而,从存储器读取数据和将数据存储到存储器中会降低处理器的速度,因为它涉及通过控制总线向存储器存储单元发送数据请求并通过相同通道获取数据的复杂过程。 为了加速处理器操作,处理器包括一些内部存储器存储位置,称为registers 。 寄存器存储数据元素以便处理而无需访问存储器。 处理器芯片内置有限数量的寄存器。 处理器寄存器 IA