1
+ use std:: cmp;
1
2
use std:: collections:: hash_map:: Entry ;
2
3
3
4
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
@@ -14,10 +15,7 @@ use rustc_span::symbol::Symbol;
14
15
15
16
use super :: PartitioningCx ;
16
17
use crate :: collector:: InliningMap ;
17
- use crate :: partitioning:: merging;
18
- use crate :: partitioning:: {
19
- MonoItemPlacement , Partition , PostInliningPartitioning , PreInliningPartitioning ,
20
- } ;
18
+ use crate :: partitioning:: { MonoItemPlacement , Partition , PlacedRootMonoItems } ;
21
19
22
20
pub struct DefaultPartitioning ;
23
21
@@ -26,7 +24,7 @@ impl<'tcx> Partition<'tcx> for DefaultPartitioning {
26
24
& mut self ,
27
25
cx : & PartitioningCx < ' _ , ' tcx > ,
28
26
mono_items : & mut I ,
29
- ) -> PreInliningPartitioning < ' tcx >
27
+ ) -> PlacedRootMonoItems < ' tcx >
30
28
where
31
29
I : Iterator < Item = MonoItem < ' tcx > > ,
32
30
{
@@ -91,38 +89,120 @@ impl<'tcx> Partition<'tcx> for DefaultPartitioning {
91
89
codegen_units. insert ( codegen_unit_name, CodegenUnit :: new ( codegen_unit_name) ) ;
92
90
}
93
91
94
- PreInliningPartitioning {
95
- codegen_units : codegen_units. into_values ( ) . collect ( ) ,
96
- roots,
97
- internalization_candidates,
98
- }
92
+ let codegen_units = codegen_units. into_values ( ) . collect ( ) ;
93
+ PlacedRootMonoItems { codegen_units, roots, internalization_candidates }
99
94
}
100
95
101
96
fn merge_codegen_units (
102
97
& mut self ,
103
98
cx : & PartitioningCx < ' _ , ' tcx > ,
104
- initial_partitioning : & mut PreInliningPartitioning < ' tcx > ,
99
+ codegen_units : & mut Vec < CodegenUnit < ' tcx > > ,
105
100
) {
106
- merging:: merge_codegen_units ( cx, initial_partitioning) ;
101
+ assert ! ( cx. target_cgu_count >= 1 ) ;
102
+
103
+ // Note that at this point in time the `codegen_units` here may not be
104
+ // in a deterministic order (but we know they're deterministically the
105
+ // same set). We want this merging to produce a deterministic ordering
106
+ // of codegen units from the input.
107
+ //
108
+ // Due to basically how we've implemented the merging below (merge the
109
+ // two smallest into each other) we're sure to start off with a
110
+ // deterministic order (sorted by name). This'll mean that if two cgus
111
+ // have the same size the stable sort below will keep everything nice
112
+ // and deterministic.
113
+ codegen_units. sort_by ( |a, b| a. name ( ) . as_str ( ) . cmp ( b. name ( ) . as_str ( ) ) ) ;
114
+
115
+ // This map keeps track of what got merged into what.
116
+ let mut cgu_contents: FxHashMap < Symbol , Vec < Symbol > > =
117
+ codegen_units. iter ( ) . map ( |cgu| ( cgu. name ( ) , vec ! [ cgu. name( ) ] ) ) . collect ( ) ;
118
+
119
+ // Merge the two smallest codegen units until the target size is
120
+ // reached.
121
+ while codegen_units. len ( ) > cx. target_cgu_count {
122
+ // Sort small cgus to the back
123
+ codegen_units. sort_by_cached_key ( |cgu| cmp:: Reverse ( cgu. size_estimate ( ) ) ) ;
124
+ let mut smallest = codegen_units. pop ( ) . unwrap ( ) ;
125
+ let second_smallest = codegen_units. last_mut ( ) . unwrap ( ) ;
126
+
127
+ // Move the mono-items from `smallest` to `second_smallest`
128
+ second_smallest. modify_size_estimate ( smallest. size_estimate ( ) ) ;
129
+ for ( k, v) in smallest. items_mut ( ) . drain ( ) {
130
+ second_smallest. items_mut ( ) . insert ( k, v) ;
131
+ }
132
+
133
+ // Record that `second_smallest` now contains all the stuff that was
134
+ // in `smallest` before.
135
+ let mut consumed_cgu_names = cgu_contents. remove ( & smallest. name ( ) ) . unwrap ( ) ;
136
+ cgu_contents. get_mut ( & second_smallest. name ( ) ) . unwrap ( ) . append ( & mut consumed_cgu_names) ;
137
+
138
+ debug ! (
139
+ "CodegenUnit {} merged into CodegenUnit {}" ,
140
+ smallest. name( ) ,
141
+ second_smallest. name( )
142
+ ) ;
143
+ }
144
+
145
+ let cgu_name_builder = & mut CodegenUnitNameBuilder :: new ( cx. tcx ) ;
146
+
147
+ if cx. tcx . sess . opts . incremental . is_some ( ) {
148
+ // If we are doing incremental compilation, we want CGU names to
149
+ // reflect the path of the source level module they correspond to.
150
+ // For CGUs that contain the code of multiple modules because of the
151
+ // merging done above, we use a concatenation of the names of all
152
+ // contained CGUs.
153
+ let new_cgu_names: FxHashMap < Symbol , String > = cgu_contents
154
+ . into_iter ( )
155
+ // This `filter` makes sure we only update the name of CGUs that
156
+ // were actually modified by merging.
157
+ . filter ( |( _, cgu_contents) | cgu_contents. len ( ) > 1 )
158
+ . map ( |( current_cgu_name, cgu_contents) | {
159
+ let mut cgu_contents: Vec < & str > =
160
+ cgu_contents. iter ( ) . map ( |s| s. as_str ( ) ) . collect ( ) ;
161
+
162
+ // Sort the names, so things are deterministic and easy to
163
+ // predict. We are sorting primitive `&str`s here so we can
164
+ // use unstable sort.
165
+ cgu_contents. sort_unstable ( ) ;
166
+
167
+ ( current_cgu_name, cgu_contents. join ( "--" ) )
168
+ } )
169
+ . collect ( ) ;
170
+
171
+ for cgu in codegen_units. iter_mut ( ) {
172
+ if let Some ( new_cgu_name) = new_cgu_names. get ( & cgu. name ( ) ) {
173
+ if cx. tcx . sess . opts . unstable_opts . human_readable_cgu_names {
174
+ cgu. set_name ( Symbol :: intern ( & new_cgu_name) ) ;
175
+ } else {
176
+ // If we don't require CGU names to be human-readable,
177
+ // we use a fixed length hash of the composite CGU name
178
+ // instead.
179
+ let new_cgu_name = CodegenUnit :: mangle_name ( & new_cgu_name) ;
180
+ cgu. set_name ( Symbol :: intern ( & new_cgu_name) ) ;
181
+ }
182
+ }
183
+ }
184
+ } else {
185
+ // If we are compiling non-incrementally we just generate simple CGU
186
+ // names containing an index.
187
+ for ( index, cgu) in codegen_units. iter_mut ( ) . enumerate ( ) {
188
+ let numbered_codegen_unit_name =
189
+ cgu_name_builder. build_cgu_name_no_mangle ( LOCAL_CRATE , & [ "cgu" ] , Some ( index) ) ;
190
+ cgu. set_name ( numbered_codegen_unit_name) ;
191
+ }
192
+ }
107
193
}
108
194
109
195
fn place_inlined_mono_items (
110
196
& mut self ,
111
197
cx : & PartitioningCx < ' _ , ' tcx > ,
112
- initial_partitioning : PreInliningPartitioning < ' tcx > ,
113
- ) -> PostInliningPartitioning < ' tcx > {
114
- let mut new_partitioning = Vec :: new ( ) ;
198
+ codegen_units : & mut [ CodegenUnit < ' tcx > ] ,
199
+ roots : FxHashSet < MonoItem < ' tcx > > ,
200
+ ) -> FxHashMap < MonoItem < ' tcx > , MonoItemPlacement > {
115
201
let mut mono_item_placements = FxHashMap :: default ( ) ;
116
202
117
- let PreInliningPartitioning {
118
- codegen_units : initial_cgus,
119
- roots,
120
- internalization_candidates,
121
- } = initial_partitioning;
122
-
123
- let single_codegen_unit = initial_cgus. len ( ) == 1 ;
203
+ let single_codegen_unit = codegen_units. len ( ) == 1 ;
124
204
125
- for old_codegen_unit in initial_cgus {
205
+ for old_codegen_unit in codegen_units . iter_mut ( ) {
126
206
// Collect all items that need to be available in this codegen unit.
127
207
let mut reachable = FxHashSet :: default ( ) ;
128
208
for root in old_codegen_unit. items ( ) . keys ( ) {
@@ -174,14 +254,10 @@ impl<'tcx> Partition<'tcx> for DefaultPartitioning {
174
254
}
175
255
}
176
256
177
- new_partitioning . push ( new_codegen_unit) ;
257
+ * old_codegen_unit = new_codegen_unit;
178
258
}
179
259
180
- return PostInliningPartitioning {
181
- codegen_units : new_partitioning,
182
- mono_item_placements,
183
- internalization_candidates,
184
- } ;
260
+ return mono_item_placements;
185
261
186
262
fn follow_inlining < ' tcx > (
187
263
mono_item : MonoItem < ' tcx > ,
@@ -201,14 +277,16 @@ impl<'tcx> Partition<'tcx> for DefaultPartitioning {
201
277
fn internalize_symbols (
202
278
& mut self ,
203
279
cx : & PartitioningCx < ' _ , ' tcx > ,
204
- partitioning : & mut PostInliningPartitioning < ' tcx > ,
280
+ codegen_units : & mut [ CodegenUnit < ' tcx > ] ,
281
+ mono_item_placements : FxHashMap < MonoItem < ' tcx > , MonoItemPlacement > ,
282
+ internalization_candidates : FxHashSet < MonoItem < ' tcx > > ,
205
283
) {
206
- if partitioning . codegen_units . len ( ) == 1 {
284
+ if codegen_units. len ( ) == 1 {
207
285
// Fast path for when there is only one codegen unit. In this case we
208
286
// can internalize all candidates, since there is nowhere else they
209
287
// could be accessed from.
210
- for cgu in & mut partitioning . codegen_units {
211
- for candidate in & partitioning . internalization_candidates {
288
+ for cgu in codegen_units {
289
+ for candidate in & internalization_candidates {
212
290
cgu. items_mut ( ) . insert ( * candidate, ( Linkage :: Internal , Visibility :: Default ) ) ;
213
291
}
214
292
}
@@ -225,15 +303,13 @@ impl<'tcx> Partition<'tcx> for DefaultPartitioning {
225
303
}
226
304
} ) ;
227
305
228
- let mono_item_placements = & partitioning. mono_item_placements ;
229
-
230
306
// For each internalization candidates in each codegen unit, check if it is
231
307
// accessed from outside its defining codegen unit.
232
- for cgu in & mut partitioning . codegen_units {
308
+ for cgu in codegen_units {
233
309
let home_cgu = MonoItemPlacement :: SingleCgu { cgu_name : cgu. name ( ) } ;
234
310
235
311
for ( accessee, linkage_and_visibility) in cgu. items_mut ( ) {
236
- if !partitioning . internalization_candidates . contains ( accessee) {
312
+ if !internalization_candidates. contains ( accessee) {
237
313
// This item is no candidate for internalizing, so skip it.
238
314
continue ;
239
315
}
0 commit comments