使用尽可能少的寄存器通常是个好主意吗?

时间:2016-11-03 15:06:24

标签: assembly x86 x86-64

This is my code.

我在x86程序集中编写程序,计算四个等级的平均值。我目前正在使用四个寄存器(RAXRBXRCXRDX)来保存我的.data部分中声明的四个等级。我还将quotremtotalans全部初始化为0.

我的一般方法是将四个寄存器一起添加并将总数存储在total变量中。我最初只是将总数保留在RAX,但后来我想将其存储在变量中,以便我可以重复使用RAXRDX

这是一个好主意还是我只为自己生成更多代码?我将RAXRDX寄存器重置为0,以便我可以将它们用于我的除法计算(总计/ 4)。我正在关注的书是使用RAXRDX寄存器,所以我认为这就是我应该做的。

代码未完成,因此忽略了最后一行的IDIV

segment .data
    a       dq  100
    b       dq  57
    c       dq  74
    d       dq  23
    quot    dq  0
    rem     dq  0
    total   dq  0
    ans     dq  0

segment .text
    global main

main:
    mov rax, [a]
    mov rbx, [b]
    mov rcx, [c]
    mov rdx, [d]

    add rax, rbx
    add rcx, rdx
    add rax, rcx
    mov [total], rax
    mov rax, 0
    mov rdx, 0
    mov rax, [total]
    mov rdx, 0

2 个答案:

答案 0 :(得分:5)

没有对错,除非你人为地限制自己的寄存器数量少于可用的寄存器,否则你就会添加操作码并使你的代码膨胀。仅使用编码操作所需的寄存器数量。

但是,如果要求发生变化并且您必须处理100个等级,请考虑将会发生什么。或者1000.或者N ..这可能激发你以不同的方式实现你的逻辑。也许考虑使用堆栈来存储成绩?

PS:从架构的角度来看,这里主要关注的是平衡溢出/恢复寄存器的缓存和操作码开销。这个决定在这里并不适用,因为你泄漏的任何数量的寄存器(手工编码)都应该在L1缓存中。实际上,当你的实现用完了寄存器而你开始不得不添加溢出操作码时。

答案 1 :(得分:2)

通常在性能方面,最好不要访问内存(尤其是L0缓存之外的内存)。

如果你有备用寄存器,暂时将值存储到它中比将它存储到存储器中更便宜(尽管该写入将被缓存并且下次读取将很有可能使用它,所以它不会伤害那么多阅读一些"新的"内存位置)。推送/弹出(堆栈)也是内存,因此将值存储到备用寄存器中也比堆栈上的临时存储更便宜。

然后再次使用算法破坏的寄存器越少,从其他地方调用该代码时,保存/恢复的次数就越少,其中您已经在寄存器中有值,因此资源丰富并且只使用尽可能少的寄存器是个好主意。

关于您的来源:

在您的代码中,mov [total],raxmov rax,0mov rax,[total]朝向end的整个三元组可以简化为仅第一条指令,这将更新" total"记忆。然后加载rax为零,然后用之前的总值加载它,即。删除这两个将只保持rax中的总值不变。

但是我会更进一步,保存更多的寄存器和浪费的指令,如下所示:

mov   rax, [a]
add   rax, [b]
add   rax, [c]
add   rax, [d]
; rax = total (can overflow for large a/b/c/d)

division - signed variant

mov   [total], rax   ; can be omitted, if you don't need [total] updated
cqo                  ; sign-extend rax into rdx:rax
; ^ your "mov rdx,0" is bug, as you want "idiv", total of 4x -1 is -4 => rdx should be -1
mov   rcx,4
idiv  rcx

; only rax, rdx and rcx are modified, [rax, rdx] contains result

除法 - 无符号变体(当a,b,c,d为正数,或者至少为#34;总数为#34;

mov   [total], rax   ; can be omitted, if you don't need [total] updated
; calculate remainder after division by 4 by copying low 2 bits of "total" into rdx
mov   edx,eax        ; 32b mov clears upper 32b of rdx!
and   edx,3          ; bit 0 and bit 1 of total is remainder after unsigned /4
; calculate quotient of usigned rax/4 (by shifting rax two bits right)
shr   rax,2

; only rax, and rdx are modified, [rax, rdx] contains result