Shu*_*hun 3 c arm simd llvm neon
这是我在通道中添加所有 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
Run Code Online (Sandbox Code Playgroud)
我尝试将所有 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
Run Code Online (Sandbox Code Playgroud)
有没有简单明了的方法来做到这一点?我希望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);
Run Code Online (Sandbox Code Playgroud)
然而,使用 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);
Run Code Online (Sandbox Code Playgroud)
其中任何一个都归结为只有 3 条 NEON 指令,并且没有标量算术。32 位 ARM 上的关键技巧是 Q 寄存器的两半的成对相加只是两个 D 寄存器的正常相加 - 这不适用于 AArch64,其中 SIMD 寄存器布局不同,但 AArch64 具有无论如何,前面提到的水平addv。
现在,我不知道这些在 LLVM IR 中看起来有多可怕 - 我想这取决于它内部如何处理向量类型和操作 - 但就最终的 ARM 机器代码而言,两者都可以被认为是最佳的。
| 归档时间: |
|
| 查看次数: |
3065 次 |
| 最近记录: |