2

公式の Intel C++ Intrinsic Reference を読むと、

SSE 2には次のコマンドがあります

__m128i _mm_madd_epi16(__m128i a, __m128i b)

a の 8 つの符号付き 16 ビット整数を b の 8 つの符号付き 16 ビット整数で乗算します。符号付き 32 ビット整数の結果をペアごとに加算し、4 つの符号付き 32 ビット整数の結果をパックします。

SSE 3が持っている間

__m128i _mm_maddubs_epi16 (__m128i a, __m128i b)

符号付きバイトと符号なしバイトを乗算し、符号付きワードの水平ペアを追加し、飽和符号付きワードをパックします。

私は8ビットのピクセルを扱っており、SSE 2のみを使用する必要があるため(古いアーキテクチャがターゲットです)、8ビットのmadd命令が必要です。どうすればそれを進めることができますか?

4

1 に答える 1

2

これが機能することを願っています-ここにはコンパイラがありません。しかし、私が何かを見逃していたとしても、全体的なアイデアを得る必要があります.

_mm_setzero_si128編集:直接使用する方がよいことを指摘してくれた@Peter Cordesに感謝します。

inline __m128i _mm_madd_epi8_SSE2(const __m128i & a, const __m128i & b)
{
    // a = 0x00 0x01 0xFE 0x04 ...
    // b = 0x00 0x02 0x80 0x84 ...

    // To extend signed 8-bit value, MSB has to be set to 0xFF
    __m128i sign_mask_a  = _mm_cmplt_epi8(a, _mm_setzero_si128());
    __m128i sign_mask_b  = _mm_cmplt_epi8(b, _mm_setzero_si128());

    // sign_mask_a = 0x00 0x00 0xFF 0x00 ...
    // sign_mask_b = 0x00 0x00 0xFF 0xFF ...

    // Unpack positives with 0x00, negatives with 0xFF
    __m128i a_epi16_l    = _mm_unpacklo_epi8(a, sign_mask_a);
    __m128i a_epi16_h    = _mm_unpackhi_epi8(a, sign_mask_a);
    __m128i b_epi16_l    = _mm_unpacklo_epi8(b, sign_mask_b);
    __m128i b_epi16_h    = _mm_unpackhi_epi8(b, sign_mask_b);

    // Here - valid 16-bit signed integers corresponding to the 8-bit input
    // a_epi16_l = 0x00 0x00 0x01 0x00 0xFE 0xFF 0x04 0x00 ... 

    // Get the a[i] * b[i] + a[i+1] * b[i+1] for both low and high parts
    __m128i madd_epi32_l = _mm_madd_epi16(a_epi16_l, b_epi16_l);
    __m128i madd_epi32_h = _mm_madd_epi16(a_epi16_h, b_epi16_h);

    // Now go back from 32-bit values to 16-bit values & signed saturate
    return _mm_packs_epi16(madd_epi32_l, madd_epi32_h);
}
于 2016-07-02T20:02:51.220 に答える