@@ -155,14 +155,16 @@ where
155
155
// functions and statics defined in the local crate.
156
156
let PlacedRootMonoItems { mut codegen_units, internalization_candidates, unique_inlined_stats } = {
157
157
let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning_place_roots" ) ;
158
- place_root_mono_items ( cx, mono_items)
159
- } ;
158
+ let mut placed = place_root_mono_items ( cx, mono_items) ;
160
159
161
- for cgu in & mut codegen_units {
162
- cgu. create_size_estimate ( tcx) ;
163
- }
160
+ for cgu in & mut placed . codegen_units {
161
+ cgu. create_size_estimate ( tcx) ;
162
+ }
164
163
165
- debug_dump ( tcx, "ROOTS" , & codegen_units, unique_inlined_stats) ;
164
+ debug_dump ( tcx, "ROOTS" , & placed. codegen_units , placed. unique_inlined_stats ) ;
165
+
166
+ placed
167
+ } ;
166
168
167
169
// Merge until we have at most `max_cgu_count` codegen units.
168
170
// `merge_codegen_units` is responsible for updating the CGU size
@@ -179,59 +181,34 @@ where
179
181
// local functions the definition of which is marked with `#[inline]`.
180
182
{
181
183
let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning_place_inline_items" ) ;
182
- place_inlined_mono_items ( cx, & mut codegen_units)
183
- } ;
184
+ place_inlined_mono_items ( cx, & mut codegen_units) ;
184
185
185
- for cgu in & mut codegen_units {
186
- cgu. create_size_estimate ( tcx) ;
187
- }
186
+ for cgu in & mut codegen_units {
187
+ cgu. create_size_estimate ( tcx) ;
188
+ }
188
189
189
- debug_dump ( tcx, "INLINE" , & codegen_units, unique_inlined_stats) ;
190
+ debug_dump ( tcx, "INLINE" , & codegen_units, unique_inlined_stats) ;
191
+ }
190
192
191
193
// Next we try to make as many symbols "internal" as possible, so LLVM has
192
194
// more freedom to optimize.
193
195
if !tcx. sess . link_dead_code ( ) {
194
196
let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning_internalize_symbols" ) ;
195
197
internalize_symbols ( cx, & mut codegen_units, internalization_candidates) ;
198
+
199
+ debug_dump ( tcx, "INTERNALIZE" , & codegen_units, unique_inlined_stats) ;
196
200
}
197
201
202
+ // Mark one CGU for dead code, if necessary.
198
203
let instrument_dead_code =
199
204
tcx. sess . instrument_coverage ( ) && !tcx. sess . instrument_coverage_except_unused_functions ( ) ;
200
-
201
205
if instrument_dead_code {
202
- assert ! (
203
- codegen_units. len( ) > 0 ,
204
- "There must be at least one CGU that code coverage data can be generated in."
205
- ) ;
206
-
207
- // Find the smallest CGU that has exported symbols and put the dead
208
- // function stubs in that CGU. We look for exported symbols to increase
209
- // the likelihood the linker won't throw away the dead functions.
210
- // FIXME(#92165): In order to truly resolve this, we need to make sure
211
- // the object file (CGU) containing the dead function stubs is included
212
- // in the final binary. This will probably require forcing these
213
- // function symbols to be included via `-u` or `/include` linker args.
214
- let mut cgus: Vec < _ > = codegen_units. iter_mut ( ) . collect ( ) ;
215
- cgus. sort_by_key ( |cgu| cgu. size_estimate ( ) ) ;
216
-
217
- let dead_code_cgu =
218
- if let Some ( cgu) = cgus. into_iter ( ) . rev ( ) . find ( |cgu| {
219
- cgu. items ( ) . iter ( ) . any ( |( _, ( linkage, _) ) | * linkage == Linkage :: External )
220
- } ) {
221
- cgu
222
- } else {
223
- // If there are no CGUs that have externally linked items,
224
- // then we just pick the first CGU as a fallback.
225
- & mut codegen_units[ 0 ]
226
- } ;
227
- dead_code_cgu. make_code_coverage_dead_code_cgu ( ) ;
206
+ mark_code_coverage_dead_code_cgu ( & mut codegen_units) ;
228
207
}
229
208
230
209
// Ensure CGUs are sorted by name, so that we get deterministic results.
231
210
assert ! ( codegen_units. is_sorted_by( |a, b| Some ( a. name( ) . as_str( ) . cmp( b. name( ) . as_str( ) ) ) ) ) ;
232
211
233
- debug_dump ( tcx, "FINAL" , & codegen_units, unique_inlined_stats) ;
234
-
235
212
codegen_units
236
213
}
237
214
@@ -363,9 +340,7 @@ fn merge_codegen_units<'tcx>(
363
340
364
341
// Move the mono-items from `smallest` to `second_smallest`
365
342
second_smallest. modify_size_estimate ( smallest. size_estimate ( ) ) ;
366
- for ( k, v) in smallest. items_mut ( ) . drain ( ) {
367
- second_smallest. items_mut ( ) . insert ( k, v) ;
368
- }
343
+ second_smallest. items_mut ( ) . extend ( smallest. items_mut ( ) . drain ( ) ) ;
369
344
370
345
// Record that `second_smallest` now contains all the stuff that was
371
346
// in `smallest` before.
@@ -545,6 +520,28 @@ fn internalize_symbols<'tcx>(
545
520
}
546
521
}
547
522
523
+ fn mark_code_coverage_dead_code_cgu < ' tcx > ( codegen_units : & mut [ CodegenUnit < ' tcx > ] ) {
524
+ assert ! ( !codegen_units. is_empty( ) ) ;
525
+
526
+ // Find the smallest CGU that has exported symbols and put the dead
527
+ // function stubs in that CGU. We look for exported symbols to increase
528
+ // the likelihood the linker won't throw away the dead functions.
529
+ // FIXME(#92165): In order to truly resolve this, we need to make sure
530
+ // the object file (CGU) containing the dead function stubs is included
531
+ // in the final binary. This will probably require forcing these
532
+ // function symbols to be included via `-u` or `/include` linker args.
533
+ let dead_code_cgu = codegen_units
534
+ . iter_mut ( )
535
+ . filter ( |cgu| cgu. items ( ) . iter ( ) . any ( |( _, ( linkage, _) ) | * linkage == Linkage :: External ) )
536
+ . min_by_key ( |cgu| cgu. size_estimate ( ) ) ;
537
+
538
+ // If there are no CGUs that have externally linked items, then we just
539
+ // pick the first CGU as a fallback.
540
+ let dead_code_cgu = if let Some ( cgu) = dead_code_cgu { cgu } else { & mut codegen_units[ 0 ] } ;
541
+
542
+ dead_code_cgu. make_code_coverage_dead_code_cgu ( ) ;
543
+ }
544
+
548
545
fn characteristic_def_id_of_mono_item < ' tcx > (
549
546
tcx : TyCtxt < ' tcx > ,
550
547
mono_item : MonoItem < ' tcx > ,
0 commit comments