SIMD要求内存数据16字节对齐的问题
SIMD要求处理的数据必须是16字节对齐的,请问普通情况下new的一个数组可以直接传递给simd的指针吗?
例如我先开辟一个普通的float型数组
float *buf = new float[100];
再用一个__m128的SIMD的指针来指向它
__m128 *p= (__m128*) buf;
因为new开辟的数组不一定是16字节对齐的,
请问这种指针传递方法有问题吗? 多谢了!
主要是后续的对这个指针的操作会不会出现问题?
[解决办法]
我给你个正确可行以及确定的答案:
如果动态分配,用memalign分配
如果分在栈上,用__attritube__((aligned(16)))
[解决办法]
单一变量默认就是对齐的:
{
int a; // 已对齐到int边界
long double f; // 已对齐到double边界
}
auto p1 = new long long; // *p1已对齐到long long边界
auto p2 = new short; // *p2已对齐到short边界
结构体或类,默认是按各成员对齐单位的最小公倍数对齐的:
struct tag1 // 已对齐到同时满足int和long double对齐的内存。
{
int a; // 已对齐到int边界
long double f; // 已对齐到double边界
};
{
tag obj1; //已对齐
}
auto p3 = new tag;//已对齐
当然,结构体或类中有多个成员时,各成员的位置还可能会被调整来适应对齐:
struct tag2 // 对齐到8字节边界
{
WORD wVal1; // 已对齐到2字节边界(因为对齐到8字节边界即也满足了2字节边界的对齐)
WORD wVal2; // 已对齐。但是为了满足dwVal3的对齐要求,在其后再追加4字节的空字节
INT64 dwVal3; // 已对齐(到8字节边界)
};
但是如果你加了#pragma pack(n),就可能有诺甘成员不满足对齐(仅限于成员默认的对齐数大于pack指定的n的成员),而且因为诺甘成员“不再需要”(你用了pack,编译器就以为你放弃了符合条件的成员的对齐请求)对齐,结构体的大小也可能会变得比没有pack修饰时的要小。
[解决办法]
既然你用了C++,你要求的这种对齐需要一些变通的办法才能比较优雅的实现:
__m128 *p = new __m128[count];//不管这个__m128是存放在哪里、用途是什么,好歹他对于编译器也只是各类型。这样做可以保证对齐。
如果实在受不了这种直接new,或者因为某些原因不能直接new,也可以用下面的办法:
float * buf = new alignas(16) float [100];
__m128 *p= (__m128*) buf;
鉴于一些编译器还不支持alignas关键字,
float * buf = (float *)new std::align_storage<sizeof(__m128), 16>::type [100 * sizeof(float) / sizeof(__m128)];//注意这一行需要根据使用场景调整,我不知道你具体的使用场景,所以暂时只能这样
__m128 *p= (__m128*) buf;
这样肯定是对齐的
[解决办法]
纠正:new开辟的数组不一定是16字节对齐的。