3.6 控制
1.条件码
除了算术和逻辑操作会设置条件码以外,cmp和test指令也会设置条件码,但这两个指令不改变任何寄存器的值,注意这两条指令也要反着读,比如 cmp S1,S2 算的是S2-S1
2.访问条件码
1)下面这些指令可以根据条件码设值某一字节的值,可以是寄存器,也可以是内存。
注意setl这个操作,以上一次操作是a-b举例,对于没有溢出的情况,OF=0,SF决定了结果,a>b结果就是正的,SF=0,a<b结果就是负的,SF=1;对于溢出了的情况,分正溢出和负溢出,正溢出是a是正数,b是负数,a-b得了个大数,导致结果正溢出,注意,正溢出时结果是负数,SF=1,那么SF^OF就是1^1=0,a此时是大于b的,所以setl要置0,对于负溢出,a是负数,b是正数,相减得了个特别小的数,导致结果负溢出,注意,负溢出时结果是正数,SF=0,那么SF^OF就是0^1=1,a此时是小于b的,所以setl要置1。
2)下面这些是跳转指令,用以实现分支结构。
跳转可以分两大类,直接跳转和间接跳转,直接跳转是给出一个标号作为跳转目的,间接跳转的跳转目的是由寄存器中的数据或是寄存器中的内存地址的数据给出的。
跳转也可以分有条件跳转和无条件跳转,注意,条件跳转只能是直接跳转
跳转指令的目标的编码使用PC相对地址,它是由本条指令的目标编码加上下一条指令的地址得到的,这是早期处理器的实现导致的,下面这一习题对于理解这一点很有帮助。注意本条指令的目标编码是由十六进制补码给出的,而下一条指令的地址是十六进制无符号数。
3.分支语句的实现
1)用条件控制来实现条件分支,这是传统的方法,这种机制简单而通用,但是在现代的处理器上他可能会变得低效
2)用条件传送来实现条件分支,这种策略只在一些受限的情况下可行,但是他在现代的处理器上更加高效。这与用条件控制来实现的本值区别就在于,条件传送会计算两个分支的结果,最后再根据分支条件来选择最终结果,而如果用条件控制来实现的话,其会先进行条件语句的比较,再计算正确分支的结果。
4.循环的实现
1)do-while
do
body-statement
while(test-expr);
loop:
body-statement
t=test-expr;
if(t)
goto loop;
do-while语句可以写成这样的goto形式
2)while
while(test-expr)
body-statement
goto test;
loop :
body - statement
test :
t = test - expr;
if (t)
goto loop;
这是相应while语句的jump to middle模板
另一种叫做guarded-do,他先测试条件,如果不成立直接结束,如果成立则变成一个do-while循环
t=test-expr;
if(!t)
goto done;
do
body-statement
while(test-expr);
done:
t=test-expr;
if(!t)
goto done;
loop
body-statement
t=test-expr;
if(t)
goto loop;
done:
3)for
for循环可以转化成等价的while循环,就可以套用while循环的模板了。
5.switch语句
switch语句用了一个很优雅的跳转表来实现,具体可以看下面这个例子