ARM NEON 内部函数将 D(64 位)寄存器转换为 Q(128 位)寄存器的低半部分,而上半部分未定义

Posted

技术标签:

【中文标题】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 【发布时间】:2017-10-24 12:36:32 【问题描述】:

我希望能够基本上能够将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 值。

有什么办法吗?

【问题讨论】:

你自己尝试了什么。有任何实验、结果、结论 - 还是什么都没有? 我上面举的两个例子? 你有没有用编程手册检查编译后的输出,看看哪种方式更有效? @PeterJ_01 哦,拜托。你不觉得你对初学者有点太苛刻了吗?大多数人甚至不知道如何打开反汇编。尤其是 android Studio 在 IDE 级别甚至没有这个选项。 @Jake 'Alquimista' LEE 这不是一个初学者的问题。我想说的很高级的问题 【参考方案1】:

aarch32 上,您完全受制于编译器。 (这就是我在汇编中编写 NEON 例程的原因)

另一方面,在 aarch64 上,它几乎是自动的,因为无论如何都不能直接访问高位 64 位。

编译器将在vcombine 上执行trn1 指令。

总而言之,aarch64 总是存在开销,而aarch32 则无法预测。如果您的 aarch32 例程简单而简短,因此不需要太多寄存器,编译器很可能巧妙地分配寄存器,但不太可能。

顺便说一句,在aarch64,如果初始化低64位,CPU会自动将高64位设置为零。我不知道这是否需要额外的时间。这确实花了我好几天的时间,直到我发现一直以来都出了什么问题。好烦!!!

【讨论】:

感谢您的回答!对于AArch64,我想这取决于编译器是否足够聪明,可以识别出vcombine可以被淘汰。

以上是关于ARM NEON 内部函数将 D(64 位)寄存器转换为 Q(128 位)寄存器的低半部分,而上半部分未定义的主要内容,如果未能解决你的问题,请参考以下文章

使用 NEON 内部函数存储非相邻 d 寄存器的最快方法

使用 ARM neon 内部函数进行深度转换

对于 ARM Aarch64 的 NEON 编码,如何将寄存器推送到堆栈?似乎 STMFD 不是 Aarch64 指令集的一部分?

ARM NEON 到 aarch64

如何访问 NEON 指令中的完整 128 位?

ARM NEON:从 NEON 寄存器(Q/D 寄存器)中包含的地址加载数据