Closed evmar closed 1 month ago
I think what's saying is that for a like 16-bit mul, you multiply into 32 bits, then compare if truncating it matters.
let x = ... as i16;
let y = ... as i16;
let widened = (x as i32).wrapping_mul(y as i32);
let result = widened as i16;
let set_flags = widened != result;
I've been experimenting with getting code that complies to the imul
instruction, and I think it's really cool that this does!
With that, I've managed to land in the following:
fn imul_trunc<I: SignedInt>(x: I, y: I, flags: &mut Flags) -> I {
let wide = x.widen() * y.widen();
let flag = x.checked_mul(&y).is_none();
flags.set(Flags::OF, flag);
flags.set(Flags::CF, flag);
I::from_wide(wide)
}
Which still compiles to just calling imul
🤩 Godbolt link
There are 4 TODOs here in imul, that we need to set flags: https://github.com/evmar/retrowin32/blob/b998e571ba9e31b4cc95e18f091376cb8372a9fb/x86/src/ops/math.rs#L787-L814
https://www.felixcloutier.com/x86/imul says:
I think what this means is that CF/OF should just be cleared in the first three of those impls (because there is no truncation). imul_trunc should instead ... do something smart once I understand the first sentence of that quote.