1
+ use rustc_codegen_ssa:: traits:: { BaseTypeCodegenMethods , ConstCodegenMethods } ;
1
2
use rustc_data_structures:: fx:: FxHashSet ;
2
3
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
3
4
use rustc_middle:: mir;
@@ -6,6 +7,9 @@ use rustc_middle::ty::{self, TyCtxt};
6
7
use rustc_span:: def_id:: DefIdSet ;
7
8
8
9
use crate :: common:: CodegenCx ;
10
+ use crate :: coverageinfo:: mapgen:: GlobalFileTable ;
11
+ use crate :: coverageinfo:: mapgen:: covfun:: { CovfunRecord , prepare_covfun_record} ;
12
+ use crate :: llvm;
9
13
10
14
/// Each CGU will normally only emit coverage metadata for the functions that it actually generates.
11
15
/// But since we don't want unused functions to disappear from coverage reports, we also scan for
@@ -15,9 +19,48 @@ use crate::common::CodegenCx;
15
19
/// coverage map (in a single designated CGU) so that we still emit coverage mappings for them.
16
20
/// We also end up adding their symbol names to a special global array that LLVM will include in
17
21
/// its embedded coverage data.
18
- pub ( crate ) fn gather_unused_function_instances < ' tcx > (
22
+ pub ( crate ) fn prepare_covfun_records_for_unused_functions < ' tcx > (
19
23
cx : & CodegenCx < ' _ , ' tcx > ,
20
- ) -> Vec < ty:: Instance < ' tcx > > {
24
+ global_file_table : & mut GlobalFileTable ,
25
+ covfun_records : & mut Vec < CovfunRecord < ' tcx > > ,
26
+ ) {
27
+ assert ! ( cx. codegen_unit. is_code_coverage_dead_code_cgu( ) ) ;
28
+
29
+ let mut unused_instances = gather_unused_function_instances ( cx) ;
30
+ // Sort the unused instances by symbol name, so that their order isn't hash-sensitive.
31
+ unused_instances. sort_by_key ( |instance| instance. symbol_name ) ;
32
+
33
+ // Try to create a covfun record for each unused function.
34
+ let mut name_globals = Vec :: with_capacity ( unused_instances. len ( ) ) ;
35
+ covfun_records. extend ( unused_instances. into_iter ( ) . filter_map ( |unused| try {
36
+ let record = prepare_covfun_record ( cx. tcx , global_file_table, unused. instance , false ) ?;
37
+ // If successful, also store its symbol name in a global constant.
38
+ name_globals. push ( cx. const_str ( unused. symbol_name . name ) . 0 ) ;
39
+ record
40
+ } ) ) ;
41
+
42
+ // Store the names of unused functions in a specially-named global array.
43
+ // LLVM's `InstrProfilling` pass will detect this array, and include the
44
+ // referenced names in its `__llvm_prf_names` section.
45
+ // (See `llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp`.)
46
+ if !name_globals. is_empty ( ) {
47
+ let initializer = cx. const_array ( cx. type_ptr ( ) , & name_globals) ;
48
+
49
+ let array = llvm:: add_global ( cx. llmod , cx. val_ty ( initializer) , c"__llvm_coverage_names" ) ;
50
+ llvm:: set_global_constant ( array, true ) ;
51
+ llvm:: set_linkage ( array, llvm:: Linkage :: InternalLinkage ) ;
52
+ llvm:: set_initializer ( array, initializer) ;
53
+ }
54
+ }
55
+
56
+ /// Holds a dummy function instance along with its symbol name, to avoid having
57
+ /// to repeatedly query for the name.
58
+ struct UnusedInstance < ' tcx > {
59
+ instance : ty:: Instance < ' tcx > ,
60
+ symbol_name : ty:: SymbolName < ' tcx > ,
61
+ }
62
+
63
+ fn gather_unused_function_instances < ' tcx > ( cx : & CodegenCx < ' _ , ' tcx > ) -> Vec < UnusedInstance < ' tcx > > {
21
64
assert ! ( cx. codegen_unit. is_code_coverage_dead_code_cgu( ) ) ;
22
65
23
66
let tcx = cx. tcx ;
@@ -45,6 +88,7 @@ pub(crate) fn gather_unused_function_instances<'tcx>(
45
88
. copied ( )
46
89
. filter ( |& def_id| is_unused_fn ( def_id) )
47
90
. map ( |def_id| make_dummy_instance ( tcx, def_id) )
91
+ . map ( |instance| UnusedInstance { instance, symbol_name : tcx. symbol_name ( instance) } )
48
92
. collect :: < Vec < _ > > ( )
49
93
}
50
94
0 commit comments