如何使用Arm v7霓虹灯内在函数获取Q寄存器int64x2_t的绝对值?

问题描述

例如:

int64x2_t a{1,-1};
auto abs_val = vabsq_s64(a);//But this intrinsic is only or A64 architecture.

谢谢!

解决方法

如果您要执行很多64位操作,则应该对硬件进行三思。在ARMv7上,有很多功能缺少64位版本,因此,如果可以升级到AArch64,则确实应该。假设您没有该选择...

基本上,vabsq_s64的每个泳道都是这样的:

res[i] = a[i] < 0 ? -a[i] : a[i];

您只需要使用其他内在函数即可。

让我们先处理一下否定。 NEON有一个vnegq_s64函数可以解决这个问题,但是它仅适用于AArch64。但是,我们可以只从0中减去a:vsubq_s64(vdupq_n_s64(0),a)

现在,我们必须在取反值和原始值(这是vbslq_s64的域)之间进行选择。 vbslq_s64的第一个参数是一个掩码,用于确定要获取每个位的值的其他哪个参数。基本上,vbslq_s64(a,b,c)在逻辑上类似于(a & b) | (~a & c)

要使用vbslq_s64,我们首先需要一个掩码,当我们要使用一个值时,该通道中的全零,而当我们要使用另一个值时,则全为零。如果您使用的是AArch64,我会说要使用vcltzq_s64,但不是。甚至vcltq_s64()都仅适用于AArch64,但这没关系,因为总有更好的方法……只使用右移算术移位,它将以符号位移位(负数为1,正数为0)。您希望将符号位广播到每个通道的每个位,因此对于一个64位的值应为vshrq_n_s64(a,63)

当然,vbslq_s64的第一个参数为uint64x2_t,但是您拥有的是int64x2_t,因此您需要使用vreinterpretq_u64_s64进行转换。

将它们放在一起:

int64x2_t my_vabsq_s64(int64x2_t a) {
  return vbslq_s64(
      vreinterpretq_u64_s64(vshrq_n_s64(a,63)),vsubq_s64(vdupq_n_s64(0),a),a);
}