避免使用条件分支
现代处理器使用了非常尖端的技术来尽可能快的执行代码。一个普遍的技术称为预测执行。这种技术使CPU的并行处理能力来同时执行多条指令。条件分支与这项技术有冲突。一般来说,处理器是不知道分支是否会执行。
一个避免这个问题的方法就是如果可能尽量避免使用条件分支。在计算eax中比特位为1的例子中,一般会用一个分支跳转到INC指令(检查CF标志),下面展示了如何使用ADC指令直接加上进位标志来替代这个分支。
setz al ;AL=如果ZF标志置位了则为1,否则为0
例如,考虑查找两个数的最大数的问题。这个问题的标准解决方法是使用一条CMP指令再使用条件分支对最大值进行操作。下面这个例子展示了不使用分支如何找到最大值。
这个诀窍就是产生一个可以用来选择出正确的最大值的掩码。另外一个可供选择的诀窍是使用DEC指令。在上面的代码中,如果用DEC代替NEG,那么结果同样是0或0xFFFFFFFF。但是,与使用NEG相比,得到值将是反过来的。
一个避免这个问题的方法就是如果可能尽量避免使用条件分支。在计算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.例如mov ecx,32
count_loop:
shl eax,1
adc bl,0
loop count_loop
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
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相比,得到值将是反过来的。