1 use crate::llvm;
2
3 use crate::abi::Abi;
4 use crate::builder::Builder;
5 use crate::common::CodegenCx;
6 use crate::coverageinfo::map_data::{CounterExpression, FunctionCoverage};
7
8 use libc::c_uint;
9 use llvm::coverageinfo::CounterMappingRegion;
10 use rustc_codegen_ssa::traits::{
11 BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, MiscMethods,
12 StaticMethods,
13 };
14 use rustc_data_structures::fx::FxHashMap;
15 use rustc_hir as hir;
16 use rustc_hir::def_id::DefId;
17 use rustc_llvm::RustString;
18 use rustc_middle::bug;
19 use rustc_middle::mir::coverage::{
20 CodeRegion, CounterValueReference, CoverageKind, ExpressionOperandId, InjectedExpressionId, Op,
21 };
22 use rustc_middle::mir::Coverage;
23 use rustc_middle::ty;
24 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
25 use rustc_middle::ty::subst::InternalSubsts;
26 use rustc_middle::ty::Instance;
27 use rustc_middle::ty::Ty;
28
29 use std::cell::RefCell;
30 use std::ffi::CString;
31
32 mod ffi;
33 pub(crate) mod map_data;
34 pub mod mapgen;
35
36 const UNUSED_FUNCTION_COUNTER_ID: CounterValueReference = CounterValueReference::START;
37
38 const VAR_ALIGN_BYTES: usize = 8;
39
40 /// A context object for maintaining all state needed by the coverageinfo module.
41 pub struct CrateCoverageContext<'ll, 'tcx> {
42 /// Coverage data for each instrumented function identified by DefId.
43 pub(crate) function_coverage_map: RefCell<FxHashMap<Instance<'tcx>, FunctionCoverage<'tcx>>>,
44 pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
45 }
46
47 impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
new() -> Self48 pub fn new() -> Self {
49 Self {
50 function_coverage_map: Default::default(),
51 pgo_func_name_var_map: Default::default(),
52 }
53 }
54
take_function_coverage_map(&self) -> FxHashMap<Instance<'tcx>, FunctionCoverage<'tcx>>55 pub fn take_function_coverage_map(&self) -> FxHashMap<Instance<'tcx>, FunctionCoverage<'tcx>> {
56 self.function_coverage_map.replace(FxHashMap::default())
57 }
58 }
59
60 // These methods used to be part of trait `CoverageInfoMethods`, which no longer
61 // exists after most coverage code was moved out of SSA.
62 impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
coverageinfo_finalize(&self)63 pub(crate) fn coverageinfo_finalize(&self) {
64 mapgen::finalize(self)
65 }
66
67 /// For LLVM codegen, returns a function-specific `Value` for a global
68 /// string, to hold the function name passed to LLVM intrinsic
69 /// `instrprof.increment()`. The `Value` is only created once per instance.
70 /// Multiple invocations with the same instance return the same `Value`.
get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value71 fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
72 if let Some(coverage_context) = self.coverage_context() {
73 debug!("getting pgo_func_name_var for instance={:?}", instance);
74 let mut pgo_func_name_var_map = coverage_context.pgo_func_name_var_map.borrow_mut();
75 pgo_func_name_var_map
76 .entry(instance)
77 .or_insert_with(|| create_pgo_func_name_var(self, instance))
78 } else {
79 bug!("Could not get the `coverage_context`");
80 }
81 }
82
83 /// Functions with MIR-based coverage are normally codegenned _only_ if
84 /// called. LLVM coverage tools typically expect every function to be
85 /// defined (even if unused), with at least one call to LLVM intrinsic
86 /// `instrprof.increment`.
87 ///
88 /// Codegen a small function that will never be called, with one counter
89 /// that will never be incremented.
90 ///
91 /// For used/called functions, the coverageinfo was already added to the
92 /// `function_coverage_map` (keyed by function `Instance`) during codegen.
93 /// But in this case, since the unused function was _not_ previously
94 /// codegenned, collect the coverage `CodeRegion`s from the MIR and add
95 /// them. The first `CodeRegion` is used to add a single counter, with the
96 /// same counter ID used in the injected `instrprof.increment` intrinsic
97 /// call. Since the function is never called, all other `CodeRegion`s can be
98 /// added as `unreachable_region`s.
define_unused_fn(&self, def_id: DefId)99 fn define_unused_fn(&self, def_id: DefId) {
100 let instance = declare_unused_fn(self, def_id);
101 codegen_unused_fn_and_counter(self, instance);
102 add_unused_function_coverage(self, instance, def_id);
103 }
104 }
105
106 impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage)107 fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage) {
108 let bx = self;
109
110 let Coverage { kind, code_region } = coverage.clone();
111 match kind {
112 CoverageKind::Counter { function_source_hash, id } => {
113 if bx.set_function_source_hash(instance, function_source_hash) {
114 // If `set_function_source_hash()` returned true, the coverage map is enabled,
115 // so continue adding the counter.
116 if let Some(code_region) = code_region {
117 // Note: Some counters do not have code regions, but may still be referenced
118 // from expressions. In that case, don't add the counter to the coverage map,
119 // but do inject the counter intrinsic.
120 bx.add_coverage_counter(instance, id, code_region);
121 }
122
123 let coverageinfo = bx.tcx().coverageinfo(instance.def);
124
125 let fn_name = bx.get_pgo_func_name_var(instance);
126 let hash = bx.const_u64(function_source_hash);
127 let num_counters = bx.const_u32(coverageinfo.num_counters);
128 let index = bx.const_u32(id.zero_based_index());
129 debug!(
130 "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
131 fn_name, hash, num_counters, index,
132 );
133 bx.instrprof_increment(fn_name, hash, num_counters, index);
134 }
135 }
136 CoverageKind::Expression { id, lhs, op, rhs } => {
137 bx.add_coverage_counter_expression(instance, id, lhs, op, rhs, code_region);
138 }
139 CoverageKind::Unreachable => {
140 bx.add_coverage_unreachable(
141 instance,
142 code_region.expect("unreachable regions always have code regions"),
143 );
144 }
145 }
146 }
147 }
148
149 // These methods used to be part of trait `CoverageInfoBuilderMethods`, but
150 // after moving most coverage code out of SSA they are now just ordinary methods.
151 impl<'tcx> Builder<'_, '_, 'tcx> {
152 /// Returns true if the function source hash was added to the coverage map (even if it had
153 /// already been added, for this instance). Returns false *only* if `-C instrument-coverage` is
154 /// not enabled (a coverage map is not being generated).
set_function_source_hash( &mut self, instance: Instance<'tcx>, function_source_hash: u64, ) -> bool155 fn set_function_source_hash(
156 &mut self,
157 instance: Instance<'tcx>,
158 function_source_hash: u64,
159 ) -> bool {
160 if let Some(coverage_context) = self.coverage_context() {
161 debug!(
162 "ensuring function source hash is set for instance={:?}; function_source_hash={}",
163 instance, function_source_hash,
164 );
165 let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
166 coverage_map
167 .entry(instance)
168 .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
169 .set_function_source_hash(function_source_hash);
170 true
171 } else {
172 false
173 }
174 }
175
176 /// Returns true if the counter was added to the coverage map; false if `-C instrument-coverage`
177 /// is not enabled (a coverage map is not being generated).
add_coverage_counter( &mut self, instance: Instance<'tcx>, id: CounterValueReference, region: CodeRegion, ) -> bool178 fn add_coverage_counter(
179 &mut self,
180 instance: Instance<'tcx>,
181 id: CounterValueReference,
182 region: CodeRegion,
183 ) -> bool {
184 if let Some(coverage_context) = self.coverage_context() {
185 debug!(
186 "adding counter to coverage_map: instance={:?}, id={:?}, region={:?}",
187 instance, id, region,
188 );
189 let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
190 coverage_map
191 .entry(instance)
192 .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
193 .add_counter(id, region);
194 true
195 } else {
196 false
197 }
198 }
199
200 /// Returns true if the expression was added to the coverage map; false if
201 /// `-C instrument-coverage` is not enabled (a coverage map is not being generated).
add_coverage_counter_expression( &mut self, instance: Instance<'tcx>, id: InjectedExpressionId, lhs: ExpressionOperandId, op: Op, rhs: ExpressionOperandId, region: Option<CodeRegion>, ) -> bool202 fn add_coverage_counter_expression(
203 &mut self,
204 instance: Instance<'tcx>,
205 id: InjectedExpressionId,
206 lhs: ExpressionOperandId,
207 op: Op,
208 rhs: ExpressionOperandId,
209 region: Option<CodeRegion>,
210 ) -> bool {
211 if let Some(coverage_context) = self.coverage_context() {
212 debug!(
213 "adding counter expression to coverage_map: instance={:?}, id={:?}, {:?} {:?} {:?}; \
214 region: {:?}",
215 instance, id, lhs, op, rhs, region,
216 );
217 let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
218 coverage_map
219 .entry(instance)
220 .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
221 .add_counter_expression(id, lhs, op, rhs, region);
222 true
223 } else {
224 false
225 }
226 }
227
228 /// Returns true if the region was added to the coverage map; false if `-C instrument-coverage`
229 /// is not enabled (a coverage map is not being generated).
add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool230 fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool {
231 if let Some(coverage_context) = self.coverage_context() {
232 debug!(
233 "adding unreachable code to coverage_map: instance={:?}, at {:?}",
234 instance, region,
235 );
236 let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
237 coverage_map
238 .entry(instance)
239 .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
240 .add_unreachable_region(region);
241 true
242 } else {
243 false
244 }
245 }
246 }
247
declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance<'tcx>248 fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance<'tcx> {
249 let tcx = cx.tcx;
250
251 let instance = Instance::new(
252 def_id,
253 InternalSubsts::for_item(tcx, def_id, |param, _| {
254 if let ty::GenericParamDefKind::Lifetime = param.kind {
255 tcx.lifetimes.re_erased.into()
256 } else {
257 tcx.mk_param_from_def(param)
258 }
259 }),
260 );
261
262 let llfn = cx.declare_fn(
263 tcx.symbol_name(instance).name,
264 cx.fn_abi_of_fn_ptr(
265 ty::Binder::dummy(tcx.mk_fn_sig(
266 [Ty::new_unit(tcx)],
267 Ty::new_unit(tcx),
268 false,
269 hir::Unsafety::Unsafe,
270 Abi::Rust,
271 )),
272 ty::List::empty(),
273 ),
274 None,
275 );
276
277 llvm::set_linkage(llfn, llvm::Linkage::PrivateLinkage);
278 llvm::set_visibility(llfn, llvm::Visibility::Default);
279
280 assert!(cx.instances.borrow_mut().insert(instance, llfn).is_none());
281
282 instance
283 }
284
codegen_unused_fn_and_counter<'tcx>(cx: &CodegenCx<'_, 'tcx>, instance: Instance<'tcx>)285 fn codegen_unused_fn_and_counter<'tcx>(cx: &CodegenCx<'_, 'tcx>, instance: Instance<'tcx>) {
286 let llfn = cx.get_fn(instance);
287 let llbb = Builder::append_block(cx, llfn, "unused_function");
288 let mut bx = Builder::build(cx, llbb);
289 let fn_name = bx.get_pgo_func_name_var(instance);
290 let hash = bx.const_u64(0);
291 let num_counters = bx.const_u32(1);
292 let index = bx.const_u32(u32::from(UNUSED_FUNCTION_COUNTER_ID));
293 debug!(
294 "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?},
295 index={:?}) for unused function: {:?}",
296 fn_name, hash, num_counters, index, instance
297 );
298 bx.instrprof_increment(fn_name, hash, num_counters, index);
299 bx.ret_void();
300 }
301
add_unused_function_coverage<'tcx>( cx: &CodegenCx<'_, 'tcx>, instance: Instance<'tcx>, def_id: DefId, )302 fn add_unused_function_coverage<'tcx>(
303 cx: &CodegenCx<'_, 'tcx>,
304 instance: Instance<'tcx>,
305 def_id: DefId,
306 ) {
307 let tcx = cx.tcx;
308
309 let mut function_coverage = FunctionCoverage::unused(tcx, instance);
310 for (index, &code_region) in tcx.covered_code_regions(def_id).iter().enumerate() {
311 if index == 0 {
312 // Insert at least one real counter so the LLVM CoverageMappingReader will find expected
313 // definitions.
314 function_coverage.add_counter(UNUSED_FUNCTION_COUNTER_ID, code_region.clone());
315 } else {
316 function_coverage.add_unreachable_region(code_region.clone());
317 }
318 }
319
320 if let Some(coverage_context) = cx.coverage_context() {
321 coverage_context.function_coverage_map.borrow_mut().insert(instance, function_coverage);
322 } else {
323 bug!("Could not get the `coverage_context`");
324 }
325 }
326
327 /// Calls llvm::createPGOFuncNameVar() with the given function instance's
328 /// mangled function name. The LLVM API returns an llvm::GlobalVariable
329 /// containing the function name, with the specific variable name and linkage
330 /// required by LLVM InstrProf source-based coverage instrumentation. Use
331 /// `bx.get_pgo_func_name_var()` to ensure the variable is only created once per
332 /// `Instance`.
create_pgo_func_name_var<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>, ) -> &'ll llvm::Value333 fn create_pgo_func_name_var<'ll, 'tcx>(
334 cx: &CodegenCx<'ll, 'tcx>,
335 instance: Instance<'tcx>,
336 ) -> &'ll llvm::Value {
337 let mangled_fn_name = CString::new(cx.tcx.symbol_name(instance).name)
338 .expect("error converting function name to C string");
339 let llfn = cx.get_fn(instance);
340 unsafe { llvm::LLVMRustCoverageCreatePGOFuncNameVar(llfn, mangled_fn_name.as_ptr()) }
341 }
342
write_filenames_section_to_buffer<'a>( filenames: impl IntoIterator<Item = &'a CString>, buffer: &RustString, )343 pub(crate) fn write_filenames_section_to_buffer<'a>(
344 filenames: impl IntoIterator<Item = &'a CString>,
345 buffer: &RustString,
346 ) {
347 let c_str_vec = filenames.into_iter().map(|cstring| cstring.as_ptr()).collect::<Vec<_>>();
348 unsafe {
349 llvm::LLVMRustCoverageWriteFilenamesSectionToBuffer(
350 c_str_vec.as_ptr(),
351 c_str_vec.len(),
352 buffer,
353 );
354 }
355 }
356
write_mapping_to_buffer( virtual_file_mapping: Vec<u32>, expressions: Vec<CounterExpression>, mapping_regions: Vec<CounterMappingRegion>, buffer: &RustString, )357 pub(crate) fn write_mapping_to_buffer(
358 virtual_file_mapping: Vec<u32>,
359 expressions: Vec<CounterExpression>,
360 mapping_regions: Vec<CounterMappingRegion>,
361 buffer: &RustString,
362 ) {
363 unsafe {
364 llvm::LLVMRustCoverageWriteMappingToBuffer(
365 virtual_file_mapping.as_ptr(),
366 virtual_file_mapping.len() as c_uint,
367 expressions.as_ptr(),
368 expressions.len() as c_uint,
369 mapping_regions.as_ptr(),
370 mapping_regions.len() as c_uint,
371 buffer,
372 );
373 }
374 }
375
hash_str(strval: &str) -> u64376 pub(crate) fn hash_str(strval: &str) -> u64 {
377 let strval = CString::new(strval).expect("null error converting hashable str to C string");
378 unsafe { llvm::LLVMRustCoverageHashCString(strval.as_ptr()) }
379 }
380
hash_bytes(bytes: Vec<u8>) -> u64381 pub(crate) fn hash_bytes(bytes: Vec<u8>) -> u64 {
382 unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_ptr().cast(), bytes.len()) }
383 }
384
mapping_version() -> u32385 pub(crate) fn mapping_version() -> u32 {
386 unsafe { llvm::LLVMRustCoverageMappingVersion() }
387 }
388
save_cov_data_to_mod<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, cov_data_val: &'ll llvm::Value, )389 pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
390 cx: &CodegenCx<'ll, 'tcx>,
391 cov_data_val: &'ll llvm::Value,
392 ) {
393 let covmap_var_name = llvm::build_string(|s| unsafe {
394 llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
395 })
396 .expect("Rust Coverage Mapping var name failed UTF-8 conversion");
397 debug!("covmap var name: {:?}", covmap_var_name);
398
399 let covmap_section_name = llvm::build_string(|s| unsafe {
400 llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
401 })
402 .expect("Rust Coverage section name failed UTF-8 conversion");
403 debug!("covmap section name: {:?}", covmap_section_name);
404
405 let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name);
406 llvm::set_initializer(llglobal, cov_data_val);
407 llvm::set_global_constant(llglobal, true);
408 llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
409 llvm::set_section(llglobal, &covmap_section_name);
410 llvm::set_alignment(llglobal, VAR_ALIGN_BYTES);
411 cx.add_used_global(llglobal);
412 }
413
save_func_record_to_mod<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, func_name_hash: u64, func_record_val: &'ll llvm::Value, is_used: bool, )414 pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
415 cx: &CodegenCx<'ll, 'tcx>,
416 func_name_hash: u64,
417 func_record_val: &'ll llvm::Value,
418 is_used: bool,
419 ) {
420 // Assign a name to the function record. This is used to merge duplicates.
421 //
422 // In LLVM, a "translation unit" (effectively, a `Crate` in Rust) can describe functions that
423 // are included-but-not-used. If (or when) Rust generates functions that are
424 // included-but-not-used, note that a dummy description for a function included-but-not-used
425 // in a Crate can be replaced by full description provided by a different Crate. The two kinds
426 // of descriptions play distinct roles in LLVM IR; therefore, assign them different names (by
427 // appending "u" to the end of the function record var name, to prevent `linkonce_odr` merging.
428 let func_record_var_name =
429 format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" });
430 debug!("function record var name: {:?}", func_record_var_name);
431
432 let func_record_section_name = llvm::build_string(|s| unsafe {
433 llvm::LLVMRustCoverageWriteFuncSectionNameToString(cx.llmod, s);
434 })
435 .expect("Rust Coverage function record section name failed UTF-8 conversion");
436 debug!("function record section name: {:?}", func_record_section_name);
437
438 let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
439 llvm::set_initializer(llglobal, func_record_val);
440 llvm::set_global_constant(llglobal, true);
441 llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
442 llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
443 llvm::set_section(llglobal, &func_record_section_name);
444 llvm::set_alignment(llglobal, VAR_ALIGN_BYTES);
445 llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
446 cx.add_used_global(llglobal);
447 }
448