Skip to content

Commit 2c85069

Browse files
authored
Rollup merge of #112639 - nnethercote:fix-dead_code_cgu, r=wesleywiser
Fix `dead_code_cgu` computation This PR fixes a bug in `dead_code_cgu` computation, and also does some refactoring. r? ```@wesleywiser```
2 parents 48b645e + 2af5f22 commit 2c85069

File tree

1 file changed

+41
-44
lines changed

1 file changed

+41
-44
lines changed

compiler/rustc_monomorphize/src/partitioning.rs

+41-44
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,16 @@ where
155155
// functions and statics defined in the local crate.
156156
let PlacedRootMonoItems { mut codegen_units, internalization_candidates, unique_inlined_stats } = {
157157
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots");
158-
place_root_mono_items(cx, mono_items)
159-
};
158+
let mut placed = place_root_mono_items(cx, mono_items);
160159

161-
for cgu in &mut codegen_units {
162-
cgu.create_size_estimate(tcx);
163-
}
160+
for cgu in &mut placed.codegen_units {
161+
cgu.create_size_estimate(tcx);
162+
}
164163

165-
debug_dump(tcx, "ROOTS", &codegen_units, unique_inlined_stats);
164+
debug_dump(tcx, "ROOTS", &placed.codegen_units, placed.unique_inlined_stats);
165+
166+
placed
167+
};
166168

167169
// Merge until we have at most `max_cgu_count` codegen units.
168170
// `merge_codegen_units` is responsible for updating the CGU size
@@ -179,59 +181,34 @@ where
179181
// local functions the definition of which is marked with `#[inline]`.
180182
{
181183
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
182-
place_inlined_mono_items(cx, &mut codegen_units)
183-
};
184+
place_inlined_mono_items(cx, &mut codegen_units);
184185

185-
for cgu in &mut codegen_units {
186-
cgu.create_size_estimate(tcx);
187-
}
186+
for cgu in &mut codegen_units {
187+
cgu.create_size_estimate(tcx);
188+
}
188189

189-
debug_dump(tcx, "INLINE", &codegen_units, unique_inlined_stats);
190+
debug_dump(tcx, "INLINE", &codegen_units, unique_inlined_stats);
191+
}
190192

191193
// Next we try to make as many symbols "internal" as possible, so LLVM has
192194
// more freedom to optimize.
193195
if !tcx.sess.link_dead_code() {
194196
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
195197
internalize_symbols(cx, &mut codegen_units, internalization_candidates);
198+
199+
debug_dump(tcx, "INTERNALIZE", &codegen_units, unique_inlined_stats);
196200
}
197201

202+
// Mark one CGU for dead code, if necessary.
198203
let instrument_dead_code =
199204
tcx.sess.instrument_coverage() && !tcx.sess.instrument_coverage_except_unused_functions();
200-
201205
if instrument_dead_code {
202-
assert!(
203-
codegen_units.len() > 0,
204-
"There must be at least one CGU that code coverage data can be generated in."
205-
);
206-
207-
// Find the smallest CGU that has exported symbols and put the dead
208-
// function stubs in that CGU. We look for exported symbols to increase
209-
// the likelihood the linker won't throw away the dead functions.
210-
// FIXME(#92165): In order to truly resolve this, we need to make sure
211-
// the object file (CGU) containing the dead function stubs is included
212-
// in the final binary. This will probably require forcing these
213-
// function symbols to be included via `-u` or `/include` linker args.
214-
let mut cgus: Vec<_> = codegen_units.iter_mut().collect();
215-
cgus.sort_by_key(|cgu| cgu.size_estimate());
216-
217-
let dead_code_cgu =
218-
if let Some(cgu) = cgus.into_iter().rev().find(|cgu| {
219-
cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External)
220-
}) {
221-
cgu
222-
} else {
223-
// If there are no CGUs that have externally linked items,
224-
// then we just pick the first CGU as a fallback.
225-
&mut codegen_units[0]
226-
};
227-
dead_code_cgu.make_code_coverage_dead_code_cgu();
206+
mark_code_coverage_dead_code_cgu(&mut codegen_units);
228207
}
229208

230209
// Ensure CGUs are sorted by name, so that we get deterministic results.
231210
assert!(codegen_units.is_sorted_by(|a, b| Some(a.name().as_str().cmp(b.name().as_str()))));
232211

233-
debug_dump(tcx, "FINAL", &codegen_units, unique_inlined_stats);
234-
235212
codegen_units
236213
}
237214

@@ -363,9 +340,7 @@ fn merge_codegen_units<'tcx>(
363340

364341
// Move the mono-items from `smallest` to `second_smallest`
365342
second_smallest.modify_size_estimate(smallest.size_estimate());
366-
for (k, v) in smallest.items_mut().drain() {
367-
second_smallest.items_mut().insert(k, v);
368-
}
343+
second_smallest.items_mut().extend(smallest.items_mut().drain());
369344

370345
// Record that `second_smallest` now contains all the stuff that was
371346
// in `smallest` before.
@@ -545,6 +520,28 @@ fn internalize_symbols<'tcx>(
545520
}
546521
}
547522

523+
fn mark_code_coverage_dead_code_cgu<'tcx>(codegen_units: &mut [CodegenUnit<'tcx>]) {
524+
assert!(!codegen_units.is_empty());
525+
526+
// Find the smallest CGU that has exported symbols and put the dead
527+
// function stubs in that CGU. We look for exported symbols to increase
528+
// the likelihood the linker won't throw away the dead functions.
529+
// FIXME(#92165): In order to truly resolve this, we need to make sure
530+
// the object file (CGU) containing the dead function stubs is included
531+
// in the final binary. This will probably require forcing these
532+
// function symbols to be included via `-u` or `/include` linker args.
533+
let dead_code_cgu = codegen_units
534+
.iter_mut()
535+
.filter(|cgu| cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External))
536+
.min_by_key(|cgu| cgu.size_estimate());
537+
538+
// If there are no CGUs that have externally linked items, then we just
539+
// pick the first CGU as a fallback.
540+
let dead_code_cgu = if let Some(cgu) = dead_code_cgu { cgu } else { &mut codegen_units[0] };
541+
542+
dead_code_cgu.make_code_coverage_dead_code_cgu();
543+
}
544+
548545
fn characteristic_def_id_of_mono_item<'tcx>(
549546
tcx: TyCtxt<'tcx>,
550547
mono_item: MonoItem<'tcx>,

0 commit comments

Comments
 (0)