c++ - GCC SSE 手写与生成

标签 c++ gcc sse simd

我正在搞SIMD优化,写了3个非常简单的 vector 类,并以两种不同的方式实现加法,一种是手写组件方式,一种是使用_mm_add_ps https://godbolt.org/z/fPAERV 。 有趣的是,GCC 无法(或者我没有正确地告诉它 x))使用 SSE 实现 vector 2 的加法,只有在明确地将第四个浮点添加到 vector (如 vector 3 中)之后,gcc 使用 SEE 指令生成加法,即使我在 16 字节边界上对齐 vector 。谁能告诉我为什么?

#include <xmmintrin.h>

struct alignas(16) vector final {
  union {
    struct {
      float x, y, z;
    };
    float axes[3];
    __m128 v;
  };

  vector(float x, float y, float z) noexcept : x(x), y(y), z(z) {};
  vector(__m128 v) noexcept : v(v){};
};

vector operator+(const vector& v0, const vector& v1) noexcept {
  return {_mm_add_ps(v0.v, v1.v)};
}

struct alignas(16) vector2 final {
  union {
    struct {
      float x, y, z;
    };
    float axes[3];
    __m128 v;
  };

  vector2(float x, float y, float z) noexcept : x(x), y(y), z(z) {};
  vector2(__m128 v) noexcept : v(v){};
};

vector2 operator+(const vector2& v0, const vector2& v1) noexcept {
  return {v0.x + v1.x, v0.y + v1.y, v0.z + v1.z};
}

struct alignas(16) vector3 final {
  union {
    struct {
      float x, y, z, w;
    };
    float axes[4];
    __m128 v;
  };

  vector3(float x, float y, float z, float w) noexcept : x(x), y(y), z(z), w(w) {};
  vector3(__m128 v) noexcept : v(v){};
};

vector3 operator+(const vector3& v0, const vector3& v1) noexcept {
  return {v0.x + v1.x, v0.y + v1.y, v0.z + v1.z, v0.w + v1.w};
}

使用 gcc9.2 和 -std=c++17 -O3 -Wall -Wextra 生成程序集

operator+(vector const&, vector const&):
        movaps  xmm1, XMMWORD PTR [rsi]
        addps   xmm1, XMMWORD PTR [rdi]
        movdqa  xmm0, xmm1
        movaps  XMMWORD PTR [rsp-24], xmm1
        movq    xmm1, QWORD PTR [rsp-16]
        ret
operator+(vector2 const&, vector2 const&):
        movss   xmm1, DWORD PTR [rdi+4]
        movss   xmm0, DWORD PTR [rdi+8]
        addss   xmm1, DWORD PTR [rsi+4]
        addss   xmm0, DWORD PTR [rsi+8]
        movss   xmm2, DWORD PTR [rdi]
        addss   xmm2, DWORD PTR [rsi]
        movss   DWORD PTR [rsp-20], xmm1
        movss   DWORD PTR [rsp-16], xmm0
        movq    xmm1, QWORD PTR [rsp-16]
        movss   DWORD PTR [rsp-24], xmm2
        movq    xmm0, QWORD PTR [rsp-24]
        ret
operator+(vector3 const&, vector3 const&):
        movaps  xmm0, XMMWORD PTR [rdi]
        addps   xmm0, XMMWORD PTR [rsi]
        movaps  XMMWORD PTR [rsp-40], xmm0
        mov     rax, QWORD PTR [rsp-32]
        movq    xmm0, QWORD PTR [rsp-40]
        movq    xmm1, rax
        mov     QWORD PTR [rsp-16], rax
        ret

最佳答案

“发明写入”通常是不允许的,并且可能会产生令人讨厌的编译器错误。 (因为线程安全,例如从另一个线程进行写入)。

尽管它是 union 对象的一部分,GCC 内部可能会将最后一个元素视为单独的元素,并且不愿意用“垃圾”来编写它。所以,是的,这是一个错过的优化,您必须手动解决。


一般来说,SIMD vector 不太适合保存 3D 几何 vector 。理想情况下,您可以构建数据,这样您就可以拥有 __m128 x四个 x坐标,另一个__m128 y四个 y坐标等。然后你可以在 3 addps 中进行 4 个 vector 加法指示。更好的是,执行 4 个 vector 长度或同时使用同一 vector 中的 x、y 和 z 的其他操作不涉及任何改组。

参见https://stackoverflow.com/tags/sse/info对于链接,尤其是 Slides: SIMD at Insomniac Games (GDC 2015)其中更详细地介绍了如何有效使用 SIMD 等。

但是当然,如​​果您已经在可以以不同方式布局数据的情况下这样做了,那么可能仍然存在其他情况,您只有几个单独的 vector 并且需要“float3”布局,并且仍然可以使用SIMD 也可以加快速度。

关于c++ - GCC SSE 手写与生成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59142599/

相关文章:

c++ - GCC 中的结构对齐(是否应在 typedef 中指定对齐?)

c++ - 初始化列表: cannot convert ‘Participant’ to ‘unsigned int’ in initialization

c - 定义全局变量,在 main 中得到不同的结果

c++ - 为什么在这种特殊情况下数据类型会影响性能?

c++ - 两个 SSE2 打包 double 的最优无分支条件选择

c++ - 在具有 'gdb' 的函数内的特定行中设置断点

c++ - C++两个模板,相同的名称,相同的签名,不同的类:如何强制编译器使用预期的模板?

c++ - 即使不添加任何搜索路径,Codeblocks 如何找到我的头文件

python - 如何用 C++ 扩展 Python?

c - SSE 到 NEON (_mm_movelh_ps)