From 42208c122757fca706bc5224f3a0c7200fae32e9 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 20 Nov 2017 01:54:43 -0800 Subject: [PATCH] Handle shifts properly * The overflow-checking shift items need to take a full 128-bit type, since they need to be able to detect idiocy like `1i128 << (1u128 << 127)` * The unchecked ones just take u32, like the `*_sh?` methods in core * Because shift-by-anything is allowed, cast into a new local for every shift --- src/librustc_mir/transform/lower_128bit.rs | 118 ++++++++++++++------ src/test/mir-opt/lower_128bit_debug_test.rs | 22 ++-- src/test/mir-opt/lower_128bit_test.rs | 20 ++-- 3 files changed, 112 insertions(+), 48 deletions(-) diff --git a/src/librustc_mir/transform/lower_128bit.rs b/src/librustc_mir/transform/lower_128bit.rs index 2075792fb81..9dc5fdadbb1 100644 --- a/src/librustc_mir/transform/lower_128bit.rs +++ b/src/librustc_mir/transform/lower_128bit.rs @@ -41,21 +41,41 @@ fn lower_128bit_ops<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir< let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut(); for block in basic_blocks.iter_mut() { for i in (0..block.statements.len()).rev() { - let lang_item = - if let Some(lang_item) = lower_to(&block.statements[i], local_decls, tcx) { - lang_item + let (lang_item, rhs_kind) = + if let Some((lang_item, rhs_kind)) = + lower_to(&block.statements[i], local_decls, tcx) + { + (lang_item, rhs_kind) } else { continue; }; + let rhs_override_ty = rhs_kind.ty(tcx); + let cast_local = + match rhs_override_ty { + None => None, + Some(ty) => { + let local_decl = LocalDecl::new_internal( + ty, block.statements[i].source_info.span); + Some(local_decls.push(local_decl)) + }, + }; + + let storage_dead = cast_local.map(|local| { + Statement { + source_info: block.statements[i].source_info, + kind: StatementKind::StorageDead(local), + } + }); let after_call = BasicBlockData { - statements: block.statements.drain((i+1)..).collect(), + statements: storage_dead.into_iter() + .chain(block.statements.drain((i+1)..)).collect(), is_cleanup: block.is_cleanup, terminator: block.terminator.take(), }; let bin_statement = block.statements.pop().unwrap(); - let (source_info, lvalue, lhs, rhs) = match bin_statement { + let (source_info, lvalue, lhs, mut rhs) = match bin_statement { Statement { source_info, kind: StatementKind::Assign( @@ -71,6 +91,23 @@ fn lower_128bit_ops<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir< _ => bug!("Statement doesn't match pattern any more?"), }; + if let Some(local) = cast_local { + block.statements.push(Statement { + source_info: source_info, + kind: StatementKind::StorageLive(local), + }); + block.statements.push(Statement { + source_info: source_info, + kind: StatementKind::Assign( + Lvalue::Local(local), + Rvalue::Cast( + CastKind::Misc, + rhs, + rhs_override_ty.unwrap())), + }); + rhs = Operand::Consume(Lvalue::Local(local)); + } + let call_did = check_lang_item_type( lang_item, &lvalue, &lhs, &rhs, local_decls, tcx); @@ -118,7 +155,7 @@ fn check_lang_item_type<'a, 'tcx, D>( } fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Option + -> Option<(LangItem, RhsKind)> where D: HasLocalDecls<'tcx> { match statement.kind { @@ -139,6 +176,23 @@ fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCt None } +#[derive(Copy, Clone)] +enum RhsKind { + Unchanged, + ForceU128, + ForceU32, +} + +impl RhsKind { + fn ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option> { + match *self { + RhsKind::Unchanged => None, + RhsKind::ForceU128 => Some(tcx.types.u128), + RhsKind::ForceU32 => Some(tcx.types.u32), + } + } +} + fn sign_of_128bit(ty: Ty) -> Option { match ty.sty { TypeVariants::TyInt(syntax::ast::IntTy::I128) => Some(true), @@ -147,39 +201,39 @@ fn sign_of_128bit(ty: Ty) -> Option { } } -fn item_for_op(bin_op: BinOp, is_signed: bool) -> Option { +fn item_for_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsKind)> { let i = match (bin_op, is_signed) { - (BinOp::Add, true) => LangItem::I128AddFnLangItem, - (BinOp::Add, false) => LangItem::U128AddFnLangItem, - (BinOp::Sub, true) => LangItem::I128SubFnLangItem, - (BinOp::Sub, false) => LangItem::U128SubFnLangItem, - (BinOp::Mul, true) => LangItem::I128MulFnLangItem, - (BinOp::Mul, false) => LangItem::U128MulFnLangItem, - (BinOp::Div, true) => LangItem::I128DivFnLangItem, - (BinOp::Div, false) => LangItem::U128DivFnLangItem, - (BinOp::Rem, true) => LangItem::I128RemFnLangItem, - (BinOp::Rem, false) => LangItem::U128RemFnLangItem, - (BinOp::Shl, true) => LangItem::I128ShlFnLangItem, - (BinOp::Shl, false) => LangItem::U128ShlFnLangItem, - (BinOp::Shr, true) => LangItem::I128ShrFnLangItem, - (BinOp::Shr, false) => LangItem::U128ShrFnLangItem, + (BinOp::Add, true) => (LangItem::I128AddFnLangItem, RhsKind::Unchanged), + (BinOp::Add, false) => (LangItem::U128AddFnLangItem, RhsKind::Unchanged), + (BinOp::Sub, true) => (LangItem::I128SubFnLangItem, RhsKind::Unchanged), + (BinOp::Sub, false) => (LangItem::U128SubFnLangItem, RhsKind::Unchanged), + (BinOp::Mul, true) => (LangItem::I128MulFnLangItem, RhsKind::Unchanged), + (BinOp::Mul, false) => (LangItem::U128MulFnLangItem, RhsKind::Unchanged), + (BinOp::Div, true) => (LangItem::I128DivFnLangItem, RhsKind::Unchanged), + (BinOp::Div, false) => (LangItem::U128DivFnLangItem, RhsKind::Unchanged), + (BinOp::Rem, true) => (LangItem::I128RemFnLangItem, RhsKind::Unchanged), + (BinOp::Rem, false) => (LangItem::U128RemFnLangItem, RhsKind::Unchanged), + (BinOp::Shl, true) => (LangItem::I128ShlFnLangItem, RhsKind::ForceU32), + (BinOp::Shl, false) => (LangItem::U128ShlFnLangItem, RhsKind::ForceU32), + (BinOp::Shr, true) => (LangItem::I128ShrFnLangItem, RhsKind::ForceU32), + (BinOp::Shr, false) => (LangItem::U128ShrFnLangItem, RhsKind::ForceU32), _ => return None, }; Some(i) } -fn item_for_checked_op(bin_op: BinOp, is_signed: bool) -> Option { +fn item_for_checked_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsKind)> { let i = match (bin_op, is_signed) { - (BinOp::Add, true) => LangItem::I128AddoFnLangItem, - (BinOp::Add, false) => LangItem::U128AddoFnLangItem, - (BinOp::Sub, true) => LangItem::I128SuboFnLangItem, - (BinOp::Sub, false) => LangItem::U128SuboFnLangItem, - (BinOp::Mul, true) => LangItem::I128MuloFnLangItem, - (BinOp::Mul, false) => LangItem::U128MuloFnLangItem, - (BinOp::Shl, true) => LangItem::I128ShloFnLangItem, - (BinOp::Shl, false) => LangItem::U128ShloFnLangItem, - (BinOp::Shr, true) => LangItem::I128ShroFnLangItem, - (BinOp::Shr, false) => LangItem::U128ShroFnLangItem, + (BinOp::Add, true) => (LangItem::I128AddoFnLangItem, RhsKind::Unchanged), + (BinOp::Add, false) => (LangItem::U128AddoFnLangItem, RhsKind::Unchanged), + (BinOp::Sub, true) => (LangItem::I128SuboFnLangItem, RhsKind::Unchanged), + (BinOp::Sub, false) => (LangItem::U128SuboFnLangItem, RhsKind::Unchanged), + (BinOp::Mul, true) => (LangItem::I128MuloFnLangItem, RhsKind::Unchanged), + (BinOp::Mul, false) => (LangItem::U128MuloFnLangItem, RhsKind::Unchanged), + (BinOp::Shl, true) => (LangItem::I128ShloFnLangItem, RhsKind::ForceU128), + (BinOp::Shl, false) => (LangItem::U128ShloFnLangItem, RhsKind::ForceU128), + (BinOp::Shr, true) => (LangItem::I128ShroFnLangItem, RhsKind::ForceU128), + (BinOp::Shr, false) => (LangItem::U128ShroFnLangItem, RhsKind::ForceU128), _ => bug!("That should be all the checked ones?"), }; Some(i) diff --git a/src/test/mir-opt/lower_128bit_debug_test.rs b/src/test/mir-opt/lower_128bit_debug_test.rs index 8d1ef82c187..4626dc17e1f 100644 --- a/src/test/mir-opt/lower_128bit_debug_test.rs +++ b/src/test/mir-opt/lower_128bit_debug_test.rs @@ -35,13 +35,13 @@ fn i128_mulo(_x: i128, _y: i128) -> (i128, bool) { (4, false) } #[lang="u128_mulo"] fn u128_mulo(_x: u128, _y: u128) -> (u128, bool) { (5, false) } #[lang="i128_shlo"] -fn i128_shlo(_x: i128, _y: i32) -> (i128, bool) { (6, false) } +fn i128_shlo(_x: i128, _y: u128) -> (i128, bool) { (6, false) } #[lang="u128_shlo"] -fn u128_shlo(_x: u128, _y: i32) -> (u128, bool) { (6, false) } +fn u128_shlo(_x: u128, _y: u128) -> (u128, bool) { (6, false) } #[lang="i128_shro"] -fn i128_shro(_x: i128, _y: i32) -> (i128, bool) { (7, false) } +fn i128_shro(_x: i128, _y: u128) -> (i128, bool) { (7, false) } #[lang="u128_shro"] -fn u128_shro(_x: u128, _y: i32) -> (u128, bool) { (8, false) } +fn u128_shro(_x: u128, _y: u128) -> (u128, bool) { (8, false) } fn test_signed(mut x: i128) -> i128 { x += 1; @@ -88,7 +88,9 @@ fn main() { // _1 = const i128_rem(_1, const 5i128) -> bb15; // ... // _1 = (_13.0: i128); -// _14 = const i128_shro(_1, const 7i32) -> bb16; +// ... +// _17 = const 7i32 as u128 (Misc); +// _14 = const i128_shro(_1, _17) -> bb16; // ... // _1 = (_14.0: i128); // ... @@ -100,7 +102,8 @@ fn main() { // ... // assert(!(_13.1: bool), "attempt to shift left with overflow") -> bb8; // ... -// _13 = const i128_shlo(_1, const 6i32) -> bb14; +// _16 = const 6i32 as u128 (Misc); +// _13 = const i128_shlo(_1, _16) -> bb14; // ... // assert(!(_14.1: bool), "attempt to shift right with overflow") -> bb9; // END rustc.test_signed.Lower128Bit.after.mir @@ -121,7 +124,9 @@ fn main() { // _1 = const u128_rem(_1, const 5u128) -> bb13; // ... // _1 = (_7.0: u128); -// _8 = const u128_shro(_1, const 7i32) -> bb14; +// ... +// _11 = const 7i32 as u128 (Misc); +// _8 = const u128_shro(_1, _11) -> bb14; // ... // _1 = (_8.0: u128); // ... @@ -133,7 +138,8 @@ fn main() { // ... // assert(!(_7.1: bool), "attempt to shift left with overflow") -> bb6; // ... -// _7 = const u128_shlo(_1, const 6i32) -> bb12; +// _10 = const 6i32 as u128 (Misc); +// _7 = const u128_shlo(_1, _10) -> bb12; // ... // assert(!(_8.1: bool), "attempt to shift right with overflow") -> bb7; // END rustc.test_unsigned.Lower128Bit.after.mir diff --git a/src/test/mir-opt/lower_128bit_test.rs b/src/test/mir-opt/lower_128bit_test.rs index ba05280e20b..207cd0ac57e 100644 --- a/src/test/mir-opt/lower_128bit_test.rs +++ b/src/test/mir-opt/lower_128bit_test.rs @@ -34,13 +34,13 @@ fn i128_rem(_x: i128, _y: i128) -> i128 { 5 } #[lang="u128_rem"] fn u128_rem(_x: u128, _y: u128) -> u128 { 6 } #[lang="i128_shl"] -fn i128_shl(_x: i128, _y: i32) -> i128 { 7 } +fn i128_shl(_x: i128, _y: u32) -> i128 { 7 } #[lang="u128_shl"] -fn u128_shl(_x: u128, _y: i32) -> u128 { 7 } +fn u128_shl(_x: u128, _y: u32) -> u128 { 7 } #[lang="i128_shr"] -fn i128_shr(_x: i128, _y: i32) -> i128 { 8 } +fn i128_shr(_x: i128, _y: u32) -> i128 { 8 } #[lang="u128_shr"] -fn u128_shr(_x: u128, _y: i32) -> u128 { 9 } +fn u128_shr(_x: u128, _y: u32) -> u128 { 9 } fn test_signed(mut x: i128) -> i128 { x += 1; @@ -82,9 +82,11 @@ fn main() { // ... // _1 = const i128_sub(_1, const 2i128) -> bb6; // ... -// _1 = const i128_shr(_1, const 7i32) -> bb9; +// _11 = const 7i32 as u32 (Misc); +// _1 = const i128_shr(_1, _11) -> bb9; // ... -// _1 = const i128_shl(_1, const 6i32) -> bb10; +// _12 = const 6i32 as u32 (Misc); +// _1 = const i128_shl(_1, _12) -> bb10; // END rustc.test_signed.Lower128Bit.after.mir // START rustc.test_unsigned.Lower128Bit.after.mir @@ -98,7 +100,9 @@ fn main() { // ... // _1 = const u128_sub(_1, const 2u128) -> bb4; // ... -// _1 = const u128_shr(_1, const 7i32) -> bb7; +// _5 = const 7i32 as u32 (Misc); +// _1 = const u128_shr(_1, _5) -> bb7; // ... -// _1 = const u128_shl(_1, const 6i32) -> bb8; +// _6 = const 6i32 as u32 (Misc); +// _1 = const u128_shl(_1, _6) -> bb8; // END rustc.test_unsigned.Lower128Bit.after.mir -- 2.44.0