【问题标题】:Adding 3D vectors using SIMD intrinsics使用 SIMD 内在函数添加 3D 向量
【发布时间】:2023-02-07 00:39:44
【问题描述】:

我有两个 3D 矢量流,我想使用 x86 AVX2 内在函数添加它们。我正在使用 GNU 编译器 11.1.0。希望代码能说明我想做什么:

// Example program
#include <utility> // std::size_t

#include <immintrin.h>

struct v3
{
    float data[3] = {};
};

void add(const v3* a, const v3* b, v3* c, const std::size_t& n)
{
    // c <- a + b
    for (auto i = std::size_t{}; i < n; i += 2) // 2 vector3s at a time ~6 data
    {
        // masking
        // [95:0] of a[i] move into [255:128], [95:0] of a[i+1] move into [255:128] of *another* 256-bit register
        // ^same with b[i]
        static const auto p1_mask = _mm256_setr_epi32(-1, -1, -1, 0, 0, 0, 0, 0);
        static const auto p2_mask = _mm256_setr_epi32(0, 0, 0, -1, -1, -1, 0, 0);
        
        const auto p1_leftop_packed = _mm256_maskload_ps(a[i].data, p1_mask);
        const auto p2_lefttop_packed = _mm256_maskload_ps(a[i].data, p2_mask);
        
        const auto p1_rightop_packed = _mm256_maskload_ps(b[i].data, p1_mask);
        const auto p2_rightop_packed = _mm256_maskload_ps(b[i].data, p2_mask);
        
        // addition is being done inefficiently with 2 AVX2 instructions!
        const auto result1_packed = _mm256_add_ps(p1_leftop_packed, p1_rightop_packed);
        const auto result2_packed = _mm256_add_ps(p2_leftop_packed, p2_rightop_packed);
        
        // store them back
        _mm256_maskstore_ps(c[i].data, p1_mask, result1_packed);
        _mm256_maskstore_ps(c[i].data, p2_mask, result2_packed);
    }
}



int main()
{
    // data
    const auto n = std::size_t{1000};
    v3 a[n] = {};
    v3 b[n] = {};
    v3 c[n] = {};
    
    // run
    add(a, b, c, n);
    
    return 0;
}

上面的代码有效,但性能非常糟糕。要更正它,我想我需要一个大致如下所示的版本:

    // c <- a + b
    for (auto i = std::size_t{}; i < n; i += 2) // 2 vector3s at a time ~6 data
    {
        // masking
        // [95:0] of a[i] move into [255:128], [95:0] of a[i+1] in [127:0]
        const auto leftop_packed = /*code required here*/;
        const auto rightop_packed = /*code required here*/;
        
        // addition is being done with only 1 AVX2 instruction
        const auto result_packed = _mm256_add_ps(leftop_packed, rightop_packed);
        
        // store them back
        // [95:0] of result_packed move into c[i], [223:128] of result_packed into c[i+1]
        /*code required here*/
    }

我如何实现这一目标?我很乐意在需要时提供任何其他信息。任何帮助将非常感激。

【问题讨论】:

  • 我想你一次可以只加载 8 个浮点数,然后如果你最后还有剩余的东西,你可以做一个蒙面存储(不确定这部分)。
  • 使用 char*float*__m256* 在 32 字节或 8 浮点块中工作,忽略向量边界,因为您只是在进行纯垂直元素加法。 float* 应该适合清理最后最多 7 个浮点数。

标签: c++ vectorization simd intrinsics avx2


【解决方案1】:

Eigen 库支持矢量化。它还具有许多已经实现的矢量/矩阵数学算法,而且效率也很高。如果可以的话,我建议您考虑使用它而不是滚动您自己的逻辑。

【讨论】:

    【解决方案2】:

    以下两个 cmets 表示相同。他们很好。按照他们说的去做。

    我想你一次可以只加载 8 个浮点数,然后如果你最后还有剩余的东西,你可以做一个蒙面存储(不确定这部分)。 – LHLaurini

    使用 char*__m256* 在 32 字节或 8 浮点块中工作,忽略向量边界,因为您只是在进行纯垂直加法。 – Peter Cordes

    【讨论】:

      猜你喜欢
      • 2018-07-21
      • 2018-06-11
      • 2020-12-12
      • 1970-01-01
      • 2015-01-08
      • 1970-01-01
      • 2015-07-24
      • 2014-05-12
      • 1970-01-01
      相关资源
      最近更新 更多