避免使用条件分支

现代处理器使用了非常尖端的技术来尽可能快的执行代码。一个普遍的技术称为预测执行。这种技术使CPU的并行处理能力来同时执行多条指令。条件分支与这项技术有冲突。一般来说,处理器是不知道分支是否会执行。
一个避免这个问题的方法就是如果可能尽量避免使用条件分支。在计算eax中比特位为1的例子中,一般会用一个分支跳转到INC指令(检查CF标志),下面展示了如何使用ADC指令直接加上进位标志来替代这个分支。
    mov bl,0
    
mov ecx,32
count_loop:
    
shl eax,1
    
adc bl,0
    loop count_loop
Setxx指令提供了在一定情况下替换条件分支的方法。基于FLAGS寄存器的状态,这些指令将一个字节的寄存器或内存空间的值置为0或1.在SET后的字符与条件分支使用的是一样的。如果SETxx条件为真,那么储存的结果就是1,如果为假,则储存的结果就为0.例如
setz al   ;AL=如果ZF标志置位了则为1,否则为0
例如,考虑查找两个数的最大数的问题。这个问题的标准解决方法是使用一条CMP指令再使用条件分支对最大值进行操作。下面这个例子展示了不使用分支如何找到最大值。
%include "asm_io.inc"

segment .data
message1    db    
"Enter a number: ",0
message2    db    
"Enter another number: ",0
message3    db    
"The larger number is: ",0

segment .bss
input1    resd    
1

segment .text
    global _asm_main
_asm_main:
    
enter 0,0
    
pusha

    
mov eax,message1
    
call print_string
    
call read_int
    
mov [input1],eax

    
mov eax,message2
    
call print_string
    
call print_nl

    
xor ebx,ebx
    
cmp eax,[input1]
    
setg bl        ;ebx=(input2>input1)?1:0
    neg ebx        ;ebx=(input2>input1)?0xFFFFFFFF:0
    mov ecx,ebx    ;ecx=(input2>input1)?0xFFFFFFFF;0
    and ecx,eax    ;ecx=(input2>input1)?input2:0
    not ebx        ;ebx=(input2>input1)?0:0xFFFFFFFF
    and ebx,[input1];ebx=(input2>input1)?0:input1
    or ecx,ebx    ;ecx=(input2>input1)?input2:input1

    
mov eax,message3
    
call print_string
    
mov eax,ecx
    
call print_int
    
call print_nl

    
popa
    
mov eax,0
    
leave
    
ret

这个诀窍就是产生一个可以用来选择出正确的最大值的掩码。另外一个可供选择的诀窍是使用DEC指令。在上面的代码中,如果用DEC代替NEG,那么结果同样是0或0xFFFFFFFF。但是,与使用NEG相比,得到值将是反过来的。

posted on 2008-02-28 10:55  woodfish  阅读(428)  评论(0编辑  收藏  举报

导航