8.5. 没有函数栈的汇编源程序

第05章介绍LoongArch ABI时提到,函数通常会先申请函数栈,用于保存返回地址、帧指针、局部变量等。GCC编译器生成函数入口代码时,也通常会分配函数栈,最小为16字节。例如,实现一个简单的两个整数加法函数,C语言可以写为:

int myadd(int a,int b){
	return a+b;
}

使用GCC把该C函数编译为汇编源文件后,内容如下:

myadd:
	addi.d 		$r3, $r3, -32 		#	申请栈空间
	st.d 		$r22, $r3, 24 		# 	将原fp值保存到栈上
	add.d 		$r22, $r3, 32 		#	将fp指向当前函数栈底
	or 			$r13, $r4, $r0 		#	保存a0和a1到栈
	or 			$r12, $r5, $r0 		#
	slli.w 		$r13, $r13, 0
	st.w 		$r13, $r22, -20
	slli.w 		$r12, $r12, 0
	st.w 		$r12, $r22, -24
	ld.w 		$r13, $r22, -20 	#	从栈上加载a0和a1
	ld.w 		$r12, $r22, -24
	add.w 		$r12, $r13, $r12 	#	加法运算
	or 			$r4, $r12, $r0 		#	设置返回值
	ld.d 		$r22, $r3, 24 
	addi.d 		$r3, $r3, 32
	jr 			$r1 				#	函数返回

按照LoongArch ABI约定,函数入口通常先申请栈空间,并把必要寄存器(如fp、参数寄存器等)保存到栈上;函数退出前再恢复寄存器并释放栈空间。因此,在没有强制内联等优化时,一个简单加法函数可能生成上面所示的16条指令。如果直接编写汇编源文件test.S实现同样功能,则只需2条指令。

myadd:
	add.d 	$v0, $a0, $a1
	jirl 	$zero, $ra, 0

编写汇编程序时,如果可以确认该函数不会破坏任何需要保留的寄存器,就可以省去函数栈分配与释放,也无需保存和恢复相关寄存器。因此,上述功能最终只用2条指令即可实现。由此可见,直接编写汇编程序能够为性能优化提供更大的空间。