我一直在尝试重新实现一些现有的向量和矩阵类来使用SSE3命令,每当我对向量数组执行一系列操作时,我似乎都会遇到这些“内存访问冲突”错误。我对SSE比较陌生,所以我一开始就很简单。这是我的矢量类的全部内容:
class SSEVector3D
{
public:
SSEVector3D();
SSEVector3D(float x, float y, float z);
SSEVector3D& operator+=(const SSEVector3D& rhs); //< Elementwise Addition
float x() const;
float y() const;
float z() const;
private:
float m_coords[3] __attribute__ ((aligned (16))); //< The x, y and z coordinates
};
所以,还没有进行很多,只有一些构造函数,访问器和一个操作。使用我的(公认有限的)SSE知识,我实现了如下的加法操作:
SSEVector3D& SSEVector3D::operator+=(const SSEVector3D& rhs)
{
__m128 * pLhs = (__m128 *) m_coords;
__m128 * pRhs = (__m128 *) rhs.m_coords;
*pLhs = _mm_add_ps(*pLhs, *pRhs);
return (*this);
}
为了对旧的矢量类进行速度测试(看看是否值得重新实现整个事物),我创建了一个简单的程序,它生成SSEVector3D对象的随机数组并将它们加在一起。没有太复杂的事情:
SSEVector3D sseSum(0, 0, 0);
for(i=0; i<sseVectors.size(); i++)
{
sseSum += sseVectors[i];
}
printf("Total: %f %f %f\n", sseSum.x(), sseSum.y(), sseSum.z());
sseVectors
变量是一个std :: vector,包含SSEVector3D
类型的元素,其组件全部初始化为-1
和1
之间的随机数。
这是我遇到的问题。如果sseVectors
的大小为8,191
或更小(我通过大量试验和错误得出的数字),这样运行正常。如果大小为8,192
或更大,我在尝试运行时会出现此错误:
信号:SIGSEGV,si_code:0(地址:0x00000080处的内存访问冲突)
但是,如果我在结尾处注释掉该print语句,即使sseVectors
的大小为8,192或更多,我也不会收到任何错误。
我写这个矢量类的方式有问题吗?我正在使用GCC 4.6版运行Ubuntu 12.04.1
答案 0 :(得分:1)
首先,最重要的是,不要这样做
__m128 * pLhs = (__m128 *) m_coords;
__m128 * pRhs = (__m128 *) rhs.m_coords;
*pLhs = _mm_add_ps(*pLhs, *pRhs);
使用SSE,总是通过适当的内在函数显式加载和存储,从不只需解除引用。不是在类中存储3个浮点数组,而是存储类型为_m128
的值。这应该使编译器正确地对齐您的类的实例,而不需要align
属性。
但请注意,这对MSVC不起作用。 MSVC似乎通常无法应对强于8字节对齐的对齐要求的值对齐参数:-(。上次我需要将SSE代码移植到Windows时,我的解决方案是使用英特尔的C ++编译器来处理SSE部件而不是MSVC ...
答案 1 :(得分:0)
诀窍是注意__m128
是16字节对齐的。使用_malloc_aligned()
确保您的浮点数组正确对齐,然后您可以继续将浮点数转换为__m128
数组。还要确保您分配的浮点数可以被4整除。