about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Daniel Faria <Nashenas88@users.noreply.github.com>2019-10-10 23:16:44 -0400
committerPaul Daniel Faria <Nashenas88@users.noreply.github.com>2019-12-02 08:30:30 -0500
commit649c73f96d8969f05000a071007bcd050fa8d466 (patch)
tree2f5f8d3bac4b6f6163726592c7f8cd93d00509e7
parentc0592faa67a1fe8fb7425f24899c5538dec23ee1 (diff)
downloadrust-649c73f96d8969f05000a071007bcd050fa8d466.tar.gz
rust-649c73f96d8969f05000a071007bcd050fa8d466.zip
Simplify Cache wrapper to single type, impl Deref on it, fix all compilation errors in librustc_codegen_ssa
-rw-r--r--src/librustc/mir/cache.rs82
-rw-r--r--src/librustc/mir/mod.rs7
-rw-r--r--src/librustc/mir/visit.rs23
-rw-r--r--src/librustc_codegen_ssa/base.rs5
-rw-r--r--src/librustc_codegen_ssa/mir/analyze.rs40
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs12
-rw-r--r--src/librustc_codegen_ssa/mir/mod.rs16
-rw-r--r--src/librustc_codegen_ssa/mir/place.rs2
-rw-r--r--src/librustc_codegen_ssa/mir/rvalue.rs6
-rw-r--r--src/librustc_mir/borrow_check/mod.rs48
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs8
-rw-r--r--src/librustc_mir/shim.rs12
-rw-r--r--src/librustc_mir/transform/ensure_predecessors_cache.rs26
-rw-r--r--src/librustc_mir/transform/generator.rs4
-rw-r--r--src/librustc_mir/transform/mod.rs3
15 files changed, 132 insertions, 162 deletions
diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs
index 4300a5acba4..e218931b749 100644
--- a/src/librustc/mir/cache.rs
+++ b/src/librustc/mir/cache.rs
@@ -6,7 +6,7 @@ use crate::mir::{BasicBlock, BasicBlockData, Body, LocalDecls, Location, Success
 use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
 use rustc_data_structures::graph::dominators::{dominators, Dominators};
 use std::iter;
-use std::ops::{Index, IndexMut};
+use std::ops::{Deref, DerefMut, Index, IndexMut};
 use std::vec::IntoIter;
 
 #[derive(Clone, Debug)]
@@ -111,33 +111,21 @@ impl Cache {
     }
 }
 
-pub struct OwningCache<'tcx> {
+pub struct BodyCache<T> {
     cache: Cache,
-    body: Body<'tcx>,
+    body: T,
 }
 
-impl<'tcx> OwningCache<'tcx> {
-    pub fn borrow(&mut self) -> BorrowedCache<'_, 'tcx> {
-        BorrowedCache {
-            cache: &mut self.cache,
-            body: &self.body,
-        }
-    }
-
-    pub fn borrow_mut(&mut self) -> MutCache<'_, 'tcx> {
-        MutCache {
-            cache: &mut self.cache,
-            body: &mut self.body,
+impl<T> BodyCache<T> {
+    pub fn new(body: T) -> Self {
+        Self {
+            cache: Cache::new(),
+            body
         }
     }
 }
 
-pub struct BorrowedCache<'a, 'tcx> {
-    cache: &'a mut Cache,
-    body: &'a Body<'tcx>
-}
-
-impl<'a, 'tcx> BorrowedCache<'a, 'tcx> {
+impl<'a, 'tcx> BodyCache<&'a Body<'tcx>> {
     #[inline]
     pub fn predecessors_for(&mut self, bb: BasicBlock) -> &[BasicBlock] {
         self.cache.predecessors_for(bb, self.body)
@@ -159,7 +147,14 @@ impl<'a, 'tcx> BorrowedCache<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Index<BasicBlock> for BorrowedCache<'a, 'tcx> {
+impl<'a, 'tcx> Deref for BodyCache<&'a Body<'tcx>> {
+    type Target = Body<'tcx>;
+    fn deref(&self) -> &Body<'tcx> {
+        self.body
+    }
+}
+
+impl<'a, 'tcx> Index<BasicBlock> for BodyCache<&'a Body<'tcx>> {
     type Output = BasicBlockData<'tcx>;
 
     #[inline]
@@ -168,16 +163,16 @@ impl<'a, 'tcx> Index<BasicBlock> for BorrowedCache<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> graph::DirectedGraph for BorrowedCache<'a, 'tcx> {
+impl<'a, 'tcx> graph::DirectedGraph for BodyCache<&'a Body<'tcx>> {
     type Node = BasicBlock;
 }
 
-impl<'a, 'graph, 'tcx> graph::GraphPredecessors<'graph> for BorrowedCache<'a, 'tcx> {
+impl<'a, 'graph, 'tcx> graph::GraphPredecessors<'graph> for BodyCache<&'a Body<'tcx>> {
     type Item = BasicBlock;
     type Iter = IntoIter<BasicBlock>;
 }
 
-impl<'a, 'tcx> graph::WithPredecessors for BorrowedCache<'a, 'tcx> {
+impl<'a, 'tcx> graph::WithPredecessors for BodyCache<&'a Body<'tcx>> {
     fn predecessors(
         &mut self,
         node: Self::Node,
@@ -186,19 +181,19 @@ impl<'a, 'tcx> graph::WithPredecessors for BorrowedCache<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> graph::WithNumNodes for BorrowedCache<'a, 'tcx> {
+impl<'a, 'tcx> graph::WithNumNodes for BodyCache<&'a Body<'tcx>> {
     fn num_nodes(&self) -> usize {
         self.body.num_nodes()
     }
 }
 
-impl<'a, 'tcx> graph::WithStartNode for BorrowedCache<'a, 'tcx> {
+impl<'a, 'tcx> graph::WithStartNode for BodyCache<&'a Body<'tcx>> {
     fn start_node(&self) -> Self::Node {
         self.body.start_node()
     }
 }
 
-impl<'a, 'tcx> graph::WithSuccessors for BorrowedCache<'a, 'tcx> {
+impl<'a, 'tcx> graph::WithSuccessors for BodyCache<&'a Body<'tcx>> {
     fn successors(
         &self,
         node: Self::Node,
@@ -207,17 +202,12 @@ impl<'a, 'tcx> graph::WithSuccessors for BorrowedCache<'a, 'tcx> {
     }
 }
 
-impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for BorrowedCache<'a, 'tcx> {
+impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for BodyCache<&'a Body<'tcx>> {
     type Item = BasicBlock;
     type Iter = iter::Cloned<Successors<'b>>;
 }
 
-pub struct MutCache<'a, 'tcx> {
-    cache: &'a mut Cache,
-    body: &'a mut Body<'tcx>,
-}
-
-impl<'a, 'tcx> MutCache<'a, 'tcx> {
+impl<'a, 'tcx> BodyCache<&'a mut Body<'tcx>> {
     #[inline]
     pub fn body(&mut self) -> &mut Body<'tcx> {
         self.body
@@ -234,7 +224,21 @@ impl<'a, 'tcx> MutCache<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Index<BasicBlock> for MutCache<'a, 'tcx> {
+impl<'a, 'tcx> Deref for BodyCache<&'a mut Body<'tcx>> {
+    type Target = Body<'tcx>;
+
+    fn deref(&self) -> &Body<'tcx> {
+        self.body
+    }
+}
+
+impl<'a, 'tcx> DerefMut for BodyCache<&'a mut Body<'tcx>> {
+    fn deref_mut(&mut self) -> &mut Body<'tcx> {
+        self.body
+    }
+}
+
+impl<'a, 'tcx> Index<BasicBlock> for BodyCache<&'a mut Body<'tcx>> {
     type Output = BasicBlockData<'tcx>;
 
     #[inline]
@@ -243,13 +247,9 @@ impl<'a, 'tcx> Index<BasicBlock> for MutCache<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> IndexMut<BasicBlock> for MutCache<'a, 'tcx> {
+impl<'a, 'tcx> IndexMut<BasicBlock> for BodyCache<&'a mut Body<'tcx>> {
     fn index_mut(&mut self, index: BasicBlock) -> &mut Self::Output {
         self.cache.invalidate_predecessors();
         &mut self.body.basic_blocks[index]
     }
 }
-
-//CloneTypeFoldableAndLiftImpls! {
-//    Cache,
-//}
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index fa435b9a51b..9f718405763 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -38,6 +38,7 @@ use syntax::symbol::Symbol;
 use syntax_pos::{Span, DUMMY_SP};
 
 pub use crate::mir::interpret::AssertMessage;
+pub use crate::mir::cache::BodyCache;
 
 pub mod cache;
 pub mod interpret;
@@ -2596,7 +2597,11 @@ impl Location {
     }
 
     /// Returns `true` if `other` is earlier in the control flow graph than `self`.
-    pub fn is_predecessor_of<'tcx>(&self, other: Location, mut body_cache: cache::BorrowedCache<'_, 'tcx>) -> bool {
+    pub fn is_predecessor_of<'tcx>(
+        &self,
+        other: Location,
+        mut body_cache: BodyCache<&'_ Body<'tcx>>
+    ) -> bool {
         // If we are in the same block as the other location and are an earlier statement
         // then we are a predecessor of `other`.
         if self.block == other.block && self.statement_index < other.statement_index {
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index fbcfe104839..5803663bbec 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -1,7 +1,6 @@
 use crate::ty::subst::SubstsRef;
 use crate::ty::{CanonicalUserTypeAnnotation, Ty};
 use crate::mir::*;
-use crate::mir::cache::*;
 use syntax_pos::Span;
 
 // # The MIR Visitor
@@ -72,7 +71,10 @@ macro_rules! make_mir_visitor {
             // Override these, and call `self.super_xxx` to revert back to the
             // default behavior.
 
-            fn visit_body(&mut self, body_cache: & $($mutability)? cache_type!('tcx $($mutability)?)) {
+            fn visit_body(
+                &mut self,
+                body_cache: & $($mutability)? BodyCache<&'_ $($mutability)? Body<'tcx>>
+            ) {
                 self.super_body(body_cache);
             }
 
@@ -241,8 +243,10 @@ macro_rules! make_mir_visitor {
             // The `super_xxx` methods comprise the default behavior and are
             // not meant to be overridden.
 
-            fn super_body(&mut self,
-                         body_cache: & $($mutability)? cache_type!('tcx $($mutability)?)) {
+            fn super_body(
+                &mut self,
+                body_cache: & $($mutability)? BodyCache<&'_ $($mutability)? Body<'tcx>>
+            ) {
                 let span = body_cache.body().span;
                 if let Some(yield_ty) = &$($mutability)? body_cache.body().yield_ty {
                     self.visit_ty(yield_ty, TyContext::YieldTy(SourceInfo {
@@ -793,7 +797,11 @@ macro_rules! make_mir_visitor {
 
             // Convenience methods
 
-            fn visit_location(&mut self, body_cache: & $($mutability)? cache_type!('tcx $($mutability)?), location: Location) {
+            fn visit_location(
+                &mut self,
+                body_cache: & $($mutability)? BodyCache<&'_ $($mutability)? Body<'tcx>>,
+                location: Location
+            ) {
                 let basic_block = & $($mutability)? body_cache[location.block];
                 if basic_block.statements.len() == location.statement_index {
                     if let Some(ref $($mutability)? terminator) = basic_block.terminator {
@@ -809,11 +817,6 @@ macro_rules! make_mir_visitor {
     }
 }
 
-macro_rules! cache_type {
-    ($tcx:lifetime mut) => {MutCache<'_, $tcx>};
-    ($tcx:lifetime) => {BorrowedCache<'_, $tcx>};
-}
-
 macro_rules! visit_place_fns {
     (mut) => (
         fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs
index 22693beb855..d67a9d3799e 100644
--- a/src/librustc_codegen_ssa/base.rs
+++ b/src/librustc_codegen_ssa/base.rs
@@ -31,6 +31,7 @@ use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::middle::cstore::EncodedMetadata;
 use rustc::middle::lang_items::StartFnLangItem;
 use rustc::middle::weak_lang_items;
+use rustc::mir::BodyCache;
 use rustc::mir::mono::{CodegenUnitNameBuilder, CodegenUnit, MonoItem};
 use rustc::ty::{self, Ty, TyCtxt, Instance};
 use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt};
@@ -374,7 +375,9 @@ pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
     let lldecl = cx.get_fn(instance);
 
     let mir = cx.tcx().instance_mir(instance.def);
-    mir::codegen_mir::<Bx>(cx, lldecl, &mir, instance, sig);
+    // TODO(nashenas88) move this into instance_mir before merging PR
+    let mut mir = BodyCache::new(mir);
+    mir::codegen_mir::<Bx>(cx, lldecl, &mut mir, instance, sig);
 }
 
 /// Creates the `main` function which will initialize the rust runtime and call
diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs
index e44551fcbcd..7a2940a8e67 100644
--- a/src/librustc_codegen_ssa/mir/analyze.rs
+++ b/src/librustc_codegen_ssa/mir/analyze.rs
@@ -4,7 +4,7 @@
 use rustc_index::bit_set::BitSet;
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc::mir::{self, Location, TerminatorKind};
+use rustc::mir::{self, Body, BodyCache, Location, TerminatorKind};
 use rustc::mir::visit::{
     Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext, NonUseContext,
 };
@@ -17,10 +17,10 @@ use super::FunctionCx;
 use crate::traits::*;
 
 pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
-    fx: &FunctionCx<'a, 'tcx, Bx>,
+    fx: &mut FunctionCx<'a, 'tcx, Bx>,
 ) -> BitSet<mir::Local> {
-    let mir = fx.mir;
-    let mut analyzer = LocalAnalyzer::new(fx);
+    let mir = fx.mir.take().unwrap();
+    let mut analyzer = LocalAnalyzer::new(fx, mir);
 
     analyzer.visit_body(mir);
 
@@ -54,11 +54,14 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         }
     }
 
-    analyzer.non_ssa_locals
+    let (mir, non_ssa_locals) = analyzer.finalize();
+    fx.mir = Some(mir);
+    non_ssa_locals
 }
 
 struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
     fx: &'mir FunctionCx<'a, 'tcx, Bx>,
+    mir: &'a mut BodyCache<&'a Body<'tcx>>,
     dominators: Dominators<mir::BasicBlock>,
     non_ssa_locals: BitSet<mir::Local>,
     // The location of the first visited direct assignment to each
@@ -67,27 +70,32 @@ struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
 }
 
 impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
-    fn new(fx: &'mir FunctionCx<'a, 'tcx, Bx>) -> Self {
+    fn new(fx: &'mir FunctionCx<'a, 'tcx, Bx>, mir: &'a mut BodyCache<&'a Body<'tcx>>) -> Self {
         let invalid_location =
-            mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location();
+            mir::BasicBlock::new(mir.basic_blocks().len()).start_location();
         let mut analyzer = LocalAnalyzer {
             fx,
-            dominators: fx.mir.dominators(),
-            non_ssa_locals: BitSet::new_empty(fx.mir.local_decls.len()),
-            first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls)
+            dominators: mir.dominators(),
+            mir,
+            non_ssa_locals: BitSet::new_empty(mir.local_decls.len()),
+            first_assignment: IndexVec::from_elem(invalid_location, &mir.local_decls)
         };
 
         // Arguments get assigned to by means of the function being called
-        for arg in fx.mir.args_iter() {
+        for arg in mir.args_iter() {
             analyzer.first_assignment[arg] = mir::START_BLOCK.start_location();
         }
 
         analyzer
     }
 
+    fn finalize(self) -> (&'a mut BodyCache<&'a Body<'tcx>>, BitSet<mir::Local>) {
+        (self.mir, self.non_ssa_locals)
+    }
+
     fn first_assignment(&self, local: mir::Local) -> Option<Location> {
         let location = self.first_assignment[local];
-        if location.block.index() < self.fx.mir.basic_blocks().len() {
+        if location.block.index() < self.mir.basic_blocks().len() {
             Some(location)
         } else {
             None
@@ -130,7 +138,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
             };
             if is_consume {
                 let base_ty =
-                    mir::Place::ty_from(place_ref.base, proj_base, self.fx.mir, cx.tcx());
+                    mir::Place::ty_from(place_ref.base, proj_base, self.mir.body(), cx.tcx());
                 let base_ty = self.fx.monomorphize(&base_ty);
 
                 // ZSTs don't require any actual memory access.
@@ -139,7 +147,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
                     .ty;
                 let elem_ty = self.fx.monomorphize(&elem_ty);
                 let span = if let mir::PlaceBase::Local(index) = place_ref.base {
-                    self.fx.mir.local_decls[*index].source_info.span
+                    self.mir.local_decls[*index].source_info.span
                 } else {
                     DUMMY_SP
                 };
@@ -243,7 +251,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
 
         if let Some(index) = place.as_local() {
             self.assign(index, location);
-            let decl_span = self.fx.mir.local_decls[index].source_info.span;
+            let decl_span = self.mir.local_decls[index].source_info.span;
             if !self.fx.rvalue_creates_operand(rvalue, decl_span) {
                 self.not_ssa(index);
             }
@@ -348,7 +356,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
             }
 
             PlaceContext::MutatingUse(MutatingUseContext::Drop) => {
-                let ty = self.fx.mir.local_decls[local].ty;
+                let ty = self.mir.local_decls[local].ty;
                 let ty = self.fx.monomorphize(&ty);
 
                 // Only need the place if we're actually dropping it.
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index d76392f7570..d09ff0160db 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -132,7 +132,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'a, 'tcx> {
         } else {
             let llret = bx.call(fn_ptr, &llargs, self.funclet(fx));
             bx.apply_attrs_callsite(&fn_abi, llret);
-            if fx.mir[*self.bb].is_cleanup {
+            if fx.mir.unwrap()[*self.bb].is_cleanup {
                 // Cleanup is always the cold path. Don't inline
                 // drop glue. Also, when there is a deeply-nested
                 // struct, there are "symmetry" issues that cause
@@ -324,7 +324,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         target: mir::BasicBlock,
         unwind: Option<mir::BasicBlock>,
     ) {
-        let ty = location.ty(self.mir, bx.tcx()).ty;
+        let ty = location.ty(self.mir.unwrap().body(), bx.tcx()).ty;
         let ty = self.monomorphize(&ty);
         let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty);
 
@@ -510,7 +510,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         let extra_args = &args[sig.inputs().len()..];
         let extra_args = extra_args.iter().map(|op_arg| {
-            let op_ty = op_arg.ty(self.mir, bx.tcx());
+            let op_ty = op_arg.ty(self.mir.unwrap().body(), bx.tcx());
             self.monomorphize(&op_ty)
         }).collect::<Vec<_>>();
 
@@ -791,7 +791,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         bb: mir::BasicBlock,
     ) {
         let mut bx = self.build_block(bb);
-        let data = &self.mir[bb];
+        let data = &self.mir.unwrap()[bb];
 
         debug!("codegen_block({:?}={:?})", bb, data);
 
@@ -1053,7 +1053,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         target_bb: Bx::BasicBlock
     ) -> Bx::BasicBlock {
         if base::wants_msvc_seh(self.cx.sess()) {
-            span_bug!(self.mir.span, "landing pad was not inserted?")
+            span_bug!(self.mir.unwrap().span, "landing pad was not inserted?")
         }
 
         let mut bx = self.new_block("cleanup");
@@ -1154,7 +1154,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 //
                 // If someone changes that, please update this code path
                 // to create a temporary.
-                span_bug!(self.mir.span, "can't directly store to unaligned value");
+                span_bug!(self.mir.unwrap().span, "can't directly store to unaligned value");
             }
             llargs.push(dest.llval);
             ReturnDest::Nothing
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index 6041232489d..8b127867238 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -1,6 +1,6 @@
 use rustc::ty::{self, Ty, TypeFoldable, Instance};
 use rustc::ty::layout::{TyLayout, HasTyCtxt, FnAbiExt};
-use rustc::mir::{self, Body};
+use rustc::mir::{self, Body, BodyCache};
 use rustc_target::abi::call::{FnAbi, PassMode};
 use crate::base;
 use crate::traits::*;
@@ -21,7 +21,7 @@ use self::operand::{OperandRef, OperandValue};
 pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
     instance: Instance<'tcx>,
 
-    mir: &'a mir::Body<'tcx>,
+    mir: Option<&'a mut BodyCache<&'a mir::Body<'tcx>>>,
 
     debug_context: Option<FunctionDebugContext<Bx::DIScope>>,
 
@@ -122,7 +122,7 @@ impl<'a, 'tcx, V: CodegenObject> LocalRef<'tcx, V> {
 pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     cx: &'a Bx::CodegenCx,
     llfn: Bx::Function,
-    mir: &'a Body<'tcx>,
+    mir: &'a mut BodyCache<&'a Body<'tcx>>,
     instance: Instance<'tcx>,
     sig: ty::FnSig<'tcx>,
 ) {
@@ -159,7 +159,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     let mut fx = FunctionCx {
         instance,
-        mir,
+        mir: Some(mir),
         llfn,
         fn_abi,
         cx,
@@ -174,7 +174,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         per_local_var_debug_info: debuginfo::per_local_var_debug_info(cx.tcx(), mir),
     };
 
-    let memory_locals = analyze::non_ssa_locals(&fx);
+    let memory_locals = analyze::non_ssa_locals(&mut fx);
 
     // Allocate variable and temp allocas
     fx.locals = {
@@ -327,10 +327,10 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     let mut idx = 0;
     let mut llarg_idx = fx.fn_abi.ret.is_indirect() as usize;
 
-    mir.args_iter().enumerate().map(|(arg_index, local)| {
-        let arg_decl = &mir.local_decls[local];
+    mir.unwrap().args_iter().enumerate().map(|(arg_index, local)| {
+        let arg_decl = &mir.unwrap().local_decls[local];
 
-        if Some(local) == mir.spread_arg {
+        if Some(local) == mir.unwrap().spread_arg {
             // This argument (e.g., the last argument in the "rust-call" ABI)
             // is a tuple that was spread at the ABI level and now we have
             // to reconstruct it into a tuple local variable, from multiple
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index 4df5bce9537..8f3c1de9c64 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -591,7 +591,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
     pub fn monomorphized_place_ty(&self, place_ref: &mir::PlaceRef<'_, 'tcx>) -> Ty<'tcx> {
         let tcx = self.cx.tcx();
-        let place_ty = mir::Place::ty_from(place_ref.base, place_ref.projection, self.mir, tcx);
+        let place_ty = mir::Place::ty_from(place_ref.base, place_ref.projection, self.mir.unwrap().body(), tcx);
         self.monomorphize(&place_ty.ty)
     }
 }
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index f7fb4a57140..c1519b6106d 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -460,7 +460,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
 
             mir::Rvalue::Discriminant(ref place) => {
-                let discr_ty = rvalue.ty(&*self.mir, bx.tcx());
+                let discr_ty = rvalue.ty(self.mir.unwrap().body(), bx.tcx());
                 let discr =  self.codegen_place(&mut bx, &place.as_ref())
                     .codegen_get_discr(&mut bx, discr_ty);
                 (bx, OperandRef {
@@ -513,7 +513,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::Rvalue::Aggregate(..) => {
                 // According to `rvalue_creates_operand`, only ZST
                 // aggregate rvalues are allowed to be operands.
-                let ty = rvalue.ty(self.mir, self.cx.tcx());
+                let ty = rvalue.ty(self.mir.unwrap().body(), self.cx.tcx());
                 let operand = OperandRef::new_zst(
                     &mut bx,
                     self.cx.layout_of(self.monomorphize(&ty)),
@@ -710,7 +710,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 true,
             mir::Rvalue::Repeat(..) |
             mir::Rvalue::Aggregate(..) => {
-                let ty = rvalue.ty(self.mir, self.cx.tcx());
+                let ty = rvalue.ty(self.mir.unwrap().body(), self.cx.tcx());
                 let ty = self.monomorphize(&ty);
                 self.cx.spanned_layout_of(ty, span).is_zst()
             }
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 63a8de5eeba..f861a423ae2 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -9,8 +9,8 @@ use rustc::lint::builtin::UNUSED_MUT;
 use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT};
 use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
 use rustc::mir::{
-    ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceElem,
-    PlaceRef, Static, StaticKind
+    ClearCrossCrate, Local, Location, Body, BodyCache, Mutability, Operand, Place, PlaceBase,
+    PlaceElem, PlaceRef, Static, StaticKind
 };
 use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
 use rustc::mir::{Terminator, TerminatorKind};
@@ -167,16 +167,12 @@ fn do_mir_borrowck<'a, 'tcx>(
     let free_regions =
         nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted);
 
-    // Region replacement above very likely invalidated the predecessors cache. It's used later on
-    // when retrieving the dominators from the body, so we need to ensure it exists before locking
-    // the body for changes.
-    body.ensure_predecessors();
-    let body = &body; // no further changes
-    let location_table = &LocationTable::new(body);
+    let body_cache = &BodyCache::new(&body); // no further changes
+    let location_table = &LocationTable::new(body_cache);
 
     let mut errors_buffer = Vec::new();
     let (move_data, move_errors): (MoveData<'tcx>, Option<Vec<(Place<'tcx>, MoveError<'tcx>)>>) =
-        match MoveData::gather_moves(body, tcx) {
+        match MoveData::gather_moves(body_cache, tcx) {
             Ok(move_data) => (move_data, None),
             Err((move_data, move_errors)) => (move_data, Some(move_errors)),
         };
@@ -186,27 +182,27 @@ fn do_mir_borrowck<'a, 'tcx>(
         param_env,
     };
 
-    let dead_unwinds = BitSet::new_empty(body.basic_blocks().len());
+    let dead_unwinds = BitSet::new_empty(body_cache.basic_blocks().len());
     let mut flow_inits = FlowAtLocation::new(do_dataflow(
         tcx,
-        body,
+        body_cache,
         def_id,
         &attributes,
         &dead_unwinds,
-        MaybeInitializedPlaces::new(tcx, body, &mdpe),
+        MaybeInitializedPlaces::new(tcx, body_cache, &mdpe),
         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
     ));
 
     let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(id).is_fn_or_closure();
     let borrow_set = Rc::new(BorrowSet::build(
-            tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
+            tcx, body_cache, locals_are_invalidated_at_exit, &mdpe.move_data));
 
     // If we are in non-lexical mode, compute the non-lexical lifetimes.
     let (regioncx, polonius_output, opt_closure_req) = nll::compute_regions(
         infcx,
         def_id,
         free_regions,
-        body,
+        body_cache,
         &promoted,
         &local_names,
         &upvars,
@@ -227,29 +223,29 @@ fn do_mir_borrowck<'a, 'tcx>(
 
     let flow_borrows = FlowAtLocation::new(do_dataflow(
         tcx,
-        body,
+        body_cache,
         def_id,
         &attributes,
         &dead_unwinds,
-        Borrows::new(tcx, body, param_env, regioncx.clone(), &borrow_set),
+        Borrows::new(tcx, body_cache, param_env, regioncx.clone(), &borrow_set),
         |rs, i| DebugFormatted::new(&rs.location(i)),
     ));
     let flow_uninits = FlowAtLocation::new(do_dataflow(
         tcx,
-        body,
+        body_cache,
         def_id,
         &attributes,
         &dead_unwinds,
-        MaybeUninitializedPlaces::new(tcx, body, &mdpe),
+        MaybeUninitializedPlaces::new(tcx, body_cache, &mdpe),
         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
     ));
     let flow_ever_inits = FlowAtLocation::new(do_dataflow(
         tcx,
-        body,
+        body_cache,
         def_id,
         &attributes,
         &dead_unwinds,
-        EverInitializedPlaces::new(tcx, body, &mdpe),
+        EverInitializedPlaces::new(tcx, body_cache, &mdpe),
         |bd, i| DebugFormatted::new(&bd.move_data().inits[i]),
     ));
 
@@ -261,11 +257,11 @@ fn do_mir_borrowck<'a, 'tcx>(
         _ => true,
     };
 
-    let dominators = body.dominators();
+    let dominators = body_cache.dominators();
 
     let mut mbcx = MirBorrowckCtxt {
         infcx,
-        body,
+        body_cache,
         mir_def_id: def_id,
         param_env,
         move_data: &mdpe.move_data,
@@ -403,7 +399,7 @@ fn do_mir_borrowck<'a, 'tcx>(
 
 crate struct MirBorrowckCtxt<'cx, 'tcx> {
     crate infcx: &'cx InferCtxt<'cx, 'tcx>,
-    body: &'cx Body<'tcx>,
+    body_cache: BodyCache<&'cx Body<'tcx>>,
     mir_def_id: DefId,
     param_env: ty::ParamEnv<'tcx>,
     move_data: &'cx MoveData<'tcx>,
@@ -494,7 +490,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
     type FlowState = Flows<'cx, 'tcx>;
 
     fn body(&self) -> &'cx Body<'tcx> {
-        self.body
+        self.body_cache
     }
 
     fn visit_block_entry(&mut self, bb: BasicBlock, flow_state: &Self::FlowState) {
@@ -644,7 +640,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
                 let tcx = self.infcx.tcx;
 
                 // Compute the type with accurate region information.
-                let drop_place_ty = drop_place.ty(self.body, self.infcx.tcx);
+                let drop_place_ty = drop_place.ty(self.body_cache, self.infcx.tcx);
 
                 // Erase the regions.
                 let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty).ty;
@@ -988,7 +984,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         let mut error_reported = false;
         let tcx = self.infcx.tcx;
-        let body = self.body;
+        let body = self.body_cache;
         let param_env = self.param_env;
         let location_table = self.location_table.start_index(location);
         let borrow_set = self.borrow_set.clone();
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 99bcfa9bc25..4f95aa4a7b0 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -385,15 +385,15 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
         }
     }
 
-    fn visit_body(&mut self, body: &Body<'tcx>) {
-        self.sanitize_type(&"return type", body.return_ty());
-        for local_decl in &body.local_decls {
+    fn visit_body(&mut self, body_cache: &BodyCache<&'_ Body<'tcx>>) {
+        self.sanitize_type(&"return type", body_cache.return_ty());
+        for local_decl in &body_cache.local_decls {
             self.sanitize_type(local_decl, local_decl.ty);
         }
         if self.errors_reported {
             return;
         }
-        self.super_body(body);
+        self.super_body(body_cache);
     }
 }
 
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 938d3f8ce97..734e1a5972e 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -123,17 +123,6 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx
         &add_call_guards::CriticalCallEdges,
     ]);
 
-    // The `ensure_predecessors_cache::EnsurePredecessorsCache` MirPass wasn't used in the
-    // `run_passes` above because the above pass is not always guaranteed to run. There can be
-    // instances where, e.g. a `MirPhase::Validated` pass has already been run on a `Body` by the
-    // time it arrived at this line, and so the above `run_passes` call will NOT run any of the
-    // passes (They do not run if a same or later pass has already been executed on a `Body`).
-    // Adding the ensure pass during the `run_passes` for `MirPhase::Validated` would not
-    // help because the predecessors cache would be invalidated between that pass and this call.
-    // Having the single ensure outside of the `run_passes` list here guarantees that anyone
-    // using this `Body` could call `Body::unwrap_predecessors()` without worrying about a panic.
-    result.ensure_predecessors();
-
     debug!("make_shim({:?}) = {:?}", instance, result);
 
     tcx.arena.alloc(result)
@@ -926,7 +915,6 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> {
         sig.inputs().len(),
         span,
     );
-    body.ensure_predecessors();
 
     crate::util::dump_mir(
         tcx,
diff --git a/src/librustc_mir/transform/ensure_predecessors_cache.rs b/src/librustc_mir/transform/ensure_predecessors_cache.rs
deleted file mode 100644
index db1ef863351..00000000000
--- a/src/librustc_mir/transform/ensure_predecessors_cache.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use rustc::mir::Body;
-use rustc::ty::TyCtxt;
-use crate::transform::{MirPass, MirSource};
-
-pub struct EnsurePredecessorsCache {
-    label: String,
-}
-
-impl EnsurePredecessorsCache {
-    pub fn new<S: Into<String>>(label: S) -> Self {
-        Self {
-            label: label.into(),
-        }
-    }
-}
-
-impl<'tcx> MirPass<'tcx> for EnsurePredecessorsCache {
-    fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        debug!("{}: Ensure predecessors cache: {:?}", self.label, body.span.data());
-        // predecessors is lazily calculated. We want to ensure that the cache is properly filled
-        // before the next stages of compilation, since these following stages will only be allowed
-        // to read the cache and not generate it. If the cache is already up to date, this line is
-        // a nop.
-        body.ensure_predecessors();
-    }
-}
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 8c11d66fb48..37205e65a0a 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -1203,10 +1203,6 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
         // RETURN_PLACE then is a fresh unused local with type ret_ty.
         let new_ret_local = replace_result_variable(ret_ty, body, tcx);
 
-        // Replacing result variables very likely clears the predecessors cache (needed inside of
-        // compute layout), so we need to ensure the cache exists.
-        body.ensure_predecessors();
-
         // Extract locals which are live across suspension point into `layout`
         // `remap` gives a mapping from local indices onto generator struct indices
         // `storage_liveness` tells us which locals have live storage at suspension points
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index e80fb936170..1eac40fc591 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -20,7 +20,6 @@ pub mod check_unsafety;
 pub mod simplify_branches;
 pub mod simplify_try;
 pub mod simplify;
-pub mod ensure_predecessors_cache;
 pub mod erase_regions;
 pub mod no_landing_pads;
 pub mod rustc_peek;
@@ -251,7 +250,6 @@ fn mir_validated(
         &simplify::SimplifyCfg::new("qualify-consts"),
     ]);
 
-    body.ensure_predecessors();
     let promoted = promote_pass.promoted_fragments.into_inner();
     (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
 }
@@ -316,7 +314,6 @@ fn run_optimization_passes<'tcx>(
         &simplify::SimplifyLocals,
 
         &add_call_guards::CriticalCallEdges,
-        &ensure_predecessors_cache::EnsurePredecessorsCache::new("before-opt-dump"),
         &dump_mir::Marker("PreCodegen"),
     ]);
 }