我有一个mat4类,一个使用sse内在函数的4x4矩阵.这个类是使用对齐的_MM_ALIGN16,因为它将矩阵存储为一组__m128.问题是,当我声明一个时atomic<mat4>,我的编译器对我大喊:
f:\program files (x86)\microsoft visual studio 12.0\vc\include\atomic(504): error C2719: '_Val': formal parameter with __declspec(align('16')) won't be aligned
Run Code Online (Sandbox Code Playgroud)
这是当我尝试传递任何与_MM_ALIGN16作为函数的参数对齐的类(不使用const &)时得到的相同错误.
如何声明mat4类的原子版?
MSC 编译器从不支持 x86 堆栈上参数超过 4 个字节的对齐方式,并且没有解决方法。
\n\n您可以通过编译自行验证这一点,
\n\nstruct A { __declspec(align(4)) int x; }; \nvoid foo(A a) {} \nRun Code Online (Sandbox Code Playgroud)\n\n相对,
\n\n// won\'t compile, alignment guarantee can\'t be fulfilled\nstruct A { __declspec(align(8)) int x; };\nRun Code Online (Sandbox Code Playgroud)\n\n相对,
\n\n// __m128d is naturally aligned, again - won\'t compile\nstruct A { __m128d x; };\nRun Code Online (Sandbox Code Playgroud)\n\n一般来说,MSC可以通过以下方式得到免除:
\n\n\n\n\n您无法指定函数参数的对齐方式。
\n\n \n
并且您无法指定对齐方式,因为 MSC 编写者希望保留决定对齐方式的自由,
\n\n\n\n\nx86 编译器使用不同的方法来对齐堆栈。默认情况下,堆栈是 4 字节对齐的。虽然这样可以节省空间,但您可以看到有些数据类型需要 8 字节对齐,并且为了获得良好的性能,有时需要 16 字节对齐。在某些情况下,编译器可以确定动态 8 字节堆栈对齐是有益的,尤其是当堆栈上存在双精度值时。
\n\n编译器以两种方式执行此操作。首先,当用户在编译和链接时指定时,编译器可以使用链接时代码生成 (LTCG) 来生成完整程序的调用树。这样,它可以确定调用树中 8 字节堆栈对齐有利的区域,并确定动态堆栈对齐获得最佳回报的调用站点。当函数在堆栈上有双精度数时,使用第二种方法,但无论出于何种原因,尚未进行 8 字节对齐。编译器应用启发式方法(随着编译器的每次迭代而改进)来确定函数是否应该动态地进行 8 字节对齐。
\n\n \n
因此,只要您将 MSC 与 32 位平台工具集一起使用,这个问题就不可避免。
\n\nx64 ABI 明确了对齐方式,定义了非平凡的结构或超过一定大小的结构作为指针参数传递。这在ABI 的第 3.2.3 节中进行了详细阐述,MSC 必须实现这一点才能与 ABI 兼容。
\n\n路径 1:使用另一个 Windows 编译器工具链:GCC 或 ICC。
\n\n路径 2:迁移到 64 位平台 MSC 工具集
\n\n路径 3:将用例减少为std::atomic<T>with T=__m128d,因为可以跳过堆栈并直接在 XMM 寄存器中传递变量。