严格别名,-ffast-math和SSE

时间:2017-05-23 11:51:23

标签: c++ clang sse strict-aliasing fast-math

考虑以下计划:

#include <iostream>
#include <cmath>
#include <cstring>
#include <xmmintrin.h>

using namespace std;

int main()
{
    // 4 float32s.
    __m128 nans;
    // Set them all to 0xffffffff which should be NaN.
    memset(&nans, 0xff, 4*4);

    // cmpord should return a mask of 0xffffffff for any non-NaNs, and 0x00000000 for NaNs.
    __m128 mask = _mm_cmpord_ps(nans, nans);
    // AND the mask with nans to zero any of the nans. The result should be 0x00000000 for every component.
    __m128 z = _mm_and_ps(mask, nans);

    cout << z[0] << " " << z[1] << " " << z[2] << " " << z[3] << endl;

    return 0;
}

如果我使用带有和不带-ffast-math的Apple Clang 7.0.2进行编译,我会得到预期的输出0 0 0 0

$ clang --version
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin14.5.0
Thread model: posix

$ clang test.cpp -o test
$ ./test
0 0 0 0 

$ clang test.cpp -ffast-math -o test
$ ./test 
0 0 0 0

然而,在更新到8.1.0之后(抱歉我不知道Clang的哪个实际版本对应 - Apple不再发布该信息),-ffast-math似乎打破了这个:

$ clang --version
Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

$ clang test.cpp -o test
$ ./test
0 0 0 0 

$ clang test.cpp -ffast-math -o test
$ ./test 
nan nan nan nan

我怀疑这是因为严格的别名规则或类似的东西。任何人都可以解释这种行为吗?

编辑:我忘了提及如果你做nans = { std::nanf(nullptr), ...它可以正常工作。

同时查看this,似乎Clang 3.8.1和Clang 3.9之间的行为发生了变化 - 后者删除了cmpordps指令。 GCC 7.1似乎留在了它。

1 个答案:

答案 0 :(得分:14)

这不是严格的别名问题。如果您阅读the documentation of -ffast-math,则会看到您的问题:

  

启用快速数学模式。这定义了__FAST_MATH__预处理器宏,并让编译器对浮点数学做出积极的,可能有损的假设。其中包括:

     
      
  • [...]
  •   
  • 浮点运算的操作数不等于NaNInf
  •   
  • [...]
  •   

-ffast-math允许编译器假设浮点数永远不是NaN(因为它设置了-ffinite-math-only选项)。由于clang尝试匹配gcc的选项,我们可以从GCC's option documentation读一点,以便更好地理解-ffinite-math-only的作用:

  

允许优化浮点运算,假设参数和结果不是NaN或+ -Infs。

     

任何-O选项都不应该打开此选项,因为它可能导致程序的输出不正确,这取决于IEEE或ISO规则/规范的精确实现。

因此,如果您的代码需要与NaN一起使用,则无法使用-ffast-math-ffinite-math-only。否则,您将面临优化程序破坏代码的风险,正如您在此处看到的那样。