【问题标题】:GCC won't optimize integer arithmetic expressionGCC 不会优化整数算术表达式
【发布时间】:2017-08-26 08:16:10
【问题描述】:
int f(int x, int y) {
    return 20 * (x - 10) + 50 * (x + 5);
}

int f_expected(int x, int y) {
    return 70 * x + 50;
}

generated code 是:

f(int, int):
        lea     eax, [rdi-50+rdi*4]
        add     edi, 5
        imul    edi, edi, 50
        lea     eax, [rdi+rax*4]
        ret
f_expected(int, int):
        imul    eax, edi, 70
        add     eax, 50
        ret

我希望 f 编译为 f_expected。我在 GCC 7 上尝试了 -O3-Ofast我正在寻找哪个标志,确切地说(如果有的话)? clang 和 icc 在 -O3 下生成预期的代码。

供参考,clang code:

f(int, int):
        imul    eax, edi, 70
        add     eax, 50
        ret

f_expected(int, int):
        imul    eax, edi, 70
        add     eax, 50
        ret

【问题讨论】:

  • "我希望 f 被编译成 f_expected" 为什么?
  • 我还有一些其他代码,可以证明这种类型的优化(我分析、手动优化等)可以加快执行速度。此外,clang 没有问题。 GCC 在这些类型的优化方面特别糟糕,还是我只是用错了?
  • 有点神秘的是,如果你使用-fwrapv,GCC 就会正确 - 是的,一个禁止某些优化的标志。
  • 最好不要,因为它与整个故事相去甚远。因为这只是一个完全随机的发现,所以这是一个不应该奏效的解决方案。它更多地证明了 GCC 中的错误,而不是解决方案。
  • @harold 我不太喜欢 GCC 和编译器开发,但 docs 的措辞对我来说听起来非常好:This flag enables some optimizations and disables others。没有太多背景,这对我来说很自然(它要么是:A 我们假设一些数学行为/不是,要么 B 我们假设两种不同的数学行为之一;我不确定这里是什么情况,显然 B) 会指示更多的那种 打开一些;关掉别人的东西

标签: c++ gcc optimization compilation arithmetic-expressions


【解决方案1】:

发生这种情况是因为 GCC 害怕引入原始版本中不存在的有符号整数溢出(这将导致程序中的未定义行为)。您可以通过将 -fwrapv 添加到 CFLAGS 来强制 GCC 允许签名溢出,但这会带来其他问题(例如,无法优化某些循环)。

$ gcc tmp.c -S -o- -O2
    ...
    leal    -50(%rdi,%rdi,4), %eax
    movl    $50, %edx
    addl    $5, %edi
    imull   %edx, %edi
    leal    (%rdi,%rax,4), %eax
    ret
$ gcc tmp.c -S -o- -O2 -fwrapv
    ...
    movl    %edi, %eax
    movl    $70, %edx
    imull   %edx, %eax
    addl    $50, %eax
    ret

现在 Clang 能够以某种方式找出原始代码中不存在 UB,因此这可能是 GCC 中缺少的优化(我鼓励您向 their Bugzilla 报告)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-09
    • 2020-04-02
    • 2011-01-25
    • 1970-01-01
    • 2017-12-19
    • 1970-01-01
    相关资源
    最近更新 更多