为什么 vld4q_f32 与 4x vld1q_f32 不同?

Why is vld4q_f32 not the same as 4x vld1q_f32?

const float* H; //input data from elsewhere
const float32x4x4_t hCols = vld4q_f32(H);

const float32x4_t hCol0 = vld1q_f32(H + 0);
const float32x4_t hCol1 = vld1q_f32(H + 4);
const float32x4_t hCol2 = vld1q_f32(H + 8);
const float32x4_t hCol3 = vld1q_f32(H + 12);

我使用 hCol0、hCol1、hCol2、hCol3 的代码被替换为 hCols.val[0]、hCols.val[1]、hCols.val[2]、hCols.val[3] 但现在我的输出很奇怪。

这两个负载是否不完全相同 vld4q_f32 可能更快?

vld4 是一个与 vld1 完全不同的指令。

虽然 vld1 是直接加载,但 vld4 是分散加载,其中每个值都分布在四个寄存器中,一个元素一个元素,一个寄存器一个寄存器。

vld4q_f32(pSrc) will translate to:

vld4.32 {d0, d2, d4, d6}, [pSrc]!
vld4.32 {d1, d3, d5, d7}, [pSrc]

*pSrc:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E

================================================

And the values are loaded as following:
q0 (d0 + d1): 0, 4, 8, C
q1 (d2 + d3): 1, 5, 9, D
q2 (d4 + d5): 2, 6, A, E
q3 (d6 + d7): 3, 7, B, F

在汇编中,可以用一条指令直接加载多个寄存器,例如:

vld1.32 {q0, q1}, [pSrc]!
vld1.32 {q2, q3}, [pSrc]

And the values are loaded as following:
q0 (d0 + d1): 0, 1, 2, 3
q1 (d2 + d3): 4, 5, 6, 7
q2 (d4 + d5): 8, 9, A, B
q3 (d6 + d7): C, D, E, F

但是,在内部函数中,您必须逐个注册: float32x4x4_t hCols;

hCols.val[0] = vld1q_f32(H + 0);
hCols.val[1] = vld1q_f32(H + 4);
hCols.val[2] = vld1q_f32(H + 8);
hCols.val[3] = vld1q_f32(H + 12);

在 Android Studio 3.01 上,vld1q_f32_x4 是为此目的而定义的,但它仍然看起来有问题。至少我没能成功搭建。

顺便说一句,你是想做 4x4 矩阵乘法吗?恭喜,您刚刚在 vld4;

中找到了如何即时自动转置矩阵

不要在内部函数上浪费时间。 汇编版本的运行速度几乎是原来的三倍,而我将 1:1 翻译成内在函数,由 Android Studio 3.01 附带的 Clang 编译。真烦人。

使用内部函数纯粹是浪费时间,至少在 ARM 上是这样。