分支指令可以改变程序计数器原有的顺序执行模式,从而实现程序中的for,while,if else等指令。分支指令分为条件分支与无条件分支。
MIPS有两条条件分支指令,一条为bne,一条为beq。bne在所给的两个寄存器操作数不相等时执行跳转。beq在所给的两个寄存器操作数相等时执行跳转。方便记忆,我把bne看作branch not equal,beq看作branch equal。
addi $s2, $0, 2
addi $s3, $0, 3
bne $s2, $s3, target
add $s1, $s2, $s3
target:
addi $s2, $s2, 1
target所在位置的操作数称为标号(label)。这里,由于$s3
与$s2
不相等,故执行跳转,继而执行addi $s2, $s2, 1
指令,也就是label后的指令。若相等,则会顺序执行add $s1, $s2, $s3
指令。
汇编代码使用标号来说明程序中指令位置,也就是上段示例中的target:
。当汇编语言翻译为机器代码时,标号会被翻译为地址。常常会不缩进标号,从而达到突出作用。
条件分支指令是if else,switch case,while,for等语句的汇编语言表示中的一部分,用于判断条件是否满足并执行相应跳转。
设a在$s0
中,b在$s1
中。
如果C语言代码为
if (a == b) {
语句1;
}
//这里是汇编语言中标号位置所在
语句2;
其相应的汇编语言指令为
bne $s0, $s1, 标号
;
如果$s0
不等于$s1
,则跳转到语句2,如果相等,则顺序执行语句1。
如果条件为a != b
,那么会用到beq指令。可以看到对于if语句,汇编语言中的判断相等还是不相等与高级程序语言中的相反。因为当执行if后大括号内语句时,实际上是在顺序执行,反而当跳过这些语句时,执行了跳转。
如果C语言代码为
if (a == b) {
语句1;
}
else {//标号1
语句2;
}
//标号2
那么在汇编代码中,除了有与上一个if示例中指令相同的指令,语句1之后会有一个无条件分支指令j,负责在执行完语句1之后跳转到标号2所在位置。
如果这些语句的判别条件是a < b
,其中a在$s0
中,b在$s1
中,则会先执行a和b的小于设置指令slt(slt是R-类型指令,当rs小于rt,rd置为1,否则rd置为0),再以slt指令的目的寄存器与保存1的寄存器进行bne指令。
设a在$s0
中。
如果C语言代码为
switch (a){
case 1: 语句1; break;
//标号1
case 2: 语句2; break;
//标号2
default: 语句3;
}
//标号3
那么在汇编代码中
addi $t0, $0, 1
bne $s0, $t0, 标号1
语句1对应指令
j 标号3
addi $t0, $0, 2
bne $s0, $t0, 标号2
语句2对应指令
j 标号3
语句3对应指令
当判断是否还要继续进行循环时,将在循环语句末尾使用bne与beq进行判断,如果条件满足,跳转到循环语句开头,不满足则顺序执行接下来的语句,跳出循环。对于for语句,initialization会放在最开始标号之前的位置,loop operation会放在最末尾跳转指令之前的位置。
无条件分支又称跳转指令。MIPS中的无条件分支指令有三种:跳转指令j, 跳转链接指令jal,寄存器跳转指令jr。
指令j直接跳转到标号所在位置。
j target
jr会跳转到它的寄存器操作数所保存的地址,从该地址执行指令。
jr $s0
jal也执行跳转,与j类似,但会保存一个返回位置,与过程调用相关。这里书中还未详解,将在过程调用章节进行学习。