我想初始化一个 __m128 类型的变量...其中 x 是 uint64_t 类型的变量
采用uint64_t 的内在函数是_mm_set_epi64x(而不是采用__m64 的_mm_set_epi64)。
我最近在 Solaris 上遇到了这个问题。 Sun Studio 12.3 及更低版本缺少_mm_set_epi64x。它还缺少解决方法,例如 _mm_cvtsi64_si128 和 _m_from_int64。
如果有兴趣,这是我使用的 hack。另一种选择是禁用 SSE2,它不太吸引人(在基准测试中它慢了 3 倍):
// Sun Studio 12.3 and earlier lack SSE2's _mm_set_epi64 and _mm_set_epi64x.
#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5130)
inline __m128i _mm_set_epi64x(const uint64_t a, const uint64_t b)
{
union INT_128_64 {
__m128i v128;
uint64_t v64[2];
};
INT_128_64 v;
v.v64[0] = b; v.v64[1] = a;
return v.v128;
}
#endif
我相信 C++11 可以做一些额外的事情来帮助编译器和性能,比如初始化一个常量数组:
const INT_128_64 v = {a,b};
return v.v128;
有一个很大的警告......我相信有undefined behavior,因为使用联合的v64 成员进行写入,然后使用联合的v128 成员进行读取。在 SunCC 下的测试表明编译器正在执行预期(但技术上不正确)的事情。
我相信您可以使用 memcpy 回避未定义的行为,但这可能会破坏性能。另请参阅 How to swap two __m128i variables in C++03 given its an opaque type and an array? 上的 Peter Cordes 的回答和讨论。
以下也可能是避免使用非活动联合成员的未定义行为的好选择。但我不确定双关语。
INT_128_64 v;
v.v64[0] = b; v.v64[1] = a;
return *(reinterpret_cast<__m128i*>(v.v64));
编辑(三个月后):Solaris 和 SunCC 不喜欢双关语。它为我们生成了错误的代码,我们不得不将memcpy 的值转换为__m128i。 Unix、Linux、Windows、GCC、Clang、ICC、MSC 都可以。只有 SunCC 给我们带来了麻烦。