Skip to content

Commit 5f54cc7

Browse files
committed
Implement checked_mul
Fixes rust-lang#6
1 parent 177348f commit 5f54cc7

File tree

4 files changed

+60
-51
lines changed

4 files changed

+60
-51
lines changed

Readme.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,6 @@ function jit_calc() {
6767
## Not yet supported
6868

6969
* Good non-rust abi support ([several problems](https://github.com/bjorn3/rustc_codegen_cranelift/issues/10))
70-
* Checked binops ([some missing instructions in cranelift](https://github.com/bytecodealliance/wasmtime/issues/1044))
70+
* Proc macros
7171
* Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041), not coming soon)
7272
* SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), some basic things work)

example/std_example.rs

+23
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ fn main() {
8787
panic!();
8888
}
8989

90+
test_checked_mul();
91+
9092
let _a = 1u32 << 2u8;
9193

9294
let empty: [i32; 0] = [];
@@ -258,6 +260,27 @@ unsafe fn test_mm_extract_epi8() {
258260
assert_eq!(r2, 3);
259261
}
260262

263+
fn test_checked_mul() {
264+
let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
265+
assert_eq!(u, None);
266+
267+
assert_eq!(1u8.checked_mul(255u8), Some(255u8));
268+
assert_eq!(255u8.checked_mul(255u8), None);
269+
assert_eq!(1i8.checked_mul(127i8), Some(127i8));
270+
assert_eq!(127i8.checked_mul(127i8), None);
271+
assert_eq!((-1i8).checked_mul(-127i8), Some(127i8));
272+
assert_eq!(1i8.checked_mul(-128i8), Some(-128i8));
273+
assert_eq!((-128i8).checked_mul(-128i8), None);
274+
275+
assert_eq!(1u64.checked_mul(u64::max_value()), Some(u64::max_value()));
276+
assert_eq!(u64::max_value().checked_mul(u64::max_value()), None);
277+
assert_eq!(1i64.checked_mul(i64::max_value()), Some(i64::max_value()));
278+
assert_eq!(i64::max_value().checked_mul(i64::max_value()), None);
279+
assert_eq!((-1i64).checked_mul(i64::min_value() + 1), Some(i64::max_value()));
280+
assert_eq!(1i64.checked_mul(i64::min_value()), Some(i64::min_value()));
281+
assert_eq!(i64::min_value().checked_mul(i64::min_value()), None);
282+
}
283+
261284
#[derive(PartialEq)]
262285
enum LoopState {
263286
Continue(()),

patches/0023-core-Ignore-failing-tests.patch

-40
Original file line numberDiff line numberDiff line change
@@ -30,38 +30,10 @@ index 4bc44e9..8e3c7a4 100644
3030

3131
#[test]
3232
fn empty_array_is_always_default() {
33-
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
34-
index c9096b7..be37fcd 100644
35-
--- a/src/libcore/tests/iter.rs
36-
+++ b/src/libcore/tests/iter.rs
37-
@@ -342,6 +342,7 @@ fn test_iterator_step_by_nth() {
38-
}
39-
40-
#[test]
41-
+#[ignore] // checked_mul impl not yet checking for overflow
42-
fn test_iterator_step_by_nth_overflow() {
43-
#[cfg(target_pointer_width = "8")]
44-
type Bigger = u16;
45-
@@ -2305,6 +2308,7 @@ fn test_repeat_with_take_collect() {
46-
}
47-
48-
#[test]
49-
+#[ignore] // checked_mul impl not yet checking for overflow
50-
fn test_successors() {
51-
let mut powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10));
52-
assert_eq!(powers_of_10.by_ref().collect::<Vec<_>>(), &[1, 10, 100, 1_000, 10_000]);
5333
diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs
5434
index a17c094..5bb11d2 100644
5535
--- a/src/libcore/tests/num/mod.rs
5636
+++ b/src/libcore/tests/num/mod.rs
57-
@@ -63,6 +63,7 @@ pub fn test_num<T>(ten: T, two: T) where
58-
}
59-
60-
#[test]
61-
+#[ignore] // checked_mul impl not yet checking for overflow
62-
fn from_str_issue7588() {
63-
let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
64-
assert_eq!(u, None);
6537
@@ -640,6 +639,7 @@ macro_rules! test_float {
6638
mod $modname {
6739
// FIXME(nagisa): these tests should test for sign of -0.0
@@ -78,17 +50,5 @@ index a17c094..5bb11d2 100644
7850
fn max() {
7951
assert_eq!((0.0 as $fty).max(0.0), 0.0);
8052
assert_eq!((-0.0 as $fty).max(-0.0), -0.0);
81-
diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs
82-
index fac70c4..9107a02 100644
83-
--- a/src/libcore/tests/time.rs
84-
+++ b/src/libcore/tests/time.rs
85-
@@ -127,6 +127,7 @@ fn mul() {
86-
}
87-
88-
#[test]
89-
+#[ignore] // checked_mul impl not yet checking for overflow
90-
fn checked_mul() {
91-
assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2)));
92-
assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3)));
9353
--
9454
2.21.0 (Apple Git-122)

src/num.rs

+36-10
Original file line numberDiff line numberDiff line change
@@ -245,16 +245,42 @@ pub(crate) fn trans_checked_int_binop<'tcx>(
245245
(val, has_overflow)
246246
}
247247
BinOp::Mul => {
248-
let val = fx.bcx.ins().imul(lhs, rhs);
249-
/*let val_hi = if !signed {
250-
fx.bcx.ins().umulhi(lhs, rhs)
251-
} else {
252-
fx.bcx.ins().smulhi(lhs, rhs)
253-
};
254-
let has_overflow = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0);*/
255-
// TODO: check for overflow
256-
let has_overflow = fx.bcx.ins().bconst(types::B1, false);
257-
(val, has_overflow)
248+
let ty = fx.bcx.func.dfg.value_type(lhs);
249+
match ty {
250+
types::I8 | types::I16 | types::I32 if !signed => {
251+
let lhs = fx.bcx.ins().uextend(ty.double_width().unwrap(), lhs);
252+
let rhs = fx.bcx.ins().uextend(ty.double_width().unwrap(), rhs);
253+
let val = fx.bcx.ins().imul(lhs, rhs);
254+
let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, val, (1 << ty.bits()) - 1);
255+
let val = fx.bcx.ins().ireduce(ty, val);
256+
(val, has_overflow)
257+
}
258+
types::I8 | types::I16 | types::I32 if signed => {
259+
let lhs = fx.bcx.ins().sextend(ty.double_width().unwrap(), lhs);
260+
let rhs = fx.bcx.ins().sextend(ty.double_width().unwrap(), rhs);
261+
let val = fx.bcx.ins().imul(lhs, rhs);
262+
let has_underflow = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, val, -(1 << (ty.bits() - 1)));
263+
let has_overflow = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, val, (1 << (ty.bits() - 1)) - 1);
264+
let val = fx.bcx.ins().ireduce(ty, val);
265+
(val, fx.bcx.ins().bor(has_underflow, has_overflow))
266+
}
267+
types::I64 => {
268+
//let val = fx.easy_call("__mulodi4", &[lhs, rhs, overflow_ptr], types::I64);
269+
let val = fx.bcx.ins().imul(lhs, rhs);
270+
let has_overflow = if !signed {
271+
let val_hi = fx.bcx.ins().umulhi(lhs, rhs);
272+
fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0)
273+
} else {
274+
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(IntCC::NotEqual, val_hi, u64::try_from((1u128 << ty.bits()) - 1).unwrap() as i64);
277+
fx.bcx.ins().band(not_all_zero, not_all_ones)
278+
};
279+
(val, has_overflow)
280+
}
281+
types::I128 => unreachable!("i128 should have been handled by codegen_i128::maybe_codegen"),
282+
_ => unreachable!("invalid non-integer type {}", ty),
283+
}
258284
}
259285
BinOp::Shl => {
260286
let val = fx.bcx.ins().ishl(lhs, rhs);

0 commit comments

Comments
 (0)