8

ネオン組み込み関数を使用して、ACコードを最適化されたコードに変換しようとしています。

これは、演算子のベクトルではなく、2つの演算子で動作するcコードです。

uint16_t mult_z216(uint16_t a,uint16_t b){
unsigned int c1 = a*b;
    if(c1)
    {
        int c1h = c1 >> 16;
        int c1l = c1 & 0xffff;
        return (c1l - c1h + ((c1l<c1h)?1:0)) & 0xffff;
    }
    return (1-a-b) & 0xffff;
}

この操作のSEE最適化バージョンは、すでに次のように実装されています。

#define MULT_Z216_SSE(a, b, c) \
    t0  = _mm_or_si128 ((a), (b)); \ //Computes the bitwise OR of the 128-bit value in a and the 128-bit value in b.
    (c) = _mm_mullo_epi16 ((a), (b)); \ //low 16-bits of the product of two 16-bit integers
    (a) = _mm_mulhi_epu16 ((a), (b)); \ //high 16-bits of the product of two 16-bit unsigned integers
    (b) = _mm_subs_epu16((c), (a)); \ //Subtracts the 8 unsigned 16-bit integers of a from the 8 unsigned 16-bit integers of c and saturates
    (b) = _mm_cmpeq_epi16 ((b), C_0x0_XMM); \ //Compares the 8 signed or unsigned 16-bit integers in a and the 8 signed or unsigned 16-bit integers in b for equality. (0xFFFF or 0x0)
    (b) = _mm_srli_epi16 ((b), 15); \ //shift right 16 bits
    (c) = _mm_sub_epi16 ((c), (a)); \ //Subtracts the 8 signed or unsigned 16-bit integers of b from the 8 signed or unsigned 16-bit integers of a.
    (a) = _mm_cmpeq_epi16 ((c), C_0x0_XMM); \ ////Compares the 8 signed or unsigned 16-bit integers in a and the 8 signed or unsigned 16-bit integers in b for equality. (0xFFFF or 0x0)
    (c) = _mm_add_epi16 ((c), (b)); \ // Adds the 8 signed or unsigned 16-bit integers in a to the 8 signed or unsigned 16-bit integers in b.
    t0  = _mm_and_si128 (t0, (a)); \ //Computes the bitwise AND of the 128-bit value in a and the 128-bit value in b.
    (c) = _mm_sub_epi16 ((c), t0); ///Subtracts the 8 signed or unsigned 16-bit integers of b from the 8 signed or unsigned 16-bit integers of a.

私はこれをネオン組み込み関数を使用してほぼ変換しました:

#define MULT_Z216_NEON(a, b, out) \
    temp = vorrq_u16 (*a, *b); \
    // ??
    // ??
    *b = vsubq_u16(*out, *a); \
    *b = vceqq_u16(*out, vdupq_n_u16(0x0000)); \
    *b = vshrq_n_u16(*b, 15); \
    *out = vsubq_s16(*out, *a); \
    *a = vceqq_s16(*c, vdupq_n_u16(0x0000)); \
    *c = vaddq_s16(*c, *b); \
    *temp = vandq_u16(*temp, *a); \
    *out = vsubq_s16(*out, *a);

_mm_mullo_epi16 ((a), (b));とに相当するネオンが欠けているだけです_mm_mulhi_epu16 ((a), (b));。私が何かを誤解しているか、NEONにそのような組み込み関数がありません。NEONS組み込み関数を使用してこれらのステップをアーカイブする同等の方法がない場合は?

アップデート :

次の点を強調するのを忘れました。関数の演算子はuint16x8_tNEONベクトルです(各要素はuint16_t => 0〜65535の整数です)。答えでは、誰かが本質的なを使用することを提案しましたvqdmulhq_s16()。乗算組み込み関数はベクトルを符号付きの値として解釈し、間違った出力を生成するため、これを使用すると、指定された実装と一致しません。

4

2 に答える 2

5

次を使用できます。

uint32x4_t vmull_u16 (uint16x4_t, uint16x4_t) 

これは、32ビット積のベクトルを返します。結果を高い部分と低い部分に分割したい場合は、NEONunzip組み込みを使用できます。

于 2012-07-02T18:30:50.593 に答える
1

vmulq_s16() は _mm_mullo_epi16 と同等です。_mm_mulhi_epu16 とまったく同じものはありません。最も近い命令は vqdmulhq_s16() で、これは「飽和、2 倍、乗算、上位部分を返す」です。符号付きの 16 ビット値のみで動作し、入力または出力を 2 で割って倍増を無効にする必要があります。

于 2012-07-02T22:02:13.933 に答える