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

Posted

技术标签:

【中文标题】为啥 g++ 使用 movabs 和一个奇怪的常量来进行简单的缩减?【英文标题】:Why does g++ use movabs, and with a weird constant, for a simple reduction?为什么 g++ 使用 movabs 和一个奇怪的常量来进行简单的缩减? 【发布时间】:2019-03-11 15:55:19 【问题描述】:

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

#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);

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

我意识到std::accumulate 在实现中可能会有一些技巧,但这仍然非常简单。不过,我对我得到的 when compiling this(在 GodBolt 上)感到惊讶。

有了-O3,并且 C++ 是一种面向编译时计算的语言,我得到了预期:

main:
        mov     eax, 15
        ret

但如果我继续使用-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

现在.L5.L3 我明白了。令人惊讶的是这些奇怪的movabs 指令,往返于rax。它们是什么意思,为什么会出现?

PS - 我在 x86_64 上使用 GCC 8.2 编译,没有设置 -march。如果我添加-march=skylake - -O3 也会搞砸! 编辑:这似乎是 GCC 中的回归,请参阅我的 GCC bug report。谢谢@FlorianWeimer!

【问题讨论】:

提示:将数字转换为十六进制 【参考方案1】:

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

movl    $1, -40(%rsp)
…
…
movl    $2, -36(%rsp)
…
movl    $3, -32(%rsp)
movl    $4, -28(%rsp)
movl    $5, -24(%rsp)

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

【讨论】:

提交的关于回归的错误报告 - 请参阅我的编辑中的链接。如果您能够将其标记为“已确认”,我将不胜感激。

以上是关于为啥 g++ 使用 movabs 和一个奇怪的常量来进行简单的缩减?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能使用常量而不是 this.item.number?

为啥不显示消息框?

使用静态/常量 ON 子句时出现奇怪的 MERGE 行为

windows环境下gcc/g++ 编译器 乱码问题解决

为啥我不能在 switch 语句中使用元组常量作为案例

为啥GCC在实现整数除法时使用乘以一个奇怪的数字?