1- use std:: ffi:: CStr ;
1+ use std:: ffi:: CString ;
22
33use itertools:: Itertools as _;
4- use rustc_codegen_ssa:: traits:: { BaseTypeCodegenMethods , ConstCodegenMethods } ;
4+ use rustc_abi:: Align ;
5+ use rustc_codegen_ssa:: traits:: {
6+ BaseTypeCodegenMethods , ConstCodegenMethods , StaticCodegenMethods ,
7+ } ;
58use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
69use rustc_hir:: def_id:: { DefId , LocalDefId } ;
710use rustc_index:: IndexVec ;
@@ -10,6 +13,7 @@ use rustc_middle::ty::{self, TyCtxt};
1013use rustc_middle:: { bug, mir} ;
1114use rustc_span:: Symbol ;
1215use rustc_span:: def_id:: DefIdSet ;
16+ use rustc_target:: spec:: HasTargetSpec ;
1317use tracing:: debug;
1418
1519use crate :: common:: CodegenCx ;
@@ -50,11 +54,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
5054 add_unused_functions ( cx) ;
5155 }
5256
53- let function_coverage_map = match cx. coverage_context ( ) {
54- Some ( ctx) => ctx. take_function_coverage_map ( ) ,
55- None => return ,
56- } ;
57-
57+ let function_coverage_map = cx. coverage_cx ( ) . take_function_coverage_map ( ) ;
5858 if function_coverage_map. is_empty ( ) {
5959 // This module has no functions with coverage instrumentation
6060 return ;
@@ -78,11 +78,9 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
7878
7979 // Generate the coverage map header, which contains the filenames used by
8080 // this CGU's coverage mappings, and store it in a well-known global.
81- let cov_data_val = generate_coverage_map ( cx, covmap_version, filenames_size, filenames_val) ;
82- coverageinfo:: save_cov_data_to_mod ( cx, cov_data_val) ;
81+ generate_covmap_record ( cx, covmap_version, filenames_size, filenames_val) ;
8382
8483 let mut unused_function_names = Vec :: new ( ) ;
85- let covfun_section_name = coverageinfo:: covfun_section_name ( cx) ;
8684
8785 // Encode coverage mappings and generate function records
8886 for ( instance, function_coverage) in function_coverage_entries {
@@ -111,9 +109,8 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
111109 unused_function_names. push ( mangled_function_name) ;
112110 }
113111
114- save_function_record (
112+ generate_covfun_record (
115113 cx,
116- & covfun_section_name,
117114 mangled_function_name,
118115 source_hash,
119116 filenames_ref,
@@ -308,15 +305,15 @@ fn encode_mappings_for_function(
308305 } )
309306}
310307
311- /// Construct coverage map header and the array of function records, and combine them into the
312- /// coverage map. Save the coverage map data into the LLVM IR as a static global using a
313- /// specific, well-known section and name .
314- fn generate_coverage_map < ' ll > (
308+ /// Generates the contents of the covmap record for this CGU, which mostly
309+ /// consists of a header and a list of filenames. The record is then stored
310+ /// as a global variable in the `__llvm_covmap` section .
311+ fn generate_covmap_record < ' ll > (
315312 cx : & CodegenCx < ' ll , ' _ > ,
316313 version : u32 ,
317314 filenames_size : usize ,
318315 filenames_val : & ' ll llvm:: Value ,
319- ) -> & ' ll llvm :: Value {
316+ ) {
320317 debug ! ( "cov map: filenames_size = {}, 0-based version = {}" , filenames_size, version) ;
321318
322319 // Create the coverage data header (Note, fields 0 and 2 are now always zero,
@@ -331,15 +328,37 @@ fn generate_coverage_map<'ll>(
331328 ) ;
332329
333330 // Create the complete LLVM coverage data value to add to the LLVM IR
334- cx. const_struct ( & [ cov_data_header_val, filenames_val] , /*packed=*/ false )
331+ let covmap_data =
332+ cx. const_struct ( & [ cov_data_header_val, filenames_val] , /*packed=*/ false ) ;
333+
334+ let covmap_var_name = CString :: new ( llvm:: build_byte_buffer ( |s| unsafe {
335+ llvm:: LLVMRustCoverageWriteMappingVarNameToString ( s) ;
336+ } ) )
337+ . unwrap ( ) ;
338+ debug ! ( "covmap var name: {:?}" , covmap_var_name) ;
339+
340+ let covmap_section_name = CString :: new ( llvm:: build_byte_buffer ( |s| unsafe {
341+ llvm:: LLVMRustCoverageWriteMapSectionNameToString ( cx. llmod , s) ;
342+ } ) )
343+ . expect ( "covmap section name should not contain NUL" ) ;
344+ debug ! ( "covmap section name: {:?}" , covmap_section_name) ;
345+
346+ let llglobal = llvm:: add_global ( cx. llmod , cx. val_ty ( covmap_data) , & covmap_var_name) ;
347+ llvm:: set_initializer ( llglobal, covmap_data) ;
348+ llvm:: set_global_constant ( llglobal, true ) ;
349+ llvm:: set_linkage ( llglobal, llvm:: Linkage :: PrivateLinkage ) ;
350+ llvm:: set_section ( llglobal, & covmap_section_name) ;
351+ // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
352+ // <https://llvm.org/docs/CoverageMappingFormat.html>
353+ llvm:: set_alignment ( llglobal, Align :: EIGHT ) ;
354+ cx. add_used_global ( llglobal) ;
335355}
336356
337- /// Construct a function record and combine it with the function's coverage mapping data.
338- /// Save the function record into the LLVM IR as a static global using a
339- /// specific, well-known section and name .
340- fn save_function_record (
357+ /// Generates the contents of the covfun record for this function, which
358+ /// contains the function's coverage mapping data. The record is then stored
359+ /// as a global variable in the `__llvm_covfun` section .
360+ fn generate_covfun_record (
341361 cx : & CodegenCx < ' _ , ' _ > ,
342- covfun_section_name : & CStr ,
343362 mangled_function_name : & str ,
344363 source_hash : u64 ,
345364 filenames_ref : u64 ,
@@ -366,13 +385,28 @@ fn save_function_record(
366385 /*packed=*/ true ,
367386 ) ;
368387
369- coverageinfo:: save_func_record_to_mod (
370- cx,
371- covfun_section_name,
372- func_name_hash,
373- func_record_val,
374- is_used,
375- ) ;
388+ // Choose a variable name to hold this function's covfun data.
389+ // Functions that are used have a suffix ("u") to distinguish them from
390+ // unused copies of the same function (from different CGUs), so that if a
391+ // linker sees both it won't discard the used copy's data.
392+ let func_record_var_name =
393+ CString :: new ( format ! ( "__covrec_{:X}{}" , func_name_hash, if is_used { "u" } else { "" } ) )
394+ . unwrap ( ) ;
395+ debug ! ( "function record var name: {:?}" , func_record_var_name) ;
396+
397+ let llglobal = llvm:: add_global ( cx. llmod , cx. val_ty ( func_record_val) , & func_record_var_name) ;
398+ llvm:: set_initializer ( llglobal, func_record_val) ;
399+ llvm:: set_global_constant ( llglobal, true ) ;
400+ llvm:: set_linkage ( llglobal, llvm:: Linkage :: LinkOnceODRLinkage ) ;
401+ llvm:: set_visibility ( llglobal, llvm:: Visibility :: Hidden ) ;
402+ llvm:: set_section ( llglobal, cx. covfun_section_name ( ) ) ;
403+ // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
404+ // <https://llvm.org/docs/CoverageMappingFormat.html>
405+ llvm:: set_alignment ( llglobal, Align :: EIGHT ) ;
406+ if cx. target_spec ( ) . supports_comdat ( ) {
407+ llvm:: set_comdat ( cx. llmod , llglobal, & func_record_var_name) ;
408+ }
409+ cx. add_used_global ( llglobal) ;
376410}
377411
378412/// Each CGU will normally only emit coverage metadata for the functions that it actually generates.
@@ -504,9 +538,5 @@ fn add_unused_function_coverage<'tcx>(
504538 // zero, because none of its counters/expressions are marked as seen.
505539 let function_coverage = FunctionCoverageCollector :: unused ( instance, function_coverage_info) ;
506540
507- if let Some ( coverage_context) = cx. coverage_context ( ) {
508- coverage_context. function_coverage_map . borrow_mut ( ) . insert ( instance, function_coverage) ;
509- } else {
510- bug ! ( "Could not get the `coverage_context`" ) ;
511- }
541+ cx. coverage_cx ( ) . function_coverage_map . borrow_mut ( ) . insert ( instance, function_coverage) ;
512542}
0 commit comments