Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么VS会用imul rax,rax,0代替简单的移动?_C++_Assembly_64 Bit - Fatal编程技术网

C++ 为什么VS会用imul rax,rax,0代替简单的移动?

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

我正在查看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
为什么它使用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