]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_llvm/coverageinfo/mod.rs
Merge branch 'master' into feature/incorporate-tracing
[rust.git] / src / librustc_codegen_llvm / coverageinfo / mod.rs
1 use crate::llvm;
2
3 use crate::builder::Builder;
4 use crate::common::CodegenCx;
5
6 use libc::c_uint;
7 use llvm::coverageinfo::CounterMappingRegion;
8 use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, ExprKind, FunctionCoverage, Region};
9 use rustc_codegen_ssa::traits::{
10     BaseTypeMethods, CoverageInfoBuilderMethods, CoverageInfoMethods, StaticMethods,
11 };
12 use rustc_data_structures::fx::FxHashMap;
13 use rustc_llvm::RustString;
14 use rustc_middle::ty::Instance;
15 use tracing::debug;
16
17 use std::cell::RefCell;
18 use std::ffi::CString;
19
20 pub mod mapgen;
21
22 const COVMAP_VAR_ALIGN_BYTES: usize = 8;
23
24 /// A context object for maintaining all state needed by the coverageinfo module.
25 pub struct CrateCoverageContext<'tcx> {
26     // Coverage region data for each instrumented function identified by DefId.
27     pub(crate) function_coverage_map: RefCell<FxHashMap<Instance<'tcx>, FunctionCoverage<'tcx>>>,
28 }
29
30 impl<'tcx> CrateCoverageContext<'tcx> {
31     pub fn new() -> Self {
32         Self { function_coverage_map: Default::default() }
33     }
34
35     pub fn take_function_coverage_map(&self) -> FxHashMap<Instance<'tcx>, FunctionCoverage<'tcx>> {
36         self.function_coverage_map.replace(FxHashMap::default())
37     }
38 }
39
40 impl CoverageInfoMethods for CodegenCx<'ll, 'tcx> {
41     fn coverageinfo_finalize(&self) {
42         mapgen::finalize(self)
43     }
44 }
45
46 impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
47     fn add_counter_region(
48         &mut self,
49         instance: Instance<'tcx>,
50         function_source_hash: u64,
51         id: u32,
52         region: Region<'tcx>,
53     ) {
54         debug!(
55             "adding counter to coverage_regions: instance={:?}, function_source_hash={}, id={}, \
56              at {:?}",
57             instance, function_source_hash, id, region,
58         );
59         let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
60         coverage_regions
61             .entry(instance)
62             .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
63             .add_counter(function_source_hash, id, region);
64     }
65
66     fn add_counter_expression_region(
67         &mut self,
68         instance: Instance<'tcx>,
69         id_descending_from_max: u32,
70         lhs: u32,
71         op: ExprKind,
72         rhs: u32,
73         region: Region<'tcx>,
74     ) {
75         debug!(
76             "adding counter expression to coverage_regions: instance={:?}, id={}, {} {:?} {}, \
77              at {:?}",
78             instance, id_descending_from_max, lhs, op, rhs, region,
79         );
80         let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
81         coverage_regions
82             .entry(instance)
83             .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
84             .add_counter_expression(id_descending_from_max, lhs, op, rhs, region);
85     }
86
87     fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: Region<'tcx>) {
88         debug!(
89             "adding unreachable code to coverage_regions: instance={:?}, at {:?}",
90             instance, region,
91         );
92         let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
93         coverage_regions
94             .entry(instance)
95             .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
96             .add_unreachable_region(region);
97     }
98 }
99
100 pub(crate) fn write_filenames_section_to_buffer<'a>(
101     filenames: impl IntoIterator<Item = &'a CString>,
102     buffer: &RustString,
103 ) {
104     let c_str_vec = filenames.into_iter().map(|cstring| cstring.as_ptr()).collect::<Vec<_>>();
105     unsafe {
106         llvm::LLVMRustCoverageWriteFilenamesSectionToBuffer(
107             c_str_vec.as_ptr(),
108             c_str_vec.len(),
109             buffer,
110         );
111     }
112 }
113
114 pub(crate) fn write_mapping_to_buffer(
115     virtual_file_mapping: Vec<u32>,
116     expressions: Vec<CounterExpression>,
117     mut mapping_regions: Vec<CounterMappingRegion>,
118     buffer: &RustString,
119 ) {
120     unsafe {
121         llvm::LLVMRustCoverageWriteMappingToBuffer(
122             virtual_file_mapping.as_ptr(),
123             virtual_file_mapping.len() as c_uint,
124             expressions.as_ptr(),
125             expressions.len() as c_uint,
126             mapping_regions.as_mut_ptr(),
127             mapping_regions.len() as c_uint,
128             buffer,
129         );
130     }
131 }
132
133 pub(crate) fn compute_hash(name: &str) -> u64 {
134     let name = CString::new(name).expect("null error converting hashable name to C string");
135     unsafe { llvm::LLVMRustCoverageComputeHash(name.as_ptr()) }
136 }
137
138 pub(crate) fn mapping_version() -> u32 {
139     unsafe { llvm::LLVMRustCoverageMappingVersion() }
140 }
141
142 pub(crate) fn save_map_to_mod<'ll, 'tcx>(
143     cx: &CodegenCx<'ll, 'tcx>,
144     cov_data_val: &'ll llvm::Value,
145 ) {
146     let covmap_var_name = llvm::build_string(|s| unsafe {
147         llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
148     })
149     .expect("Rust Coverage Mapping var name failed UTF-8 conversion");
150     debug!("covmap var name: {:?}", covmap_var_name);
151
152     let covmap_section_name = llvm::build_string(|s| unsafe {
153         llvm::LLVMRustCoverageWriteSectionNameToString(cx.llmod, s);
154     })
155     .expect("Rust Coverage section name failed UTF-8 conversion");
156     debug!("covmap section name: {:?}", covmap_section_name);
157
158     let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name);
159     llvm::set_initializer(llglobal, cov_data_val);
160     llvm::set_global_constant(llglobal, true);
161     llvm::set_linkage(llglobal, llvm::Linkage::InternalLinkage);
162     llvm::set_section(llglobal, &covmap_section_name);
163     llvm::set_alignment(llglobal, COVMAP_VAR_ALIGN_BYTES);
164     cx.add_used_global(llglobal);
165 }