1
- use std:: ffi:: CStr ;
1
+ use std:: ffi:: CString ;
2
2
3
3
use 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
+ } ;
5
8
use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
6
9
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
7
10
use rustc_index:: IndexVec ;
@@ -10,6 +13,7 @@ use rustc_middle::ty::{self, TyCtxt};
10
13
use rustc_middle:: { bug, mir} ;
11
14
use rustc_span:: Symbol ;
12
15
use rustc_span:: def_id:: DefIdSet ;
16
+ use rustc_target:: spec:: HasTargetSpec ;
13
17
use tracing:: debug;
14
18
15
19
use crate :: common:: CodegenCx ;
@@ -50,11 +54,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
50
54
add_unused_functions ( cx) ;
51
55
}
52
56
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 ( ) ;
58
58
if function_coverage_map. is_empty ( ) {
59
59
// This module has no functions with coverage instrumentation
60
60
return ;
@@ -78,11 +78,9 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
78
78
79
79
// Generate the coverage map header, which contains the filenames used by
80
80
// 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) ;
83
82
84
83
let mut unused_function_names = Vec :: new ( ) ;
85
- let covfun_section_name = coverageinfo:: covfun_section_name ( cx) ;
86
84
87
85
// Encode coverage mappings and generate function records
88
86
for ( instance, function_coverage) in function_coverage_entries {
@@ -111,9 +109,8 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
111
109
unused_function_names. push ( mangled_function_name) ;
112
110
}
113
111
114
- save_function_record (
112
+ generate_covfun_record (
115
113
cx,
116
- & covfun_section_name,
117
114
mangled_function_name,
118
115
source_hash,
119
116
filenames_ref,
@@ -308,15 +305,15 @@ fn encode_mappings_for_function(
308
305
} )
309
306
}
310
307
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 > (
315
312
cx : & CodegenCx < ' ll , ' _ > ,
316
313
version : u32 ,
317
314
filenames_size : usize ,
318
315
filenames_val : & ' ll llvm:: Value ,
319
- ) -> & ' ll llvm :: Value {
316
+ ) {
320
317
debug ! ( "cov map: filenames_size = {}, 0-based version = {}" , filenames_size, version) ;
321
318
322
319
// Create the coverage data header (Note, fields 0 and 2 are now always zero,
@@ -331,15 +328,37 @@ fn generate_coverage_map<'ll>(
331
328
) ;
332
329
333
330
// 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) ;
335
355
}
336
356
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 (
341
361
cx : & CodegenCx < ' _ , ' _ > ,
342
- covfun_section_name : & CStr ,
343
362
mangled_function_name : & str ,
344
363
source_hash : u64 ,
345
364
filenames_ref : u64 ,
@@ -366,13 +385,28 @@ fn save_function_record(
366
385
/*packed=*/ true ,
367
386
) ;
368
387
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) ;
376
410
}
377
411
378
412
/// 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>(
504
538
// zero, because none of its counters/expressions are marked as seen.
505
539
let function_coverage = FunctionCoverageCollector :: unused ( instance, function_coverage_info) ;
506
540
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) ;
512
542
}
0 commit comments