Arm neon执行汇总SAD时发生总线错误(绝对差之和)

Arm neon执行汇总SAD时发生总线错误(绝对差之和),arm,simd,neon,Arm,Simd,Neon,我正在尝试编写一个霓虹灯版本的16 uint8大小输入的绝对差之和: inline static int f_sad_16(const uint8_t* a, const uint8_t* b) { int sad = 0; for (int i = 0; i < 16; i++) { sad += abs(static_cast<int>(a[i]) - static_cast<int>(b[i])); } return sad; } i

我正在尝试编写一个霓虹灯版本的16 uint8大小输入的绝对差之和:

inline static int f_sad_16(const uint8_t* a, const uint8_t* b)
{
  int sad = 0;
  for (int i = 0; i < 16; i++) {
    sad += abs(static_cast<int>(a[i]) - static_cast<int>(b[i]));
  }
  return sad;
}
inline static int f_sad_16(const uint8_t*a,const uint8_t*b)
{
int sad=0;
对于(int i=0;i<16;i++){
sad+=abs(静态施法(a[i])-静态施法(b[i]);
}
返回悲伤;
}
我写的霓虹灯代码:

inline static int f_sad_16_neon(const uint8_t* a, const uint8_t* b)
{
  int32_t r[4] = { 0, 0, 0, 0 };
  uint8x16_t va, vb, vr;

  va = vld1q_u8(a);
  vb = vld1q_u8(b);

  vr = vabdq_u8(va, vb);

  uint16x8_t vr1 = vpaddlq_u8 (vr );
  uint32x4_t vr2 = vpaddlq_u16(vr1);
  uint64x2_t vr3 = vpaddlq_u32(vr2);

  vst1q_u64 (reinterpret_cast<uint64_t*>(r), vr3);

  return r[0] + r[2];
}
inline static int f_sad_16_neon(const uint8_t*a,const uint8_t*b)
{
int32_t r[4]={0,0,0,0};
uint8x16_t va、vb、vr;
va=vld1q_u8(a);
vb=vld1q_u8(b);
vr=vabdq_u8(va,vb);
uint16x8_t vr1=vpaddlq_u8(vr);
uint32x4_t vr2=vpaddlq_u16(vr1);
uint64x2_t vr3=vpaddlq_u32(vr2);
vst1q_u64(重新解释铸造(r),vr3);
返回r[0]+r[2];
}
由于某种原因,我得到一个总线错误。我的测试程序对两个输入使用了
\uuuu属性(aligned(16))
gcc指令,通过分配给它们的内存地址,我可以看出输入是16字节对齐的


问题的根源是什么?

您需要确保
r
正确对齐-更改:

int32_t r[4] = { 0, 0, 0, 0 };
致:


但是,请注意,此例程不太可能有益,因为它同时使用大量标量指令和霓虹灯指令,这意味着它的性能很可能与原始标量实现的性能相似。

在哪一条源线上出现总线错误?您是对的,对齐了r[4]消除了总线错误。我仍然在寻找你提到的错误,我的测试程序显示了预期的结果。如果你有一个测试用例,其中的错误会显示自己,我很高兴看到它。对不起-我收回关于错误的-我读代码太快了。不过,我对性能的评论仍然站得住脚——您的NEON代码不太可能比一个像样的标量实现快得多。真的。在一个小的骨架测试中,我看到在常规C代码上启用-O3时,与gcc(4.6.3)相比~x1.7的加速比。经过重新思考,我得到了一个解决方案,它满足了128个uint8的SAD需求,这就是我正在编码的算法所需要的SAD值。使用vpadalq_u8,16个uint8的总和减少为8个uint16,并进行累积。在第8次迭代后,使用vpaddlq将部分和减少到1 SAD值。这使我的测试程序加速了~x7.5。所有测试均在Cortex-A9上进行。
int32_t r[4] = { 0, 0, 0, 0 } __attribute__ ((aligned(16)));