ARM NEON 内部函数将 D(64 位)寄存器转换为 Q(128 位)寄存器的低半部分,而上半部分未定义
ARM NEON intrinsics convert D (64-bit) register to low half of Q (128-bit) register, leaving upper half undefined
我希望能够在没有开销的情况下将 uint8x8_t
类型转换为 uint8x16_t
,同时保留高 64 位未定义。如果您只关心底部 64 位,但希望使用 128 位指令,这很有用,例如:
uint8x16_t data = (uint8x16_t)vld1_u8(src); // if you can somehow do this
uint8x16_t shifted = vextq_u8(oldData, data, 2);
根据我对 ARM 汇编的理解,这应该是可能的,因为可以将负载发布到 D 寄存器,然后解释为 Q 寄存器。
我能想到的一些方法是:
data = vcombine_u8(vld1_u8(src), vdup_n_u8(0));
- 编译器似乎努力将上半部分设置为 0,即使这从来没有必要
data = vld1q_u8(src);
- 执行 128 位加载工作(在我的情况下很好),但在具有 64 位 NEON 单元的处理器上可能更慢?
我想 CPU 中可能存在部分依赖关系的棘手情况,只设置了一半这样的寄存器,但我宁愿编译器在这里找到最好的方法而不是强制它使用 0 值。
有什么办法吗?
在 aarch32
上,您完全受制于编译器。 (这就是我用汇编写NEON例程的原因)
另一方面,在 aarch64
上,它几乎是自动的,因为无论如何都不能直接访问上层 64 位。
虽然编译器会在 vcombine
上执行 trn1
指令。
总而言之,aarch64
上总是有开销,而 aarch32
上则不可预测。如果您的 aarch32
例程简单而简短,因此不需要很多寄存器,编译器很可能会巧妙地分配寄存器,否则就不太可能了。
顺便说一句,在 aarch64
上,如果您初始化低 64 位,CPU 会自动将高 64 位设置为零。我不知道这是否需要额外的时间。我确实花了好几天时间才发现一直以来出了什么问题。好烦!!!
我希望能够在没有开销的情况下将 uint8x8_t
类型转换为 uint8x16_t
,同时保留高 64 位未定义。如果您只关心底部 64 位,但希望使用 128 位指令,这很有用,例如:
uint8x16_t data = (uint8x16_t)vld1_u8(src); // if you can somehow do this
uint8x16_t shifted = vextq_u8(oldData, data, 2);
根据我对 ARM 汇编的理解,这应该是可能的,因为可以将负载发布到 D 寄存器,然后解释为 Q 寄存器。
我能想到的一些方法是:
data = vcombine_u8(vld1_u8(src), vdup_n_u8(0));
- 编译器似乎努力将上半部分设置为 0,即使这从来没有必要data = vld1q_u8(src);
- 执行 128 位加载工作(在我的情况下很好),但在具有 64 位 NEON 单元的处理器上可能更慢?
我想 CPU 中可能存在部分依赖关系的棘手情况,只设置了一半这样的寄存器,但我宁愿编译器在这里找到最好的方法而不是强制它使用 0 值。
有什么办法吗?
在 aarch32
上,您完全受制于编译器。 (这就是我用汇编写NEON例程的原因)
另一方面,在 aarch64
上,它几乎是自动的,因为无论如何都不能直接访问上层 64 位。
虽然编译器会在 vcombine
上执行 trn1
指令。
总而言之,aarch64
上总是有开销,而 aarch32
上则不可预测。如果您的 aarch32
例程简单而简短,因此不需要很多寄存器,编译器很可能会巧妙地分配寄存器,否则就不太可能了。
顺便说一句,在 aarch64
上,如果您初始化低 64 位,CPU 会自动将高 64 位设置为零。我不知道这是否需要额外的时间。我确实花了好几天时间才发现一直以来出了什么问题。好烦!!!