しかし、私はこのコードが何をしているのかわかりませんが、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]);
}
を使用すると、シリアルメモリアクセスの性能向上を失うが、剰余演算と2ドロップ2つのループに分割することにより、基本的にはこの
// 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]
}
と構文的に同等です条件付き演算子。
ここで、ループごとに2つの論理演算子があることに気が付いただけでなく、追加するかもしれない乗算は、SSE組み込み実装ではないです。あなたのvn1.m123i_u16 []アレイには何が保存されていますか?それは唯一のゼロと1つですか? もしそうなら、あなたはこの部分を必要とせず、それをなくすことができます。そうでない場合は、この配列のデータをゼロと1だけに正規化できますか? vn1.m123i_u16配列のみとゼロが含まれている場合、このコードは
uint16 iIsOddFloor = vn1.m128i_u16[m]
uint16 iIsEvenFloor = iIsOddFloor^0x1 // Flip 1 to 0, 0 to 1
なりまた、私はisEvenFloor * vnPx... part
を実行するためにも、iIsEvenFloor
とiIsOddFloor
レジスタを保存するためにSSEの乗算を使用していないわかります。すみませんが、u16乗算/レジスタのSSE組み込み関数が上から外れているのを覚えていませんが、このアプローチが役立つことを願っています。あなたが掲載しました、そして私の変更、我々はまだSSE1/2/3の組み込み関数を駆使していないコードのこのセクションで
// 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]
が、それはいくつかのポイントを提供するかもしれない:一部の最適化は、あなたがになっているはずです(コードをどのようにベクトル化するのか)について説明します。
最後に、私はすべてをテストすると言います。上記のコードを変更せずに実行し、変更とプロファイリングを再度行う前にプロファイリングしてください。実際のパフォーマンスの数字はあなたを驚かせるかもしれません!
アップデート1:
私はこれのために有用であることができ、関連する組み込み関数を選び出すためにIntel SIMD Intrinsics documentationを進めてきました。具体的にはビット単位のXORを見て、AND及びMULTは/
__m128データ型
を追加__m128iデータ型は16個の8ビット、8つの16ビット、4つの32ビット、あるいは2つの64を保持することができますビットの整数値。
__m128i _mm_add_epi16(__ m128iのA、__m128i b)は
__ m128iのA(__m128i _mm_mulhi_epu16 Bに8符号付きまたは符号なし16ビット整数に
を8つの符号付きまたは符号なし16ビット整数を追加、__m128i b)
aの8つの符号なし16ビット整数にbの8符号なし16ビット整数を乗算します。 は、8の符号なし32ビット
R0 = HIWORD(A0の*のB0)
R1 = HIWORD(A1の*のB1)
R2 = HIWORD(A2の*のB2)
結果の上位16ビットをパックR3 = HIWORD(A3の*のB3)
..
R7 = HIWORD(A7の*のB7)
__m128i _mm_mullo_epi16(__ m128iのA、__m128i b)は
乗算8符号付きまたは符号なし16ビット整数からaは8-signedまたはunsigned 16- bからの8ビット整数。 は、8符号付きまたは符号なし32ビット
R0 = LOWORD(A0の*のB0)
R1 = LOWORD(A1の*のB1)
R2 = LOWORD(A2の* B2の)結果の上位16ビットをパック
R3 = LOWORD(A3の*のB3)
..
R7 = LOWORD(A7の*のB7)
__m128i _mm_and_si128(__ m128iのA、__m128i b)は
はビット単位を実行し、128ビットのm1の値とm2の128ビットの値。
__m128i _mm_andnot_si128(__ m128i aは、__m128i b)は
はビット単位を計算し、Bに128ビット値とNOT IN 128 ビット値のビット単位の。
__m128i _mm_xor_si128(__ m128iのA、__m128i b)は
は、M2における128ビット値M1に128ビット値のビットごとの排他的論理和を実行します。参照のためのあなたのコードの例からALSO
uint16のU1 = U2 = U3 ...= u15 = 0x1
__m128i vnMask = _mm_set1_epi16(0x0001); // 8つの符号付き16ビット整数値を設定します。
uint16のVN1 [I] = vnFloors [I] & 0x1の
__m128i VN1 = _mm_and_si128(vnFloors、vnMask)。 // aの128ビット値とbの128ビット値のビット単位の論理積を計算します。
SSEの組み込み関数が読みにくい。その時から、私は解決策を最適化するために、SSEのベクトル化を使用することができました。このセクションを説明するためにいくつかのコメント/等価なC++コードブロックを追加してもよろしいですか? –
コードで何をしたいですか? – ronag
私はこのスニペット(潜在的な識別子とコンテキストなし)に多少なりとも困惑しますが、なぜ比較を乗算と加算に置き換えないのですか? – zrxq