与AVX一起使用4个水平双精度和

8 sum intel avx

问题可以描述如下.

输入

__m256d a, b, c, d
Run Code Online (Sandbox Code Playgroud)

产量

__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]}
Run Code Online (Sandbox Code Playgroud)

到目前为止我所做的工作

这看起来很容易:两个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]}
Run Code Online (Sandbox Code Playgroud)

我是否能够以相同的方式置换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]}
Run Code Online (Sandbox Code Playgroud)

然后

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]}
Run Code Online (Sandbox Code Playgroud)

这是我想要的结果.

因此,我只需要找到如何执行

x,y => {x[0], x[2], y[0], y[2]}, {x[1], x[3], y[1], y[3]}
Run Code Online (Sandbox Code Playgroud)

不幸的是,我得出的结论是,使用VSHUFPD,VBLENDPD,VPERMILPD,VPERM2F128,VUNPCKHPD,VUNPCKLPD的任何组合都是不可能的.问题的关键在于,在__m256d的实例u中交换u [1]和u [2]是不可能的.

这真的是死路一条吗?或者我错过了排列指令?

Nor*_* P. 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);
Run Code Online (Sandbox Code Playgroud)

这给出了5条指令的结果.我希望我的常数合适.

您提出的排列当然可以实现,但它需要多个指令.对不起,我没有回答你的那部分问题.

编辑:我无法抗拒,这是完整的排列.(再次,尽我所能努力使常量正确.)你可以看到交换u[1]并且u[2]是可能的,只需要做一些工作.在第一代中跨越128位屏障是困难的.AVX.我还想说这VADD是优选的,VHADD因为VADD吞吐量是两倍,即使它正在进行相同数量的添加.

// {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);
Run Code Online (Sandbox Code Playgroud)