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

时间:2017-07-20 03:21:02

标签: arm simd neon

我正在进行8位定点工作,我有一个数组和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 16bit可以代表Q15。另外,我不能向右移Q7xQ7的结果,我需要保持高精度。 我怎么能使用霓虹灯,我想要的是32位a,b还是8bit。我不想把a和b转移到16bit并使用vmlal_s16,它会慢慢来。我只需要一个可以做多次加法的指令一个指令时间。 霓虹灯内在函数没有这个功能,也许霓虹灯汇编代码可以做到这一点。谁可以帮助我?谢谢。 Here是vmla汇编代码信息。也许我可以使用它。请给出一些建议,我不熟悉汇编代码。

1 个答案:

答案 0 :(得分:0)

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

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%。

相关问题