]> git.lizzy.rs Git - rust.git/commitdiff
Allow Locals to be propagated into and from, but restricted to their own block
authorFélix Fischer <felix91gr@gmail.com>
Thu, 23 Apr 2020 16:25:28 +0000 (12:25 -0400)
committerFélix Fischer <felix91gr@gmail.com>
Tue, 28 Apr 2020 04:44:50 +0000 (00:44 -0400)
src/librustc_mir/transform/const_prop.rs
src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/tuple_literal_propagation/rustc.main.ConstProp.diff
src/test/mir-opt/simplify-arm-identity.rs
src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff [new file with mode: 0644]
src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff [new file with mode: 0644]
src/test/mir-opt/simplify_match/rustc.main.SimplifyBranches-after-copy-prop.diff
src/test/run-fail/divide-by-zero.rs
src/test/run-fail/dst-raw-slice.rs
src/test/run-fail/mod-zero.rs

index ed02ef566a6523bf47d20f6162525ecff0c7b683..b5c2fa24e64616654b5d470ba4bdaff9e1665f11 100644 (file)
@@ -326,6 +326,8 @@ struct ConstPropagator<'mir, 'tcx> {
     // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
     // the last known `SourceInfo` here and just keep revisiting it.
     source_info: Option<SourceInfo>,
+    // Locals we need to forget at the end of the current block
+    locals_of_current_block: BitSet<Local>,
 }
 
 impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> {
@@ -395,6 +397,7 @@ fn new(
             //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
             local_decls: body.local_decls.clone(),
             source_info: None,
+            locals_of_current_block: BitSet::new_empty(body.local_decls.len()),
         }
     }
 
@@ -409,8 +412,10 @@ fn get_const(&self, local: Local) -> Option<OpTy<'tcx>> {
         }
     }
 
-    fn remove_const(&mut self, local: Local) {
-        self.ecx.frame_mut().locals[local] =
+    /// Remove `local` from the pool of `Locals`. Allows writing to them,
+    /// but not reading from them anymore.
+    fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) {
+        ecx.frame_mut().locals[local] =
             LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) };
     }
 
@@ -756,6 +761,8 @@ fn should_const_prop(&mut self, op: OpTy<'tcx>) -> bool {
 enum ConstPropMode {
     /// The `Local` can be propagated into and reads of this `Local` can also be propagated.
     FullConstProp,
+    /// The `Local` can only be propagated into and from its own block.
+    OnlyInsideOwnBlock,
     /// The `Local` can be propagated into but reads cannot be propagated.
     OnlyPropagateInto,
     /// No propagation is allowed at all.
@@ -787,10 +794,18 @@ fn check(body: &Body<'_>) -> IndexVec<Local, ConstPropMode> {
             //        lint for x != y
             // FIXME(oli-obk): lint variables until they are used in a condition
             // FIXME(oli-obk): lint if return value is constant
-            if cpv.local_kinds[local] == LocalKind::Arg || cpv.local_kinds[local] == LocalKind::Var
-            {
+            if cpv.local_kinds[local] == LocalKind::Arg {
                 *val = ConstPropMode::OnlyPropagateInto;
-                trace!("local {:?} can't be const propagated because it's not a temporary", local);
+                trace!(
+                    "local {:?} can't be const propagated because it's a function argument",
+                    local
+                );
+            } else if cpv.local_kinds[local] == LocalKind::Var {
+                *val = ConstPropMode::OnlyInsideOwnBlock;
+                trace!(
+                    "local {:?} will only be propagated inside its block, because it's a user variable",
+                    local
+                );
             }
         }
         cpv.visit_body(&body);
@@ -858,25 +873,35 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio
                 if let Some(local) = place.as_local() {
                     let can_const_prop = self.can_const_prop[local];
                     if let Some(()) = self.const_prop(rval, place_layout, source_info, place) {
-                        if can_const_prop == ConstPropMode::FullConstProp
-                            || can_const_prop == ConstPropMode::OnlyPropagateInto
-                        {
+                        if can_const_prop != ConstPropMode::NoPropagation {
+                            // This will return None for Locals that are from other blocks,
+                            // so it should be okay to propagate from here on down.
                             if let Some(value) = self.get_const(local) {
                                 if self.should_const_prop(value) {
                                     trace!("replacing {:?} with {:?}", rval, value);
                                     self.replace_with_const(rval, value, statement.source_info);
-
-                                    if can_const_prop == ConstPropMode::FullConstProp {
+                                    if can_const_prop == ConstPropMode::FullConstProp
+                                        || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
+                                    {
                                         trace!("propagated into {:?}", local);
                                     }
                                 }
+                                if can_const_prop == ConstPropMode::OnlyInsideOwnBlock {
+                                    trace!(
+                                        "found local restricted to its block. Will remove it from const-prop after block is finished. Local: {:?}",
+                                        local
+                                    );
+                                    self.locals_of_current_block.insert(local);
+                                }
                             }
                         }
                     }
-                    if self.can_const_prop[local] != ConstPropMode::FullConstProp {
+                    if self.can_const_prop[local] == ConstPropMode::OnlyPropagateInto
+                        || self.can_const_prop[local] == ConstPropMode::NoPropagation
+                    {
                         trace!("can't propagate into {:?}", local);
                         if local != RETURN_PLACE {
-                            self.remove_const(local);
+                            Self::remove_const(&mut self.ecx, local);
                         }
                     }
                 }
@@ -915,7 +940,7 @@ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Loca
                         // doesn't use the invalid value
                         match cond {
                             Operand::Move(ref place) | Operand::Copy(ref place) => {
-                                self.remove_const(place.local);
+                                Self::remove_const(&mut self.ecx, place.local);
                             }
                             Operand::Constant(_) => {}
                         }
@@ -992,5 +1017,13 @@ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Loca
             //FIXME(wesleywiser) Call does have Operands that could be const-propagated
             TerminatorKind::Call { .. } => {}
         }
+        // We remove all Locals which are restricted in propagation to their containing blocks.
+        // We wouldn't need to clone, but the borrow checker can't see that we're not aliasing
+        // the locals_of_current_block field, so we need to clone it first.
+        // let ecx = &mut self.ecx;
+        for local in self.locals_of_current_block.iter() {
+            Self::remove_const(&mut self.ecx, local);
+        }
+        self.locals_of_current_block.clear();
     }
 }
index f872696cf94dddd676d2226f259e280b3cb6ff39..0183ff7716cbb6853a8bdfa5132ed040c26978ef 100644 (file)
                                            // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
           StorageLive(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
           StorageLive(_3);                 // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
-          _3 = _1;                         // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
+-         _3 = _1;                         // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
++         _3 = const 1u32;                 // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x00000001))
++                                          // mir::Constant
++                                          // + span: $DIR/scalar_literal_propagation.rs:4:13: 4:14
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
           _2 = const consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
                                            // ty::Const
                                            // + ty: fn(u32) {consume}
index f57b7f78d99aa19ce3c1d45c20662ae8667151ae..1511b361f587ff0db022d899797cc7dc9a7b6960 100644 (file)
                                            // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
           StorageLive(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15
           StorageLive(_3);                 // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
-          _3 = _1;                         // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
+-         _3 = _1;                         // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
++         _3 = (const 1u32, const 2u32);   // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x00000001))
++                                          // mir::Constant
++                                          // + span: $DIR/tuple_literal_propagation.rs:5:13: 5:14
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x00000002))
++                                          // mir::Constant
++                                          // + span: $DIR/tuple_literal_propagation.rs:5:13: 5:14
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
           _2 = const consume(move _3) -> bb1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15
                                            // ty::Const
                                            // + ty: fn((u32, u32)) {consume}
index cc6aab7523f009e8064518ecbd79ca142e00bf33..24e91b3ff611c484c3ad91596c6f663296486d75 100644 (file)
@@ -2,6 +2,7 @@
 // Regression test for issue #66856.
 //
 // compile-flags: -Zmir-opt-level=2
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 enum Src {
     Foo(u8),
diff --git a/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff
new file mode 100644 (file)
index 0000000..bf24bfb
--- /dev/null
@@ -0,0 +1,53 @@
+- // MIR for `main` before SimplifyArmIdentity
++ // MIR for `main` after SimplifyArmIdentity
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify-arm-identity.rs:17:11: 17:11
+      let _1: Src as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+      let mut _2: Dst;                     // in scope 0 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+      let mut _3: isize;                   // in scope 0 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+      let mut _5: u8;                      // in scope 0 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+      scope 1 {
+          debug e => _1;                   // in scope 1 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+          let _4: u8;                      // in scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
+          scope 2 {
+          }
+          scope 3 {
+              debug x => _4;               // in scope 3 at $DIR/simplify-arm-identity.rs:20:18: 20:19
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+          ((_1 as Foo).0: u8) = const 0u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:18:27: 18:28
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+          discriminant(_1) = 0;            // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
+          StorageLive(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+          _3 = const 0isize;               // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+                                           // ty::Const
+                                           // + ty: isize
+                                           // + val: Value(Scalar(0x00000000))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:20:9: 20:20
+                                           // + literal: Const { ty: isize, val: Value(Scalar(0x00000000)) }
+          _4 = ((_1 as Foo).0: u8);        // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
+          ((_2 as Foo).0: u8) = move _4;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          discriminant(_2) = 0;            // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          StorageDead(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7
+          _0 = const ();                   // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:17:11: 23:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:23:1: 23:2
+          return;                          // scope 0 at $DIR/simplify-arm-identity.rs:23:2: 23:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff
new file mode 100644 (file)
index 0000000..ff7183e
--- /dev/null
@@ -0,0 +1,53 @@
+- // MIR for `main` before SimplifyArmIdentity
++ // MIR for `main` after SimplifyArmIdentity
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify-arm-identity.rs:17:11: 17:11
+      let _1: Src as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+      let mut _2: Dst;                     // in scope 0 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+      let mut _3: isize;                   // in scope 0 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+      let mut _5: u8;                      // in scope 0 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+      scope 1 {
+          debug e => _1;                   // in scope 1 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+          let _4: u8;                      // in scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
+          scope 2 {
+          }
+          scope 3 {
+              debug x => _4;               // in scope 3 at $DIR/simplify-arm-identity.rs:20:18: 20:19
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+          ((_1 as Foo).0: u8) = const 0u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:18:27: 18:28
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+          discriminant(_1) = 0;            // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
+          StorageLive(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
+          _3 = const 0isize;               // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+                                           // ty::Const
+                                           // + ty: isize
+                                           // + val: Value(Scalar(0x0000000000000000))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:20:9: 20:20
+                                           // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000000)) }
+          _4 = ((_1 as Foo).0: u8);        // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
+          ((_2 as Foo).0: u8) = move _4;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          discriminant(_2) = 0;            // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
+          StorageDead(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:22:6: 22:7
+          _0 = const ();                   // scope 0 at $DIR/simplify-arm-identity.rs:17:11: 23:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-arm-identity.rs:17:11: 23:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:23:1: 23:2
+          return;                          // scope 0 at $DIR/simplify-arm-identity.rs:23:2: 23:2
+      }
+  }
+  
index 68b1b70c52a80ade71f7bbaab2a3353f1a15bb4a..ae6dfae30b97b64f8826d46c2aaddf8e58a11f2d 100644 (file)
       }
   
       bb0: {
-          nop;                             // scope 0 at $DIR/simplify_match.rs:6:11: 6:31
-          nop;                             // scope 0 at $DIR/simplify_match.rs:6:17: 6:18
-          nop;                             // scope 0 at $DIR/simplify_match.rs:6:21: 6:26
-          nop;                             // scope 1 at $DIR/simplify_match.rs:6:28: 6:29
-          nop;                             // scope 0 at $DIR/simplify_match.rs:6:30: 6:31
--         switchInt(const false) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:7:9: 7:13
--                                          // ty::Const
--                                          // + ty: bool
--                                          // + val: Value(Scalar(0x00))
--                                          // mir::Constant
--                                          // + span: $DIR/simplify_match.rs:6:21: 6:26
--                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+         goto -> bb1;                     // scope 0 at $DIR/simplify_match.rs:7:9: 7:13
+          StorageLive(_1);                 // scope 0 at $DIR/simplify_match.rs:6:11: 6:31
+          StorageLive(_2);                 // scope 0 at $DIR/simplify_match.rs:6:17: 6:18
+          _2 = const false;                // scope 0 at $DIR/simplify_match.rs:6:21: 6:26
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_match.rs:6:21: 6:26
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _1 = const false;                // scope 1 at $DIR/simplify_match.rs:6:28: 6:29
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify_match.rs:6:28: 6:29
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_match.rs:6:30: 6:31
+          goto -> bb1;                     // scope 0 at $DIR/simplify_match.rs:7:9: 7:13
       }
   
       bb1: {
@@ -47,7 +52,7 @@
       }
   
       bb3: {
-          nop;                             // scope 0 at $DIR/simplify_match.rs:10:1: 10:2
+          StorageDead(_1);                 // scope 0 at $DIR/simplify_match.rs:10:1: 10:2
           return;                          // scope 0 at $DIR/simplify_match.rs:10:2: 10:2
       }
   }
index fdb3f4842e50af9574f23aa9280f4dae5bb65d70..ba93563154a3b3958189e8d5fd82cadb58dfad3f 100644 (file)
@@ -1,5 +1,5 @@
 // error-pattern:attempt to divide by zero
-
+#[allow(unconditional_panic)]
 fn main() {
     let y = 0;
     let _z = 1 / y;
index 561b1fb42ed0634cf07a7b2c57b9cf2670b92cc9..2575de7cc58336fbd85028a9be61dd0cb1c060c8 100644 (file)
@@ -1,6 +1,6 @@
 // Test bounds checking for DST raw slices
 // error-pattern:index out of bounds
-
+#[allow(unconditional_panic)]
 fn main() {
     let a: *const [_] = &[1, 2, 3];
     unsafe {
index ac2959fcd38535964a29fabd42a7fb1f426df5ef..f70b3ac920c6116258ae0ccd79ece1d8171b1171 100644 (file)
@@ -1,5 +1,5 @@
 // error-pattern:attempt to calculate the remainder with a divisor of zero
-
+#[allow(unconditional_panic)]
 fn main() {
     let y = 0;
     let _z = 1 % y;