about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Daniel Faria <Nashenas88@users.noreply.github.com>2019-10-23 13:46:23 -0400
committerPaul Daniel Faria <Nashenas88@users.noreply.github.com>2019-12-02 08:30:30 -0500
commit2eed90a621f40aa3a2d56eda16f25315d17c4ca8 (patch)
treee64f332454dd6d845379982e3fe47aee5048bd77
parentc8c266a0fb4c83136cad45aaa0201594b9bd50db (diff)
downloadrust-2eed90a621f40aa3a2d56eda16f25315d17c4ca8.tar.gz
rust-2eed90a621f40aa3a2d56eda16f25315d17c4ca8.zip
Account for new maybe_sideeffect helper that requires predecessors
-rw-r--r--src/librustc/mir/cache.rs165
-rw-r--r--src/librustc/mir/mod.rs4
-rw-r--r--src/librustc/mir/visit.rs13
-rw-r--r--src/librustc_codegen_ssa/mir/analyze.rs29
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs34
-rw-r--r--src/librustc_codegen_ssa/mir/mod.rs19
-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_data_structures/graph/mod.rs2
-rw-r--r--src/librustc_data_structures/graph/reference.rs35
10 files changed, 176 insertions, 133 deletions
diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs
index 103b24ecf61..63d8eba971b 100644
--- a/src/librustc/mir/cache.rs
+++ b/src/librustc/mir/cache.rs
@@ -47,8 +47,7 @@ impl Cache {
     }
 
     #[inline]
-    /// This will recompute the predecessors cache if it is not available
-    pub fn predecessors(&mut self, body: &Body<'_>) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
+    pub fn ensure_predecessors(&mut self, body: &Body<'_>) {
         if self.predecessors.is_none() {
             let mut result = IndexVec::from_elem(vec![], body.basic_blocks());
             for (bb, data) in body.basic_blocks().iter_enumerated() {
@@ -61,7 +60,12 @@ impl Cache {
 
             self.predecessors = Some(result)
         }
+    }
 
+    #[inline]
+    /// This will recompute the predecessors cache if it is not available
+    pub fn predecessors(&mut self, body: &Body<'_>) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
+        self.ensure_predecessors(body);
         self.predecessors.as_ref().unwrap()
     }
 
@@ -71,6 +75,11 @@ impl Cache {
     }
 
     #[inline]
+    fn unwrap_predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] {
+        &self.predecessors.as_ref().unwrap()[bb]
+    }
+
+    #[inline]
     pub fn predecessor_locations<'a>(&'a mut self, loc: Location, body: &'a Body<'a>) -> impl Iterator<Item = Location> + 'a {
         let if_zero_locations = if loc.statement_index == 0 {
             let predecessor_blocks = self.predecessors_for(loc.block, body);
@@ -137,13 +146,17 @@ impl<'a, 'tcx> BodyCache<&'a Body<'tcx>> {
     }
 
     #[inline]
-    pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
-        &self.body.basic_blocks
+    pub fn read_only(mut self) -> ReadOnlyBodyCache<'a, 'tcx> {
+        self.cache.ensure_predecessors(self.body);
+        ReadOnlyBodyCache {
+            cache: self.cache,
+            body: self.body,
+        }
     }
 
     #[inline]
-    pub fn dominators(&mut self) -> Dominators<BasicBlock> {
-        dominators(self)
+    pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+        &self.body.basic_blocks
     }
 }
 
@@ -164,50 +177,6 @@ impl<'a, 'tcx> Index<BasicBlock> for BodyCache<&'a Body<'tcx>> {
     }
 }
 
-impl<'a, 'tcx> graph::DirectedGraph for BodyCache<&'a Body<'tcx>> {
-    type Node = BasicBlock;
-}
-
-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 BodyCache<&'a Body<'tcx>> {
-    fn predecessors(
-        &mut self,
-        node: Self::Node,
-    ) -> <Self as GraphPredecessors<'_>>::Iter {
-        self.predecessors_for(node).to_vec().into_iter()
-    }
-}
-
-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 BodyCache<&'a Body<'tcx>> {
-    fn start_node(&self) -> Self::Node {
-        self.body.start_node()
-    }
-}
-
-impl<'a, 'tcx> graph::WithSuccessors for BodyCache<&'a Body<'tcx>> {
-    fn successors(
-        &self,
-        node: Self::Node,
-    ) -> <Self as GraphSuccessors<'_>>::Iter {
-        self.body.successors(node)
-    }
-}
-
-impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for BodyCache<&'a Body<'tcx>> {
-    type Item = BasicBlock;
-    type Iter = iter::Cloned<Successors<'b>>;
-}
-
 impl<'a, 'tcx> BodyCache<&'a mut Body<'tcx>> {
     #[inline]
     pub fn body(&self) -> &Body<'tcx> {
@@ -259,3 +228,99 @@ impl<'a, 'tcx> IndexMut<BasicBlock> for BodyCache<&'a mut Body<'tcx>> {
         &mut self.body.basic_blocks[index]
     }
 }
+
+pub struct ReadOnlyBodyCache<'a, 'tcx> {
+    cache: Cache,
+    body: &'a Body<'tcx>,
+}
+
+impl ReadOnlyBodyCache<'a, 'tcx> {
+    #[inline]
+    pub fn predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] {
+        self.cache.unwrap_predecessors_for(bb)
+    }
+
+    #[inline]
+    pub fn body(&self) -> &'a Body<'tcx> {
+        self.body
+    }
+
+    #[inline]
+    pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+        &self.body.basic_blocks
+    }
+
+    #[inline]
+    pub fn dominators(&self) -> Dominators<BasicBlock> {
+        dominators(self)
+    }
+
+    pub fn to_owned(self) -> BodyCache<&'a Body<'tcx>> {
+        BodyCache {
+            cache: self.cache,
+            body: self.body,
+        }
+    }
+}
+
+impl graph::DirectedGraph for ReadOnlyBodyCache<'a, 'tcx> {
+    type Node = BasicBlock;
+}
+
+impl graph::GraphPredecessors<'graph> for ReadOnlyBodyCache<'a, 'tcx> {
+    type Item = BasicBlock;
+    type Iter = IntoIter<BasicBlock>;
+}
+
+impl graph::WithPredecessors for ReadOnlyBodyCache<'a, 'tcx> {
+    fn predecessors(
+        &self,
+        node: Self::Node,
+    ) -> <Self as GraphPredecessors<'_>>::Iter {
+        self.cache.unwrap_predecessors_for(node).to_vec().into_iter()
+    }
+}
+
+impl graph::WithNumNodes for ReadOnlyBodyCache<'a, 'tcx> {
+    fn num_nodes(&self) -> usize {
+        self.body.num_nodes()
+    }
+}
+
+impl graph::WithStartNode for ReadOnlyBodyCache<'a, 'tcx> {
+    fn start_node(&self) -> Self::Node {
+        self.body.start_node()
+    }
+}
+
+impl graph::WithSuccessors for ReadOnlyBodyCache<'a, 'tcx> {
+    fn successors(
+        &self,
+        node: Self::Node,
+    ) -> <Self as GraphSuccessors<'_>>::Iter {
+        self.body.successors(node)
+    }
+}
+
+impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for ReadOnlyBodyCache<'a, 'tcx> {
+    type Item = BasicBlock;
+    type Iter = iter::Cloned<Successors<'b>>;
+}
+
+
+impl Deref for ReadOnlyBodyCache<'a, 'tcx> {
+    type Target = Body<'tcx>;
+
+    fn deref(&self) -> &Self::Target {
+        self.body
+    }
+}
+
+impl Index<BasicBlock> for ReadOnlyBodyCache<'a, 'tcx> {
+    type Output = BasicBlockData<'tcx>;
+
+    #[inline]
+    fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
+        &self.body[index]
+    }
+}
\ No newline at end of file
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 9f718405763..57d396ae933 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -38,7 +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 use crate::mir::cache::{BodyCache, ReadOnlyBodyCache};
 
 pub mod cache;
 pub mod interpret;
@@ -2600,7 +2600,7 @@ impl Location {
     pub fn is_predecessor_of<'tcx>(
         &self,
         other: Location,
-        mut body_cache: BodyCache<&'_ Body<'tcx>>
+        body_cache: &ReadOnlyBodyCache<'_, '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`.
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index aa3aeb36e06..7877466fbf6 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -65,6 +65,15 @@ use syntax_pos::Span;
 // variant argument) that does not require visiting, as in
 // `is_cleanup` above.
 
+macro_rules! body_cache_type {
+    (mut $a:lifetime, $tcx:lifetime) => {
+        &mut BodyCache<& $a mut Body<$tcx>>
+    };
+    ($a:lifetime, $tcx:lifetime) => {
+        &ReadOnlyBodyCache<$a, $tcx>
+    };
+}
+
 macro_rules! make_mir_visitor {
     ($visitor_trait_name:ident, $($mutability:ident)?) => {
         pub trait $visitor_trait_name<'tcx> {
@@ -73,7 +82,7 @@ macro_rules! make_mir_visitor {
 
             fn visit_body(
                 &mut self,
-                body_cache: & $($mutability)? BodyCache<&'_ $($mutability)? Body<'tcx>>
+                body_cache: body_cache_type!($($mutability)? '_, 'tcx)
             ) {
                 self.super_body(body_cache);
             }
@@ -245,7 +254,7 @@ macro_rules! make_mir_visitor {
 
             fn super_body(
                 &mut self,
-                body_cache: & $($mutability)? BodyCache<&'_ $($mutability)? Body<'tcx>>
+                body_cache: body_cache_type!($($mutability)? '_, 'tcx)
             ) {
                 macro_rules! body {
                     (mut) => (body_cache.body_mut());
diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs
index 6b405ed2827..fff01178341 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, Body, BodyCache, Location, TerminatorKind};
+use rustc::mir::{self, Location, TerminatorKind};
 use rustc::mir::visit::{
     Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext, NonUseContext,
 };
@@ -16,15 +16,14 @@ use syntax_pos::DUMMY_SP;
 use super::FunctionCx;
 use crate::traits::*;
 
-pub fn non_ssa_locals<'a, 'b, 'c, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
-    fx: &FunctionCx<'a, 'b, 'tcx, Bx>,
-    mir: &'c mut BodyCache<&'b Body<'tcx>>,
+pub fn non_ssa_locals<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    fx: &FunctionCx<'a, 'b, 'tcx, Bx>
 ) -> BitSet<mir::Local> {
-    let mut analyzer = LocalAnalyzer::new(fx, mir);
+    let mut analyzer = LocalAnalyzer::new(fx);
 
-    analyzer.visit_body(mir);
+    analyzer.visit_body(fx.mir);
 
-    for (local, decl) in mir.local_decls.iter_enumerated()
+    for (local, decl) in fx.mir.local_decls.iter_enumerated()
     {
         // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
         // of putting everything in allocas just so we can use llvm.dbg.declare.
@@ -66,20 +65,20 @@ struct LocalAnalyzer<'mir, 'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
     first_assignment: IndexVec<mir::Local, Location>,
 }
 
-impl<'mir, 'a, 'b, 'c, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'b, 'tcx, Bx> {
-    fn new(fx: &'mir FunctionCx<'a, 'b, 'tcx, Bx>, mir: &'c mut BodyCache<&'b Body<'tcx>>) -> Self {
+impl<'mir, 'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'b, 'tcx, Bx> {
+    fn new(fx: &'mir FunctionCx<'a, 'b, 'tcx, Bx>) -> Self {
         let invalid_location =
-            mir::BasicBlock::new(mir.basic_blocks().len()).start_location();
-        let dominators = mir.dominators();
+            mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location();
+        let dominators = fx.mir.dominators();
         let mut analyzer = LocalAnalyzer {
             fx,
             dominators,
-            non_ssa_locals: BitSet::new_empty(mir.local_decls.len()),
-            first_assignment: IndexVec::from_elem(invalid_location, &mir.local_decls)
+            non_ssa_locals: BitSet::new_empty(fx.mir.local_decls.len()),
+            first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls)
         };
 
         // Arguments get assigned to by means of the function being called
-        for arg in mir.args_iter() {
+        for arg in fx.mir.args_iter() {
             analyzer.first_assignment[arg] = mir::START_BLOCK.start_location();
         }
 
@@ -131,7 +130,7 @@ impl<'mir, 'a, 'b, 'c, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, '
             };
             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.fx.mir.body(), cx.tcx());
                 let base_ty = self.fx.monomorphize(&base_ty);
 
                 // ZSTs don't require any actual memory access.
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 53bffc794d7..e2cae0aa565 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -153,7 +153,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'a, 'tcx> {
     // a loop.
     fn maybe_sideeffect<'b, 'tcx2: 'b, Bx: BuilderMethods<'b, 'tcx2>>(
         &self,
-        mir: &'b mir::Body<'tcx>,
+        mir: &mir::ReadOnlyBodyCache<'_, 'tcx>,
         bx: &mut Bx,
         targets: &[mir::BasicBlock],
     ) {
@@ -216,7 +216,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
             let lltrue = helper.llblock(self, targets[0]);
             let llfalse = helper.llblock(self, targets[1]);
             if switch_ty == bx.tcx().types.bool {
-                helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice());
+                helper.maybe_sideeffect(&self.mir, &mut bx, targets.as_slice());
                 // Don't generate trivial icmps when switching on bool
                 if let [0] = values[..] {
                     bx.cond_br(discr.immediate(), llfalse, lltrue);
@@ -230,11 +230,11 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
                 );
                 let llval = bx.const_uint_big(switch_llty, values[0]);
                 let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval);
-                helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice());
+                helper.maybe_sideeffect(&self.mir, &mut bx, targets.as_slice());
                 bx.cond_br(cmp, lltrue, llfalse);
             }
         } else {
-            helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice());
+            helper.maybe_sideeffect(&self.mir, &mut bx, targets.as_slice());
             let (otherwise, targets) = targets.split_last().unwrap();
             bx.switch(
                 discr.immediate(),
@@ -324,13 +324,13 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
         target: mir::BasicBlock,
         unwind: Option<mir::BasicBlock>,
     ) {
-        let ty = location.ty(self.mir, bx.tcx()).ty;
+        let ty = location.ty(self.mir.body(), bx.tcx()).ty;
         let ty = self.monomorphize(&ty);
         let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty);
 
         if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
             // we don't actually need to drop anything.
-            helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
+            helper.maybe_sideeffect(&self.mir, &mut bx, &[target]);
             helper.funclet_br(self, &mut bx, target);
             return
         }
@@ -361,7 +361,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
                  FnAbi::of_instance(&bx, drop_fn))
             }
         };
-        helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
+        helper.maybe_sideeffect(&self.mir, &mut bx, &[target]);
         helper.do_call(self, &mut bx, fn_ty, drop_fn, args,
                        Some((ReturnDest::Nothing, target)),
                        unwind);
@@ -397,7 +397,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
 
         // Don't codegen the panic block if success if known.
         if const_cond == Some(expected) {
-            helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
+            helper.maybe_sideeffect(&self.mir, &mut bx, &[target]);
             helper.funclet_br(self, &mut bx, target);
             return;
         }
@@ -408,7 +408,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
         // Create the failure block and the conditional branch to it.
         let lltarget = helper.llblock(self, target);
         let panic_block = self.new_block("panic");
-        helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
+        helper.maybe_sideeffect(&self.mir, &mut bx, &[target]);
         if expected {
             bx.cond_br(cond, lltarget, panic_block.llbb());
         } else {
@@ -493,7 +493,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
             if let Some(destination_ref) = destination.as_ref() {
                 let &(ref dest, target) = destination_ref;
                 self.codegen_transmute(&mut bx, &args[0], dest);
-                helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
+                helper.maybe_sideeffect(&self.mir, &mut bx, &[target]);
                 helper.funclet_br(self, &mut bx, target);
             } else {
                 // If we are trying to transmute to an uninhabited type,
@@ -510,7 +510,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, '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.body(), bx.tcx());
             self.monomorphize(&op_ty)
         }).collect::<Vec<_>>();
 
@@ -521,7 +521,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
             Some(ty::InstanceDef::DropGlue(_, None)) => {
                 // Empty drop glue; a no-op.
                 let &(_, target) = destination.as_ref().unwrap();
-                helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
+                helper.maybe_sideeffect(&self.mir, &mut bx, &[target]);
                 helper.funclet_br(self, &mut bx, target);
                 return;
             }
@@ -553,7 +553,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
                 let llfn = bx.get_fn_addr(instance);
 
                 if let Some((_, target)) = destination.as_ref() {
-                    helper.maybe_sideeffect(self.mir, &mut bx, &[*target]);
+                    helper.maybe_sideeffect(&self.mir, &mut bx, &[*target]);
                 }
                 // Codegen the actual panic invoke/call.
                 helper.do_call(
@@ -568,7 +568,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
             } else {
                 // a NOP
                 let target = destination.as_ref().unwrap().1;
-                helper.maybe_sideeffect(mir, &mut bx, &[target]);
+                helper.maybe_sideeffect(&self.mir, &mut bx, &[target]);
                 helper.funclet_br(self, &mut bx, destination.as_ref().unwrap().1)
             }
             return;
@@ -682,7 +682,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
             }
 
             if let Some((_, target)) = *destination {
-                helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
+                helper.maybe_sideeffect(&self.mir, &mut bx, &[target]);
                 helper.funclet_br(self, &mut bx, target);
             } else {
                 bx.unreachable();
@@ -776,7 +776,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
         };
 
         if let Some((_, target)) = destination.as_ref() {
-            helper.maybe_sideeffect(self.mir, &mut bx, &[*target]);
+            helper.maybe_sideeffect(&self.mir, &mut bx, &[*target]);
         }
         helper.do_call(self, &mut bx, fn_ty, fn_ptr, &llargs,
                        destination.as_ref().map(|&(_, target)| (ret_dest, target)),
@@ -827,7 +827,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
             }
 
             mir::TerminatorKind::Goto { target } => {
-                helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
+                helper.maybe_sideeffect(&self.mir, &mut bx, &[target]);
                 helper.funclet_br(self, &mut bx, target);
             }
 
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index db7d0bfa6be..a58b13ce102 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -21,7 +21,7 @@ use self::operand::{OperandRef, OperandValue};
 pub struct FunctionCx<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
     instance: Instance<'tcx>,
 
-    mir: &'b mir::Body<'tcx>,
+    mir: &'b mir::ReadOnlyBodyCache<'a, 'tcx>,
 
     debug_context: Option<FunctionDebugContext<Bx::DIScope>>,
 
@@ -156,10 +156,11 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         }).collect();
 
     let (landing_pads, funclets) = create_funclets(&mir, &mut bx, &cleanup_kinds, &block_bxs);
-
+    let mir_body = mir.body();
+    let readonly_mir = mir.read_only();
     let mut fx = FunctionCx {
         instance,
-        mir: mir.body(),
+        mir: &readonly_mir,
         llfn,
         fn_abi,
         cx,
@@ -174,14 +175,14 @@ 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, &mut mir);
+    let memory_locals = analyze::non_ssa_locals(&fx);
 
     // Allocate variable and temp allocas
     fx.locals = {
         let args = arg_local_refs(&mut bx, &fx, &memory_locals);
 
         let mut allocate_local = |local| {
-            let decl = &mir.local_decls[local];
+            let decl = &mir_body.local_decls[local];
             let layout = bx.layout_of(fx.monomorphize(&decl.ty));
             assert!(!layout.ty.has_erasable_regions());
 
@@ -207,7 +208,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         let retptr = allocate_local(mir::RETURN_PLACE);
         iter::once(retptr)
             .chain(args.into_iter())
-            .chain(mir.vars_and_temps_iter().map(allocate_local))
+            .chain(mir_body.vars_and_temps_iter().map(allocate_local))
             .collect()
     };
 
@@ -226,8 +227,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         debug_context.source_locations_enabled = true;
     }
 
-    let rpo = traversal::reverse_postorder(&mir);
-    let mut visited = BitSet::new_empty(mir.basic_blocks().len());
+    let rpo = traversal::reverse_postorder(&mir_body);
+    let mut visited = BitSet::new_empty(mir_body.basic_blocks().len());
 
     // Codegen the body of each block using reverse postorder
     for (bb, _) in rpo {
@@ -237,7 +238,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     // Remove blocks that haven't been visited, or have no
     // predecessors.
-    for bb in mir.basic_blocks().indices() {
+    for bb in mir_body.basic_blocks().indices() {
         // Unreachable block
         if !visited.contains(bb.index()) {
             debug!("codegen_mir: block {:?} was not visited", bb);
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index 245998bd87d..34f2b56adee 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -591,7 +591,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, '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.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 5180f4376a6..19554156b22 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -460,7 +460,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
             }
 
             mir::Rvalue::Discriminant(ref place) => {
-                let discr_ty = rvalue.ty(self.mir, bx.tcx());
+                let discr_ty = rvalue.ty(self.mir.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, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, '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.body(), self.cx.tcx());
                 let operand = OperandRef::new_zst(
                     &mut bx,
                     self.cx.layout_of(self.monomorphize(&ty)),
@@ -714,7 +714,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'b, 'tcx, Bx> {
                 true,
             mir::Rvalue::Repeat(..) |
             mir::Rvalue::Aggregate(..) => {
-                let ty = rvalue.ty(self.mir, self.cx.tcx());
+                let ty = rvalue.ty(self.mir.body(), self.cx.tcx());
                 let ty = self.monomorphize(&ty);
                 self.cx.spanned_layout_of(ty, span).is_zst()
             }
diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs
index 9ce60d207ad..37335799d19 100644
--- a/src/librustc_data_structures/graph/mod.rs
+++ b/src/librustc_data_structures/graph/mod.rs
@@ -50,7 +50,7 @@ where
     Self: for<'graph> GraphPredecessors<'graph, Item = <Self as DirectedGraph>::Node>,
 {
     fn predecessors(
-        &mut self,
+        &self,
         node: Self::Node,
     ) -> <Self as GraphPredecessors<'_>>::Iter;
 }
diff --git a/src/librustc_data_structures/graph/reference.rs b/src/librustc_data_structures/graph/reference.rs
index bc4458334d5..eab217692d0 100644
--- a/src/librustc_data_structures/graph/reference.rs
+++ b/src/librustc_data_structures/graph/reference.rs
@@ -4,20 +4,11 @@ impl<'graph, G: DirectedGraph> DirectedGraph for &'graph G {
     type Node = G::Node;
 }
 
-impl<'graph, G: DirectedGraph> DirectedGraph for &'graph mut G {
-    type Node = G::Node;
-}
-
 impl<'graph, G: WithNumNodes> WithNumNodes for &'graph G {
     fn num_nodes(&self) -> usize {
         (**self).num_nodes()
     }
 }
-impl<'graph, G: WithNumNodes> WithNumNodes for &'graph mut G {
-    fn num_nodes(&self) -> usize {
-        (**self).num_nodes()
-    }
-}
 
 impl<'graph, G: WithStartNode> WithStartNode for &'graph G {
     fn start_node(&self) -> Self::Node {
@@ -25,25 +16,13 @@ impl<'graph, G: WithStartNode> WithStartNode for &'graph G {
     }
 }
 
-impl<'graph, G: WithStartNode> WithStartNode for &'graph mut G {
-    fn start_node(&self) -> Self::Node {
-        (**self).start_node()
-    }
-}
-
 impl<'graph, G: WithSuccessors> WithSuccessors for &'graph G {
     fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter {
         (**self).successors(node)
     }
 }
-impl<'graph, G: WithSuccessors> WithSuccessors for &'graph mut G {
-    fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter {
-        (**self).successors(node)
-    }
-}
-
-impl<'graph, G: WithPredecessors> WithPredecessors for &'graph mut G {
-    fn predecessors(&mut self,
+impl<'graph, G: WithPredecessors> WithPredecessors for &'graph G {
+    fn predecessors(&self,
                     node: Self::Node)
                     -> <Self as GraphPredecessors<'_>>::Iter {
         (**self).predecessors(node)
@@ -55,17 +34,7 @@ impl<'iter, 'graph, G: WithPredecessors> GraphPredecessors<'iter> for &'graph G
     type Iter = <G as GraphPredecessors<'iter>>::Iter;
 }
 
-impl<'iter, 'graph, G: WithPredecessors> GraphPredecessors<'iter> for &'graph mut G {
-    type Item = G::Node;
-    type Iter = <G as GraphPredecessors<'iter>>::Iter;
-}
-
 impl<'iter, 'graph, G: WithSuccessors> GraphSuccessors<'iter> for &'graph G {
     type Item = G::Node;
     type Iter = <G as GraphSuccessors<'iter>>::Iter;
 }
-
-impl<'iter, 'graph, G: WithSuccessors> GraphSuccessors<'iter> for &'graph mut G {
-    type Item = G::Node;
-    type Iter = <G as GraphSuccessors<'iter>>::Iter;
-}