@@ -4,14 +4,16 @@ use crate::coverageinfo::ffi::CounterMappingRegion;
44use crate :: coverageinfo:: map_data:: FunctionCoverage ;
55use crate :: llvm;
66
7- use rustc_codegen_ssa:: traits:: ConstMethods ;
7+ use rustc_codegen_ssa:: traits:: { BaseTypeMethods , ConstMethods } ;
88use rustc_data_structures:: fx:: FxIndexSet ;
99use rustc_hir:: def:: DefKind ;
1010use rustc_hir:: def_id:: DefId ;
1111use rustc_index:: IndexVec ;
1212use rustc_middle:: bug;
13+ use rustc_middle:: mir;
1314use rustc_middle:: mir:: coverage:: CodeRegion ;
1415use rustc_middle:: ty:: { self , TyCtxt } ;
16+ use rustc_span:: def_id:: DefIdSet ;
1517use rustc_span:: Symbol ;
1618
1719/// Generates and exports the Coverage Map.
@@ -94,8 +96,14 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
9496 // Generate the LLVM IR representation of the coverage map and store it in a well-known global
9597 let cov_data_val = generate_coverage_map ( cx, version, filenames_size, filenames_val) ;
9698
99+ let mut unused_function_names = Vec :: new ( ) ;
100+
97101 let covfun_section_name = coverageinfo:: covfun_section_name ( cx) ;
98102 for ( mangled_function_name, source_hash, is_used, coverage_mapping_buffer) in function_data {
103+ if !is_used {
104+ unused_function_names. push ( mangled_function_name) ;
105+ }
106+
99107 save_function_record (
100108 cx,
101109 & covfun_section_name,
@@ -107,6 +115,25 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
107115 ) ;
108116 }
109117
118+ // For unused functions, we need to take their mangled names and store them
119+ // in a specially-named global array. LLVM's `InstrProfiling` pass will
120+ // detect this global and include those names in its `__llvm_prf_names`
121+ // section. (See `llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp`.)
122+ if !unused_function_names. is_empty ( ) {
123+ assert ! ( cx. codegen_unit. is_code_coverage_dead_code_cgu( ) ) ;
124+
125+ let name_globals = unused_function_names
126+ . into_iter ( )
127+ . map ( |mangled_function_name| cx. const_str ( mangled_function_name) . 0 )
128+ . collect :: < Vec < _ > > ( ) ;
129+ let initializer = cx. const_array ( cx. type_ptr ( ) , & name_globals) ;
130+
131+ let array = llvm:: add_global ( cx. llmod , cx. val_ty ( initializer) , "__llvm_coverage_names" ) ;
132+ llvm:: set_global_constant ( array, true ) ;
133+ llvm:: set_linkage ( array, llvm:: Linkage :: InternalLinkage ) ;
134+ llvm:: set_initializer ( array, initializer) ;
135+ }
136+
110137 // Save the coverage data value to LLVM IR
111138 coverageinfo:: save_cov_data_to_mod ( cx, cov_data_val) ;
112139}
@@ -287,13 +314,12 @@ fn save_function_record(
287314/// `-Clink-dead-code` will not generate code for unused generic functions.)
288315///
289316/// We can find the unused functions (including generic functions) by the set difference of all MIR
290- /// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`tcx` query
291- /// `codegened_and_inlined_items`).
317+ /// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`codegenned_and_inlined_items`).
292318///
293- /// These unused functions are then codegen'd in one of the CGUs which is marked as the
294- /// "code coverage dead code cgu" during the partitioning process. This prevents us from generating
295- /// code regions for the same function more than once which can lead to linker errors regarding
296- /// duplicate symbols .
319+ /// These unused functions don't need to be codegenned, but we do need to add them to the function
320+ /// coverage map (in a single designated CGU) so that we still emit coverage mappings for them.
321+ /// We also end up adding their symbol names to a special global array that LLVM will include in
322+ /// its embedded coverage data .
297323fn add_unused_functions ( cx : & CodegenCx < ' _ , ' _ > ) {
298324 assert ! ( cx. codegen_unit. is_code_coverage_dead_code_cgu( ) ) ;
299325
@@ -324,19 +350,80 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
324350 } )
325351 . collect ( ) ;
326352
327- let codegenned_def_ids = tcx . codegened_and_inlined_items ( ( ) ) ;
353+ let codegenned_def_ids = codegenned_and_inlined_items ( tcx ) ;
328354
329- for non_codegenned_def_id in
330- eligible_def_ids . into_iter ( ) . filter ( |id| !codegenned_def_ids . contains ( id ) )
331- {
355+ // For each `DefId` that should have coverage instrumentation but wasn't
356+ // codegenned, add it to the function coverage map as an unused function.
357+ for def_id in eligible_def_ids . into_iter ( ) . filter ( |id| !codegenned_def_ids . contains ( id ) ) {
332358 // Skip any function that didn't have coverage data added to it by the
333359 // coverage instrumentor.
334- let body = tcx. instance_mir ( ty:: InstanceDef :: Item ( non_codegenned_def_id ) ) ;
360+ let body = tcx. instance_mir ( ty:: InstanceDef :: Item ( def_id ) ) ;
335361 let Some ( function_coverage_info) = body. function_coverage_info . as_deref ( ) else {
336362 continue ;
337363 } ;
338364
339- debug ! ( "generating unused fn: {:?}" , non_codegenned_def_id) ;
340- cx. define_unused_fn ( non_codegenned_def_id, function_coverage_info) ;
365+ debug ! ( "generating unused fn: {def_id:?}" ) ;
366+ let instance = declare_unused_fn ( tcx, def_id) ;
367+ add_unused_function_coverage ( cx, instance, function_coverage_info) ;
368+ }
369+ }
370+
371+ /// All items participating in code generation together with (instrumented)
372+ /// items inlined into them.
373+ fn codegenned_and_inlined_items ( tcx : TyCtxt < ' _ > ) -> DefIdSet {
374+ let ( items, cgus) = tcx. collect_and_partition_mono_items ( ( ) ) ;
375+ let mut visited = DefIdSet :: default ( ) ;
376+ let mut result = items. clone ( ) ;
377+
378+ for cgu in cgus {
379+ for item in cgu. items ( ) . keys ( ) {
380+ if let mir:: mono:: MonoItem :: Fn ( ref instance) = item {
381+ let did = instance. def_id ( ) ;
382+ if !visited. insert ( did) {
383+ continue ;
384+ }
385+ let body = tcx. instance_mir ( instance. def ) ;
386+ for block in body. basic_blocks . iter ( ) {
387+ for statement in & block. statements {
388+ let mir:: StatementKind :: Coverage ( _) = statement. kind else { continue } ;
389+ let scope = statement. source_info . scope ;
390+ if let Some ( inlined) = scope. inlined_instance ( & body. source_scopes ) {
391+ result. insert ( inlined. def_id ( ) ) ;
392+ }
393+ }
394+ }
395+ }
396+ }
397+ }
398+
399+ result
400+ }
401+
402+ fn declare_unused_fn < ' tcx > ( tcx : TyCtxt < ' tcx > , def_id : DefId ) -> ty:: Instance < ' tcx > {
403+ ty:: Instance :: new (
404+ def_id,
405+ ty:: GenericArgs :: for_item ( tcx, def_id, |param, _| {
406+ if let ty:: GenericParamDefKind :: Lifetime = param. kind {
407+ tcx. lifetimes . re_erased . into ( )
408+ } else {
409+ tcx. mk_param_from_def ( param)
410+ }
411+ } ) ,
412+ )
413+ }
414+
415+ fn add_unused_function_coverage < ' tcx > (
416+ cx : & CodegenCx < ' _ , ' tcx > ,
417+ instance : ty:: Instance < ' tcx > ,
418+ function_coverage_info : & ' tcx mir:: coverage:: FunctionCoverageInfo ,
419+ ) {
420+ // An unused function's mappings will automatically be rewritten to map to
421+ // zero, because none of its counters/expressions are marked as seen.
422+ let function_coverage = FunctionCoverage :: unused ( instance, function_coverage_info) ;
423+
424+ if let Some ( coverage_context) = cx. coverage_context ( ) {
425+ coverage_context. function_coverage_map . borrow_mut ( ) . insert ( instance, function_coverage) ;
426+ } else {
427+ bug ! ( "Could not get the `coverage_context`" ) ;
341428 }
342429}
0 commit comments