2012-08-08 10 views
5

私は高速コーナーの最適化を続行し、 _mm_movemask_epi8 SSE命令に固執しました。私はuint8x16_t入力のARM Neonのためにどのように書き換えることができますか?私はこれのいずれかをテストしていませんが、このような何かがうまくいくかもしれないSSE _mm_movemask_epi8 ARM NEONの同等メソッド

答えて

0

は正しい動作します:

int32_t _mm_movemask_epi8_neon(uint8x16_t input) 
{ 
    const int8_t __attribute__ ((aligned (16))) xr[8] = {-7,-6,-5,-4,-3,-2,-1,0}; 
    uint8x8_t mask_and = vdup_n_u8(0x80); 
    int8x8_t mask_shift = vld1_s8(xr); 

    uint8x8_t lo = vget_low_u8(input); 
    uint8x8_t hi = vget_high_u8(input); 

    lo = vand_u8(lo, mask_and); 
    lo = vshl_u8(lo, mask_shift); 

    hi = vand_u8(hi, mask_and); 
    hi = vshl_u8(hi, mask_shift); 

    lo = vpadd_u8(lo,lo); 
    lo = vpadd_u8(lo,lo); 
    lo = vpadd_u8(lo,lo); 

    hi = vpadd_u8(hi,hi); 
    hi = vpadd_u8(hi,hi); 
    hi = vpadd_u8(hi,hi); 

    return ((hi[0] << 8) | (lo[0] & 0xFF)); 
} 
0

注:

X := the vector that you want to create the mask from 
A := 0x808080808080... 
B := 0x00FFFEFDFCFB... (i.e. 0,-1,-2,-3,...) 

X = vand_u8(X, A); // Keep d7 of each byte in X 
X = vshl_u8(X, B); // X[7]>>=0; X[6]>>=1; X[5]>>=2; ... 
// Each byte of X now contains its msb shifted 7-N bits to the right, where N 
// is the byte index. 
// Do 3 pairwise adds in order to pack all these into X[0] 
X = vpadd_u8(X, X); 
X = vpadd_u8(X, X); 
X = vpadd_u8(X, X); 
// X[0] should now contain the mask. Clear the remaining bytes if necessary 

これはvpaddのみ64上で動作するので、128ビットのベクトルを処理するために、一度繰り返される必要があるだろうビットベクトル。それは、コードを以下のようになりますいくつかのテストの後

+0

こんにちは、@Michael thanxです。あなたはどのように私はベクトルBを必要なバイトで埋めることができます説明できますか? Aのために私はvdup_n_u8(0x80)を使うことができますが、私はAのためにそれをどうすればいいのですか?また、あなたはvshl_u8を書くことができますが、コメントには右シフトがありますか? – inspirit

+0

const配列(?)からベクトルB: 'vld1'を初期化します。右シフトについて:ARMのドキュメントでは、「シフト値が正の場合は左シフト、そうでない場合は右シフトです。」あなたがシフトしたデータが 'u8'か' s8'を使う必要があるのか​​どうかは完全にはわかりません。 – Michael

+0

私は配列からBをロードする必要があることを理解しています。それについてもっと具体的にすることができますか? [0、-1、-2、-3、-4、-5、-6、-7]でなければなりません。はい、私は今すぐu3データベクトルのためにそれが必要です – inspirit

5

私はこのポストはかなり古くなって知っているが、私はそれが便利な私の(検証)溶液を得ました。これは、入力引数のすべてのレーンですべて1 /すべて0とみなします。

const uint8_t __attribute__ ((aligned (16))) _Powers[16]= 
    { 1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128 }; 

// Set the powers of 2 (do it once for all, if applicable) 
uint8x16_t Powers= vld1q_u8(_Powers); 

// Compute the mask from the input 
uint64x2_t Mask= vpaddlq_u32(vpaddlq_u16(vpaddlq_u8(vandq_u8(Input, Powers)))); 

// Get the resulting bytes 
uint16_t Output; 
vst1q_lane_u8((uint8_t*)&Output + 0, (uint8x16_t)Mask, 0); 
vst1q_lane_u8((uint8_t*)&Output + 1, (uint8x16_t)Mask, 8); 

(とにかくマインドhttp://gcc.gnu.org/bugzilla/show_bug.cgi?id=47553、。)同様

マイケルに、トリックは、非ヌルのエントリのインデックスの力を形成するために、それらを3回対毎合計することです。これは、追加するたびにストライドを倍にするためにデータサイズを増やすことで行う必要があります。 2 x 8 8ビットのエントリから2 x 4 16ビットに、次に2 x 2 32ビットと2 x 1 64ビットに減らします。これらの2つの数字の下位バイトが解決策を示します。 NEONを使用して単一の短い値を形成するために、それらを一緒にまとめる簡単な方法はないと思います。

入力が適切な形式であり、パワーを事前にロードできる場合は、6つのNEON命令を実行します。

関連する問題