2016-11-16 42 views
0

我試圖使用Intel Intrinsics在float陣列上快速執行操作。這些行動本身似乎運作良好;但是,當我嘗試將操作的結果轉換爲標準C變量時,我得到一個SEGFAULT。如果我將下面的指示線註釋掉,程序就會運行。如果我保存指定行的結果,但不以任何方式操縱它,程序運行正常。只有當我試圖(以任何方式)與_mm_cvtss_f32(C)的結果進行交互時,我的程序纔會崩潰。有任何想法嗎?使用生成的浮點數時出現SSE SIMD分段錯誤

float proc(float *a, float *b, int n, int c, int width) { 
    // Operation: SUM: (A - B)^2 
    __m128 A, B, C; 
    float total = 0; 
    for (int d = 0, k = 0; k < c; d += width, k++) { 
     for (int i = 0; i < n/4 * 4; i += 4) { 
      A = _mm_load_ps(&a[i + d]); 
      B = _mm_load_ps(&b[i + d]); 
      C = _mm_sub_ps(A, B); 
      C = _mm_mul_ps(C, C); 
      C = _mm_hadd_ps(C, C); 
      C = _mm_hadd_ps(C, C); 
      total += _mm_cvtss_f32(C); // SEGFAULT HERE 
     } 
     for (int i = n/4 * 4; i < n; i++) { 
      int diff = a[i + d] - b[i + d]; 
      total += diff * diff; 
     } 
    } 
    return total; 
} 
+4

你確定你的程序實際上是在你引用的指令上崩潰的,或者是編譯器只是優化了剩餘的循環,如果你刪除'_mm_cvtss_f32()'行(它沒有任何其他可見的副作用) ?由於使用對齊的加載指令,因此潛在的故障原因可能是「a」和「b」陣列的不正確對齊。你確定它們是16字節對齊的嗎?在當代英特爾硬件上,16字節對齊和不對齊負載之間的性能差別非常小(「movaps」的指令編碼比「movups」短,但就是這一點)。 –

+1

謝謝你,我把'load'改成了'loadu',它現在好像工作了! – Simon

+1

@JasonR:它們的編碼長度相同。 http://www.felixcloutier.com/x86/MOVAPS.html與http://www.felixcloutier.com/x86/MOVUPS.html。如果您比較反彙編,其中一個是否有REX前綴或不同的尋址模式?無論如何,當數據在運行時對齊時,它們的表現完全相同,但當L1高速緩存讀取帶寬是瓶頸時,對齊的負載具有優勢。確保您的數據在價格低廉時保持​​一致是個不錯的主意。 –

回答

0

你確定你的程序崩潰其實在你提到的指令,或者是編譯器只是優化循環的其餘部分路程,如果你刪除_mm_cvtss_f32()行(它不具有任何其他可見側效果)?由於您使用的是對齊的加載指令,潛在的故障原因將是a和b陣列的不正確對齊。你確定它們是16字節對齊的嗎?在當代英特爾硬件上,16字節對齊和未對齊的負載之間幾乎沒有性能差異(請參閱上面關於該問題討論的問題的評論)。

我在我的原始評論中提到movaps的編碼比movups短。 這是不正確的。我在想,而不是movapsmovapd,它們進行相同的內存傳輸,只是將它們分別標記爲單精度和雙精度數據。在實踐中,他們做同樣的事情,但movaps有一個較短的編碼。