8

この問題は次のように説明できます。

入力

__m256d a, b, c, d

出力

__m256d s = {a[0]+a[1]+a[2]+a[3], b[0]+b[1]+b[2]+b[3], 
             c[0]+c[1]+c[2]+c[3], d[0]+d[1]+d[2]+d[3]}

今までやってきた仕事

簡単そうに思えた: 2 つの VHADD の間にいくつかのシャッフルがあるが、実際には、AVX によって特徴付けられるすべての順列を組み合わせても、その目標を達成するために必要な順列そのものを生成することはできない。説明させてください:

VHADD x, a, b => x = {a[0]+a[1], b[0]+b[1], a[2]+a[3], b[2]+b[3]}
VHADD y, c, d => y = {c[0]+c[1], d[0]+d[1], c[2]+c[3], d[2]+d[3]}

x と y を同じ方法で並べ替えて取得できましたか?

x1 = {a[0]+a[1], a[2]+a[3], c[0]+c[1], c[2]+c[3]}
y1 = {b[0]+b[1], b[2]+b[3], d[0]+d[1], d[2]+d[3]}

それから

VHADD s, x1, y1 => s1 = {a[0]+a[1]+a[2]+a[3], b[0]+b[1]+b[2]+b[3], 
                         c[0]+c[1]+c[2]+c[3], d[0]+d[1]+d[2]+d[3]}

これは私が望んでいた結果です。

したがって、実行する方法を見つける必要があります

x,y => {x[0], x[2], y[0], y[2]}, {x[1], x[3], y[1], y[3]}

残念ながら、VSHUFPD、VBLENDPD、VPERMILPD、VPERM2F128、VUNPCKHPD、VUNPCKLPD の任意の組み合わせを使用しても、これはおそらく不可能であるという結論に達しました。問題の核心は、__m256d のインスタンス u で u[1] と u[2] を入れ替えることができないということです。

質問

これは本当に行き止まりですか?または、置換命令を見逃しましたか?

4

2 に答える 2

6

VHADD指示は通常の後に続くことを意図していますVADD。次のコードは、あなたが望むものを与えるはずです:

// {a[0]+a[1], b[0]+b[1], a[2]+a[3], b[2]+b[3]}
__m256d sumab = _mm256_hadd_pd(a, b);
// {c[0]+c[1], d[0]+d[1], c[2]+c[3], d[2]+d[3]}
__m256d sumcd = _mm256_hadd_pd(c, d);

// {a[0]+a[1], b[0]+b[1], c[2]+c[3], d[2]+d[3]}
__m256d blend = _mm256_blend_pd(sumab, sumcd, 0b1100);
// {a[2]+a[3], b[2]+b[3], c[0]+c[1], d[0]+d[1]}
__m256d perm = _mm256_permute2f128_pd(sumab, sumcd, 0x21);

__m256d sum =  _mm256_add_pd(perm, blend);

これにより、5 つの命令で結果が得られます。定数が正しいことを願っています。

あなたが提案した順列は確かに達成可能ですが、複数の指示が必要です。申し訳ありませんが、私はあなたの質問のその部分に答えていません。

編集:私は抵抗できませんでした。これが完全な順列です。(ここでも、定数を正しく設定するために最善を尽くしました。) スワップが可能であることがわかりますu[1]u[2]少し手間がかかります。初代では128ビットの壁を越えるのは難しい。AVX。また、同じ数の追加を行っているにもかかわらず、2 倍のスループットがあるため、VADDより好ましいと言いたいです。VHADDVADD

// {x[0],x[1],x[2],x[3]}
__m256d x;

// {x[1],x[0],x[3],x[2]}
__m256d xswap = _mm256_permute_pd(x, 0b0101);

// {x[3],x[2],x[1],x[0]}
__m256d xflip128 = _mm256_permute2f128_pd(xswap, xswap, 0x01);

// {x[0],x[2],x[1],x[3]} -- not imposssible to swap x[1] and x[2]
__m256d xblend = _mm256_blend_pd(x, xflip128, 0b0110);

// repeat the same for y
// {y[0],y[2],y[1],y[3]}
__m256d yblend;

// {x[0],x[2],y[0],y[2]}
__m256d x02y02 = _mm256_permute2f128_pd(xblend, yblend, 0x20);

// {x[1],x[3],y[1],y[3]}
__m256d x13y13 = _mm256_permute2f128_pd(xblend, yblend, 0x31);
于 2012-05-31T14:27:30.543 に答える
0

そのような順列を可能にする命令は知りません。AVX 命令は通常、レジスタの上位 128 ビットと下位 128 ビットがある程度独立しているように動作します。2 つの半分の値を混在させる機能はあまりありません。私が考えることができる最良の実装は、この質問への回答に基づいています。

__m128d horizontal_add_pd(__m256d x1, __m256d x2)
{
    // calculate 4 two-element horizontal sums:
    // lower 64 bits contain x1[0] + x1[1]
    // next 64 bits contain x2[0] + x1[1]
    // next 64 bits contain x1[2] + x1[3]
    // next 64 bits contain x2[2] + x2[3]
    __m256d sum = _mm256_hadd_pd(x1, x2);
    // extract upper 128 bits of result
    __m128d sum_high = _mm256_extractf128_pd(sum1, 1);
    // add upper 128 bits of sum to its lower 128 bits
    __m128d result = _mm_add_pd(sum_high, (__m128d) sum);
    // lower 64 bits of result contain the sum of x1[0], x1[1], x1[2], x1[3]
    // upper 64 bits of result contain the sum of x2[0], x2[1], x2[2], x2[3]
    return result;
}

__m256d a, b, c, d;
__m128d res1 = horizontal_add_pd(a, b);
__m128d res2 = horizontal_add_pd(c, d);
// At this point:
//     res1 contains a's horizontal sum in bits 0-63
//     res1 contains b's horizontal sum in bits 64-127
//     res2 contains c's horizontal sum in bits 0-63
//     res2 contains d's horizontal sum in bits 64-127
// cast res1 to a __m256d, then insert res2 into the upper 128 bits of the result
__m256d sum = _mm256_insertf128_pd(_mm256_castpd128_pd256(res1), res2, 1);
// At this point:
//     sum contains a's horizontal sum in bits 0-63
//     sum contains b's horizontal sum in bits 64-127
//     sum contains c's horizontal sum in bits 128-191
//     sum contains d's horizontal sum in bits 192-255

これはあなたが望むものでなければなりません。上記は、合計 7 つの命令で実行できるはずです (キャストは実際には何もするべきではありません。コンパイラが の値を処理する方法を変更するようにコンパイラに通知するだけです) res1horizontal_add_pd()十分な数のレジスタが利用可能です。

于 2012-05-31T12:53:49.223 に答える