ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c – 获得8个源__m256向量的__m256水平和的最有效方法

2019-10-03 06:06:01  阅读:220  来源: 互联网

标签:c matrix sum sse avx


我知道如何将一个__m256加起来得到一个求和值.但是,我有8个矢量
输入

1: a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
.....,
.....,
8: h[0], h[1], h[2], h[3], h[4], a[5], a[6], a[7]

产量

a[0]+a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7], 
 ...., 
h[0]+h[1]+h[2]+h[3]+h[4]+h[5]+h[6]+h[7]

我的方法.好奇如果有更好的方法.

            __m256 sumab = _mm256_hadd_ps(accumulator1, accumulator2);
            __m256 sumcd = _mm256_hadd_ps(accumulator3, accumulator4);

            __m256 sumef = _mm256_hadd_ps(accumulator5, accumulator6);
            __m256 sumgh = _mm256_hadd_ps(accumulator7, accumulator8);

            __m256 sumabcd = _mm256_hadd_ps(sumab, sumcd);
            __m256 sumefgh = _mm256_hadd_ps(sumef, sumgh);

            __m128 sumabcd1 = _mm256_extractf128_ps(sumabcd, 0);
            __m128 sumabcd2 = _mm256_extractf128_ps(sumabcd, 1);
            __m128 sumefgh1 = _mm256_extractf128_ps(sumefgh, 0);
            __m128 sumefgh2 = _mm256_extractf128_ps(sumefgh, 1);

            sumabcd1 = _mm_add_ps(sumabcd1, sumabcd2);
            sumefgh1 = _mm_add_ps(sumefgh1, sumefgh2);

 __m256 result =_mm256_insertf128_ps(_mm256_castps128_ps256(sumabcd1), sumefgh1, 1)

解决方法:

您可以使用2x _mm256_permute2f128_ps排列垂直vaddps的低和高通道.这不是2x extractf128 / insertf128.这也将两个128b vaddps xmm指令转换为单个256b vaddps ymm.

vperm2f128与Intel CPU上的单个vextractf128或vinsertf128一样快.然而,它在AMD上的速度很慢(在Bulldozer系列上有8c-ops,延迟时间为4c).尽管如此,即使你关心AMD的性能,你也需要避免它. (其中一个permutes实际上可以是vinsertf128).

__m256 hsum8(__m256 a, __m256 b, __m256 c, __m256 d,
             __m256 e, __m256 f, __m256 g, __m256 h)
{
    // a = [ A7 A6 A5 A4 | A3 A2 A1 A0 ]
    __m256 sumab = _mm256_hadd_ps(a, b);
    __m256 sumcd = _mm256_hadd_ps(c, d);

    __m256 sumef = _mm256_hadd_ps(e, f);
    __m256 sumgh = _mm256_hadd_ps(g, h);

    __m256 sumabcd = _mm256_hadd_ps(sumab, sumcd);  // [ D7:4 ... A7:4 | D3:0 ... A3:0 ]
    __m256 sumefgh = _mm256_hadd_ps(sumef, sumgh);  // [ H7:4 ... E7:4 | H3:0 ... E3:0 ]

    __m256 sum_hi = _mm256_permute2f128_ps(sumabcd, sumefgh, 0x31);  // [ H7:4 ... E7:4 | D7:4 ... A7:4 ]
    __m256 sum_lo = _mm256_permute2f128_ps(sumabcd, sumefgh, 0x20);  // [ H3:0 ... E3:0 | D3:0 ... A3:0 ]

    __m256 result = _mm256_add_ps(sum_hi, sum_lo);
    return result;
}

这个compiles as you’d expect.第二个permute2f128实际编译为vinsertf128,因为它只使用每个输入的低通道,就像vinsertf128一样. gcc 4.7及更高版本执行此优化,但只有更新的clang版本(v3.7).如果您关心旧铿锵,请在源级别执行此操作.

源代码行的节省大于指令中的节省,因为_mm256_extractf128_ps(sumabcd,0);编译为零指令:它只是一个演员.没有编译器应该使用除了1之外的imm8发出vextractf128.(vmovdqa xmm / m128,xmm总是更好地获得低通道).英特尔做得很好,因为普通的VEX前缀没有足够的空间来编码更长的矢量,因此在未来验证时会浪费一个指令字节.

两个vaddps xmm指令可以并行运行,因此使用单个vaddps ymm主要是吞吐量(和代码大小)增益,而不是延迟.

尽管如此,我们还是完全消除了最终的vinsertf128,从而缩短了3个周期.

vhaddps是3 uops,5c延迟,每2c吞吐量一个. (Skylake的6c延迟).这三个uop中的两个在shuffle端口上运行.我猜它基本上是做2x shufps来为addps生成操作数.

如果我们可以使用单个shufps / addps或其他东西来模拟haddps(或至少得到我们可以使用的水平操作),我们就会提前出来.不幸的是,我不知道如何.单个shuffle只能使用来自两个向量的数据生成一个结果,但我们需要两个输入到垂直addps以获得来自两个向量的数据.

我不认为以另一种方式做横向总和看起来很有希望. Normally, hadd is not a good choice,因为常见的水平和用例只关心其输出的一个元素.这不是这里的情况:实际使用每个hadd结果的每个元素.

标签:c,matrix,sum,sse,avx
来源: https://codeday.me/bug/20191003/1847346.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有