为什么通过指针进行int加法比通过指针进行int乘法少一条x86指令?

我有以下 C/C++ 代码(编译器资源管理器链接):

void update_mul(int *x, int *amount) { 
    *x *= *amount; 
}

void update_add(int *x, int *amount) { 
    *x += *amount; 
}

在 clang 和 gcc 编译为 C 或 C++ 并至少-O1启用的情况下,以上转换为以下程序集:

update_mul:                             # @update_mul
        mov     eax, dword ptr [rdi]
        imul    eax, dword ptr [rsi]
        mov     dword ptr [rdi], eax
        ret
update_add:                             # @update_add
        mov     eax, dword ptr [rsi]
        add     dword ptr [rdi], eax
        ret

似乎添加它正在做类似的事情:

register = *amount;
*x += register;

但是对于乘法,它正在做:

register = *x;
register *= *amount;
*x = register;

为什么乘法需要额外的加法指令,或者不需要但只是更快?

回答

在IA-32体系结构规范(替换的单页链路)示出了是根本不存在编码IMUL其中目的地(第一自变量)是操作数的存储器:

Encoding               | Meaning
IMUL r/m8*             | AX ? AL ? r/m byte.
IMUL r/m16             | DX:AX ? AX ? r/m word.
IMUL r/m32             | EDX:EAX ? EAX ? r/m32.
IMUL r/m64             | RDX:RAX ? RAX ? r/m64.
IMUL r16, r/m16        | word register ? word register ? r/m16.
IMUL r32, r/m32        | doubleword register ? doubleword register ? r/m32.
IMUL r64, r/m64        | Quadword register ? Quadword register ? r/m64.
IMUL r16, r/m16, imm8  | word register ? r/m16 ? sign-extended immediate byte.
IMUL r32, r/m32, imm8  | doubleword register ? r/m32 ? sign- extended immediate byte.
IMUL r64, r/m64, imm8  | Quadword register ? r/m64 ? sign-extended immediate byte.
IMUL r16, r/m16, imm16 | word register ? r/m16 ? immediate word.
IMUL r32, r/m32, imm32 | doubleword register ? r/m32 ? immediate doubleword.
IMUL r64, r/m64, imm32 | Quadword register ? r/m64 ? immediate doubleword.

  • 历史原因:`imul` 的多操作数形式是新的,有 186(立即数)和 386(r,r/m)。与 `add` 不同,来自原始 8086 的 ALU 指令之一因此具有 `r, r/m` 和 `r/m, r` 形式的操作码。与其他一些限制/设计选择不同,没有内存目标乘法对于 x86 来说不是一个明显的问题。在现实生活中,您总是希望内联像这样的小函数,并且通常至少有一个操作数已经在寄存器中。

以上是为什么通过指针进行int加法比通过指针进行int乘法少一条x86指令?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>