]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_monomorphize/src/partitioning/merging.rs
Rollup merge of #103625 - WaffleLapkin:no_tyctxt_dogs_allowed, r=compiler-errors
[rust.git] / compiler / rustc_monomorphize / src / partitioning / merging.rs
1 use std::cmp;
2
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;
7
8 use super::PartitioningCx;
9 use crate::partitioning::PreInliningPartitioning;
10
11 pub fn merge_codegen_units<'tcx>(
12     cx: &PartitioningCx<'_, 'tcx>,
13     initial_partitioning: &mut PreInliningPartitioning<'tcx>,
14 ) {
15     assert!(cx.target_cgu_count >= 1);
16     let codegen_units = &mut initial_partitioning.codegen_units;
17
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
21     // from the input.
22     //
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(|a, b| a.name().as_str().partial_cmp(b.name().as_str()).unwrap());
28
29     // This map keeps track of what got merged into what.
30     let mut cgu_contents: FxHashMap<Symbol, Vec<Symbol>> =
31         codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect();
32
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();
39
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);
44         }
45
46         // Record that `second_smallest` now contains all the stuff that was in
47         // `smallest` before.
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);
50
51         debug!(
52             "CodegenUnit {} merged into CodegenUnit {}",
53             smallest.name(),
54             second_smallest.name()
55         );
56     }
57
58     let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
59
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
67             .into_iter()
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.as_str()).collect();
73
74                 // Sort the names, so things are deterministic and easy to
75                 // predict.
76
77                 // We are sorting primitive &strs here so we can use unstable sort
78                 cgu_contents.sort_unstable();
79
80                 (current_cgu_name, cgu_contents.join("--"))
81             })
82             .collect();
83
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.unstable_opts.human_readable_cgu_names {
87                     cgu.set_name(Symbol::intern(&new_cgu_name));
88                 } else {
89                     // If we don't require CGU names to be human-readable, we
90                     // use a fixed length hash of the composite CGU name
91                     // instead.
92                     let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name);
93                     cgu.set_name(Symbol::intern(&new_cgu_name));
94                 }
95             }
96         }
97     } else {
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));
102         }
103     }
104 }
105
106 fn numbered_codegen_unit_name(
107     name_builder: &mut CodegenUnitNameBuilder<'_>,
108     index: usize,
109 ) -> Symbol {
110     name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index))
111 }