2.6 C语言的机器表示
C语言等高级语言编写的程序必须经过编译器转换为汇编语言,再由汇编器转换为指令码才能在CPU上执行。本节简要介绍高级语言转换为指令码涉及的一些问题,为方便起见,选择C语言和LoongArch汇编码进行介绍。
2.6.1 过程调用
过程调用是高级语言程序中的一个关键特性,它可以让特定程序段的内容与其他程序和数据分离。过程接受参数输入,并通过参数返回执行结果。C语言中过程和函数的概念相同,本节后面也不进行区分。过程调用中,调用者和被调用者必须遵循同样的接口约定,包括寄存器使用、栈的使用和参数传递的约定等。这部分涉及内容较多,将在第4章中进行详细的介绍。本节中,主要介绍过程调用的流程和其中与指令集相关的内容。
在LoongArch指令集中,负责函数调用的指令是BL,这是一条相对转移指令。该指令在跳转的同时还将其下一条指令的地址放入1号通用寄存器(记为$ra)中,作为函数返回地址。负责函数返回的指令是JR,属于间接跳转指令,该指令的操作数为寄存器,因此LoongArch汇编中最常见的函数返回指令是jr $ra。
除了调用和返回的指令外,函数调用和执行过程中还需要执行一系列操作:
·调用者(S)将参数(实参)放入寄存器或栈中;
·使用BL指令调用被调用者(R);
·R在栈中分配自己所需要的局部变量空间;
·执行R过程;
·R释放局部变量空间(将栈指针还原);
·R使用JR指令返回调用者S。
默认情况下,通用寄存器$r4~$r11(记为$a0~$a7)作为参数输入,其中$r4和$r5同时也作为返回值,通用寄存器$r12~$r20(记为$t0~$t8)作为子程序的暂存器无须存储和恢复。LoongArch中没有专门的栈结构和栈指针,通用寄存器$r3(记为$sp)通常作为栈指针寄存器,指向栈顶。
一个简单的C语言过程调用程序及其LoongArch汇编码如图2.10所示。
图2.10 过程调用及其LoongArch机器表示
add程序是被调用的子程序,由于程序功能很简单,因此无须使用栈来存储任何信息,其输入参数存放在$a0、$a1两个寄存器中,计算的结果存放在$a0寄存器中。
ref程序是add程序的调用者,通过BL指令进行调用,BL指令会修改$ra寄存器的值,因此在ref中需要将$ra寄存器的值保存到栈中,栈顶指针和RA值存放的位置遵循LoongArch函数调用规范,这部分内容将在4.1节中进行介绍。add程序的返回值放在$a0寄存器中,这同时也是ref程序的返回值,因此无须进行更多搬运。
[1] 在LoongArch指令集中,JR指令是JIRL指令rd=0且offs16=0时的别称。
2.6.2 流程控制语句
C语言中的控制流语句共有9种,可分为三类:辅助控制语句、选择语句、循环语句,如表2.11所示。
(1)辅助控制语句
goto语句无条件地跳转到程序中某标号处,其作用与无条件相对跳转指令相同,在LoongArch指令集中表示为B指令跳转到一个标号。break、continue语句的作用与goto类似,只是跳转的标号位置不同。return语句将过程中的变量作为返回值并直接返回,在编译器中对应于返回值写入和返回操作。
(2)选择语句
if~else语句及其对应的LoongArch汇编码如图2.11所示。
表2.11 C语言控制流语句
图2.11 if~else语句及其LoongArch机器表示
这里的if~else实现采用了BEQZ指令,当$t0寄存器的值等于0时进行跳转,跳转到标号.L1执行“else”分支中的操作,当$t0寄存器的值不等于0时,则顺序执行“then”分支中的操作并在完成后无条件跳转到标号.L2处绕开“else”分支。
switch~case语句的结构更为复杂,由于可能的分支数较多,通常会被映射为跳转表的形式,如图2.12所示。如果在编译选项中加入-fno-jump-tables的选项,那么switch~case语句还可以被映射为跳转级联的形式,如图2.13所示。
图2.12 switch~case语句及其跳转表形式的LoongArch机器表示
注①:alsl.d rd,rj,rk,sa所进行的操作是:GR[rd]=(GR[rj]<<sa)+GR[rk]。即将rj号通用寄存器中的值先左移sa位再与rk号通用寄存器中的值相加,结果写入rd号通用寄存器中。
在这个例子中,$t0寄存器存放各case分支的值并依次与第一个参数a(存放在$a0寄存器中)进行比较,根据比较的结果分别跳转到指定标号。读者可自行分析各case分支的执行流。通过比较图2.12和图2.13中的汇编代码可以看到,在case分支较多时,采用跳转表实现有助于减少级联的转移指令。
(3)循环语句
循环语句均可映射为条件跳转指令,与选择语句的区别就在于跳转的目标标号在程序段已执行过的位置(backward)。三种循环语句的C语言及其对应的LoongArch汇编码如图2.14所示。
图2.13 switch~case语句及其跳转级联形式的LoongArch机器表示
图2.14 循环语句及其LoongArch机器表示