You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将uint64_t中的位对解压缩为__m256i?

位对解压缩:uint64_t转__m256i(AVX2/AVX512实现)

需求说明

现有uint64_t类型数据,每连续2位代表一个数值,规则如下:

  • b00对应有符号字节0x00(数值0)
  • b01对应有符号字节0x01(数值1)
  • b11对应有符号字节0xFF(数值-1)
  • b10为未使用状态,无需处理

需将该uint64_t解压缩为__m256i类型,保持原数据中位对的顺序。

已实现的反向打包代码

以下是将__m256i的字节打包为uint64_t位对的实现:

const __m256i vBits0 = _mm256_slli_epi16(target, 7);
const int bits1 = _mm256_movemask_epi8(target);
const int bits0 = _mm256_movemask_epi8(vBits0);
const uint64_t withHigher = _pdep_u64(bits1, 0xAAAAAAAAAAAAAAAA);
const uint64_t withLower =  _pdep_u64(bits0, 0x5555555555555555);
return withHigher | withLower;

AVX2解压缩实现

利用AVX2的位操作指令,将uint64_t的每个位对提取并映射为对应字节:

__m256i unpack_bits_to_bytes_avx2(uint64_t packed) {
    // 将uint64_t加载到256位向量低64位,其余位清零
    __m256i v_packed = _mm256_set_epi64x(0, 0, 0, packed);
    
    // 提取每个位对的高位(bit1)
    const __m256i mask_high = _mm256_set1_epi64x(0xAAAAAAAAAAAAAAAA);
    __m256i v_high = _mm256_and_si256(v_packed, mask_high);
    v_high = _mm256_srli_epi64(v_high, 1); // 右移1位,将高位移到低位位置
    
    // 提取每个位对的低位(bit0)
    const __m256i mask_low = _mm256_set1_epi64x(0x5555555555555555);
    __m256i v_low = _mm256_and_si256(v_packed, mask_low);
    
    // 合并高低位,得到每个位对的2位值
    __m256i v_pair = _mm256_or_si256(v_high, v_low);
    
    // 映射位对到目标字节:b01→1,b11→0xFF,其余保持0
    __m256i v_one = _mm256_cmpeq_epi8(v_pair, _mm256_set1_epi8(1));
    v_one = _mm256_and_si256(v_one, _mm256_set1_epi8(1));
    
    __m256i v_neg_one = _mm256_cmpeq_epi8(v_pair, _mm256_set1_epi8(3));
    v_neg_one = _mm256_and_si256(v_neg_one, _mm256_set1_epi8(0xFF));
    
    // 合并结果
    return _mm256_or_si256(v_one, v_neg_one);
}

实现说明

  1. 将uint64_t加载到256位向量后,通过掩码分别提取每个位对的高低位;
  2. 合并高低位得到2位的原始值;
  3. 通过比较和掩码操作,将b01映射为0x01、b11映射为0xFF,b00保持0x00;
  4. 最终向量的32个字节与原uint64_t的32个位对顺序完全对应。

AVX512解压缩实现

利用AVX512的查找表(LUT)和VPSHUFB指令,实现更高效的映射:

__m256i unpack_bits_to_bytes_avx512(uint64_t packed) {
    // 将uint64_t加载到512位向量低64位,其余位清零
    __m512i v_packed = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, packed);
    
    // 提取每个位对的高低位并合并
    const __m512i mask_high = _mm512_set1_epi64x(0xAAAAAAAAAAAAAAAA);
    __m512i v_high = _mm512_and_si512(v_packed, mask_high);
    v_high = _mm512_srli_epi64(v_high, 1);
    
    const __m512i mask_low = _mm512_set1_epi64x(0x5555555555555555);
    __m512i v_low = _mm512_and_si512(v_packed, mask_low);
    
    __m512i v_pair = _mm512_or_si512(v_high, v_low);
    
    // 构建查找表:索引0→0,1→1,2→0,3→0xFF(对应b00、b01、b10、b11)
    const __m512i lut = _mm512_setr_epi8(
        0, 1, 0, 0xFF, 0, 1, 0, 0xFF, 0, 1, 0, 0xFF, 0, 1, 0, 0xFF,
        0, 1, 0, 0xFF, 0, 1, 0, 0xFF, 0, 1, 0, 0xFF, 0, 1, 0, 0xFF,
        0, 1, 0, 0xFF, 0, 1, 0, 0xFF, 0, 1, 0, 0xFF, 0, 1, 0, 0xFF,
        0, 1, 0, 0xFF, 0, 1, 0, 0xFF, 0, 1, 0, 0xFF, 0, 1, 0, 0xFF
    );
    
    // 通过查找表映射得到结果
    __m512i v_result = _mm512_shuffle_epi8(lut, v_pair);
    
    // 截断为__m256i返回
    return _mm256_castsi512_si256(v_result);
}

实现说明

  1. 提取位对的逻辑与AVX2一致,但使用512位向量操作;
  2. 预定义查找表,直接通过VPSHUFB指令将2位的位对值映射为目标字节;
  3. 最后截断为256位向量返回,效率比AVX2版本更高。

内容的提问来源于stack exchange,提问作者Serge Rogatch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 19:09:59