2

私はSSE2の組み込みに次のコードを持っています。Kinectからの入力を処理します。

__m128i md = _mm_setr_epi16((r0<<3)  | (r1>>5), ((r1<<6)  | (r2>>2) ), ((r2<<9)  | (r3<<1) | (r4>>7) ), ((r4<<4)  | (r5>>4) ), ((r5<<7)  | (r6>>1) ),((r6<<10) | (r7<<2) | (r8>>6) ), ((r8<<5)  | (r9>>3) ), ((r9<<8)  | (r10)   ));
md = _mm_and_si128(md, mmask);
__m128i mz = _mm_load_si128((__m128i *) &depth_ref_z[i]);
__m128i mZ = _mm_load_si128((__m128i *) &depth_ref_Z[i]);
mz = _mm_cmpgt_epi16(md, mz);
mZ = _mm_cmpgt_epi16(mZ, md);
mz = _mm_and_si128(mz, mZ);
md = _mm_and_si128(mz, md);
_mm_store_si128((__m128i *) frame,md)
if(_mm_movemask_epi8(mz)){ ... }

これは基本的に、SSEレジスタ内の11 uint8_t(r0-r10​​)から8 uint16_tをアンパックします(mmaskは定数であり、以前に作成されています)。次に、境界として機能する2つの配列から、対応する要素を含む2つのレジスタをロードします。それらをチェックし、ゼロ化された基準に適合しない要素を持つレジスタを作成します。次に、それらを保存し、各要素をさらに処理します。movemaskは、どの要素も通過しない場合に最適化として機能します。その場合、処理をスキップできます。

これはうまく機能し、今度はNEONにも移植したいと思います。2つの部分を除いて、そのほとんどは簡単です。SSE2コードからのアセンブラー出力(gcc)を見ると、_mm_setr_epi16で8つのuint16_t移動を実行する代わりに、シフトしてuint32_tに移動し、最後に4つの移動を実行することがわかります。それは効率的だと思われ、コンパイラがそれを処理するので、私はコードを変更しませんでした。NEONの場合は手動で適用する必要がありますか?8 vsetq_lane_u16の代わりに、シフトを実行して4 vsetq_lane_u32を実行しますか?エンディアンに問題がありますか?それは価値がありますか?

同等のものを見つけることができなかったので、最後の部分はムーブマスクです。誰かが何かを提案できますか?

4

1 に答える 1

1

SSE2 ではなく、単純な C コードから始めることをお勧めします。この低レベルでは容易に見られない最適化の機会があるかもしれません

于 2012-02-22T20:21:23.617 に答える