Skip to content

Commit ade6d2c

Browse files
authored
Rollup merge of rust-lang#98901 - davidtwco:split-dwarf-incr-workproduct, r=michaelwoerister
incr: cache dwarf objects in work products Cache DWARF objects alongside object files in work products when those exist so that DWARF object files are available for thorin in packed mode in incremental scenarios. r? `@michaelwoerister`
2 parents 776bb64 + e106523 commit ade6d2c

File tree

8 files changed

+147
-80
lines changed

8 files changed

+147
-80
lines changed

compiler/rustc_codegen_cranelift/src/driver/aot.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ fn emit_module(
6666
let work_product = if backend_config.disable_incr_cache {
6767
None
6868
} else {
69-
rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(tcx.sess, &name, &tmp_file)
69+
rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
70+
tcx.sess,
71+
&name,
72+
&[("o", &tmp_file)],
73+
)
7074
};
7175

7276
ModuleCodegenResult(
@@ -82,7 +86,10 @@ fn reuse_workproduct_for_cgu(
8286
) -> CompiledModule {
8387
let work_product = cgu.previous_work_product(tcx);
8488
let obj_out = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str()));
85-
let source_file = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, &work_product.saved_file);
89+
let source_file = rustc_incremental::in_incr_comp_dir_sess(
90+
&tcx.sess,
91+
&work_product.saved_files.get("o").expect("no saved object file in work product"),
92+
);
8693
if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
8794
tcx.sess.err(&format!(
8895
"unable to copy {} to {}: {}",

compiler/rustc_codegen_ssa/src/back/link.rs

+19-14
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,23 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
151151
return;
152152
}
153153

154-
let remove_temps_from_module = |module: &CompiledModule| {
155-
if let Some(ref obj) = module.object {
156-
ensure_removed(sess.diagnostic(), obj);
157-
}
158-
};
154+
let maybe_remove_temps_from_module =
155+
|preserve_objects: bool, preserve_dwarf_objects: bool, module: &CompiledModule| {
156+
if !preserve_objects {
157+
if let Some(ref obj) = module.object {
158+
ensure_removed(sess.diagnostic(), obj);
159+
}
160+
}
161+
162+
if !preserve_dwarf_objects {
163+
if let Some(ref dwo_obj) = module.dwarf_object {
164+
ensure_removed(sess.diagnostic(), dwo_obj);
165+
}
166+
}
167+
};
168+
169+
let remove_temps_from_module =
170+
|module: &CompiledModule| maybe_remove_temps_from_module(false, false, module);
159171

160172
// Otherwise, always remove the metadata and allocator module temporaries.
161173
if let Some(ref metadata_module) = codegen_results.metadata_module {
@@ -177,15 +189,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
177189
debug!(?preserve_objects, ?preserve_dwarf_objects);
178190

179191
for module in &codegen_results.modules {
180-
if !preserve_objects {
181-
remove_temps_from_module(module);
182-
}
183-
184-
if !preserve_dwarf_objects {
185-
if let Some(ref obj) = module.dwarf_object {
186-
ensure_removed(sess.diagnostic(), obj);
187-
}
188-
}
192+
maybe_remove_temps_from_module(preserve_objects, preserve_dwarf_objects, module);
189193
}
190194
});
191195

@@ -649,6 +653,7 @@ fn link_dwarf_object<'a>(
649653
sess.struct_err("linking dwarf objects with thorin failed")
650654
.note(&format!("{:?}", e))
651655
.emit();
656+
sess.abort_if_errors();
652657
}
653658
}
654659
}

compiler/rustc_codegen_ssa/src/back/write.rs

+51-24
Original file line numberDiff line numberDiff line change
@@ -494,12 +494,18 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
494494
let _timer = sess.timer("copy_all_cgu_workproducts_to_incr_comp_cache_dir");
495495

496496
for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
497-
if let Some(path) = &module.object {
498-
if let Some((id, product)) =
499-
copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, path)
500-
{
501-
work_products.insert(id, product);
502-
}
497+
let mut files = Vec::new();
498+
if let Some(object_file_path) = &module.object {
499+
files.push(("o", object_file_path.as_path()));
500+
}
501+
if let Some(dwarf_object_file_path) = &module.dwarf_object {
502+
files.push(("dwo", dwarf_object_file_path.as_path()));
503+
}
504+
505+
if let Some((id, product)) =
506+
copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, files.as_slice())
507+
{
508+
work_products.insert(id, product);
503509
}
504510
}
505511

@@ -856,29 +862,50 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
856862
assert!(module_config.emit_obj != EmitObj::None);
857863

858864
let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
859-
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name));
860-
let source_file = in_incr_comp_dir(&incr_comp_session_dir, &module.source.saved_file);
861-
debug!(
862-
"copying pre-existing module `{}` from {:?} to {}",
863-
module.name,
864-
source_file,
865-
obj_out.display()
865+
866+
let load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| {
867+
let source_file = in_incr_comp_dir(&incr_comp_session_dir, saved_path);
868+
debug!(
869+
"copying pre-existing module `{}` from {:?} to {}",
870+
module.name,
871+
source_file,
872+
output_path.display()
873+
);
874+
match link_or_copy(&source_file, &output_path) {
875+
Ok(_) => Some(output_path),
876+
Err(err) => {
877+
let diag_handler = cgcx.create_diag_handler();
878+
diag_handler.err(&format!(
879+
"unable to copy {} to {}: {}",
880+
source_file.display(),
881+
output_path.display(),
882+
err
883+
));
884+
None
885+
}
886+
}
887+
};
888+
889+
let object = load_from_incr_comp_dir(
890+
cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name)),
891+
&module.source.saved_files.get("o").expect("no saved object file in work product"),
866892
);
867-
if let Err(err) = link_or_copy(&source_file, &obj_out) {
868-
let diag_handler = cgcx.create_diag_handler();
869-
diag_handler.err(&format!(
870-
"unable to copy {} to {}: {}",
871-
source_file.display(),
872-
obj_out.display(),
873-
err
874-
));
875-
}
893+
let dwarf_object =
894+
module.source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file| {
895+
let dwarf_obj_out = cgcx
896+
.output_filenames
897+
.split_dwarf_path(cgcx.split_debuginfo, cgcx.split_dwarf_kind, Some(&module.name))
898+
.expect(
899+
"saved dwarf object in work product but `split_dwarf_path` returned `None`",
900+
);
901+
load_from_incr_comp_dir(dwarf_obj_out, &saved_dwarf_object_file)
902+
});
876903

877904
WorkItemResult::Compiled(CompiledModule {
878905
name: module.name,
879906
kind: ModuleKind::Regular,
880-
object: Some(obj_out),
881-
dwarf_object: None,
907+
object,
908+
dwarf_object,
882909
bytecode: None,
883910
})
884911
}

compiler/rustc_incremental/src/persist/load.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -161,19 +161,13 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
161161
Decodable::decode(&mut work_product_decoder);
162162

163163
for swp in work_products {
164-
let mut all_files_exist = true;
165-
let path = in_incr_comp_dir_sess(sess, &swp.work_product.saved_file);
166-
if !path.exists() {
167-
all_files_exist = false;
168-
169-
if sess.opts.debugging_opts.incremental_info {
170-
eprintln!(
171-
"incremental: could not find file for work \
172-
product: {}",
173-
path.display()
174-
);
164+
let all_files_exist = swp.work_product.saved_files.iter().all(|(_, path)| {
165+
let exists = in_incr_comp_dir_sess(sess, path).exists();
166+
if !exists && sess.opts.debugging_opts.incremental_info {
167+
eprintln!("incremental: could not find file for work product: {path}",);
175168
}
176-
}
169+
exists
170+
});
177171

178172
if all_files_exist {
179173
debug!("reconcile_work_products: all files for {:?} exist", swp);

compiler/rustc_incremental/src/persist/save.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -108,16 +108,17 @@ pub fn save_work_product_index(
108108
for (id, wp) in previous_work_products.iter() {
109109
if !new_work_products.contains_key(id) {
110110
work_product::delete_workproduct_files(sess, wp);
111-
debug_assert!(!in_incr_comp_dir_sess(sess, &wp.saved_file).exists());
111+
debug_assert!(
112+
!wp.saved_files.iter().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists())
113+
);
112114
}
113115
}
114116

115117
// Check that we did not delete one of the current work-products:
116118
debug_assert!({
117-
new_work_products
118-
.iter()
119-
.map(|(_, wp)| in_incr_comp_dir_sess(sess, &wp.saved_file))
120-
.all(|path| path.exists())
119+
new_work_products.iter().all(|(_, wp)| {
120+
wp.saved_files.iter().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists())
121+
})
121122
});
122123
}
123124

compiler/rustc_incremental/src/persist/work_product.rs

+25-21
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! [work products]: WorkProduct
44
55
use crate::persist::fs::*;
6+
use rustc_data_structures::stable_map::FxHashMap;
67
use rustc_fs_util::link_or_copy;
78
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
89
use rustc_session::Session;
@@ -13,38 +14,41 @@ use std::path::Path;
1314
pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
1415
sess: &Session,
1516
cgu_name: &str,
16-
path: &Path,
17+
files: &[(&'static str, &Path)],
1718
) -> Option<(WorkProductId, WorkProduct)> {
18-
debug!("copy_cgu_workproduct_to_incr_comp_cache_dir({:?},{:?})", cgu_name, path);
19+
debug!(?cgu_name, ?files);
1920
sess.opts.incremental.as_ref()?;
2021

21-
let file_name = format!("{}.o", cgu_name);
22-
let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
23-
let saved_file = match link_or_copy(path, &path_in_incr_dir) {
24-
Ok(_) => file_name,
25-
Err(err) => {
26-
sess.warn(&format!(
27-
"error copying object file `{}` to incremental directory as `{}`: {}",
28-
path.display(),
29-
path_in_incr_dir.display(),
30-
err
31-
));
32-
return None;
22+
let mut saved_files = FxHashMap::default();
23+
for (ext, path) in files {
24+
let file_name = format!("{cgu_name}.{ext}");
25+
let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
26+
match link_or_copy(path, &path_in_incr_dir) {
27+
Ok(_) => {
28+
let _ = saved_files.insert(ext.to_string(), file_name);
29+
}
30+
Err(err) => {
31+
sess.warn(&format!(
32+
"error copying object file `{}` to incremental directory as `{}`: {}",
33+
path.display(),
34+
path_in_incr_dir.display(),
35+
err
36+
));
37+
}
3338
}
34-
};
35-
36-
let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_file };
39+
}
3740

41+
let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_files };
42+
debug!(?work_product);
3843
let work_product_id = WorkProductId::from_cgu_name(cgu_name);
3944
Some((work_product_id, work_product))
4045
}
4146

4247
/// Removes files for a given work product.
4348
pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
44-
let path = in_incr_comp_dir_sess(sess, &work_product.saved_file);
45-
match std_fs::remove_file(&path) {
46-
Ok(()) => {}
47-
Err(err) => {
49+
for (_, path) in &work_product.saved_files {
50+
let path = in_incr_comp_dir_sess(sess, path);
51+
if let Err(err) = std_fs::remove_file(&path) {
4852
sess.warn(&format!(
4953
"file-system error deleting outdated file `{}`: {}",
5054
path.display(),

compiler/rustc_query_system/src/dep_graph/graph.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -886,8 +886,12 @@ impl<K: DepKind> DepGraph<K> {
886886
#[derive(Clone, Debug, Encodable, Decodable)]
887887
pub struct WorkProduct {
888888
pub cgu_name: String,
889-
/// Saved file associated with this CGU.
890-
pub saved_file: String,
889+
/// Saved files associated with this CGU. In each key/value pair, the value is the path to the
890+
/// saved file and the key is some identifier for the type of file being saved.
891+
///
892+
/// By convention, file extensions are currently used as identifiers, i.e. the key "o" maps to
893+
/// the object file's path, and "dwo" to the dwarf object file's path.
894+
pub saved_files: FxHashMap<String, String>,
891895
}
892896

893897
// Index type for `DepNodeData`'s edges.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Check that compiling with packed Split DWARF twice succeeds. This should confirm that DWARF
2+
// objects are cached as work products and available to the incremental compilation for `thorin` to
3+
// pack into a DWARF package.
4+
5+
// ignore-tidy-linelength
6+
// only-x86_64-unknown-linux-gnu
7+
// revisions:rpass1 rpass2
8+
9+
// [rpass1]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split
10+
// [rpass2]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split
11+
12+
#![feature(rustc_attrs)]
13+
// For `rpass2`, nothing has changed so everything should re-used.
14+
#![rustc_partition_reused(module = "split_debuginfo_cached", cfg = "rpass2")]
15+
#![rustc_partition_reused(module = "split_debuginfo_cached-another_module", cfg = "rpass2")]
16+
17+
mod another_module {
18+
pub fn foo() -> &'static str {
19+
"hello world"
20+
}
21+
}
22+
23+
pub fn main() {
24+
println!("{}", another_module::foo());
25+
}

0 commit comments

Comments
 (0)