首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用AVX指令进行水平向量求和的最快方法

使用AVX指令进行水平向量求和的最快方法
EN

Stack Overflow用户
提问于 2012-03-20 02:11:59
回答 3查看 25.4K关注 0票数 20

我有一个包含四个64位浮点值的压缩向量。

我想要得到向量元素的和。

使用SSE (并使用32位浮点数),我可以执行以下操作:

代码语言:javascript
复制
v_sum = _mm_hadd_ps(v_sum, v_sum);
v_sum = _mm_hadd_ps(v_sum, v_sum);

不幸的是,尽管AVX具有_mm256_hadd_pd指令,但它的结果与SSE版本不同。我相信这是因为大多数AVX指令对每个低128位和高128位分别作为SSE指令工作,而不需要跨越128位的边界。

理想情况下,我正在寻找的解决方案应该遵循以下指导原则:

1)仅使用AVX/AVX2指令。(无SSE)

2)不超过2-3条指令。

然而,任何高效/优雅的方法(即使不遵循上面的指导原则)总是被广泛接受的。

非常感谢你的帮助。

-Luigi Castelli

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-03-20 03:24:24

如果您有两个__m256d向量x1x2,每个向量包含四个要水平求和的double,您可以这样做:

代码语言:javascript
复制
__m256d x1, x2;
// calculate 4 two-element horizontal sums:
// lower 64 bits contain x1[0] + x1[1]
// next 64 bits contain x2[0] + x2[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, _mm256_castpd256_pd128(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]

所以看起来3条指令会做你需要的2条水平求和。以上内容未经测试,但您应该了解其中的概念。

票数 28
EN

Stack Overflow用户

发布于 2013-12-05 09:39:09

如果您只想要总和,并且可以接受一些标量代码:

代码语言:javascript
复制
__m256d x;
__m256d s = _mm256_hadd_pd(x,x);
return ((double*)&s)[0] + ((double*)&s)[2];
票数 4
EN

Stack Overflow用户

发布于 2014-08-14 23:45:52

假设你有一个包含4个打包的double的__m256d向量,你想要计算它的分量之和,即a0, a1, a2, a3是你想要的每个双分量,然后这里是另一个a0 + a1 + a2 + a3解决方案:

代码语言:javascript
复制
// goal to calculate a0 + a1 + a2 + a3
__m256d values = _mm256_set_pd(23211.24, -123.421, 1224.123, 413.231);

// assuming _mm256_hadd_pd(a, b) == a0 + a1, b0 + b1, a2 + a3, b2 + b3 (5 cycles) ...
values = _mm256_hadd_pd(values, _mm256_permute2f128_pd(values, values, 1));
// ^^^^^^^^^^^^^^^^^^^^ a0 + a1, a2 + a3, a2 + a3, a0 + a1

values = _mm256_hadd_pd(values, values);
// ^^^^^^^^^^^^^^^^^^^^ (a0 + a1 + a2 + a3), (a0 + a1 + a2 + a3), (a2 + a3 + a0 + a1), (a2 + a3 + a0 + a1)

// Being that addition is associative then each component of values contains the sum of all its initial components (11 cycles) to calculate, (1-2 cycles) to extract, total (12-13 cycles)
double got = _mm_cvtsd_f64(_mm256_castpd256_pd128(values)), exp = (23211.24 + -123.421 + 1224.123 + 413.231);

if (got != exp || _mm256_movemask_pd(_mm256_cmp_pd(values, _mm256_set1_pd(exp), _CMP_EQ_OS)) != 0b1111)
    printf("Failed to sum double components, exp: %f, got %f\n", exp, got);
else
    printf("ok\n");

这个解决方案广播了可能有用的sum。

如果我误解了这个问题,我向您道歉。

代码语言:javascript
复制
$ uname -a
Darwin Samys-MacBook-Pro.local 13.3.0 Darwin Kernel Version 13.3.0: Tue Jun  3 21:27:35 PDT 2014; root:xnu-2422.110.17~1/RELEASE_X86_64 x86_64

$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.3.0
Thread model: posix
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9775538

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档