2017-05-27 38 views
11

我在旁邊的其他人的代碼中,並試圖找出爲什麼_mm_load_si128存在。爲什麼SSE有128位加載函數?

從本質上講,我試圖與

_ra = *reinterpret_cast<__m128i*>(&cd->data[idx]); 

更換

_ra = _mm_load_si128(reinterpret_cast<__m128i*>(&cd->data[idx])); 

和它的工作原理,準確地執行相同的。

我計算過,對於較小的類型存在負載功能只是爲了方便起見,這樣的人就不必手動進行,但數據打包成連續的內存已經在正確的順序,何必呢?

有沒有別的東西,_mm_load_si128呢?或者它本質上只是一種分配價值的迂迴方式?

+0

它可能是(或擴展到)一些編譯器內建的。你在用什麼C++編譯器? –

+0

@BasileStarynkevitch一個自帶的視覺工作室 – user81993

+0

是不是'_ra = reinterpret_cast <__m128>(cd-> data [idx])'也有可能嗎? – Walter

回答

13

在SSE中有顯式和隱式加載。

  • _mm_load_si128(reinterpret_cast<__m128i*>(&cd->data[idx]));是一個明確的負載
  • *reinterpret_cast<__m128i*>(&cd->data[idx]);一個隱含的負載

明確與您指示編譯器將數據加載到XMM寄存器明確的負荷 - 這是「官方」英特爾方式來做到這一點。您還可以通過使用_mm_load_si128_mm_loadu_si128來控制負載是對齊還是未對齊的負載。

儘管作爲擴展,大多數編譯器也能夠在您執行type-punning時自動生成XMM加載,但這種方式無法控制加載是否對齊或未對齊。在這種情況下,由於在現代CPU上數據對齊時沒有使用未對齊的加載的性能損失,編譯器傾向於通用地使用未對齊的加載。

另一個更重要的方面是,對於隱式加載,您違反了strict aliasing規則,這可能會導致未定義的行爲。雖然這是值得一提的是 - 作爲擴展的一部分 - 它支持英特爾內部函數不傾向於強制執行XMM佔位符類型嚴格別名規則像__m128__m128d__m128i編譯器。

儘管如此,我認爲明確的負載更清潔,更防彈。


爲什麼編譯器不傾向於強制執行SSE佔位符類型嚴格別名規則?

1原因在於上證所內部函數的設計:有明顯的情況下,當你必須使用類型雙關,因爲是使用一些內部函數沒有別的辦法。 Mysticial's answer完美地總結。正如Cody Gray在評論中指出的那樣,值得一提的是,歷史上MMX內在關係(現在大部分被SSE2取代)甚至沒有提供明確的加載或存儲 - 你必須使用類型雙關。

第二個原因(與第一個有些相關)在於這些類型的類型定義。

GCC的typedef S爲SSE ​​/ SSE2佔位符類型<xmmintrin.h ><emmintrin.h>

/* The Intel API is flexible enough that we must allow aliasing with other 
    vector types, and their scalar components. */ 

typedef float __m128 __attribute__ ((__vector_size__ (16), __may_alias__));  
typedef long long __m128i __attribute__ ((__vector_size__ (16), __may_alias__)); 
typedef double __m128d __attribute__ ((__vector_size__ (16), __may_alias__)); 

這裏的關鍵是__may_alias__屬性,這使得在即使嚴格走樣啓用這些類型的類型雙關工作-fstrict-aliasing標誌。

現在,由於clangICCGCC兼容,他們應該遵循相同的約定。因此,目前,在這3個編譯器中,即使使用-fstrict-aliasing標誌,隱式加載/存儲也可以保證工作。最後,MSVC根本不支持嚴格的別名,所以它甚至不是那裏的問題。

但是,這並不意味着您應該更喜歡隱式加載/存儲而不是顯式加載/存儲。

+0

這個答案的關鍵部分是嚴格的別名 - 顯式加載避免未定義的行爲。對於支持英特爾內部函數的編譯器不對XMM類型強制實施嚴格的別名規則,還是僅基於您自己的經驗,您是否有某種類型的參考?我問,因爲它也適合我的經驗,但僅僅因爲有效的事情並不意味着它不會冒險UB! –

+0

也可以補充說明,這些顯式加載對於SSE來說是新的。它們不是由MMX內部函數提供的,它基本上對所有*加載操作進行隱式加載和醜陋轉換。 –

+0

@CodyGray此行爲與英特爾內部函數沒有正式關聯,但是當內部函數的設計強制您使用別名時存在明顯的情況 - 沒有其他方式。我推薦這個答案:https://stackoverflow.com/a/24788226/2430597。 – plasmacel