@@ -5,7 +5,7 @@ use rustc_abi::Size;
5
5
use rustc_codegen_ssa::traits::{
6
6
BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
7
7
};
8
- use rustc_data_structures::fx::{FxHashMap, FxIndexSet };
8
+ use rustc_data_structures::fx::{FxHashMap, FxIndexMap };
9
9
use rustc_middle::mir::coverage::CoverageKind;
10
10
use rustc_middle::ty::Instance;
11
11
use tracing::{debug, instrument};
@@ -20,9 +20,14 @@ mod mapgen;
20
20
21
21
/// Extra per-CGU context/state needed for coverage instrumentation.
22
22
pub(crate) struct CguCoverageContext<'ll, 'tcx> {
23
- /// Coverage data for each instrumented function identified by DefId.
24
- pub(crate) instances_used: RefCell<FxIndexSet<Instance<'tcx>>>,
25
- pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
23
+ /// Associates function instances with an LLVM global that holds the
24
+ /// function's symbol name, as needed by LLVM coverage intrinsics.
25
+ ///
26
+ /// Instances in this map are also considered "used" for the purposes of
27
+ /// emitting covfun records. Every covfun record holds a hash of its
28
+ /// symbol name, and `llvm-cov` will exit fatally if it can't resolve that
29
+ /// hash back to an entry in the binary's `__llvm_prf_names` linker section.
30
+ pub(crate) pgo_func_name_var_map: RefCell<FxIndexMap<Instance<'tcx>, &'ll llvm::Value>>,
26
31
pub(crate) mcdc_condition_bitmap_map: RefCell<FxHashMap<Instance<'tcx>, Vec<&'ll llvm::Value>>>,
27
32
28
33
covfun_section_name: OnceCell<CString>,
@@ -31,7 +36,6 @@ pub(crate) struct CguCoverageContext<'ll, 'tcx> {
31
36
impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
32
37
pub(crate) fn new() -> Self {
33
38
Self {
34
- instances_used: RefCell::<FxIndexSet<_>>::default(),
35
39
pgo_func_name_var_map: Default::default(),
36
40
mcdc_condition_bitmap_map: Default::default(),
37
41
covfun_section_name: Default::default(),
@@ -53,6 +57,14 @@ impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
53
57
.and_then(|bitmap_map| bitmap_map.get(decision_depth as usize))
54
58
.copied() // Dereference Option<&&Value> to Option<&Value>
55
59
}
60
+
61
+ /// Returns the list of instances considered "used" in this CGU, as
62
+ /// inferred from the keys of `pgo_func_name_var_map`.
63
+ pub(crate) fn instances_used(&self) -> Vec<Instance<'tcx>> {
64
+ // Collecting into a Vec is way easier than trying to juggle RefCell
65
+ // projections, and this should only run once per CGU anyway.
66
+ self.pgo_func_name_var_map.borrow().keys().copied().collect::<Vec<_>>()
67
+ }
56
68
}
57
69
58
70
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
@@ -78,7 +90,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
78
90
/// string, to hold the function name passed to LLVM intrinsic
79
91
/// `instrprof.increment()`. The `Value` is only created once per instance.
80
92
/// Multiple invocations with the same instance return the same `Value`.
81
- fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
93
+ ///
94
+ /// This has the side-effect of causing coverage codegen to consider this
95
+ /// function "used", making it eligible to emit an associated covfun record.
96
+ fn ensure_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
82
97
debug!("getting pgo_func_name_var for instance={:?}", instance);
83
98
let mut pgo_func_name_var_map = self.coverage_cx().pgo_func_name_var_map.borrow_mut();
84
99
pgo_func_name_var_map.entry(instance).or_insert_with(|| {
@@ -102,7 +117,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
102
117
return;
103
118
}
104
119
105
- let fn_name = self.get_pgo_func_name_var (instance);
120
+ let fn_name = self.ensure_pgo_func_name_var (instance);
106
121
let hash = self.const_u64(function_coverage_info.function_source_hash);
107
122
let bitmap_bits = self.const_u32(function_coverage_info.mcdc_bitmap_bits as u32);
108
123
self.mcdc_parameters(fn_name, hash, bitmap_bits);
@@ -151,19 +166,14 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
151
166
return;
152
167
};
153
168
154
- // Mark the instance as used in this CGU, for coverage purposes.
155
- // This includes functions that were not partitioned into this CGU,
156
- // but were MIR-inlined into one of this CGU's functions.
157
- coverage_cx.instances_used.borrow_mut().insert(instance);
158
-
159
169
match *kind {
160
170
CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
161
171
"marker statement {kind:?} should have been removed by CleanupPostBorrowck"
162
172
),
163
173
CoverageKind::VirtualCounter { bcb }
164
174
if let Some(&id) = ids_info.phys_counter_for_node.get(&bcb) =>
165
175
{
166
- let fn_name = bx.get_pgo_func_name_var (instance);
176
+ let fn_name = bx.ensure_pgo_func_name_var (instance);
167
177
let hash = bx.const_u64(function_coverage_info.function_source_hash);
168
178
let num_counters = bx.const_u32(ids_info.num_counters);
169
179
let index = bx.const_u32(id.as_u32());
@@ -193,7 +203,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
193
203
"bitmap index of the decision out of range"
194
204
);
195
205
196
- let fn_name = bx.get_pgo_func_name_var (instance);
206
+ let fn_name = bx.ensure_pgo_func_name_var (instance);
197
207
let hash = bx.const_u64(function_coverage_info.function_source_hash);
198
208
let bitmap_index = bx.const_u32(bitmap_idx);
199
209
bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap);
0 commit comments