使用SSE 4.2内建函数清零SSE寄存器首个零字节后剩余字节
使用SSE 4.2实现寄存器内首个零相关区域清零
针对你提出的需求——在SSE寄存器内找到首个零相关区域后清零后续内容,以下是基于SSE4.2内置函数的实现方案,全程在寄存器内完成操作,无需回写内存:
核心思路
利用SSE4.2的字符串比较指令快速定位目标位置,生成对应掩码后通过按位与操作完成清零,避免内存交互开销。
场景1:首个全0字节(0x00)后清零
如果需求是找到第一个全0字节,并将该字节之后的所有字节清零(保留该全0字节及之前的内容),可以用以下代码:
#include <smmintrin.h> __m128i clear_after_first_full_zero_byte(__m128i input) { // 生成全0的模板寄存器 const __m128i zero_template = _mm_setzero_si128(); // 生成匹配全0字节的掩码:匹配位置为1,其余为0 __m128i match_mask = _mm_cmpistrm(zero_template, input, _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_BIT_MASK | _SIDD_UNIT_BYTE); // 构造前缀保留掩码:从第一个全0字节开始,之后的位全为0 __m128i prefix_mask = _mm_or_si128(match_mask, _mm_andnot_si128(_mm_slli_si128(match_mask, 1), _mm_set1_epi8(0xFF))); // 应用掩码清零后续字节 return _mm_and_si128(input, prefix_mask); }
场景2:首个含0位的字节后清零(匹配你的示例)
从你的示例来看,实际需求更可能是找到第一个包含0比特位的字节,将该字节内0位之后的所有位清零,同时清零后续所有字节。这种情况可以结合位查找指令实现:
#include <smmintrin.h> #include <immintrin.h> __m128i clear_after_first_zero_bit(__m128i input) { // 生成全1字节模板,用于查找非全1的字节(即含0位的字节) const __m128i all_one_template = _mm_set1_epi8(0xFF); // 找到第一个非全1的字节索引 int byte_idx = _mm_cmpistri(all_one_template, input, _SIDD_CMP_NOT_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_BIT_MASK | _SIDD_UNIT_BYTE); // 所有字节都是全1,直接返回原数据 if (byte_idx == 16) return input; // 提取目标字节并找到第一个0位的位置 uint8_t target_byte = _mm_extract_epi8(input, byte_idx); int bit_pos = _lzcnt_u32(target_byte) - 24; // 计算高位开始的第一个0位位置 // 生成目标字节的掩码:保留第一个0位之前的位 uint8_t byte_mask = (0xFF << (8 - bit_pos)) & 0xFF; // 构造完整128位掩码:目标字节之后的所有字节清零 __m128i mask = _mm_set1_epi8(0xFF); mask = _mm_srli_si128(mask, 16 - byte_idx); mask = _mm_slli_si128(mask, 16 - byte_idx); // 替换目标字节的掩码 mask = _mm_insert_epi8(mask, byte_mask, byte_idx); // 应用掩码完成清零 return _mm_and_si128(input, mask); }
关键指令说明
_mm_cmpistri:SSE4.2字符串比较指令,快速在128位寄存器中查找符合条件的字节,返回匹配位置的索引。_mm_cmpistrm:同系列指令,直接生成匹配位置的掩码,避免单独处理索引的开销。_lzcnt_u32:计算无符号整数的前导1数量,用于定位字节内的第一个0位(需CPU支持BMI1指令集,通常与SSE4.2共存)。
内容的提问来源于stack exchange,提问作者Crigges
相关产品推荐
相关产品推荐

