代码之家  ›  专栏  ›  技术社区  ›  guxiangtao

如何在32位矢量中使用arm neon 8位乘法和加法

  •  0
  • guxiangtao  · 技术社区  · 7 年前

    我在做8bit定点工作,我有一个数组和B数组,它们都是Q7格式,我想得到它们的和积 演示代码:

    int8_t ra1[], ra2[], rb[];
    int8x16_t va1, va2, vb;
    int16x4_t vsum1, vsum2;
    va1 = vld1q_s8(ra1);
    va2 = vld1q_s8(ra2);
    vb = vld1q_s8(rb);
    vsum1 = vdup_n_s16(0);
    vsum2 = vdup_n_s16(0);
        for (......)
        vsum1 = vmlal_s8(vsum1, vget_high_s8(va1), vget_high_s8(vb));
        vsum1 = vmlal_s8(vsum1, vget_low_s8(va1), vget_low_s8(vb));
    

    16位可以代表Q15。此外,我不能右移Q7xQ7的结果,我需要保持高精度。 我怎么能用neonI想要和是32位ab还是8位我不想把a和b转移到16位,用vmlal_s16,它会很慢。我只需要一条指令,它可以在一个指令时间内进行乘法和加法。 neon c内部函数没有这个功能,也许neon汇编代码可以做到这一点。谁能帮我?谢谢 Here 是vmla汇编代码信息。也许我可以用。请给我一些建议,我不熟悉汇编代码。

    1 回复  |  直到 7 年前
        1
  •  1
  •   ErmIg    7 年前

    我希望这个代码示例可以帮助您:

    inline int32x4_t Correlation(const int8x16_t & a, const int8x16_t & b)
    {
        int16x8_t lo = vmull_s8(vget_low_s8(a), vget_low_s8(b));
        int16x8_t hi = vmull_s8(vget_high_s8(a), vget_high_s8(b));
        return vaddq_s32(vpaddlq_s16(lo), vpaddlq_s16(hi));
    }
    
    void CorrelationSum(const int8_t * a, const int8_t * b, size_t bStride, size_t size, int32_t * sum)
    {
        int32x4_t sums = vdupq_n_s32(0);
        for (size_t i = 0; i < size; i += 16)
            sums = vaddq_s32(sums, Correlation(vld1q_s8(a + i), vld1q_s8(b + i)));
        *sum = vgetq_lane_s32(sums, 0) + vgetq_lane_s32(sums, 1) + vgetq_lane_s32(sums, 2) + vgetq_lane_s32(sums, 3);
    } 
    

    注:本例基于函数 Simd::Neon::CorrelationSum()

    inline int8x16_t Load(const int8_t * p)
    {
    #ifdef __GNUC__
        __builtin_prefetch(p + 384);
    #endif
        return vld1q_s8(p);
    }
    

    使用预取可以提高15-20%的性能。