3 use rustc_data_structures
::fx
::FxHashMap
;
4 use rustc_hir
::def_id
::LOCAL_CRATE
;
5 use rustc_middle
::mir
::mono
::{CodegenUnit, CodegenUnitNameBuilder}
;
6 use rustc_span
::symbol
::{Symbol, SymbolStr}
;
8 use super::PartitioningCx
;
9 use crate::monomorphize
::partitioning
::PreInliningPartitioning
;
11 pub fn merge_codegen_units
<'tcx
>(
12 cx
: &PartitioningCx
<'_
, 'tcx
>,
13 initial_partitioning
: &mut PreInliningPartitioning
<'tcx
>,
15 assert
!(cx
.target_cgu_count
>= 1);
16 let codegen_units
= &mut initial_partitioning
.codegen_units
;
18 // Note that at this point in time the `codegen_units` here may not be in a
19 // deterministic order (but we know they're deterministically the same set).
20 // We want this merging to produce a deterministic ordering of codegen units
23 // Due to basically how we've implemented the merging below (merge the two
24 // smallest into each other) we're sure to start off with a deterministic
25 // order (sorted by name). This'll mean that if two cgus have the same size
26 // the stable sort below will keep everything nice and deterministic.
27 codegen_units
.sort_by_cached_key(|cgu
| cgu
.name().as_str());
29 // This map keeps track of what got merged into what.
30 let mut cgu_contents
: FxHashMap
<Symbol
, Vec
<SymbolStr
>> =
31 codegen_units
.iter().map(|cgu
| (cgu
.name(), vec
![cgu
.name().as_str()])).collect();
33 // Merge the two smallest codegen units until the target size is reached.
34 while codegen_units
.len() > cx
.target_cgu_count
{
35 // Sort small cgus to the back
36 codegen_units
.sort_by_cached_key(|cgu
| cmp
::Reverse(cgu
.size_estimate()));
37 let mut smallest
= codegen_units
.pop().unwrap();
38 let second_smallest
= codegen_units
.last_mut().unwrap();
40 // Move the mono-items from `smallest` to `second_smallest`
41 second_smallest
.modify_size_estimate(smallest
.size_estimate());
42 for (k
, v
) in smallest
.items_mut().drain() {
43 second_smallest
.items_mut().insert(k
, v
);
46 // Record that `second_smallest` now contains all the stuff that was in
48 let mut consumed_cgu_names
= cgu_contents
.remove(&smallest
.name()).unwrap();
49 cgu_contents
.get_mut(&second_smallest
.name()).unwrap().append(&mut consumed_cgu_names
);
52 "CodegenUnit {} merged into CodegenUnit {}",
54 second_smallest
.name()
58 let cgu_name_builder
= &mut CodegenUnitNameBuilder
::new(cx
.tcx
);
60 if cx
.tcx
.sess
.opts
.incremental
.is_some() {
61 // If we are doing incremental compilation, we want CGU names to
62 // reflect the path of the source level module they correspond to.
63 // For CGUs that contain the code of multiple modules because of the
64 // merging done above, we use a concatenation of the names of
65 // all contained CGUs.
66 let new_cgu_names
: FxHashMap
<Symbol
, String
> = cgu_contents
68 // This `filter` makes sure we only update the name of CGUs that
69 // were actually modified by merging.
70 .filter(|(_
, cgu_contents
)| cgu_contents
.len() > 1)
71 .map(|(current_cgu_name
, cgu_contents
)| {
72 let mut cgu_contents
: Vec
<&str> = cgu_contents
.iter().map(|s
| &s
[..]).collect();
74 // Sort the names, so things are deterministic and easy to
77 // We are sorting primitive &strs here so we can use unstable sort
78 cgu_contents
.sort_unstable();
80 (current_cgu_name
, cgu_contents
.join("--"))
84 for cgu
in codegen_units
.iter_mut() {
85 if let Some(new_cgu_name
) = new_cgu_names
.get(&cgu
.name()) {
86 if cx
.tcx
.sess
.opts
.debugging_opts
.human_readable_cgu_names
{
87 cgu
.set_name(Symbol
::intern(&new_cgu_name
));
89 // If we don't require CGU names to be human-readable, we
90 // use a fixed length hash of the composite CGU name
92 let new_cgu_name
= CodegenUnit
::mangle_name(&new_cgu_name
);
93 cgu
.set_name(Symbol
::intern(&new_cgu_name
));
98 // If we are compiling non-incrementally we just generate simple CGU
99 // names containing an index.
100 for (index
, cgu
) in codegen_units
.iter_mut().enumerate() {
101 cgu
.set_name(numbered_codegen_unit_name(cgu_name_builder
, index
));
106 fn numbered_codegen_unit_name(
107 name_builder
: &mut CodegenUnitNameBuilder
<'_
>,
110 name_builder
.build_cgu_name_no_mangle(LOCAL_CRATE
, &["cgu"], Some(index
))