]> git.lizzy.rs Git - rust.git/commitdiff
Limit storage duration of inlined always live locals
authorTomasz Miąsko <tomasz.miasko@gmail.com>
Sun, 15 Nov 2020 00:00:00 +0000 (00:00 +0000)
committerTomasz Miąsko <tomasz.miasko@gmail.com>
Sun, 15 Nov 2020 00:00:00 +0000 (00:00 +0000)
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_mir/src/transform/inline.rs
src/test/mir-opt/inline/inline_diverging.h.Inline.diff
src/test/mir-opt/inline/inline_generator.main.Inline.diff
src/test/mir-opt/inline/inline_shims.drop.Inline.diff
src/test/ui/mir/auxiliary/issue_76375_aux.rs
src/test/ui/mir/issue-76375.rs

index 5fe7b0f647dcdae7fd8c85153cdeb0e05dc43dae..454cdad2e6a788a7951e827195ca1f1b633ef104 100644 (file)
@@ -420,7 +420,9 @@ pub fn args_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator {
     /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
     /// locals that are neither arguments nor the return place).
     #[inline]
-    pub fn vars_and_temps_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator {
+    pub fn vars_and_temps_iter(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = Local> + ExactSizeIterator {
         let arg_count = self.arg_count;
         let local_count = self.local_decls.len();
         (arg_count + 1..local_count).map(Local::new)
index aae98f5b6d8d691a1091b95814568e5f875cb06d..220fc06da8610dd10f4a9a0b4c2cb3ea3668f2ac 100644 (file)
@@ -459,6 +459,7 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
                     tcx: self.tcx,
                     callsite_span: callsite.source_info.span,
                     body_span: callee_body.span,
+                    always_live_locals: BitSet::new_filled(callee_body.local_decls.len()),
                 };
 
                 // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones
@@ -490,6 +491,34 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
                     }
                 }
 
+                // If there are any locals without storage markers, give them storage only for the
+                // duration of the call.
+                for local in callee_body.vars_and_temps_iter() {
+                    if integrator.always_live_locals.contains(local) {
+                        let new_local = integrator.map_local(local);
+                        caller_body[callsite.block].statements.push(Statement {
+                            source_info: callsite.source_info,
+                            kind: StatementKind::StorageLive(new_local),
+                        });
+                    }
+                }
+                if let Some(block) = callsite.target {
+                    // To avoid repeated O(n) insert, push any new statements to the end and rotate
+                    // the slice once.
+                    let mut n = 0;
+                    for local in callee_body.vars_and_temps_iter().rev() {
+                        if integrator.always_live_locals.contains(local) {
+                            let new_local = integrator.map_local(local);
+                            caller_body[block].statements.push(Statement {
+                                source_info: callsite.source_info,
+                                kind: StatementKind::StorageDead(new_local),
+                            });
+                            n += 1;
+                        }
+                    }
+                    caller_body[block].statements.rotate_right(n);
+                }
+
                 // Insert all of the (mapped) parts of the callee body into the caller.
                 caller_body.local_decls.extend(
                     // FIXME(eddyb) make `Range<Local>` iterable so that we can use
@@ -670,6 +699,7 @@ struct Integrator<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     callsite_span: Span,
     body_span: Span,
+    always_live_locals: BitSet<Local>,
 }
 
 impl<'a, 'tcx> Integrator<'a, 'tcx> {
@@ -759,6 +789,15 @@ fn visit_retag(&mut self, kind: &mut RetagKind, place: &mut Place<'tcx>, loc: Lo
         }
     }
 
+    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
+        if let StatementKind::StorageLive(local) | StatementKind::StorageDead(local) =
+            statement.kind
+        {
+            self.always_live_locals.remove(local);
+        }
+        self.super_statement(statement, location);
+    }
+
     fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, loc: Location) {
         // Don't try to modify the implicit `_0` access on return (`return` terminators are
         // replaced down below anyways).
index b728ad4b42899bd56f378988156a32a30631f615..07994eb3c16613170e83220a715df13a0c14d475 100644 (file)
@@ -40,6 +40,7 @@
 -                                          // mir::Constant
                                            // + span: $DIR/inline-diverging.rs:22:16: 22:21
                                            // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar(<ZST>)) }
++         StorageLive(_6);                 // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
 +         StorageLive(_3);                 // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
 +         StorageLive(_4);                 // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
 +         _4 = &_2;                        // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
index aa32daa82dd51135f81ceb0b2e2f91f03adbb1a8..99497a6fc791c18525b8f148e2a40769ee21cfb2 100644 (file)
 -                                          // + literal: Const { ty: for<'r> fn(std::pin::Pin<&'r mut impl std::ops::Generator<bool>>, bool) -> std::ops::GeneratorState<<impl std::ops::Generator<bool> as std::ops::Generator<bool>>::Yield, <impl std::ops::Generator<bool> as std::ops::Generator<bool>>::Return> {<impl std::ops::Generator<bool> as std::ops::Generator<bool>>::resume}, val: Value(Scalar(<ZST>)) }
 +         StorageLive(_7);                 // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         _7 = const false;                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
++         StorageLive(_8);                 // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
++         StorageLive(_9);                 // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         _9 = discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]))); // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
 +         switchInt(move _9) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
       }
   
 -     bb3: {
 +     bb1: {
++         StorageDead(_9);                 // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
++         StorageDead(_8);                 // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         StorageDead(_7);                 // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
           StorageDead(_2);                 // scope 0 at $DIR/inline-generator.rs:9:45: 9:46
           StorageDead(_4);                 // scope 0 at $DIR/inline-generator.rs:9:46: 9:47
index 503d8bc6b7a68d291de30a9c3968ef36698dbeb6..092ff42c3b66da9c156ed8c1421fe806f155ff30 100644 (file)
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-shims.rs:12:14: 12:37
 -                                          // + literal: Const { ty: unsafe fn(*mut std::option::Option<B>) {std::intrinsics::drop_in_place::<std::option::Option<B>>}, val: Value(Scalar(<ZST>)) }
++         StorageLive(_6);                 // scope 2 at $DIR/inline-shims.rs:12:14: 12:40
++         StorageLive(_7);                 // scope 2 at $DIR/inline-shims.rs:12:14: 12:40
 +         _6 = discriminant((*_5));        // scope 3 at $DIR/inline-shims.rs:12:14: 12:40
 +         switchInt(move _6) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $DIR/inline-shims.rs:12:14: 12:40
       }
   
       bb2: {
++         StorageDead(_7);                 // scope 2 at $DIR/inline-shims.rs:12:14: 12:40
++         StorageDead(_6);                 // scope 2 at $DIR/inline-shims.rs:12:14: 12:40
           StorageDead(_5);                 // scope 2 at $DIR/inline-shims.rs:12:39: 12:40
           return;                          // scope 0 at $DIR/inline-shims.rs:13:2: 13:2
 +     }
index f8b318d58ba2adb115f16953c71ad723561557c8..72f32ecf7ea22602d1e54cf18e3c5712ea897fd8 100644 (file)
@@ -1,8 +1,8 @@
 // edition:2018
-// compile-flags: -Z mir-opt-level=2 -Z unsound-mir-opts
+// compile-flags: -Z mir-opt-level=2
 
 #[inline(always)]
-pub fn f(s: bool) -> String {
+pub fn copy_prop(s: bool) -> String {
     let a = "Hello world!".to_string();
     let b = a;
     let c = b;
@@ -12,3 +12,9 @@ pub fn f(s: bool) -> String {
         String::new()
     }
 }
+
+#[inline(always)]
+pub fn dest_prop(x: &[u8]) -> &[u8] {
+    let y = &x[..x.len()];
+    y
+}
index ef459f6a28ec8864669d944a5b889a0d3a47bcde..a7772cb1fe68dba6d78b4efcc7488374bcca5373 100644 (file)
@@ -1,6 +1,8 @@
+// Regression test for issue #76375.
+//
 // edition:2018
 // build-pass
-// compile-flags: -Z mir-opt-level=2 -L.
+// compile-flags: -Z mir-opt-level=2
 // aux-build:issue_76375_aux.rs
 
 #![crate_type = "lib"]
@@ -8,8 +10,18 @@
 extern crate issue_76375_aux;
 
 pub async fn g() {
-    issue_76375_aux::f(true);
+    issue_76375_aux::copy_prop(true);
     h().await;
 }
 
+pub async fn u() {
+    let b = [0u8; 32];
+    let mut i = 0;
+    while i != 10 {
+        issue_76375_aux::dest_prop(&b);
+        h().await;
+        i += 1;
+    }
+}
+
 pub async fn h() {}