Multiplication on x86/x64 never overflows when using the one operand form.
This is because mul and its sibling imul produce an output twice as wide as their operands1.
In your example, multiplying by al
produces an output in ax
and no overflow is generated.
The CF
and OF
当结果无法适合操作数大小时设置。
这可用于执行饱和乘法,例如:
;Unsigned
mul ebx
sbb edx, edx ;EDX = CF replicated along all the 32 bits
or eax, edx ;EAX = 0ff..ffh if overflow, EAX*EBX otherwise
;Signed (perhaps not the most efficient way)
imul ebx
cmovc eax, 7fffffffh ;Signed positive max if overflow. (CMOV-immediate doesn't really exist, but imagine register sources)
cmovnc edx, 0 ; don't modify EAX for the non-overflow case.
sar edx, 31 ; EDX = all-ones if overflow && negative
xor eax, edx ; if negative && overflow
; flip 7fffffff (INT_MIN) to 80000000 (INT_MIN)
; else xor with 0 is a no-op
(当前的 Rust 编译器还实现a.saturating_mul(b)
对于 i32 和 i64,使用 imul 中的标志,但设置不同:https://rust.godbolt.org/z/ab3jMjzbv)
However to implement a multi-precision multiplication, say 64x64-bit, those flags are not needed, in fact, denoting with 232 with k we have:
(a·k+b) × (c·k+d) = a·c·k2 + (a·d+b·c)·k + b·d
其中 32 位产品产生 64 位结果,添加如下
.----.----.
| b·d |
'----'----'
+
.----.----.
| a·d+b·c |
'----'----'
+
.----.----.
| a·c |
'----'----'
=
.----.----.----.----.
| 128-bit result |
'----'----'----'----'
1 And this suffices to prevent overflow.