@@ -125,7 +125,7 @@ struct PartitioningCx<'a, 'tcx> {
125
125
usage_map : & ' a UsageMap < ' tcx > ,
126
126
}
127
127
128
- struct PlacedRootMonoItems < ' tcx > {
128
+ struct PlacedMonoItems < ' tcx > {
129
129
/// The codegen units, sorted by name to make things deterministic.
130
130
codegen_units : Vec < CodegenUnit < ' tcx > > ,
131
131
@@ -150,18 +150,13 @@ where
150
150
151
151
let cx = & PartitioningCx { tcx, usage_map } ;
152
152
153
- // In the first step, we place all regular monomorphizations into their
154
- // respective 'home' codegen unit. Regular monomorphizations are all
155
- // functions and statics defined in the local crate.
156
- let PlacedRootMonoItems { mut codegen_units, internalization_candidates, unique_inlined_stats } = {
157
- let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning_place_roots" ) ;
158
- let mut placed = place_root_mono_items ( cx, mono_items) ;
153
+ // Place all mono items into a codegen unit. `place_mono_items` is
154
+ // responsible for initializing the CGU size estimates.
155
+ let PlacedMonoItems { mut codegen_units, internalization_candidates, unique_inlined_stats } = {
156
+ let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning_place_items" ) ;
157
+ let placed = place_mono_items ( cx, mono_items) ;
159
158
160
- for cgu in & mut placed. codegen_units {
161
- cgu. create_size_estimate ( tcx) ;
162
- }
163
-
164
- debug_dump ( tcx, "ROOTS" , & placed. codegen_units , placed. unique_inlined_stats ) ;
159
+ debug_dump ( tcx, "PLACE" , & placed. codegen_units , placed. unique_inlined_stats ) ;
165
160
166
161
placed
167
162
} ;
@@ -175,23 +170,8 @@ where
175
170
debug_dump ( tcx, "MERGE" , & codegen_units, unique_inlined_stats) ;
176
171
}
177
172
178
- // In the next step, we use the inlining map to determine which additional
179
- // monomorphizations have to go into each codegen unit. These additional
180
- // monomorphizations can be drop-glue, functions from external crates, and
181
- // local functions the definition of which is marked with `#[inline]`.
182
- {
183
- let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning_place_inline_items" ) ;
184
- place_inlined_mono_items ( cx, & mut codegen_units) ;
185
-
186
- for cgu in & mut codegen_units {
187
- cgu. create_size_estimate ( tcx) ;
188
- }
189
-
190
- debug_dump ( tcx, "INLINE" , & codegen_units, unique_inlined_stats) ;
191
- }
192
-
193
- // Next we try to make as many symbols "internal" as possible, so LLVM has
194
- // more freedom to optimize.
173
+ // Make as many symbols "internal" as possible, so LLVM has more freedom to
174
+ // optimize.
195
175
if !tcx. sess . link_dead_code ( ) {
196
176
let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning_internalize_symbols" ) ;
197
177
internalize_symbols ( cx, & mut codegen_units, internalization_candidates) ;
@@ -212,10 +192,7 @@ where
212
192
codegen_units
213
193
}
214
194
215
- fn place_root_mono_items < ' tcx , I > (
216
- cx : & PartitioningCx < ' _ , ' tcx > ,
217
- mono_items : I ,
218
- ) -> PlacedRootMonoItems < ' tcx >
195
+ fn place_mono_items < ' tcx , I > ( cx : & PartitioningCx < ' _ , ' tcx > , mono_items : I ) -> PlacedMonoItems < ' tcx >
219
196
where
220
197
I : Iterator < Item = MonoItem < ' tcx > > ,
221
198
{
@@ -236,6 +213,8 @@ where
236
213
let mut num_unique_inlined_items = 0 ;
237
214
let mut unique_inlined_items_size = 0 ;
238
215
for mono_item in mono_items {
216
+ // Handle only root items directly here. Inlined items are handled at
217
+ // the bottom of the loop based on reachability.
239
218
match mono_item. instantiation_mode ( cx. tcx ) {
240
219
InstantiationMode :: GloballyShared { .. } => { }
241
220
InstantiationMode :: LocalCopy => {
@@ -248,7 +227,7 @@ where
248
227
let characteristic_def_id = characteristic_def_id_of_mono_item ( cx. tcx , mono_item) ;
249
228
let is_volatile = is_incremental_build && mono_item. is_generic_fn ( ) ;
250
229
251
- let codegen_unit_name = match characteristic_def_id {
230
+ let cgu_name = match characteristic_def_id {
252
231
Some ( def_id) => compute_codegen_unit_name (
253
232
cx. tcx ,
254
233
cgu_name_builder,
@@ -259,9 +238,7 @@ where
259
238
None => fallback_cgu_name ( cgu_name_builder) ,
260
239
} ;
261
240
262
- let codegen_unit = codegen_units
263
- . entry ( codegen_unit_name)
264
- . or_insert_with ( || CodegenUnit :: new ( codegen_unit_name) ) ;
241
+ let cgu = codegen_units. entry ( cgu_name) . or_insert_with ( || CodegenUnit :: new ( cgu_name) ) ;
265
242
266
243
let mut can_be_internalized = true ;
267
244
let ( linkage, visibility) = mono_item_linkage_and_visibility (
@@ -274,23 +251,56 @@ where
274
251
internalization_candidates. insert ( mono_item) ;
275
252
}
276
253
277
- codegen_unit. items_mut ( ) . insert ( mono_item, ( linkage, visibility) ) ;
254
+ cgu. items_mut ( ) . insert ( mono_item, ( linkage, visibility) ) ;
255
+
256
+ // Get all inlined items that are reachable from `mono_item` without
257
+ // going via another root item. This includes drop-glue, functions from
258
+ // external crates, and local functions the definition of which is
259
+ // marked with `#[inline]`.
260
+ let mut reachable_inlined_items = FxHashSet :: default ( ) ;
261
+ get_reachable_inlined_items ( cx. tcx , mono_item, cx. usage_map , & mut reachable_inlined_items) ;
262
+
263
+ // Add those inlined items. It's possible an inlined item is reachable
264
+ // from multiple root items within a CGU, which is fine, it just means
265
+ // the `insert` will be a no-op.
266
+ for inlined_item in reachable_inlined_items {
267
+ // This is a CGU-private copy.
268
+ cgu. items_mut ( ) . insert ( inlined_item, ( Linkage :: Internal , Visibility :: Default ) ) ;
269
+ }
278
270
}
279
271
280
272
// Always ensure we have at least one CGU; otherwise, if we have a
281
273
// crate with just types (for example), we could wind up with no CGU.
282
274
if codegen_units. is_empty ( ) {
283
- let codegen_unit_name = fallback_cgu_name ( cgu_name_builder) ;
284
- codegen_units. insert ( codegen_unit_name , CodegenUnit :: new ( codegen_unit_name ) ) ;
275
+ let cgu_name = fallback_cgu_name ( cgu_name_builder) ;
276
+ codegen_units. insert ( cgu_name , CodegenUnit :: new ( cgu_name ) ) ;
285
277
}
286
278
287
279
let mut codegen_units: Vec < _ > = codegen_units. into_values ( ) . collect ( ) ;
288
280
codegen_units. sort_by ( |a, b| a. name ( ) . as_str ( ) . cmp ( b. name ( ) . as_str ( ) ) ) ;
289
281
290
- PlacedRootMonoItems {
282
+ for cgu in codegen_units. iter_mut ( ) {
283
+ cgu. compute_size_estimate ( cx. tcx ) ;
284
+ }
285
+
286
+ return PlacedMonoItems {
291
287
codegen_units,
292
288
internalization_candidates,
293
289
unique_inlined_stats : ( num_unique_inlined_items, unique_inlined_items_size) ,
290
+ } ;
291
+
292
+ fn get_reachable_inlined_items < ' tcx > (
293
+ tcx : TyCtxt < ' tcx > ,
294
+ item : MonoItem < ' tcx > ,
295
+ usage_map : & UsageMap < ' tcx > ,
296
+ visited : & mut FxHashSet < MonoItem < ' tcx > > ,
297
+ ) {
298
+ usage_map. for_each_inlined_used_item ( tcx, item, |inlined_item| {
299
+ let is_new = visited. insert ( inlined_item) ;
300
+ if is_new {
301
+ get_reachable_inlined_items ( tcx, inlined_item, usage_map, visited) ;
302
+ }
303
+ } ) ;
294
304
}
295
305
}
296
306
@@ -314,7 +324,7 @@ fn merge_codegen_units<'tcx>(
314
324
// worse generated code. So we don't allow CGUs smaller than this (unless
315
325
// there is just one CGU, of course). Note that CGU sizes of 100,000+ are
316
326
// common in larger programs, so this isn't all that large.
317
- const NON_INCR_MIN_CGU_SIZE : usize = 1000 ;
327
+ const NON_INCR_MIN_CGU_SIZE : usize = 1800 ;
318
328
319
329
// Repeatedly merge the two smallest codegen units as long as:
320
330
// - we have more CGUs than the upper limit, or
@@ -338,9 +348,11 @@ fn merge_codegen_units<'tcx>(
338
348
let mut smallest = codegen_units. pop ( ) . unwrap ( ) ;
339
349
let second_smallest = codegen_units. last_mut ( ) . unwrap ( ) ;
340
350
341
- // Move the mono-items from `smallest` to `second_smallest`
342
- second_smallest. modify_size_estimate ( smallest. size_estimate ( ) ) ;
351
+ // Move the items from `smallest` to `second_smallest`. Some of them
352
+ // may be duplicate inlined items, in which case the destination CGU is
353
+ // unaffected. Recalculate size estimates afterwards.
343
354
second_smallest. items_mut ( ) . extend ( smallest. items_mut ( ) . drain ( ) ) ;
355
+ second_smallest. compute_size_estimate ( cx. tcx ) ;
344
356
345
357
// Record that `second_smallest` now contains all the stuff that was
346
358
// in `smallest` before.
@@ -406,43 +418,6 @@ fn merge_codegen_units<'tcx>(
406
418
codegen_units. sort_by ( |a, b| a. name ( ) . as_str ( ) . cmp ( b. name ( ) . as_str ( ) ) ) ;
407
419
}
408
420
409
- fn place_inlined_mono_items < ' tcx > (
410
- cx : & PartitioningCx < ' _ , ' tcx > ,
411
- codegen_units : & mut [ CodegenUnit < ' tcx > ] ,
412
- ) {
413
- for cgu in codegen_units. iter_mut ( ) {
414
- // Collect all inlined items that need to be available in this codegen unit.
415
- let mut reachable_inlined_items = FxHashSet :: default ( ) ;
416
- for root in cgu. items ( ) . keys ( ) {
417
- // Get all inlined items that are reachable from it without going
418
- // via another root item.
419
- get_reachable_inlined_items ( cx. tcx , * root, cx. usage_map , & mut reachable_inlined_items) ;
420
- }
421
-
422
- // Add all monomorphizations that are not already there.
423
- for inlined_item in reachable_inlined_items {
424
- assert ! ( !cgu. items( ) . contains_key( & inlined_item) ) ;
425
-
426
- // This is a CGU-private copy.
427
- cgu. items_mut ( ) . insert ( inlined_item, ( Linkage :: Internal , Visibility :: Default ) ) ;
428
- }
429
- }
430
-
431
- fn get_reachable_inlined_items < ' tcx > (
432
- tcx : TyCtxt < ' tcx > ,
433
- item : MonoItem < ' tcx > ,
434
- usage_map : & UsageMap < ' tcx > ,
435
- visited : & mut FxHashSet < MonoItem < ' tcx > > ,
436
- ) {
437
- usage_map. for_each_inlined_used_item ( tcx, item, |inlined_item| {
438
- let is_new = visited. insert ( inlined_item) ;
439
- if is_new {
440
- get_reachable_inlined_items ( tcx, inlined_item, usage_map, visited) ;
441
- }
442
- } ) ;
443
- }
444
- }
445
-
446
421
fn internalize_symbols < ' tcx > (
447
422
cx : & PartitioningCx < ' _ , ' tcx > ,
448
423
codegen_units : & mut [ CodegenUnit < ' tcx > ] ,
0 commit comments