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.sfst.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