C++ 阵列初始化优化

C++ 阵列初始化优化,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

编译以下代码段时(clangx86-64
-O3

然而,对于小型阵列,它似乎想出了一个窍门

std::array<int, 3> test()
{
    std::array<int, 3> values {{0, 1, 2}};
    return values;
}
那个神奇的数字(
4294967296
)是从哪里来的?这本质上是一个可以通过某种方式将
重新解释为
int
数组的值吗?

a
std::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]
这样的东西来创建第二个大常量,而不是2x
movabs
。e、 g.参见clang使用movabs rcx的地方,9223372036854775807
lea-rax,[rcx+1]
分别在rcx和rax中具体化
INT64_MAX
INT64_MIN
,在需要两者的函数版本中。GCC只使用2x
movabs
,即使使用
-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