Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 7f0e351

Browse files
committed
Fix overflow checking when multiplying two i64
Fixes rust-lang#1162
1 parent 6d6c574 commit 7f0e351

File tree

2 files changed

+12
-7
lines changed

2 files changed

+12
-7
lines changed

example/std_example.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ fn main() {
4848
assert_eq!(2.3f32.copysign(-1.0), -2.3f32);
4949
println!("{}", 2.3f32.powf(2.0));
5050

51+
assert_eq!(i64::MAX.checked_mul(2), None);
52+
5153
assert_eq!(-128i8, (-128i8).saturating_sub(1));
5254
assert_eq!(127i8, 127i8.saturating_sub(-128));
5355
assert_eq!(-128i8, (-128i8).saturating_add(-128));

src/num.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -271,14 +271,17 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
271271
let val_hi = fx.bcx.ins().umulhi(lhs, rhs);
272272
fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0)
273273
} else {
274+
// Based on LLVM's instruction sequence for compiling
275+
// a.checked_mul(b).is_some() to riscv64gc:
276+
// mulh a2, a0, a1
277+
// mul a0, a0, a1
278+
// srai a0, a0, 63
279+
// xor a0, a0, a2
280+
// snez a0, a0
274281
let val_hi = fx.bcx.ins().smulhi(lhs, rhs);
275-
let not_all_zero = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0);
276-
let not_all_ones = fx.bcx.ins().icmp_imm(
277-
IntCC::NotEqual,
278-
val_hi,
279-
u64::try_from((1u128 << ty.bits()) - 1).unwrap() as i64,
280-
);
281-
fx.bcx.ins().band(not_all_zero, not_all_ones)
282+
let val_sign = fx.bcx.ins().sshr_imm(val, i64::from(ty.bits() - 1));
283+
let xor = fx.bcx.ins().bxor(val_hi, val_sign);
284+
fx.bcx.ins().icmp_imm(IntCC::NotEqual, xor, 0)
282285
};
283286
(val, has_overflow)
284287
}

0 commit comments

Comments
 (0)