【发布时间】:2013-11-12 20:27:00
【问题描述】:
我最近偶然发现了隐式 SSE/AVX 加载/存储。我认为这些是 GCC 的一些特殊扩展,但后来意识到它们也适用于 MSVC。
__m128 a = *(__m128*)data // same as __m128 a = _mm_load_ps(data)?
__m128 *b = (__m128*)result; // same as _mm_store_ps(result, a)?
这些隐式加载/存储的正确语法是什么?
根据我的阅读 (Addressing a non-integer address, and sse),隐式加载/存储使用对齐的加载/存储,因此内存必须正确对齐。假设它们对于支持 SSE/AVX 内在函数的大多数编译器(GCC/ICC/MSVC/Clang/MinGW,...)工作相同是否公平?进行这些隐式加载/存储的动机是什么?
我的下一组问题是关于将 SSE/AVX 寄存器推送和弹出到堆栈。 这是如何实施的?如果堆栈不是 16 字节对齐的怎么办?然后它是否使用未对齐的加载/存储?据我了解,堆栈现在通常是 16 字节对齐的,但不一定是 32 字节对齐的(至少在 64 位模式下)。如果算法具有较高的 AVX 占用率并且需要经常将 AVX 寄存器推送到堆栈上,那么将堆栈对齐到 32 字节(例如,在 GCC 中使用 mpreferred-stack-boundary)以潜在地提高性能是否有意义?
【问题讨论】:
-
我在可以传入任意指针类型的宏中经常使用它们。如果它没有对齐,你只会得到一个未对齐的错误。编译器应该已经为它使用的任何 SIMD 正确对齐堆栈。
-
第二行代码或注释不正确。
_mm_store_ps(result, a)应该等同于__m128 *result = (__m128*)a。_mm_store_ps的签名是void _mm_store_ps (float* mem_addr, __m128 a),其中mem_addr必须与16 字节边界对齐。 -
@plasmacel,你是对的。虽然。我个人永远不会使用隐式 SSE/AVX 加载/存储。