这是我在车道中添加所有 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 在我的主机上不起作用。

最佳答案

如果你只想要一个 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 中看起来有多可怕——我想这取决于它如何在内部处理 vector 类型和操作——但就最终的 ARM 机器代码而言,两者都可以被认为是最佳的。

关于c - 如何使用内在 NEON 在车道中添加所有 int32 元素,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40890319/

10-14 07:11