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条指令即可实现。由此可见,直接编写汇编程序能够为性能优化提供更大的空间。