按照每个通用寄存器的用途编写x86汇编是否必要或更容易

J.S*_*ith 3 c++ optimization x86 assembly cpu-registers

一般来说,按照每个寄存器的用途编码x86汇编是否必要或更容易?

x86架构中的寄存器每个都是首先设计用于特殊目的,但现代编译器似乎并不关心它们的使用(除非在某些特殊条件下,例如REP MOV或MUL).

那么,取决于每个寄存器的用途,代码是更容易还是更优化?(不管与某些寄存器相同的特殊指令(或编码))

例如(我可以改用REP MOVSB或LODSB STOSB,但只是为了演示):

第一个代码:

LEA ESI,[AddressOfSomething]
LEA EDI,[AddressOfSomethingElse]
MOV ECX,NUMBER_OF_LOOP
LoopHere:
MOV AL,[ESI]
ADD AL,8
MOV [EDI],AL
ADD ESI,1
ADD EDI,1
CMP AL,0
JNZ LoopHere
TheEnd:
;...
Run Code Online (Sandbox Code Playgroud)

第二代码:

LEA ECX,[AddressOfSomething]
LEA EDX,[AddressOfSomethingElse]
MOV EBX,NUMBER_OF_LOOP
LoopHere:
MOV AL,[ECX]
ADD AL,8
MOV [EDX],AL
ADD ECX,1
ADD EDX,1
CMP AL,0
JNZ LoopHere
TheEnd:
;...
Run Code Online (Sandbox Code Playgroud)

我使用的编译器 - Visual Studio 2015在执行这样的任务时通常使用第二种方法,它不使用寄存器取决于它的用途,相反,编译器只根据其"volatile"选择使用哪个寄存器或"非易失性"特征(在调用函数后).因此,所有高级编程语言编程软件反汇编都使用第二种方法.

另一个有趣的事实是,在ARM语言中,GPR都具有相同的用途,并且被命名为R0-R7,这意味着当代码使用它时,代码将更类似于第二代码.

总而言之,我的观点是这两个代码使用相同的指令,因此无论我使用哪个寄存器,它都应该具有相同的速度.但我是对的吗?哪个代码更容易编码?

Mar*_*oom 5

遵循每个登记册的目的主要是:

  • 代码密度

    例如,使用A寄存器1通常会减少常用操作(如移动,算术,逻辑和IO 2)的代码大小.
    使用C寄存器进行计数可以利用jcxz指令族,避免显式比较.
    movsd类似的是非常"密集"的指令,它们执行复杂的操作,否则将需要大量的代码.

    然而,由于x86明显是CISC,因此代码密度并不意味着"更快",复杂指令可能比同等系列的更简单指令需要更多时间来执行3.

  • 可读性

    rep movsd有效的指令是编码将数据从源移动到目的地的循环的"高级"方式.
    解析循环

    push eax
    pushf
    .loop:
      mov eax, DWORD [esi]
      mov DWORD [es:edi], eax
    
      add esi, 4*(1-D*2)
      add edi, 4*(1-D*2)
    
      dec ecx
      jnz .loop
    popf
    pop eax
    
    Run Code Online (Sandbox Code Playgroud)

    要困难得多.

  • 惯用语编程

    采用SP作为堆栈指针是由很多的指令(假定call,ret,push,...).
    可以避免使用SP堆栈指针,但它不会非常惯用(也不高效).

  • 数据移动量减少

    在实模式中,只有少数寄存器可用作基址(其中一个是B寄存器).从头开始
    保持地址B将避免以后将它们移入其中.虽然寄存器寄存器移动今天不需要执行单元,但它们使源更难以读取4.

大多数惯用寄存器用法今天已经放宽了5,因为太多的特定用途寄存器会减少编译器可以做的优化(并且溢出到堆栈上的代价很高).

CPU非常复杂,如果您想编写速度代码,那么您应该只考虑速度指标.惯用寄存器的使用不是其中之一,因为有一点没有单一A,B或者C在微架构层面注册,所以"注册"程序员看到它们只是一个人类概念(好吧,和前端概念) ).


1在其形式AL,AX,EAX,RAX
2 mov A, [mem]使用操作码A0A1,而mov B, [mem]使用8A 1E8B 1E.对于add和类似的情况也是如此.in,out,div,mul强制使用A.
3但不要取和解码.
4数据移入寄存器是否有相当于"意大利面条代码"?
5考虑例如各种寻址模式或imul指令