2

この質問は、SSE で __m128i ベクトルの最大値を取得しますか? に似ているようです。ただし、整数 + 最大の代わりに、短と最小を使用します。これは私が思いついたものです:

typedef short int weight;

weight horizontal_min_Vec4i(__m128i x) {
    __m128i max1 = _mm_shufflehi_epi16(x, _MM_SHUFFLE(0, 0, 3, 2));
    __m128i max1b = _mm_shufflelo_epi16(x, _MM_SHUFFLE(0, 0, 3, 2));
    __m128i max2 = _mm_min_epi16(max1, max1b);
    //max2 = _mm_min_epi16(max2, x);
    max1 = _mm_shufflehi_epi16(max2, _MM_SHUFFLE(0, 0, 0, 1));
    max1b = _mm_shufflelo_epi16(max2, _MM_SHUFFLE(0, 0, 0, 1));
    __m128i max3 = _mm_min_epi16(max1, max1b);
    max2 = _mm_min_epi16(max2, max3);
    return min(_mm_extract_epi16(max2, 0), _mm_extract_epi16(max2, 4));
}

この関数は基本的に、x の上部と下部についてhttps://stackoverflow.com/a/18616825/1500111の回答と同じことを行います。したがって、最小値は __m128i 変数 max2 の位置 0 または 4 のいずれかにあることがわかっています。以下に示すSIMD 関数なしよりははるかに高速ですが 、最後の行horizontal_min_Vec4i_Plain(__m128i x)がボトルネックになっていると思います。_mm_extract_epi16 operationより良いスピードアップのために、これを達成するためのより良い方法はありますか? Haswell を使用しているので、最新の SSE 拡張機能にアクセスできます。

weight horizontal_min_Vec4i_Plain(__m128i x) {
    weight result[8] __attribute__((aligned(16)));
    _mm_store_si128((__m128i *) result, x);
    weight myMin = result[0];
    for (int l = 1; l < 8; l++) {
        if (myMin > result[l]) {
            myMin = result[l];
        }
    }
    return myMin;
}
4

1 に答える 1

2

符号付き比較と符号なし比較はほとんど同じですが、符号なし比較では上位ビットが設定されていない範囲よりも上位ビットが設定されている範囲の方が大きく、符号付き比較では上位ビットが設定されていない範囲よりも小さい範囲として扱われます。つまり、符号付き比較と符号なし比較は、次の規則によって相互に変換できます。

x <s y = (x ^ signbit) <u (y ^ signbit)
x <u y = (x ^ signbit) <s (y ^ signbit)

minこのプロパティはとに直接転送されるmaxため、次のようになります。

min_s(x, y) = min_u(x ^ signbit, y ^ signbit) ^ signbit

そして_mm_minpos_epu16、水平方向の最小値を処理するために使用でき、合計で次のようなものを取得できます

__m128i xs = _mm_xor_si128(x, _mm_set1_epi16(0x8000));
return _mm_extract_epi16(_mm_minpos_epu16(xs), 0) - 0x8000;

- 0x8000is^ 0x8000と符号拡張 ( extractzero-extends ) が 1 つにまとめられました。

于 2015-02-18T15:58:26.007 に答える