高效的装配检查多个位

时间:2014-01-24 19:10:18

标签: assembly logic bit

我在AX中有一些价值,需要一次检查多个位。 假设我想检查第一位和最后一位,其他位是DC值。 我做了什么,但是因为我为不同的值多次检查它是如此低效。

AND AX,8001H
CMP AX,8001H
JE

我已经考虑过基于奇偶校验的ANDing和跳转,但是使用MASM,奇偶校验仅用于前8位......

2 个答案:

答案 0 :(得分:2)

要测试两个位是否都已设置,我担心你总是需要两条指令(不包括条件跳转)。你自己的方法需要6个字节:

25 01 80          AND   AX,8001H
3D 01 80          CMP   AX,8001H

您可以使用NOT保存一个字节;它反转所有位(使CMP不必要),并且它只有2个字节。

F7 D0             NOT   AX
25 01 80          AND   AX,8001H

如果指令处于循环执行多次,你有一个备用寄存器,那么你可以保存另一个字节。代码的总量更多,但是因为你可以将它的一部分保留在循环之外,所以它应该稍快一点。

BB 01 80          MOV   BX,8001H   ; keep this outside the loop
...               ...
F7 D0             NOT   AX
21 D8             AND   AX,BX

修改 改善的最后一种可能性。如果您总是测试 set 中的一个或多个位,那么您可能希望在整个函数中翻转零和1的含义,甚至可能在整个程序中。没有法律禁止将零定义为真,一个定义为假。 (在数字电路中,你实际上看到了很多。)然后你可以删除NOT AX,再节省两个字节。更重要的是,您可以使用非破坏性AND替换TEST,从而无需保存和恢复AX即可执行多项测试。为了判断在您的特定情况下这是否可行,我将不得不看到更多的代码。

答案 1 :(得分:2)

总的来说,我认为Ruud正在走上正轨。但是,如果您正在为最近(例如Haswell)支持新Bit Manipulation Instructions(BMI1,BMI2,也见Intel Manuals)的CPU编码,那么 - 根据代码上下文 - 这些新指令中的一些可能是有帮助的。

特别是假设您的Mask = 8001h现在有ANDN指令可以像这样使用(如Ruud的回答):

andn eax, eax, Mask ; Mask can be reg32 or mem32
jz ... 

在某些情况下,PEXT也可能有用:

pext DEST, eax, Mask    ; Mask can be in reg32 or mem32 / DEST is a reg32
    ; Mask ... 10000000 00000001b = 8001h
    ; EAX  ... Yyyyyyyy xxxxxxxXb
    ; DEST ... 00000000 000000YXb
    ; Flags NOT affected!
cmp DEST, 11b
je ...

免责声明:我这里没有Haswell CPU,所以上面的代码是基于阅读英特尔文档

的推测