本节书摘来自华章计算机《计算机系统:系统架构与操作系统的高度集成》一书中的第2章,第2.6节,作者:(美)拉姆阿堪德兰(Ramachandran, U.)(美)莱希(Leahy, W. D.)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

2.6 条件语句和循环

在谈论条件语句之前,理解程序执行时的控制流概念是非常重要的。在普通的控制流下,程序是顺序执行的:
image

指令I1执行后紧跟着I2,然后是I3、I4等。我们使用一个专用的寄存器,称为程序计数器(PC)。概念上,我们可以想象PC指向正在执行的指令。我们知道,程序并非总是沿着顺序的控制流路径执行。

2.6.1 if-then-else语句
考虑下面的语句:
image

我们来研究编译上面的语句需要什么。if语句包含两部分:
1)对断言“j == k”求值:这可以通过我们已经说过的表达式求值用的指令来完成。
2)如果断言为真,那么它将控制流从下一条语句改变到目标L1。到目前为止,我们的指令集还无法完成改变控制流的任务。
因此,我们有必要添加这样的新指令,它除了可以对算术和逻辑运算进行求值,还能改变控制流。我们引入这样一条新指令:
image

这条指令的语义如下:
1)比较r1和r2。
2)如果它们相等,那么下一条被执行的指令在地址L1处。
3)如果它们不相等,那么下一条被执行的指令就是紧跟着这条beq指令的指令。
BEQ是用于改变控制流的条件分支指令的一个例子。我们在指令中需要指明分支的目标地址。在描述算术/逻辑运算指令时,我们讨论了可寻址性(见2.4.1节)并认为将操作数放在寄存器而非指令中是一个好方法,因为这样减少了指令用来指明操作数的位数。这很自然地引出了分支指令中目标地址是否需要放在寄存器中而不是作为指令一部分这个问题。也就是说,地址L1应该放在寄存器中吗?一条分支指令通常将控制流从当前指令(即分支指令)带到另一条相距不是很远的指令。我们知道PC指向当前执行的指令,那么分支的目标可以用指令中提供的相对于当前分支指令位置的地址偏移量来表示。鉴于从当前指令到分支目标指令的距离不是太远,所以地址偏移量只需要分支指令中的少数几位来表示。换句话说,用分支指令的一部分作为内存地址(确切地说,地址偏移量)来指定分支目标是合适的。
因此,分支指令的格式如下:
image

这条指令的效果有:

  1. 比较r1和r2。
  2. 如果它们相等,那么下一条被执行的指令的地址为PC+offsetadjusted。
  3. 如果它们不等,那么下一条被执行的指令就是直接跟在beq指令后面的指令。
    我们本质上新增了一种计算有效地址的寻址模式,这被称为程序计数器相对寻址。

指令集体系结构对于条件分支语句可能有不同的喜好,例如BNE(不等时跳转)、BZ(为零时跳转),以及BN(为负时跳转)。
经常的情况是,在条件语句中会有一个else分句。
image
image

事实证明我们编译上面的代码不需要在体系结构中新增任何指令。条件分支指令非常有效地处理了上面的if语句有关的计算和分支。然而,当if分句的部分被执行完之后,控制流需要无条件地转移到L1(紧接着else分句的语句块的开头)。
为了能够这么做,我们引入“无条件跳转”语句
image

这里的rtarget包含了无条件跳转的目标地址。
对无条件跳转指令的需求需要详细的阐述,毕竟我们已经有了条件分支指令了。无论如何,我们可以通过条件分支指令beq来实现无条件分支。当beq指令的两个操作数使用同一个寄存器时(即beq r1,r1,offset),结果就是无条件跳转。然而,这里有一个迷惑人的地方。条件分支指令的范围受到偏移量大小的制约。比如,一个8位的偏移量(假设偏移量使用补码表示,这样正负偏移量都可以表示),那么分支的范围被限制在PC–128~PC+127。这正是引入新的无条件跳转指令的原因,在这样的指令中,使用一个寄存器来表示跳转的目的地址。
读者应该可以明显感觉到,使用条件和无条件分支,我们可以编译任意多层级的嵌套if-then-else语句。
2.6.2 switch语句
许多高级语言提供了特殊的条件语句,以C语言的switch语句为代表。
image

如果case的数量有限或者比较稀疏,最好的方法就是将这个语句编译为多个if-then-else语句结构。另一方面,如果有很多连续的、不稀疏的case,那么将它们编译为嵌套的if-then-else语句就会生成低效的代码。另一种选择是,使用一个跳转表记录所有case代码段的起始地址,这样就能产生高效的代码(见图2-6)。
image

图2-6 使用跳转表实现switch语句。表中的每一项指向与case值对应的第一条指令
原则上,完成这样的实现不需要新的指令。虽然不需要往指令集体系结构中添加新的指令以支持switch语句,但让无条件跳转语句支持一级的间接寻址会有很大好处。
这就是
image

这里的rtarget包含了(无条件)跳转的目标地址。
另外,一些体系结构提供了专用的指令用于边界检查。例如,MIPS体系结构提供了一个若不大于则置位(set-on-less-than)指令。
image

它的效果是
image

这条指令对于实现switch语句时的边界检查是非常有用的。
2.6.3 循环语句
高级语言提供了不同形式的循环结构。考虑如下代码片段
image

假设寄存器r1用于保存变量j,而寄存器r2中包含值100,我们可以按下面的方式编译前面的循环结构:
image

因此,不需要新指令或寻址模式去支持上述循环结构。读者应该能明显感觉到,其他一切形式的循环(如for、while、repeat等)都能用已经介绍过的条件和无条件分支指令类似地编译。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐