SSE优化了64位整数的仿真

时间:2012-04-19 09:11:09

标签: c++ optimization x86 sse

对于我正在研究的业余爱好项目,我需要在x86 CPU上模拟某些64位整数运算,并且它需要 fast

目前,我正在通过MMX指令执行此操作,但这真的很难用,因为我必须一直刷新fp寄存器状态(并且因为大多数MMX指令处理签名整数,我需要无符号行为。)

所以我想知道SO上的SSE /优化专家是否可以使用SSE提供更好的实现。

我需要的操作如下(非常具体):

uint64_t X, Y;

X = 0;
X = 1;
X << 1;
X != Y;
X + 1;
X & 0x1 // get lsb
X | 0x1 // set lsb
X > Y;

具体来说,我不需要通用添加或移位,例如,只需添加一个和左移一个。真的,只是这里显示的完全操作。

当然,除了x86之外,使用两个32位标量来模拟uint64_t,这很慢(而且,在我的情况下,根本不起作用,因为我需要加载/存储原子,它们在加载/存储两个独立的寄存器时不会出现。)

因此,我需要一个SIMD解决方案。 其中一些操作很简单,已经由SSE2支持。其他人(!=<)需要更多的工作。

连连呢? SSE和SSE2都没问题。允许SSE3需要一些说服力,SSE4可能是不可能的(支持SSE4的CPU可能无论如何都要运行64位,因此我不需要这些解决方法)

1 个答案:

答案 0 :(得分:14)

SSE2直接支持某些64位整数运算:

将两个元素都设置为0:

__m128i z = _mm_setzero_si128();

将两个元素都设置为1:

__m128i z = _mm_set_epi32(0,1,0,1);

垂直添加/减去每个64位整数:

__m128i z = _mm_add_epi64(x,y)
__m128i z = _mm_sub_epi64(x,y)

http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011/compiler_c/intref_cls/common/intref_sse2_integer_arithmetic.htm#intref_sse2_integer_arithmetic

左移:

__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的常量。


比较更难,因为没有64位支持。

这是平等的:

__m128i t = _mm_cmpeq_epi32(a,b);
__m128i z = _mm_and_si128(t,_mm_shuffle_epi32(t,177));

如果它们相等,这将把每个64位元素设置为0xffffffffffff。如果您希望01中的int_mm_cvtsi32_si128(),则可以使用1将其删除并添加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);

并且小于:(未完全测试)

0xffffffffffff

如果a中的相应元素小于b,则会将每个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; }


以下是返回bool的“equals”和“less-than”的版本。它们返回底部64位整数的比较结果。

{{1}}