我是否违反了严格的别名规则?

时间:2014-04-17 18:01:36

标签: c++ c++11 sse strict-aliasing

我想知道我是否正在使用此代码段破坏严格的别名规则。 (我想是这样的,因为它取消引用了一个惩罚指针,但是它只在一个表达式中完成,而/ 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撰写的文章。

4 个答案:

答案 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];怎么样?