私は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を実行しますか?エンディアンに問題がありますか?それは価値がありますか?
同等のものを見つけることができなかったので、最後の部分はムーブマスクです。誰かが何かを提案できますか?