1、重解釋轉(zhuǎn)換
雖然128位的XMM寄存器在硬件上只是256位YMM寄存器的下半部分,但在C++中它們是不同的類型。有一些intrinsic函數(shù)可以將它們重新解釋為不同的類型,如下表所示,行代表源類型,列代表目標(biāo)類型。
__m128 |
__m128d |
__m128i |
__m256 |
__m256d |
__m256d |
|
---|---|---|---|---|---|---|
__m128 |
= | _mm_castps_pd |
_mm_castps_si128 |
_mm256_castps128_ps256 |
||
__m128d |
_mm_castpd_ps |
= | _mm_castpd_si128 |
_mm256_castpd128_pd256 |
||
__m128i |
_mm_castsi128_ps |
_mm_castsi128_pd |
= | _mm256_castsi128_si256 |
||
__m256 |
_mm256_castps256_ps128 |
= | _mm256_castps_pd |
_mm256_castps_si256 |
||
__m256d |
_mm256_castpd256_pd128 |
_mm256_castpd_ps |
= | _mm256_castpd_si256 |
||
__m256i |
_mm256_castsi256_si128 |
_mm256_castsi256_ps |
_mm256_castsi256_pd |
= |
這些函數(shù)不會被編譯成任何指令,所以性能上幾乎沒有損耗,因為它們不改變寄存器中的值,例如32位float浮點數(shù)1.0f
轉(zhuǎn)換成32位整數(shù)后會變?yōu)?code>0x3f800000。將128位值轉(zhuǎn)換成256位值時,上半部分是未定義的。
2、類型轉(zhuǎn)換
類型轉(zhuǎn)換只支持帶符號的32位整數(shù),例如:
函數(shù)示例 | 說明 |
---|---|
_mm_cvtepi32_ps 、_mm256_cvtepi32_ps
|
將32位整數(shù)轉(zhuǎn)換成對應(yīng)的32位浮點數(shù) |
_mm_cvtepi32_pd 、_mm256_cvtepi32_pd
|
將32位整數(shù)轉(zhuǎn)換成對應(yīng)的64位浮點數(shù) |
_mm_cvtps_epi32 、_mm256_cvtps_epi32
|
將32位浮點數(shù)轉(zhuǎn)換成對應(yīng)的32位整數(shù) |
_mm_cvtpd_epi32 、_mm256_cvtpd_epi32
|
將64位浮點數(shù)轉(zhuǎn)換成對應(yīng)的32位整數(shù) |
當(dāng)浮點數(shù)轉(zhuǎn)換為整數(shù)時,函數(shù)使用MXCSR寄存器中指定的舍入模式,若要更改模式,可以使用宏_MM_SET_ROUNDING_MODE
。此外,也有一些名稱中帶有額外t
的函數(shù)會忽略MXCSR寄存器,并始終使用向零截斷(_MM_ROUND_TOWARD_ZERO
)的模式,例如_mm_cvttpd_epi32
、_mm_cvttps_epi32
。
此外還有一些函數(shù)可以在32位浮點數(shù)與64位浮點數(shù)之間進行轉(zhuǎn)換,例如_mm256_cvtps_pd
將32位浮點數(shù)轉(zhuǎn)換成64位浮點數(shù)。
3、內(nèi)存訪問
3.1、加載
-
對齊/非對齊加載:所有數(shù)據(jù)類型都支持對齊加載和非對齊加載。對齊加載例如
_mm_load_si128
或_mm256_load_ps
,它們要求源地址是16字節(jié)或者32字節(jié)對齊的,否則可能會導(dǎo)致崩潰;非對齊加載例如_mm_loadu_si128
或_mm256_loadu_ps
,它們函數(shù)名中額外的u
表示unaligned,它們的速度可能會慢于對齊加載的版本。 -
單通道加載:
__m128
和__m128d
支持單通道加載,即只加載第一條通道并把其它通道設(shè)置成0.0,例如_mm_load_ss
和_mm_load_sd
。 -
逆序加載:
__m128
和__m128d
支持逆序加載,即以逆序方式將數(shù)據(jù)加載到寄存器中,例如_mm_loadr_ps
和_mm_loadr_pd
。 -
廣播加載:在AVX指令集中,
__m128
、__m256
、__m256d
支持廣播加載,也就是把單個值加載到多個寄存器通道中,例如_mm256_broadcast_ss
等。 -
掩碼加載:AVX引入了掩碼加載,即根據(jù)掩碼的值選擇性地加載數(shù)據(jù),例如
_mm_maskload_ps
等。 -
跨距加載:AVX2引入了跨距加載,它可以利用索引寄存器來加載非連續(xù)地址的數(shù)據(jù)元素,不過速度較慢,例如
_mm_i32gather_ps
等。 -
流加載:這類指令繞過緩存,直接將內(nèi)存數(shù)據(jù)加載到寄存器中,從而減少緩存污染和緩存替換的開銷,適用于一次性讀取大量數(shù)據(jù)并進行向量化計算的場景,例如
_mm_stream_load_si128
、_mm256_stream_load_si256
等。
3.2、存儲
-
對齊/非對齊存儲:與對齊/非對齊加載同理,對應(yīng)的存儲指令也有
_mm_store_ps
、_mm_storeu_ps
等。 -
單通道存儲:與單通道加載類似,只把第一條通道的數(shù)據(jù)寫入內(nèi)存,例如
_mm_store_ss
等。 -
逆序存儲:與逆序加載類似,它以逆序方式將數(shù)據(jù)寫入內(nèi)存中,例如
_mm_storer_ps
等。 -
掩碼存儲:與掩碼加載類似,根據(jù)掩碼的值選擇性地存儲數(shù)據(jù),例如
_mm_maskstore_ps
等。 -
流存儲:與流加載指令類似,繞過緩存直接將數(shù)據(jù)寫入內(nèi)存,從而減少了緩存寫回的開銷,適用于大規(guī)模數(shù)據(jù)的存儲操作,例如
_mm_stream_ps
、_mm256_stream_si256
等。
4、向量寄存器初始化
所有向量寄存器類型都有_mm_setzero_ps
或_mm256_setzero_si256
這樣的函數(shù),用于將寄存器初始化為全零,它可能會被編譯成xorps xmm0, xmm0, xmm0
這樣的指令,其執(zhí)行效率很高。
雖然CPU無法使用0以外的常量來初始化寄存器,但編譯器還是提供了一些函數(shù)來實現(xiàn)非0初始化,例如_mm_set_ps
可以用不同的值初始化各個通道,_mm256_set1_epi
用相同的值初始化所有通道。這些函數(shù)的實現(xiàn)依據(jù)具體情況而定:如果參數(shù)是編譯時的常量,它們通常會被編譯成二進制文件中的只讀數(shù)據(jù);如果編譯時無法確定參數(shù),編譯器就會執(zhí)行其它合理操作,例如寄存器大部分為0,而我們只設(shè)置了一條通道,那么編譯器可能會執(zhí)行插入指令,再比如參數(shù)來自變量,編譯器就可能會先實行洗牌或標(biāo)量存儲、然后再進行向量加載。
5、向量寄存器與通用寄存器的轉(zhuǎn)換
數(shù)據(jù)類型 | 數(shù)據(jù)復(fù)制方向 | 函數(shù)示例 |
---|---|---|
整數(shù) | 向量寄存器最低通道 ==> 通用寄存器 |
_mm_cvtsi128_si32 、_mm_cvtsi128_si64
|
整數(shù) | 通用寄存器 ==> 向量寄存器最低通道 |
_mm_cvtsi32_si128 、_mm_cvtsi64x_si128
|
浮點數(shù) | 向量寄存器最低通道 ==> 通用寄存器 |
_mm_cvtss_f32 、_mm_cvtsd_f64
|
浮點數(shù) | 通用寄存器 ==> 向量寄存器最低通道 | 沒有對應(yīng)的轉(zhuǎn)換函數(shù),但可以使用_mm_set_ps 或_mm_set1_ps 實現(xiàn)相同功能 |
上表中列舉的轉(zhuǎn)換函數(shù)只操作向量寄存器的最低通道,除此之外還有一類函數(shù)可以將整數(shù)向量寄存器任意通道的值復(fù)制到通用寄存器,它們是_mm_extract_epi8
、_mm_extract_epi16
等。
當(dāng)程序是32位時,所有通用寄存器也都是32位的,在向量寄存器和通用寄存器之間移動64位整數(shù)的指令不可用。
6、位運算
浮點數(shù)和整數(shù)有一套完整的位運算指令,它們包含AND、OR、XOR、ANDNOT指令,例如_mm_and_ps
、_mm256_xor_epi32
等。如果需要位運算NOT,最快的方法可能是與所有1進行XOR,例如:文章來源:http://www.zghlxwxcb.cn/news/detail-741777.html
__m128i bitwiseNot(__m128i x)
{
const __m128i zero = _mm_setzero_si128();
const __m128i one = _mm_cmpeq_epi32(zero, zero);
return _mm_xor_si128(x, one);
}
test指令將計算結(jié)果直接保存到int
型的通用寄存器中,部分test函數(shù)及其功能如下表所示:文章來源地址http://www.zghlxwxcb.cn/news/detail-741777.html
函數(shù)示例 | 返回結(jié)果 |
---|---|
_mm_testz_si128 、_mm256_testz_si256
|
return ((a & b) == 0) ? 1 : 0 |
_mm_testc_si128 、_mm256_testc_si256
|
return (((~a) & b) == 0) ? 1 : 0 |
_mm_testnzc_si128 、_mm256_testnzc_si256
|
testz 和testc 結(jié)果都為0時返回1,否則返回0 |
_mm_test_all_ones |
把輸入向量取反后與全1向量按位與,如果等于0則返回1,否則返回0 |
_mm_test_all_zeros |
把輸入向量與掩碼向量按位與,如果等于0則返回1,否則返回0 |
到了這里,關(guān)于x86平臺SIMD編程入門(2):通用指令的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!