我使用ARM NEON内在函数(llvm,iOS)向量化内部循环。我一般都在使用float32x4_t
。我的计算结束时需要对这个向量中的四个浮点数中的三个进行求和。
我可以在此时退回到C浮点数并vst1q_f32
以获得四个值并将我需要的三个值相加。但我认为如果有一种方法可以直接用指令或两个指令中的向量来实现它,那么只需抓住一个单一的通道结果,但我无法弄清楚这样做的任何明确路径。
我是NEON编程的新手,现有的“文档”非常可怕。有任何想法吗?谢谢!
答案 0 :(得分:4)
您应该能够使用VFP单元执行此类任务。 NEON和VFP共享相同的寄存器组,这意味着您不需要在寄存器周围进行混洗以获得一个单元的优势,并且它们也可以具有相同寄存器位的不同视图。
您的float32x4_t
为128位,因此必须位于四(Q)寄存器中。如果你只使用手臂内在,你不会知道你正在使用哪一个。问题是如果它位于4以上,VFP无法将其视为单一精度(对于好奇的读者:我保持这很简单,因为VFP版本之间存在差异,这是最低要求。)。因此,最好将float32x4_t
移至Q0
这样的固定寄存器。在此之后,您可以将{0,S,S2,S2等寄存器与vadd.f32
相加,并将结果移回ARM寄存器。
一些警告...... VFP和NEON在理论上是不同的执行单元,共享相同的寄存器组和流水线。我不确定这种方法是否比其他方法更好,我不需要再说一遍,你应该做基准测试。此方法也没有简化霓虹内在因素,因此您可能需要使用内联汇编来制作代码。
我做了一个简单的片段,看看它是怎么样的,我想出了这个:
#include "arm_neon.h"
float32_t sum3() {
register float32x4_t v asm ("q0");
float32_t ret;
asm volatile(
"vadd.f32 s0, s1\n"
"vadd.f32 s0, s2\n"
"vmov %[ret], s0\n"
: [ret] "=r" (ret)
:
:);
return ret;
}
objdump
看起来像(用gcc编译-O3 -mfpu = neon -mfloat-abi = softfp)
00000000 <sum3>:
0: ee30 0a20 vadd.f32 s0, s0, s1
4: ee30 0a01 vadd.f32 s0, s0, s2
8: ee10 3a10 vmov r0, s0
c: 4770 bx lr
e: bf00 nop
如果你愿意,我真的很想听听你的印象!
答案 1 :(得分:3)
你能把第四个元素归零吗?也许只是通过复制它并使用vset_lane_f32
?
如果是这样,您可以使用Sum all elements in a quadword vector in ARM assembly with NEON的答案,如:
float32x2_t r = vadd_f32(vget_high_f32(input), vget_low_f32(input));
return vget_lane_f32(vpadd_f32(r, r), 0); // vpadd adds adjacent elements
虽然这实际上比你需要的工作多一点,但是用vget_lane_f32
提取三个浮点数并添加它们可能会更快。
答案 2 :(得分:2)
听起来你想使用(某些版本的)VLD1将零加载到你的额外通道中(除非你可以将它安排为零),然后是两条VPADDL指令,将四条通道分成两部分并且然后将两条车道合二为一。