检查SHL x86汇编指令是否溢出

3
有没有一种简单的方法可以在执行完SHL EAX, CL指令后检查理论结果(EAX乘以(2的CL次方))是否适合EAX?这个问题是关于无符号整数的。
我希望有类似于在ADD指令中检查进位标志或在MUL指令中检查EDX的方法。

1
很遗憾,进位(carry)只对单个位移有用。如果计数是恒定的,您可以使用“test”来检查是否设置了任何高位。由于您提到了产生双宽度结果的“mul”,您还可以使用“shld”来实现类似的功能。 - undefined
2
neg cl / shr reg,cl 与原始的 shl 一起使用,将保留原始 shl 移出的位。因此,如果 ZF=1,则表示没有溢出。(但是在第一次移位之前,您需要 mov edx, eax,或者使用BMI2 shlx 进行复制和移位)。或者像Jester所说的那样,使用SHLD将位移入一个清零的寄存器,例如 xor edx,edx / shld edx, eax, cl / 检查 ZF / shl eax, cl。在Intel上可能更快,因为 shld reg, reg, cl 只需 4 个微操作,而在AMD上,尤其是在Zen 3之前,可能需要更多。这只检查无符号溢出,而不是移出任何设置的位。 - undefined
如果你想要检查所有位移出的位与EAX的新MSB(有符号溢出)具有相同的值,那就不同了。 - undefined
这只检查无符号溢出,而不检查是否移出了任何已设置的位。@PeterCordes 我发现这行代码有点令人困惑。我现在理解它的意思是“这检查无符号溢出”和“这检查我们没有移出任何已设置的位”,但是这里的“不”连接词让我一开始读起来感到混乱。 - undefined
1
@ecm: 你说得对,我应该避免使用笨拙的措辞。我的意思是它检查我们是否移除了任何已设置的位,这是我们用于检查无符号溢出的必要条件。(与有符号溢出相反,从小的负数的顶部移除已设置的位并不是一个问题,只要我们移除的所有位都相等。比如,如果dst + 1恰好有一个已设置的位呢?但这会忽略dst = 1但该位是有符号溢出的情况。) - undefined
1个回答

2
你不能通过在指令之后进行检查来完成这个操作。它不会记录关于无符号溢出的信息,即是否有任何1位被移出。进位标志只包含最后一个被移出的位。
例如,如果EAX = 0xF0000000,CL = 7,那么SHL EAX, CL将使EAX = 0,进位标志清零。如果输入是EAX = 0x00000000,你将得到完全相同的体系结构结果,包括所有其他标志值。所以即使一个有溢出,另一个没有,事后也无法区分它们。
你可以在指令之前测试是否会溢出,通过检查EAX的前CL位是否为零。例如(未经测试):
    MOV    EBX, 0x80000000
    SAR    EBX, CL    ; now top CL+1 bits of EBX are 1
    SHL    EBX, 1     ; now top CL bits of EBX are 1
    TEST   EBX, EAX   ; mask off all lower bits
    JNZ    will_overflow

一些其他可能的算法(也许更好)在评论中被提出,比如SHLD
只是因为我碰巧在思考这个问题,这里有一个检查有符号溢出的方法,只有当前CL+1位的最高位不全相等时才会发生。
    MOV    EBX, 0x80000000
    SAR    EBX, CL      ; now top CL+1 bits of EBX are 1
    MOV    EDX, EAX     ; copy the input to be shifted
    AND    EDX, EBX     ; mask off all but top CL+1 bits
    JZ     no_overflow  ; top bits all 0
    CMP    EDX, EBX     
    JE     no_overflow  ; top bits all 1
    ; else handle overflow

对于一位移指令SHL EAX, 1,进位标志确切地指示无符号溢出是否发生。同时,溢出标志指示是否发生了有符号溢出。实际上,CF、OF、ZF、SF、PF这些标志的设置与数学上等效的ADD EAX, EAX完全相同。因此,如果您更注重节省空间而不是速度,那么您可以考虑使用循环,迭代CL次并在每次迭代中执行SHL EAX, 1,然后跟随JC overflow_occurred

如果您有多个要移位的事物,并且移位计数相同,您可以重复使用掩码,只需使用test/jnz overflow进行每次移位,这是显而易见的最佳选择。对于单个移位,其他策略可能更好或不好,因为它避免了破坏CL中的移位计数,并且避免了在AMD上速度较慢的shld指令。(此外,对于某些CPU而言,add ebx, ebxshl ebx, 1更便宜,因为add指令可以在没有移位算术逻辑单元的端口上运行,而我们预计周围的代码至少还有一个移位操作。) - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接