C++ 为什么VS会用imul rax,rax,0代替简单的移动?
我正在查看Visual Studio为这个简单的x64程序生成的程序集:C++ 为什么VS会用imul rax,rax,0代替简单的移动?,c++,assembly,64-bit,C++,Assembly,64 Bit,我正在查看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
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
为什么它使用imul-rax,rax,0而不是简单的mov-rax,0,甚至是xor-rax,rax?imul如何提高效率(如果有的话?Kamac
原因是程序集正在计算数组中恰好位于堆栈上的点
对象的偏移量,以及变量b
的偏移量
具有三(3)个操作数状态的imul英特尔文档:
三操作数形式-此形式需要目标操作数(
第一个操作数)和两个源操作数(第二个和第三个)
操作数)。这里,第一个源操作数(可以是
通用寄存器或内存位置)乘以
第二个源操作数(立即数)。中间产品
(第一个源操作数大小的两倍)被截断并存储
在目标操作数(通用寄存器)中
在您的例子中,它是计算数组中对象的偏移量,从而寻址堆栈上的第一个(第零个)点
位置。解决该问题后,将添加.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
指示。所有这些解析为arr[0]。b=2
我认为你没有进行积极的优化编译。当进行直接编译(无优化、调试等)时,编译器不会对寻址做出任何假设
与叮当声的比较
在具有clang3.9.0
且无优化标志的OS X(El Capitan)上,一旦点
对象在数组中实例化,则.b=2
的赋值简单如下:
mov dword ptr [rbp - 44], 2
在这种情况下,clang
在默认优化过程中非常聪明地处理偏移量和解析寻址 Kamac
原因是程序集正在计算数组中恰好位于堆栈上的点
对象的偏移量,以及变量b
的偏移量
具有三(3)个操作数状态的imul英特尔文档:
三操作数形式-此形式需要目标操作数(
第一个操作数)和两个源操作数(第二个和第三个)
操作数)。这里,第一个源操作数(可以是
通用寄存器或内存位置)乘以
第二个源操作数(立即数)。中间产品
(第一个源操作数大小的两倍)被截断并存储
在目标操作数(通用寄存器)中
在您的例子中,它是计算数组中对象的偏移量,从而寻址堆栈上的第一个(第零个)点
位置。解决该问题后,将添加.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
指示。所有这些解析为arr[0]。b=2
我认为你没有进行积极的优化编译。当进行直接编译(无优化、调试等)时,编译器不会对寻址做出任何假设
与叮当声的比较
在具有clang3.9.0
且无优化标志的OS X(El Capitan)上,一旦点
对象在数组中实例化,则.b=2
的赋值简单如下:
mov dword ptr [rbp - 44], 2
在这种情况下,
clang
在默认优化过程中非常聪明地处理偏移量和解析寻址 没有解释为什么编译器不只是mov dword ptr[rbp+4],而是2
。@EOF想象它是arr[10]。b
。它需要将点的大小
乘以10
,以获得数组元素的偏移量。@如果是imul rax,rax,10
@Barmar:如果是arr[10].b
,则这将是越界访问的未定义行为。别跟我耍花招,你一点也不在行。@EOF的要点是,它只是天真地将索引放入imul
指令中。如果对代码进行优化,它可能会做得更好。没有解释为什么编译器不只是mov dword ptr[rbp+4],而是2
。@EOF想象它是arr[10]。b
。它需要将点的大小
乘以10
,以获得数组元素的偏移量。@如果是imul rax,rax,10
@Barmar:如果是arr[10].b
,则这将是越界访问的未定义行为。别跟我耍花招,你一点也不在行。@EOF的要点是,它只是天真地将索引放入imul
指令中。如果对代码进行了优化,它可能会做得更好。请尝试使用优化开关编译。我尝试过不使用优化和/02,但它仍然使用imul rax,rax,0。通过全面优化,我甚至无法让它实际向arr[0]写入任何内容,它将所有内容都存储为临时变量或类似的内容。您的VS似乎与我的不一样。这完全不会像预期的那样使用/O2生成代码。重新调整代码,使优化器无法删除分配,会产生预期的mov dword ptr[rsp+24小时],2。imul仅在未优化的版本中生成。请尝试使用优化开关编译。我尝试过不使用优化和/02,但它仍然使用imul rax,rax,0。通过全面优化,我甚至无法让它实际向arr[0]写入任何内容,它将所有内容都存储为临时变量或类似的内容。您的VS似乎与我的不一样。这完全不会像预期的那样使用/O2生成代码。重新调整代码,使优化器无法删除赋值,将生成mov dword