6

SSE3組み込み関数で記述されたコードをNEONSIMDに変換しようとしていますが、シャッフル機能が原因でスタックしています。GCC組み込み関数 ARMマニュアル、その他のフォーラムを確認しましたが、解決策を見つけることができませんでした。

コード:

_m128i upper = _mm_loadu_si128((__m128i*)p1);

register __m128i mask1 = _mm_set_epi8 (0x80,0x80,0x80,0x80,0x80,0x80,0x80,12,0x80,10,0x80,7,0x80,4,0x80,1);
register __m128i mask2 = _mm_set_epi8 (0x80,0x80,0x80,0x80,0x80,0x80,12,0x80,10,0x80,7,0x80,4,0x80,1,0x80);
__m128i temp1_upper = _mm_or_si128(_mm_shuffle_epi8(upper,mask1),_mm_shuffle_epi8(upper,mask2));

vtbl1_u8(uint8x8_t、uint8x8_t)命令は、宛先レジスタに値を割り当てるために使用できるルックアップテーブルを作成しますが、64ビットレジスタでのみ動作します。また、シャッフル操作は、開始時に実行する必要がある比較を実行します。 NEONと私はそれを効率的に行う方法を知りません。

r0 =(mask0&0x80)?0:SELECT(a、mask0&0x0f)// SELECT(a、n)は、aからn番目の8ビットパラメータを抽出します。

r1 =(mask1&0x80)?0:SELECT(a、mask1&0x0f)

..。

最初にマスクの上位ビットをチェックし、次にマスクの下位4ビットを効率的に選択する命令が見つかりません。レジスタ内の各ビットを比較してから、条件が指定されている場合は下位4ビットを選択できることはわかっていますが、私はそれを効率的に行うことを望んでいました。誰かが助けてくれるか、参考になることを願っています。

どうもありがとう、

乾杯!

4

2 に答える 2

3

インデックスが範囲外の場合、VTBLは0を返します。

ルックアップテーブルとして最大2つのQレジスタをサポートするため、非常に簡単です。

  1. ルックアップテーブルをQレジスタにロードします(たとえばQ8)
  2. vtbl.8 d0、{q8}、d0(d0にはマスクが含まれます)

それでうまくいきます。

ビット4〜6を邪魔にならないようにしたい場合は、vtblの前にそれらをマスクすることができます。

残念ながら、VBICは8ビットイミディエートにはまったく役に立ちません。

したがって、ビットマスクオペランドとして初期化されたレジスタを犠牲にする必要があります。

  1. vmov.u8、d1、#0x70
  2. ルックアップテーブルをQレジスタにロードします(たとえばQ8)
  3. vbic.i8 d0、d0、d1
  4. vtbl.8 d0、{q8}、d0(d0にはマスクが含まれます)
于 2011-11-01T09:56:29.317 に答える
3

vtbl2_u8入力を分割して出力を適切に結合する2回使用する必要があります。

#define uint8x16_to_8x8x2(v) ((uint8x8x2_t) { vget_low_u8(v), vget_high_u8(v) })

uint8x16_t a = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
uint8x16_t b = { 0x80, 0x0f, 0x01, 0x0e, 0x02, 0x0d, 0x03, 0x0c, 0x04, 0x0b, 0x05, 0x0a, 0x06, 0x09, 0x07, 0x08 };
uint8x16_t c = vcombine_u8(vtbl2_u8(uint8x16_to_8x8x2(a), vget_low_u8(b)), vtbl2_u8(uint8x16_to_8x8x2(a), vget_high_u8(b)));
// c = 00 ff 11 ee 22 dd 33 cc 44 bb 55 aa 66 99 77 88

Jakeが言っvtblたように、インデックスが範囲外の場合は常に0を返すため、この場合に特別な処理を行う必要はありません0x80

于 2012-10-12T21:02:54.140 に答える