无法在 x86 上以 SSE 类型访问内存,但在 x64 上工作正常

Posted

技术标签:

【中文标题】无法在 x86 上以 SSE 类型访问内存,但在 x64 上工作正常【英文标题】:Cannot access memory as SSE type on x86 but works fine on x64 【发布时间】:2012-05-07 15:42:17 【问题描述】:

我有一些使用 MSVC SSE 内在函数编写的代码。

            __m128 zero = _mm_setzero_ps();
            __m128 center = _mm_load_ps(&sphere.origin.x);
            __m128 boxmin = _mm_load_ps(&rhs.BottomLeftClosest.x);
            __m128 boxmax = _mm_load_ps(&rhs.TopRightFurthest.x);

            __m128 e = _mm_add_ps(_mm_max_ps(_mm_sub_ps(boxmin, center), zero), _mm_max_ps(_mm_sub_ps(center, boxmax), zero));
            e = _mm_mul_ps(e, e);

            __declspec(align(16)) float arr[4];
            _mm_store_ps(arr, e);
            float r = sphere.radius;
            return (arr[0] + arr[1] + arr[2] <= r * r);

Math::Vector 类型(sphere.originrhs.BottomLeftClosestrhs.TopRightFurthest 的类型)实际上是一个包含 3 个浮点数的数组。我将它们对齐到 16 个字节,这段代码在 x64 上执行得很好。但是在 x86 上,我在读取空指针时遇到访问冲突。关于这来自哪里的任何建议?

【问题讨论】:

未对齐的 SSE 访问将显示为空指针访问。 是的,听起来像是未对齐的负载。尝试使用loadu 而不是load,看看错误是否消失。或者直接进入调试器,检查地址 好的,反对票是怎么回事? @jalf 诸如“为什么 崩溃”之类的问题值得被否决。此类问题的唯一有效答案是“您的调试器会告诉您”。 [另外,我在使用 MSVC+SSE 时遇到了一些奇怪的代码生成问题:我不排除编译器错误。] @zvrba:所以你说的问题可能是编译器错误应该关闭?我认为如果“编译器错误”是一个潜在的答案,那就意味着这个问题有足够的价值被问和回答。此外,问题不是“为什么这段代码在没有上下文的情况下崩溃”。有相当多的上下文:它是 SSE 代码,而 SSE 是对齐敏感的。它适用于 x64,这意味着答案比简单的逻辑错误更有趣。有足够的上下文来回答问题。 【参考方案1】:
        __m128 center = _mm_load_ps(&sphere.origin.x);

_mm_load_ps() 要求传递的指针是 16 字节对齐的。没有证据表明您确保 sphere.origin.x 正确对齐。如果您无法提供该保证,则需要改用 _mm_loadu_ps()。

【讨论】:

这当然解决了问题。显然,将__declspec(align(16)) 添加到origin 的声明实际上并不意味着它是16 字节对齐的。那好吧。谢谢你。 对,不行,你不能对齐结构或类成员。 如果编译器能提到这一点就好了。 嗯,这很困难,因为它无法猜测您需要绝对对齐而不是相对对齐。您可以将功能请求发布到 connect.microsoft.com 那么如何访问大量的浮点数呢?你可以保证第一个元素是 16 Byte 元素,其他的呢?

以上是关于无法在 x86 上以 SSE 类型访问内存,但在 x64 上工作正常的主要内容,如果未能解决你的问题,请参考以下文章

不同的 mmx、sse 和 avx 版本是互补的还是彼此的超集?

SSE 内存访问

C++ 中 SSE/AVX 的 x86 CPU 调度

x86 程序集中的 SSE2 寄存器

在 x86(使用 SSE2)和 ARM(使用 vfpv4 NEON)上尾数为 11 位的 atan2 近似值

如何捕获未对齐的内存访问?