Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preliminary work for incremental ThinLTO. #52266

Merged
merged 7 commits into from Jul 14, 2018
79 changes: 77 additions & 2 deletions src/librustc/mir/mono.rs
Expand Up @@ -8,15 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use hir::def_id::DefId;
use hir::def_id::{DefId, CrateNum};
use syntax::ast::NodeId;
use syntax::symbol::InternedString;
use syntax::symbol::{Symbol, InternedString};
use ty::{Instance, TyCtxt};
use util::nodemap::FxHashMap;
use rustc_data_structures::base_n;
use rustc_data_structures::stable_hasher::{HashStable, StableHasherResult,
StableHasher};
use ich::{Fingerprint, StableHashingContext, NodeIdHashingMode};
use std::fmt;
use std::hash::Hash;

#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
Expand Down Expand Up @@ -173,6 +174,80 @@ impl<'tcx> CodegenUnit<'tcx> {
self.size_estimate = Some(size_estimate + delta);
}
}

/// 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>(-<component>)*[.<special-suffix>]
/// ```
///
/// 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>(tcx: TyCtxt,
cnum: CrateNum,
components: I,
special_suffix: Option<S>)
-> InternedString
where I: IntoIterator<Item=C>,
C: fmt::Display,
S: fmt::Display,
{
let cgu_name = CodegenUnit::build_cgu_name_no_mangle(tcx,
cnum,
components,
special_suffix);

if 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>(tcx: TyCtxt,
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
write!(cgu_name,
"{}.{}",
tcx.crate_name(cnum),
tcx.crate_disambiguator(cnum)).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()
}
}

impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> {
Expand Down
9 changes: 9 additions & 0 deletions src/librustc/session/mod.rs
Expand Up @@ -26,6 +26,7 @@ use util::nodemap::{FxHashMap, FxHashSet};
use util::common::{duration_to_secs_str, ErrorReported};
use util::common::ProfileQueriesMsg;

use rustc_data_structures::base_n;
use rustc_data_structures::sync::{self, Lrc, Lock, LockCell, OneThread, Once, RwLock};

use syntax::ast::NodeId;
Expand Down Expand Up @@ -1185,6 +1186,14 @@ impl CrateDisambiguator {
}
}

impl fmt::Display for CrateDisambiguator {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let (a, b) = self.0.as_value();
let as_u128 = a as u128 | ((b as u128) << 64);
f.write_str(&base_n::encode(as_u128, base_n::CASE_INSENSITIVE))
}
}

impl From<Fingerprint> for CrateDisambiguator {
fn from(fingerprint: Fingerprint) -> CrateDisambiguator {
CrateDisambiguator(fingerprint)
Expand Down
53 changes: 45 additions & 8 deletions src/librustc_incremental/assert_module_sources.rs
Expand Up @@ -27,11 +27,11 @@
//! the HIR doesn't change as a result of the annotations, which might
//! perturb the reuse results.

use rustc::hir::def_id::LOCAL_CRATE;
use rustc::dep_graph::{DepNode, DepConstructor};
use rustc::mir::mono::CodegenUnit;
use rustc::ty::TyCtxt;
use syntax::ast;
use syntax_pos::symbol::Symbol;
use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_CODEGENED};

const MODULE: &'static str = "module";
Expand Down Expand Up @@ -72,34 +72,71 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
return;
}

let mname = self.field(attr, MODULE);
let mangled_cgu_name = CodegenUnit::mangle_name(&mname.as_str());
let mangled_cgu_name = Symbol::intern(&mangled_cgu_name).as_interned_str();
let user_path = self.field(attr, MODULE).as_str().to_string();
let crate_name = self.tcx.crate_name(LOCAL_CRATE).as_str().to_string();

if !user_path.starts_with(&crate_name) {
let msg = format!("Found malformed codegen unit name `{}`. \
Codegen units names must always start with the name of the \
crate (`{}` in this case).", user_path, crate_name);
self.tcx.sess.span_fatal(attr.span, &msg);
}

// Split of the "special suffix" if there is one.
let (user_path, cgu_special_suffix) = if let Some(index) = user_path.rfind(".") {
(&user_path[..index], Some(&user_path[index + 1 ..]))
} else {
(&user_path[..], None)
};

let mut cgu_path_components = user_path.split("-").collect::<Vec<_>>();

// Remove the crate name
assert_eq!(cgu_path_components.remove(0), crate_name);

let cgu_name = CodegenUnit::build_cgu_name(self.tcx,
LOCAL_CRATE,
cgu_path_components,
cgu_special_suffix);

debug!("mapping '{}' to cgu name '{}'", self.field(attr, MODULE), cgu_name);

let dep_node = DepNode::new(self.tcx,
DepConstructor::CompileCodegenUnit(mangled_cgu_name));
DepConstructor::CompileCodegenUnit(cgu_name));

if let Some(loaded_from_cache) = self.tcx.dep_graph.was_loaded_from_cache(&dep_node) {
match (disposition, loaded_from_cache) {
(Disposition::Reused, false) => {
self.tcx.sess.span_err(
attr.span,
&format!("expected module named `{}` to be Reused but is Codegened",
mname));
user_path));
}
(Disposition::Codegened, true) => {
self.tcx.sess.span_err(
attr.span,
&format!("expected module named `{}` to be Codegened but is Reused",
mname));
user_path));
}
(Disposition::Reused, true) |
(Disposition::Codegened, false) => {
// These are what we would expect.
}
}
} else {
self.tcx.sess.span_err(attr.span, &format!("no module named `{}`", mname));
let available_cgus = self.tcx
.collect_and_partition_mono_items(LOCAL_CRATE)
.1
.iter()
.map(|cgu| format!("{}", cgu.name()))
.collect::<Vec<String>>()
.join(", ");

self.tcx.sess.span_err(attr.span,
&format!("no module named `{}` (mangled: {}).\nAvailable modules: {}",
user_path,
cgu_name,
available_cgus));
}
}

Expand Down
68 changes: 22 additions & 46 deletions src/librustc_mir/monomorphize/partitioning.rs
Expand Up @@ -104,7 +104,7 @@

use monomorphize::collector::InliningMap;
use rustc::dep_graph::WorkProductId;
use rustc::hir::def_id::DefId;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::hir::map::DefPathData;
use rustc::mir::mono::{Linkage, Visibility};
use rustc::middle::exported_symbols::SymbolExportLevel;
Expand All @@ -114,7 +114,7 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet};
use std::collections::hash_map::Entry;
use std::cmp;
use syntax::ast::NodeId;
use syntax::symbol::{Symbol, InternedString};
use syntax::symbol::InternedString;
use rustc::mir::mono::MonoItem;
use monomorphize::item::{MonoItemExt, InstantiationMode};

Expand Down Expand Up @@ -204,16 +204,9 @@ impl<'tcx> CodegenUnitExt<'tcx> for CodegenUnit<'tcx> {

// Anything we can't find a proper codegen unit for goes into this.
fn fallback_cgu_name(tcx: TyCtxt) -> InternedString {
const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit";

if tcx.sess.opts.debugging_opts.human_readable_cgu_names {
Symbol::intern(FALLBACK_CODEGEN_UNIT).as_interned_str()
} else {
Symbol::intern(&CodegenUnit::mangle_name(FALLBACK_CODEGEN_UNIT)).as_interned_str()
}
CodegenUnit::build_cgu_name(tcx, LOCAL_CRATE, &["fallback"], Some("cgu"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may now do a bit more work than before. Ideally it would be cached (although I doubt this is the cause of the regression).

}


pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mono_items: I,
strategy: PartitioningStrategy,
Expand All @@ -224,8 +217,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// In the first step, we place all regular monomorphizations into their
// respective 'home' codegen unit. Regular monomorphizations are all
// functions and statics defined in the local crate.
let mut initial_partitioning = place_root_mono_items(tcx,
mono_items);
let mut initial_partitioning = place_root_mono_items(tcx, mono_items);

initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(&tcx));

Expand All @@ -234,7 +226,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// If the partitioning should produce a fixed count of codegen units, merge
// until that count is reached.
if let PartitioningStrategy::FixedUnitCount(count) = strategy {
merge_codegen_units(&mut initial_partitioning, count, &tcx.crate_name.as_str());
merge_codegen_units(tcx, &mut initial_partitioning, count);

debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
}
Expand Down Expand Up @@ -328,7 +320,7 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
};

let codegen_unit = codegen_units.entry(codegen_unit_name.clone())
.or_insert_with(make_codegen_unit);
.or_insert_with(make_codegen_unit);

let mut can_be_internalized = true;
let default_visibility = |id: DefId, is_generic: bool| {
Expand Down Expand Up @@ -491,9 +483,9 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}

fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<'tcx>,
target_cgu_count: usize,
crate_name: &str) {
fn merge_codegen_units<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>,
initial_partitioning: &mut PreInliningPartitioning<'tcx>,
target_cgu_count: usize) {
assert!(target_cgu_count >= 1);
let codegen_units = &mut initial_partitioning.codegen_units;

Expand Down Expand Up @@ -522,7 +514,7 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<
}

for (index, cgu) in codegen_units.iter_mut().enumerate() {
cgu.set_name(numbered_codegen_unit_name(crate_name, index));
cgu.set_name(numbered_codegen_unit_name(tcx, index));
}
}

Expand Down Expand Up @@ -727,42 +719,26 @@ fn compute_codegen_unit_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
volatile: bool)
-> InternedString {
// Unfortunately we cannot just use the `ty::item_path` infrastructure here
// because we need paths to modules and the DefIds of those are not
// available anymore for external items.
let mut cgu_name = String::with_capacity(64);

let def_path = tcx.def_path(def_id);
cgu_name.push_str(&tcx.crate_name(def_path.krate).as_str());

for part in tcx.def_path(def_id)
.data
.iter()
.take_while(|part| {
match part.data {
DefPathData::Module(..) => true,
_ => false,
}
}) {
cgu_name.push_str("-");
cgu_name.push_str(&part.data.as_interned_str().as_str());
}

if volatile {
cgu_name.push_str(".volatile");
}
let components = def_path.data.iter().take_while(|part| {
match part.data {
DefPathData::Module(..) => true,
_ => false,
}
}).map(|part| part.data.as_interned_str());

let cgu_name = if tcx.sess.opts.debugging_opts.human_readable_cgu_names {
cgu_name
let volatile_suffix = if volatile {
Some("volatile")
} else {
CodegenUnit::mangle_name(&cgu_name)
None
};

Symbol::intern(&cgu_name[..]).as_interned_str()
CodegenUnit::build_cgu_name(tcx, def_path.krate, components, volatile_suffix)
}

fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString {
Symbol::intern(&format!("{}{}", crate_name, index)).as_interned_str()
fn numbered_codegen_unit_name(tcx: TyCtxt, index: usize) -> InternedString {
CodegenUnit::build_cgu_name_no_mangle(tcx, LOCAL_CRATE, &["cgu"], Some(index))
}

fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Expand Down
2 changes: 1 addition & 1 deletion src/test/incremental/issue-39828/auxiliary/generic.rs
Expand Up @@ -11,7 +11,7 @@
// revisions:rpass1 rpass2
// compile-flags: -Z query-dep-graph

#![rustc_partition_reused(module="__rustc_fallback_codegen_unit", cfg="rpass2")]
#![rustc_partition_reused(module="generic-fallback.cgu", cfg="rpass2")]
#![feature(rustc_attrs)]

#![crate_type="rlib"]
Expand Down