x86程序集:无溢出和分支的ADD / SUB / INC / DEC

x86 assembly: ADD/SUB/INC/DEC without overflow and branching

在x86 ASM中,是否可以在不分支的情况下进行加法或减法来禁止溢出?因此,例如,从0x01减去0x02时,它将设置为0x00而不是0xFF。

我希望这可能是不可能的,所以我也想回答这个问题的一种更严格的形式,其中仅添加/减去0x01。我有个想法(OF是溢出标志):

1
2
dec eax
add eax,OF

我不了解其他体系结构,但是对于i386,我无法为此找到操作码,因为显然标记不能解释为整数,不能用于算术运算。我找到了一个有效的解决方案,但仅当未使用较高字节时才对最低字节进行处理:

1
2
3
dec ax
sub al,ah
xor ah,ah

是否有更好的方法可以做到这一点,也许这也适用于更一般的情况?


在加1的情况下(使用add #1,而不是inc),之后可以仅sbc #0即可实现饱和。同样,对于递减1:使用sub #1,然后使用adc #0

或者考虑使用SSE,它支持在单个指令中使用饱和整数算术运算。


您可以在较新的处理器上使用cmov(条件MOV)指令集,以避免在很多情况下分支,包括您描述的示例。如果正确设置了标志值,则这些指令的行为类似于常规的mov,否则不执行任何操作。

请参阅http://www.jaist.ac.jp/iscenter-new/mpc/altix/altixdata/opt/intel/vtune/doc/users_guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/mergedProjects/instructions/instruct32_hh/ vc35.htm

但是:

I had an idea that goes like this (OF being the overflow flag)

这不是您想要的溢出标志;表示该值溢出了使用2的补码可表示的范围(因此对于16位字值,如果该值小于-32768或大于32767,则溢出)。您似乎正在使用无符号数字(并且希望钳位为0),所以您需要的是进位标志。

例如,如果有进位(例如,结果从0到0xFFpackage),则可以使用CMOVC加载新值。

1
2
3
sub ax, 1
xor bx, bx
cmovc ax, bx

这在减去任何值时有效。但是,事实证明,如果您只想递减,则有一种更简单的方法。您可以减去1,然后使用精确执行以下操作的指令加0进位:

1
2
sub ax, 1
adc ax, 0

请注意,您不能使用dec指令替代sub,因为dec不会影响进位标志。

使用其他方式(加法),可以使用sbb代替adc(当然也可以使用add代替sub)。对于一般情况,您可以执行以下操作:

1
2
3
add ax, 1
mov bx, 0FFFFh
cmovc ax, bx