如何使用Neon内在函数在通道中添加所有int32元素

这是我在一个车道中添加所有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汇编代码在编译后能简单明了.我也希望求和的最终类型是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具有无论如何,上述水平添加.

现在,我不知道它在LLVM IR中的表现如何可怕-我想这取决于它在内部如何处理向量类型和运算-但是就最终的ARM机器代码而言,这两个都可以认为是最佳的.

转载注明原文:如何使用Neon内在函数在通道中添加所有int32元素 - 代码日志