【发布时间】:2016-02-26 15:24:11
【问题描述】:
我有一些适用于__m128 值的代码。我在这些值上使用 x86-64 SSE 内在函数,我发现如果这些值在内存中未对齐,我会崩溃。这是由于我的编译器(在本例中为 clang)仅生成对齐的加载指令。
我能否指示我的编译器生成未对齐的负载,无论是全局还是为某些值(可能带有某种注释)?
首先我有未对齐的值的原因是我试图节省内存。我有一个struct,大致如下:
#pragma pack(push, 4)
struct Foobar {
__m128 a;
__m128 b;
int c;
};
#pragma pack(pop)
然后我正在创建这些结构的数组。数组中的第二个元素从 36 字节开始,不是 16 的倍数。
我知道我可以切换到数组表示的结构,或删除打包编译指示(以将结构的大小从 36 字节增加到 48 字节为代价);但我也知道现在未对齐的负载并没有那么昂贵,我想先尝试一下。
更新以回答以下一些 cmets:
我的实际代码更接近这个:
struct Vector4 {
__m128 data;
Vector4(__m128 v) : data(v) {}
};
struct Foobar {
Vector4 a;
Vector4 b;
int c;
}
然后我有一些实用功能,例如:
inline Vector4 add( const Vector4& a, const Vector4 &b ) {
return Vector4(_mm_add_ps(a.data, b.data));
}
inline Vector4 subtract( const Vector4& a, const Vector4& b ) {
return Vector4(_mm_sub_ps(a.data, b.data));
}
// etc..
我经常结合使用这些实用程序。假例子:
Foobar myArray[1000];
myArray[i+1].b = sub(add(myArray[i].a, myArray[i].b), myArray[i+1].a);
当查看“Z Bozon”的答案时,我的代码实际上变成了:
struct Vector4 {
float data[4];
};
inline Vector4 add( const Vector4& a, const Vector4 &b ) {
Vector4 result;
_mm_storeu_ps(result.data, _mm_add_ps(_mm_loadu_ps(a.data), _mm_loadu_ps(b.data)));
return result;
}
我担心的是,当上述实用程序函数组合使用时,生成的代码可能具有冗余的加载/存储指令。事实证明这不是问题。我测试了我的编译器(clang),它已将它们全部删除。我会接受 Z Bozon 的回答。
【问题讨论】:
-
不要在你的结构中使用
__m128。使用例如float a[4]并使用_mm_loadu_ps和_mm_storeu_ps显式执行加载和存储。 -
听起来 OP 不仅使用显式内在函数,而且在某些情况下由于自动矢量化而获得由 clang 生成的 SIMD 代码?
-
@PaulR,如果是这种情况,那么 OP 应该将该信息添加到他的问题中。
-
是的,很难说,但这是我对 OP 第一段的解释。希望他稍后会过来澄清一下。
-
我认为大多数编译器会为获取
__m128变量生成对齐的负载,因为这种数据类型在 C 语言中定义了 16 字节对齐。这意味着除非您专门模拟您的编译器,否则它将确保__m128类型的值正确对齐。您强制编译器使其未对齐,这可能违反规则。我相信像 Z boson 所建议的那样使用_mm_storeu_ps是在这种情况下唯一可靠的解决方案。
标签: c++ x86-64 sse simd intrinsics