From 6a5a086fd61a87d36cfa3652b279c543601860da Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 20 Nov 2017 00:04:54 -0800 Subject: [PATCH] Add type checking for the lang item As part of doing so, add more lang items instead of passing u128 to the i128 ones where it doesn't matter in twos-complement. --- src/librustc/middle/lang_items.rs | 5 ++ src/librustc_mir/transform/lower_128bit.rs | 64 +++++++++++++++------ src/test/mir-opt/lower_128bit_debug_test.rs | 21 +++---- src/test/mir-opt/lower_128bit_test.rs | 27 +++++---- 4 files changed, 78 insertions(+), 39 deletions(-) diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 1c52a8dbc97..a858a8d7449 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -313,13 +313,17 @@ pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems { // A lang item for each of the 128-bit operators we can optionally lower. I128AddFnLangItem, "i128_add", i128_add_fn; + U128AddFnLangItem, "u128_add", u128_add_fn; I128SubFnLangItem, "i128_sub", i128_sub_fn; + U128SubFnLangItem, "u128_sub", u128_sub_fn; I128MulFnLangItem, "i128_mul", i128_mul_fn; + U128MulFnLangItem, "u128_mul", u128_mul_fn; I128DivFnLangItem, "i128_div", i128_div_fn; U128DivFnLangItem, "u128_div", u128_div_fn; I128RemFnLangItem, "i128_rem", i128_rem_fn; U128RemFnLangItem, "u128_rem", u128_rem_fn; I128ShlFnLangItem, "i128_shl", i128_shl_fn; + U128ShlFnLangItem, "u128_shl", u128_shl_fn; I128ShrFnLangItem, "i128_shr", i128_shr_fn; U128ShrFnLangItem, "u128_shr", u128_shr_fn; // And overflow versions for the operators that are checkable. @@ -331,6 +335,7 @@ pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems { I128MuloFnLangItem, "i128_mulo", i128_mulo_fn; U128MuloFnLangItem, "u128_mulo", u128_mulo_fn; I128ShloFnLangItem, "i128_shlo", i128_shlo_fn; + U128ShloFnLangItem, "u128_shlo", u128_shlo_fn; I128ShroFnLangItem, "i128_shro", i128_shro_fn; U128ShroFnLangItem, "u128_shro", u128_shro_fn; } diff --git a/src/librustc_mir/transform/lower_128bit.rs b/src/librustc_mir/transform/lower_128bit.rs index 3a5b8e0790d..2075792fb81 100644 --- a/src/librustc_mir/transform/lower_128bit.rs +++ b/src/librustc_mir/transform/lower_128bit.rs @@ -41,9 +41,9 @@ 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 call_did = - if let Some(call_did) = lower_to(&block.statements[i], local_decls, tcx) { - call_did + let lang_item = + if let Some(lang_item) = lower_to(&block.statements[i], local_decls, tcx) { + lang_item } else { continue; }; @@ -71,6 +71,9 @@ fn lower_128bit_ops<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir< _ => bug!("Statement doesn't match pattern any more?"), }; + let call_did = check_lang_item_type( + lang_item, &lvalue, &lhs, &rhs, local_decls, tcx); + let bb = BasicBlock::new(cur_len + new_blocks.len()); new_blocks.push(after_call); @@ -92,25 +95,43 @@ fn lower_128bit_ops<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir< } } +fn check_lang_item_type<'a, 'tcx, D>( + lang_item: LangItem, + lvalue: &Lvalue<'tcx>, + lhs: &Operand<'tcx>, + rhs: &Operand<'tcx>, + local_decls: &D, + tcx: TyCtxt<'a, 'tcx, 'tcx>) +-> DefId + where D: HasLocalDecls<'tcx> +{ + let did = tcx.require_lang_item(lang_item); + let poly_sig = tcx.fn_sig(did); + let sig = tcx.no_late_bound_regions(&poly_sig).unwrap(); + let lhs_ty = lhs.ty(local_decls, tcx); + let rhs_ty = rhs.ty(local_decls, tcx); + let lvalue_ty = lvalue.ty(local_decls, tcx).to_ty(tcx); + let expected = [lhs_ty, rhs_ty, lvalue_ty]; + assert_eq!(sig.inputs_and_output[..], expected, + "lang item {}", tcx.def_symbol_name(did)); + did +} + fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Option + -> Option where D: HasLocalDecls<'tcx> { match statement.kind { StatementKind::Assign(_, Rvalue::BinaryOp(bin_op, ref lhs, _)) => { let ty = lhs.ty(local_decls, tcx); - if let Some(is_signed) = sign_of_128bit(&ty) { - if let Some(item) = item_for_op(bin_op, is_signed) { - return Some(tcx.require_lang_item(item)) - } + if let Some(is_signed) = sign_of_128bit(ty) { + return item_for_op(bin_op, is_signed); } }, StatementKind::Assign(_, Rvalue::CheckedBinaryOp(bin_op, ref lhs, _)) => { let ty = lhs.ty(local_decls, tcx); - if let Some(is_signed) = sign_of_128bit(&ty) { - if let Some(item) = item_for_checked_op(bin_op, is_signed) { - return Some(tcx.require_lang_item(item)) - } + if let Some(is_signed) = sign_of_128bit(ty) { + return item_for_checked_op(bin_op, is_signed); } }, _ => {}, @@ -118,7 +139,7 @@ fn lower_to<'a, 'tcx, D>(statement: &Statement<'tcx>, local_decls: &D, tcx: TyCt None } -fn sign_of_128bit(ty: &Ty) -> Option { +fn sign_of_128bit(ty: Ty) -> Option { match ty.sty { TypeVariants::TyInt(syntax::ast::IntTy::I128) => Some(true), TypeVariants::TyUint(syntax::ast::UintTy::U128) => Some(false), @@ -128,14 +149,18 @@ fn sign_of_128bit(ty: &Ty) -> Option { fn item_for_op(bin_op: BinOp, is_signed: bool) -> Option { let i = match (bin_op, is_signed) { - (BinOp::Add, _) => LangItem::I128AddFnLangItem, - (BinOp::Sub, _) => LangItem::I128SubFnLangItem, - (BinOp::Mul, _) => LangItem::I128MulFnLangItem, + (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, _) => LangItem::I128ShlFnLangItem, + (BinOp::Shl, true) => LangItem::I128ShlFnLangItem, + (BinOp::Shl, false) => LangItem::U128ShlFnLangItem, (BinOp::Shr, true) => LangItem::I128ShrFnLangItem, (BinOp::Shr, false) => LangItem::U128ShrFnLangItem, _ => return None, @@ -151,10 +176,11 @@ fn item_for_checked_op(bin_op: BinOp, is_signed: bool) -> Option { (BinOp::Sub, false) => LangItem::U128SuboFnLangItem, (BinOp::Mul, true) => LangItem::I128MuloFnLangItem, (BinOp::Mul, false) => LangItem::U128MuloFnLangItem, - (BinOp::Shl, _) => LangItem::I128ShloFnLangItem, + (BinOp::Shl, true) => LangItem::I128ShloFnLangItem, + (BinOp::Shl, false) => LangItem::U128ShloFnLangItem, (BinOp::Shr, true) => LangItem::I128ShroFnLangItem, (BinOp::Shr, false) => LangItem::U128ShroFnLangItem, - _ => return None, + _ => bug!("That should be all the checked ones?"), }; Some(i) } \ No newline at end of file diff --git a/src/test/mir-opt/lower_128bit_debug_test.rs b/src/test/mir-opt/lower_128bit_debug_test.rs index 1de5e151220..8d1ef82c187 100644 --- a/src/test/mir-opt/lower_128bit_debug_test.rs +++ b/src/test/mir-opt/lower_128bit_debug_test.rs @@ -16,31 +16,32 @@ #[lang="i128_div"] fn i128_div(_x: i128, _y: i128) -> i128 { 3 } #[lang="u128_div"] -fn u128_div(_x: i128, _y: i128) -> i128 { 4 } +fn u128_div(_x: u128, _y: u128) -> u128 { 4 } #[lang="i128_rem"] fn i128_rem(_x: i128, _y: i128) -> i128 { 5 } #[lang="u128_rem"] -fn u128_rem(_x: i128, _y: i128) -> i128 { 6 } +fn u128_rem(_x: u128, _y: u128) -> u128 { 6 } #[lang="i128_addo"] fn i128_addo(_x: i128, _y: i128) -> (i128, bool) { (0, false) } #[lang="u128_addo"] -fn u128_addo(_x: i128, _y: i128) -> (i128, bool) { (1, false) } +fn u128_addo(_x: u128, _y: u128) -> (u128, bool) { (1, false) } #[lang="i128_subo"] fn i128_subo(_x: i128, _y: i128) -> (i128, bool) { (2, false) } #[lang="u128_subo"] -fn u128_subo(_x: i128, _y: i128) -> (i128, bool) { (3, false) } +fn u128_subo(_x: u128, _y: u128) -> (u128, bool) { (3, false) } #[lang="i128_mulo"] fn i128_mulo(_x: i128, _y: i128) -> (i128, bool) { (4, false) } #[lang="u128_mulo"] -fn u128_mulo(_x: i128, _y: i128) -> (i128, bool) { (5, false) } +fn u128_mulo(_x: u128, _y: u128) -> (u128, bool) { (5, false) } #[lang="i128_shlo"] -fn i128_shlo(_x: i128, _y: u32) -> (i128, bool) { (6, false) } +fn i128_shlo(_x: i128, _y: i32) -> (i128, bool) { (6, false) } +#[lang="u128_shlo"] +fn u128_shlo(_x: u128, _y: i32) -> (u128, bool) { (6, false) } #[lang="i128_shro"] -fn i128_shro(_x: i128, _y: u32) -> (i128, bool) { (7, false) } +fn i128_shro(_x: i128, _y: i32) -> (i128, bool) { (7, false) } #[lang="u128_shro"] -fn u128_shro(_x: i128, _y: u32) -> (i128, bool) { (8, false) } - +fn u128_shro(_x: u128, _y: i32) -> (u128, bool) { (8, false) } fn test_signed(mut x: i128) -> i128 { x += 1; @@ -132,7 +133,7 @@ fn main() { // ... // assert(!(_7.1: bool), "attempt to shift left with overflow") -> bb6; // ... -// _7 = const i128_shlo(_1, const 6i32) -> bb12; +// _7 = const u128_shlo(_1, const 6i32) -> 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 15a5535dba4..ba05280e20b 100644 --- a/src/test/mir-opt/lower_128bit_test.rs +++ b/src/test/mir-opt/lower_128bit_test.rs @@ -15,25 +15,32 @@ #[lang="i128_add"] fn i128_add(_x: i128, _y: i128) -> i128 { 0 } +#[lang="u128_add"] +fn u128_add(_x: u128, _y: u128) -> u128 { 0 } #[lang="i128_sub"] fn i128_sub(_x: i128, _y: i128) -> i128 { 1 } +#[lang="u128_sub"] +fn u128_sub(_x: u128, _y: u128) -> u128 { 1 } #[lang="i128_mul"] fn i128_mul(_x: i128, _y: i128) -> i128 { 2 } +#[lang="u128_mul"] +fn u128_mul(_x: u128, _y: u128) -> u128 { 2 } #[lang="i128_div"] fn i128_div(_x: i128, _y: i128) -> i128 { 3 } #[lang="u128_div"] -fn u128_div(_x: i128, _y: i128) -> i128 { 4 } +fn u128_div(_x: u128, _y: u128) -> u128 { 4 } #[lang="i128_rem"] fn i128_rem(_x: i128, _y: i128) -> i128 { 5 } #[lang="u128_rem"] -fn u128_rem(_x: i128, _y: i128) -> i128 { 6 } +fn u128_rem(_x: u128, _y: u128) -> u128 { 6 } #[lang="i128_shl"] -fn i128_shl(_x: i128, _y: u32) -> i128 { 7 } +fn i128_shl(_x: i128, _y: i32) -> i128 { 7 } +#[lang="u128_shl"] +fn u128_shl(_x: u128, _y: i32) -> u128 { 7 } #[lang="i128_shr"] -fn i128_shr(_x: i128, _y: u32) -> i128 { 8 } +fn i128_shr(_x: i128, _y: i32) -> i128 { 8 } #[lang="u128_shr"] -fn u128_shr(_x: i128, _y: u32) -> i128 { 9 } - +fn u128_shr(_x: u128, _y: i32) -> u128 { 9 } fn test_signed(mut x: i128) -> i128 { x += 1; @@ -81,17 +88,17 @@ fn main() { // END rustc.test_signed.Lower128Bit.after.mir // START rustc.test_unsigned.Lower128Bit.after.mir -// _1 = const i128_add(_1, const 1u128) -> bb5; +// _1 = const u128_add(_1, const 1u128) -> bb5; // ... // _1 = const u128_div(_1, const 4u128) -> bb6; // ... // _1 = const u128_rem(_1, const 5u128) -> bb9; // ... -// _1 = const i128_mul(_1, const 3u128) -> bb3; +// _1 = const u128_mul(_1, const 3u128) -> bb3; // ... -// _1 = const i128_sub(_1, const 2u128) -> bb4; +// _1 = const u128_sub(_1, const 2u128) -> bb4; // ... // _1 = const u128_shr(_1, const 7i32) -> bb7; // ... -// _1 = const i128_shl(_1, const 6i32) -> bb8; +// _1 = const u128_shl(_1, const 6i32) -> bb8; // END rustc.test_unsigned.Lower128Bit.after.mir