4

SSE2 を使用して内積を作成する必要があります (_mm_dp_ps も _mm_hadd_ps もありません):

#include <xmmintrin.h>

inline __m128 sse_dot4(__m128 a, __m128 b)
{
    const __m128 mult = _mm_mul_ps(a, b);
    const __m128 shuf1 = _mm_shuffle_ps(mult, mult, _MM_SHUFFLE(0, 3, 2, 1));
    const __m128 shuf2 = _mm_shuffle_ps(mult,mult, _MM_SHUFFLE(1, 0, 3, 2));
    const __m128 shuf3 = _mm_shuffle_ps(mult,mult, _MM_SHUFFLE(2, 1, 0, 3));

    return _mm_add_ss(_mm_add_ss(_mm_add_ss(mult, shuf1), shuf2), shuf3);
}

しかし、生成されたアセンブラを gcc 4.9 (実験的) -O3 で調べたところ、次のようになりました。

    mulps   %xmm1, %xmm0
    movaps  %xmm0, %xmm3         //These lines
    movaps  %xmm0, %xmm2         //have no use
    movaps  %xmm0, %xmm1         //isn't it ?
    shufps  $57, %xmm0, %xmm3
    shufps  $78, %xmm0, %xmm2
    shufps  $147, %xmm0, %xmm1
    addss   %xmm3, %xmm0
    addss   %xmm2, %xmm0
    addss   %xmm1, %xmm0
    ret

なぜgccがxmm0をxmm1、2、3にコピーするのか疑問に思っています...フラグを使用して取得したコードは次のとおりです: -march=native (より良く見えます)

    vmulps  %xmm1, %xmm0, %xmm1
    vshufps $78, %xmm1, %xmm1, %xmm2
    vshufps $57, %xmm1, %xmm1, %xmm3
    vshufps $147, %xmm1, %xmm1, %xmm0
    vaddss  %xmm3, %xmm1, %xmm1
    vaddss  %xmm2, %xmm1, %xmm1
    vaddss  %xmm0, %xmm1, %xmm0
    ret
4

4 に答える 4

5

以下は、元の SSE 命令のみを使用した内積であり、各要素で結果をスウィズルします。

inline __m128 sse_dot4(__m128 v0, __m128 v1)
{
    v0 = _mm_mul_ps(v0, v1);

    v1 = _mm_shuffle_ps(v0, v0, _MM_SHUFFLE(2, 3, 0, 1));
    v0 = _mm_add_ps(v0, v1);
    v1 = _mm_shuffle_ps(v0, v0, _MM_SHUFFLE(0, 1, 2, 3));
    v0 = _mm_add_ps(v0, v1);

    return v0;
}

これは (7 ではなく) 5 つの SIMD 命令ですが、レイテンシを隠す実際の機会はありません。どの要素も結果を保持します。float f = _mm_cvtss_f32(sse_dot4(a, b);

haddps命令のレイテンシはかなりひどいものです。SSE3 の場合:

inline __m128 sse_dot4(__m128 v0, __m128 v1)
{
    v0 = _mm_mul_ps(v0, v1);

    v0 = _mm_hadd_ps(v0, v0);
    v0 = _mm_hadd_ps(v0, v0);

    return v0;
}

わずか 3 つの SIMD 命令ですが、これはおそらく遅くなります。一度に複数のドット積を実行できる場合は、最初のケースで命令をインターリーブできます。最近のマイクロアーキテクチャでは、シャッフルは非常に高速です。

于 2013-06-08T22:44:53.620 に答える
4

SIMD を使用して内積を計算する場合は、一度に複数のベクトルを操作する方法を見つけることをお勧めします。たとえば、SSE では、4 つのベクトルがあり、固定ベクトルと内積を取りたい場合、(xxxx)、(yyyy)、(zzzz)、(wwww) のようにデータを配置し、各 SSE ベクトルを追加して、一度に 4 つの内積の結果。これにより、100% (4 倍のスピードアップ) の効率が得られ、4 成分ベクトルに限定されず、n 成分ベクトルでも 100% 効率的です。SSE のみを使用する例を次に示します。

#include <xmmintrin.h>
#include <stdio.h>

void dot4x4(float *aosoa, float *b, float *out) {   
    __m128 vx = _mm_load_ps(&aosoa[0]);
    __m128 vy = _mm_load_ps(&aosoa[4]);
    __m128 vz = _mm_load_ps(&aosoa[8]);
    __m128 vw = _mm_load_ps(&aosoa[12]);
    __m128 brod1 = _mm_set1_ps(b[0]);
    __m128 brod2 = _mm_set1_ps(b[1]);
    __m128 brod3 = _mm_set1_ps(b[2]);
    __m128 brod4 = _mm_set1_ps(b[3]);
    __m128 dot4 = _mm_add_ps(
        _mm_add_ps(_mm_mul_ps(brod1, vx), _mm_mul_ps(brod2, vy)),
        _mm_add_ps(_mm_mul_ps(brod3, vz), _mm_mul_ps(brod4, vw)));
    _mm_store_ps(out, dot4);

}

int main() {
    float *aosoa = (float*)_mm_malloc(sizeof(float)*16, 16);
    /* initialize array to AoSoA vectors v1 =(0,1,2,3}, v2 = (4,5,6,7), v3 =(8,9,10,11), v4 =(12,13,14,15) */
    float a[] = {
        0,4,8,12,
        1,5,9,13,
        2,6,10,14,
        3,7,11,15,
    };
    for (int i=0; i<16; i++) aosoa[i] = a[i];

    float *out = (float*)_mm_malloc(sizeof(float)*4, 16);
    float b[] = {1,1,1,1};
    dot4x4(aosoa, b, out);
    printf("%f %f %f %f\n", out[0], out[1], out[2], out[3]);

    _mm_free(aosoa);
    _mm_free(out);
}
于 2013-06-10T08:44:21.030 に答える
4

貼り付けた最初のリストは、SSE アーキテクチャー専用です。ほとんどの SSE 命令は、2 つのオペランドの構文のみをサポートします。命令は の形式ですa = a OP b

あなたのコードでは、aですmult。したがって、コピーが作成されずにmultxmm0あなたの例では)直接渡された場合、その値は上書きされ、残りの_mm_shuffle_ps命令で失われます

2 番目のリストを渡すことmarch=nativeで、AVX 命令を有効にしました。AVX は、SSE 命令で 3 つのオペランド構文を使用できるようにしますc = a OP b。この場合、ソース オペランドを上書きする必要がないため、追加のコピーは必要ありません。

于 2013-06-08T17:50:12.013 に答える
1

(実際、すべての賛成票にもかかわらず、この質問が投稿されたときに与えられた回答は、私が期待していたものではありませんでした.これが私が待っていた回答です。)

SSE命令

shufps $IMM, xmmA, xmmB

として機能しません

xmmB = f($IMM, xmmA) 
//set xmmB with xmmA's words shuffled according to $IMM

しかし、

xmmB = f($IMM, xmmA, xmmB) 
//set xmmB with 2 words of xmmA and 2 words of xmmB according to $IMM

これがtomulpsからの結果のコピーが必要な理由です。xmm0xmm1..3

于 2014-09-08T14:52:30.113 に答える