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

AArch64 SIMD/ARM NEON中如何转向量比较掩码为位掩码并查询匹配?

NEON实现匹配索引与位掩码的解决方案

获取首个匹配的索引

NEON没有直接对应AVX2 tzcnt的指令,但可以通过位操作+编译器内置函数实现相同效果:

  1. 从比较结果(uint8x16_t,匹配为0xFF,不匹配为0x00)中提取每个字节的最低位(匹配则为1,不匹配则为0):
    uint8x16_t match_bits = vandq_u8(result, vdupq_n_u8(1));
    
  2. 将16个8位的位值打包成一个16位整数:
    // 合并低8位和高8位为16位掩码
    uint16_t mask = vget_lane_u16(vpaddlq_u8(match_bits), 0);
    mask |= vget_lane_u16(vpaddlq_u8(vextq_u8(match_bits, match_bits, 8)), 0) << 8;
    
  3. 用内置函数查找第一个置位位的索引,等价于tzcnt:
    int first_match_idx = __builtin_ctz(mask);
    
    注:__builtin_ctz是GCC/Clang支持的ARM架构内置函数,若需纯指令实现,可通过rbit+clz组合:
    int first_match_idx = __builtin_clz(__builtin_rbit(mask)) - 16;
    

生成匹配位掩码(类似AVX2 movemask)

要将每个字节的匹配状态转换为对应位(匹配为1,不匹配为0),可按以下步骤高效实现:

  1. 提取匹配位(同上述第一步):
    uint8x16_t match_bits = vandq_u8(result, vdupq_n_u8(1));
    
  2. 批量移位合并为16位掩码:
    // 生成移位因子:低8位对应0-7位偏移,高8位对应8-15位偏移
    uint16x8_t shift_low = vcreate_u16(0x0706050403020100ULL);
    uint16x8_t shift_high = vaddq_u16(shift_low, vdupq_n_u16(8));
    
    // 处理低8位,将每个位移到对应位置后求和合并
    uint16x8_t vec_low = vreinterpretq_u16_u8(match_bits);
    uint16_t mask_low = vaddvq_u16(vshlq_u16(vec_low, shift_low));
    
    // 处理高8位,同理合并
    uint16x8_t vec_high = vreinterpretq_u16_u8(vextq_u8(match_bits, match_bits, 8));
    uint16_t mask_high = vaddvq_u16(vshlq_u16(vec_high, shift_high));
    
    // 最终得到16位掩码,第i位对应输入第i个字节的匹配状态
    uint16_t full_mask = mask_low | mask_high;
    
    以"ABAA"为例,此代码会生成0b1101(即十进制13),对应第0、2、3位为1,第1位为0。

注意事项

  • 上述代码假设输入是16字节的uint8x16_t,若处理其他长度的NEON寄存器,可调整移位因子和合并逻辑。
  • 确保编译器开启NEON优化(如-mfpu=neon),以生成高效的ARM指令。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 06:45:33