2013-11-01 89 views
2

我最近偶然發現隱式SSE/AVX加載/存儲。我認爲這些是GCC的一些特殊擴展,但是後來他們意識到他們也在MSVC上工作。Imprets SSE/AVX加載/存儲和堆棧

__m128 a = *(__m128*)data // same as __m128 a = _mm_load_ps(data)? 
__m128 *b = (__m128*)result; // same as _mm_store_ps(result, a)? 

這些隱式加載/存儲的正確語法是什麼?

從我讀的(Addressing a non-integer address, and sse)隱式加載/存儲使用對齊的加載/存儲,所以內存必須正確對齊。對於支持SSE/AVX內部函數的大多數編譯器(GCC/ICC/MSVC/Clang/MinGW等),假設它們的工作原理是否公平?有這些隱式加載/存儲的動機是什麼?

我的下一組問題是關於推送和彈出SSE/AVX寄存器到堆棧。 這是如何實施的?如果堆棧不是16字節對齊呢?它是否使用未對齊的加載/存儲?據我所知,棧現在通常是16字節對齊,但不一定是32字節對齊(至少在64位模式下)。如果算法具有較高的AVX佔用率,並且需要頻繁地將AVX寄存器推送到堆棧上,那麼將堆棧對齊到32個字節(例如,在具有優先堆棧邊界的GCC中)可能會提高性能?

+1

我用他們很多在宏在那裏我可以在任意的指針類型傳遞。如果它不對齊,你只會得到一個錯位錯誤。編譯器應該已經正確地調整堆棧以適應它正在使用的任何SIMD。 – Mysticial

+1

代碼或第二行的註釋不正確。 '_mm_store_ps(result,a)'應該等於'__m128 * result =(__m128 *)a'。 '_mm_store_ps'的簽名是'void _mm_store_ps(float * mem_addr,__m128 a)',其中'mem_addr'必須與16字節邊界對齊。 – plasmacel

+0

@plasmacel,你是對的。雖然。我個人絕不會使用隱含的SSE/AVX加載/存儲。 –

回答

1

你在這裏做的是將內存重新解釋爲由__m128變量填充的內存。這是有效的,因爲__m128基本上是4個浮點數(4個整數,或者2個雙精度,或者......)連續寫入一個內存。所以你可以把它當作一個浮點數組。唯一的區別是__m128在16個字節上對齊,同時保證浮點數組僅在4個位置對齊。

這是更好地使用reinterpret_cast的這種重新解釋:

// sqrt calculation : b = sqrt(a) 
const int N = 1000; // N%4 has to be equal 0! 
float a[N] __attribute__((aligned(16))); // Input. Force 16 bytes alignment. 
float b[N] __attribute__((aligned(16))); // Result. 

for(int i=0; i<N; i+=4) { 
    __m128 &aVec = reinterpret_cast<__m128&>(a[i]); 
    __m128 &bVec = reinterpret_cast<__m128&>(c_simd[i]); 
    bVec = _mm_sqrt_ps(aVec); 
}