jal*_*alf 9 c++ optimization 64-bit x86 sse
对于我正在开发的业余爱好项目,我需要在x86 CPU上模拟某些64位整数运算,并且它需要很快.
目前,我正在通过MMX指令这样做,但这真的很难用,因为我必须一直刷新fp寄存器状态(因为大多数MMX指令处理有符号整数,我需要无符号行为).
所以我想知道如果SSE /优化大师在这里SO可以拿出使用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;
Run Code Online (Sandbox Code Playgroud)
具体来说,我不需要通用添加或移位,例如,只需添加一个和左移一个.真的,只是这里显示的确切操作.
当然,除了在x86上,uint64_t使用两个32位标量进行模拟,这很慢(在我的情况下,根本不起作用,因为我需要加载/存储是原子的,它们不会是当加载/存储两个单独的寄存器时).
因此,我需要一个SIMD解决方案.其中一些操作很简单,已经由SSE2支持.其他人(!=和<)需要更多的工作.
建议?SSE和SSE2都没问题.允许SSE3需要一些说服力,SSE4可能是不可能的(支持SSE4的CPU 无论如何都可能运行64位,所以我不需要这些解决方法)
Mys*_*ial 15
SSE2直接支持某些64位整数运算:
将两个元素都设置为0:
__m128i z = _mm_setzero_si128();
Run Code Online (Sandbox Code Playgroud)
将两个元素都设置为1:
__m128i z = _mm_set1_epi64x(1); // also works for variables.
__m128i z = _mm_set_epi64x(hi, lo); // elements can be different
__m128i z = _mm_set_epi32(0,1,0,1); // if any compilers refuse int64_t in 32-bit mode. (None of the major ones do.)
Run Code Online (Sandbox Code Playgroud)
垂直添加/减去每个64位整数:
// 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); // movq or movsd 64-bit load
_mm_cvtsi64x_si128(a); // only ICC, others refuse in 32-bit mode
_mm_loadl_epi64((const __m128i*)&a); // portable for a value instead of pointer
Run Code Online (Sandbox Code Playgroud)
左移:
__m128i z = _mm_add_epi64(x,y)
__m128i z = _mm_sub_epi64(x,y)
Run Code Online (Sandbox Code Playgroud)
按位运算符:
__m128i z = _mm_slli_epi64(x,i) // i must be an immediate
Run Code Online (Sandbox Code Playgroud)
SSE没有增量,所以你必须使用常量_mm_set_epi32.
比较更难,因为没有64位支持.
这是平等的:
__m128i z = _mm_and_si128(x,y)
__m128i z = _mm_or_si128(x,y)
Run Code Online (Sandbox Code Playgroud)
_mm_loadl_epi64如果它们相等,这将设置每个64位元素.如果你想把它作为一个1或pcmpeqq一个pcmpgtq,你可以使用0xffffffffffff和添加它-1).
和小于:(未完全测试)
__m128i t = _mm_cmpeq_epi32(a,b);
__m128i z = _mm_and_si128(t,_mm_shuffle_epi32(t,177));
Run Code Online (Sandbox Code Playgroud)
0如果相应的元素in 1小于,则将每个64位元素设置为int.
这是"等于"和"小于"的版本,返回一个bool.它们返回底部64位整数的比较结果.
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);
Run Code Online (Sandbox Code Playgroud)