好的,所以我不知道這段代碼在做什麼,但是我確實知道你在問如何優化ternery運算符並讓這部分代碼只在SSE中運行。作爲第一步,我會建議嘗試使用整數標誌和乘法來避免條件運算符。例如:
本節
for(int m=0; m < PBS_SSE_PIXELS_PROCESS_AT_ONCE; m++)
{
bool bIsEvenFloor = vn1.m128i_u16[m]==0;
vnPxChroma.m128i_u16[m] = m%2==0 ?
(bIsEvenFloor ? vnPxCeilChroma.m128i_u16[m] : vnPxFloorChroma.m128i_u16[m]) :
(bIsEvenFloor ? vnPxFloorChroma.m128i_u16[m] : vnPxCeilChroma.m128i_u16[m]);
}
在語法上等同於該
// DISCLAIMER: Untested both in compilation and execution
// Process all m%2=0 in steps of 2
for(int m=0; m < PBS_SSE_PIXELS_PROCESS_AT_ONCE; m+=2)
{
// This line could surely pack muliple u16s into one SSE2 register
uint16 iIsOddFloor = vn1.m128i_u16[m] & 0x1 // If u16[m] == 0, result is 0
uint16 iIsEvenFloor = iIsOddFloor^0x1 // Flip 1 to 0, 0 to 1
// This line could surely perform an SSE2 multiply across multiple registers
vnPxChroma.m128i_u16[m] = iIsEvenFloor * vnPxCeilChroma.m128i_u16[m] +
iIsOddFloor * vnPxFloorChroma.m128i_u16[m]
}
// Process all m%2!=0 in steps of 2
for(int m=1; m < PBS_SSE_PIXELS_PROCESS_AT_ONCE; m+=2)
{
uint16 iIsOddFloor = vn1.m128i_u16[m] & 0x1 // If u16[m] == 0, result is 0
uint16 iIsEvenFloor = iIsOddFloor^0x1 // Flip 1 to 0, 0 to 1
vnPxChroma.m128i_u16[m] = iIsEvenFloor * vnPxFloorChroma.m128i_u16[m] +
iIsOddFloor * vnPxCeilChroma.m128i_u16[m]
}
基本上被分裂成兩個循環你失去的串行存儲器訪問的性能提升,但下降模運算,並且兩個條件操作符。
現在你說,你注意到每個循環有兩個布爾運算符,以及我可能添加的乘積不是SSE內部實現。什麼存儲在你的vn1.m123i_u16 []數組中?它只是零和那些? 如果是這樣,你不需要這部分,可以取消它。如果沒有,你能否規範化你的數據在這個數組中只有零和一個?如果vn1.m123i_u16陣列只包含一和零那麼這個代碼變得
uint16 iIsOddFloor = vn1.m128i_u16[m]
uint16 iIsEvenFloor = iIsOddFloor^0x1 // Flip 1 to 0, 0 to 1
您還會注意到我沒有使用SSE乘以執行isEvenFloor * vnPx... part
也不存儲iIsEvenFloor
和iIsOddFloor
寄存器。很抱歉,我不記得U16的SSE內部函數是從頂部乘以/註冊的,但我希望這種方法很有幫助。一些優化技術你應該看看:
// This line could surely pack muliple u16s into one SSE2 register
uint16 iIsOddFloor = vn1.m128i_u16[m] & 0x1 // If u16[m] == 0, result is 0
uint16 iIsEvenFloor = iIsOddFloor^0x1 // Flip 1 to 0, 0 to 1
// This line could surely perform an SSE2 multiply across multiple registers
vnPxChroma.m128i_u16[m] = iIsEvenFloor * vnPxCeilChroma.m128i_u16[m] +
iIsOddFloor * vnPxFloorChroma.m128i_u16[m]
在這部分代碼你張貼,我的修改,我們還沒有充分利用SSE1/2/3的內部函數,但它可能會提供一些點如何做到這一點(如何矢量化代碼)。
最後我會說要測試一切。在進行更改和分析之前,先運行上面的代碼並對其進行配置。實際的表現數字可能讓你感到驚訝!
更新1:
我已經通過Intel SIMD Intrinsics documentation挑選出相關的內部函數這可能是使用了這一點。具體地來看看按位異或,AND和MULT/ADD
__m128數據類型
的__m128i數據類型可容納16個8位,8個16位,4個32位,或2個64位整數值。
__m128i _mm_add_epi16(__ m128i一個,__m128i B)
在添加8個符號或無符號16位整數有符號的8或16位無符號整數b中
__m128i _mm_mulhi_epu16(__ m128i一個,__m128i b)
將a的8個無符號16位整數乘以b的8個無符號16位整數。 包8無符號的32位的高16位結果
R0 = HIWORD(A0 * B0)
R1 = HIWORD(A1 * B1)
R2 = HIWORD(A2 * B2)
R3 = HIWORD(A3 * B3)
..
R7 = HIWORD(A7 * B7)
__m128i _mm_mullo_epi16(__ m128i一個,__m128i b)
倍增來自8符號或無符號16位整數一個由8位有符號或無符號的16位數字組成,來自b的位整數。 包的高位16比特的8符號或無符號的32位結果
R0 = LOWORD(A0 * B0)
R1 = LOWORD(A1 * B1)
R2 = LOWORD(A2 * b2)的
R3 = LOWORD(A3 * B3)
..
R7 = LOWORD(A7 * B7)
__m128i _mm_and_si128(__ m128i一個,__m128i b)
執行按位與128位的m1中的值與以m2計的128位值。
__m128i _mm_andnot_si128(__ m128i一個,__m128i B)
計算的位與B中的128位的值和所述按比特的NOT在所述128 比特值。
__m128i _mm_xor_si128(__ m128i一個,__m128i B)
在M1執行按位異或128位值的與平方米的128位的值。
從您的代碼示例
也可對照
UINT16 U1 = U2 = U3 ...= U15 =爲0x1
__m128i vnMask = _mm_set1_epi16(0×0001); //設置8個有符號的16位整數值。
UINT16 VN1 [I] = vnFloors [I] &爲0x1
__m128i VN1 = _mm_and_si128(vnFloors,vnMask); //計算a中128位值與b中128位值之間的按位與。
上證所內部函數是難以閱讀。你介意添加一些評論/等價的C++代碼塊來解釋這一部分? –
你想要代碼做什麼? – ronag
我有點被這個片段(神祕的標識和沒有上下文)困惑,但你爲什麼不換成乘法和加法比較? – zrxq