【问题标题】:How to add all int32 element in a lane using neon intrinsic如何使用霓虹灯内在通道中添加所有 int32 元素
【发布时间】:2017-04-14 21:23:55
【问题描述】:

这是我在车道中添加所有 int16x4 元素的代码:

#include <arm_neon.h>
...
int16x4_t acc = vdup_n_s16(1);
int32x2_t acc1;
int64x1_t acc2;
int32_t sum;
acc1 = vpaddl_s16(acc);
acc2 = vpaddl_s32(acc1);
sum = (int)vget_lane_s64(acc2, 0);
printf("%d\n", sum);// 4

我尝试将所有 int32x4 元素添加到一个通道中。

但我的代码看起来效率低下:

#include <arm_neon.h>
...
int32x4_t accl = vdupq_n_s32(1);
int64x2_t accl_1;
int64_t temp;
int64_t temp2;
int32_t sum1;
accl_1=vpaddlq_s32(accl);
temp = (int)vgetq_lane_s64(accl_1,0);
temp2 = (int)vgetq_lane_s64(accl_1,1);
sum1=temp+temp2;
printf("%d\n", sum);// 4

有没有简单明了的方法来做到这一点?我希望 LLVM 汇编代码在编译后简洁明了。我也希望sum 的最终类型是 32 位。

我使用了基于 LLVM 编译器基础架构的 ellcc 交叉编译器来编译它。

我在 stackoverflow 上看到了类似的问题 (Add all elements in a lane),但内在的 addv 在我的主机上不起作用。

【问题讨论】:

  • 为什么你觉得你的代码看起来效率低下?我看不到复杂的循环或分支。只是顺序。除了效率之外,您还试图解决其他问题吗?即代码是否执行了它应该执行的操作?
  • 因为 LLVM 汇编代码在编译后很复杂,所以我想知道有没有更简单的方法来做到这一点,比如使用 neon 内在函数。
  • 我的目标是通过 pass 自动生成 LLVM-IR,如果 LLVM-IR 代码很复杂,对我来说很难。

标签: c arm llvm simd neon


【解决方案1】:

如果你只想要一个 32 位的结果,可能中间溢出是不太可能的,或者你根本不关心它,在这种情况下你可以一直保持 32 位:

int32x2_t temp = vadd_s32(vget_high_s32(accl), vget_low_s32(accl));
int32x2_t temp2 = vpadd_s32(temp, temp);
int32_t sum1 = vget_lane_s32(temp2, 0);

不过,使用 64 位累加其实并不麻烦,而且不用退出 NEON 也可以做到——只是操作顺序不同:

int64x2_t temp = vpaddlq_s32(accl);
int64x1_t temp2 = vadd_s64(vget_high_s64(temp), vget_low_s64(temp));
int32_t sum1 = vget_lane_s32(temp2, 0);

其中任何一个都归结为只有 3 条 NEON 指令,并且没有标量算术。 32 位 ARM 的关键技巧是,Q 寄存器的两半的成对相加只是两个 D 寄存器的正常相加 - 这不适用于 SIMD 寄存器布局不同的 AArch64,但 AArch64 具有前面提到的水平addv反正。

现在,我不知道在 LLVM IR 中这看起来有多可怕——我想这取决于它如何在内部处理向量类型和操作——但就最终的 ARM 机器代码而言,两者都可以被认为是最优的。

【讨论】:

  • 您的回答很有帮助!在我的 LLVM IR 中有 shufflevector 指令而不是类型转换指令,例如 truncsext。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-25
  • 1970-01-01
  • 2015-02-14
相关资源
最近更新 更多