提问人:Kolodez 提问时间:10/30/2023 最后编辑:Kolodez 更新时间:10/31/2023 访问量:77
检查 SHL x86 汇编指令是否存在溢出
Checking the SHL x86 assembly instruction for overflow
问:
在指令后检查理论结果(EAX 乘以(2 次方 CL))是否适合 EAX 的简单方法是什么?问题是关于无符号整数的。SHL EAX, CL
我希望在指令的情况下检查进位标志或在指令的情况下检查 EDX。ADD
MUL
答:
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, 1
ADD EAX, EAX
SHL EAX, CL
SHL EAX, 1
JC overflow_occurred
评论
0赞
Peter Cordes
10/31/2023
如果您有多个东西要以相同的班次计数进行班次,您可以重复使用掩码,只需/每个班次,这显然是这种情况的最佳选择。对于单次移位,其他策略可能会更好,也可能更好,因为这可以避免破坏 CL 中的移位计数,并避免在 AMD 上速度较慢。(此外,在某些 CPU 上比 便宜,因为可以在没有移位 ALU 的端口上运行,并且我们希望周围的代码至少再有一个移位。test
jnz overflow
shld
add ebx, ebx
shl ebx, 1
add
评论
test
mul
shld
neg cl
/shr reg,cl
使用原始移位输入的副本将仅保留原始移位的位。因此,ZF=1 意味着没有溢出。(但你需要在第一次班次之前,或者使用 BMI2 进行复制和班次)。或者像 Jester 说的 SHLD 将位转移到归零寄存器中,例如 / / 检查 ZF / 。这在英特尔上可能更快,因为英特尔“只有”4 个 uops,而 AMD 则更多,尤其是在 Zen 3 之前。这仅检查无符号溢出,而不会移出任何设置位。shl
mov edx, eax
shlx
xor edx,edx
shld edx, eax, cl
shl eax, cl
shld reg, reg, cl
dst + 1
dst = 1