]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_llvm/coverageinfo/mod.rs
Auto merge of #75137 - Aaron1011:fix/hygiene-skip-expndata, r=petrochenkov
[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 log::debug;
9 use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, ExprKind, FunctionCoverage, Region};
10 use rustc_codegen_ssa::traits::{
11     BaseTypeMethods, CoverageInfoBuilderMethods, CoverageInfoMethods, StaticMethods,
12 };
13 use rustc_data_structures::fx::FxHashMap;
14 use rustc_llvm::RustString;
15 use rustc_middle::ty::Instance;
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(filenames: &Vec<CString>, buffer: &RustString) {
101     let c_str_vec = filenames.iter().map(|cstring| cstring.as_ptr()).collect::<Vec<_>>();
102     unsafe {
103         llvm::LLVMRustCoverageWriteFilenamesSectionToBuffer(
104             c_str_vec.as_ptr(),
105             c_str_vec.len(),
106             buffer,
107         );
108     }
109 }
110
111 pub(crate) fn write_mapping_to_buffer(
112     virtual_file_mapping: Vec<u32>,
113     expressions: Vec<CounterExpression>,
114     mut mapping_regions: Vec<CounterMappingRegion>,
115     buffer: &RustString,
116 ) {
117     unsafe {
118         llvm::LLVMRustCoverageWriteMappingToBuffer(
119             virtual_file_mapping.as_ptr(),
120             virtual_file_mapping.len() as c_uint,
121             expressions.as_ptr(),
122             expressions.len() as c_uint,
123             mapping_regions.as_mut_ptr(),
124             mapping_regions.len() as c_uint,
125             buffer,
126         );
127     }
128 }
129
130 pub(crate) fn compute_hash(name: &str) -> u64 {
131     let name = CString::new(name).expect("null error converting hashable name to C string");
132     unsafe { llvm::LLVMRustCoverageComputeHash(name.as_ptr()) }
133 }
134
135 pub(crate) fn mapping_version() -> u32 {
136     unsafe { llvm::LLVMRustCoverageMappingVersion() }
137 }
138
139 pub(crate) fn save_map_to_mod<'ll, 'tcx>(
140     cx: &CodegenCx<'ll, 'tcx>,
141     cov_data_val: &'ll llvm::Value,
142 ) {
143     let covmap_var_name = llvm::build_string(|s| unsafe {
144         llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
145     })
146     .expect("Rust Coverage Mapping var name failed UTF-8 conversion");
147     debug!("covmap var name: {:?}", covmap_var_name);
148
149     let covmap_section_name = llvm::build_string(|s| unsafe {
150         llvm::LLVMRustCoverageWriteSectionNameToString(cx.llmod, s);
151     })
152     .expect("Rust Coverage section name failed UTF-8 conversion");
153     debug!("covmap section name: {:?}", covmap_section_name);
154
155     let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name);
156     llvm::set_initializer(llglobal, cov_data_val);
157     llvm::set_global_constant(llglobal, true);
158     llvm::set_linkage(llglobal, llvm::Linkage::InternalLinkage);
159     llvm::set_section(llglobal, &covmap_section_name);
160     llvm::set_alignment(llglobal, COVMAP_VAR_ALIGN_BYTES);
161     cx.add_used_global(llglobal);
162 }