C++ 阵列初始化优化
编译以下代码段时(clangx86-64C++ 阵列初始化优化,c++,x86-64,compiler-optimization,calling-convention,abi,C++,X86 64,Compiler Optimization,Calling Convention,Abi,编译以下代码段时(clangx86-64-O3) 然而,对于小型阵列,它似乎想出了一个窍门 std::array<int, 3> test() { std::array<int, 3> values {{0, 1, 2}}; return values; } 那个神奇的数字(4294967296)是从哪里来的?这本质上是一个可以通过某种方式将重新解释为int数组的值吗?astd::array在您的实现中是96位宽的。因此,ABI声明它应该以RAX+RDX
-O3
)
然而,对于小型阵列,它似乎想出了一个窍门
std::array<int, 3> test()
{
std::array<int, 3> values {{0, 1, 2}};
return values;
}
那个神奇的数字(4294967296
)是从哪里来的?这本质上是一个可以通过某种方式将重新解释为int
数组的值吗?astd::array
在您的实现中是96位宽的。因此,ABI声明它应该以RAX+RDX的低32位(也称为EDX)的形式返回
4294967296是232,十六进制是$1'0000'0000
。因此,movabs
在RAX的低位32位存储0,在RAX的高位存储1。mov
将2存储在EDX中(这正是您想要的)。D'oh!感谢sasha提出的编辑建议,感谢caf这么做。有趣的事实:有了BMI2,可能更理想的编译方法是mov-edx,2
,然后创建1@PeterCordes我认为优化器没有发现这种特殊的可能性是可以原谅的——它非常特定于特定的数据模式!clang确实会寻找像lear64、[reg+disp8]
这样的东西来创建第二个大常量,而不是2xmovabs
。e、 g.参见clang使用movabs rcx的地方,9223372036854775807
lea-rax,[rcx+1]
分别在rcx和rax中具体化INT64_MAX
和INT64_MIN
,在需要两者的函数版本中。GCC只使用2xmovabs
,即使使用-Os
GCC和clang在某些情况下也会寻求类似的优化:比如使用子rax,120
创建第二个邻近常量,而不是使用另一个movabs
。不过他们不太擅长旋转,是的,他们可能也没有寻找旋转的可能性:POn Godbolt你可以将鼠标移到数字上,以十六进制显示。如果您经常查看asm,您将习惯于4294967…
大约为2^32,因此您应该查看十六进制以查看上/下32位。(或者对于刚好低于2^32的数字,它实际上是一个负32位整数。)
test(): # @test()
mov rax, rdi
mov ecx, dword ptr [rip + .L__const.test().values+16]
mov dword ptr [rdi + 16], ecx
movups xmm0, xmmword ptr [rip + .L__const.test().values]
movups xmmword ptr [rdi], xmm0
ret
.L__const.test().values:
.long 0 # 0x0
.long 1 # 0x1
.long 2 # 0x2
.long 3 # 0x3
.long 4 # 0x4
std::array<int, 3> test()
{
std::array<int, 3> values {{0, 1, 2}};
return values;
}
test(): # @test()
movabs rax, 4294967296
mov edx, 2
ret