为什么VS模拟rax,rax,0而不是简单的移动

Why VS does imul rax,rax,0 instead of simple move?

本文关键字:rax 简单 移动 VS 模拟 为什么      更新时间:2023-10-16

我正在查看Visual Studio为这个简单的x64程序生成的程序集:

struct Point {
int a, b;
Point() {
a = 0; b = 1;
}
};
int main(int argc, char* argv[])
{
Point arr[3];
arr[0].b = 2;
return 0;
}

当它遇到arr[0].b=2时,它会生成以下内容:

mov eax, 8
imul rax, rax, 0
mov dword ptr [rbp+rax+4],2

为什么它要做模拟rax,rax,0而不是简单的mov rax,0,甚至xor rax,rax?如果有的话,imul是如何更高效的?

Kamac

原因是程序集正在计算数组中恰好在堆栈上的Point对象的偏移量,以及到变量b的偏移量。

带三(3)个操作数状态的imul英特尔文档:

三操作数形式--此形式需要一个目标操作数(第一个操作数)和两个源操作数(第二个和第三个操作数)。这里,第一个源操作数(可以是通用寄存器或存储器位置)乘以第二个源操作数(立即数)。中间产品(第一个源操作数大小的两倍)被截断并存储在目标操作数(通用寄存器)中。

在您的情况下,它计算数组中对象的偏移量,从而寻址堆栈上的第一个(第零个)Point位置。在解决了该问题之后,然后添加.b的偏移量,该偏移量是+4。所以分解:

mov  eax,8                   ; prepare to offset into the Point array
imul rax, rax, 0             ; Calculate which Point object is being referred to
mov  dword ptr [rbp+rax+4],2 ; Add the offset to b and move value 2 in

指令。所有这些都解析为CCD_ 7。

我认为你没有进行积极的优化编译。当进行直接编译(没有优化、调试等)时,编译器不会对寻址做出任何假设。

与clang的比较

在带有clang 3.9.0且没有优化标志的OS X(El Capitan)上,一旦Point对象在数组中实例化,.b = 2的赋值就简单地为:

mov dword ptr [rbp - 44], 2

在这种情况下,clang在偏移方面非常聪明,并在默认优化期间解决了寻址问题。