rustc_codegen_llvm/coverageinfo/
mod.rs1use std::cell::{OnceCell, RefCell};
2use std::ffi::{CStr, CString};
3
4use rustc_abi::Size;
5use rustc_codegen_ssa::traits::{
6 BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
7};
8use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
9use rustc_middle::mir::coverage::CoverageKind;
10use rustc_middle::ty::Instance;
11use tracing::{debug, instrument};
12
13use crate::builder::Builder;
14use crate::common::CodegenCx;
15use crate::llvm;
16
17pub(crate) mod ffi;
18mod llvm_cov;
19mod mapgen;
20
21pub(crate) struct CguCoverageContext<'ll, 'tcx> {
23 pub(crate) pgo_func_name_var_map: RefCell<FxIndexMap<Instance<'tcx>, &'ll llvm::Value>>,
31 pub(crate) mcdc_condition_bitmap_map: RefCell<FxHashMap<Instance<'tcx>, Vec<&'ll llvm::Value>>>,
32
33 covfun_section_name: OnceCell<CString>,
34}
35
36impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
37 pub(crate) fn new() -> Self {
38 Self {
39 pgo_func_name_var_map: Default::default(),
40 mcdc_condition_bitmap_map: Default::default(),
41 covfun_section_name: Default::default(),
42 }
43 }
44
45 fn try_get_mcdc_condition_bitmap(
50 &self,
51 instance: &Instance<'tcx>,
52 decision_depth: u16,
53 ) -> Option<&'ll llvm::Value> {
54 self.mcdc_condition_bitmap_map
55 .borrow()
56 .get(instance)
57 .and_then(|bitmap_map| bitmap_map.get(decision_depth as usize))
58 .copied() }
60
61 pub(crate) fn instances_used(&self) -> Vec<Instance<'tcx>> {
64 self.pgo_func_name_var_map.borrow().keys().copied().collect::<Vec<_>>()
67 }
68}
69
70impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
71 pub(crate) fn coverageinfo_finalize(&mut self) {
72 mapgen::finalize(self)
73 }
74
75 fn covfun_section_name(&self) -> &CStr {
84 self.coverage_cx()
85 .covfun_section_name
86 .get_or_init(|| llvm_cov::covfun_section_name(self.llmod))
87 }
88
89 fn ensure_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
97 debug!("getting pgo_func_name_var for instance={:?}", instance);
98 let mut pgo_func_name_var_map = self.coverage_cx().pgo_func_name_var_map.borrow_mut();
99 pgo_func_name_var_map.entry(instance).or_insert_with(|| {
100 let llfn = self.get_fn(instance);
101 let mangled_fn_name: &str = self.tcx.symbol_name(instance).name;
102 llvm_cov::create_pgo_func_name_var(llfn, mangled_fn_name)
103 })
104 }
105}
106
107impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
108 fn init_coverage(&mut self, instance: Instance<'tcx>) {
109 let Some(function_coverage_info) =
110 self.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
111 else {
112 return;
113 };
114
115 if function_coverage_info.mcdc_bitmap_bits == 0 {
117 return;
118 }
119
120 let fn_name = self.ensure_pgo_func_name_var(instance);
121 let hash = self.const_u64(function_coverage_info.function_source_hash);
122 let bitmap_bits = self.const_u32(function_coverage_info.mcdc_bitmap_bits as u32);
123 self.mcdc_parameters(fn_name, hash, bitmap_bits);
124
125 let mut cond_bitmaps = vec![];
127 for i in 0..function_coverage_info.mcdc_num_condition_bitmaps {
128 let align = self.tcx.data_layout.i32_align.abi;
131 let cond_bitmap = self.alloca(Size::from_bytes(4), align);
132 llvm::set_value_name(cond_bitmap, format!("mcdc.addr.{i}").as_bytes());
133 self.store(self.const_i32(0), cond_bitmap, align);
134 cond_bitmaps.push(cond_bitmap);
135 }
136
137 self.coverage_cx().mcdc_condition_bitmap_map.borrow_mut().insert(instance, cond_bitmaps);
138 }
139
140 #[instrument(level = "debug", skip(self))]
141 fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
142 let bx = self;
150
151 let Some(coverage_cx) = &bx.cx.coverage_cx else { return };
157
158 let Some(function_coverage_info) =
159 bx.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
160 else {
161 debug!("function has a coverage statement but no coverage info");
162 return;
163 };
164 let Some(ids_info) = bx.tcx.coverage_ids_info(instance.def) else {
165 debug!("function has a coverage statement but no IDs info");
166 return;
167 };
168
169 match *kind {
170 CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
171 "marker statement {kind:?} should have been removed by CleanupPostBorrowck"
172 ),
173 CoverageKind::VirtualCounter { bcb }
174 if let Some(&id) = ids_info.phys_counter_for_node.get(&bcb) =>
175 {
176 let fn_name = bx.ensure_pgo_func_name_var(instance);
177 let hash = bx.const_u64(function_coverage_info.function_source_hash);
178 let num_counters = bx.const_u32(ids_info.num_counters);
179 let index = bx.const_u32(id.as_u32());
180 debug!(
181 "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
182 fn_name, hash, num_counters, index,
183 );
184 bx.instrprof_increment(fn_name, hash, num_counters, index);
185 }
186 CoverageKind::VirtualCounter { .. } => {}
188 CoverageKind::CondBitmapUpdate { index, decision_depth } => {
189 let cond_bitmap = coverage_cx
190 .try_get_mcdc_condition_bitmap(&instance, decision_depth)
191 .expect("mcdc cond bitmap should have been allocated for updating");
192 let cond_index = bx.const_i32(index as i32);
193 bx.mcdc_condbitmap_update(cond_index, cond_bitmap);
194 }
195 CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => {
196 let cond_bitmap =
197 coverage_cx.try_get_mcdc_condition_bitmap(&instance, decision_depth).expect(
198 "mcdc cond bitmap should have been allocated for merging \
199 into the global bitmap",
200 );
201 assert!(
202 bitmap_idx as usize <= function_coverage_info.mcdc_bitmap_bits,
203 "bitmap index of the decision out of range"
204 );
205
206 let fn_name = bx.ensure_pgo_func_name_var(instance);
207 let hash = bx.const_u64(function_coverage_info.function_source_hash);
208 let bitmap_index = bx.const_u32(bitmap_idx);
209 bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap);
210 bx.mcdc_condbitmap_reset(cond_bitmap);
211 }
212 }
213 }
214}