如何使用 arm neon 8bit 乘加和到 32 位向量?

Posted

技术标签:

【中文标题】如何使用 arm neon 8bit 乘加和到 32 位向量?【英文标题】:How to use arm neon 8bit multiply add sum into 32 bit vector ? 【发布时间】:2017-07-20 03:21:02 【问题描述】:

我在做 8bit 定点工作,我有 A 数组和 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));

总和+=a * b;这个和是16bit,很容易溢出,因为a*b是Q7×Q7 16bit可以代表Q15。另外,我不能右移Q7xQ7的结果,我需要保持高精度。 我如何使用 neon,我想要 sum 是 32bit a,b 仍然是 8bit。我不想将 a 和 b 传输到 16bit 并使用 vmlal_s16,它会很慢。我只需要一个可以做乘法和加法的指令一个指令时间。 neon c 内部函数没有这个功能,也许 neon 汇编代码可以做到这一点。谁能帮帮我?谢谢。 Here 是 vmla 汇编代码信息。也许我可以使用它。请给一些建议,我不熟悉汇编代码。

【问题讨论】:

确定在乘法之前将ab 转换为16 位很慢(即你有没有测试过这个)? AFAIR,至少一些 NEON 实现需要两倍的时间来执行 8 bit x 8 bit 向量乘法作为 16 bit x 16 bit 向量乘法,因为它们在硬件中有 16 位乘法器。在这种情况下,这意味着在乘法之前扩大实际上不会增加​​任何成本。 【参考方案1】:

希望此代码示例对您有所帮助:

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()。另外我建议使用以下函数 Load() 而不是 vld1q_s8():

inline int8x16_t Load(const int8_t * p)

#ifdef __GNUC__
    __builtin_prefetch(p + 384);
#endif
    return vld1q_s8(p);

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

【讨论】:

谢谢,但是你使用4条指令,我只有一条指令,我需要这个功能足够快。我已经做了16bit定点,我正在尝试做8bit定点,所以我需要一个指令像vmlal一样,乘加一条指令,但是我的8bit定点数据太大,我需要用32bit求和。 我确定,这没关系,因为此任务受到内存吞吐量的限制。 谢谢,我试试看。

以上是关于如何使用 arm neon 8bit 乘加和到 32 位向量?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ARM Neon 内在函数对 IF 块进行矢量化?

使用NEON优化ARM的卷积运算

如何使用 arm neon 指令右移值

Eigen 3.3 中的 ARM NEON 改进

ARM Neon 汇编器 + C 如何传递和使用指针数组

如何使用 Neon Extension 有效地反转汇编语言 ARM 中的数组?