4

値の半分を取得し、半分のサイズの新しい配列に入れたいショーツの配列があります。各ブロックが 128 ビット (8 ショート) である、この種のパターンで特定の値を取得したいと考えています。これは私が使用する唯一のパターンです。「一般的なパターン」である必要はありません!

白の値は破棄されます。私の配列サイズは常に 2 の累乗になります。

unsigned short size = 1 << 8;
unsigned short* data = new unsigned short[size];

...

unsigned short* newdata = new unsigned short[size >>= 1];

unsigned int* uintdata = (unsigned int*) data;
unsigned int* uintnewdata = (unsigned int*) newdata;

for (unsigned short uintsize = size >> 1, i = 0; i < uintsize; ++i)
{
 uintnewdata[i] = (uintdata[i * 2] & 0xFFFF0000) | (uintdata[(i * 2) + 1] & 0x0000FFFF);
}

私はこのようなものから始めました:

static const __m128i startmask128 = _mm_setr_epi32(0xFFFF0000, 0x00000000, 0xFFFF0000, 0x00000000);
static const __m128i endmask128 = _mm_setr_epi32(0x00000000, 0x0000FFFF, 0x00000000, 0x0000FFFF);

__m128i* data128 = (__m128i*) data;
__m128i* newdata128 = (__m128i*) newdata;

マスクを繰り返し実行_mm_and_si128して、探している値を取得し、 と組み合わせて_mm_or_si128、結果を に入れることができますnewdata128[i]。ただし、物事を「圧縮」して白の値を削除する方法がわかりません。それができれば、仮面はまったくいらない気がする。

どうすればそれができますか?

とにかく、最終的には、この操作の逆も行い、2 倍のサイズの新しい配列を作成し、その中に現在の値を分散させたいと思います。

また、白いブロックに挿入する新しい値もあります。これは、元のデータのショーツの各ペアで繰り返し計算する必要があります。この計算はベクトル化できませんが、結果の値の挿入はベクトル化する必要があります。現在の値を新しい配列に「広げる」にはどうすればよいですか? また、計算された値を挿入する最良の方法は何でしょうか? 128 ビットの反復ごとにすべてを計算し、それらを独自の一時ブロック (64 ビット? 128 ビット?) に入れてから、一括して挿入する必要がありますか? __m128iそれとも、コストは一時的に入れるのと同等であるように思われるので、ターゲットに直接配置する必要がありますか? もしそうなら、私の他の価値観を台無しにすることなく、どうすればそれを行うことができますか?

これにはせいぜいSSE2操作を使用したいと思います。

4

1 に答える 1

1

試すことができる概要は次のとおりです。

  • _mm_unpackhi/lo_epi16ゼロを含むレジスタでインターリーブ命令 ( ) を使用して、16 ビット値を「展開」します。のような 2 つのレジスタができますB_R_B_R_
  • 右シフト作成_B_R_B_R
  • AND 最初のバージョンのRB___B___
  • そして、B は 2 番目のバージョンから___R___R
  • または一緒にB__RB__R

他の方向では、shift/and/or で設定した後、最後に _mm_packs_epi32 を使用します。

各方向は 10 個の SSE 命令である必要があります (定数のセットアップ、ゼロと AND マスク、およびロード/ストアはカウントされません)。

于 2013-01-07T19:20:35.700 に答える