diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs deleted file mode 100644 index 1f604877841a7..0000000000000 --- a/src/librustc/mir/cache.rs +++ /dev/null @@ -1,73 +0,0 @@ -use rustc_data_structures::indexed_vec::IndexVec; -use rustc_data_structures::sync::{RwLock, MappedReadGuard, ReadGuard}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; -use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; -use crate::ich::StableHashingContext; -use crate::mir::{Body, BasicBlock}; - -#[derive(Clone, Debug)] -pub struct Cache { - predecessors: RwLock>>> -} - - -impl rustc_serialize::Encodable for Cache { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - Encodable::encode(&(), s) - } -} - -impl rustc_serialize::Decodable for Cache { - fn decode(d: &mut D) -> Result { - Decodable::decode(d).map(|_v: ()| Self::new()) - } -} - -impl<'a> HashStable> for Cache { - fn hash_stable(&self, - _: &mut StableHashingContext<'a>, - _: &mut StableHasher) { - // Do nothing. - } -} - -impl Cache { - pub fn new() -> Self { - Cache { - predecessors: RwLock::new(None) - } - } - - pub fn invalidate(&self) { - // FIXME: consider being more fine-grained - *self.predecessors.borrow_mut() = None; - } - - pub fn predecessors( - &self, - body: &Body<'_> - ) -> MappedReadGuard<'_, IndexVec>> { - if self.predecessors.borrow().is_none() { - *self.predecessors.borrow_mut() = Some(calculate_predecessors(body)); - } - - ReadGuard::map(self.predecessors.borrow(), |p| p.as_ref().unwrap()) - } -} - -fn calculate_predecessors(body: &Body<'_>) -> IndexVec> { - let mut result = IndexVec::from_elem(vec![], body.basic_blocks()); - for (bb, data) in body.basic_blocks().iter_enumerated() { - if let Some(ref term) = data.terminator { - for &tgt in term.successors() { - result[tgt].push(bb); - } - } - } - - result -} - -CloneTypeFoldableAndLiftImpls! { - Cache, -} diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 92efcf44dea36..f9326af2340f6 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -26,7 +26,6 @@ use rustc_data_structures::graph::dominators::{dominators, Dominators}; use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::sync::MappedReadGuard; use rustc_macros::HashStable; use rustc_serialize::{Encodable, Decodable}; use smallvec::SmallVec; @@ -42,7 +41,6 @@ use syntax_pos::{Span, DUMMY_SP}; pub use crate::mir::interpret::AssertMessage; -mod cache; pub mod interpret; pub mod mono; pub mod tcx; @@ -162,7 +160,7 @@ pub struct Body<'tcx> { pub span: Span, /// A cache for various calculations. - cache: cache::Cache, + predecessors_cache: Option>>, } impl<'tcx> Body<'tcx> { @@ -200,7 +198,7 @@ impl<'tcx> Body<'tcx> { __upvar_debuginfo_codegen_only_do_not_use, spread_arg: None, span, - cache: cache::Cache::new(), + predecessors_cache: None, control_flow_destroyed, } } @@ -212,26 +210,73 @@ impl<'tcx> Body<'tcx> { #[inline] pub fn basic_blocks_mut(&mut self) -> &mut IndexVec> { - self.cache.invalidate(); &mut self.basic_blocks } + pub fn basic_block_terminator_opt_mut(&mut self, bb: BasicBlock) -> &mut Option> { + self.predecessors_cache = None; + &mut self.basic_blocks[bb].terminator + } + + pub fn basic_block_terminator_mut(&mut self, bb: BasicBlock) -> &mut Terminator<'tcx> { + self.predecessors_cache = None; +/* + let data = &mut self.basic_blocks[bb]; + if let Some(cache) = self.predecessors_cache.as_mut() { + for successor in data.terminator().successors() { + let successor_vec = &mut cache[*successor]; + for i in (0..successor_vec.len()).rev() { + if successor_vec[i] == bb { + successor_vec.swap_remove(i); + break; + } + } + } + } +*/ + + self.basic_blocks[bb].terminator_mut() + } + #[inline] pub fn basic_blocks_and_local_decls_mut( &mut self, ) -> (&mut IndexVec>, &mut LocalDecls<'tcx>) { - self.cache.invalidate(); (&mut self.basic_blocks, &mut self.local_decls) } #[inline] - pub fn predecessors(&self) -> MappedReadGuard<'_, IndexVec>> { - self.cache.predecessors(self) + pub fn unwrap_predecessors(&self) -> &IndexVec> { + assert!(self.predecessors_cache.is_some()); + self.predecessors_cache.as_ref().unwrap() } #[inline] - pub fn predecessors_for(&self, bb: BasicBlock) -> MappedReadGuard<'_, Vec> { - MappedReadGuard::map(self.predecessors(), |p| &p[bb]) + pub fn predecessors(&mut self) -> &IndexVec> { + if self.predecessors_cache.is_none() { + self.predecessors_cache = Some(self.calculate_predecessors()) + } + + self.predecessors_cache.as_ref().unwrap() + } + + fn calculate_predecessors(&self) -> IndexVec> { + let mut result = IndexVec::from_elem(vec![], self.basic_blocks()); + for (bb, data) in self.basic_blocks().iter_enumerated() { + if let Some(ref term) = data.terminator { + for &tgt in term.successors() { + result[tgt].push(bb); + } + } + } + + result + } + + #[inline] + pub fn predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] { + // TODO(nashenas88) could this be predecessors sometimes too? + &self.unwrap_predecessors()[bb] } #[inline] @@ -422,7 +467,7 @@ impl_stable_hash_for!(struct Body<'tcx> { spread_arg, control_flow_destroyed, span, - cache + predecessors_cache }); impl<'tcx> Index for Body<'tcx> { @@ -1006,6 +1051,8 @@ impl BasicBlock { } } +CloneTypeFoldableAndLiftImpls!{ BasicBlock, } + /////////////////////////////////////////////////////////////////////////// // BasicBlockData and Terminator @@ -1336,6 +1383,10 @@ impl<'tcx> BasicBlockData<'tcx> { BasicBlockData { statements: vec![], terminator, is_cleanup: false } } + pub fn terminator_opt(&self) -> &Option> { + &self.terminator + } + /// Accessor for terminator. /// /// Terminator may not be None after construction of the basic block is complete. This accessor @@ -1344,10 +1395,17 @@ impl<'tcx> BasicBlockData<'tcx> { self.terminator.as_ref().expect("invalid terminator state") } - pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> { + // This cannot be public since changing the terminator will break the predecessors cache in Body + // To do so outside of this module, use Body::basic_block_terminator_mut(BasicBlock) + fn terminator_mut(&mut self) -> &mut Terminator<'tcx> { self.terminator.as_mut().expect("invalid terminator state") } + // This can be public since changing the kind will not break the predecessors cache in Body + pub fn terminator_kind_mut(&mut self) -> &mut TerminatorKind<'tcx> { + &mut self.terminator_mut().kind + } + pub fn retain_statements(&mut self, mut f: F) where F: FnMut(&mut Statement<'_>) -> bool, @@ -2625,7 +2683,7 @@ impl<'tcx> graph::WithPredecessors for Body<'tcx> { &self, node: Self::Node, ) -> >::Iter { - self.predecessors_for(node).clone().into_iter() + self.predecessors_for(node).to_vec().into_iter() } } @@ -2685,13 +2743,13 @@ impl Location { } // If we're in another block, then we want to check that block is a predecessor of `other`. - let mut queue: Vec = body.predecessors_for(other.block).clone(); + let mut queue: Vec = body.predecessors_for(other.block).to_vec(); let mut visited = FxHashSet::default(); while let Some(block) = queue.pop() { // If we haven't visited this block before, then make sure we visit it's predecessors. if visited.insert(block) { - queue.append(&mut body.predecessors_for(block).clone()); + queue.extend(body.predecessors_for(block).iter().cloned()); } else { continue; } @@ -2964,7 +3022,7 @@ BraceStructTypeFoldableImpl! { spread_arg, control_flow_destroyed, span, - cache, + predecessors_cache, } } diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index 1416a5f0a6e9f..87f4541f797b8 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -55,7 +55,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { let data = &self.body[idx]; - if let Some(ref term) = data.terminator { + if let Some(ref term) = data.terminator_opt() { self.worklist.extend(term.successors()); } @@ -117,7 +117,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { let data = &po.body[root]; - if let Some(ref term) = data.terminator { + if let Some(ref term) = data.terminator_opt() { po.visited.insert(root); po.visit_stack.push((root, term.successors())); po.traverse_successor(); @@ -186,7 +186,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { }; if self.visited.insert(bb) { - if let Some(term) = &self.body[bb].terminator { + if let Some(term) = &self.body[bb].terminator_opt() { self.visit_stack.push((bb, term.successors())); } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 1e3b9eb29c79d..0cc16833f9523 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -847,6 +847,7 @@ macro_rules! make_mir_visitor { fn visit_location(&mut self, body: & $($mutability)? Body<'tcx>, location: Location) { let basic_block = & $($mutability)? body[location.block]; if basic_block.statements.len() == location.statement_index { + // TODO(nashenas88) how to ensure we clear the cache only in the mutable case... if let Some(ref $($mutability)? terminator) = basic_block.terminator { self.visit_terminator(terminator, location) } diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index aa3971a1da81a..aa117b8d51fa1 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -369,7 +369,7 @@ fn create_funclets<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let funclet; let ret_llbb; - match mir[bb].terminator.as_ref().map(|t| &t.kind) { + match mir[bb].terminator_opt().as_ref().map(|t| &t.kind) { // This is a basic block that we're aborting the program for, // notably in an `extern` function. These basic blocks are inserted // so that we assert that `extern` functions do indeed not panic, diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 5bccd2835c980..85d5143368e02 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -522,7 +522,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .. }, .. - }) = bbd.terminator { + }) = bbd.terminator_opt() { if let Some(source) = BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx) { diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 3ed6b4ff34678..734135c324a41 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -64,7 +64,7 @@ impl<'tcx> CFG<'tcx> { source_info: SourceInfo, kind: TerminatorKind<'tcx>) { debug!("terminating block {:?} <- {:?}", block, kind); - debug_assert!(self.block_data(block).terminator.is_none(), + debug_assert!(self.block_data(block).terminator_opt().is_none(), "terminate: block {:?}={:?} already has a terminator set", block, self.block_data(block)); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 647d7515fe98d..ea955f792b6ef 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -754,7 +754,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { yield_ty: Option>) -> Body<'tcx> { for (index, block) in self.cfg.basic_blocks.iter().enumerate() { - if block.terminator.is_none() { + if block.terminator_opt().is_none() { span_bug!(self.fn_span, "no terminator on block {:?}", index); } } diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index a86fcb30f4d36..393bee6d87803 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -98,7 +98,7 @@ fn precompute_borrows_out_of_scope<'tcx>( // Add successor BBs to the work list, if necessary. let bb_data = &body[bb]; assert!(hi == bb_data.statements.len()); - for &succ_bb in bb_data.terminator.as_ref().unwrap().successors() { + for &succ_bb in bb_data.terminator().successors() { visited.entry(succ_bb) .and_modify(|lo| { // `succ_bb` has been seen before. If it wasn't diff --git a/src/librustc_mir/lints.rs b/src/librustc_mir/lints.rs index 8c815a51b5d65..981f78f49dcdd 100644 --- a/src/librustc_mir/lints.rs +++ b/src/librustc_mir/lints.rs @@ -81,7 +81,7 @@ fn check_fn_for_unconditional_recursion( let block = &basic_blocks[bb]; - if let Some(ref terminator) = block.terminator { + if let Some(ref terminator) = block.terminator_opt() { match terminator.kind { TerminatorKind::Call { ref func, .. } => { let func_ty = func.ty(body, tcx); diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs index 15ecc6c37920b..132c0ef11d949 100644 --- a/src/librustc_mir/transform/add_call_guards.rs +++ b/src/librustc_mir/transform/add_call_guards.rs @@ -46,8 +46,9 @@ impl AddCallGuards { let cur_len = body.basic_blocks().len(); - for block in body.basic_blocks_mut() { - match block.terminator { + for bb in body.basic_blocks().indices() { + let is_cleanup = body.basic_blocks()[bb].is_cleanup; + match body.basic_block_terminator_opt_mut(bb) { Some(Terminator { kind: TerminatorKind::Call { destination: Some((_, ref mut destination)), @@ -60,9 +61,9 @@ impl AddCallGuards { // It's a critical edge, break it let call_guard = BasicBlockData { statements: vec![], - is_cleanup: block.is_cleanup, + is_cleanup: is_cleanup, terminator: Some(Terminator { - source_info, + source_info: *source_info, kind: TerminatorKind::Goto { target: *destination } }) }; diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index caf588af851dd..3c20cc0770455 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -313,7 +313,7 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> { VariantIdx::new(RETURNED) // state for returned }; data.statements.push(self.set_discr(state, source_info)); - data.terminator.as_mut().unwrap().kind = TerminatorKind::Return; + *data.terminator_kind_mut() = TerminatorKind::Return; } self.super_basic_block_data(block, data); @@ -807,10 +807,10 @@ fn insert_switch<'tcx>( is_cleanup: false, }); - let blocks = body.basic_blocks_mut().iter_mut(); - - for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) { - *target = BasicBlock::new(target.index() + 1); + for bb in body.basic_blocks_mut().indices() { + for target in body.basic_block_terminator_mut(bb).successors_mut() { + *target = BasicBlock::new(target.index() + 1); + } } } @@ -889,7 +889,7 @@ fn create_generator_drop_shim<'tcx>( insert_switch(&mut body, cases, &transform, TerminatorKind::Return); for block in body.basic_blocks_mut() { - let kind = &mut block.terminator_mut().kind; + let kind = block.terminator_kind_mut(); if let TerminatorKind::GeneratorDrop = *kind { *kind = TerminatorKind::Return; } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 5ad026dc143c9..94492ef77977d 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -386,7 +386,7 @@ impl Inliner<'tcx> { callsite: CallSite<'tcx>, caller_body: &mut Body<'tcx>, mut callee_body: Body<'tcx>) -> bool { - let terminator = caller_body[callsite.bb].terminator.take().unwrap(); + let terminator = caller_body.basic_block_terminator_opt_mut(callsite.bb).take().unwrap(); match terminator.kind { // FIXME: Handle inlining of diverging calls TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => { @@ -494,12 +494,12 @@ impl Inliner<'tcx> { kind: TerminatorKind::Goto { target: BasicBlock::new(bb_len) } }; - caller_body[callsite.bb].terminator = Some(terminator); + *caller_body.basic_block_terminator_opt_mut(callsite.bb) = Some(terminator); true } kind => { - caller_body[callsite.bb].terminator = Some(Terminator { + *caller_body.basic_block_terminator_opt_mut(callsite.bb) = Some(Terminator { source_info: terminator.source_info, kind, }); diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 7d1b96b8be170..1816e8259fd44 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -246,7 +246,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let terminator = if self.keep_original { self.source[loc.block].terminator().clone() } else { - let terminator = self.source[loc.block].terminator_mut(); + let terminator = self.source.basic_block_terminator_mut(loc.block); let target = match terminator.kind { TerminatorKind::Call { destination: Some((_, target)), .. } => target, ref kind => { @@ -271,7 +271,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let last = self.promoted.basic_blocks().last().unwrap(); let new_target = self.new_block(); - *self.promoted[last].terminator_mut() = Terminator { + *self.promoted.basic_block_terminator_mut(last) = Terminator { kind: TerminatorKind::Call { func, args, @@ -356,11 +356,12 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { } }, Candidate::Argument { bb, index } => { - let terminator = blocks[bb].terminator_mut(); - match terminator.kind { + let data = &mut blocks[bb]; + let terminator_span = data.terminator().source_info.span; + match data.terminator_kind_mut() { TerminatorKind::Call { ref mut args, .. } => { let ty = args[index].ty(local_decls, self.tcx); - let span = terminator.source_info.span; + let span = terminator_span; let operand = Operand::Copy(promoted_place(ty, span)); mem::replace(&mut args[index], operand) } @@ -469,8 +470,8 @@ pub fn promote_candidates<'tcx>( // Eliminate assignments to, and drops of promoted temps. let promoted = |index: Local| temps[index] == TempState::PromotedOut; - for block in body.basic_blocks_mut() { - block.statements.retain(|statement| { + for bb in body.basic_blocks().indices() { + body.basic_blocks_mut()[bb].statements.retain(|statement| { match statement.kind { StatementKind::Assign(box(Place { base: PlaceBase::Local(index), @@ -483,7 +484,7 @@ pub fn promote_candidates<'tcx>( _ => true } }); - let terminator = block.terminator_mut(); + let terminator = body.basic_block_terminator_mut(bb); match terminator.kind { TerminatorKind::Drop { location: Place { base: PlaceBase::Local(index), diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 795721f3b3f28..7cdf0cabebd5a 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1724,14 +1724,14 @@ fn remove_drop_and_storage_dead_on_promoted_locals( ) { debug!("run_pass: promoted_temps={:?}", promoted_temps); - for block in body.basic_blocks_mut() { - block.statements.retain(|statement| { + for bb in body.basic_blocks().indices() { + body.basic_blocks_mut()[bb].statements.retain(|statement| { match statement.kind { StatementKind::StorageDead(index) => !promoted_temps.contains(index), _ => true } }); - let terminator = block.terminator_mut(); + let terminator = body.basic_block_terminator_mut(bb); match terminator.kind { TerminatorKind::Drop { location: Place { diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index 70b11944e2fbc..9ae98fc738511 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -102,7 +102,7 @@ impl RemoveNoopLandingPads { let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect(); for bb in postorder { debug!(" processing {:?}", bb); - for target in body[bb].terminator_mut().successors_mut() { + for target in body.basic_block_terminator_mut(bb).successors_mut() { if *target != resume_block && nop_landing_pads.contains(*target) { debug!(" folding noop jump to {:?} to resume block", target); *target = resume_block; @@ -110,7 +110,7 @@ impl RemoveNoopLandingPads { } } - match body[bb].terminator_mut().unwind_mut() { + match body.basic_block_terminator_mut(bb).unwind_mut() { Some(unwind) => { if *unwind == Some(resume_block) { debug!(" removing noop landing pad"); diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index d4599ee08aa46..7015becb64566 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -64,7 +64,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg { } pub struct CfgSimplifier<'a, 'tcx> { - basic_blocks: &'a mut IndexVec>, + body: &'a mut Body<'tcx>, pred_count: IndexVec } @@ -77,21 +77,23 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { pred_count[START_BLOCK] = 1; for (_, data) in traversal::preorder(body) { - if let Some(ref term) = data.terminator { + if let Some(ref term) = data.terminator_opt() { for &tgt in term.successors() { pred_count[tgt] += 1; } } } - let basic_blocks = body.basic_blocks_mut(); - CfgSimplifier { - basic_blocks, + body, pred_count, } } + fn basic_blocks(&mut self) -> &mut IndexVec> { + self.body.basic_blocks_mut() + } + pub fn simplify(mut self) { self.strip_nops(); @@ -102,14 +104,14 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { self.collapse_goto_chain(&mut start, &mut changed); - for bb in self.basic_blocks.indices() { + for bb in self.body.basic_blocks().indices() { if self.pred_count[bb] == 0 { continue } debug!("simplifying {:?}", bb); - let mut terminator = self.basic_blocks[bb].terminator.take() + let mut terminator = self.body.basic_block_terminator_opt_mut(bb).take() .expect("invalid terminator state"); for successor in terminator.successors_mut() { @@ -124,9 +126,8 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { inner_changed |= self.merge_successor(&mut new_stmts, &mut terminator); changed |= inner_changed; } - - self.basic_blocks[bb].statements.extend(new_stmts); - self.basic_blocks[bb].terminator = Some(terminator); + self.basic_blocks()[bb].statements.extend(new_stmts); + *self.body.basic_block_terminator_opt_mut(bb) = Some(terminator); changed |= inner_changed; } @@ -136,17 +137,17 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { if start != START_BLOCK { debug_assert!(self.pred_count[START_BLOCK] == 0); - self.basic_blocks.swap(START_BLOCK, start); + self.basic_blocks().swap(START_BLOCK, start); self.pred_count.swap(START_BLOCK, start); // pred_count == 1 if the start block has no predecessor _blocks_. if self.pred_count[START_BLOCK] > 1 { - for (bb, data) in self.basic_blocks.iter_enumerated_mut() { + for bb in self.basic_blocks().indices() { if self.pred_count[bb] == 0 { continue; } - for target in data.terminator_mut().successors_mut() { + for target in self.body.basic_block_terminator_mut(bb).successors_mut() { if *target == start { *target = START_BLOCK; } @@ -158,7 +159,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { // Collapse a goto chain starting from `start` fn collapse_goto_chain(&mut self, start: &mut BasicBlock, changed: &mut bool) { - let mut terminator = match self.basic_blocks[*start] { + let mut terminator = match self.basic_blocks()[*start] { BasicBlockData { ref statements, terminator: ref mut terminator @ Some(Terminator { @@ -177,7 +178,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { } _ => unreachable!() }; - self.basic_blocks[*start].terminator = terminator; + self.basic_blocks()[*start].terminator = terminator; debug!("collapsing goto chain from {:?} to {:?}", *start, target); @@ -209,7 +210,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { }; debug!("merging block {:?} into {:?}", target, terminator); - *terminator = match self.basic_blocks[target].terminator.take() { + *terminator = match self.body.basic_block_terminator_opt_mut(target).take() { Some(terminator) => terminator, None => { // unreachable loop - this should not be possible, as we @@ -217,7 +218,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { return false } }; - new_stmts.extend(self.basic_blocks[target].statements.drain(..)); + new_stmts.extend(self.basic_blocks()[target].statements.drain(..)); self.pred_count[target] = 0; true @@ -250,7 +251,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { } fn strip_nops(&mut self) { - for blk in self.basic_blocks.iter_mut() { + for blk in self.basic_blocks().iter_mut() { blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind { false } else { @@ -266,24 +267,27 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { seen.insert(bb.index()); } - let basic_blocks = body.basic_blocks_mut(); - - let num_blocks = basic_blocks.len(); - let mut replacements : Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); - let mut used_blocks = 0; - 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. - basic_blocks.raw.swap(alive_index, used_blocks); + let mut replacements: Vec; + { + let basic_blocks = body.basic_blocks_mut(); + + let num_blocks = basic_blocks.len(); + replacements = (0..num_blocks).map(BasicBlock::new).collect(); + let mut used_blocks = 0; + 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. + basic_blocks.raw.swap(alive_index, used_blocks); + } + used_blocks += 1; } - used_blocks += 1; + basic_blocks.raw.truncate(used_blocks); } - basic_blocks.raw.truncate(used_blocks); - for block in basic_blocks { - for target in block.terminator_mut().successors_mut() { + for bb in body.basic_blocks().indices() { + for target in body.basic_block_terminator_mut(bb).successors_mut() { *target = replacements[target.index()]; } } diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 0a509666d34ae..1e45ad5d428cf 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -21,8 +21,8 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranches { fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { let param_env = tcx.param_env(src.def_id()); - for block in body.basic_blocks_mut() { - let terminator = block.terminator_mut(); + for bb in body.basic_blocks().indices() { + let terminator = body.basic_block_terminator_mut(bb); terminator.kind = match terminator.kind { TerminatorKind::SwitchInt { discr: Operand::Constant(ref c), switch_ty, ref values, ref targets, .. diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index b42eebc7ee3be..cc0f9b3032806 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -94,7 +94,7 @@ pub fn liveness_of_locals( dirty_queue.insert(bb); } - let predecessors = body.predecessors(); + let predecessors = body.unwrap_predecessors(); while let Some(bb) = dirty_queue.pop() { // bits = use ∪ (bits - def) diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index 2ea9924af7f28..dadde3605d90e 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -141,7 +141,7 @@ impl<'tcx> MirPatch<'tcx> { for (src, patch) in self.patch_map.into_iter_enumerated() { if let Some(patch) = patch { debug!("MirPatch: patching block {:?}", src); - body[src].terminator_mut().kind = patch; + body.basic_block_terminator_mut(src).kind = patch; } }