SSE2对一些64位整数操作提供了直接支持:
将两个元素都设置为0:
__m128i z = _mm_setzero_si128();
将两个元素都设置为1:
__m128i z = _mm_set1_epi64x(1)
__m128i z = _mm_set_epi64x(hi, lo)
__m128i z = _mm_set_epi32(0,1,0,1)
设置/加载低64位,将其扩展为__m128i(一种数据类型)
// supported even in 32-bit mode, and listed as an intrinsic for MOVQ
// so it should be atomic on aligned integers.
_mm_loadl_epi64((const __m128i*)p)
_mm_cvtsi64x_si128(a)
_mm_loadl_epi64((const __m128i*)&a)
基于
_mm_set_epi32
的内容可能会被一些编译器编译成混乱的代码,因此,在MSVC、ICC以及gcc/clang中,
_mm_loadl_epi64
似乎是最好的选择,并且实际上对于您在32位模式下的原子64位加载要求也应该是安全的。请参见
Godbolt编译器浏览器。
垂直加/减每个64位整数:
__m128i z = _mm_add_epi64(x,y)
__m128i z = _mm_sub_epi64(x,y)
左移位:
__m128i z = _mm_slli_epi64(x,i) // i must be an immediate
http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011/compiler_c/intref_cls/common/intref_sse2_int_shift.htm
按位运算符:
__m128i z = _mm_and_si128(x,y)
__m128i z = _mm_or_si128(x,y)
http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011/compiler_c/intref_cls/common/intref_sse2_integer_logical.htm
SSE没有增量,所以您需要使用常数1
。
比较更难,因为直到SSE4.1的64位支持才存在pcmpeqq
和SSE4.2的pcmpgtq
这是用于相等性的一个示例:
__m128i t = _mm_cmpeq_epi32(a,b);
__m128i z = _mm_and_si128(t,_mm_shuffle_epi32(t,177));
这将把每个64位元素设置为
0xffffffffffff
(也称为
-1
),如果它们相等。如果您想在
int
中使用
0
或
1
,可以使用
_mm_cvtsi32_si128()
将其提取出来并加
1
。(但有时您可以使用
total -= cmp_result;
而不是转换和添加。)
小于:(未经充分测试)
a = _mm_xor_si128(a,_mm_set1_epi32(0x80000000))
b = _mm_xor_si128(b,_mm_set1_epi32(0x80000000))
__m128i t = _mm_cmplt_epi32(a,b)
__m128i u = _mm_cmpgt_epi32(a,b)
__m128i z = _mm_or_si128(t,_mm_shuffle_epi32(t,177))
z = _mm_andnot_si128(_mm_shuffle_epi32(u,245),z)
如果a
中的相应元素小于b
,则此操作将每个64位元素设置为0xffffffffffff
。
这里有两个返回布尔值的版本:"equals"和"less-than"。它们返回底部64位整数的比较结果。
inline bool equals(__m128i a,__m128i b){
__m128i t = _mm_cmpeq_epi32(a,b);
__m128i z = _mm_and_si128(t,_mm_shuffle_epi32(t,177));
return _mm_cvtsi128_si32(z) & 1;
}
inline bool lessthan(__m128i a,__m128i b){
a = _mm_xor_si128(a,_mm_set1_epi32(0x80000000));
b = _mm_xor_si128(b,_mm_set1_epi32(0x80000000));
__m128i t = _mm_cmplt_epi32(a,b);
__m128i u = _mm_cmpgt_epi32(a,b);
__m128i z = _mm_or_si128(t,_mm_shuffle_epi32(t,177));
z = _mm_andnot_si128(_mm_shuffle_epi32(u,245),z);
return _mm_cvtsi128_si32(z) & 1;
}