这是我在通道中添加所有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
在我的主机上不起作用。
答案 0 :(得分:3)
如果你只想要一个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机器代码而言,两者都可以被视为最佳