diff options
Diffstat (limited to 'compiler/rustc_middle/src/mir')
| -rw-r--r-- | compiler/rustc_middle/src/mir/coverage.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/graph_cyclic_cache.rs | 62 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/mod.rs | 35 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/mono.rs | 44 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/query.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/visit.rs | 4 |
6 files changed, 120 insertions, 48 deletions
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 8a6bf9dff7b..95096d0fb71 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -118,17 +118,11 @@ impl CoverageKind { } pub fn is_counter(&self) -> bool { - match self { - Self::Counter { .. } => true, - _ => false, - } + matches!(self, Self::Counter { .. }) } pub fn is_expression(&self) -> bool { - match self { - Self::Expression { .. } => true, - _ => false, - } + matches!(self, Self::Expression { .. }) } pub fn is_unreachable(&self) -> bool { diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs new file mode 100644 index 00000000000..5f028975bd0 --- /dev/null +++ b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs @@ -0,0 +1,62 @@ +use rustc_data_structures::graph::{ + self, DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors, +}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::sync::OnceCell; +use rustc_serialize as serialize; + +/// Helper type to cache the result of `graph::is_cyclic`. +#[derive(Clone, Debug)] +pub(super) struct GraphIsCyclicCache { + cache: OnceCell<bool>, +} + +impl GraphIsCyclicCache { + #[inline] + pub(super) fn new() -> Self { + GraphIsCyclicCache { cache: OnceCell::new() } + } + + pub(super) fn is_cyclic<G>(&self, graph: &G) -> bool + where + G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes, + { + *self.cache.get_or_init(|| graph::is_cyclic(graph)) + } + + /// Invalidates the cache. + #[inline] + pub(super) fn invalidate(&mut self) { + // Invalidating the cache requires mutating the MIR, which in turn requires a unique + // reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all + // callers of `invalidate` have a unique reference to the MIR and thus to the + // cache. This means we never need to do synchronization when `invalidate` is called, + // we can simply reinitialize the `OnceCell`. + self.cache = OnceCell::new(); + } +} + +impl<S: serialize::Encoder> serialize::Encodable<S> for GraphIsCyclicCache { + #[inline] + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + serialize::Encodable::encode(&(), s) + } +} + +impl<D: serialize::Decoder> serialize::Decodable<D> for GraphIsCyclicCache { + #[inline] + fn decode(d: &mut D) -> Result<Self, D::Error> { + serialize::Decodable::decode(d).map(|_v: ()| Self::new()) + } +} + +impl<CTX> HashStable<CTX> for GraphIsCyclicCache { + #[inline] + fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { + // do nothing + } +} + +TrivialTypeFoldableAndLiftImpls! { + GraphIsCyclicCache, +} diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index ad48c351048..fab2f2c97e4 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -35,11 +35,13 @@ use std::ops::{ControlFlow, Index, IndexMut}; use std::slice; use std::{iter, mem, option}; +use self::graph_cyclic_cache::GraphIsCyclicCache; use self::predecessors::{PredecessorCache, Predecessors}; pub use self::query::*; pub mod abstract_const; pub mod coverage; +mod graph_cyclic_cache; pub mod interpret; pub mod mono; mod predecessors; @@ -227,6 +229,7 @@ pub struct Body<'tcx> { pub is_polymorphic: bool, predecessor_cache: PredecessorCache, + is_cyclic: GraphIsCyclicCache, } impl<'tcx> Body<'tcx> { @@ -267,6 +270,7 @@ impl<'tcx> Body<'tcx> { required_consts: Vec::new(), is_polymorphic: false, predecessor_cache: PredecessorCache::new(), + is_cyclic: GraphIsCyclicCache::new(), }; body.is_polymorphic = body.has_param_types_or_consts(); body @@ -296,6 +300,7 @@ impl<'tcx> Body<'tcx> { var_debug_info: Vec::new(), is_polymorphic: false, predecessor_cache: PredecessorCache::new(), + is_cyclic: GraphIsCyclicCache::new(), }; body.is_polymorphic = body.has_param_types_or_consts(); body @@ -309,11 +314,12 @@ impl<'tcx> Body<'tcx> { #[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. + // invalidate the caches. // // FIXME: Use a finer-grained API for this, so only transformations that alter terminators - // invalidate the predecessor cache. + // invalidate the caches. self.predecessor_cache.invalidate(); + self.is_cyclic.invalidate(); &mut self.basic_blocks } @@ -322,6 +328,7 @@ impl<'tcx> Body<'tcx> { &mut self, ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) { self.predecessor_cache.invalidate(); + self.is_cyclic.invalidate(); (&mut self.basic_blocks, &mut self.local_decls) } @@ -334,13 +341,14 @@ impl<'tcx> Body<'tcx> { &mut Vec<VarDebugInfo<'tcx>>, ) { self.predecessor_cache.invalidate(); + self.is_cyclic.invalidate(); (&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info) } /// 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 { - graph::is_cyclic(self) + self.is_cyclic.is_cyclic(self) } #[inline] @@ -1737,18 +1745,14 @@ impl<'tcx> Place<'tcx> { /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or /// a single deref of a local. - // - // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? + #[inline(always)] pub fn local_or_deref_local(&self) -> Option<Local> { - match self.as_ref() { - PlaceRef { local, projection: [] } - | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local), - _ => None, - } + self.as_ref().local_or_deref_local() } /// If this place represents a local variable like `_X` with no /// projections, return `Some(_X)`. + #[inline(always)] pub fn as_local(&self) -> Option<Local> { self.as_ref().as_local() } @@ -1762,6 +1766,7 @@ impl<'tcx> Place<'tcx> { /// As a concrete example, given the place a.b.c, this would yield: /// - (a, .b) /// - (a.b, .c) + /// /// Given a place without projections, the iterator is empty. pub fn iter_projections( self, @@ -1782,8 +1787,6 @@ impl From<Local> for Place<'_> { impl<'tcx> PlaceRef<'tcx> { /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or /// a single deref of a local. - // - // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? pub fn local_or_deref_local(&self) -> Option<Local> { match *self { PlaceRef { local, projection: [] } @@ -1800,6 +1803,14 @@ impl<'tcx> PlaceRef<'tcx> { _ => None, } } + + pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> { + if let &[ref proj_base @ .., elem] = self.projection { + Some((PlaceRef { local: self.local, projection: proj_base }, elem)) + } else { + None + } + } } impl Debug for Place<'_> { diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 1e70f760504..698c2521596 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,7 +1,6 @@ -use crate::dep_graph::{DepConstructor, DepNode, WorkProduct, WorkProductId}; +use crate::dep_graph::{dep_constructor, DepNode, WorkProduct, WorkProductId}; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; -use rustc_attr::InlineAttr; use rustc_data_structures::base_n; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -79,14 +78,6 @@ impl<'tcx> MonoItem<'tcx> { } pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode { - let generate_cgu_internal_copies = tcx - .sess - .opts - .debugging_opts - .inline_in_all_cgus - .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No) - && !tcx.sess.link_dead_code(); - match *self { MonoItem::Fn(ref instance) => { let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id); @@ -99,21 +90,26 @@ impl<'tcx> MonoItem<'tcx> { return InstantiationMode::GloballyShared { may_conflict: false }; } + let generate_cgu_internal_copies = tcx + .sess + .opts + .debugging_opts + .inline_in_all_cgus + .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No) + && !tcx.sess.link_dead_code(); + // At this point we don't have explicit linkage and we're an - // inlined function. If we're inlining into all CGUs then we'll - // be creating a local copy per CGU. + // inlined function. If we should generate local copies for each CGU, + // then return `LocalCopy`, otherwise we'll just generate one copy + // and share it with all CGUs in this crate. if generate_cgu_internal_copies { - return InstantiationMode::LocalCopy; - } - - // Finally, if this is `#[inline(always)]` we're sure to respect - // that with an inline copy per CGU, but otherwise we'll be - // creating one copy of this `#[inline]` function which may - // conflict with upstream crates as it could be an exported - // symbol. - match tcx.codegen_fn_attrs(instance.def_id()).inline { - InlineAttr::Always => InstantiationMode::LocalCopy, - _ => InstantiationMode::GloballyShared { may_conflict: true }, + InstantiationMode::LocalCopy + } else { + // Finally, if we've reached this point, then we should optimize for + // compilation speed. In that regard, we will ignore any `#[inline]` + // annotations on the function and simply codegen it as usual. This could + // conflict with upstream crates as it could be an exported symbol. + InstantiationMode::GloballyShared { may_conflict: true } } } MonoItem::Static(..) | MonoItem::GlobalAsm(..) => { @@ -362,7 +358,7 @@ impl<'tcx> CodegenUnit<'tcx> { } pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode { - DepConstructor::CompileCodegenUnit(tcx, self.name()) + dep_constructor::CompileCodegenUnit(tcx, self.name()) } } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 89a93096f1c..a7b847fc5e0 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -439,18 +439,27 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn optimized_mir_opt_const_arg( + pub fn optimized_mir_or_const_arg_mir( self, def: ty::WithOptConstParam<DefId>, ) -> &'tcx Body<'tcx> { if let Some((did, param_did)) = def.as_const_arg() { - self.optimized_mir_of_const_arg((did, param_did)) + self.mir_for_ctfe_of_const_arg((did, param_did)) } else { self.optimized_mir(def.did) } } #[inline] + pub fn mir_for_ctfe_opt_const_arg(self, def: ty::WithOptConstParam<DefId>) -> &'tcx Body<'tcx> { + if let Some((did, param_did)) = def.as_const_arg() { + self.mir_for_ctfe_of_const_arg((did, param_did)) + } else { + self.mir_for_ctfe(def.did) + } + } + + #[inline] pub fn mir_abstract_const_opt_const_arg( self, def: ty::WithOptConstParam<DefId>, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index e281010eb06..023555d91cc 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -306,13 +306,13 @@ macro_rules! make_mir_visitor { let mut index = 0; for statement in statements { - let location = Location { block: block, statement_index: index }; + let location = Location { block, statement_index: index }; self.visit_statement(statement, location); index += 1; } if let Some(terminator) = terminator { - let location = Location { block: block, statement_index: index }; + let location = Location { block, statement_index: index }; self.visit_terminator(terminator, location); } } |
