2017-05-23 18 views
10

는 다음과 같은 프로그램을 고려 :엄격한 앨리어싱, -ffast - 수학 및 SSE

$ 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 
:

#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없이 애플 연타 7.0.2 컴파일하는 경우를, 내가 예상 출력 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), ...을하면 잘 작동한다고 언급하는 것을 잊어 버렸습니다.

또한을 보면 Clang 3.8.1과 Clang 3.9 사이에서 동작이 변경된 것 같습니다. 후자는 cmpordps 명령을 제거합니다. GCC 7.1은 그것을 그대로두고있는 것 같습니다.

답변

12

이것은 엄격한 앨리어싱 문제는 아닙니다. the documentation of -ffast-math을 읽으면 문제가 표시됩니다.

빠른 계산 모드를 사용하도록 설정합니다. 이것은 __FAST_MATH__ 전 처리기 매크로를 정의하고 컴파일러가 부동 소수점 연산에 대한 공격적이고 잠재적으로 손실이있는 가정을하도록합니다. 이들은 다음을 포함한다 :

  • [...] 조작 NaNInf 같지 않은 부동 소수점에
  • 피연산자 및
  • [...]

-ffast-math 허용 컴파일러는 부동 소수점 숫자가 결코 NaN이라고 가정하지 않습니다 (-ffinite-math-only 옵션을 설정하기 때문에). 그 소리는 GCC의 옵션을 일치 시키려고하기 때문에, 우리는 더 나은 -ffinite-math-only가 무엇을 이해하는 GCC's option documentation에서 조금 읽을 수 있습니다

인수 및 결과가 NaN이 나 + -Infs없는 가정 부동 소수점 연산을위한 최적화를 허용합니다.

이 옵션은 IEEE 또는 ISO 규칙/사양의 정확한 구현에 의존하는 프로그램에 대해 올바르지 않은 결과가 발생할 수 있으므로 -O 옵션으로 절대로 사용하지 않아야합니다. 코드가 NaN 작업을 할 필요가있는 경우

그래서, 당신은 -ffast-math 또는 -ffinite-math-only 사용할 수 없습니다. 그렇지 않으면 옵티 마이저가 코드를 파괴 할 위험이 있습니다.

+0

허 나는 그것을 몰랐다. .. 고마워! – Timmmm