SIMD和动态内存分配[重复]
Posted
技术标签:
【中文标题】SIMD和动态内存分配[重复]【英文标题】:SIMD and dynamic memory allocation [duplicate] 【发布时间】:2012-10-03 16:37:39 【问题描述】:可能重复:SSE, intrinsics, and alignment
我是 SIMD 编程的新手,所以如果我问一个明显的问题,请原谅。
我进行了一些试验,结果想将 SIMD 值存储在动态分配的结构中。
代码如下:
struct SimdTest
__m128 m_simdVal;
void setZero()
__m128 tmp = _mm_setzero_ps();
m_simdVal = tmp; // <<--- CRASH ---
;
TEST( Plane, dynamicallyAllocatedPlane )
SimdTest* test = new SimdTest();
test->setZero();
delete test;
当执行带有 CRASH 注释的方法时,代码会崩溃,并出现以下异常:
Unhandled exception at 0x775315de in test-core.exe: 0xC0000005: Access violation reading location 0x00000000
有人可以解释一下为什么赋值操作会中断,以及应该如何动态分配包含 SIMD 的对象以使其正常工作?
我需要补充一点,如果我静态实例化 SimdTest 对象并调用 setZero 方法,一切正常。
谢谢, 帕克萨斯
【问题讨论】:
看起来你是最新的错位受害者。new
没有充分对齐 16 个字节。
在外面的某个地方一定有一个很好的副本。
是的——肯定是这样。当我将自定义分配器添加到将分配的内存地址与 16 字节边界对齐的类时,一切都开始正常工作了。
尝试:__declspec(align(16)) SimdTest * test = ...
@stark 不,那宁愿对齐指针变量本身,这不是必需的,它是分配的内存,其地址分配给需要对齐的指针。
【参考方案1】:
它死了,因为结构没有对齐。 CRT 分配器只承诺与 8 对齐,此处需要 16。您需要在 MSVC 上使用 _aligned_malloc() 来获得正确对齐的堆分配内存。
有两种方法。由于这是一个 POD 结构,您可以直接转换:
#include <malloc.h>
...
SimdTest* test = (SimdTest*)_aligned_malloc(sizeof SimdTest, 16);
test->setZero();
_aligned_free(test);
或者您可以覆盖结构的新/删除运算符:
struct SimdTest
void* operator new(size_t size) return _aligned_malloc(size, 16);
void operator delete(void* mem) return _aligned_free(mem);
// etc..
;
【讨论】:
附带说明,这些重载的实现通常还有更多内容,其他new/delete
版本也应该有重载(同样还有std::allocator
的特化)。我知道你知道这一点,只是为了向其他读者评论,所以无论如何都要 +1。【参考方案2】:
MSDN 声明 _m128 自动对齐 16 个字节,而不是 __m128,而是 _m128。但无论如何我猜其他人是对的,因为我记得有两种移动指令,一种用于对齐的 movAps,一种用于未对齐的 - movUps。首先需要 16b 对齐,其他不需要。不知道编译器是否能够同时使用两者,但我尝试过这种 _m128 类型。
其实有专门的型号:_M128A。
【讨论】:
我认为不存在_m128
或 _M128A
类型。而__m128
自动对齐到 16 个字节,但这并不总是有效(例如,在进行动态分配时)。
__m128
类型(是的,它是 __m128
而不是 _m128
,我从来没有听说过)如果在堆栈上分配(例如作为自动变量)是正确对齐的。但这在动态分配它们时无济于事(例如使用new
)。以上是关于SIMD和动态内存分配[重复]的主要内容,如果未能解决你的问题,请参考以下文章