条件传送和条件转移
v = test-expr ? then-expr : else-expr; |
- 条件转移:
当条件满足时,程序沿着一条执行路径进行,而当条件不满足时,就走另一条路径。
if (!test-expr) goto false; v = true-expr; goto done; false: v = else-expr; done:
|
- 条件传送:
基于条件传送的代码,会对 then-expr else-expr 都求值,最终值的选择基于对 est-expr 的求值。只有当测试条件满足时,vt的值才会被复制到v中。
vt = then-expr; v = else-expr; t = test-expr; if (t) v = vt; |
会根据条件码的值,选择要么什么都不做,要么将一个值复制到一个寄存器。
int absdiff(int x, int y) { return x < y? y-x: x-y; } |
|
movl 8(%ebp), %ecx movl 12(%ebp), %edx movl %edx.,%ebx subl %ecx, %ebx movl %ecx, %eax subl %ed.x, %eax cmpl %ed.x, %eax cmovl %ebx, %eax |
ecx= y edx= .x ebx=x y-x y eax= x-y Compare x:y If <, eax= y--x
|
Compare:
1.基于条件数据传送的代码比基于条件控制转移的代码性能好。
①处理器通过使用流水线来获得高性能。在流水线中,一条指令的处理要经过一系列的阶段,每个阶段执行所需操作的一小部分。
②通过重叠连续指令的步骤来获得高性能,例如,在取一条指令的时候,执行它前面一条指令的算术运算。要做到这一点,要求能够事先确定要执行指令的序列,这样才能保持流水线中充满了待执行的指令。
③处理器采用非常精密的分支预测逻辑试图猜测每条跳转指令是否会执行。只要它的猜测还比较可靠(现代微处理器设计试图达到 90% 以上的成功率),指令流水线中就会充满着指令。
④错误预测一个跳转要求处理器丢掉它为该跳转指令后所有指令已经做了的工作, 然后再开始用从正确位置处起始的指令去填充流水线。
2.条件传送的弊端:
①如果这两个表达式中的任意一个可能产生错误条件或者副作用,就会导致非法的行为。
int cread(int *xp) { return (xp? *Xp: 0); } |
Xp==0时间接引用了空指针
int lcount = O; int absdiff_se(int x, int y) { return x < y? (lcount++, y-x) : x-y; } |
这个函数在then-expre 中会对全局变量lcount 加一。因此,必须用分支代码来保证只有当 测试条件满足时才会产生这个副作用。
②如果 then-expr 或者 else-expr 的求 值需要大量的计算,那么当相对应的条件不满足时,这些工作就白费了。编译器不知道分支遵循可预测的模式有多好。只有当两个表达式都很容易计算时,它才使用条件传送。