1、算術(shù)指令
算術(shù)類型 | 函數(shù)示例 | 備注 |
---|---|---|
加 |
_mm_add_sd 、_mm256_add_ps
|
|
減 |
_mm_sub_sd 、_mm256_sub_ps
|
|
乘 |
_mm_mul_sd 、_mm256_mul_ps
|
|
除 |
_mm_div_sd 、_mm256_div_ps
|
|
平方根 |
_mm_sqrt_sd 、_mm256_sqrt_ps
|
|
倒數(shù) |
_mm_rcp_ss 、_mm_rcp_ps 、_mm256_rcp_ps
|
快速計算32位浮點數(shù)的近似倒數(shù)(1/x),最大相對誤差小于\(1.5\times 2^{-12}\)。 |
倒數(shù)平方根 |
_mm_rsqrt_ss 、_mm_rsqrt_ps 、_mm256_rsqrt_ps
|
快速計算32位浮點數(shù)的近似倒數(shù)平方根(1/sqrt(x)),最大相對誤差小于\(1.5\times 2^{-12}\)。 |
水平加 |
_mm_hadd_ps 、_mm256_hadd_pd
|
輸入兩個寄存器[a, b, c, d]和[e, f, g, h],返回[a+b, c+d, e+f, g+h]。 |
水平減 |
_mm_hsub_ps 、_mm256_hsub_pd
|
輸入兩個寄存器[a, b, c, d]和[e, f, g, h],返回[a-b, c-d, e-f, g-h]。 |
交替加減 |
_mm_addsub_ps 、_mm256_addsub_pd
|
輸入兩個寄存器[a, b, c, d]和[e, f, g, h],返回[a-e, b+f, c-g, d+h]。對于復(fù)數(shù)乘法比較有用。 |
點乘 |
_mm_dp_ps 、_mm_dp_pd 、_mm256_dp_ps
|
輸入兩個寄存器和一個8位常量,常量高4位表示需要點乘的通道,低4位表示需要廣播結(jié)果的通道。 |
四舍五入 |
_mm_round_ps 、_mm_floor_ss 、_mm256_ceil_pd
|
|
最大/最小值 |
_mm_min_ss 、_mm256_max_pd
|
x86 SIMD指令中沒有一元減號或絕對值指令,但可以通過位操作技巧來實現(xiàn)對應(yīng)的功能,例如_mm_xor_ps(x, _mm_set1_ps(-0.0f))
可實現(xiàn)一元減號運算,_mm_andnot_ps(_mm_set1_ps(-0.0f), x)
可實現(xiàn)取絕對值。(因為-0.0f
浮點數(shù)值只把符號位設(shè)置為1,其余位均為0,所以_mm_xor_ps
會翻轉(zhuǎn)符號,_mm_andnot_ps
會清除符號位。)
2、比較指令
SSE實現(xiàn)了各種浮點數(shù)比較運算,如下表所示:
運算符 | 函數(shù)示例 |
---|---|
等于 |
_mm_cmpeq_ss 、_mm_cmpeq_ps 、_mm_cmpeq_sd 、_mm_cmpeq_pd
|
小于 |
_mm_cmplt_ss 、_mm_cmplt_ps 、_mm_cmplt_sd 、_mm_cmplt_pd
|
小于等于 |
_mm_cmple_ss 、_mm_cmple_ps 、_mm_cmple_sd 、_mm_cmple_pd
|
大于 |
_mm_cmpgt_ss 、_mm_cmpgt_ps 、_mm_cmpgt_sd 、_mm_cmpgt_pd
|
大于等于 |
_mm_cmpge_ss 、_mm_cmpge_ps 、_mm_cmpge_sd 、_mm_cmpge_pd
|
不等于 |
_mm_cmpneq_ss 、_mm_cmpneq_ps 、_mm_cmpneq_sd 、_mm_cmpneq_pd
|
不小于 |
_mm_cmpnlt_ss 、_mm_cmpnlt_ps 、_mm_cmpnlt_sd 、_mm_cmpnlt_pd
|
不小于等于 |
_mm_cmpnle_ss 、_mm_cmpnle_ps 、_mm_cmpnle_sd 、_mm_cmpnle_pd
|
不大于 |
_mm_cmpngt_ss 、_mm_cmpngt_ps 、_mm_cmpngt_sd 、_mm_cmpngt_pd
|
不大于等于 |
_mm_cmpnge_ss 、_mm_cmpnge_ps 、_mm_cmpnge_sd 、_mm_cmpnge_pd
|
AVX將浮點數(shù)比較指令統(tǒng)一成了_mm_cmp_xx
和_mm256_cmp_xx
這樣的形式,然后通過一個常量來表示比較謂語。比較謂語如下表所示,兩個數(shù)比較時若其中一個數(shù)為NaN,則ordered模式將返回false,unordered模式將返回true,另外signalling只影響MXCSR的值。
比較運算 | ordered (non-signalling) | unordered (non-signalling) | ordered (signalling) | unordered (signalling) |
---|---|---|---|---|
a < b | _CMP_LT_OQ | _CMP_NGE_UQ | _CMP_LT_OS | _CMP_NGE_US |
a <= b | _CMP_LE_OQ | _CMP_NGT_UQ | _CMP_LE_OS | _CMP_NGT_US |
a == b | _CMP_EQ_OQ | _CMP_EQ_UQ | _CMP_EQ_OS | _CMP_EQ_US |
a != b | _CMP_NEQ_OQ | _CMP_NEQ_UQ | _CMP_NEQ_OS | _CMP_NEQ_US |
a >= b | _CMP_GE_OQ | _CMP_NLT_UQ | _CMP_GE_OS | _CMP_NLT_US |
a > b | _CMP_GT_OQ | _CMP_NLE_UQ | _CMP_GT_OS | _CMP_NLE_US |
true | _CMP_ORD_Q | _CMP_TRUE_UQ | _CMP_ORD_S | _CMP_TRUE_US |
false | _CMP_FALSE_OQ | _CMP_UNORD_Q | _CMP_FALSE_OS | _CMP_UNORD_S |
浮點數(shù)比較指令返回另一個寄存器來保存結(jié)果,其中比較條件成立的值賦為全1(NaN),其它賦為全0(0.0f)。可以使用_mm_movemask_ps
、_mm_movemask_pd
或AVX中的等效指令來將結(jié)果發(fā)送到CPU通用寄存器,這些指令收集每個浮點數(shù)通道的最高有效位(恰好也是符號位)并打包成標(biāo)量,然后復(fù)制到通用寄存器中。
const __m128 zero = _mm_setzero_ps();
const __m128 eq = _mm_cmpeq_ps(zero, zero);
const int mask = _mm_movemask_ps(eq);
printf("%i\n", mask);
在上面這段代碼中,對于__m128
的所有4個通道,0 == 0
的比較結(jié)果都是正確的,eq
變量的所有128位都設(shè)置為1,然后_mm_movemask_ps
收集并返回所有4個浮點數(shù)通道的符號位,最終打印出的mask
值是15,即二進制的0b1111。比較結(jié)果的另外一些用途,就是可以將它們作為其它指令的參數(shù)(例如blendv指令)。
除了全通道比較函數(shù)外,也有一些函數(shù)可以只比較兩個寄存器的最低通道,如下表所示:
運算符 | 函數(shù)示例 |
---|---|
等于 |
_mm_comieq_ss 、_mm_comieq_sd
|
不等于 |
_mm_comineq_ss 、_mm_comineq_sd
|
小于 |
_mm_comilt_ss 、_mm_comilt_sd
|
小于等于 |
_mm_comile_ss 、_mm_comile_sd
|
大于 |
_mm_comigt_ss 、_mm_comigt_sd
|
大于等于 |
_mm_comige_ss 、_mm_comige_sd
|
3、洗牌指令
3.1、固定順序洗牌
函數(shù)示例 | 說明 | 示意圖 |
---|---|---|
_mm_movehl_ps |
將向量a中的高2個元素復(fù)制到dst的高2個元素中,將向量b中的高2個元素復(fù)制到dst的低2個元素中。 | ![]() |
_mm_movelh_ps |
將向量a中的低2個元素復(fù)制到dst的低2個元素中,將向量b中的低2個元素復(fù)制到dst的高2個元素中。 | ![]() |
_mm_unpacklo_ps |
取向量a和向量b的低半部分元素并交錯存儲到dst中。 | ![]() |
_mm_unpackhi_ps |
取向量a和向量b的高半部分元素并交錯存儲到dst中。 | ![]() |
_mm_movehdup_ps |
復(fù)制輸入向量中的奇數(shù)索引元素,并存儲到dst中。 | ![]() |
_mm_moveldup_ps |
復(fù)制輸入向量中的偶數(shù)索引元素,并存儲到dst中。 | ![]() |
_mm_broadcastss_ps |
將輸入向量的最低通道元素廣播到dst的所有元素中。 | ![]() |
3.2、編譯時洗牌
這類函數(shù)都接收一個編譯期確定的常量來控制洗牌順序,如果傳入的控制系數(shù)無法在編譯期確定,那么將導(dǎo)致編譯錯誤,例如:
const __m128 zero = _mm_setzero_ps();
_mm_shuffle_ps(zero, zero, rand()); //error C2057: expected constant expression
下表僅列舉了一些參數(shù)是__m128
類型的洗牌函數(shù),__m128d
、__m256
、__m256d
也都有對應(yīng)的函數(shù),可以類推。示意圖中藍(lán)色箭頭表示使用控制系數(shù)選擇的內(nèi)容,灰色箭頭表示不同控制系數(shù)可能選擇的內(nèi)容。
函數(shù)示例 | 說明 | 示意圖 |
---|---|---|
_mm_shuffle_ps |
右圖中,控制常數(shù)是0x98(二進制 10 01 10 00)。輸出向量的前2個通道來自第一個輸入向量的0b00和0b10號通道,后2個通道來自第二個輸入向量的0b01和0b10號通道。如果要對單個向量進行置換,可將兩個輸入向量都設(shè)為同一個向量??梢允褂煤?code>_MM_SHUFFLE來生成控制常數(shù)。 | ![]() |
_mm_blend_ps |
右圖中,控制常數(shù)為1(二進制 0 0 0 1),所以只從第二個輸入向量中提取了對應(yīng)的0號通道,其余通道都取自第一個輸入向量的對應(yīng)通道。 | ![]() |
_mm_insert_ps |
插入單個通道,并可選擇將某些通道清零。右圖中,控制常數(shù)為0x61(二進制 01 10 0001):源索引為0b01,目標(biāo)索引為0b10,所以第二個輸入向量中0b01號通道的F被插入了輸出的0b10號通道;最低4位為0b0001,因此0號輸出通道被清零。此外,我們也可以選擇性地將某些通道清零而無需插入,例如控制常數(shù)0b00001001將0號和3號通道清零。(也可以使用_mm_blend_ps 和_mm_setzero_ps 實現(xiàn)等價功能,但這就是兩條指令,而不是一條。) |
![]() |
_mm_permute_ps |
與_mm_shuffle_ps 類似,區(qū)別在于僅對一個輸入向量進行洗牌。右圖中,控制常數(shù)是0x63(二進制 01 10 00 11)。 |
![]() |
3.3、運行時洗牌
_mm_blendv_ps
、_mm_blendv_pd
、_mm256_blendv_ps
、_mm256_blendv_pd
接收3個參數(shù),通過掩碼的符號位從向量a或向量b中選擇通道。
_mm_permutevar_ps
、_mm256_permutevar8x32_ps
都接收一個包含源數(shù)據(jù)的浮點數(shù)寄存器和一個包含源索引的整數(shù)寄存器,根據(jù)整數(shù)寄存器中的索引值從浮點數(shù)寄存器中選擇通道。文章來源:http://www.zghlxwxcb.cn/news/detail-741778.html
4、乘加融合指令
乘加運算 | 函數(shù)示例 |
---|---|
(a · b) + c |
_mm_fmadd_ps 、_mm256_fmadd_pd
|
(a · b) - c |
_mm_fmsub_ps 、_mm256_fmsub_pd
|
-(a · b) + c |
_mm_fnmadd_ps 、_mm256_fnmadd_pd
|
-(a · b) - c |
_mm_fnmsub_ps 、_mm256_fnmsub_pd
|
相較于分別使用乘法和加法指令,乘加融合(fused multiply-add, FMA)指令除了性能較高外,還更加精確,因為這些指令只在計算完乘法與加法后進行一次舍入。文章來源地址http://www.zghlxwxcb.cn/news/detail-741778.html
到了這里,關(guān)于x86平臺SIMD編程入門(3):浮點指令的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!