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

如何将含可变比特数的NEON向量归约为单个32位值?

高效NEON SIMD比特拼接优化方案需求

需求说明

输入为两个NEON uint8x16_t SIMD寄存器:

  • 第一个寄存器的每个元素低N位为有效信息,剩余8-N位为0;
  • 第二个寄存器对应元素存储该N值,且所有元素的N之和≤32。

需将这些有效比特无填充地拼接为单个32位寄存器,可调整有效比特的存储位置(如改存高N位)或元素顺序,唯一硬限制是拼接无填充且顺序固定。

现有实现方案

1. 循环累加的朴素方案

uint32_t bit_reduce_naive(uint8x16_t bits, uint8x16_t bit_counts)
{
    uint32_t result = 0;
    for (size_t i = 0; i != 16; ++i)
    {
        result <<= bit_counts[i];
        result |= bits[i];
    }
    return result;
}

2. 迭代合并的SIMD优化方案

先实现u8转u16的归约步骤:

inline std::pair<uint16x8_t, uint16x8_t> reduce_step_u8(uint8x16_t bits, uint8x16_t bit_counts)
{
    const uint16x8_t expanded_count_lower = vmovl_u8(vget_low_u8(bit_counts));
    const uint16x8_t expanded_bits_lower  = vmovl_u8(vget_low_u8(bits));
    const uint16x8_t expanded_bits_higher = vmovl_high_u8(bits);
    return std::pair
    {
        vorrq_u16(expanded_bits_lower, vshlq_u16(expanded_bits_higher, expanded_count_lower)),
        vaddl_u8( vget_low_u8(bit_counts), vget_high_u8(bit_counts)),
    };
}

再通过链式调用将输入归约为两个uint64_t值后合并:

uint32_t bit_reduce_better(uint8x16_t bits, uint8x16_t bit_counts)
{
    const auto [bits_u16, counts_u16] = reduce_step_u8(bits, bit_counts);
    const auto [bits_u32, counts_u32] = reduce_step_u16(bits_u16, counts_u16);
    const auto [bits_u64, counts_u64] = reduce_step_u32(bits_u32, counts_u32);

    const uint64_t low_bits  = vget_low_u64(bits_u64)[0];
    const uint64_t high_bits = vget_low_u64(bits_u64)[0]; // 注:原代码此处疑似笔误,应为vget_high_u64
    const uint64_t low_bits_count = vget_high_u64(counts_u64)[0];

    return static_cast<uint32_t>(low_bits | (high_bits << low_bits_count));
}

注:该SIMD方案的比特拼接顺序与原向量不同,但顺序并非硬要求。现有方案已满足功能需求,现寻求更高效的实现方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 20:23:25