2

好的,所以我刚刚开始在我的代码中使用 C 内在函数,并且我创建了一个类,它简化后如下所示:

class _Vector3D
{
public:
_Vector3D() 
{
    aVals[0] = _mm_setzero_ps();
    aVals[1] = _mm_setzero_ps();
    aVals[2] = _mm_setzero_ps();
}
~_Vector3D() {}
private:
__m128 aVals[3];
};

到目前为止,一切都很好。但是当我用 _Vector3D 成员创建第二个类时,我遇到了问题:

class RayPacket
{
public:
RayPacket() {orig = _Vector3D(); dir = _Vector3D(); power = _mm_setzero_ps();}
~RayPacket() {}

RayPacket(_Vector3D origins, _Vector3D directions, float pow)
{
    orig = origins;
    dir = directions;
    power = _mm_set_ps1(pow);
}

_Vector3D orig;
_Vector3D dir;
__m128 power;
};

我收到以下错误:

错误 C2719: 'origins': 带有 __declspec(align('16')) 的形式参数不会对齐

指向构造函数重载:

RayPacket(_Vector3D origins, _Vector3D directions, float pow)

那么我会以错误的方式解决这个问题吗?我应该改用结构还是可以让它与类一起使用?

4

3 回答 3

4

该答案基于文档和猜测,而不是实际知识。谨防!

__m128的文档说:

_m128 [sic] 类型的变量在 16 字节边界上自动对齐。

因此,通过在类中使用__m128成员,这会强制编译器在 16 字节边界上对齐类的实例。隐式__declspec(align(16))添加到您的类中,但在函数参数上不允许这样做,因为编译器很难(不可能?)在堆栈帧内强制对齐。

作为一种解决方法,请尝试通过引用传递构造函数参数:

RayPacket(_Vector3D const &origins, _Vector3D const &directions, float pow)
于 2009-10-28T19:39:43.143 回答
4

_Vector3D我认为问题在于编译器无法保证在堆栈上创建对象以传递给构造函数时堆栈指针将正确对齐。

在 32 位系统上,堆栈指针通常保证为 4 字节对齐(有时为 8 字节对齐),而在 64 位系统上,我认为堆栈指针通常保证为 8 字节对齐,因此编译器不会知道何时调用堆栈将正确对齐的构造函数。您可能需要传递指针或引用。

请注意,malloc()朋友们,有时不能保证为块返回的保证对齐方式能够处理这样的特殊类型。在这种情况下,平台将具有特殊的分配功能来分配这些对象。

有关 MSVC ( http://msdn.microsoft.com/en-us/library/aa290049.aspx )的详细信息,请参阅以下内容:

堆栈对齐

在这两个 64 位平台上,每个堆栈帧的顶部都是 16 字节对齐的。尽管这使用了比需要更多的空间,但它保证了编译器可以以所有元素对齐的方式将所有数据放在堆栈上。

x86 编译器使用不同的方法来对齐堆栈。默认情况下,堆栈是 4 字节对齐的。虽然这样节省空间,但您可以看到有些数据类型需要 8 字节对齐,并且为了获得良好的性能,有时需要 16 字节对齐。在某些情况下,编译器可以确定动态 8 字节堆栈对齐是有益的——特别是当堆栈上有双精度值时。

编译器通过两种方式做到这一点。首先,当用户在编译和链接时指定时,编译器可以使用链接时代码生成 (LTCG) 来生成完整程序的调用树。有了这个,它可以确定调用树的 8 字节堆栈对齐将是有益的区域,并确定动态堆栈对齐获得最佳回报的调用站点。当函数在堆栈上具有双精度值时使用第二种方法,但由于某种原因尚未对齐 8 字节。编译器应用启发式(随着编译器的每次迭代而改进)来确定函数是否应该动态地 8 字节对齐。

注意 就性能而言,动态 8 字节堆栈对齐的一个缺点是帧指针省略 (/Oy) 有效地被关闭。寄存器 EBP 必须用于引用动态 8 字节堆栈的堆栈,因此它不能用作函数中的通用寄存器。

malloc()上面链接的文章还提供了一些关于特殊堆函数的信息,如果您需要,这些函数可以提供高于标准的对齐保证。

于 2009-10-28T19:43:32.683 回答
0

尝试通过_Vector3Dconst 引用传递,如下所示:

RayPacket( const _Vector3D& origins, const _Vector3D& directions, float pow );
这会将指针而不是值放在调用堆栈上。

于 2009-10-28T19:40:35.843 回答