如何在重载数组访问运算符时访问SIMD向量元素?

oli*_*kin 5 c++ operator-overloading simd clang avx

我正在尝试制作一些适用于MSVC的SIMD代码与Xcode 6上的Clang一起编译.不幸的是,我得到一个错误,其中数组访问运算符已经在我无法修复的自定义向量类中重载.向量模板具有使用SIMD内在函数的长度为4和8的数组的特化,但是数组访问运算符返回对向量元素的引用(用于更新该元素)在clang上给出了一个错误"非const引用不能绑定到向量元素".

完整的源代码

重载运算符:

#ifdef _MSC_VER
  float operator[](int idx) const { return v.m256_f32[idx]; } // m256_f32 MSVC only
  float& operator[](int idx) { return v.m256_f32[idx]; }
#else
  float operator[](int idx) const { return v[idx]; }
  float& operator[](int idx) { return v[idx]; }
#endif
Run Code Online (Sandbox Code Playgroud)

来自Clang的错误:

non-const reference cannot bind to vector element
  float& operator[](int idx) { return v[idx]; }
                                      ^~~~~~
Run Code Online (Sandbox Code Playgroud)

Pau*_*l R 5

我想你可能需要使用一个联盟,例如:

union U {
    __m256 v;
    float a[8];
};
Run Code Online (Sandbox Code Playgroud)

然后值运算符将是:

float operator[](int idx) const { U u = { v }; return u.a[idx]; }
Run Code Online (Sandbox Code Playgroud)

参考运算符虽然比较棘手,但我能看到的唯一方法是通过类型惩罚,所以通常需要注意:

float& operator[](int idx) { return ((float *)&v)[idx]; }
Run Code Online (Sandbox Code Playgroud)

我甚至不确定这会编译,你可能需要-fno-strict-aliasing.

为了避免这种肮脏,我想你可以考虑将你的成员变量__m256 v;改为U u;.

我希望你不要在任何性能关键的循环中做这种事情.

  • 相关:stackoverflow.com/q/24787268/ @PaulR,你说得对,技术上违反了严格的别名要求.但实际上,每个现有的编译器(据我所知)都允许SIMD向量类型对其组件的数组进行别名.所以即使没有`-fno-strict-aliasing`,这在实践中也是安全的 (2认同)