Skip to content

Commit 02e01bd

Browse files
committed
Auto merge of #52309 - michaelwoerister:incr-thinlto-2, r=<try>
[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.
2 parents 68c39b9 + 4e28b6c commit 02e01bd

File tree

29 files changed

+707
-269
lines changed

29 files changed

+707
-269
lines changed

src/librustc/dep_graph/graph.rs

+82-33
Original file line numberDiff line numberDiff line change
@@ -204,13 +204,31 @@ impl DepGraph {
204204
where C: DepGraphSafe + StableHashingContextProvider<'gcx>,
205205
R: HashStable<StableHashingContext<'gcx>>,
206206
{
207-
self.with_task_impl(key, cx, arg, false, task,
207+
self.with_task_impl(key, cx, arg, false, true, task,
208208
|key| OpenTask::Regular(Lock::new(RegularOpenTask {
209209
node: key,
210210
reads: SmallVec::new(),
211211
read_set: FxHashSet(),
212212
})),
213-
|data, key, task| data.borrow_mut().complete_task(key, task))
213+
|data, key, task| data.borrow_mut().complete_task(key, task, false))
214+
}
215+
216+
pub fn with_forced_task<'gcx, C, A, R>(&self,
217+
key: DepNode,
218+
cx: C,
219+
arg: A,
220+
task: fn(C, A) -> R)
221+
-> (R, DepNodeIndex)
222+
where C: DepGraphSafe + StableHashingContextProvider<'gcx>,
223+
R: HashStable<StableHashingContext<'gcx>>,
224+
{
225+
self.with_task_impl(key, cx, arg, false, false, task,
226+
|key| OpenTask::Regular(Lock::new(RegularOpenTask {
227+
node: key,
228+
reads: SmallVec::new(),
229+
read_set: FxHashSet(),
230+
})),
231+
|data, key, task| data.borrow_mut().complete_task(key, task, true))
214232
}
215233

216234
/// Creates a new dep-graph input with value `input`
@@ -226,7 +244,7 @@ impl DepGraph {
226244
arg
227245
}
228246

229-
self.with_task_impl(key, cx, input, true, identity_fn,
247+
self.with_task_impl(key, cx, input, true, true, identity_fn,
230248
|_| OpenTask::Ignore,
231249
|data, key, _| data.borrow_mut().alloc_node(key, SmallVec::new()))
232250
}
@@ -237,6 +255,7 @@ impl DepGraph {
237255
cx: C,
238256
arg: A,
239257
no_tcx: bool,
258+
do_fingerprinting: bool,
240259
task: fn(C, A) -> R,
241260
create_task: fn(DepNode) -> OpenTask,
242261
finish_task_and_alloc_depnode: fn(&Lock<CurrentDepGraph>,
@@ -282,41 +301,58 @@ impl DepGraph {
282301

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

285-
let mut stable_hasher = StableHasher::new();
286-
result.hash_stable(&mut hcx, &mut stable_hasher);
304+
if do_fingerprinting {
305+
let mut stable_hasher = StableHasher::new();
306+
result.hash_stable(&mut hcx, &mut stable_hasher);
287307

288-
let current_fingerprint = stable_hasher.finish();
308+
let current_fingerprint = stable_hasher.finish();
289309

290-
// Store the current fingerprint
291-
{
292-
let mut fingerprints = self.fingerprints.borrow_mut();
310+
// Store the current fingerprint
311+
{
312+
let mut fingerprints = self.fingerprints.borrow_mut();
313+
314+
if dep_node_index.index() >= fingerprints.len() {
315+
fingerprints.resize(dep_node_index.index() + 1, Fingerprint::ZERO);
316+
}
293317

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

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

304-
// Determine the color of the new DepNode.
305-
if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
306-
let prev_fingerprint = data.previous.fingerprint_by_index(prev_index);
328+
let color = if current_fingerprint == prev_fingerprint {
329+
DepNodeColor::Green(dep_node_index)
330+
} else {
331+
DepNodeColor::Red
332+
};
307333

308-
let color = if current_fingerprint == prev_fingerprint {
309-
DepNodeColor::Green(dep_node_index)
310-
} else {
311-
DepNodeColor::Red
312-
};
334+
let mut colors = data.colors.borrow_mut();
335+
debug_assert!(colors.get(prev_index).is_none(),
336+
"DepGraph::with_task() - Duplicate DepNodeColor \
337+
insertion for {:?}", key);
338+
339+
colors.insert(prev_index, color);
340+
}
341+
} else {
342+
// Always store a ZERO fingerprint
343+
{
344+
let mut fingerprints = self.fingerprints.borrow_mut();
313345

314-
let mut colors = data.colors.borrow_mut();
315-
debug_assert!(colors.get(prev_index).is_none(),
316-
"DepGraph::with_task() - Duplicate DepNodeColor \
317-
insertion for {:?}", key);
346+
if dep_node_index.index() >= fingerprints.len() {
347+
fingerprints.resize(dep_node_index.index() + 1, Fingerprint::ZERO);
348+
}
349+
350+
fingerprints[dep_node_index] = Fingerprint::ZERO;
351+
}
318352

319-
colors.insert(prev_index, color);
353+
if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
354+
data.colors.borrow_mut().insert(prev_index, DepNodeColor::Red);
355+
}
320356
}
321357

322358
(result, dep_node_index)
@@ -378,7 +414,7 @@ impl DepGraph {
378414
}
379415

380416
/// Execute something within an "eval-always" task which is a task
381-
// that runs whenever anything changes.
417+
/// that runs whenever anything changes.
382418
pub fn with_eval_always_task<'gcx, C, A, R>(&self,
383419
key: DepNode,
384420
cx: C,
@@ -388,7 +424,7 @@ impl DepGraph {
388424
where C: DepGraphSafe + StableHashingContextProvider<'gcx>,
389425
R: HashStable<StableHashingContext<'gcx>>,
390426
{
391-
self.with_task_impl(key, cx, arg, false, task,
427+
self.with_task_impl(key, cx, arg, false, true, task,
392428
|key| OpenTask::EvalAlways { node: key },
393429
|data, key, task| data.borrow_mut().complete_eval_always_task(key, task))
394430
}
@@ -939,7 +975,11 @@ impl CurrentDepGraph {
939975
}
940976
}
941977

942-
fn complete_task(&mut self, key: DepNode, task: OpenTask) -> DepNodeIndex {
978+
fn complete_task(&mut self,
979+
key: DepNode,
980+
task: OpenTask,
981+
allow_existing_dep_node: bool)
982+
-> DepNodeIndex {
943983
if let OpenTask::Regular(task) = task {
944984
let RegularOpenTask {
945985
node,
@@ -970,7 +1010,16 @@ impl CurrentDepGraph {
9701010
}
9711011
}
9721012

973-
self.alloc_node(node, reads)
1013+
if allow_existing_dep_node {
1014+
if let Some(&dep_node_index) = self.node_to_node_index.get(&node) {
1015+
self.edges[dep_node_index] = reads;
1016+
dep_node_index
1017+
} else {
1018+
self.alloc_node(node, reads)
1019+
}
1020+
} else {
1021+
self.alloc_node(node, reads)
1022+
}
9741023
} else {
9751024
bug!("complete_task() - Expected regular task to be popped")
9761025
}

src/librustc/mir/mono.rs

+77-2
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use hir::def_id::DefId;
11+
use hir::def_id::{DefId, CrateNum};
1212
use syntax::ast::NodeId;
13-
use syntax::symbol::InternedString;
13+
use syntax::symbol::{Symbol, InternedString};
1414
use ty::{Instance, TyCtxt};
1515
use util::nodemap::FxHashMap;
1616
use rustc_data_structures::base_n;
1717
use rustc_data_structures::stable_hasher::{HashStable, StableHasherResult,
1818
StableHasher};
1919
use ich::{Fingerprint, StableHashingContext, NodeIdHashingMode};
20+
use std::fmt;
2021
use std::hash::Hash;
2122

2223
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
@@ -173,6 +174,80 @@ impl<'tcx> CodegenUnit<'tcx> {
173174
self.size_estimate = Some(size_estimate + delta);
174175
}
175176
}
177+
178+
/// CGU names should fulfill the following requirements:
179+
/// - They should be able to act as a file name on any kind of file system
180+
/// - They should not collide with other CGU names, even for different versions
181+
/// of the same crate.
182+
///
183+
/// Consequently, we don't use special characters except for '.' and '-' and we
184+
/// prefix each name with the crate-name and crate-disambiguator.
185+
///
186+
/// This function will build CGU names of the form:
187+
///
188+
/// ```
189+
/// <crate-name>.<crate-disambiguator>(-<component>)*[.<special-suffix>]
190+
/// ```
191+
///
192+
/// The '.' before `<special-suffix>` makes sure that names with a special
193+
/// suffix can never collide with a name built out of regular Rust
194+
/// identifiers (e.g. module paths).
195+
pub fn build_cgu_name<I, C, S>(tcx: TyCtxt,
196+
cnum: CrateNum,
197+
components: I,
198+
special_suffix: Option<S>)
199+
-> InternedString
200+
where I: IntoIterator<Item=C>,
201+
C: fmt::Display,
202+
S: fmt::Display,
203+
{
204+
let cgu_name = CodegenUnit::build_cgu_name_no_mangle(tcx,
205+
cnum,
206+
components,
207+
special_suffix);
208+
209+
if tcx.sess.opts.debugging_opts.human_readable_cgu_names {
210+
cgu_name
211+
} else {
212+
let cgu_name = &cgu_name.as_str()[..];
213+
Symbol::intern(&CodegenUnit::mangle_name(cgu_name)).as_interned_str()
214+
}
215+
}
216+
217+
/// Same as `CodegenUnit::build_cgu_name()` but will never mangle the
218+
/// resulting name.
219+
pub fn build_cgu_name_no_mangle<I, C, S>(tcx: TyCtxt,
220+
cnum: CrateNum,
221+
components: I,
222+
special_suffix: Option<S>)
223+
-> InternedString
224+
where I: IntoIterator<Item=C>,
225+
C: fmt::Display,
226+
S: fmt::Display,
227+
{
228+
use std::fmt::Write;
229+
230+
let mut cgu_name = String::with_capacity(64);
231+
232+
// Start out with the crate name and disambiguator
233+
write!(cgu_name,
234+
"{}.{}",
235+
tcx.crate_name(cnum),
236+
tcx.crate_disambiguator(cnum)).unwrap();
237+
238+
// Add the components
239+
for component in components {
240+
write!(cgu_name, "-{}", component).unwrap();
241+
}
242+
243+
if let Some(special_suffix) = special_suffix {
244+
// We add a dot in here so it cannot clash with anything in a regular
245+
// Rust identifier
246+
write!(cgu_name, ".{}", special_suffix).unwrap();
247+
}
248+
249+
Symbol::intern(&cgu_name[..]).as_interned_str()
250+
}
176251
}
177252

178253
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> {

src/librustc/session/config.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1973,7 +1973,7 @@ pub fn build_session_options_and_crate_config(
19731973
(&None, &None) => None,
19741974
}.map(|m| PathBuf::from(m));
19751975

1976-
if cg.lto != Lto::No && incremental.is_some() {
1976+
if cg.lto == Lto::Fat && incremental.is_some() {
19771977
early_error(
19781978
error_format,
19791979
"can't perform LTO when compiling incrementally",

src/librustc/session/mod.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use util::nodemap::{FxHashMap, FxHashSet};
2626
use util::common::{duration_to_secs_str, ErrorReported};
2727
use util::common::ProfileQueriesMsg;
2828

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

3132
use syntax::ast::NodeId;
@@ -582,11 +583,6 @@ impl Session {
582583
return config::Lto::No;
583584
}
584585

585-
// Right now ThinLTO isn't compatible with incremental compilation.
586-
if self.opts.incremental.is_some() {
587-
return config::Lto::No;
588-
}
589-
590586
// Now we're in "defaults" territory. By default we enable ThinLTO for
591587
// optimized compiles (anything greater than O0).
592588
match self.opts.optimize {
@@ -1185,6 +1181,14 @@ impl CrateDisambiguator {
11851181
}
11861182
}
11871183

1184+
impl fmt::Display for CrateDisambiguator {
1185+
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
1186+
let (a, b) = self.0.as_value();
1187+
let as_u128 = a as u128 | ((b as u128) << 64);
1188+
f.write_str(&base_n::encode(as_u128, base_n::CASE_INSENSITIVE))
1189+
}
1190+
}
1191+
11881192
impl From<Fingerprint> for CrateDisambiguator {
11891193
fn from(fingerprint: Fingerprint) -> CrateDisambiguator {
11901194
CrateDisambiguator(fingerprint)

src/librustc/ty/query/config.rs

-6
Original file line numberDiff line numberDiff line change
@@ -702,12 +702,6 @@ impl<'tcx> QueryDescription<'tcx> for queries::codegen_unit<'tcx> {
702702
}
703703
}
704704

705-
impl<'tcx> QueryDescription<'tcx> for queries::compile_codegen_unit<'tcx> {
706-
fn describe(_tcx: TyCtxt, _: InternedString) -> String {
707-
format!("compile_codegen_unit")
708-
}
709-
}
710-
711705
impl<'tcx> QueryDescription<'tcx> for queries::output_filenames<'tcx> {
712706
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
713707
format!("output_filenames")

src/librustc/ty/query/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use middle::stability::{self, DeprecationEntry};
2727
use middle::lang_items::{LanguageItems, LangItem};
2828
use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol};
2929
use mir::interpret::ConstEvalResult;
30-
use mir::mono::{CodegenUnit, Stats};
30+
use mir::mono::CodegenUnit;
3131
use mir;
3232
use mir::interpret::{GlobalId, Allocation};
3333
use session::{CompileResult, CrateDisambiguator};
@@ -436,7 +436,6 @@ define_queries! { <'tcx>
436436
-> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>),
437437
[] fn is_codegened_item: IsCodegenedItem(DefId) -> bool,
438438
[] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
439-
[] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats,
440439
[] fn output_filenames: output_filenames_node(CrateNum)
441440
-> Arc<OutputFilenames>,
442441

src/librustc_codegen_llvm/back/link.rs

-7
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,6 @@ use std::process::{Output, Stdio};
4545
use std::str;
4646
use syntax::attr;
4747

48-
/// The LLVM module name containing crate-metadata. This includes a `.` on
49-
/// purpose, so it cannot clash with the name of a user-defined module.
50-
pub const METADATA_MODULE_NAME: &'static str = "crate.metadata";
51-
52-
// same as for metadata above, but for allocator shim
53-
pub const ALLOCATOR_MODULE_NAME: &'static str = "crate.allocator";
54-
5548
pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default_output_for_target,
5649
invalid_output_for_target, build_link_meta, out_filename,
5750
check_file_is_writeable};

0 commit comments

Comments
 (0)