rust/src/librustc/mir/mono.rs

342 lines
11 KiB
Rust
Raw Normal View History

2019-02-05 11:20:45 -06:00
use crate::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use syntax::ast::NodeId;
2018-07-10 19:16:22 +02:00
use syntax::symbol::{Symbol, InternedString};
2019-02-05 11:20:45 -06:00
use crate::ty::{Instance, TyCtxt};
use crate::util::nodemap::FxHashMap;
use rustc_data_structures::base_n;
2017-09-18 12:14:52 +02:00
use rustc_data_structures::stable_hasher::{HashStable, StableHasherResult,
StableHasher};
2019-02-05 11:20:45 -06:00
use crate::ich::{Fingerprint, StableHashingContext, NodeIdHashingMode};
2018-07-10 19:16:22 +02:00
use std::fmt;
use std::hash::Hash;
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
2017-10-25 17:04:24 +02:00
pub enum MonoItem<'tcx> {
Fn(Instance<'tcx>),
Static(DefId),
GlobalAsm(NodeId),
}
2018-01-15 18:28:34 +00:00
impl<'tcx> MonoItem<'tcx> {
pub fn size_estimate<'a>(&self, tcx: &TyCtxt<'a, 'tcx, 'tcx>) -> usize {
match *self {
MonoItem::Fn(instance) => {
// Estimate the size of a function based on how many statements
// it contains.
2018-01-19 00:32:58 +00:00
tcx.instance_def_size_estimate(instance.def)
2018-01-15 18:28:34 +00:00
},
// Conservatively estimate the size of a static declaration
// or assembly to be 1.
Upgrade to LLVM's master branch (LLVM 7) This commit upgrades the main LLVM submodule to LLVM's current master branch. The LLD submodule is updated in tandem as well as compiler-builtins. Along the way support was also added for LLVM 7's new features. This primarily includes the support for custom section concatenation natively in LLD so we now add wasm custom sections in LLVM IR rather than having custom support in rustc itself for doing so. Some other miscellaneous changes are: * We now pass `--gc-sections` to `wasm-ld` * The optimization level is now passed to `wasm-ld` * A `--stack-first` option is passed to LLD to have stack overflow always cause a trap instead of corrupting static data * The wasm target for LLVM switched to `wasm32-unknown-unknown`. * The syntax for aligned pointers has changed in LLVM IR and tests are updated to reflect this. * The `thumbv6m-none-eabi` target is disabled due to an [LLVM bug][llbug] Nowadays we've been mostly only upgrading whenever there's a major release of LLVM but enough changes have been happening on the wasm target that there's been growing motivation for quite some time now to upgrade out version of LLD. To upgrade LLD, however, we need to upgrade LLVM to avoid needing to build yet another version of LLVM on the builders. The revision of LLVM in use here is arbitrarily chosen. We will likely need to continue to update it over time if and when we discover bugs. Once LLVM 7 is fully released we can switch to that channel as well. [llbug]: https://bugs.llvm.org/show_bug.cgi?id=37382
2018-06-01 10:20:00 -07:00
MonoItem::Static(_) |
MonoItem::GlobalAsm(_) => 1,
2018-01-15 18:28:34 +00:00
}
}
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
2017-09-18 12:14:52 +02:00
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
2017-09-18 12:14:52 +02:00
hasher: &mut StableHasher<W>) {
::std::mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
2017-10-25 17:04:24 +02:00
MonoItem::Fn(ref instance) => {
2017-09-18 12:14:52 +02:00
instance.hash_stable(hcx, hasher);
}
MonoItem::Static(def_id) => {
def_id.hash_stable(hcx, hasher);
}
2017-10-25 17:04:24 +02:00
MonoItem::GlobalAsm(node_id) => {
2017-09-18 12:14:52 +02:00
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
node_id.hash_stable(hcx, hasher);
})
}
}
}
}
pub struct CodegenUnit<'tcx> {
/// A name for this CGU. Incremental compilation requires that
/// name be unique amongst **all** crates. Therefore, it should
/// contain something unique to this crate (e.g., a module path)
/// as well as the crate name and disambiguator.
name: InternedString,
2017-10-25 17:04:24 +02:00
items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>,
2018-01-15 18:28:34 +00:00
size_estimate: Option<usize>,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum Linkage {
External,
AvailableExternally,
LinkOnceAny,
LinkOnceODR,
WeakAny,
WeakODR,
Appending,
Internal,
Private,
ExternalWeak,
Common,
}
2017-09-18 12:14:52 +02:00
impl_stable_hash_for!(enum self::Linkage {
External,
AvailableExternally,
LinkOnceAny,
LinkOnceODR,
WeakAny,
WeakODR,
Appending,
Internal,
Private,
ExternalWeak,
Common
});
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Visibility {
Default,
Hidden,
Protected,
}
2017-09-18 12:14:52 +02:00
impl_stable_hash_for!(enum self::Visibility {
Default,
Hidden,
Protected
});
impl<'tcx> CodegenUnit<'tcx> {
pub fn new(name: InternedString) -> CodegenUnit<'tcx> {
CodegenUnit {
name: name,
items: Default::default(),
2018-01-15 18:28:34 +00:00
size_estimate: None,
}
}
pub fn name(&self) -> &InternedString {
&self.name
}
pub fn set_name(&mut self, name: InternedString) {
self.name = name;
}
2017-10-25 17:04:24 +02:00
pub fn items(&self) -> &FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)> {
&self.items
}
pub fn items_mut(&mut self)
2017-10-25 17:04:24 +02:00
-> &mut FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>
{
&mut self.items
}
pub fn mangle_name(human_readable_name: &str) -> String {
// We generate a 80 bit hash from the name. This should be enough to
// avoid collisions and is still reasonably short for filenames.
let mut hasher = StableHasher::new();
human_readable_name.hash(&mut hasher);
let hash: u128 = hasher.finish();
let hash = hash & ((1u128 << 80) - 1);
base_n::encode(hash, base_n::CASE_INSENSITIVE)
}
2018-01-15 18:28:34 +00:00
pub fn estimate_size<'a>(&mut self, tcx: &TyCtxt<'a, 'tcx, 'tcx>) {
// Estimate the size of a codegen unit as (approximately) the number of MIR
// statements it corresponds to.
self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum());
}
pub fn size_estimate(&self) -> usize {
// Should only be called if `estimate_size` has previously been called.
self.size_estimate.expect("estimate_size must be called before getting a size_estimate")
2018-01-15 18:28:34 +00:00
}
pub fn modify_size_estimate(&mut self, delta: usize) {
assert!(self.size_estimate.is_some());
if let Some(size_estimate) = self.size_estimate {
self.size_estimate = Some(size_estimate + delta);
}
}
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> {
2017-09-18 12:14:52 +02:00
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
2017-09-18 12:14:52 +02:00
hasher: &mut StableHasher<W>) {
let CodegenUnit {
ref items,
name,
// The size estimate is not relevant to the hash
size_estimate: _,
2017-09-18 12:14:52 +02:00
} = *self;
name.hash_stable(hcx, hasher);
2018-05-08 16:10:16 +03:00
let mut items: Vec<(Fingerprint, _)> = items.iter().map(|(mono_item, &attrs)| {
2017-09-18 12:14:52 +02:00
let mut hasher = StableHasher::new();
2018-05-08 16:10:16 +03:00
mono_item.hash_stable(hcx, &mut hasher);
let mono_item_fingerprint = hasher.finish();
(mono_item_fingerprint, attrs)
2017-09-18 12:14:52 +02:00
}).collect();
items.sort_unstable_by_key(|i| i.0);
items.hash_stable(hcx, hasher);
}
}
#[derive(Clone, Default)]
pub struct Stats {
pub n_glues_created: usize,
pub n_null_glues: usize,
pub n_real_glues: usize,
pub n_fns: usize,
pub n_inlines: usize,
pub n_closures: usize,
pub n_llvm_insns: usize,
pub llvm_insns: FxHashMap<String, usize>,
// (ident, llvm-instructions)
pub fn_stats: Vec<(String, usize)>,
}
2017-09-18 12:14:52 +02:00
impl_stable_hash_for!(struct self::Stats {
n_glues_created,
n_null_glues,
n_real_glues,
n_fns,
n_inlines,
n_closures,
n_llvm_insns,
llvm_insns,
fn_stats
});
impl Stats {
pub fn extend(&mut self, stats: Stats) {
self.n_glues_created += stats.n_glues_created;
self.n_null_glues += stats.n_null_glues;
self.n_real_glues += stats.n_real_glues;
self.n_fns += stats.n_fns;
self.n_inlines += stats.n_inlines;
self.n_closures += stats.n_closures;
self.n_llvm_insns += stats.n_llvm_insns;
for (k, v) in stats.llvm_insns {
*self.llvm_insns.entry(k).or_insert(0) += v;
}
self.fn_stats.extend(stats.fn_stats);
}
}
pub struct CodegenUnitNameBuilder<'a, 'gcx: 'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
cache: FxHashMap<CrateNum, String>,
}
impl<'a, 'gcx: 'tcx, 'tcx: 'a> CodegenUnitNameBuilder<'a, 'gcx, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
CodegenUnitNameBuilder {
tcx,
cache: Default::default(),
}
}
/// CGU names should fulfill the following requirements:
/// - They should be able to act as a file name on any kind of file system
/// - They should not collide with other CGU names, even for different versions
/// of the same crate.
///
/// Consequently, we don't use special characters except for '.' and '-' and we
/// prefix each name with the crate-name and crate-disambiguator.
///
/// This function will build CGU names of the form:
///
/// ```
/// <crate-name>.<crate-disambiguator>[-in-<local-crate-id>](-<component>)*[.<special-suffix>]
/// <local-crate-id> = <local-crate-name>.<local-crate-disambiguator>
/// ```
///
/// The '.' before `<special-suffix>` makes sure that names with a special
/// suffix can never collide with a name built out of regular Rust
/// identifiers (e.g., module paths).
pub fn build_cgu_name<I, C, S>(&mut self,
cnum: CrateNum,
components: I,
special_suffix: Option<S>)
-> InternedString
where I: IntoIterator<Item=C>,
C: fmt::Display,
S: fmt::Display,
{
let cgu_name = self.build_cgu_name_no_mangle(cnum,
components,
special_suffix);
if self.tcx.sess.opts.debugging_opts.human_readable_cgu_names {
cgu_name
} else {
let cgu_name = &cgu_name.as_str()[..];
Symbol::intern(&CodegenUnit::mangle_name(cgu_name)).as_interned_str()
}
}
/// Same as `CodegenUnit::build_cgu_name()` but will never mangle the
/// resulting name.
pub fn build_cgu_name_no_mangle<I, C, S>(&mut self,
cnum: CrateNum,
components: I,
special_suffix: Option<S>)
-> InternedString
where I: IntoIterator<Item=C>,
C: fmt::Display,
S: fmt::Display,
{
use std::fmt::Write;
let mut cgu_name = String::with_capacity(64);
// Start out with the crate name and disambiguator
let tcx = self.tcx;
let crate_prefix = self.cache.entry(cnum).or_insert_with(|| {
// Whenever the cnum is not LOCAL_CRATE we also mix in the
// local crate's ID. Otherwise there can be collisions between CGUs
// instantiating stuff for upstream crates.
let local_crate_id = if cnum != LOCAL_CRATE {
let local_crate_disambiguator =
format!("{}", tcx.crate_disambiguator(LOCAL_CRATE));
format!("-in-{}.{}",
tcx.crate_name(LOCAL_CRATE),
&local_crate_disambiguator[0 .. 8])
} else {
String::new()
};
2018-10-03 15:07:18 +02:00
let crate_disambiguator = tcx.crate_disambiguator(cnum).to_string();
// Using a shortened disambiguator of about 40 bits
format!("{}.{}{}",
tcx.crate_name(cnum),
&crate_disambiguator[0 .. 8],
local_crate_id)
});
write!(cgu_name, "{}", crate_prefix).unwrap();
// Add the components
for component in components {
write!(cgu_name, "-{}", component).unwrap();
}
if let Some(special_suffix) = special_suffix {
// We add a dot in here so it cannot clash with anything in a regular
// Rust identifier
write!(cgu_name, ".{}", special_suffix).unwrap();
}
Symbol::intern(&cgu_name[..]).as_interned_str()
}
}