总结自《深入理解计算机系统》第三版
条件码和条件指令
CPU还维护一组单个位的条件码寄存器,用来描述最近的算术和逻辑操作的属性。常用
CF:无符号溢出
OF:有符号溢出
ZF:零标志
SF:符号标志
注意:
- leaq不改变任何条件码,只用于地址计算
- 逻辑操作,会使进位标志和溢出标志设置为0
- 移位操作,进位标志设置为最近移除的位,溢出标志为0
- INC和DEC,作用于有符号数,设置溢出位和零标志,不改变进位标志
CMP指令和TEST指令
TEST指令与AND指令一样,而不改变dest寄存器
用法:两个操作数是一样的,例如testq %rax,%rax用来检测%rax是负数、零、正数
假设temp=test %rax,%rax
- 得到temp的同时,最高位赋给SF,判别正负
- 若temp=0,则ZF=1,判断为零
SET指令
SET指令的目的操作数是低位单字节寄存器,或是一个字节的内存位置(指令将这个字节设置为0或1,为得到32或64位结果,将高位清零)
机器代码对于有符号和无符号两种情况都使用一样的指令,许多算术运算对于无符号和补码算术有一样的位级操作。对于右移、除法、乘法和不同的条件码组合需使用的不同的版本。
跳转指令
两种指令
- 目的地用一个标号(label)指明
jmp .L1 - 目的地为寄存器
jmp *%rax
jmp *(%rax)
PC-relative编码
将目标指令的地址与紧跟在跳转指令后面那条指令的地址之间的差作为编码。
还有一种编码方式是给出绝对地址,用4字节直接指定目标,汇编器和链接器会选择适当编码。
movq %rdi,%rax
jmp .L2
.L3:
sarq %rax
.L2:
testq %rax,%rax
jg .L3
rep;ret
汇编产生“.o”格式反汇编版本
0: 48 89 f8 ;mov %rdi,%rax
3: eb 03 ;jmp 8<loop+0x8>
5: 48 d1 f8 ;sar %rax
8: 48 85 c0 ;test %rax,%rax
b: 7f f8 ;jg 5<loop+0x5>
d: f3 c3 ;repz retq
第二行的跳转目标是0x8,指令中的字节编码为0x03,它与第三行地址0x5相加为0x8,,第5行跳转目标是0x5,指令中的字节编码为0xf8(十进制-8)
注意:程序计数器的值是跳转指令后面的那条指令,而不是跳转指令本身地址。
使用PC-relative寻址好处
- 指令编码简洁
- 当指令被重定位到不同的地址时,跳转目标的编码不需要改变。
条件分支
C语言的if-else语句
if(test-expr)
then-statement
else
else-statement
汇编形式
t-test-expr;
if(!t)
goto false;
then-statement
goto done;
false:
else-statement
done:
用条件传送实现条件分支
控制的条件转移,当条件满足时,程序沿着一条路径,不满足时,条件沿着另一条路径,在现代处理器上很低效。
处理器通过流水线(pipelining)获得高性能,流水线中一条指令的处理经过一系列阶段,每个阶段执行所需操作的一部分(例如,从内存取指令,确定指令类型,从内存读数据,执行算术运算,向内存写数据,更新程序计数器),通过重叠连续指令的步骤获得高性能。这要保证能过事先确定要执行的指令序列,保证流水线里充满了待执行的指令。而条件跳转,需要分支条件求值后才能决定路径。处理器会采用分支预测逻辑猜测指令路径。错误的预测跳转,要求处理器丢掉之前的指令,再用正确的位置填充流水线,大约15~30个时钟周期。
条件传送指令
处理器无需预测测试结果就可以执行条件传送,处理器读源值,检查条件码,看是否需要更新目的寄存器。
C语言形式
v=test-expr?then-expr:else-expr;
条件传送形式
v=then-expr;
ve=else-expr;
t=test-expr;
if(!t) v=ve;
例子
存在的问题
- 当表达式存在副作用是不能用条件传送语句。
- 条件传送并不总是提高代码效率,即当v和ve的计算量较大时。编译器需考虑浪费计算和分支预测错误的相对性能。只有当表达式容易计算时才会使用条件传送。
循环
do-while循环
do
body-statement
while(test-expr);
汇编形式
loop:
body-statement
t=test-expr;
if(t)
goto loop;
while循环
while(test-expr)
body-statement
汇编形式
goto test;
loop:
body-statement
test:
t=test-expr;
if(t)
gpto loop;
switch语句
考官语句通过整数索引值进行多重分支,使用跳转表(地址数组),表项i是一个代码段的地址,这个代码段的实现相当于开关索引值等于i时程序的路径。这里直接给出书上的例子。