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

Checking the SHL x86 assembly instruction for overflow

提问人:Kolodez 提问时间:10/30/2023 最后编辑:Kolodez 更新时间:10/31/2023 访问量:77

问:

在指令后检查理论结果(EAX 乘以(2 次方 CL))是否适合 EAX 的简单方法是什么?问题是关于无符号整数的。SHL EAX, CL

我希望在指令的情况下检查进位标志或在指令的情况下检查 EDX。ADDMUL

程序集 x86 整数溢出

评论

1赞 Jester 10/30/2023
不幸的是,进位仅适用于单位移位。如果计数是常数,则可以用于检查是否设置了任何高阶位。既然你提到了哪个产生双倍宽度的结果,你也可以用它来做类似的事情。testmulshld
2赞 Peter Cordes 10/30/2023
neg cl / shr reg,cl使用原始移位输入的副本将仅保留原始移位的位。因此,ZF=1 意味着没有溢出。(但你需要在第一次班次之前,或者使用 BMI2 进行复制和班次)。或者像 Jester 说的 SHLD 将位转移到归零寄存器中,例如 / / 检查 ZF / 。这在英特尔上可能更快,因为英特尔“只有”4 个 uops,而 AMD 则更多,尤其是在 Zen 3 之前。这仅检查无符号溢出,而不会移出任何设置位。shlmov edx, eaxshlxxor edx,edxshld edx, eax, clshl eax, clshld reg, reg, cl
0赞 Peter Cordes 10/30/2023
如果要检查移出的位是否与 EAX 的新 MSB(有符号溢出)具有相同的值,则情况会有所不同。
0赞 ecm 10/30/2023
“这只会检查无符号溢出,不会移出任何设置位。” @PeterCordes我发现这句话令人困惑。我现在假设它的意思是“这检查无符号溢出”和“这检查我们没有移出任何设置位”,但这里的“不”连接词让我最初在阅读时感到困惑。
1赞 Peter Cordes 10/30/2023
@ecm:你说得对,我应该避免笨拙的措辞。我的意思是它会检查我们是否没有移出任何设置位,这是我们检查无符号溢出所需的。(与有符号相反,从一个小负数的顶部移出设置位不是问题,只要我们移出的所有位彼此相等。比如也许如果只有一个固定位?但这忽略了这种情况,但那位是有符号的溢出。dst + 1dst = 1

答:

2赞 Nate Eldredge 10/31/2023 #1

您不能通过在指令后检查来做到这一点。它不记录有关无符号溢出的信息,即是否有任何 1 位被移出。进位标志仅包含移出的最后一位。

例如,如果 EAX = 0xF0000000 且 CL = 7,则将保留 EAX = 0 并清除进位标志。如果输入为 EAX = 0x00000000,您将获得完全相同的体系结构结果,包括所有其他标志值。因此,即使一个有溢出,另一个没有,事后也无法区分它们。SHL EAX, CL

您可以在指令之前通过检查 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

对于 1-bit shift 指令,则 carry 标志确实指示是否发生无符号溢出。此外,溢出标志指示是否发生有符号溢出。事实上,所有 CF、OF、ZF、SF、PF 的设置都与数学上等效的设置完全相同。因此,如果您要针对空间而不是速度进行优化,那么您可以考虑一个循环,迭代 CL 时间并在每次迭代时执行,然后执行。SHL EAX, 1ADD EAX, EAXSHL EAX, CLSHL EAX, 1JC overflow_occurred

评论

0赞 Peter Cordes 10/31/2023
如果您有多个东西要以相同的班次计数进行班次,您可以重复使用掩码,只需/每个班次,这显然是这种情况的最佳选择。对于单次移位,其他策略可能会更好,也可能更好,因为这可以避免破坏 CL 中的移位计数,并避免在 AMD 上速度较慢。(此外,在某些 CPU 上比 便宜,因为可以在没有移位 ALU 的端口上运行,并且我们希望周围的代码至少再有一个移位。testjnz overflowshldadd ebx, ebxshl ebx, 1add