2017-07-20 58 views
0

我正在做8bit定点工作,我有一个数组和B阵列都是Q7格式的,我想得到他们的和积 演示代码:如何使用arm霓虹灯8bit乘加总和到32位矢量中?

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

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

+0

你确定*在乘法运算缓慢之前将a和b转换为16位(即你有没有测试过*)? AFAIR,至少有一些NEON实现需要两倍长的时间来执行'8位×8位'向量乘法,因为它们在硬件中具有16位乘法器。在这种情况下,这意味着在乘法之前加宽并不会增加成本。 – EOF

回答

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()。此外,我会建议使用下面的函数加载()的vld1q_s8而不是():

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

使用预取增加了15%-20%的性能。

+0

谢谢,但你使用4条指令,我只是一条指令,我需要这个函数足够快。我已经完成了16位固定piont,我正在尝试做8位定点,所以我需要一个像vmlal,乘法和加法一条指令,但我的8位定点数据太大了,我需要在32bit中求和。 – guxiangtao

+0

我确定,这并不重要,因为此任务受限于内存吞吐量。 – ErmIg

+0

谢谢,我会尝试。 – guxiangtao