如何将浮点常量移入 FP 寄存器?

Posted

技术标签:

【中文标题】如何将浮点常量移入 FP 寄存器?【英文标题】:How do I move a floating point constant into an FP register? 【发布时间】:2020-10-30 12:24:01 【问题描述】:

所以,我正在使用 A64 指令集以汇编形式 ARM 进行编程。 我正在使用指令 fmov d1, #31.0 将值移动到 dx 寄存器。 但是,当我使用 0.0 或任何高于 31.0 的值时,它会显示错误:

"Error: invalid floating-point constant at operand 2 -- `fmov d1,#32.0'"

那么,如何在 A64 上定义浮点常量?为什么我不能使用 31 以上的任何值或使用 0?如何用十六进制表示值?

另一个问题是:根据arm's website,它支持使用浮点寄存器作为 Bx、Hx、Sx、Dx 和 Qx(分别为 8、16、34、64 和 128 位),但我只能' t 使用 Bx、Hx 和 Qx 寄存器,它显示:

" 错误:操作数不匹配 -- `fmov b1,#1.0'"

" 错误:选择的处理器不支持 `fmov h1,#2.0"

" 错误:操作数不匹配 -- `fmov q1,#2.0'"

如何正确设置第二个操作数?

【问题讨论】:

【参考方案1】:

只有极少量的浮点常量可以与fmov 一起使用,因为该常量在指令中被编码为 8 位立即数。具体来说,它必须可以表示为 ±n/16×2r 其中 n 是范围内的整数16 ≤ n ≤ 31 且 r 是 -3 ≤ n ≤ 4 范围内的整数。

ARMv8 架构参考手册中给出了支持数字的确切列表。此外,fmov 仅适用于 16、32 和 64 位数据大小,而不是 8 位或 128 位浮点格式是为 ARMv8 指定的。对于不支持FEAT_FP16 的 ARMv8 内核,也不支持 16 位数据大小。 ARMv8 在很多这样的地方缺乏正交性;并非所有指令都适用于所有操作数大小。

对于一个简单的替代解决方案,请在文字池中使用 ldr 和常量(您需要手动将其转换为整数)。例如,要加载32.0,将32.0 转换为它的IEEE 754 表示,得到0x4040000000000000。然后你可以像这样加载这个常量:

ldr d1, =0x4040000000000000

带有 SIMD&FP 寄存器和文字池中的值的 ldr 指令可用于 32 位、64 位和 128 位的操作数大小。较小的操作数大小不适用于文字池寻址模式。如果要加载 8 位或 16 位寄存器,请改为加载相应的 32 位寄存器。

稍微快一点的解决方案是首先将所需数字加载到通用寄存器(支持更灵活的立即数生成)中,然后将其移动到 SIMD&FP 寄存器中:

mov x0, #0x4040000000000000
fmov d1, x0

要加载0.0 或掩码,请使用movi 指令。该指令的合法立即数集合取决于操作数大小。但对于你的情况,这只是

movi d1, #0

这会清除d1 寄存器(因此也会清除b1h1s1q1 寄存器)。

【讨论】:

那么让我看看我是否明白了:我真的不能将大于 31 的数字直接加载到浮点寄存器中吗? @MarlonPedersoli 您可以直接使用ldr 执行此操作。 fmov 指令确实支持大于 31.0 的其他数字(例如 32.0),只要它们适合第一段中给出的可直接加载的数字集。

以上是关于如何将浮点常量移入 FP 寄存器?的主要内容,如果未能解决你的问题,请参考以下文章

如何将浮点常量值移动到 xmm 寄存器中?

如何将 64 位指针移入 RAX 寄存器?

有条件地将零移入寄存器?

如何为 ARMCC 声明全局浮点寄存器

如何在Micropython汇编语言中测试浮点寄存器的符号

为什么浮点寄存器与通用寄存器不同