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, FxIndexSet};
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) instances_used: RefCell<FxIndexSet<Instance<'tcx>>>,
25 pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
26 pub(crate) mcdc_condition_bitmap_map: RefCell<FxHashMap<Instance<'tcx>, Vec<&'ll llvm::Value>>>,
27
28 covfun_section_name: OnceCell<CString>,
29}
30
31impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
32 pub(crate) fn new() -> Self {
33 Self {
34 instances_used: RefCell::<FxIndexSet<_>>::default(),
35 pgo_func_name_var_map: Default::default(),
36 mcdc_condition_bitmap_map: Default::default(),
37 covfun_section_name: Default::default(),
38 }
39 }
40
41 fn try_get_mcdc_condition_bitmap(
46 &self,
47 instance: &Instance<'tcx>,
48 decision_depth: u16,
49 ) -> Option<&'ll llvm::Value> {
50 self.mcdc_condition_bitmap_map
51 .borrow()
52 .get(instance)
53 .and_then(|bitmap_map| bitmap_map.get(decision_depth as usize))
54 .copied() }
56}
57
58impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
59 pub(crate) fn coverageinfo_finalize(&self) {
60 mapgen::finalize(self)
61 }
62
63 fn covfun_section_name(&self) -> &CStr {
72 self.coverage_cx()
73 .covfun_section_name
74 .get_or_init(|| llvm_cov::covfun_section_name(self.llmod))
75 }
76
77 fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
82 debug!("getting pgo_func_name_var for instance={:?}", instance);
83 let mut pgo_func_name_var_map = self.coverage_cx().pgo_func_name_var_map.borrow_mut();
84 pgo_func_name_var_map.entry(instance).or_insert_with(|| {
85 let llfn = self.get_fn(instance);
86 let mangled_fn_name: &str = self.tcx.symbol_name(instance).name;
87 llvm_cov::create_pgo_func_name_var(llfn, mangled_fn_name)
88 })
89 }
90}
91
92impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
93 fn init_coverage(&mut self, instance: Instance<'tcx>) {
94 let Some(function_coverage_info) =
95 self.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
96 else {
97 return;
98 };
99
100 if function_coverage_info.mcdc_bitmap_bits == 0 {
102 return;
103 }
104
105 let fn_name = self.get_pgo_func_name_var(instance);
106 let hash = self.const_u64(function_coverage_info.function_source_hash);
107 let bitmap_bits = self.const_u32(function_coverage_info.mcdc_bitmap_bits as u32);
108 self.mcdc_parameters(fn_name, hash, bitmap_bits);
109
110 let mut cond_bitmaps = vec![];
112 for i in 0..function_coverage_info.mcdc_num_condition_bitmaps {
113 let align = self.tcx.data_layout.i32_align.abi;
116 let cond_bitmap = self.alloca(Size::from_bytes(4), align);
117 llvm::set_value_name(cond_bitmap, format!("mcdc.addr.{i}").as_bytes());
118 self.store(self.const_i32(0), cond_bitmap, align);
119 cond_bitmaps.push(cond_bitmap);
120 }
121
122 self.coverage_cx().mcdc_condition_bitmap_map.borrow_mut().insert(instance, cond_bitmaps);
123 }
124
125 #[instrument(level = "debug", skip(self))]
126 fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
127 let bx = self;
135
136 let Some(coverage_cx) = &bx.cx.coverage_cx else { return };
142
143 let Some(function_coverage_info) =
144 bx.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
145 else {
146 debug!("function has a coverage statement but no coverage info");
147 return;
148 };
149 let Some(ids_info) = bx.tcx.coverage_ids_info(instance.def) else {
150 debug!("function has a coverage statement but no IDs info");
151 return;
152 };
153
154 coverage_cx.instances_used.borrow_mut().insert(instance);
158
159 match *kind {
160 CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
161 "marker statement {kind:?} should have been removed by CleanupPostBorrowck"
162 ),
163 CoverageKind::VirtualCounter { bcb }
164 if let Some(&id) = ids_info.phys_counter_for_node.get(&bcb) =>
165 {
166 let fn_name = bx.get_pgo_func_name_var(instance);
167 let hash = bx.const_u64(function_coverage_info.function_source_hash);
168 let num_counters = bx.const_u32(ids_info.num_counters);
169 let index = bx.const_u32(id.as_u32());
170 debug!(
171 "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
172 fn_name, hash, num_counters, index,
173 );
174 bx.instrprof_increment(fn_name, hash, num_counters, index);
175 }
176 CoverageKind::VirtualCounter { .. } => {}
178 CoverageKind::CondBitmapUpdate { index, decision_depth } => {
179 let cond_bitmap = coverage_cx
180 .try_get_mcdc_condition_bitmap(&instance, decision_depth)
181 .expect("mcdc cond bitmap should have been allocated for updating");
182 let cond_index = bx.const_i32(index as i32);
183 bx.mcdc_condbitmap_update(cond_index, cond_bitmap);
184 }
185 CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => {
186 let cond_bitmap =
187 coverage_cx.try_get_mcdc_condition_bitmap(&instance, decision_depth).expect(
188 "mcdc cond bitmap should have been allocated for merging \
189 into the global bitmap",
190 );
191 assert!(
192 bitmap_idx as usize <= function_coverage_info.mcdc_bitmap_bits,
193 "bitmap index of the decision out of range"
194 );
195
196 let fn_name = bx.get_pgo_func_name_var(instance);
197 let hash = bx.const_u64(function_coverage_info.function_source_hash);
198 let bitmap_index = bx.const_u32(bitmap_idx);
199 bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap);
200 bx.mcdc_condbitmap_reset(cond_bitmap);
201 }
202 }
203 }
204}