如何使用SIMD检查__m128i中奇偶通道是否在指定范围内?
高效检查__m128i向量中奇偶索引字节的范围合法性
我们有一个存储16个无符号char的__m128i向量,其中**偶数索引(0、2、4……14)**的字节需落在[even_min, even_max]区间,**奇数索引(1、3、5……15)**的字节需落在[odd_min, odd_max]区间。示例如下:
// 合法示例 vec1: [1, 5, 6, 10, 2, 6, 4, 6, 2, 7, 4, 9, 2, 7, 4, 8] // 非法示例:第0位(偶数索引)超过even_max vec2: [8, 5, 6, 10, 2, 6, 4, 6, 2, 7, 4, 9, 2, 7, 4, 8]
现有实现方案
你当前采用分两组检查的方式,逻辑直观但存在优化空间:
// 用于无符号char的包含性比较宏 #define _mm_cmpge_epi8(a, b) _mm_cmpeq_epi8(_mm_max_epu8(a, b), a) #define _mm_cmple_epi8(a, b) _mm_cmpge_epi8(b, a) // 检查偶数索引字节 __m128i even_min = _mm_set1_epi8(xxx); __m128i even_max = _mm_set1_epi8(xxx); __m128i even_mask = _mm_set_epi8(0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1); __m128i evenRange = _mm_and_si128(_mm_cmpge_epi8(vec, even_min), _mm_cmple_epi8(vec, even_max)); bool isEvenOk = _mm_testc_si128(evenRange, even_mask); // 奇数索引字节的检查逻辑与上述类似
更高效的优化方案
通过合并奇偶范围的比较逻辑,可以减少SIMD指令调用次数,提升执行效率:
- 构造混合min/max向量:将
even_min放在偶数索引位,odd_min放在奇数索引位;同理构造max向量。 - 一次性完成所有字节的范围检查,再用掩码分别验证奇偶位的合法性。
优化后的代码示例:
#define _mm_cmpge_epi8(a, b) _mm_cmpeq_epi8(_mm_max_epu8(a, b), a) #define _mm_cmple_epi8(a, b) _mm_cmpge_epi8(b, a) // 构造奇偶混合的min向量:偶数位为even_min,奇数位为odd_min __m128i min_vec = _mm_setr_epi8( even_min_val, odd_min_val, even_min_val, odd_min_val, even_min_val, odd_min_val, even_min_val, odd_min_val, even_min_val, odd_min_val, even_min_val, odd_min_val, even_min_val, odd_min_val, even_min_val, odd_min_val ); // 构造奇偶混合的max向量:偶数位为even_max,奇数位为odd_max __m128i max_vec = _mm_setr_epi8( even_max_val, odd_max_val, even_max_val, odd_max_val, even_max_val, odd_max_val, even_max_val, odd_max_val, even_max_val, odd_max_val, even_max_val, odd_max_val, even_max_val, odd_max_val, even_max_val, odd_max_val ); // 一次性完成所有字节的范围检查:合法字节为0xFF,非法为0 __m128i all_valid = _mm_and_si128(_mm_cmpge_epi8(vec, min_vec), _mm_cmple_epi8(vec, max_vec)); // 奇偶索引掩码 __m128i even_mask = _mm_set_epi8(0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1); __m128i odd_mask = _mm_set_epi8(-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0); // 验证奇偶位是否全部合法 bool isEvenOk = _mm_testc_si128(all_valid, even_mask); bool isOddOk = _mm_testc_si128(all_valid, odd_mask); bool isAllOk = isEvenOk && isOddOk;
额外优化技巧(AVX2环境)
如果你的编译环境支持AVX2指令集,可以用_mm_shuffle_epi8快速构造混合min/max向量,尤其适合min/max为变量的场景:
__m128i even_min_vec = _mm_set1_epi8(even_min_val); __m128i odd_min_vec = _mm_set1_epi8(odd_min_val); // 交叉排列even和odd的min值 __m128i shuffle_mask = _mm_setr_epi8(0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16); __m128i min_vec = _mm_shuffle_epi8(_mm_unpacklo_epi8(even_min_vec, odd_min_vec), shuffle_mask);
内容的提问来源于stack exchange,提问作者chenzhongpu
相关产品推荐
相关产品推荐

