使用_mm_cmpeq_epi8查找ASCII空格时返回值为0的问题排查
路由解析SIMD实现eax返回0问题排查
核心错误原因
- 指针偏移计算逻辑错误:
__m128i类型为16字节长度,对该类型指针做算术运算时,偏移量的单位为16字节,而非1字节。代码中(const __m128i *)buffer + curr_index的写法等价于访问buffer + curr_index * 16地址,完全偏离了预期要访问的buffer + curr_index位置,读取到的是输入缓冲区外的非法内存数据,自然无法匹配到空格,导致eax始终返回0。
修复方案
修改xmm0的加载逻辑,先做字节级偏移再转换为SIMD指针,修正后的代码如下:
const char spaces[17] __attribute__((aligned(16))) = " \0"; void parse_route_simd(const char *buffer, const int buffer_len) { int index_simd; int curr_index = route_start; register __m128i xmm0, xmm1, xmm2; register unsigned int eax; register unsigned char ebx; while (buffer_len - curr_index >= 16) { debug_print("route_start %d\nindex_simd %d\nbuff %s\nspaces :%s:\n", route_start, index_simd, buffer + curr_index, spaces); // 修正:先做字节偏移,再转换为__m128i指针 xmm0 = _mm_loadu_si128((const __m128i *)(buffer + curr_index)); xmm1 = _mm_load_si128((const __m128i *)spaces); // spaces是16字节对齐的,可将loadu换成load获得更好性能 xmm2 = _mm_cmpeq_epi8(xmm0, xmm1); eax = _mm_movemask_epi8(xmm2); debug_print("eax %d\n", eax); index_simd = __builtin_ffs(eax); // eax是32位,无需用ffsll处理64位值 // 后续逻辑... } }
额外优化建议
spaces数组已经做了16字节对齐声明,可以把_mm_loadu_si128换成_mm_load_si128加载,性能更高。eax是_mm_movemask_epi8返回的16位掩码,存储在32位无符号整型中,使用__builtin_ffs即可,不需要调用处理64位值的__builtin_ffsll。
内容的提问来源于stack exchange,提问作者Christopher Clark
相关产品推荐
相关产品推荐

