Skip to content

Commit

Permalink
Auto merge of #52309 - michaelwoerister:incr-thinlto-2, r=<try>
Browse files Browse the repository at this point in the history
[wip] Enable ThinLTO with incremental compilation.

This (work-in-progress) PR allows for combining ThinLTO and incremental compilation. I'll write up something more detailed once the kinks are worked out. For now, I'm mostly interested in what this does to compile times.
  • Loading branch information
bors committed Jul 13, 2018
2 parents 68c39b9 + 4e28b6c commit 02e01bd
Show file tree
Hide file tree
Showing 29 changed files with 707 additions and 269 deletions.
115 changes: 82 additions & 33 deletions src/librustc/dep_graph/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,31 @@ impl DepGraph {
where C: DepGraphSafe + StableHashingContextProvider<'gcx>,
R: HashStable<StableHashingContext<'gcx>>,
{
self.with_task_impl(key, cx, arg, false, task,
self.with_task_impl(key, cx, arg, false, true, task,
|key| OpenTask::Regular(Lock::new(RegularOpenTask {
node: key,
reads: SmallVec::new(),
read_set: FxHashSet(),
})),
|data, key, task| data.borrow_mut().complete_task(key, task))
|data, key, task| data.borrow_mut().complete_task(key, task, false))
}

pub fn with_forced_task<'gcx, C, A, R>(&self,
key: DepNode,
cx: C,
arg: A,
task: fn(C, A) -> R)
-> (R, DepNodeIndex)
where C: DepGraphSafe + StableHashingContextProvider<'gcx>,
R: HashStable<StableHashingContext<'gcx>>,
{
self.with_task_impl(key, cx, arg, false, false, task,
|key| OpenTask::Regular(Lock::new(RegularOpenTask {
node: key,
reads: SmallVec::new(),
read_set: FxHashSet(),
})),
|data, key, task| data.borrow_mut().complete_task(key, task, true))
}

/// Creates a new dep-graph input with value `input`
Expand All @@ -226,7 +244,7 @@ impl DepGraph {
arg
}

self.with_task_impl(key, cx, input, true, identity_fn,
self.with_task_impl(key, cx, input, true, true, identity_fn,
|_| OpenTask::Ignore,
|data, key, _| data.borrow_mut().alloc_node(key, SmallVec::new()))
}
Expand All @@ -237,6 +255,7 @@ impl DepGraph {
cx: C,
arg: A,
no_tcx: bool,
do_fingerprinting: bool,
task: fn(C, A) -> R,
create_task: fn(DepNode) -> OpenTask,
finish_task_and_alloc_depnode: fn(&Lock<CurrentDepGraph>,
Expand Down Expand Up @@ -282,41 +301,58 @@ impl DepGraph {

let dep_node_index = finish_task_and_alloc_depnode(&data.current, key, open_task);

let mut stable_hasher = StableHasher::new();
result.hash_stable(&mut hcx, &mut stable_hasher);
if do_fingerprinting {
let mut stable_hasher = StableHasher::new();
result.hash_stable(&mut hcx, &mut stable_hasher);

let current_fingerprint = stable_hasher.finish();
let current_fingerprint = stable_hasher.finish();

// Store the current fingerprint
{
let mut fingerprints = self.fingerprints.borrow_mut();
// Store the current fingerprint
{
let mut fingerprints = self.fingerprints.borrow_mut();

if dep_node_index.index() >= fingerprints.len() {
fingerprints.resize(dep_node_index.index() + 1, Fingerprint::ZERO);
}

if dep_node_index.index() >= fingerprints.len() {
fingerprints.resize(dep_node_index.index() + 1, Fingerprint::ZERO);
debug_assert!(fingerprints[dep_node_index] == Fingerprint::ZERO,
"DepGraph::with_task() - Duplicate fingerprint \
insertion for {:?}", key);
fingerprints[dep_node_index] = current_fingerprint;
}

debug_assert!(fingerprints[dep_node_index] == Fingerprint::ZERO,
"DepGraph::with_task() - Duplicate fingerprint \
insertion for {:?}", key);
fingerprints[dep_node_index] = current_fingerprint;
}
// Determine the color of the new DepNode.
if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
let prev_fingerprint = data.previous.fingerprint_by_index(prev_index);

// Determine the color of the new DepNode.
if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
let prev_fingerprint = data.previous.fingerprint_by_index(prev_index);
let color = if current_fingerprint == prev_fingerprint {
DepNodeColor::Green(dep_node_index)
} else {
DepNodeColor::Red
};

let color = if current_fingerprint == prev_fingerprint {
DepNodeColor::Green(dep_node_index)
} else {
DepNodeColor::Red
};
let mut colors = data.colors.borrow_mut();
debug_assert!(colors.get(prev_index).is_none(),
"DepGraph::with_task() - Duplicate DepNodeColor \
insertion for {:?}", key);

colors.insert(prev_index, color);
}
} else {
// Always store a ZERO fingerprint
{
let mut fingerprints = self.fingerprints.borrow_mut();

let mut colors = data.colors.borrow_mut();
debug_assert!(colors.get(prev_index).is_none(),
"DepGraph::with_task() - Duplicate DepNodeColor \
insertion for {:?}", key);
if dep_node_index.index() >= fingerprints.len() {
fingerprints.resize(dep_node_index.index() + 1, Fingerprint::ZERO);
}

fingerprints[dep_node_index] = Fingerprint::ZERO;
}

colors.insert(prev_index, color);
if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
data.colors.borrow_mut().insert(prev_index, DepNodeColor::Red);
}
}

(result, dep_node_index)
Expand Down Expand Up @@ -378,7 +414,7 @@ impl DepGraph {
}

/// Execute something within an "eval-always" task which is a task
// that runs whenever anything changes.
/// that runs whenever anything changes.
pub fn with_eval_always_task<'gcx, C, A, R>(&self,
key: DepNode,
cx: C,
Expand All @@ -388,7 +424,7 @@ impl DepGraph {
where C: DepGraphSafe + StableHashingContextProvider<'gcx>,
R: HashStable<StableHashingContext<'gcx>>,
{
self.with_task_impl(key, cx, arg, false, task,
self.with_task_impl(key, cx, arg, false, true, task,
|key| OpenTask::EvalAlways { node: key },
|data, key, task| data.borrow_mut().complete_eval_always_task(key, task))
}
Expand Down Expand Up @@ -939,7 +975,11 @@ impl CurrentDepGraph {
}
}

fn complete_task(&mut self, key: DepNode, task: OpenTask) -> DepNodeIndex {
fn complete_task(&mut self,
key: DepNode,
task: OpenTask,
allow_existing_dep_node: bool)
-> DepNodeIndex {
if let OpenTask::Regular(task) = task {
let RegularOpenTask {
node,
Expand Down Expand Up @@ -970,7 +1010,16 @@ impl CurrentDepGraph {
}
}

self.alloc_node(node, reads)
if allow_existing_dep_node {
if let Some(&dep_node_index) = self.node_to_node_index.get(&node) {
self.edges[dep_node_index] = reads;
dep_node_index
} else {
self.alloc_node(node, reads)
}
} else {
self.alloc_node(node, reads)
}
} else {
bug!("complete_task() - Expected regular task to be popped")
}
Expand Down
79 changes: 77 additions & 2 deletions src/librustc/mir/mono.rs
Original file line number Diff line number Diff line change
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
2 changes: 1 addition & 1 deletion src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1973,7 +1973,7 @@ pub fn build_session_options_and_crate_config(
(&None, &None) => None,
}.map(|m| PathBuf::from(m));

if cg.lto != Lto::No && incremental.is_some() {
if cg.lto == Lto::Fat && incremental.is_some() {
early_error(
error_format,
"can't perform LTO when compiling incrementally",
Expand Down
14 changes: 9 additions & 5 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
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 @@ -582,11 +583,6 @@ impl Session {
return config::Lto::No;
}

// Right now ThinLTO isn't compatible with incremental compilation.
if self.opts.incremental.is_some() {
return config::Lto::No;
}

// Now we're in "defaults" territory. By default we enable ThinLTO for
// optimized compiles (anything greater than O0).
match self.opts.optimize {
Expand Down Expand Up @@ -1185,6 +1181,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
6 changes: 0 additions & 6 deletions src/librustc/ty/query/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -702,12 +702,6 @@ impl<'tcx> QueryDescription<'tcx> for queries::codegen_unit<'tcx> {
}
}

impl<'tcx> QueryDescription<'tcx> for queries::compile_codegen_unit<'tcx> {
fn describe(_tcx: TyCtxt, _: InternedString) -> String {
format!("compile_codegen_unit")
}
}

impl<'tcx> QueryDescription<'tcx> for queries::output_filenames<'tcx> {
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
format!("output_filenames")
Expand Down
3 changes: 1 addition & 2 deletions src/librustc/ty/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use middle::stability::{self, DeprecationEntry};
use middle::lang_items::{LanguageItems, LangItem};
use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol};
use mir::interpret::ConstEvalResult;
use mir::mono::{CodegenUnit, Stats};
use mir::mono::CodegenUnit;
use mir;
use mir::interpret::{GlobalId, Allocation};
use session::{CompileResult, CrateDisambiguator};
Expand Down Expand Up @@ -436,7 +436,6 @@ define_queries! { <'tcx>
-> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>),
[] fn is_codegened_item: IsCodegenedItem(DefId) -> bool,
[] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
[] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats,
[] fn output_filenames: output_filenames_node(CrateNum)
-> Arc<OutputFilenames>,

Expand Down
7 changes: 0 additions & 7 deletions src/librustc_codegen_llvm/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,6 @@ use std::process::{Output, Stdio};
use std::str;
use syntax::attr;

/// The LLVM module name containing crate-metadata. This includes a `.` on
/// purpose, so it cannot clash with the name of a user-defined module.
pub const METADATA_MODULE_NAME: &'static str = "crate.metadata";

// same as for metadata above, but for allocator shim
pub const ALLOCATOR_MODULE_NAME: &'static str = "crate.allocator";

pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default_output_for_target,
invalid_output_for_target, build_link_meta, out_filename,
check_file_is_writeable};
Expand Down
Loading

0 comments on commit 02e01bd

Please sign in to comment.