Skip to content

Commit

Permalink
Auto merge of #61062 - mark-i-m:mono-mv, r=eddyb,oli-obk
Browse files Browse the repository at this point in the history
Remove _all_ codegen dependencies on `rustc_mir` 🎉

~This code is pretty self-contained. It has no references to the rest of `rustc_mir`. Moving it to its own crate means that almost all of the references from `rustc_codegen_*` to `rustc_mir` are instead moved to `rustc_monomorphize`, which should help improve compile times for the compiler a bit...~

With the help of eddyb and oli-obk, all of the dependencies of `librustc_codegen_*` on `librustc_mir` have been removed:
- dependencies on `rustc_mir::monomorphize` were moved to `rustc::mir::mono`
- `rustc_mir::const_eval::const_field` is made into a query.
- `rustc_mir::interpret::type_name` is made into a query.

This should help reduce compile time when working on `rustc_mir` 🕐

cc #47849

r? @eddyb
  • Loading branch information
bors committed Jun 3, 2019
2 parents c57ed9d + 0f822d7 commit da9ebc8
Show file tree
Hide file tree
Showing 44 changed files with 733 additions and 636 deletions.
2 changes: 0 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2684,7 +2684,6 @@ dependencies = [
"rustc_errors 0.0.0",
"rustc_fs_util 0.0.0",
"rustc_incremental 0.0.0",
"rustc_mir 0.0.0",
"rustc_target 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
Expand All @@ -2703,7 +2702,6 @@ dependencies = [
"rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_data_structures 0.0.0",
"rustc_metadata 0.0.0",
"rustc_mir 0.0.0",
"rustc_target 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
Expand Down
1 change: 1 addition & 0 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
//! user of the `DepNode` API of having to know how to compute the expected
//! fingerprint for a given set of node parameters.

use crate::mir;
use crate::mir::interpret::GlobalId;
use crate::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
use crate::hir::map::DefPathHash;
Expand Down
259 changes: 258 additions & 1 deletion src/librustc/mir/mono.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,45 @@
use crate::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use crate::hir::HirId;
use syntax::symbol::InternedString;
use crate::ty::{Instance, TyCtxt};
use syntax::attr::InlineAttr;
use syntax::source_map::Span;
use crate::ty::{Instance, InstanceDef, TyCtxt, SymbolName, subst::InternalSubsts};
use crate::util::nodemap::FxHashMap;
use crate::ty::print::obsolete::DefPathBasedNames;
use crate::dep_graph::{WorkProductId, DepNode, WorkProduct, DepConstructor};
use rustc_data_structures::base_n;
use rustc_data_structures::stable_hasher::{HashStable, StableHasherResult,
StableHasher};
use crate::ich::{Fingerprint, StableHashingContext, NodeIdHashingMode};
use crate::session::config::OptLevel;
use std::fmt;
use std::hash::Hash;

/// Describes how a monomorphization will be instantiated in object files.
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
pub enum InstantiationMode {
/// There will be exactly one instance of the given MonoItem. It will have
/// external linkage so that it can be linked to from other codegen units.
GloballyShared {
/// In some compilation scenarios we may decide to take functions that
/// are typically `LocalCopy` and instead move them to `GloballyShared`
/// to avoid codegenning them a bunch of times. In this situation,
/// however, our local copy may conflict with other crates also
/// inlining the same function.
///
/// This flag indicates that this situation is occurring, and informs
/// symbol name calculation that some extra mangling is needed to
/// avoid conflicts. Note that this may eventually go away entirely if
/// ThinLTO enables us to *always* have a globally shared instance of a
/// function within one crate's compilation.
may_conflict: bool,
},

/// Each codegen unit containing a reference to the given MonoItem will
/// have its own private copy of the function (with internal linkage).
LocalCopy,
}

#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
pub enum MonoItem<'tcx> {
Fn(Instance<'tcx>),
Expand All @@ -31,6 +61,166 @@ impl<'tcx> MonoItem<'tcx> {
MonoItem::GlobalAsm(_) => 1,
}
}

pub fn is_generic_fn(&self) -> bool {
match *self {
MonoItem::Fn(ref instance) => {
instance.substs.non_erasable_generics().next().is_some()
}
MonoItem::Static(..) |
MonoItem::GlobalAsm(..) => false,
}
}

pub fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> SymbolName {
match *self {
MonoItem::Fn(instance) => tcx.symbol_name(instance),
MonoItem::Static(def_id) => {
tcx.symbol_name(Instance::mono(tcx, def_id))
}
MonoItem::GlobalAsm(hir_id) => {
let def_id = tcx.hir().local_def_id_from_hir_id(hir_id);
SymbolName {
name: InternedString::intern(&format!("global_asm_{:?}", def_id))
}
}
}
}

pub fn instantiation_mode(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> InstantiationMode {
let inline_in_all_cgus =
tcx.sess.opts.debugging_opts.inline_in_all_cgus.unwrap_or_else(|| {
tcx.sess.opts.optimize != OptLevel::No
}) && !tcx.sess.opts.cg.link_dead_code;

match *self {
MonoItem::Fn(ref instance) => {
let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
// If this function isn't inlined or otherwise has explicit
// linkage, then we'll be creating a globally shared version.
if self.explicit_linkage(tcx).is_some() ||
!instance.def.requires_local(tcx) ||
Some(instance.def_id()) == entry_def_id
{
return InstantiationMode::GloballyShared { may_conflict: false }
}

// 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
if inline_in_all_cgus {
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 }
}
}
}
MonoItem::Static(..) |
MonoItem::GlobalAsm(..) => {
InstantiationMode::GloballyShared { may_conflict: false }
}
}
}

pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Linkage> {
let def_id = match *self {
MonoItem::Fn(ref instance) => instance.def_id(),
MonoItem::Static(def_id) => def_id,
MonoItem::GlobalAsm(..) => return None,
};

let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
codegen_fn_attrs.linkage
}

/// Returns `true` if this instance is instantiable - whether it has no unsatisfied
/// predicates.
///
/// In order to codegen an item, all of its predicates must hold, because
/// otherwise the item does not make sense. Type-checking ensures that
/// the predicates of every item that is *used by* a valid item *do*
/// hold, so we can rely on that.
///
/// However, we codegen collector roots (reachable items) and functions
/// in vtables when they are seen, even if they are not used, and so they
/// might not be instantiable. For example, a programmer can define this
/// public function:
///
/// pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
/// <&mut () as Clone>::clone(&s);
/// }
///
/// That function can't be codegened, because the method `<&mut () as Clone>::clone`
/// does not exist. Luckily for us, that function can't ever be used,
/// because that would require for `&'a mut (): Clone` to hold, so we
/// can just not emit any code, or even a linker reference for it.
///
/// Similarly, if a vtable method has such a signature, and therefore can't
/// be used, we can just not emit it and have a placeholder (a null pointer,
/// which will never be accessed) in its place.
pub fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
debug!("is_instantiable({:?})", self);
let (def_id, substs) = match *self {
MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs),
MonoItem::Static(def_id) => (def_id, InternalSubsts::empty()),
// global asm never has predicates
MonoItem::GlobalAsm(..) => return true
};

tcx.substitute_normalize_and_test_predicates((def_id, &substs))
}

pub fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, debug: bool) -> String {
return match *self {
MonoItem::Fn(instance) => {
to_string_internal(tcx, "fn ", instance, debug)
},
MonoItem::Static(def_id) => {
let instance = Instance::new(def_id, tcx.intern_substs(&[]));
to_string_internal(tcx, "static ", instance, debug)
},
MonoItem::GlobalAsm(..) => {
"global_asm".to_string()
}
};

fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
prefix: &str,
instance: Instance<'tcx>,
debug: bool)
-> String {
let mut result = String::with_capacity(32);
result.push_str(prefix);
let printer = DefPathBasedNames::new(tcx, false, false);
printer.push_instance_as_string(instance, &mut result, debug);
result
}
}

pub fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Span> {
match *self {
MonoItem::Fn(Instance { def, .. }) => {
tcx.hir().as_local_hir_id(def.def_id())
}
MonoItem::Static(def_id) => {
tcx.hir().as_local_hir_id(def_id)
}
MonoItem::GlobalAsm(hir_id) => {
Some(hir_id)
}
}.map(|hir_id| tcx.hir().span_by_hir_id(hir_id))
}
}

impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
Expand Down Expand Up @@ -161,6 +351,73 @@ impl<'tcx> CodegenUnit<'tcx> {
self.size_estimate = Some(size_estimate + delta);
}
}

pub fn contains_item(&self, item: &MonoItem<'tcx>) -> bool {
self.items().contains_key(item)
}

pub fn work_product_id(&self) -> WorkProductId {
WorkProductId::from_cgu_name(&self.name().as_str())
}

pub fn work_product(&self, tcx: TyCtxt<'_, '_, '_>) -> WorkProduct {
let work_product_id = self.work_product_id();
tcx.dep_graph
.previous_work_product(&work_product_id)
.unwrap_or_else(|| {
panic!("Could not find work-product for CGU `{}`", self.name())
})
}

pub fn items_in_deterministic_order<'a>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> Vec<(MonoItem<'tcx>,
(Linkage, Visibility))> {
// The codegen tests rely on items being process in the same order as
// they appear in the file, so for local items, we sort by node_id first
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct ItemSortKey(Option<HirId>, SymbolName);

fn item_sort_key<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
item: MonoItem<'tcx>) -> ItemSortKey {
ItemSortKey(match item {
MonoItem::Fn(ref instance) => {
match instance.def {
// We only want to take HirIds of user-defined
// instances into account. The others don't matter for
// the codegen tests and can even make item order
// unstable.
InstanceDef::Item(def_id) => {
tcx.hir().as_local_hir_id(def_id)
}
InstanceDef::VtableShim(..) |
InstanceDef::Intrinsic(..) |
InstanceDef::FnPtrShim(..) |
InstanceDef::Virtual(..) |
InstanceDef::ClosureOnceShim { .. } |
InstanceDef::DropGlue(..) |
InstanceDef::CloneShim(..) => {
None
}
}
}
MonoItem::Static(def_id) => {
tcx.hir().as_local_hir_id(def_id)
}
MonoItem::GlobalAsm(hir_id) => {
Some(hir_id)
}
}, item.symbol_name(tcx))
}

let mut items: Vec<_> = self.items().iter().map(|(&i, &l)| (i, l)).collect();
items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i));
items
}

pub fn codegen_dep_node(&self, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> DepNode {
DepNode::new(tcx, DepConstructor::CompileCodegenUnit(self.name().clone()))
}
}

impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> {
Expand Down
19 changes: 19 additions & 0 deletions src/librustc/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};
use crate::ty::subst::SubstsRef;
use crate::dep_graph::SerializedDepNodeIndex;
use crate::hir::def_id::{CrateNum, DefId, DefIndex};
use crate::mir;
use crate::mir::interpret::GlobalId;
use crate::traits;
use crate::traits::query::{
Expand Down Expand Up @@ -431,6 +432,24 @@ rustc_queries! {
tcx.queries.on_disk_cache.try_load_query_result(tcx, id).map(Ok)
}
}

/// Extracts a field of a (variant of a) const.
query const_field(
key: ty::ParamEnvAnd<'tcx, (&'tcx ty::Const<'tcx>, mir::Field)>
) -> &'tcx ty::Const<'tcx> {
eval_always
no_force
desc { "extract field of const" }
}

/// Produces an absolute path representation of the given type. See also the documentation
/// on `std::any::type_name`.
query type_name(key: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
eval_always
no_force
desc { "get absolute path of type" }
}

}

TypeChecking {
Expand Down
Loading

0 comments on commit da9ebc8

Please sign in to comment.