about summary refs log tree commit diff
path: root/compiler/rustc_middle/src/mir
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle/src/mir')
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs10
-rw-r--r--compiler/rustc_middle/src/mir/graph_cyclic_cache.rs62
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs35
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs44
-rw-r--r--compiler/rustc_middle/src/mir/query.rs13
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs4
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);
                 }
             }