use polonius_engine::Atom;
use rustc_index::bit_set::BitMatrix;
use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::graph::dominators::{dominators, Dominators};
-use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
+use rustc_data_structures::graph::dominators::Dominators;
+use rustc_data_structures::graph::{self, GraphSuccessors};
use rustc_index::vec::{Idx, IndexVec};
use rustc_data_structures::sync::Lrc;
use rustc_macros::HashStable;
use smallvec::SmallVec;
use std::borrow::Cow;
use std::fmt::{self, Debug, Display, Formatter, Write};
-use std::ops::{Index, IndexMut};
+use std::ops::Index;
use std::slice;
-use std::vec::IntoIter;
use std::{iter, mem, option, u32};
use syntax::ast::Name;
use syntax::symbol::Symbol;
use syntax_pos::{Span, DUMMY_SP};
pub use crate::mir::interpret::AssertMessage;
+pub use crate::mir::cache::{BodyCache, ReadOnlyBodyCache};
+pub use crate::read_only;
+pub mod cache;
pub mod interpret;
pub mod mono;
pub mod tcx;
pub yield_ty: Option<Ty<'tcx>>,
/// Generator drop glue.
- pub generator_drop: Option<Box<Body<'tcx>>>,
+ pub generator_drop: Option<Box<BodyCache<'tcx>>>,
/// The layout of a generator. Produced by the state transformation.
pub generator_layout: Option<GeneratorLayout<'tcx>>,
/// A span representing this MIR, for error reporting.
pub span: Span,
-
- /// A cache for various calculations.
- predecessors_cache: Option<IndexVec<BasicBlock, Vec<BasicBlock>>>,
}
impl<'tcx> Body<'tcx> {
spread_arg: None,
var_debug_info,
span,
- predecessors_cache: None,
control_flow_destroyed,
}
}
&self.basic_blocks
}
- #[inline]
- pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
- &mut self.basic_blocks
- }
-
- pub fn basic_block_terminator_opt_mut(
- &mut self, bb: BasicBlock
- ) -> &mut Option<Terminator<'tcx>> {
- // FIXME we should look into improving the cache invalidation
- debug!("Invalidating predecessors cache through opt terminator for block at : {:?}", self.span.data());
- self.predecessors_cache = None;
- &mut self.basic_blocks[bb].terminator
- }
-
- pub fn basic_block_terminator_mut(&mut self, bb: BasicBlock) -> &mut Terminator<'tcx> {
- // FIXME we should look into improving the cache invalidation
- debug!("Invalidating predecessors cache through terminator for block at : {:?}", self.span.data());
- self.predecessors_cache = None;
- self.basic_blocks[bb].terminator_mut()
- }
-
- #[inline]
- pub fn basic_blocks_and_local_decls_mut(
- &mut self,
- ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
- (&mut self.basic_blocks, &mut self.local_decls)
- }
-
- #[inline]
- pub fn unwrap_predecessors(&self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
- assert!(self.predecessors_cache.is_some(), "Expected predecessors_cache to be `Some(...)` for block at: {:?}", self.span.data());
- self.predecessors_cache.as_ref().unwrap()
- }
-
- #[inline]
- pub fn ensure_predecessors(&mut self) {
- if self.predecessors_cache.is_none() {
- 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);
- }
- }
- }
-
- self.predecessors_cache = Some(result)
- }
- }
-
- #[inline]
- /// This will recompute the predecessors cache if it is not available
- pub fn predecessors(&mut self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
- self.ensure_predecessors();
- self.predecessors_cache.as_ref().unwrap()
- }
-
- #[inline]
- pub fn predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] {
- &self.unwrap_predecessors()[bb]
- }
-
- #[inline]
- pub fn predecessor_locations(&self, loc: Location) -> impl Iterator<Item = Location> + '_ {
- let if_zero_locations = if loc.statement_index == 0 {
- let predecessor_blocks = self.predecessors_for(loc.block);
- let num_predecessor_blocks = predecessor_blocks.len();
- Some(
- (0..num_predecessor_blocks)
- .map(move |i| predecessor_blocks[i])
- .map(move |bb| self.terminator_loc(bb)),
- )
- } else {
- None
- };
-
- let if_not_zero_locations = if loc.statement_index == 0 {
- None
- } else {
- Some(Location { block: loc.block, statement_index: loc.statement_index - 1 })
- };
-
- if_zero_locations.into_iter().flatten().chain(if_not_zero_locations)
- }
-
- #[inline]
- pub fn dominators(&self) -> Dominators<BasicBlock> {
- dominators(self)
- }
-
/// Returns `true` if a cycle exists in the control-flow graph that is reachable from the
/// `START_BLOCK`.
pub fn is_cfg_cyclic(&self) -> bool {
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
/// invalidating statement indices in `Location`s.
pub fn make_statement_nop(&mut self, location: Location) {
- let block = &mut self[location.block];
+ let block = &mut self.basic_blocks[location.block];
debug_assert!(location.statement_index < block.statements.len());
block.statements[location.statement_index].make_nop()
}
}
}
-impl<'tcx> IndexMut<BasicBlock> for Body<'tcx> {
- #[inline]
- fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> {
- &mut self.basic_blocks_mut()[index]
- }
-}
-
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable)]
pub enum ClearCrossCrate<T> {
Clear,
}
}
-CloneTypeFoldableAndLiftImpls!{ BasicBlock, }
-
///////////////////////////////////////////////////////////////////////////
// BasicBlockData and Terminator
BasicBlockData { statements: vec![], terminator, is_cleanup: false }
}
- pub fn terminator_opt(&self) -> &Option<Terminator<'tcx>> {
- &self.terminator
- }
-
/// Accessor for terminator.
///
/// Terminator may not be None after construction of the basic block is complete. This accessor
self.terminator.as_ref().expect("invalid terminator state")
}
- // 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> {
+ pub 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<F>(&mut self, mut f: F)
where
F: FnMut(&mut Statement<'_>) -> bool,
}
}
-impl<'tcx> graph::WithPredecessors for Body<'tcx> {
- fn predecessors(
- &self,
- node: Self::Node,
- ) -> <Self as GraphPredecessors<'_>>::Iter {
- self.predecessors_for(node).to_vec().into_iter()
- }
-}
-
impl<'tcx> graph::WithSuccessors for Body<'tcx> {
fn successors(
&self,
}
}
-impl<'a, 'b> graph::GraphPredecessors<'b> for Body<'a> {
- type Item = BasicBlock;
- type Iter = IntoIter<BasicBlock>;
-}
-
impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> {
type Item = BasicBlock;
type Iter = iter::Cloned<Successors<'b>>;
}
/// Returns `true` if `other` is earlier in the control flow graph than `self`.
- pub fn is_predecessor_of<'tcx>(&self, other: Location, body: &Body<'tcx>) -> bool {
+ pub fn is_predecessor_of<'tcx>(
+ &self,
+ other: Location,
+ body: 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`.
if self.block == other.block && self.statement_index < other.statement_index {