]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_mir/transform/simplify.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / librustc_mir / transform / simplify.rs
index 385fc7ed2cd001d17cc7eb2da7e76f3965d03595..628ac721adc59886ca8954b70940253680357cfb 100644 (file)
 
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc::ty::TyCtxt;
+use rustc::ty::{self, TyCtxt};
 use rustc::mir::*;
 use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext, MutatingUseContext};
-use rustc::session::config::DebugInfo;
 use std::borrow::Cow;
 use crate::transform::{MirPass, MirSource};
 
@@ -44,7 +43,7 @@ impl SimplifyCfg {
     }
 }
 
-pub fn simplify_cfg(body: &mut Body<'_>) {
+pub fn simplify_cfg(body: &mut BodyAndCache<'_>) {
     CfgSimplifier::new(body).simplify();
     remove_dead_blocks(body);
 
@@ -57,7 +56,9 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg {
         Cow::Borrowed(&self.label)
     }
 
-    fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(
+        &self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
+    ) {
         debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body);
         simplify_cfg(body);
     }
@@ -69,7 +70,7 @@ pub struct CfgSimplifier<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
-    pub fn new(body: &'a mut Body<'tcx>) -> Self {
+    pub fn new(body: &'a mut BodyAndCache<'tcx>) -> Self {
         let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks());
 
         // we can't use mir.predecessors() here because that counts
@@ -125,8 +126,9 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
                     changed |= inner_changed;
                 }
 
-                self.basic_blocks[bb].statements.extend(new_stmts);
-                self.basic_blocks[bb].terminator = Some(terminator);
+                let data = &mut self.basic_blocks[bb];
+                data.statements.extend(new_stmts);
+                data.terminator = Some(terminator);
 
                 changed |= inner_changed;
             }
@@ -260,7 +262,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
     }
 }
 
-pub fn remove_dead_blocks(body: &mut Body<'_>) {
+pub fn remove_dead_blocks(body: &mut BodyAndCache<'_>) {
     let mut seen = BitSet::new_empty(body.basic_blocks().len());
     for (bb, _) in traversal::preorder(body) {
         seen.insert(bb.index());
@@ -274,8 +276,8 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
     for alive_index in seen.iter() {
         replacements[alive_index] = BasicBlock::new(used_blocks);
         if alive_index != used_blocks {
-            // Swap the next alive block data with the current available slot. Since alive_index is
-            // non-decreasing this is a valid operation.
+            // Swap the next alive block data with the current available slot. Since
+            // alive_index is non-decreasing this is a valid operation.
             basic_blocks.raw.swap(alive_index, used_blocks);
         }
         used_blocks += 1;
@@ -293,27 +295,23 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
 pub struct SimplifyLocals;
 
 impl<'tcx> MirPass<'tcx> for SimplifyLocals {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(
+        &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
+    ) {
         trace!("running SimplifyLocals on {:?}", source);
         let locals = {
+            let read_only_cache = read_only!(body);
             let mut marker = DeclMarker {
                 locals: BitSet::new_empty(body.local_decls.len()),
                 body,
             };
-            marker.visit_body(body);
+            marker.visit_body(read_only_cache);
             // Return pointer and arguments are always live
             marker.locals.insert(RETURN_PLACE);
             for arg in body.args_iter() {
                 marker.locals.insert(arg);
             }
 
-            // We may need to keep dead user variables live for debuginfo.
-            if tcx.sess.opts.debuginfo == DebugInfo::Full {
-                for local in body.vars_iter() {
-                    marker.locals.insert(local);
-                }
-            }
-
             marker.locals
         };
 
@@ -359,18 +357,25 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> {
         // Ignore stores of constants because `ConstProp` and `CopyProp` can remove uses of many
         // of these locals. However, if the local is still needed, then it will be referenced in
         // another place and we'll mark it as being used there.
-        if ctx == PlaceContext::MutatingUse(MutatingUseContext::Store) {
-            let stmt =
-                &self.body.basic_blocks()[location.block].statements[location.statement_index];
-            if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(c)))) = &stmt.kind {
-                match c.literal.val {
-                    // Keep assignments from unevaluated constants around, since the evaluation
-                    // may report errors, even if the use of the constant is dead code.
-                    interpret::ConstValue::Unevaluated(..) => {}
-                    _ => if p.as_local().is_some() {
-                        trace!("skipping store of const value {:?} to {:?}", c, p);
-                        return;
-                    },
+        if ctx == PlaceContext::MutatingUse(MutatingUseContext::Store) ||
+           ctx == PlaceContext::MutatingUse(MutatingUseContext::Projection) {
+            let block = &self.body.basic_blocks()[location.block];
+            if location.statement_index != block.statements.len() {
+                let stmt =
+                    &block.statements[location.statement_index];
+
+                if let StatementKind::Assign(
+                    box (p, Rvalue::Use(Operand::Constant(c)))
+                ) = &stmt.kind {
+                    match c.literal.val {
+                        // Keep assignments from unevaluated constants around, since the evaluation
+                        // may report errors, even if the use of the constant is dead code.
+                        ty::ConstKind::Unevaluated(..) => {}
+                        _ => if !p.is_indirect() {
+                            trace!("skipping store of const value {:?} to {:?}", c, p);
+                            return;
+                        },
+                    }
                 }
             }
         }
@@ -397,7 +402,7 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
                     self.map[*l].is_some()
                 }
                 StatementKind::Assign(box (place, _)) => {
-                    if let Some(local) = place.as_local() {
+                    if let PlaceBase::Local(local) = place.base {
                         self.map[local].is_some()
                     } else {
                         true