我在AX中有一些价值,需要一次检查多个位。 假设我想检查第一位和最后一位,其他位是DC值。 我做了什么,但是因为我为不同的值多次检查它是如此低效。
AND AX,8001H
CMP AX,8001H
JE
我已经考虑过基于奇偶校验的ANDing和跳转,但是使用MASM,奇偶校验仅用于前8位......
答案 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,所以上面的代码是基于阅读英特尔文档
的推测