use*_*913 5 c x86 gcc sse simd
我有 16 字节的“字符串”(它们可能更短,但您可能会假设它们在末尾用零填充),但您可能不会假设它们是 16 字节对齐的(至少不总是)。
如何编写一个例程将它们与 SSE 内在函数进行比较(是否相等)?我发现这个代码片段可能会有帮助,但我不确定它是否合适?
register __m128i xmm0, xmm1;
register unsigned int eax;
xmm0 = _mm_load_epi128((__m128i*)(a));
xmm1 = _mm_load_epi128((__m128i*)(b));
xmm0 = _mm_cmpeq_epi8(xmm0, xmm1);
eax = _mm_movemask_epi8(xmm0);
if(eax==0xffff) //equal
else //not equal
Run Code Online (Sandbox Code Playgroud)
有人可以解释一下或者写一个函数体吗?
它需要在 GCC/mingw 中工作(在 32 位 Windows 上)。
向量比较指令根据相应源元素之间的比较将其结果生成为全 1(真)或全 0(假)元素的掩码。
请参阅https://stackoverflow.com/tags/x86/info获取一些链接,这些链接将告诉您这些内在函数的作用。
问题中的代码看起来应该可以工作。
如果您想找出哪些元素不相等,请使用 movemask 版本(pmovmskb或movmskps)。您可以tzcnt/bsf对第一个匹配项进行位扫描,或popcnt对匹配项进行计数。全部平等给你一个0xffff面具,非平等给你一个0。
您可能想知道 SSE4.1ptest在这里是否有用。它是可用的,但实际上并没有更快,特别是如果您对结果进行分支而不是将其转换为布尔值 0 / -1。
// slower alternative using SSE4.1 ptest
__m128i avec, bvec;
avec = _mm_loadu_si128((__m128i*)(a));
bvec = _mm_loadu_si128((__m128i*)(b));
__m128i diff = _mm_xor_si128(avec, bvec); // XOR: all zero only if *a==*b
if(_mm_test_all_zeros(diff, diff)) { //equal
} else { //not equal
}
Run Code Online (Sandbox Code Playgroud)
在 asm 中,ptest是 2 uops,并且不能与jcc条件分支进行宏融合。因此,前端的总pxor++ptest分支为 4 uops,并且仍然会破坏输入之一,除非您有 AVX 将异或结果放入第三个寄存器中。
pcmpeqb xmm0, xmm1//总共 3 个 uop,在 Intel 和 AMD CPU 上 cmp/jcc 融合为 1 个 uop pmovmskb eax, xmm0。cmp/jcc
如果您有更宽的元素,则可以在 的结果上使用movmskps或来获取 4 位或 2 位掩码。如果您想要位扫描或 popcnt 而不将每个元素除以 4 或 8 字节,则这是最有用的。(或者使用 AVX2、8 位或 4 位而不是 32 位掩码。)movmskpdpcmpeqd/q
ptest只有当您不需要任何额外的指令来为其构建输入时,这才是一个好主意:测试是否全零,带或不带掩码。例如,检查每个元素或某些元素中的某些位。
| 归档时间: |
|
| 查看次数: |
4275 次 |
| 最近记录: |