13.2. 基础浮点指令类
【例1】 单/双精度浮点数的加法运算
fadd.s $f0, $f2, $f1 # 单精度浮点数加法,f0[31:0] = f2[31:0] + f1[31:0]
fadd.d $f0, $f2, $f1 # 双精度浮点数加法,f0[63:0] = f2[63:0] + f1[63:0]
这两条指令分别完成单精度和双精度浮点加法,并把结果写入浮点寄存器 f0。
【例2】 双精度浮点数乘加运算
fmadd.d $f0, $f1, $f2, $f3 # 双精度浮点数乘加,f0 = f1*f2 + f3
浮点乘加指令是 LoongArch 中较少见的四操作数指令,包含一个目的寄存器和3个源寄存器。它执行类似 a = b * c + d 的乘加运算,计算与舍入规则遵循 IEEE 754-2008 标准。
【例3】 写出如下程序的汇编指令
float a = 1.0;
float b = 2.0;
float c = a + b;
这段 C 代码涉及浮点加载、浮点加法和浮点存储三类操作,对应的 LoongArch 汇编指令如下:
fld.s $f0, $r12, 0 # 从内存加载1.0到浮点寄存器f0
fld.s $f1, $r12, 4 # 从内存加载2.0到浮点寄存器f1
fadd.s $f2, $f0, $f1 # 将1.0 + 2.0结果写入浮点寄存器f2
fst.s $f2, $r12, 8 # 将结果写回内存
这里假设 r12 保存变量 a 的起始地址,变量 b 和 c 紧随 a 存放。因此加载 b 的地址为 r12 + 4,写回 c 的地址为 r12 + 8。由于这两个偏移量都在12位范围内,可直接使用 fld.s 和 fst.s。若偏移量超过12位,则需要改用相应的 fldx/fstx 指令。
【例4】 编写如下C语言语句对应的汇编指令
float a = 1.0;
float b = 2.0;
float c = (a < b)? 1 : 0 ;
这段语句比较浮点变量 a 与 b。若条件成立,c 赋值为1;否则赋值为0。对应的 LoongArch 汇编实现如下:
li.w $r4, 0 # 加载0到寄存器r4
fcmp.slt.s fcc0,$f0,$f1 # 如果f0 < f1成立,则条件标志寄存器fcc0置1,否则置0
bceqz fcc0, 4 # 如果fcc0等于0,跳转到nop,否则继续执行下一条li指令
li.w $r4, 1
nop
这里假设 a 位于浮点寄存器 f0,b 位于 f1,c 位于通用寄存器 r4。由于当前 a 为1.0、b 为2.0,fcmp.slt.s fcc0, f0, f1 执行后 fcc0 为1,bceqz 不跳转,程序继续执行 li.w r4, 1,把 c 置为1。
【例5】 编写如下C语言语句对应的汇编指令
float fv = (a < b)? a : b;
这段 C 语句把 a 和 b 中较小的值赋给浮点变量 fv。对应汇编可写为:
fcmp.slt.s fcc0, $f0, $f1
bceqz fcc0, 0x4
fmov.s $f2, $f0
fmov.s $f2, $f1
这里假设 a、b、fv 分别存放在浮点寄存器 f0、f1、f2。fcmp.slt.s fcc0, f0, f1 完成 a < b 的比较,并把结果写入 fcc0。bceqz fcc0, 0x4 根据 fcc0 决定是否跳转:若 fcc0 为0,即 a < b 不成立,则跳转到 fmov.s f2, f1,把 b 赋给 fv;否则顺序执行 fmov.s f2, f0,把 a 赋给 fv。
【例6】 编写如下C语言语句对应的汇编指令
float fv = 3.0;
double dv = fv;
上述语句用于把单精度浮点数 fv 转换为双精度浮点数 dv。对应汇编如下:
fcvt.d.s $f1, $f0
这里假设 fv 存放在浮点寄存器 f0,dv 存放在 f1。执行 fcvt.d.s f1, f0 后,即完成从 fv 到 dv 的精度转换。
【例7】 当浮点寄存器 f1 的值分别为 1.2340f 和 1.5340f 时,在如下指令执行后,寄存器 f0 的值为多少?
frint.s $f0, $f1
frint.s 按当前浮点舍入规则,把单精度浮点数转换为整数值对应的单精度浮点数。当 f1 为 1.2340f 时,执行后 f0 为 1.0000f;当 f1 为 1.5340f 时,执行后 f0 为 2.0000f。
【例8】 实现浮点数 double 类型到 long 类型的强制转换
long ret = (long)3.145; // ret结果为3
对应的 LoongArch 汇编可写为:
ftintrz.l.d $f30, $f1 // f1存放浮点数3.145,指令结束后f30为3.000
movfr2gr.d $r7, $f30 // 将f30中的3.000移动到整型寄存器r7,指令结束后r7为3
【例9】 定点数转浮点数示例
float fval = 3;
该语句对应的 LoongArch 汇编指令如下:
li.w $r12, 0x3
movgr2fr.w $f0, $r12
ffint.s.w $f0, $f0
这里 li.w 先把定点数3装入通用寄存器 r12;movgr2fr 将 r12 的内容搬到浮点寄存器 f0;最后 ffint.s.w 把 f0 中的定点数3转换为浮点数3.0,并写回 f0。
【例10】 使能浮点控制状态寄存器 fcsr0 的 Enable 域中的所有位(VZOUI)
li $r7, 0x1f
movgr2fcsr $r0, $r7 // 这里使用通用寄存器r0来标识fcsr0