我无法在ARM NEON指令中找出vld4_f32
和vld4q_f32
之间的区别。
当我提高编码级别并开始查看汇编指令而不是信息量较少的内在函数时,就开始出现混淆。
我需要在这里使用 vld4 变体指令的原因是因为,我想从每个第4个位置捕获 4 float32_t
我的大阵列。
vld4_f32
内在函数和相应的汇编指令如下所示(From this link)
float32x2x4_t vld4_f32 (const float32_t *)
Form of expected instruction(s): vld4.32 {d0, d1, d2, d3}, [r0]
vld4q_f32
内在函数及其相应的汇编指令如下所示
float32x4x4_t vld4q_f32 (const float32_t *)
Form of expected instruction(s): vld4.32 {d0, d1, d2, d3}, [r0]
嗯,在内在级别,我看到的差异是返回类型,但是如果我查看汇编指令和寄存器的数量,它们看起来都是一样的。编译器或汇编器将如何知道两者之间的区别?
有人可以对此进行更多澄清,并解释如何将 4 float32_t 值加载到单个寄存器中
>答案 0 :(得分:7)
是的,我发现了差异。我使用CodeSourcery查看所有加载指令的实际寄存器内容。我发布的链接并未提供有关vld4q_f32的完整详细信息。
好的,首先是vld4_f32
,这会加载 4 d 寄存器(例如d16-19),每个 d 寄存器是64位长,所以这条指令将加载以间隔4交错的前8个值,如下图所示。
在第二种情况下vld4q_f32
,这会加载 8 d 寄存器(例如d16-23)而不是4。对于这个link的读者来说,完全不清楚是否会加载8个寄存器。当我查看vld4qf32
的反汇编代码时,它正在使用8 d寄存器。
这条指令确实会做我希望它做的事情,即加载4个float32_t
值,间隔为4,如下图所示。
答案 1 :(得分:2)
我已经拆解了两个内在函数,也许它对某人有帮助:
// C++
uint32x4x4_t r = vld4q_u32( ( uint32_t *) output );
// assembly
VLD4.32 {D16,D18,D20,D22}, [R0]!
VLD4.32 {D17,D19,D21,D23}, [R0]
// C++
uint32x2x4_t r = vld4_u32( ( uint32_t *) output );
// assembly
VLD4.32 {D20-D23}, [R0]