Rozważmy następujący program:Strict aliasing, -ffast-matematyka i SSE
#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;
}
Jeśli mogę skompilować z Apple Clang 7.0.2 i bez -ffast-math
, uzyskać oczekiwane wyjście 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
Jednak po aktualizacji do 8.1.0 (przepraszam, nie mam pojęcia, która aktualna wersja Clang to odpowiada - Apple już nie publikuje tej informacji), -ffast-math
wydaje się łamać to:
$ 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
Podejrzewam, że dzieje się tak z powodu surowych reguł aliasingu lub czegoś w tym stylu. Czy ktoś może wyjaśnić to zachowanie?
Edycja: Zapomniałem wspomnieć, że jeśli robisz nans = { std::nanf(nullptr), ...
, to działa dobrze.
Wygląda również na godbolt wydaje się, że zachowanie zmieniło się pomiędzy Clang 3.8.1 a Clang 3.9 - ten ostatni usuwa instrukcję cmpordps
. Wydaje się, że GCC 7.1 go zostawia.
Huh Nie wiedziałem tego ... Dzięki! – Timmmm