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

C++ 我是否违反了严格的别名规则?,c++,c++11,sse,strict-aliasing,C++,C++11,Sse,Strict Aliasing,我想知道这段代码是否违反了严格的别名规则。(我认为是这样的,因为它取消了对双关语指针的引用,但是它是在一个表达式中完成的,/Wall不会哭。) 内联双plop()常量//成员函数 { __m128d x=_mm_载荷_pd(v); …一些东西 return*(reinterpret_cast(&x));//返回x引用的xmm reg中较低的双精度。 } 如果是,解决方法是什么?一旦你想遵守规范,同时使用不同的表示法就成了铁杆 谢谢你的回答,我正在失去寻找解决办法的好心情 不被接受的答案以及原因

我想知道这段代码是否违反了严格的别名规则。(我认为是这样的,因为它取消了对双关语指针的引用,但是它是在一个表达式中完成的,/Wall不会哭。)

内联双plop()常量//成员函数
{
__m128d x=_mm_载荷_pd(v);
…一些东西
return*(reinterpret_cast(&x));//返回x引用的xmm reg中较低的双精度。
}
如果是,解决方法是什么?一旦你想遵守规范,同时使用不同的表示法就成了铁杆

谢谢你的回答,我正在失去寻找解决办法的好心情

不被接受的答案以及原因:

“use mm_store”->如果以下指令需要xmm寄存器,优化器将无法删除它,因此它会在它之后生成一个加载。存储+免费加载


如果对同一对象使用两种类型,则“使用联合”->别名规则冲突。如果我很理解Thiago Macieira写的文章。

< Pr>我想把粗体的点放在这里,我们可以把代码登记为代码四。关于严格的别名,编译器在union周围总是非常协调,因为在原点,只有强制转换(char*)被认为是有效的

§3.10: 如果程序试图通过访问对象的存储值 行为为以下类型之一以外的glvalue 未定义(此列表的目的是指定对象可能有别名或可能没有别名的情况):

  • 对象的动态类型
  • 对象动态类型的cv限定版本
  • 与对象的动态类型类似的类型(如4.4中所定义)
  • 与对象的动态类型相对应的有符号或无符号类型
  • 一种类型,它是与对象的动态类型的cv限定版本相对应的有符号或无符号类型
  • 在其元素或非静态数据成员中包含上述类型之一的聚合或联合类型(包括, 递归地,子集合或子集合的元素或非静态数据成员 包含的联合体),
  • 是对象动态类型的基类类型(可能是cv限定的)
  • 字符或无符号字符类型
是的,我认为这打破了严格的别名。然而,在实践中,这通常是好的。
(我写这篇文章主要是为了回答这个问题,因为在评论中很难描述清楚)

但是,你可以这样做:

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
}

那么
返回x.m128d_f64[0]呢

只有一个内在函数从xmm寄存器“提取”低阶双精度值:

double _mm_cvtsd_f64 (__m128d a)
您可以这样使用它:

return _mm_cvtsd_f64(x);

不同的参考文献之间有些矛盾。说明:
此内在函数不映射到任何特定的机器指令
。而《英特尔内部指南》提到了
movsd
指令。在后一种情况下,优化器很容易消除此附加指令。至少带有
-O2
标志的gcc 4.8.1可以生成无需额外指令的代码。

将普通的
memcpy
转换为
双精度
如何?在处理SIMD时,几乎不可能避免别名。理想情况下,您可以避免像现在这样访问单个元素,但如果您确实需要,我建议对堆栈上的内容进行联合,并对来自参数的指针进行指针转换。C99中明确允许联合类型双关,并且所有主流编译器都将它转入C++。在处理非标准扩展时,试图完全符合标准在某种程度上是自相矛盾的。@Praetorian:使用simd本质并调用memcpy不是一种天堂吗^^您是说您也有并发问题吗?如果是这样的话,你应该先解决这个问题。Irc,C++ 11指定了至少一个写的同一对象的任何竞争条件是UB。C99中明确允许“@ MyStuple”联合类型双关,并且所有主流编译器都将它转入C++。“即使在支持它时,它也不能生成好的代码:还有一些编译器不支持IIRC(我认为Solaris CC就是一个例子)。最好只使用memcpy。这假设实现中
\uuum128d
的成员可以这样访问。并非所有的实现都是如此。例如:,其中
\uuum128d
被定义为
typedef double\uuuum128d\uuuuuu属性(((uuuu向量大小)uuuuu16))如果所有编译器都有一种方式来表示对元素的访问,那么依赖于编译器的宏可能是一个好主意,使用m128d_f64表示msvc,直接使用clang上的[]运算符等。。。这可能是一个确保编译器的优化器部分不会丢失或无法进行优化的想法。非常好的答案我没有考虑到没有编译器实际使用此类型作为关键字,而是作为一个特定类型,即显式兼容的类型typedef或包含兼容类型的联合代表。。。让我做一些检查,我会非常感激地接受你的回答。这是第二个最好的解决方案,但它需要重新包装每个SIMD类型,因为有些编译器有奇怪的特殊表示法,不包括双数组。根据标准,在一个联合体的一个成员被分配到,所有其他成员的值将变为未指定。联合不能可移植地用于重新解释位模式。@Sneftel:这是行为,定义行为需要实现。对于GCC(以及我使用过的所有编译器),它不会破坏严格的别名。您可以阅读行为是如何定义的。标准将其描述为“未指定”,而不是“实现定义”。就是
return _mm_cvtsd_f64(x);