基于Intel AVX的掩码混排咨询:重复字节复制的函数选择
嘿,作为AVX新手碰到这种自定义字节混排(还带重复复制)的需求,确实会有点懵,我来给你指条明路~
首选指令:AVX2的
_mm256_shuffle_epi8(PSHUFB) 这完全是为你的需求量身定做的指令!它可以让你用一个掩码寄存器,精确指定源寄存器(R1)的每个字节复制到目标寄存器(R2)的哪些位置,甚至支持同一个源字节复制到多个目标位置,完美匹配你的{(0,0),(1,1),(1,4),(2,5)...}这种掩码格式。
怎么把你的掩码转换成PSHUFB需要的格式?
PSHUFB的掩码寄存器是一个256位的__m256i,其中每个字节对应目标寄存器R2的一个字节位置:
- 掩码字节的低4位:指定要从源寄存器R1中取哪个字节的索引(0~31,因为256位是32个字节)
- 掩码字节的高4位:如果设为
1(也就是字节值≥0x80),那么目标位置会被清零;如果设为0,就正常复制源字节
举个例子,你的需求里:
- R2的第0个字节要取R1的第0个字节 → 掩码的第0个字节设为
0x00 - R2的第1个字节要取R1的第1个字节 → 掩码的第1个字节设为
0x01 - R2的第4个字节要取R1的第1个字节 → 掩码的第4个字节设为
0x01 - R2的第5个字节要取R1的第2个字节 → 掩码的第5个字节设为
0x02 - 其他没指定的位置,如果不需要保留值,可以设为
0x80来清零
代码示例(C++ Intrinsics)
#include <immintrin.h> int main() { // 先初始化你的源寄存器R1,这里用_set_epi8举例子,你可以换成自己的数据 __m256i R1 = _mm256_set_epi8( 31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16, 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 ); // 构建符合你需求的混排掩码 __m256i shuffle_mask = _mm256_set_epi8( // 从高字节到低字节依次对应R2的第31到第0个字节 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80, // R2第7位 0x80, // R2第6位 0x02, // R2第5位 → 取R1第2位 0x01, // R2第4位 → 取R1第1位 0x80, // R2第3位 0x80, // R2第2位 0x01, // R2第1位 → 取R1第1位 0x00 // R2第0位 → 取R1第0位 ); // 执行混排操作 __m256i R2 = _mm256_shuffle_epi8(R1, shuffle_mask); return 0; }
注意事项
- 这个指令需要CPU支持AVX2(绝大多数2013年之后的x86 CPU都支持),如果你的环境只能用AVX1,那没有直接的字节级混排指令,得用更复杂的组合(比如拆分寄存器+移位),但AVX2肯定是最优解。
- 掩码的字节顺序要注意:
_mm256_set_epi8是从高字节到低字节依次初始化寄存器的,所以最左边的参数对应R2的第31个字节,最右边的对应第0个字节,别搞反了!
内容的提问来源于stack exchange,提问作者NFoerster
相关产品推荐
相关产品推荐

