我想知道我是否正在使用此代码段破坏严格的别名规则。 (我想是这样的,因为它取消引用了一个惩罚指针,但是它只在一个表达式中完成,而/ Wall不会哭。)
inline double plop() const // member function
{
__m128d x = _mm_load_pd(v);
... // some stuff
return *(reinterpret_cast<double*>(&x)); // return the lower double in xmm reg referred to by x.
}
如果是,那么解决方法是什么?一旦您想要遵守规范,同时使用不同的表示就变成了核心。
感谢您的回答,我正试图寻找解决方案时失去了良好的心情。
不接受的答案以及原因:
“使用mm_store” - &gt;如果以下指令需要xmm寄存器,则优化器无法将其删除,因此它会在其后生成负载。存储+加载任何东西。
“使用工会” - &gt;如果对同一对象使用两种类型,则会违反别名规则。如果我理解Thiago Macieira撰写的文章。
答案 0 :(得分:4)
我认为允许你的演员阵容以粗体显示,因为我们可能会认为__m128d
是整个注册表的四个double
联合的集合。关于严格别名,编译器总是在union之间非常和谐,在原点只有一个转换为(char *)才有效。
§3.10: 如果程序试图通过访问对象的存储值 行为是除以下类型之一以外的glvalue undefined(此列表的目的是指定对象可能存在或不存在别名的情况):
- 对象的动态类型,
- 对象的动态类型的cv限定版本,
- 与对象的动态类型相似的类型(如4.4中所定义)
- 与对象的动态类型对应的有符号或无符号类型的类型
- 与对象的动态类型的cv限定版本对应的有符号或无符号类型的类型,
- 聚合或联合类型,包括其元素或非静态数据成员中的上述类型之一(包括, 递归地,子聚合的子元素或非静态数据成员 包含联盟),
- 一种类型,它是对象动态类型的(可能是cv限定的)基类类型,
- char或unsigned char类型。
答案 1 :(得分:3)
只有一个内在函数从xmm寄存器中“提取”低阶双精度值:
double _mm_cvtsd_f64 (__m128d a)
你可以这样使用它:
return _mm_cvtsd_f64(x);
不同的参考文献之间存在一些矛盾。 MSDN说:This intrinsic does not map to any specific machine instruction
。英特尔内在指南提到了movsd
指令。在后一种情况下,优化器可以轻松消除此附加指令。至少带有-O2
标志的gcc 4.8.1会生成没有附加指令的代码。
答案 2 :(得分:1)
是的,我认为这会破坏严格的别名。但是,实际上这通常很好 (我大多写这个作为答案,因为在评论中很难描述)
但是,你可以这样做:
inline double plop() const // member function
{
__m128d x = _mm_load_pd(v);
... // some stuff
union {
unsigned long long i; // 64-bit int
double d; // 64-bit double
};
i = _mm_cvtsi128_si64(_mm_castpd_si128(x)); // _mm_castpd_si128 to interpret the register as an int vector, _mm_cvtsi128_si64 to extract the lowest 64-bits
return d; // use the union to return the value as a double without breaking strict aliasing
}
答案 3 :(得分:1)
return x.m128d_f64[0];
怎么样?