你如何使用__m256d?
假设我想在具有3-64位双精度分量(x,y和z)的简单Vector3类上使用Intel AVX指令_mm256_add_pd
.使用它的正确方法是什么?
由于x,y和z是Vector3类的成员,_我可以将它们与__m256d变量联合声明吗?
union Vector3 { struct { double x,y,z ; } ; __m256d _register ; // the Intel register? } ;
然后我可以去:
Vector3 add( const Vector3& o ) { Vector3 result; result._register = _mm256_add_pd( _register,o._register ) ; // add 'em return result; }
这会起作用吗?或者我是否需要申报临时工,
Vector3 add( const Vector3& o ) { __m256d d1 = *(__m256d*)(&x) ; // ? Cast to __m256d? __m256d d2 = *(__m256d*)(&o.x) ; // ? Cast to __m256d? __m256d result = _mm256_add_pd( d1,d2 ) ; // add 'em return Vector3( result ) ; // make a ctor that accepts __m256d? }
编辑
我想出了这个例子,
#include <stdio.h> #include <intrin.h> int main() { __m256d a,b,res; for( int i = 0; i < sizeof(__m256d)/sizeof(double); i++ ) { a.m256d_f64[i] = i ; b.m256d_f64[i] = 2*i ; } // Perform __4__ adds. res = _mm256_add_pd(a,b); for( int i = 0; i < sizeof(__m256d)/sizeof(double); i++ ) { printf("%f + %f = %f\n",a.m256d_f64[i],b.m256d_f64[i],res.m256d_f64[i]); } puts(""); }
我想现在的问题是,_mm256_add_pd是否会自动加载操作,或者如果我没有将我的__m256d寄存器声明为接近使用位置的本地,那么会有什么东西搞砸了? (我害怕hotel room / deskdrawer型问题)
编辑2:
我尝试在我相当大的项目中添加一个__m256寄存器,我得到了很多
error C2719: ‘value’: formal parameter with __declspec(align(’32’)) won’t be aligned
错误,它让我相信你不能把__m256寄存器放在一个类中,而应该声明它们是本地的?
解决方法
首先,我想澄清一点混乱. __m256d不是一种寄存器,它是一种可以加载到AVX寄存器的数据类型. __m256d不再是寄存器而是int是寄存器.有几种方法可以将数据输入和输出__m256d(或任何其他矢量类型):
使用联合:是的,联合技巧有效.它工作得很好,因为联合通常会有正确的对齐方式(尽管malloc可能没有,使用posix_memalign或_aligned_malloc).
class Vector3 { public: Vector3(double xx,double yy,double zz); Vector3(__m256d vvec); Vector3 operator+(const Vector3 &other) const { return Vector3(_mm256_add_pd(vec,other.vec)); } union { struct { double x,z; }; __m256d vec; // a data field,maybe a register,maybe not }; };
使用内在函数:在函数内部,通常使用内在函数来更容易地将数据输入和输出矢量类型.
__m256d vec = ...; double x,z; vec = _mm256_add_pd(vec,_mm256_set_pd(x,z,0.0));
使用指针转换:由于几个原因,转换指针是最后的手段.
>指针可能未正确对齐.
>转换指针有时会破坏编译器的别名分析.
>指针式铸造绕过了许多安全保障.
所以我只使用指针转换来浏览大量数据.