所以你想做一个 16 位移位,但从低半部分的顶部设置 CF?我不知道你为什么想要那个,特别是如果你打算jnc
而不是使用adc cl, 0
CL += CF。
有更有效的方法来弹出寄存器的高半字节,例如复制寄存器并实际将位移出而不是仅仅使用寄存器。或者popcnt
在隔离寄存器中的这些位之后使用指令,如果你可以假设一个现代 CPU。
无论如何,没有一条指令可以做到这一点,但是有几个选项可以根据您的需要设置 CF,具体取决于您需要的 CPU 兼容性。最直接的就是:
;; 386 for BT/BTS
shl ax, 1
bt ax, 8 ; set CF from the bit that was previously the top of AL
adc cl, 0 ; CL += CF
还有一种方式在旧 CPU 上可能很慢:x86 移位/旋转用&31
(或&63
64 位移位)掩盖计数,因此小于 32 位的移位/旋转可以使用与操作数大小一样大的计数并拥有它不计为 0。
rol
根据从高到低“环绕”的最后一位设置 CF。8 位寄存器的计数为 8 时保持不变,最后一位旋转为低位。此外,286 之前的 CPU 无论如何都不会屏蔽计数,它们只需要与移位计数一样多的时钟周期。(因此,在没有用于恒定时间旋转的桶形移位器的旧 CPU 上,这非常慢。)
或者如果手册的 Operation 部分反映了实际的 286 实现,mod size
则为实际的移位工作而旋转,但count != 0
检查它是否设置了 FLAGS 是基于count & 1Fh
not count mod 8
。如果确实如此,CF = LSB(dest)
;; 186 for immediate-count shifts/rotates
shl ax, 1
rol ah, 8 ; set CF from the bit that was previously the top of AL
adc cl, 0 ; CL += CF
显然,根据特定位设置 ZF 更容易,例如
add ax, ax ; AX <<= 1
test ah, 1 ; ZF = low bit of AH
;test ax, 1<<8 ; ZF = low bit of AH same code size, actually
jz no_increment
inc cl
no_increment:
但是分支很糟糕adc
。
请注意,shl
by 1 基本上没有任何优势,除非您可以将其与注册目标一起使用。add ax,ax
在某些 CPU 上,使用左移更有效。它甚至以相同的方式设置 CF(根据之前的最高位)。