如何使用 SIMD 比较两个向量并获得类似 strncmp 的结果?
How to compare two vectors using SIMD and get a strncmp like result?
我想实现类似 strncmp 结果但没那么复杂
我试图阅读 https://code.woboq.org/userspace/glibc/sysdeps/x86_64/multiarch/strcmp-avx2.S.html 源代码,但未能理解它
假设我们需要 256 位向量
我如何根据 8 位比较来比较这两个以获得像 strncmp
这样的结果
我知道有一个图书馆,但我想了解基础知识。
如何 return -1,0,1 结果与 _mm256_cmpeq_epi8
和 _mm256_min_epu8
我会那样做。
inline int compareBytes( __m256i a, __m256i b )
{
// Compare for both a <= b and a >= b
__m256i min = _mm256_min_epu8( a, b );
__m256i le = _mm256_cmpeq_epi8( a, min );
__m256i ge = _mm256_cmpeq_epi8( b, min );
// Reverse bytes within 16-byte lanes
const __m128i rev16 = _mm_set_epi8( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 );
const __m256i rev32 = _mm256_broadcastsi128_si256( rev16 );
le = _mm256_shuffle_epi8( le, rev32 );
ge = _mm256_shuffle_epi8( ge, rev32 );
// Move the masks to scalar registers
uint32_t lessMask = (uint32_t)_mm256_movemask_epi8( le );
uint32_t greaterMask = (uint32_t)_mm256_movemask_epi8( ge );
// Flip high/low 16-bit pieces in the masks.
// Apparently, modern compilers are smart enough to emit ROR instructions for that code
lessMask = ( lessMask >> 16 ) | ( lessMask << 16 );
greaterMask = ( greaterMask >> 16 ) | ( greaterMask << 16 );
// Produce the desired result
if( lessMask > greaterMask )
return -1;
else if( lessMask < greaterMask )
return +1;
else
return 0;
}
该方法之所以有效,整数比较本质上是寻找不同的最高有效位,比较结果等于最高有效不同位的差异。因为我们颠倒了被测试字节的顺序,向量中的第一个字节对应于掩码中的最高有效位。因此,当源向量中的第一个不同字节 ( a < b )
评估为真时,( lessMask > greaterMask )
表达式评估为真。
我想实现类似 strncmp 结果但没那么复杂 我试图阅读 https://code.woboq.org/userspace/glibc/sysdeps/x86_64/multiarch/strcmp-avx2.S.html 源代码,但未能理解它
假设我们需要 256 位向量 我如何根据 8 位比较来比较这两个以获得像 strncmp
这样的结果我知道有一个图书馆,但我想了解基础知识。
如何 return -1,0,1 结果与 _mm256_cmpeq_epi8
和 _mm256_min_epu8
我会那样做。
inline int compareBytes( __m256i a, __m256i b )
{
// Compare for both a <= b and a >= b
__m256i min = _mm256_min_epu8( a, b );
__m256i le = _mm256_cmpeq_epi8( a, min );
__m256i ge = _mm256_cmpeq_epi8( b, min );
// Reverse bytes within 16-byte lanes
const __m128i rev16 = _mm_set_epi8( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 );
const __m256i rev32 = _mm256_broadcastsi128_si256( rev16 );
le = _mm256_shuffle_epi8( le, rev32 );
ge = _mm256_shuffle_epi8( ge, rev32 );
// Move the masks to scalar registers
uint32_t lessMask = (uint32_t)_mm256_movemask_epi8( le );
uint32_t greaterMask = (uint32_t)_mm256_movemask_epi8( ge );
// Flip high/low 16-bit pieces in the masks.
// Apparently, modern compilers are smart enough to emit ROR instructions for that code
lessMask = ( lessMask >> 16 ) | ( lessMask << 16 );
greaterMask = ( greaterMask >> 16 ) | ( greaterMask << 16 );
// Produce the desired result
if( lessMask > greaterMask )
return -1;
else if( lessMask < greaterMask )
return +1;
else
return 0;
}
该方法之所以有效,整数比较本质上是寻找不同的最高有效位,比较结果等于最高有效不同位的差异。因为我们颠倒了被测试字节的顺序,向量中的第一个字节对应于掩码中的最高有效位。因此,当源向量中的第一个不同字节 ( a < b )
评估为真时,( lessMask > greaterMask )
表达式评估为真。