sum - 使用 AVX 一次性完成 4 个水平 double 求和

标签 sum intel avx

这个问题可以描述如下。

输入

__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]}

到目前为止我所做的工作

这看起来很简单:两个 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]。

问题

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

最佳答案

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。我也想说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);

关于sum - 使用 AVX 一次性完成 4 个水平 double 求和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10833234/

相关文章:

c - 优化从 AVX2 寄存器中提取 64 位值

c++ - 将 vector 以不匹配的大小加载到AVX2寄存器中

c# - LINQ-to-SQL - 'Sum' 里面选择新

c - 根据用户输入的数组添加值

python - Numpy sum() 出现 'keepdims' 错误

c++ - GCC 中的 FMA3 : how to enable

memory - x86 内存排序 : Loads Reordered with Earlier Stores vs. 处理器内转发

x86 - 如何找到 AVX 向量中元素的索引?

mysql - 一组中的计数总和

operating-system - STARTUP IPI 对应用程序处理器有什么影响?