2013-07-04 41 views
0

這個錯誤可能實際上並沒有顯示在所有的機器上,但在我的我跑下面的代碼,並得到了輸出(注意值-1.#IND00)?SSE移位指令在隨後的指令中導致奇怪的輸出(-1。#IND00)?

values int:: 4 2 
shifts:: 4 2 
result: : 64 32 
input 1 HADDPD:: 10.000000 -1.#IND00 
input 2 HADDPD:: 13.000000 10.000000 
result of HADDPD:: -1.#IND00 23.000000 

如果我註釋掉

__m64 PSLLDm64_IN = _mm_set_pi32(2,4); 
    __m64 PSLLDm64_C = _mm_set_pi32(2,4);//could this be the culprit? 
    __m64 PSLLDm64_r = PSLLD(PSLLDm64_IN, PSLLDm64_C); 

    print_2_32_bit_int("values int:" , PSLLDm64_IN); 
    print_2_32_bit_int("shifts:", PSLLDm64_C); 
    print_2_32_bit_int("result: ", PSLLDm64_r); 

我得到...

input 1 HADDPD:: 10.000000 100.000000 
input 2 HADDPD:: 13.000000 10.000000 
result of HADDPD:: 110.000000 23.000000 

我想知道如果線32,其中__m64 PSLLDm64_C = _mm_set_pi32(2,4);可以搞砸了?

繼承人完整的代碼(它使用g ++與-msse3 -mmmx一起運行)並非所有的頭文件都是非常必要的。

#include <xmmintrin.h> 
#include <emmintrin.h> 
#include <pmmintrin.h> 
#include <stdio.h> 
#include <stdint.h> 
#include <iostream> 

void print_2_64_bit_doubles(const char * label, __m128d m64_r) 
{ 
    double *val = (double *) &m64_r; 
    printf("%s: %f %f\n", 
     label, val[0], val[1]); 
} 
void print_2_32_bit_int(const char * label, __m64 m32_r) 
{ 
    int *val = (int *) &m32_r; 
    printf("%s: %d %d\n", 
     label, val[0], val[1]); 
} 
__m128d HADDPD(__m128d __X, __m128d __Y) 
{ 
    return _mm_hadd_pd (__X, __Y); 
} 
__m64 PSLLD(__m64 __m, __m64 __count) 
{ 
    return _mm_sll_pi32 (__m, __count); 
} 
int main() 
{ 
    //PSLLD------------------------------------------------------------------- 
    __m64 PSLLDm64_IN = _mm_set_pi32(2,4); 
    __m64 PSLLDm64_C = _mm_set_pi32(2,4); 
    __m64 PSLLDm64_r = PSLLD(PSLLDm64_IN, PSLLDm64_C); 

    print_2_32_bit_int("values int:" , PSLLDm64_IN); 
    print_2_32_bit_int("shifts:", PSLLDm64_C); 
    print_2_32_bit_int("result: ", PSLLDm64_r); 
    //HADDPD------------------------------------------------------------------ 
    double C1 = 10; 
    double D = C1*C1; 
    double x = 10; 
    double y = 13; 

    __m128d HADDPDm64_1 = _mm_set_pd(D,C1); 
    __m128d HADDPDm64_2 = _mm_set_pd(x,y); 
    __m128d HADDPDm64_r = HADDPD(HADDPDm64_1, HADDPDm64_2); 

    print_2_64_bit_doubles("input 1 HADDPD:", HADDPDm64_1); 
    print_2_64_bit_doubles("input 2 HADDPD:", HADDPDm64_2); 
    print_2_64_bit_doubles("result of HADDPD:", HADDPDm64_r); 

    return 0; 
} 

編輯:這是與G ++ 4.4.1 -msse -msse2 -msse3 -msse4

#include <xmmintrin.h> 
#include <emmintrin.h> 
#include <pmmintrin.h> 
#include <mmintrin.h> 
#include <stdio.h> 
#include <stdint.h> 


void print_2_64_bit_doubles(const char * label, __m128d m64_r) 
{ 
    double *val = (double *) &m64_r; 
    printf("%s: %f %f\n", 
     label, val[0], val[1]); 
} 
void print_2_32_bit_int(const char * label, __m64 m32_r) 
{ 
    int *val = (int *) &m32_r; 
    printf("%s: %d %d\n", 
     label, val[0], val[1]); 
} 
void print_1_32_bit_int(const char * label, __m64 m32_r) 
{ 
    int *val = (int *) &m32_r; 
    printf("%s: %d \n", 
     label, val[0]); 
} 
__m128d HADDPD(__m128d __X, __m128d __Y) 
{ 
    return _mm_hadd_pd (__X, __Y); 
} 
__m64 PSLLD(__m64 __m, __m64 __count) 
{ 
    return _mm_sll_pi32 (__m, __count); 
} 
int main() 
{ 
    //PSLLD------------------------------------------------------------------- 
    __m64 PSLLDm64_IN = _mm_set_pi32(2,4); 
    long long __i = 2; 
    __m64 PSLLDm64_C = (__m64)(__i); 
    __m64 PSLLDm64_r = PSLLD(PSLLDm64_IN, PSLLDm64_C); 
    _mm_empty(); 

    print_2_32_bit_int("values int:" , PSLLDm64_IN); 
    print_1_32_bit_int("shifts:", PSLLDm64_C); 
    print_2_32_bit_int("result: ", PSLLDm64_r); 
    //HADDPD------------------------------------------------------------------ 
    double C1 = 10; 
    double D = C1*C1; 
    double x = 10; 
    double y = 13; 

    __m128d HADDPDm64_1 = _mm_set_pd(D,C1); 
    __m128d HADDPDm64_2 = _mm_set_pd(x,y); 
    __m128d HADDPDm64_r = HADDPD(HADDPDm64_1, HADDPDm64_2); 

    print_2_64_bit_doubles("input 1 HADDPD:", HADDPDm64_1); 
    print_2_64_bit_doubles("input 2 HADDPD:", HADDPDm64_2); 
    print_2_64_bit_doubles("result of HADDPD:", HADDPDm64_r); 

    return 0; 
} 

和輸出

values int:: 4 2 
shifts:: 2 
result: : 16 8 
input 1 HADDPD:: 10.000000 -1.#IND00 
input 2 HADDPD:: 13.000000 10.000000 
result of HADDPD:: -1.#IND00 23.000000 
+0

用gcc工作正常4.2.1 - 你在用什麼編譯器? –

+0

我想知道在64位SIMD之後是否需要'_mm_empty()'? –

+0

當我在命令行輸入'g ++ -v'時,得到'gcc 4.4.1 tdm-2 mingw 32'。我在__m64 PSLLDm64_r = PSLLD(PSLLDm64_IN,PSLLDm64_C)之後放置了_mm_empty();'和輸出結果相同? – pandoragami

回答

1

測試與Windows的x64編譯新的換擋指示更新的代碼gcc和g ++ 4.8.1的端口從http://www.drangon.org/mingw/都給出了預期的結果。只需解壓縮存檔並將路徑設置爲mingw64 \ bin。使用編譯器選項(如-msse4)告訴編譯器您的硬件支持這些說明。

07/05/2013:對不完整的初始評論感到抱歉。此外,上述答案旨在成爲評論而不是答案。

微軟VS2010得到了你從cygwin報告的錯誤結果,並且很容易找到微軟調試器的原因。實際上,編譯警告也指出了這個問題:

warning C4730: 'main' : mixing _m64 and floating point expressions may result in incorrect code 

當編譯器生成MMX和x87 FPU指令混合時,報告的問題就會發生。編譯器使用MMX寄存器_m64數據,編譯器使用x87 FPU寄存器或更新的XMM或YMM寄存器來實現浮點數據類型double。當英特爾設計MMX時,決定重新使用x87寄存器來存儲MMX寄存器數據。這樣做是爲了使操作系統不需要任何更新來支持MMX的使用。這個決定的缺點是MMX和x87 FPU指令不能混用。爲了幫助防止FPU和MMX指令意外混合,Intel讓MMX寄存器將相應FPU寄存器的標籤字位標記爲SNAN(信號NAN)。這就是導致你看到意外輸出的原因。某些編譯器和構建選項組合可能會允許此代碼正常工作。此代碼在某些情況下可能會起作用的原因如下: 1)編譯器使用XMM或YMM寄存器來實現雙精度數據。 2)編譯器將所有x87 FPU值保留在內存中,並且不依賴MMX指令中的FPU寄存器狀態。底線是編碼器要避免允許編譯器生成混合MMX和x87 FPU指令的代碼。對於「函數」print_2_32_bit_int'沒有EMMS指令「或」混合_m64和浮點表達式可能導致代碼不正確「的警告嚴重。一種可行的方法是完全避免_m64數據類型。

Paul R關於使用_mm_empty()的建議解決了Microsoft VS2010的問題。我在'double C1 = 10'之前加了它,問題就消失了。這裏解釋_mm_empty http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011Update/compiler_c/intref_cls/common/intref_mmx_emms_usage.htm

對於其他問題,我使用的命令行僅適用於gcc,沒有IDE。如果添加_mm_empty()或避免混合使用MMX和x87 FPU代碼,舊版本的gcc應該可以正常工作。

+0

我只是想知道,如果你使用的是IDE,比如代碼塊(這是我在)。我可以改變我的工具鏈mingw64/bin中,但我不能讓它編譯任何東西(例如,它停了下來話說,編譯失敗)。你用什麼IDE的方式? – pandoragami