如何从__m256i AVX2寄存器提取字节至另一__m256i寄存器并修改后写回原寄存器
AVX2实现提取__m256i指定索引字节并修改后写回
没问题,我来帮你搞定这个AVX2字节操作的需求!从你的示例来看,你需要对256位寄存器__m256i a中的每个4字节块(共8个,刚好填满32字节)的指定索引字节进行提取、修改,再写回原寄存器且不改动其他字节。下面是具体的实现步骤和代码示例:
核心思路
整个流程分为三步:
- 从
a中提取每个4字节块的目标字节,构建初始的__m256i b - 对
b中的目标字节执行自定义计算 - 将修改后的字节写回
a的对应位置,保留其他字节不变
具体代码实现
假设我们要操作的字节索引是i=2(即每个4字节块的第3个字节,0-based索引),代码如下:
1. 提取目标字节到b
我们使用AVX2的_mm256_shuffle_epi8(对应指令VPSHUFB)来提取指定字节,再和全0xFF的寄存器合并得到你示例中的初始b:
#include <immintrin.h> // 定义要操作的字节索引(0-3,对应4字节块内的位置) const int byte_idx = 2; __m256i a = _mm256_set1_epi32(0xAAAAAAAA); // 示例中的初始a: |AAAA|AAAA|...|AAAA| // 创建洗牌掩码:仅保留每个4字节块的byte_idx位置的字节,其他位置置0(掩码字节0x80表示目标字节为0) __m256i extract_mask = _mm256_setr_epi8( 0x80, 0x80, byte_idx, 0x80, 0x80, 0x80, byte_idx + 4, 0x80, 0x80, 0x80, byte_idx + 8, 0x80, 0x80, 0x80, byte_idx + 12, 0x80, 0x80, 0x80, byte_idx + 16, 0x80, 0x80, 0x80, byte_idx + 20, 0x80, 0x80, 0x80, byte_idx + 24, 0x80, 0x80, 0x80, byte_idx + 28, 0x80 ); // 提取目标字节到b,此时其他位置为0 __m256i b = _mm256_shuffle_epi8(a, extract_mask); // 和全0xFF合并,得到示例中的初始b: |FAFF|FAFF|...|FAFF|(FA是原a的字节,FF填充其他位置) __m256i full_ff = _mm256_set1_epi8(0xFF); b = _mm256_or_si256(b, full_ff);
2. 对b执行自定义计算
这里以把目标字节从0xAA改为0x06为例(对应你的示例结果):
// 创建掩码:仅保留目标字节位置,其他位置清零 __m256i calc_mask = _mm256_setr_epi8( 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF ); // 先清空b中的目标字节位置,再写入新值0x06 b = _mm256_and_si256(b, calc_mask); __m256i new_byte = _mm256_set1_epi8(0x06); b = _mm256_or_si256(b, new_byte);
3. 将修改后的字节写回a
我们需要先清空a中目标字节的位置,再把b中的新值合并进去:
// 清空a中的目标字节位置 __m256i a_cleared = _mm256_and_si256(a, calc_mask); // 提取b中的新值(其他位置清零) __m256i b_new = _mm256_andnot_si256(calc_mask, b); // 合并得到修改后的a __m256i a_updated = _mm256_or_si256(a_cleared, b_new);
适配其他索引的方法
如果要操作的字节索引不是2,只需要修改extract_mask中保留的字节位置,以及calc_mask中清零的位置即可。比如索引i=0,就把extract_mask中对应的位置改为0,4,8,...,calc_mask中把第0、4、8...位置设为0x00。
注意事项
- x86架构是小端字节序,所以寄存器中的字节存储顺序和我们直观的“|AAAA|”表示可能相反,不过上述代码已经考虑了这一点,掩码是按实际寄存器字节位置设置的。
- 确保你的编译环境支持AVX2指令集(比如GCC需要加
-mavx2编译选项)。
内容的提问来源于stack exchange,提问作者simonlet
相关产品推荐
相关产品推荐

