Skip to content

Commit a7cbd92

Browse files
authored
Rollup merge of rust-lang#60385 - nnethercote:earlier-metadata, r=alexcrichton
Emit metadata files earlier This will make cargo pipelining much more effective.
2 parents 01ce87a + 38dffeb commit a7cbd92

File tree

10 files changed

+166
-156
lines changed

10 files changed

+166
-156
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2802,6 +2802,7 @@ dependencies = [
28022802
"rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
28032803
"rustc_allocator 0.0.0",
28042804
"rustc_borrowck 0.0.0",
2805+
"rustc_codegen_ssa 0.0.0",
28052806
"rustc_codegen_utils 0.0.0",
28062807
"rustc_data_structures 0.0.0",
28072808
"rustc_errors 0.0.0",
@@ -2821,6 +2822,7 @@ dependencies = [
28212822
"syntax 0.0.0",
28222823
"syntax_ext 0.0.0",
28232824
"syntax_pos 0.0.0",
2825+
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
28242826
]
28252827

28262828
[[package]]

src/librustc_codegen_llvm/base.rs

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use rustc::mir::mono::{Linkage, Visibility, Stats};
2828
use rustc::middle::cstore::{EncodedMetadata};
2929
use rustc::ty::TyCtxt;
3030
use rustc::middle::exported_symbols;
31-
use rustc::session::config::{self, DebugInfo};
31+
use rustc::session::config::DebugInfo;
3232
use rustc_codegen_ssa::mono_item::MonoItemExt;
3333
use rustc_data_structures::small_c_str::SmallCStr;
3434

@@ -42,47 +42,16 @@ use rustc::hir::CodegenFnAttrs;
4242

4343
use crate::value::Value;
4444

45-
46-
pub fn write_metadata<'a, 'gcx>(
45+
pub fn write_compressed_metadata<'a, 'gcx>(
4746
tcx: TyCtxt<'a, 'gcx, 'gcx>,
47+
metadata: &EncodedMetadata,
4848
llvm_module: &mut ModuleLlvm
49-
) -> EncodedMetadata {
49+
) {
5050
use std::io::Write;
5151
use flate2::Compression;
5252
use flate2::write::DeflateEncoder;
5353

5454
let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
55-
56-
#[derive(PartialEq, Eq, PartialOrd, Ord)]
57-
enum MetadataKind {
58-
None,
59-
Uncompressed,
60-
Compressed
61-
}
62-
63-
let kind = tcx.sess.crate_types.borrow().iter().map(|ty| {
64-
match *ty {
65-
config::CrateType::Executable |
66-
config::CrateType::Staticlib |
67-
config::CrateType::Cdylib => MetadataKind::None,
68-
69-
config::CrateType::Rlib => MetadataKind::Uncompressed,
70-
71-
config::CrateType::Dylib |
72-
config::CrateType::ProcMacro => MetadataKind::Compressed,
73-
}
74-
}).max().unwrap_or(MetadataKind::None);
75-
76-
if kind == MetadataKind::None {
77-
return EncodedMetadata::new();
78-
}
79-
80-
let metadata = tcx.encode_metadata();
81-
if kind == MetadataKind::Uncompressed {
82-
return metadata;
83-
}
84-
85-
assert!(kind == MetadataKind::Compressed);
8655
let mut compressed = tcx.metadata_encoding_version();
8756
DeflateEncoder::new(&mut compressed, Compression::fast())
8857
.write_all(&metadata.raw_data).unwrap();
@@ -107,7 +76,6 @@ pub fn write_metadata<'a, 'gcx>(
10776
let directive = CString::new(directive).unwrap();
10877
llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr())
10978
}
110-
return metadata;
11179
}
11280

11381
pub struct ValueIter<'ll> {

src/librustc_codegen_llvm/lib.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,13 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
110110
ModuleLlvm::new_metadata(tcx, mod_name)
111111
}
112112

113-
fn write_metadata<'b, 'gcx>(
113+
fn write_compressed_metadata<'b, 'gcx>(
114114
&self,
115115
tcx: TyCtxt<'b, 'gcx, 'gcx>,
116-
metadata: &mut ModuleLlvm
117-
) -> EncodedMetadata {
118-
base::write_metadata(tcx, metadata)
116+
metadata: &EncodedMetadata,
117+
llvm_module: &mut ModuleLlvm
118+
) {
119+
base::write_compressed_metadata(tcx, metadata, llvm_module)
119120
}
120121
fn codegen_allocator<'b, 'gcx>(
121122
&self,
@@ -289,9 +290,12 @@ impl CodegenBackend for LlvmCodegenBackend {
289290
fn codegen_crate<'b, 'tcx>(
290291
&self,
291292
tcx: TyCtxt<'b, 'tcx, 'tcx>,
293+
metadata: EncodedMetadata,
294+
need_metadata_module: bool,
292295
rx: mpsc::Receiver<Box<dyn Any + Send>>
293296
) -> Box<dyn Any> {
294-
box rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx, rx)
297+
box rustc_codegen_ssa::base::codegen_crate(
298+
LlvmCodegenBackend(()), tcx, metadata, need_metadata_module, rx)
295299
}
296300

297301
fn join_codegen_and_link(

src/librustc_codegen_ssa/back/link.rs

Lines changed: 44 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc::session::config::{
77
};
88
use rustc::session::search_paths::PathKind;
99
use rustc::middle::dependency_format::Linkage;
10-
use rustc::middle::cstore::{LibSource, NativeLibrary, NativeLibraryKind};
10+
use rustc::middle::cstore::{EncodedMetadata, LibSource, NativeLibrary, NativeLibraryKind};
1111
use rustc::util::common::{time, time_ext};
1212
use rustc::hir::def_id::CrateNum;
1313
use rustc_data_structures::fx::FxHashSet;
@@ -50,9 +50,9 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
5050
outputs: &OutputFilenames,
5151
crate_name: &str,
5252
target_cpu: &str) {
53+
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
5354
for &crate_type in sess.crate_types.borrow().iter() {
5455
// Ignore executable crates if we have -Z no-codegen, as they will error.
55-
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
5656
if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) &&
5757
!output_metadata &&
5858
crate_type == config::CrateType::Executable {
@@ -63,12 +63,43 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
6363
bug!("invalid output type `{:?}` for target os `{}`",
6464
crate_type, sess.opts.target_triple);
6565
}
66-
link_binary_output::<B>(sess,
67-
codegen_results,
68-
crate_type,
69-
outputs,
70-
crate_name,
71-
target_cpu);
66+
67+
for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
68+
check_file_is_writeable(obj, sess);
69+
}
70+
71+
let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err|
72+
sess.fatal(&format!("couldn't create a temp dir: {}", err)));
73+
74+
if outputs.outputs.should_codegen() {
75+
let out_filename = out_filename(sess, crate_type, outputs, crate_name);
76+
match crate_type {
77+
config::CrateType::Rlib => {
78+
link_rlib::<B>(sess,
79+
codegen_results,
80+
RlibFlavor::Normal,
81+
&out_filename,
82+
&tmpdir).build();
83+
}
84+
config::CrateType::Staticlib => {
85+
link_staticlib::<B>(sess, codegen_results, &out_filename, &tmpdir);
86+
}
87+
_ => {
88+
link_natively::<B>(
89+
sess,
90+
crate_type,
91+
&out_filename,
92+
codegen_results,
93+
tmpdir.path(),
94+
target_cpu,
95+
);
96+
}
97+
}
98+
}
99+
100+
if sess.opts.cg.save_temps {
101+
let _ = tmpdir.into_path();
102+
}
72103
}
73104

74105
// Remove the temporary object file and metadata if we aren't saving temps
@@ -85,7 +116,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
85116
if let Some(ref obj) = metadata_module.object {
86117
remove(sess, obj);
87118
}
88-
}
119+
}
89120
if let Some(ref allocator_module) = codegen_results.allocator_module {
90121
if let Some(ref obj) = allocator_module.object {
91122
remove(sess, obj);
@@ -97,73 +128,6 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
97128
}
98129
}
99130

100-
fn link_binary_output<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
101-
codegen_results: &CodegenResults,
102-
crate_type: config::CrateType,
103-
outputs: &OutputFilenames,
104-
crate_name: &str,
105-
target_cpu: &str) {
106-
for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
107-
check_file_is_writeable(obj, sess);
108-
}
109-
110-
if outputs.outputs.contains_key(&OutputType::Metadata) {
111-
let out_filename = filename_for_metadata(sess, crate_name, outputs);
112-
// To avoid races with another rustc process scanning the output directory,
113-
// we need to write the file somewhere else and atomically move it to its
114-
// final destination, with a `fs::rename` call. In order for the rename to
115-
// always succeed, the temporary file needs to be on the same filesystem,
116-
// which is why we create it inside the output directory specifically.
117-
let metadata_tmpdir = TempFileBuilder::new()
118-
.prefix("rmeta")
119-
.tempdir_in(out_filename.parent().unwrap())
120-
.unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
121-
let metadata = emit_metadata(sess, codegen_results, &metadata_tmpdir);
122-
match fs::rename(&metadata, &out_filename) {
123-
Ok(_) => {
124-
if sess.opts.debugging_opts.emit_directives {
125-
sess.parse_sess.span_diagnostic.maybe_emit_json_directive(
126-
format!("metadata file written: {}", out_filename.display()));
127-
}
128-
}
129-
Err(e) => sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)),
130-
}
131-
}
132-
133-
let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err|
134-
sess.fatal(&format!("couldn't create a temp dir: {}", err)));
135-
136-
if outputs.outputs.should_codegen() {
137-
let out_filename = out_filename(sess, crate_type, outputs, crate_name);
138-
match crate_type {
139-
config::CrateType::Rlib => {
140-
link_rlib::<B>(sess,
141-
codegen_results,
142-
RlibFlavor::Normal,
143-
&out_filename,
144-
&tmpdir).build();
145-
}
146-
config::CrateType::Staticlib => {
147-
link_staticlib::<B>(sess, codegen_results, &out_filename, &tmpdir);
148-
}
149-
_ => {
150-
link_natively::<B>(
151-
sess,
152-
crate_type,
153-
&out_filename,
154-
codegen_results,
155-
tmpdir.path(),
156-
target_cpu,
157-
);
158-
}
159-
}
160-
}
161-
162-
if sess.opts.cg.save_temps {
163-
let _ = tmpdir.into_path();
164-
}
165-
}
166-
167131
// The third parameter is for env vars, used on windows to set up the
168132
// path for MSVC to find its DLLs, and gcc to find its bundled
169133
// toolchain
@@ -261,13 +225,13 @@ pub fn each_linked_rlib(sess: &Session,
261225
/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
262226
/// directory being searched for `extern crate` (observing an incomplete file).
263227
/// The returned path is the temporary file containing the complete metadata.
264-
fn emit_metadata<'a>(
228+
pub fn emit_metadata<'a>(
265229
sess: &'a Session,
266-
codegen_results: &CodegenResults,
230+
metadata: &EncodedMetadata,
267231
tmpdir: &TempDir
268232
) -> PathBuf {
269233
let out_filename = tmpdir.path().join(METADATA_FILENAME);
270-
let result = fs::write(&out_filename, &codegen_results.metadata.raw_data);
234+
let result = fs::write(&out_filename, &metadata.raw_data);
271235

272236
if let Err(e) = result {
273237
sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
@@ -351,7 +315,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
351315
RlibFlavor::Normal => {
352316
// Instead of putting the metadata in an object file section, rlibs
353317
// contain the metadata in a separate file.
354-
ab.add_file(&emit_metadata(sess, codegen_results, tmpdir));
318+
ab.add_file(&emit_metadata(sess, &codegen_results.metadata, tmpdir));
355319

356320
// For LTO purposes, the bytecode of this library is also inserted
357321
// into the archive.

src/librustc_codegen_ssa/base.rs

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::{ModuleCodegen, ModuleKind, CachedModuleCodegen};
1717

1818
use rustc::dep_graph::cgu_reuse_tracker::CguReuse;
1919
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
20+
use rustc::middle::cstore::EncodedMetadata;
2021
use rustc::middle::lang_items::StartFnLangItem;
2122
use rustc::middle::weak_lang_items;
2223
use rustc::mir::mono::{Stats, CodegenUnitNameBuilder};
@@ -25,7 +26,7 @@ use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt};
2526
use rustc::ty::query::Providers;
2627
use rustc::middle::cstore::{self, LinkagePreference};
2728
use rustc::util::common::{time, print_time_passes_entry};
28-
use rustc::session::config::{self, CrateType, EntryFnType, Lto};
29+
use rustc::session::config::{self, EntryFnType, Lto};
2930
use rustc::session::Session;
3031
use rustc_mir::monomorphize::item::DefPathBasedNames;
3132
use rustc_mir::monomorphize::Instance;
@@ -530,26 +531,13 @@ pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX;
530531
pub fn codegen_crate<B: ExtraBackendMethods>(
531532
backend: B,
532533
tcx: TyCtxt<'a, 'tcx, 'tcx>,
534+
metadata: EncodedMetadata,
535+
need_metadata_module: bool,
533536
rx: mpsc::Receiver<Box<dyn Any + Send>>
534537
) -> OngoingCodegen<B> {
535538

536539
check_for_rustc_errors_attr(tcx);
537540

538-
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
539-
540-
// Codegen the metadata.
541-
tcx.sess.profiler(|p| p.start_activity("codegen crate metadata"));
542-
543-
let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE,
544-
&["crate"],
545-
Some("metadata")).as_str()
546-
.to_string();
547-
let mut metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name);
548-
let metadata = time(tcx.sess, "write metadata", || {
549-
backend.write_metadata(tcx, &mut metadata_llvm_module)
550-
});
551-
tcx.sess.profiler(|p| p.end_activity("codegen crate metadata"));
552-
553541
// Skip crate items and just output metadata in -Z no-codegen mode.
554542
if tcx.sess.opts.debugging_opts.no_codegen ||
555543
!tcx.sess.opts.output_types.should_codegen() {
@@ -569,6 +557,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
569557
return ongoing_codegen;
570558
}
571559

560+
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
561+
572562
// Run the monomorphization collector and partition the collected items into
573563
// codegen units.
574564
let codegen_units = tcx.collect_and_partition_mono_items(LOCAL_CRATE).1;
@@ -632,17 +622,21 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
632622
ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module);
633623
}
634624

635-
let needs_metadata_module = tcx.sess.crate_types.borrow().iter().any(|ct| {
636-
match *ct {
637-
CrateType::Dylib |
638-
CrateType::ProcMacro => true,
639-
CrateType::Executable |
640-
CrateType::Rlib |
641-
CrateType::Staticlib |
642-
CrateType::Cdylib => false,
643-
}
644-
});
645-
if needs_metadata_module {
625+
if need_metadata_module {
626+
// Codegen the encoded metadata.
627+
tcx.sess.profiler(|p| p.start_activity("codegen crate metadata"));
628+
629+
let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE,
630+
&["crate"],
631+
Some("metadata")).as_str()
632+
.to_string();
633+
let mut metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name);
634+
time(tcx.sess, "write compressed metadata", || {
635+
backend.write_compressed_metadata(tcx, &ongoing_codegen.metadata,
636+
&mut metadata_llvm_module);
637+
});
638+
tcx.sess.profiler(|p| p.end_activity("codegen crate metadata"));
639+
646640
let metadata_module = ModuleCodegen {
647641
name: metadata_cgu_name,
648642
module_llvm: metadata_llvm_module,

src/librustc_codegen_ssa/traits/backend.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ impl<'tcx, T> Backend<'tcx> for T where
3333

3434
pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send {
3535
fn new_metadata(&self, sess: TyCtxt<'_, '_, '_>, mod_name: &str) -> Self::Module;
36-
fn write_metadata<'b, 'gcx>(
36+
fn write_compressed_metadata<'b, 'gcx>(
3737
&self,
3838
tcx: TyCtxt<'b, 'gcx, 'gcx>,
39-
metadata: &mut Self::Module,
40-
) -> EncodedMetadata;
39+
metadata: &EncodedMetadata,
40+
llvm_module: &mut Self::Module,
41+
);
4142
fn codegen_allocator<'b, 'gcx>(
4243
&self,
4344
tcx: TyCtxt<'b, 'gcx, 'gcx>,

0 commit comments

Comments
 (0)