about summary refs log tree commit diff
diff options
context:
space:
mode:
authorScott McMurray <scottmcm@users.noreply.github.com>2017-11-20 01:54:43 -0800
committerScott McMurray <scottmcm@users.noreply.github.com>2017-11-20 01:54:43 -0800
commit42208c122757fca706bc5224f3a0c7200fae32e9 (patch)
tree83e34bff2c2bfdecea7387d3354a9dc7f3a93b8d
parent6a5a086fd61a87d36cfa3652b279c543601860da (diff)
downloadrust-42208c122757fca706bc5224f3a0c7200fae32e9.tar.gz
rust-42208c122757fca706bc5224f3a0c7200fae32e9.zip
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
-rw-r--r--src/librustc_mir/transform/lower_128bit.rs118
-rw-r--r--src/test/mir-opt/lower_128bit_debug_test.rs22
-rw-r--r--src/test/mir-opt/lower_128bit_test.rs20
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 @@ impl Lower128Bit {
         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 @@ impl Lower128Bit {
                     _ => 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)
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