From 376ec8c258ff5bc0400bff16979199fa3f9ce871 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 8 Aug 2018 09:34:56 +0200 Subject: [PATCH] Don't crash on checked binops (treated like unchecked ones atm) --- Readme.md | 2 -- build.sh | 2 +- src/abi.rs | 2 -- src/base.rs | 79 ++++++++++++++++++++++++++++++++++++++++----------- src/common.rs | 14 +++++++-- 5 files changed, 76 insertions(+), 23 deletions(-) diff --git a/Readme.md b/Readme.md index 7c1efe263f69..8e3105d49cfe 100644 --- a/Readme.md +++ b/Readme.md @@ -18,8 +18,6 @@ $ cargo build $ rustc -Zcodegen-backend=$(pwd)/target/debug/librustc_codegen_cranelift.so my_crate.rs --crate-type lib -Og ``` -> You must compile with `-Og`, because checked binops are not yet supported. - ## Building libcore ```bash diff --git a/build.sh b/build.sh index 82160c6435da..762dc3a8d944 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ cargo build || exit 1 cd examples/ -RUSTC="rustc -Zcodegen-backend=$(pwd)/../target/debug/librustc_codegen_cranelift.so -Og -L crate=. --crate-type lib" +RUSTC="rustc -Zcodegen-backend=$(pwd)/../target/debug/librustc_codegen_cranelift.so -L crate=. --crate-type lib" $RUSTC mini_core.rs --crate-name mini_core && $RUSTC example.rs && diff --git a/src/abi.rs b/src/abi.rs index 3931ef4a3f1d..c1097864bf0c 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -398,7 +398,6 @@ pub fn codegen_call<'a, 'tcx: 'a>( args[1], ret.layout().ty, false, - false, ), TypeVariants::TyInt(_) => crate::base::trans_int_binop( fx, @@ -407,7 +406,6 @@ pub fn codegen_call<'a, 'tcx: 'a>( args[1], ret.layout().ty, true, - false, ), _ => panic!(), }; diff --git a/src/base.rs b/src/base.rs index 4970eef10d85..9d09409aa9ef 100644 --- a/src/base.rs +++ b/src/base.rs @@ -313,10 +313,10 @@ fn trans_stmt<'a, 'tcx: 'a>( trans_bool_binop(fx, *bin_op, lhs, rhs, lval.layout().ty) } TypeVariants::TyUint(_) => { - trans_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, false, false) + trans_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, false) } TypeVariants::TyInt(_) => { - trans_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, true, false) + trans_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, true) } TypeVariants::TyFloat(_) => { trans_float_binop(fx, *bin_op, lhs, rhs, lval.layout().ty) @@ -325,9 +325,9 @@ fn trans_stmt<'a, 'tcx: 'a>( trans_char_binop(fx, *bin_op, lhs, rhs, lval.layout().ty) } TypeVariants::TyRawPtr(..) => { - trans_ptr_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, false) + trans_ptr_binop(fx, *bin_op, lhs, rhs, lval.layout().ty) } - _ => unimplemented!("bin op {:?} for {:?}", bin_op, ty), + _ => unimplemented!("binop {:?} for {:?}", bin_op, ty), }; lval.write_cvalue(fx, res); } @@ -338,14 +338,13 @@ fn trans_stmt<'a, 'tcx: 'a>( let res = match ty.sty { TypeVariants::TyUint(_) => { - trans_int_binop(fx, *bin_op, lhs, rhs, ty, false, true) + trans_checked_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, false) } TypeVariants::TyInt(_) => { - trans_int_binop(fx, *bin_op, lhs, rhs, ty, true, true) + trans_checked_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, true) } - _ => unimplemented!("checked bin op {:?} for {:?}", bin_op, ty), + _ => unimplemented!("checked binop {:?} for {:?}", bin_op, ty), }; - return Err(format!("checked bin op {:?}", bin_op)); lval.write_cvalue(fx, res); } Rvalue::UnaryOp(un_op, operand) => { @@ -510,7 +509,7 @@ pub fn trans_get_discriminant<'a, 'tcx: 'a>( macro_rules! binop_match { (@single $fx:expr, $bug_fmt:expr, $var:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, bug) => { - bug!("bin op {} on {} lhs: {:?} rhs: {:?}", stringify!($var), $bug_fmt, $lhs, $rhs) + bug!("binop {} on {} lhs: {:?} rhs: {:?}", stringify!($var), $bug_fmt, $lhs, $rhs) }; (@single $fx:expr, $bug_fmt:expr, $var:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, icmp($cc:ident)) => {{ assert_eq!($fx.tcx.types.bool, $ret_ty); @@ -585,12 +584,14 @@ pub fn trans_int_binop<'a, 'tcx: 'a>( bin_op: BinOp, lhs: CValue<'tcx>, rhs: CValue<'tcx>, - ty: Ty<'tcx>, + out_ty: Ty<'tcx>, signed: bool, - _checked: bool, ) -> CValue<'tcx> { - let res = binop_match! { - fx, bin_op, signed, lhs, rhs, ty, "int/uint"; + if bin_op != BinOp::Shl && bin_op != BinOp::Shr { + assert_eq!(lhs.layout().ty, rhs.layout().ty, "int binop requires lhs and rhs of same type"); + } + binop_match! { + fx, bin_op, signed, lhs, rhs, out_ty, "int/uint"; Add (_) iadd; Sub (_) isub; Mul (_) imul; @@ -617,10 +618,57 @@ pub fn trans_int_binop<'a, 'tcx: 'a>( Gt (true) icmp(SignedGreaterThan); Offset (_) bug; + } +} + +fn trans_checked_int_binop<'a, 'tcx: 'a>( + fx: &mut FunctionCx<'a, 'tcx>, + bin_op: BinOp, + lhs: CValue<'tcx>, + rhs: CValue<'tcx>, + out_ty: Ty<'tcx>, + signed: bool, +) -> CValue<'tcx> { + if bin_op != BinOp::Shl && bin_op != BinOp::Shr { + assert_eq!(lhs.layout().ty, rhs.layout().ty, "checked int binop requires lhs and rhs of same type"); + } + let res_ty = match out_ty.sty { + TypeVariants::TyTuple(tys) => tys[0], + _ => bug!("Checked int binop requires tuple as output, but got {:?}", out_ty), }; - // TODO: return correct value for checked binops - res + let res = binop_match! { + fx, bin_op, signed, lhs, rhs, res_ty, "checked int/uint"; + Add (_) iadd; + Sub (_) isub; + Mul (_) imul; + Div (_) bug; + Rem (_) bug; + BitXor (_) bug; + BitAnd (_) bug; + BitOr (_) bug; + Shl (_) ishl; + Shr (false) ushr; + Shr (true) sshr; + + Eq (_) bug; + Lt (_) bug; + Le (_) bug; + Ne (_) bug; + Ge (_) bug; + Gt (_) bug; + + Offset (_) bug; + }; + + let has_overflow = CValue::const_val(fx, fx.tcx.types.bool, 0); + + let out_place = CPlace::temp(fx, out_ty); + out_place.place_field(fx, mir::Field::new(0)).write_cvalue(fx, res); + println!("abc"); + out_place.place_field(fx, mir::Field::new(1)).write_cvalue(fx, has_overflow); + + out_place.to_cvalue(fx) } fn trans_float_binop<'a, 'tcx: 'a>( @@ -703,7 +751,6 @@ fn trans_ptr_binop<'a, 'tcx: 'a>( lhs: CValue<'tcx>, rhs: CValue<'tcx>, ty: Ty<'tcx>, - _checked: bool, ) -> CValue<'tcx> { binop_match! { fx, bin_op, false, lhs, rhs, ty, "ptr"; diff --git a/src/common.rs b/src/common.rs index 421b2cb2d03b..0f19c8c7e6b9 100644 --- a/src/common.rs +++ b/src/common.rs @@ -133,8 +133,8 @@ impl<'tcx> CValue<'tcx> { pub fn expect_byref(self) -> (Value, TyLayout<'tcx>) { match self { CValue::ByRef(value, layout) => (value, layout), - CValue::ByVal(_, _) => bug!("Expected CValue::ByRef, found CValue::ByVal"), - CValue::Func(_, _) => bug!("Expected CValue::ByRef, found CValue::Func"), + CValue::ByVal(_, _) => bug!("Expected CValue::ByRef, found CValue::ByVal: {:?}", self), + CValue::Func(_, _) => bug!("Expected CValue::ByRef, found CValue::Func: {:?}", self), } } @@ -187,6 +187,16 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { } } + pub fn temp(fx: &mut FunctionCx<'a, 'tcx>, ty: Ty<'tcx>) -> CPlace<'tcx> { + let layout = fx.layout_of(ty); + let stack_slot = fx.bcx.create_stack_slot(StackSlotData { + kind: StackSlotKind::ExplicitSlot, + size: layout.size.bytes() as u32, + offset: None, + }); + CPlace::Addr(fx.bcx.ins().stack_addr(types::I64, stack_slot, 0), layout) + } + pub fn from_stack_slot( fx: &mut FunctionCx<'a, 'tcx>, stack_slot: StackSlot,