From bf3ec3be3e595780d842ac3069bb07f3c50f54b8 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 13 Jul 2019 16:55:08 +0200 Subject: [PATCH] Implement checked binops --- example/mini_core.rs | 48 +++++++++++++++++++++++ example/mini_core_hello_world.rs | 17 +++++++++ src/base.rs | 65 ++++++++++++++++++++++++++------ 3 files changed, 119 insertions(+), 11 deletions(-) diff --git a/example/mini_core.rs b/example/mini_core.rs index d900776c55c..8c372450abd 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -128,6 +128,14 @@ impl Add for u8 { } } +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + impl Add for usize { type Output = Self; @@ -151,6 +159,30 @@ impl Sub for usize { } } +impl Sub for u8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i16 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + #[lang = "bitor"] pub trait BitOr { type Output; @@ -270,6 +302,22 @@ pub trait Neg { fn neg(self) -> Self::Output; } +impl Neg for i8 { + type Output = i8; + + fn neg(self) -> i8 { + -self + } +} + +impl Neg for i16 { + type Output = i16; + + fn neg(self) -> i16 { + -self + } +} + impl Neg for isize { type Output = isize; diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index e51f257f6b4..15f0442b624 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -236,4 +236,21 @@ fn main() { unsafe { assert_eq!(ABC as usize, 0); } &mut (|| Some(0 as *const ())) as &mut FnMut() -> Option<*const ()>; + + // checked binops + let zeroi8 = 0i8; + let oneu8 = 1u8; + let onei8 = 1i8; + zeroi8 - 1; + oneu8 - 1; + zeroi8 - -2i8; + #[allow(unreachable_code)] + { + if false { + let minustwoi8 = -2i8; + oneu8 + 255; + onei8 + 127; + minustwoi8 - 127; + } + } } diff --git a/src/base.rs b/src/base.rs index 1adcec046e0..7b29d15e56b 100644 --- a/src/base.rs +++ b/src/base.rs @@ -241,7 +241,7 @@ fn codegen_fn_content<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx, impl Backend>) } else { fx.bcx.ins().brz(cond, target, &[]); }; - trap_panic(fx, format!("[panic] Assert {:?} failed.", msg)); + trap_panic(fx, format!("[panic] Assert {:?} failed at {:?}.", msg, bb_data.terminator().source_info.span)); } TerminatorKind::SwitchInt { @@ -948,17 +948,62 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>( let lhs = in_lhs.load_scalar(fx); let rhs = in_rhs.load_scalar(fx); - let res = match bin_op { - BinOp::Add => fx.bcx.ins().iadd(lhs, rhs), - BinOp::Sub => fx.bcx.ins().isub(lhs, rhs), - BinOp::Mul => fx.bcx.ins().imul(lhs, rhs), - BinOp::Shl => fx.bcx.ins().ishl(lhs, rhs), + let (res, has_overflow) = match bin_op { + BinOp::Add => { + /*let (val, c_out) = fx.bcx.ins().iadd_cout(lhs, rhs); + (val, c_out)*/ + // FIXME(CraneStation/cranelift#849) legalize iadd_cout for i8 and i16 + let val = fx.bcx.ins().iadd(lhs, rhs); + let has_overflow = if !signed { + fx.bcx.ins().icmp(IntCC::UnsignedLessThan, val, lhs) + } else { + let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0); + let slt = fx.bcx.ins().icmp(IntCC::SignedLessThan, val, lhs); + fx.bcx.ins().bxor(rhs_is_negative, slt) + }; + (val, has_overflow) + } + BinOp::Sub => { + /*let (val, b_out) = fx.bcx.ins().isub_bout(lhs, rhs); + (val, b_out)*/ + // FIXME(CraneStation/cranelift#849) legalize isub_bout for i8 and i16 + let val = fx.bcx.ins().isub(lhs, rhs); + let has_overflow = if !signed { + fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, val, lhs) + } else { + let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0); + let sgt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, val, lhs); + fx.bcx.ins().bxor(rhs_is_negative, sgt) + }; + (val, has_overflow) + } + BinOp::Mul => { + let val = fx.bcx.ins().imul(lhs, rhs); + /*let val_hi = if !signed { + fx.bcx.ins().umulhi(lhs, rhs) + } else { + fx.bcx.ins().smulhi(lhs, rhs) + }; + let has_overflow = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0);*/ + // TODO: check for overflow + let has_overflow = fx.bcx.ins().bconst(types::B1, false); + (val, has_overflow) + } + BinOp::Shl => { + let val = fx.bcx.ins().ishl(lhs, rhs); + // TODO: check for overflow + let has_overflow = fx.bcx.ins().bconst(types::B1, false); + (val, has_overflow) + } BinOp::Shr => { - if !signed { + let val = if !signed { fx.bcx.ins().ushr(lhs, rhs) } else { fx.bcx.ins().sshr(lhs, rhs) - } + }; + // TODO: check for overflow + let has_overflow = fx.bcx.ins().bconst(types::B1, false); + (val, has_overflow) } _ => bug!( "binop {:?} on checked int/uint lhs: {:?} rhs: {:?}", @@ -968,9 +1013,7 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>( ), }; - // TODO: check for overflow - let has_overflow = fx.bcx.ins().iconst(types::I8, 0); - + let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow); let out_place = CPlace::new_stack_slot(fx, out_ty); let out_layout = out_place.layout(); out_place.write_cvalue(fx, CValue::by_val_pair(res, has_overflow, out_layout));