@@ -136,25 +136,21 @@ where
136
136
{
137
137
let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning" ) ;
138
138
139
+ let mut estimator = SizeEstimator :: new ( ) ;
140
+
139
141
// In the first step, we place all regular monomorphizations into their
140
142
// respective 'home' codegen unit. Regular monomorphizations are all
141
143
// functions and statics defined in the local crate.
142
- let mut initial_partitioning = {
144
+ let initial_partitioning = {
143
145
let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning_place_roots" ) ;
144
- place_root_mono_items ( tcx, mono_items)
146
+ place_root_mono_items ( tcx, mono_items, & mut estimator )
145
147
} ;
146
148
147
- initial_partitioning. codegen_units . iter_mut ( ) . for_each ( |cgu| cgu. estimate_size ( tcx) ) ;
148
-
149
- debug_dump ( tcx, "INITIAL PARTITIONING:" , initial_partitioning. codegen_units . iter ( ) ) ;
150
-
151
- // If the partitioning should produce a fixed count of codegen units, merge
152
- // until that count is reached.
153
- if let PartitioningStrategy :: FixedUnitCount ( count) = strategy {
154
- let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning_merge_cgus" ) ;
155
- merge_codegen_units ( tcx, & mut initial_partitioning, count) ;
156
- debug_dump ( tcx, "POST MERGING:" , initial_partitioning. codegen_units . iter ( ) ) ;
157
- }
149
+ debug_dump (
150
+ tcx,
151
+ "INITIAL PARTITIONING:" ,
152
+ initial_partitioning. codegen_units . iter ( ) ,
153
+ & mut estimator) ;
158
154
159
155
// In the next step, we use the inlining map to determine which additional
160
156
// monomorphizations have to go into each codegen unit. These additional
@@ -163,12 +159,18 @@ where
163
159
let mut post_inlining = {
164
160
let _prof_timer =
165
161
tcx. prof . generic_activity ( "cgu_partitioning_place_inline_items" ) ;
166
- place_inlined_mono_items ( initial_partitioning, inlining_map)
162
+ place_inlined_mono_items ( tcx , initial_partitioning, inlining_map, & mut estimator )
167
163
} ;
168
164
169
- post_inlining. codegen_units . iter_mut ( ) . for_each ( |cgu| cgu . estimate_size ( tcx ) ) ;
165
+ debug_dump ( tcx , "POST INLINING:" , post_inlining. codegen_units . iter ( ) , & mut estimator ) ;
170
166
171
- debug_dump ( tcx, "POST INLINING:" , post_inlining. codegen_units . iter ( ) ) ;
167
+ // If the partitioning should produce a fixed count of codegen units, merge
168
+ // until that count is reached.
169
+ if let PartitioningStrategy :: FixedUnitCount ( count) = strategy {
170
+ let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning_merge_cgus" ) ;
171
+ merge_codegen_units ( tcx, & mut post_inlining, count, & mut estimator) ;
172
+ debug_dump ( tcx, "POST MERGING:" , post_inlining. codegen_units . iter ( ) , & mut estimator) ;
173
+ }
172
174
173
175
// Next we try to make as many symbols "internal" as possible, so LLVM has
174
176
// more freedom to optimize.
@@ -181,7 +183,6 @@ where
181
183
// Finally, sort by codegen unit name, so that we get deterministic results.
182
184
let PostInliningPartitioning {
183
185
codegen_units : mut result,
184
- mono_item_placements : _,
185
186
internalization_candidates : _,
186
187
} = post_inlining;
187
188
@@ -192,6 +193,27 @@ where
192
193
result
193
194
}
194
195
196
+ struct SizeEstimator < ' tcx > {
197
+ cache : FxHashMap < MonoItem < ' tcx > , usize > ,
198
+ }
199
+ impl < ' tcx > SizeEstimator < ' tcx > {
200
+ pub fn new ( ) -> SizeEstimator < ' tcx > {
201
+ SizeEstimator { cache : Default :: default ( ) }
202
+ }
203
+ pub fn size_estimate ( & mut self , tcx : TyCtxt < ' tcx > , mono_item : MonoItem < ' tcx > ) -> usize {
204
+ * self . cache . entry ( mono_item) . or_insert_with ( || match mono_item {
205
+ MonoItem :: Fn ( instance) => {
206
+ // Estimate the size of a function based on how many statements
207
+ // it contains.
208
+ tcx. instance_def_size_estimate ( instance. def )
209
+ }
210
+ // Conservatively estimate the size of a static declaration
211
+ // or assembly to be 1.
212
+ MonoItem :: Static ( _) | MonoItem :: GlobalAsm ( _) => 1 ,
213
+ } )
214
+ }
215
+ }
216
+
195
217
struct PreInliningPartitioning < ' tcx > {
196
218
codegen_units : Vec < CodegenUnit < ' tcx > > ,
197
219
roots : FxHashSet < MonoItem < ' tcx > > ,
@@ -209,11 +231,14 @@ enum MonoItemPlacement {
209
231
210
232
struct PostInliningPartitioning < ' tcx > {
211
233
codegen_units : Vec < CodegenUnit < ' tcx > > ,
212
- mono_item_placements : FxHashMap < MonoItem < ' tcx > , MonoItemPlacement > ,
213
234
internalization_candidates : FxHashSet < MonoItem < ' tcx > > ,
214
235
}
215
236
216
- fn place_root_mono_items < ' tcx , I > ( tcx : TyCtxt < ' tcx > , mono_items : I ) -> PreInliningPartitioning < ' tcx >
237
+ fn place_root_mono_items < ' tcx , I > (
238
+ tcx : TyCtxt < ' tcx > ,
239
+ mono_items : I ,
240
+ estimator : & mut SizeEstimator < ' tcx > ,
241
+ ) -> PreInliningPartitioning < ' tcx >
217
242
where
218
243
I : Iterator < Item = MonoItem < ' tcx > > ,
219
244
{
@@ -264,8 +289,8 @@ where
264
289
if visibility == Visibility :: Hidden && can_be_internalized {
265
290
internalization_candidates. insert ( mono_item) ;
266
291
}
267
-
268
- codegen_unit. items_mut ( ) . insert ( mono_item, ( linkage, visibility) ) ;
292
+ let item_size = estimator . size_estimate ( tcx , mono_item ) ;
293
+ codegen_unit. add_item ( mono_item, ( linkage, visibility) , item_size ) ;
269
294
roots. insert ( mono_item) ;
270
295
}
271
296
@@ -477,11 +502,12 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit
477
502
478
503
fn merge_codegen_units < ' tcx > (
479
504
tcx : TyCtxt < ' tcx > ,
480
- initial_partitioning : & mut PreInliningPartitioning < ' tcx > ,
505
+ partitioning : & mut PostInliningPartitioning < ' tcx > ,
481
506
target_cgu_count : usize ,
507
+ estimator : & mut SizeEstimator < ' tcx > ,
482
508
) {
483
509
assert ! ( target_cgu_count >= 1 ) ;
484
- let codegen_units = & mut initial_partitioning . codegen_units ;
510
+ let codegen_units = & mut partitioning . codegen_units ;
485
511
486
512
// Note that at this point in time the `codegen_units` here may not be in a
487
513
// deterministic order (but we know they're deterministically the same set).
@@ -501,9 +527,9 @@ fn merge_codegen_units<'tcx>(
501
527
let mut smallest = codegen_units. pop ( ) . unwrap ( ) ;
502
528
let second_smallest = codegen_units. last_mut ( ) . unwrap ( ) ;
503
529
504
- second_smallest . modify_size_estimate ( smallest. size_estimate ( ) ) ;
505
- for ( k , v ) in smallest . items_mut ( ) . drain ( ) {
506
- second_smallest. items_mut ( ) . insert ( k , v) ;
530
+ for ( mono_item , v ) in smallest. items_mut ( ) . drain ( ) {
531
+ let item_size = estimator . size_estimate ( tcx , mono_item ) ;
532
+ second_smallest. add_item ( mono_item , v, item_size ) ;
507
533
}
508
534
debug ! ( "CodegenUnit {} merged in to CodegenUnit {}" ,
509
535
smallest. name( ) ,
@@ -516,20 +542,19 @@ fn merge_codegen_units<'tcx>(
516
542
}
517
543
}
518
544
519
- fn place_inlined_mono_items < ' tcx > ( initial_partitioning : PreInliningPartitioning < ' tcx > ,
520
- inlining_map : & InliningMap < ' tcx > )
521
- -> PostInliningPartitioning < ' tcx > {
545
+ fn place_inlined_mono_items < ' tcx > ( tcx : TyCtxt < ' tcx > ,
546
+ initial_partitioning : PreInliningPartitioning < ' tcx > ,
547
+ inlining_map : & InliningMap < ' tcx > ,
548
+ estimator : & mut SizeEstimator < ' tcx > ,
549
+ ) -> PostInliningPartitioning < ' tcx > {
522
550
let mut new_partitioning = Vec :: new ( ) ;
523
- let mut mono_item_placements = FxHashMap :: default ( ) ;
524
551
525
552
let PreInliningPartitioning {
526
553
codegen_units : initial_cgus,
527
554
roots,
528
555
internalization_candidates,
529
556
} = initial_partitioning;
530
557
531
- let single_codegen_unit = initial_cgus. len ( ) == 1 ;
532
-
533
558
for old_codegen_unit in initial_cgus {
534
559
// Collect all items that need to be available in this codegen unit.
535
560
let mut reachable = FxHashSet :: default ( ) ;
@@ -543,40 +568,20 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
543
568
for mono_item in reachable {
544
569
if let Some ( linkage) = old_codegen_unit. items ( ) . get ( & mono_item) {
545
570
// This is a root, just copy it over.
546
- new_codegen_unit. items_mut ( ) . insert ( mono_item, * linkage) ;
571
+ let item_size = estimator. size_estimate ( tcx, mono_item) ;
572
+ new_codegen_unit. add_item ( mono_item, * linkage, item_size) ;
547
573
} else {
548
574
if roots. contains ( & mono_item) {
549
575
bug ! ( "GloballyShared mono-item inlined into other CGU: \
550
576
{:?}", mono_item) ;
551
577
}
552
578
553
579
// This is a CGU-private copy.
554
- new_codegen_unit. items_mut ( ) . insert (
580
+ let item_size = estimator. size_estimate ( tcx, mono_item) ;
581
+ new_codegen_unit. add_item (
555
582
mono_item,
556
583
( Linkage :: Internal , Visibility :: Default ) ,
557
- ) ;
558
- }
559
-
560
- if !single_codegen_unit {
561
- // If there is more than one codegen unit, we need to keep track
562
- // in which codegen units each monomorphization is placed.
563
- match mono_item_placements. entry ( mono_item) {
564
- Entry :: Occupied ( e) => {
565
- let placement = e. into_mut ( ) ;
566
- debug_assert ! ( match * placement {
567
- MonoItemPlacement :: SingleCgu { ref cgu_name } => {
568
- * cgu_name != * new_codegen_unit. name( )
569
- }
570
- MonoItemPlacement :: MultipleCgus => true ,
571
- } ) ;
572
- * placement = MonoItemPlacement :: MultipleCgus ;
573
- }
574
- Entry :: Vacant ( e) => {
575
- e. insert ( MonoItemPlacement :: SingleCgu {
576
- cgu_name : new_codegen_unit. name ( ) . clone ( )
577
- } ) ;
578
- }
579
- }
584
+ item_size) ;
580
585
}
581
586
}
582
587
@@ -585,7 +590,6 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
585
590
586
591
return PostInliningPartitioning {
587
592
codegen_units : new_partitioning,
588
- mono_item_placements,
589
593
internalization_candidates,
590
594
} ;
591
595
@@ -632,7 +636,24 @@ fn internalize_symbols<'tcx>(
632
636
}
633
637
} ) ;
634
638
635
- let mono_item_placements = & partitioning. mono_item_placements ;
639
+ // If there is more than one codegen unit, we need to keep track
640
+ // in which codegen units each monomorphization is placed.
641
+ let mut mono_item_placements = FxHashMap :: default ( ) ;
642
+
643
+ for cgu in & partitioning. codegen_units {
644
+ for mono_item in cgu. items ( ) . keys ( ) {
645
+ match mono_item_placements. entry ( * mono_item) {
646
+ Entry :: Occupied ( e) => {
647
+ * e. into_mut ( ) = MonoItemPlacement :: MultipleCgus ;
648
+ }
649
+ Entry :: Vacant ( e) => {
650
+ e. insert ( MonoItemPlacement :: SingleCgu {
651
+ cgu_name : cgu. name ( ) . clone ( )
652
+ } ) ;
653
+ }
654
+ }
655
+ }
656
+ }
636
657
637
658
// For each internalization candidates in each codegen unit, check if it is
638
659
// accessed from outside its defining codegen unit.
@@ -781,7 +802,10 @@ fn numbered_codegen_unit_name(
781
802
name_builder. build_cgu_name_no_mangle ( LOCAL_CRATE , & [ "cgu" ] , Some ( index) )
782
803
}
783
804
784
- fn debug_dump < ' a , ' tcx , I > ( tcx : TyCtxt < ' tcx > , label : & str , cgus : I )
805
+ fn debug_dump < ' a , ' tcx , I > ( tcx : TyCtxt < ' tcx > ,
806
+ label : & str ,
807
+ cgus : I ,
808
+ estimator : & mut SizeEstimator < ' tcx > )
785
809
where
786
810
I : Iterator < Item = & ' a CodegenUnit < ' tcx > > ,
787
811
' tcx : ' a ,
@@ -801,7 +825,7 @@ where
801
825
mono_item. to_string( tcx, true ) ,
802
826
linkage,
803
827
symbol_hash,
804
- mono_item . size_estimate( tcx) ) ;
828
+ estimator . size_estimate( tcx, * mono_item ) ) ;
805
829
}
806
830
807
831
debug ! ( "" ) ;
0 commit comments