@@ -155,14 +155,16 @@ where
155155 // functions and statics defined in the local crate.
156156 let PlacedRootMonoItems { mut codegen_units, internalization_candidates, unique_inlined_stats } = {
157157 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) ;
160159
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+ }
164163
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+ } ;
166168
167169 // Merge until we have at most `max_cgu_count` codegen units.
168170 // `merge_codegen_units` is responsible for updating the CGU size
@@ -179,59 +181,34 @@ where
179181 // local functions the definition of which is marked with `#[inline]`.
180182 {
181183 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) ;
184185
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+ }
188189
189- debug_dump ( tcx, "INLINE" , & codegen_units, unique_inlined_stats) ;
190+ debug_dump ( tcx, "INLINE" , & codegen_units, unique_inlined_stats) ;
191+ }
190192
191193 // Next we try to make as many symbols "internal" as possible, so LLVM has
192194 // more freedom to optimize.
193195 if !tcx. sess . link_dead_code ( ) {
194196 let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning_internalize_symbols" ) ;
195197 internalize_symbols ( cx, & mut codegen_units, internalization_candidates) ;
198+
199+ debug_dump ( tcx, "INTERNALIZE" , & codegen_units, unique_inlined_stats) ;
196200 }
197201
202+ // Mark one CGU for dead code, if necessary.
198203 let instrument_dead_code =
199204 tcx. sess . instrument_coverage ( ) && !tcx. sess . instrument_coverage_except_unused_functions ( ) ;
200-
201205 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) ;
228207 }
229208
230209 // Ensure CGUs are sorted by name, so that we get deterministic results.
231210 assert ! ( codegen_units. is_sorted_by( |a, b| Some ( a. name( ) . as_str( ) . cmp( b. name( ) . as_str( ) ) ) ) ) ;
232211
233- debug_dump ( tcx, "FINAL" , & codegen_units, unique_inlined_stats) ;
234-
235212 codegen_units
236213}
237214
@@ -363,9 +340,7 @@ fn merge_codegen_units<'tcx>(
363340
364341 // Move the mono-items from `smallest` to `second_smallest`
365342 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 ( ) ) ;
369344
370345 // Record that `second_smallest` now contains all the stuff that was
371346 // in `smallest` before.
@@ -545,6 +520,28 @@ fn internalize_symbols<'tcx>(
545520 }
546521}
547522
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+
548545fn characteristic_def_id_of_mono_item < ' tcx > (
549546 tcx : TyCtxt < ' tcx > ,
550547 mono_item : MonoItem < ' tcx > ,
0 commit comments