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

如何使用arm neon 8位乘法加和到32位向量?;,arm,simd,neon,Arm,Simd,Neon,我在做8位定点工作,我有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 (......) vs

我在做8位定点工作,我有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;这个和是16位的,它很容易溢出,因为a*b是Q7×Q7 16位可以代表Q15。另外,我不能右移Q7xQ7结果,我需要保持高精度。 如何使用neon,我希望总和是32位a,b仍然是8位。我不希望将a和b转换为16位并使用vmlal_s16,速度会很慢。我只需要一条指令,它可以在一个指令时间内进行乘法和加法。 neon c内部函数没有这个功能,也许neon汇编代码可以做到。谁能帮我?谢谢
是vmla程序集代码信息。也许我可以使用它。请给我一些建议,我不熟悉汇编代码。

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

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);
} 

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

您确定在乘法运算速度较慢之前将
a
b
转换为16位(即,您是否测试过这一点)?至少一些NEON实现需要两倍于16位x 16位向量乘法的
8位x 8位
向量乘法,因为它们在硬件中有16位乘法器。在这种情况下,这意味着乘法之前的加宽有效地增加了成本。谢谢,但是你使用4条指令,我只需要一条指令,我需要这个函数足够快。我已经完成了16位的固定点,我正在尝试做8位的固定点,所以我需要一条指令,比如vmlal,乘法和加法,一条指令,但是我的8位定点数据太大了,我需要32位求和。我确信,这没关系,因为这个任务受内存吞吐量的限制。谢谢,我会尝试的。
inline int8x16_t Load(const int8_t * p)
{
#ifdef __GNUC__
    __builtin_prefetch(p + 384);
#endif
    return vld1q_s8(p);
}