+++ /dev/null
-use crate::ich::StableHashingContext;
-use crate::mir::{BasicBlock, BasicBlockData, Body, LocalDecls, Location, Successors};
-use rustc_data_structures::graph::dominators::{dominators, Dominators};
-use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_index::vec::IndexVec;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-use smallvec::SmallVec;
-use std::iter;
-use std::ops::{Deref, DerefMut, Index, IndexMut};
-use std::vec::IntoIter;
-
-#[derive(Clone, Debug)]
-pub struct Cache {
- // Typically 95%+ of the inner vectors have 4 or fewer elements.
- predecessors: Option<IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>>,
-}
-
-impl rustc_serialize::Encodable for Cache {
- fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- Encodable::encode(&(), s)
- }
-}
-
-impl rustc_serialize::Decodable for Cache {
- fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
- Decodable::decode(d).map(|_v: ()| Self::new())
- }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for Cache {
- fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
- // Do nothing.
- }
-}
-
-impl Cache {
- pub fn new() -> Self {
- Self { predecessors: None }
- }
-
- pub fn invalidate_predecessors(&mut self) {
- // FIXME: consider being more fine-grained
- self.predecessors = None;
- }
-
- pub fn ensure_predecessors(&mut self, body: &Body<'_>) {
- if self.predecessors.is_none() {
- let mut result = IndexVec::from_elem(smallvec![], 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);
- }
- }
- }
-
- self.predecessors = Some(result)
- }
- }
-
- /// This will recompute the predecessors cache if it is not available
- fn predecessors(
- &mut self,
- body: &Body<'_>,
- ) -> &IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>> {
- self.ensure_predecessors(body);
- self.predecessors.as_ref().unwrap()
- }
-
- fn unwrap_predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] {
- &self.predecessors.as_ref().unwrap()[bb]
- }
-
- fn unwrap_predecessor_locations<'a>(
- &'a 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.unwrap_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| body.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)
- }
-
- pub fn basic_blocks_mut<'a, 'tcx>(
- &mut self,
- body: &'a mut Body<'tcx>,
- ) -> &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
- debug!("bbm: Clearing predecessors cache for body at: {:?}", body.span.data());
- self.invalidate_predecessors();
- &mut body.basic_blocks
- }
-
- pub fn basic_blocks_and_local_decls_mut<'a, 'tcx>(
- &mut self,
- body: &'a mut Body<'tcx>,
- ) -> (&'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &'a mut LocalDecls<'tcx>) {
- debug!("bbaldm: Clearing predecessors cache for body at: {:?}", body.span.data());
- self.invalidate_predecessors();
- (&mut body.basic_blocks, &mut body.local_decls)
- }
-}
-
-#[derive(Clone, Debug, HashStable, RustcEncodable, RustcDecodable, TypeFoldable)]
-pub struct BodyAndCache<'tcx> {
- body: Body<'tcx>,
- cache: Cache,
-}
-
-impl BodyAndCache<'tcx> {
- pub fn new(body: Body<'tcx>) -> Self {
- Self { body, cache: Cache::new() }
- }
-}
-
-#[macro_export]
-macro_rules! read_only {
- ($body:expr) => {{
- $body.ensure_predecessors();
- $body.unwrap_read_only()
- }};
-}
-
-impl BodyAndCache<'tcx> {
- pub fn ensure_predecessors(&mut self) {
- self.cache.ensure_predecessors(&self.body);
- }
-
- pub fn predecessors(&mut self) -> &IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>> {
- self.cache.predecessors(&self.body)
- }
-
- pub fn unwrap_read_only(&self) -> ReadOnlyBodyAndCache<'_, 'tcx> {
- ReadOnlyBodyAndCache::new(&self.body, &self.cache)
- }
-
- pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
- self.cache.basic_blocks_mut(&mut self.body)
- }
-
- pub fn basic_blocks_and_local_decls_mut(
- &mut self,
- ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
- self.cache.basic_blocks_and_local_decls_mut(&mut self.body)
- }
-}
-
-impl<'tcx> Index<BasicBlock> for BodyAndCache<'tcx> {
- type Output = BasicBlockData<'tcx>;
-
- fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
- &self.body[index]
- }
-}
-
-impl<'tcx> IndexMut<BasicBlock> for BodyAndCache<'tcx> {
- fn index_mut(&mut self, index: BasicBlock) -> &mut Self::Output {
- &mut self.basic_blocks_mut()[index]
- }
-}
-
-impl<'tcx> Deref for BodyAndCache<'tcx> {
- type Target = Body<'tcx>;
-
- fn deref(&self) -> &Self::Target {
- &self.body
- }
-}
-
-impl<'tcx> DerefMut for BodyAndCache<'tcx> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.body
- }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub struct ReadOnlyBodyAndCache<'a, 'tcx> {
- body: &'a Body<'tcx>,
- cache: &'a Cache,
-}
-
-impl ReadOnlyBodyAndCache<'a, 'tcx> {
- fn new(body: &'a Body<'tcx>, cache: &'a Cache) -> Self {
- assert!(
- cache.predecessors.is_some(),
- "Cannot construct ReadOnlyBodyAndCache without computed predecessors"
- );
- Self { body, cache }
- }
-
- pub fn predecessors(&self) -> &IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>> {
- self.cache.predecessors.as_ref().unwrap()
- }
-
- pub fn predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] {
- self.cache.unwrap_predecessors_for(bb)
- }
-
- pub fn predecessor_locations(&self, loc: Location) -> impl Iterator<Item = Location> + '_ {
- self.cache.unwrap_predecessor_locations(loc, self.body)
- }
-
- pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
- &self.body.basic_blocks
- }
-
- pub fn dominators(&self) -> Dominators<BasicBlock> {
- dominators(self)
- }
-}
-
-impl graph::DirectedGraph for ReadOnlyBodyAndCache<'a, 'tcx> {
- type Node = BasicBlock;
-}
-
-impl graph::GraphPredecessors<'graph> for ReadOnlyBodyAndCache<'a, 'tcx> {
- type Item = BasicBlock;
- type Iter = IntoIter<BasicBlock>;
-}
-
-impl graph::WithPredecessors for ReadOnlyBodyAndCache<'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 ReadOnlyBodyAndCache<'a, 'tcx> {
- fn num_nodes(&self) -> usize {
- self.body.num_nodes()
- }
-}
-
-impl graph::WithStartNode for ReadOnlyBodyAndCache<'a, 'tcx> {
- fn start_node(&self) -> Self::Node {
- self.body.start_node()
- }
-}
-
-impl graph::WithSuccessors for ReadOnlyBodyAndCache<'a, 'tcx> {
- fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter {
- self.body.successors(node)
- }
-}
-
-impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for ReadOnlyBodyAndCache<'a, 'tcx> {
- type Item = BasicBlock;
- type Iter = iter::Cloned<Successors<'b>>;
-}
-
-impl Deref for ReadOnlyBodyAndCache<'a, 'tcx> {
- type Target = &'a Body<'tcx>;
-
- fn deref(&self) -> &Self::Target {
- &self.body
- }
-}
-
-CloneTypeFoldableAndLiftImpls! {
- Cache,
-}
pub use rustc_ast::ast::Mutability;
use rustc_ast::ast::Name;
use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::graph::dominators::Dominators;
+use rustc_data_structures::graph::dominators::{dominators, Dominators};
use rustc_data_structures::graph::{self, GraphSuccessors};
+use rustc_data_structures::sync::MappedLockGuard;
use rustc_index::bit_set::BitMatrix;
use rustc_index::vec::{Idx, IndexVec};
use rustc_macros::HashStable;
use rustc_serialize::{Decodable, Encodable};
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
+use smallvec::SmallVec;
use std::borrow::Cow;
use std::fmt::{self, Debug, Display, Formatter, Write};
-use std::ops::Index;
+use std::ops::{Index, IndexMut};
use std::slice;
use std::{iter, mem, option};
-pub use self::cache::{BodyAndCache, ReadOnlyBodyAndCache};
+use self::predecessors::{PredecessorCache, Predecessors};
pub use self::query::*;
-pub use crate::read_only;
-mod cache;
pub mod interpret;
pub mod mono;
+mod predecessors;
mod query;
pub mod tcx;
pub mod traversal;
pub yield_ty: Option<Ty<'tcx>>,
/// Generator drop glue.
- pub generator_drop: Option<Box<BodyAndCache<'tcx>>>,
+ pub generator_drop: Option<Box<Body<'tcx>>>,
/// The layout of a generator. Produced by the state transformation.
pub generator_layout: Option<GeneratorLayout<'tcx>>,
/// implementation without the flag hid this situation silently.
/// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components.
pub ignore_interior_mut_in_const_validation: bool,
+
+ pub predecessor_cache: PredecessorCache,
}
impl<'tcx> Body<'tcx> {
span,
ignore_interior_mut_in_const_validation: false,
control_flow_destroyed,
+ predecessor_cache: PredecessorCache::new(),
}
}
generator_kind: None,
var_debug_info: Vec::new(),
ignore_interior_mut_in_const_validation: false,
+ predecessor_cache: PredecessorCache::new(),
}
}
&self.basic_blocks
}
+ #[inline]
+ pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+ // Because the user could mutate basic block terminators via this reference, we need to
+ // invalidate the predecessor cache.
+ //
+ // FIXME: Use a finer-grained API for this, so only transformations that alter terminators
+ // invalidate the predecessor cache.
+ self.predecessor_cache.invalidate();
+ &mut self.basic_blocks
+ }
+
+ #[inline]
+ pub fn basic_blocks_and_local_decls_mut(
+ &mut self,
+ ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
+ self.predecessor_cache.invalidate();
+ (&mut self.basic_blocks, &mut self.local_decls)
+ }
+
/// 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 {
pub fn terminator_loc(&self, bb: BasicBlock) -> Location {
Location { block: bb, statement_index: self[bb].statements.len() }
}
+
+ pub fn predecessors_for(
+ &self,
+ bb: BasicBlock,
+ ) -> impl std::ops::Deref<Target = SmallVec<[BasicBlock; 4]>> + '_ {
+ let predecessors = self.predecessor_cache.compute(&self.basic_blocks);
+ MappedLockGuard::map(predecessors, |preds| &mut preds[bb])
+ }
+
+ pub fn predecessors(&self) -> impl std::ops::Deref<Target = Predecessors> + '_ {
+ self.predecessor_cache.compute(&self.basic_blocks)
+ }
+
+ #[inline]
+ pub fn dominators(&self) -> Dominators<BasicBlock> {
+ dominators(self)
+ }
}
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
}
}
+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,
type Iter = iter::Cloned<Successors<'b>>;
}
+impl graph::GraphPredecessors<'graph> for Body<'tcx> {
+ type Item = BasicBlock;
+ type Iter = smallvec::IntoIter<[BasicBlock; 4]>;
+}
+
+impl graph::WithPredecessors for Body<'tcx> {
+ fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter {
+ self.predecessors_for(node).clone().into_iter()
+ }
+}
+
/// `Location` represents the position of the start of the statement; or, if
/// `statement_index` equals the number of statements, then the start of the
/// terminator.
}
/// Returns `true` if `other` is earlier in the control flow graph than `self`.
- pub fn is_predecessor_of<'tcx>(
- &self,
- other: Location,
- body: ReadOnlyBodyAndCache<'_, 'tcx>,
- ) -> bool {
+ pub fn is_predecessor_of<'tcx>(&self, other: Location, body: &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 {
--- /dev/null
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::{Lock, LockGuard, MappedLockGuard};
+use rustc_index::vec::IndexVec;
+use rustc_serialize as serialize;
+use smallvec::SmallVec;
+
+use crate::mir::{BasicBlock, BasicBlockData};
+
+// Typically 95%+ of basic blocks have 4 or fewer predecessors.
+pub type Predecessors = IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>;
+
+#[derive(Clone, Debug)]
+pub struct PredecessorCache {
+ cache: Lock<Option<Predecessors>>,
+}
+
+impl PredecessorCache {
+ pub fn new() -> Self {
+ PredecessorCache { cache: Lock::new(None) }
+ }
+
+ pub fn invalidate(&mut self) {
+ *self.cache.get_mut() = None;
+ }
+
+ pub fn compute(
+ &self,
+ basic_blocks: &IndexVec<BasicBlock, BasicBlockData<'_>>,
+ ) -> MappedLockGuard<'_, Predecessors> {
+ LockGuard::map(self.cache.lock(), |cache| {
+ cache.get_or_insert_with(|| {
+ let mut preds = IndexVec::from_elem(SmallVec::new(), basic_blocks);
+ for (bb, data) in basic_blocks.iter_enumerated() {
+ if let Some(term) = &data.terminator {
+ for &succ in term.successors() {
+ preds[succ].push(bb);
+ }
+ }
+ }
+
+ preds
+ })
+ })
+ }
+}
+
+impl serialize::Encodable for PredecessorCache {
+ fn encode<S: serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+ serialize::Encodable::encode(&(), s)
+ }
+}
+
+impl serialize::Decodable for PredecessorCache {
+ fn decode<D: serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
+ serialize::Decodable::decode(d).map(|_v: ()| Self::new())
+ }
+}
+
+impl<CTX> HashStable<CTX> for PredecessorCache {
+ fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
+ // do nothing
+ }
+}
+
+CloneTypeFoldableAndLiftImpls! {
+ PredecessorCache,
+}