从SSE迁移至AVX:如何高效模拟缺失的_mm256_maskmoveu_si256指令?
模拟AVX版本的_mm256_maskmoveu_si256指令
由于AVX指令集未提供原生的_mm256_maskmoveu_si256指令,可通过以下两种高效方式模拟其功能,严格匹配原SSE指令的行为:
方法1:拆分为两个SSE掩码存储操作
这是兼容性最好的实现方式,利用AVX寄存器可拆分的特性,将256位的源数据和掩码分别拆分为两个128位部分,调用SSE的_mm_maskmoveu_si128分别处理低16字节和高16字节。
代码实现
#include <immintrin.h> void avx_maskmoveu_si256(void* dest, __m256i src, __m256i mask) { // 处理低128位(前16字节) _mm_maskmoveu_si128(_mm256_castsi256_si128(src), _mm256_castsi256_si128(mask), static_cast<char*>(dest)); // 处理高128位(后16字节),目标地址偏移16字节 _mm_maskmoveu_si128(_mm256_extracti128_si256(src, 1), _mm256_extracti128_si256(mask, 1), static_cast<char*>(dest) + 16); }
优缺点
- 优点:实现简单,无需额外掩码转换逻辑;兼容性强,仅需支持AVX和SSE2即可,覆盖绝大多数现代CPU。
- 缺点:需执行两次128位掩码存储指令,在部分微架构下吞吐量略低于单条256位指令,但实际性能差异极小。
方法2:利用AVX2的掩码存储指令(需AVX2支持)
AVX2提供的_mm256_maskstore_epi8指令可实现256位条件存储,但它的掩码格式与_mm_maskmoveu_si128不同:前者用每个bit对应一个字节的存储决策,后者用每个字节的最高位作为决策依据。需先将原掩码转换为bit掩码格式。
代码实现
#include <immintrin.h> void avx_maskmoveu_si256(void* dest, __m256i src, __m256i mask) { // 比较掩码每个字节是否最高位为1(即值大于0x7F) __m256i cmp_result = _mm256_cmpgt_epi8(mask, _mm256_set1_epi8(0x7F)); // 将比较结果压缩为32位bit掩码:每个bit对应原掩码字节的最高位状态 uint32_t mask_bits = _mm256_movemask_epi8(cmp_result); // 使用AVX2掩码存储指令完成条件存储 _mm256_maskstore_epi8(static_cast<char*>(dest), mask_bits, src); }
优缺点
- 优点:使用单条256位掩码存储指令,在支持AVX2的CPU上指令吞吐量更优;代码逻辑更贴近原生AVX操作风格。
- 缺点:依赖AVX2指令集,无法在仅支持AVX的平台上运行;需要额外的掩码转换指令。
注意事项
两种实现均严格保持原_mm_maskmoveu_si128的行为:仅当掩码对应字节的最高位为1时,才将源的对应字节写入目标内存,否则不修改目标地址的对应字节。同时,两者都支持非对齐内存地址,与原指令的u(unaligned)特性一致。
内容的提问来源于stack exchange,提问作者user21508463
相关产品推荐
相关产品推荐

