首页 > 解决方案 > 编译器可以用双打简化表达式吗?

问题描述

我正在阅读这里的代码:

 template<typename T> T Math::AngRound(T x) {
    static const T z = 1/T(16);
    if (x == 0) return 0;
    GEOGRAPHICLIB_VOLATILE T y = abs(x);
    // The compiler mustn't "simplify" z - (z - y) to y
    y = y < z ? z - (z - y) : y;
    return x < 0 ? -y : y;
  }

在哪里和T是。doubleGEOGRAPHICLIB_VOLATILEvolatile

我想知道,编译器是否允许“简化”z - (z - y)y,这是否被阻止volatile?如果相关,我对 C++17 标准感兴趣。

检查程序集的 clang 表明 withoutvolatile -O3不会导致z - (z - y)to的简化y

另一方面,icc 在这两种情况下都简化了代码:https ://godbolt.org/z/rz7erdhev 。如果使用 volatile,它会增加额外的读取,但不会增加任何实际计算。

标签: c++c++17

解决方案


你正在寻找-ffast-math. 这是一个简单的演示:

$ cat main.c
int main(int argc, char **argv)
{
    double x=argc+0.5;
    return x-(x-27.5);
}

首先使用默认的浮点支持编译它:

$ gcc -g -O3 main.c -o main
$ objdump -S -D main > main.default
$ sed -n "296,310p;311q" main.default
int main(int argc, char **argv)
{
    double x=argc+0.5;
 4f0:   66 0f ef c0             pxor   %xmm0,%xmm0
 4f4:   f2 0f 2a c7             cvtsi2sd %edi,%xmm0
 4f8:   f2 0f 58 05 b8 01 00    addsd  0x1b8(%rip),%xmm0        # 6b8 <_IO_stdin_used+0x8>
 4ff:   00 
    return x-(x-27.5);
 500:   66 0f 28 c8             movapd %xmm0,%xmm1
 504:   f2 0f 5c 0d b4 01 00    subsd  0x1b4(%rip),%xmm1        # 6c0 <_IO_stdin_used+0x10>
 50b:   00 
 50c:   f2 0f 5c c1             subsd  %xmm1,%xmm0
 510:   f2 0f 2c c0             cvttsd2si %xmm0,%eax
}
 514:   c3                      retq   

现在浮点快速支持编译它:

$ gcc -g -O3 -ffast-math main.c -o main
$ objdump -S -D main > main.opt
$ sed -n "308,314p;315q" main.opt
int main(int argc, char **argv)
{
    double x=argc+0.5;
    return x-(x-27.5);
}
 510:   b8 1b 00 00 00          mov    $0x1b,%eax
 515:   c3                      retq   

推荐阅读