我与 SSE 合作已经有一段时间了,我也看到了一些一致性问题。然而,这超出了我的理解范围:
无论我是否 使用 F5(调试)运行程序或 我是否在调试器之外运行它 (Ctrl+F5)!
一些背景信息: 我正在使用支持 SSE 的数据类型的包装器 - 具有重载运算符和自定义分配器(使用
new
和 delete
重载_mm_malloc
和 _mm_free
运算符)。但在下面的示例中,我成功地进一步减少了问题,即即使我不使用自定义分配器,问题也会发生。
如下所示,在 main() 中,我在堆上动态分配了一个 TestClass 对象,其中包含一个 SSEVector 类型的对象。我正在使用虚拟
float[2]
成员变量来稍微“错位”堆栈。
当我使用 F5 运行时,我获得以下输出:
object address 00346678
_memberVariable1 address 00346678
_sseVector address 00346688
如果我使用 Ctrl+F5 运行:
object address 00345B70
_memberVariable1 address 00345B70
_sseVector address 00345B80
如您所见,当我在调试器中运行它时,对齐方式是不同的(即不是 16 字节)。使用 Ctrl-F5 时对齐正确只是巧合吗?我正在将 Visual Studio 2010 与新项目一起使用(默认设置)。
如果我在堆栈上声明对象,即
TestClass myObject;
,则不会出现此问题。使用 __declspec(align(16))
也没有帮助。
我用来重现问题的代码:
#include <iostream>
#include <string>
#include <xmmintrin.h> // SSE
//#include "DynAlignedAllocator.h"
//////////////////////////////////////////////////////////////
class SSEVector /*: public DynAlignedAllocator<16>*/
{
public:
SSEVector() { }
__m128 vec;
};
class TestClass
{
public:
TestClass() { }
/*__declspec(align(16))*/ float _memberVariable1 [2];
SSEVector _sseVector;
};
//////////////////////////////////////////////////////////////
int main (void)
{
TestClass* myObject = new TestClass;
std::cout << "object address " << myObject << std::endl;
std::cout << "_memberVariable1 address " << &(myObject->_memberVariable1) << std::endl;
std::cout << "_sseVector address " << &(myObject->_sseVector) << std::endl;
delete myObject;
// wait for ENTER
std::string dummy;
std::getline(std::cin, dummy);
return 0;
}
非常感谢任何提示或评论。预先感谢。
在调试器下运行时,您正在使用调试堆,这可能会影响对齐。
在您的环境设置中设置
_NO_DEBUG_HEAP=1
,看看这是否有帮助。
参见例如http://msdn.microsoft.com/en-us/library/aa366705%28v=vs.85%29.aspx
但是,使用 malloc 或 new 分配时不能保证对齐。在 VS 中解决这个问题的“正确”方法是使用
_aligned_malloc
。
当您希望 SSEVector 作为另一个结构体的成员时,您需要更改该结构体的 packing(使用 #pragma pack),或 SSEVector 的 __declspec(align)。
您的情况发生的是(除了看似巧合的调试器/非调试器差异):
SSEVector
被声明为未对齐。如果直接使用 _aligned_malloc
分配它,它就会对齐。 TestClass
也是未对齐的,并使用默认包装。如果您使用 _aligned_malloc
分配它,则 TestClass
实例将正确对齐。这对您没有任何帮助,因为您希望 SSEVector
成员变量 对齐。
使用
SSEVector
在__declspec(align)
上添加对齐要求将告诉编译器SSEVector
堆栈变量必须对齐,并且作为结构体成员的SSEVector
必须在结构/类内对齐。现在,如果您使用 TestClass
分配 _aligned_malloc
,它将正确对齐。由于 declspec,结构中的 SSEVector
偏移量也正确对齐,因此 SSEVector 的绝对地址对于您的使用来说是正确的。