我正在查看为这个简单的x64程序生成的程序集Visual Studio:
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如何更有效率?
最佳答案
卡马奇
原因是因为程序集正在计算数组中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
指令。所有这些都解析为
arr[0].b = 2
。我认为您没有进行积极的优化。在进行直接编译(不进行优化,调试等)时,编译器不会对寻址进行任何假设。
与c比较
在具有
clang 3.9.0
并且没有优化标志的OS X(El Capitan)上,一旦在数组中实例化了Point
对象,对.b = 2
的分配就很简单:mov dword ptr [rbp - 44], 2
在这种情况下,
clang
非常了解偏移量,并在默认优化过程中解析地址。关于c++ - 为什么VS imul rax,rax,0而不是简单的举动?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37629283/