SSE和C ++容器

时间:2011-03-07 05:11:30

标签: c++ sse memory-alignment allocator

有以下代码段错误的明显原因吗?

#include <vector>
#include <emmintrin.h>

struct point {
    __m128i v;

  point() {
    v = _mm_setr_epi32(0, 0, 0, 0);
  }
};

int main(int argc, char *argv[])
{
  std::vector<point> a(3);
}

由于

编辑:我在linux / i686上使用g ++ 4.5.0,我可能不知道我在做什么,但是因为即使是以下的段错误

int main(int argc, char *argv[])
{
  point *p = new point();
}

我真的认为必须和对齐问题。

4 个答案:

答案 0 :(得分:11)

如果v未正确对齐,可能出错的显而易见的事情就是。

但它是由vector动态分配的,所以它不受堆栈错位问题的影响。

但是,正如phooji正确指出的那样,“模板”或“原型”值将传递给std::vector构造函数,该构造函数将被复制到向量的所有元素。 <{1}}的这个参数将被放置在堆栈上并且可能未对齐。

有些编译器有一个用于控制函数内堆栈对齐的编译指示(基本上,编译器会根据需要浪费一些额外的空间来使所有本地正确对齐)。

根据Microsoft文档Visual C++ 2010 should set up 8 byte stack alignment automatically for SSE typeshas done so since Visual C++ 2003

对于gcc,我不知道。


在C ++ 0x下,std::vector::vector返回未对齐存储是一种严重的违规行为。 new point()说(来自n3225草案的措辞):

  

分配功能尝试分配所请求的存储量。如果成功,它应该   返回存储块的起始地址,其长度以字节为单位应至少与   要求的大小。返回时,分配的存储内容没有限制   分配功能。连续调用分配的存储的顺序,连续性和初始值   分配功能未指定。返回的指针应适当对齐,以便可以转换   到具有基本对齐要求(3.11)的任何完整对象类型的指针然后使用   访问分配的存储中的对象或数组(直到通过调用显式释放存储   相应的解除分配函数)。

[basic.stc.dynamic.allocation]说:

  

另外,请求运行时分配动态存储   请求的对齐不能被视为分配失败。

你可以尝试更新版本的gcc吗?

答案 1 :(得分:3)

您正在使用的vector构造函数实际上是这样定义的:

explicit vector ( size_type n, const T& value= T(), const Allocator& = Allocator() );

(参见例如http://www.cplusplus.com/reference/stl/vector/vector/)。

换句话说,一个元素是默认构造的(即,当您调用构造函数时的默认参数值),然后通过复制第一个元素来创建其余元素。我的猜测是你需要point的复制构造函数来正确处理__m128i值的(非)复制。

更新:当我尝试使用Visual Studio 2010(v.10.0.30319.1)构建代码时,出现以下构建错误:

error C2719: '_Val': formal parameter with __declspec(align('16')) won't be aligned c:\program files\microsoft visual studio 10.0\vc\include\vector 870 1   meh

这表明Ben对于这种对齐问题是正确的。

答案 2 :(得分:1)

编译器的STL实现中的默认分配器分配的内存可能没有对齐。这将取决于特定平台和编译器供应商。

通常默认分配器使用运算符new,它通常不保证超出字大小(32位或64位)的对齐。要解决此问题,可能需要实现使用_aligned_malloc的自定义分配器。

另外,一个简单的修复(虽然不是一个令人满意的修复)是将值赋给本地__m128i变量,然后使用未对齐的指令将该变量复制到结构。例如:

struct point {
    __m128i v;
    point() {
        __m128i temp = _mm_setr_epi32(0, 0, 0, 0);
        _mm_storeu_si128(&v, temp);
    }
};

答案 3 :(得分:1)

SSE内在函数需要在内存中进行16字节对齐。在堆栈上分配__m128时,没有问题,因为编译器会自动正确对齐这些问题。处理动态内存分配的std::vector<>的默认分配器不会产生对齐的分配。