为什么g ++使用movabs和一个奇怪的常量来进行简单的缩减?

ein*_*ica 5 c++ assembly g++ reduction accumulate

我正在编译这个简单的程序:

#include <numeric> 

int main()
{
    int numbers[] = {1, 2, 3, 4, 5};
    auto num_numbers = sizeof(numbers)/sizeof(numbers[0]);
    return std::accumulate(numbers,  numbers + num_numbers, 0);
}
Run Code Online (Sandbox Code Playgroud)

它将整数1到5相加并返回该总和(即15).

我意识到在实现中std::accumulate可能会有一些技巧,但是,这仍然非常简单.尽管如此,我在编译时(在GodBolt上)我得到的结果让我感到惊讶.

随着-O3C++是一种面向编译时计算的语言,我得到了预期的结果:

main:
        mov     eax, 15
        ret
Run Code Online (Sandbox Code Playgroud)

但是如果我继续-O2- 仍然是一些重要的优化 - 不仅我没有得到这个编译时计算,但我看到这个奇怪的程序集:

main:
        movabs  rax, 8589934593
        lea     rdx, [rsp-40]
        mov     ecx, 1
        mov     DWORD PTR [rsp-24], 5
        mov     QWORD PTR [rsp-40], rax
        lea     rsi, [rdx+20]
        movabs  rax, 17179869187
        mov     QWORD PTR [rsp-32], rax
        xor     eax, eax
        jmp     .L3
.L5:
        mov     ecx, DWORD PTR [rdx]
.L3:
        add     rdx, 4
        add     eax, ecx
        cmp     rdx, rsi
        jne     .L5
        ret
Run Code Online (Sandbox Code Playgroud)

现在.L5,.L3我明白了.令人惊讶的是这些奇怪的movabs指示,来往rax.他们是什么意思,为什么他们在那里?

PS - 我在没有-march设置的x86_64上使用GCC 8.2编译.如果我加上-march=skylake- -O3也搞砸了!编辑:这似乎是GCC的回归,请参阅我的GCC错误报告.谢谢@FlorianWeimer!

Flo*_*mer 6

8589934593是十六进制的0x200000001,17179869187是0x400000003.这两movabs条指令只是将两个int常量分别加载到一个64位寄存器中,用于初始化堆栈上的数组.您可以使用禁用此GCC优化-fno-store-merging,然后您将获得类似这样-O2的数组初始化:

movl    $1, -40(%rsp)
…
…
movl    $2, -36(%rsp)
…
movl    $3, -32(%rsp)
movl    $4, -28(%rsp)
movl    $5, -24(%rsp)
Run Code Online (Sandbox Code Playgroud)

顺便说一句,缺乏对单个常量的优化看起来像GCC回归.我没有看到GCC 6.3.它实际上可能与商店合并有关,我认为这不是GCC 6的一部分.