SIMD 組み込み関数を使用してストリーム圧縮 (配列を取得し、空の要素を取り除く) を作成しようとしています。ループの各反復では、一度に 8 つの要素が処理されます (SIMD 幅)。
SSE 組み込み関数を使用すると、_mm_shuffle_epi8() を使用してこれをかなり効率的に実行できます。これは、16 エントリのテーブル ルックアップ (並列コンピューティング用語で収集) を実行します。シャッフル インデックスは事前に計算され、ビット マスクで検索されます。
for (i = 0; i < n; i += 8)
{
v8n_Data = _mm_load_si128(&data[i]);
mask = _mm_movemask_epi8(&is_valid[i]) & 0xff; // is_valid is byte array
v8n_Compacted = _mm_shuffle_epi8(v16n_ShuffleIndices[mask]);
_mm_storeu_si128(&compacted[count], v8n_Compacted);
count += bitCount[mask];
}
私の問題は、Altivec SIMD にもこれを実装したいということです (理由は聞かないでください - 見当違いのビジネス上の決定です)。Altivec には、重要な要素である _mm_movemask_epi8() に相当するものはありません。だから、私はどちらかへの方法を見つける必要があります
エミュレート _mm_movemask_epi8() - コストがかかるようで、いくつかのシフトと OR
シャッフル インデックスを効率的に直接生成する -
つまり、インデックス i は、圧縮されていないデータの i 番目の有効な要素のインデックスになります。
element_valid: 0 0 1 0 1 0 0 1 0
gather_indices: x x x x x x 6 4 1
scatter_indices: 3 3 2 2 1 1 1 0 0
これをシリアルに行うのは簡単ですが、パラレル (SIMD) にする必要があります。プレフィックスサムを使用してスキャッター インデックスを生成するのは簡単に思えますが、AltiVec も SSE もスキャッター命令を持たないため、代わりにインデックスを収集する必要があります。収集インデックスは分散インデックスの逆関数ですが、どのように並行して取得できますか? GPU プログラミングの黎明期には、スキャッターをギャザーに変換するのが一般的な手法だったことは知っていますが、説明されているこれら 2 つの方法はどれも実用的ではないようです。
圧縮が要素の順序を維持することを主張しないと、より効率的な実装が可能になるでしょうか? 私はそれをあきらめることができます。