]> git.lizzy.rs Git - rust.git/commitdiff
Handle shifts properly
authorScott McMurray <scottmcm@users.noreply.github.com>
Mon, 20 Nov 2017 09:54:43 +0000 (01:54 -0800)
committerScott McMurray <scottmcm@users.noreply.github.com>
Mon, 20 Nov 2017 09:54:43 +0000 (01:54 -0800)
* 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
src/test/mir-opt/lower_128bit_debug_test.rs
src/test/mir-opt/lower_128bit_test.rs

index 2075792fb817c88bb3ad71d96715f20d13803e5b..9dc5fdadbb195cf9739e2332fe452d8a2720f3e9 100644 (file)
@@ -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<LangItem>
+    -> 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<Ty<'tcx>> {
+        match *self {
+            RhsKind::Unchanged => None,
+            RhsKind::ForceU128 => Some(tcx.types.u128),
+            RhsKind::ForceU32 => Some(tcx.types.u32),
+        }
+    }
+}
+
 fn sign_of_128bit(ty: Ty) -> Option<bool> {
     match ty.sty {
         TypeVariants::TyInt(syntax::ast::IntTy::I128) => Some(true),
@@ -147,39 +201,39 @@ fn sign_of_128bit(ty: Ty) -> Option<bool> {
     }
 }
 
-fn item_for_op(bin_op: BinOp, is_signed: bool) -> Option<LangItem> {
+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<LangItem> {
+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)
index 8d1ef82c187f9fa4a36da44c41ded524938ca72c..4626dc17e1f6efe75dd347cc7c95741d6a0ab6fe 100644 (file)
@@ -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
index ba05280e20b72d85a20653ee726c915a802dcdb1..207cd0ac57eb0d683feb0b8cbe189be0f22ef0ea 100644 (file)
@@ -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