3 use crate::builder
::Builder
;
4 use crate::common
::CodegenCx
;
7 use llvm
::coverageinfo
::CounterMappingRegion
;
8 use rustc_codegen_ssa
::coverageinfo
::map
::{CounterExpression, FunctionCoverage}
;
9 use rustc_codegen_ssa
::traits
::{
10 BaseTypeMethods
, CoverageInfoBuilderMethods
, CoverageInfoMethods
, MiscMethods
, StaticMethods
,
12 use rustc_data_structures
::fx
::FxHashMap
;
13 use rustc_llvm
::RustString
;
14 use rustc_middle
::mir
::coverage
::{
15 CodeRegion
, CounterValueReference
, ExpressionOperandId
, InjectedExpressionId
, Op
,
17 use rustc_middle
::ty
::Instance
;
19 use std
::cell
::RefCell
;
20 use std
::ffi
::CString
;
26 const VAR_ALIGN_BYTES
: usize = 8;
28 /// A context object for maintaining all state needed by the coverageinfo module.
29 pub struct CrateCoverageContext
<'tcx
> {
30 // Coverage data for each instrumented function identified by DefId.
31 pub(crate) function_coverage_map
: RefCell
<FxHashMap
<Instance
<'tcx
>, FunctionCoverage
<'tcx
>>>,
34 impl<'tcx
> CrateCoverageContext
<'tcx
> {
35 pub fn new() -> Self {
36 Self { function_coverage_map: Default::default() }
39 pub fn take_function_coverage_map(&self) -> FxHashMap
<Instance
<'tcx
>, FunctionCoverage
<'tcx
>> {
40 self.function_coverage_map
.replace(FxHashMap
::default())
44 impl CoverageInfoMethods
for CodegenCx
<'ll
, 'tcx
> {
45 fn coverageinfo_finalize(&self) {
46 mapgen
::finalize(self)
50 impl CoverageInfoBuilderMethods
<'tcx
> for Builder
<'a
, 'll
, 'tcx
> {
51 /// Calls llvm::createPGOFuncNameVar() with the given function instance's mangled function name.
52 /// The LLVM API returns an llvm::GlobalVariable containing the function name, with the specific
53 /// variable name and linkage required by LLVM InstrProf source-based coverage instrumentation.
54 fn create_pgo_func_name_var(&self, instance
: Instance
<'tcx
>) -> Self::Value
{
55 let llfn
= self.cx
.get_fn(instance
);
56 let mangled_fn_name
= CString
::new(self.tcx
.symbol_name(instance
).name
)
57 .expect("error converting function name to C string");
58 unsafe { llvm::LLVMRustCoverageCreatePGOFuncNameVar(llfn, mangled_fn_name.as_ptr()) }
61 fn set_function_source_hash(
63 instance
: Instance
<'tcx
>,
64 function_source_hash
: u64,
66 if let Some(coverage_context
) = self.coverage_context() {
68 "ensuring function source hash is set for instance={:?}; function_source_hash={}",
69 instance
, function_source_hash
,
71 let mut coverage_map
= coverage_context
.function_coverage_map
.borrow_mut();
74 .or_insert_with(|| FunctionCoverage
::new(self.tcx
, instance
))
75 .set_function_source_hash(function_source_hash
);
82 fn add_coverage_counter(
84 instance
: Instance
<'tcx
>,
85 id
: CounterValueReference
,
88 if let Some(coverage_context
) = self.coverage_context() {
90 "adding counter to coverage_map: instance={:?}, id={:?}, region={:?}",
93 let mut coverage_map
= coverage_context
.function_coverage_map
.borrow_mut();
96 .or_insert_with(|| FunctionCoverage
::new(self.tcx
, instance
))
97 .add_counter(id
, region
);
104 fn add_coverage_counter_expression(
106 instance
: Instance
<'tcx
>,
107 id
: InjectedExpressionId
,
108 lhs
: ExpressionOperandId
,
110 rhs
: ExpressionOperandId
,
111 region
: Option
<CodeRegion
>,
113 if let Some(coverage_context
) = self.coverage_context() {
115 "adding counter expression to coverage_map: instance={:?}, id={:?}, {:?} {:?} {:?}; \
117 instance
, id
, lhs
, op
, rhs
, region
,
119 let mut coverage_map
= coverage_context
.function_coverage_map
.borrow_mut();
122 .or_insert_with(|| FunctionCoverage
::new(self.tcx
, instance
))
123 .add_counter_expression(id
, lhs
, op
, rhs
, region
);
130 fn add_coverage_unreachable(&mut self, instance
: Instance
<'tcx
>, region
: CodeRegion
) -> bool
{
131 if let Some(coverage_context
) = self.coverage_context() {
133 "adding unreachable code to coverage_map: instance={:?}, at {:?}",
136 let mut coverage_map
= coverage_context
.function_coverage_map
.borrow_mut();
139 .or_insert_with(|| FunctionCoverage
::new(self.tcx
, instance
))
140 .add_unreachable_region(region
);
148 pub(crate) fn write_filenames_section_to_buffer
<'a
>(
149 filenames
: impl IntoIterator
<Item
= &'a CString
>,
152 let c_str_vec
= filenames
.into_iter().map(|cstring
| cstring
.as_ptr()).collect
::<Vec
<_
>>();
154 llvm
::LLVMRustCoverageWriteFilenamesSectionToBuffer(
162 pub(crate) fn write_mapping_to_buffer(
163 virtual_file_mapping
: Vec
<u32>,
164 expressions
: Vec
<CounterExpression
>,
165 mapping_regions
: Vec
<CounterMappingRegion
>,
169 llvm
::LLVMRustCoverageWriteMappingToBuffer(
170 virtual_file_mapping
.as_ptr(),
171 virtual_file_mapping
.len() as c_uint
,
172 expressions
.as_ptr(),
173 expressions
.len() as c_uint
,
174 mapping_regions
.as_ptr(),
175 mapping_regions
.len() as c_uint
,
180 pub(crate) fn hash_str(strval
: &str) -> u64 {
181 let strval
= CString
::new(strval
).expect("null error converting hashable str to C string");
182 unsafe { llvm::LLVMRustCoverageHashCString(strval.as_ptr()) }
185 pub(crate) fn hash_bytes(bytes
: Vec
<u8>) -> u64 {
186 unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_ptr().cast(), bytes.len()) }
189 pub(crate) fn mapping_version() -> u32 {
190 unsafe { llvm::LLVMRustCoverageMappingVersion() }
193 pub(crate) fn save_cov_data_to_mod
<'ll
, 'tcx
>(
194 cx
: &CodegenCx
<'ll
, 'tcx
>,
195 cov_data_val
: &'ll llvm
::Value
,
197 let covmap_var_name
= llvm
::build_string(|s
| unsafe {
198 llvm
::LLVMRustCoverageWriteMappingVarNameToString(s
);
200 .expect("Rust Coverage Mapping var name failed UTF-8 conversion");
201 debug
!("covmap var name: {:?}", covmap_var_name
);
203 let covmap_section_name
= llvm
::build_string(|s
| unsafe {
204 llvm
::LLVMRustCoverageWriteMapSectionNameToString(cx
.llmod
, s
);
206 .expect("Rust Coverage section name failed UTF-8 conversion");
207 debug
!("covmap section name: {:?}", covmap_section_name
);
209 let llglobal
= llvm
::add_global(cx
.llmod
, cx
.val_ty(cov_data_val
), &covmap_var_name
);
210 llvm
::set_initializer(llglobal
, cov_data_val
);
211 llvm
::set_global_constant(llglobal
, true);
212 llvm
::set_linkage(llglobal
, llvm
::Linkage
::PrivateLinkage
);
213 llvm
::set_section(llglobal
, &covmap_section_name
);
214 llvm
::set_alignment(llglobal
, VAR_ALIGN_BYTES
);
215 cx
.add_used_global(llglobal
);
218 pub(crate) fn save_func_record_to_mod
<'ll
, 'tcx
>(
219 cx
: &CodegenCx
<'ll
, 'tcx
>,
221 func_record_val
: &'ll llvm
::Value
,
224 // Assign a name to the function record. This is used to merge duplicates.
226 // In LLVM, a "translation unit" (effectively, a `Crate` in Rust) can describe functions that
227 // are included-but-not-used. If (or when) Rust generates functions that are
228 // included-but-not-used, note that a dummy description for a function included-but-not-used
229 // in a Crate can be replaced by full description provided by a different Crate. The two kinds
230 // of descriptions play distinct roles in LLVM IR; therefore, assign them different names (by
231 // appending "u" to the end of the function record var name, to prevent `linkonce_odr` merging.
232 let func_record_var_name
=
233 format
!("__covrec_{:X}{}", func_name_hash
, if is_used { "u" }
else { "" }
);
234 debug
!("function record var name: {:?}", func_record_var_name
);
236 let func_record_section_name
= llvm
::build_string(|s
| unsafe {
237 llvm
::LLVMRustCoverageWriteFuncSectionNameToString(cx
.llmod
, s
);
239 .expect("Rust Coverage function record section name failed UTF-8 conversion");
240 debug
!("function record section name: {:?}", func_record_section_name
);
242 let llglobal
= llvm
::add_global(cx
.llmod
, cx
.val_ty(func_record_val
), &func_record_var_name
);
243 llvm
::set_initializer(llglobal
, func_record_val
);
244 llvm
::set_global_constant(llglobal
, true);
245 llvm
::set_linkage(llglobal
, llvm
::Linkage
::LinkOnceODRLinkage
);
246 llvm
::set_visibility(llglobal
, llvm
::Visibility
::Hidden
);
247 llvm
::set_section(llglobal
, &func_record_section_name
);
248 llvm
::set_alignment(llglobal
, VAR_ALIGN_BYTES
);
249 llvm
::set_comdat(cx
.llmod
, llglobal
, &func_record_var_name
);
250 cx
.add_used_global(llglobal
);