2012-02-13 51 views
4

假設我有兩個向量由兩個數組double兩個數組表示,每個數組的大小爲2.我想添加相應的位置。所以假設矢量i0i1,我想添加i0[0] + i1[0]i0[1] + i1[1]在一起。SSE加載和添加

由於類型是double,我需要兩個寄存器。訣竅是將i0[0]i1[0],i0[1]i1[1]放在另一箇中,並將其與自身相加。

我的問題是,如果我打電話_mm_load_ps(i0[0]),然後_mm_load_ps(i1[0]),將它們分別放在較低和較高的64位,或將它替換爲第二個load?我如何將兩個雙打放在同一個寄存器中,所以我可以在撥打add_ps之後?

感謝,

回答

7

我想你想要的是這樣的:

double i0[2]; 
double i1[2]; 

__m128d x1 = _mm_load_pd(i0); 
__m128d x2 = _mm_load_pd(i1); 
__m128d sum = _mm_add_pd(x1, x2); 
// do whatever you want to with "sum" now 

當你做一個_mm_load_pd,它把第一雙入冊和第二的低64位到上16位。因此,在上述負荷後,x1保留兩個doublei0[0]i0[1](以及類似的x2)。對_mm_add_pd的調用垂直添加了x1x2中的相應元素,因此在添加之後,sumi0[0] + i1[0]保留在其較低的64位中,將i0[1] + i1[1]保留在其較高的64位中。

編輯:我應該指出,有使用_mm_load_pd代替_mm_load_ps沒有好處。如函數名稱所示,pd類顯式加載兩個壓縮雙精度,並且ps版加載四個壓縮單精度浮點數。由於這些都是純位移內存,並且都使用SSE浮點單元,所以使用_mm_load_ps加載double數據沒有任何損失。而且,_mm_load_ps還有一個好處:它的指令編碼比_mm_load_pd短一個字節,所以它從指令高速緩存意義上講效率更高(可能還有指令解碼;我不是現代x86處理器所有複雜性的專家)。使用_mm_load_ps上面的代碼看起來像:

double i0[2]; 
double i1[2]; 

__m128d x1 = (__m128d) _mm_load_ps((float *) i0); 
__m128d x2 = (__m128d) _mm_load_ps((float *) i1); 
__m128d sum = _mm_add_pd(x1, x2); 
// do whatever you want to with "sum" now 

沒有被蒙上暗示的功能;它只是讓編譯器重新解釋SSE寄存器的內容爲保持雙精度而不是浮點數,以便它可以傳遞到雙精度算術函數_mm_add_pd

+0

你當然可以使用'_mm_load_ps',但風險在其上設計了這樣一種方式的假設未來處理器性能的下降,有單間域旁路處罰和雙精度浮點運算。我知道沒有這樣的處理器的計劃,但這並不是說永遠不會實施;這就是爲什麼有不同的加載操作。誠然,這是一個遙遠的可能性,但爲什麼冒這個險呢? – 2012-02-13 15:32:51

+0

我同意未來的處理器存在性能下降的風險。我建議人們考慮(即衡量)通過在特定應用的基礎上使用「MOVPS」而不是「MOVPD」來獲得任何性能優勢。如果今天使用它是有好處的,並且沒有跡象表明即將到來的架構會有這樣的懲罰,我會這樣做。像這樣的負載可以很容易地被抽象化,以允許將來自動切換到不同的實現。 – 2012-02-13 16:41:58

3

_ps前綴是的縮寫「packed single」,意思是它用於單精度浮點而不是雙精度。

取而代之,你想要_mm_load_pd()。該函數將一個16字節的對齊指針指向兩個double的數組中的第一個成員,並加載它們。所以,你可以使用這個像這樣:

__m128d v0 = _mm_load_pd(i0); 
__m128d v1 = _mm_load_pd(i1); 

v0 = _mm_add_pd(v0, v1); 
+0

'_mm_load_ps'實際上可以用於雙精度值(並且這樣做有好處);看到我的答案。 – 2012-02-13 15:27:12