1
- use std:: ffi:: CStr ;
1
+ use std:: ffi:: { CStr , 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 ;
@@ -78,8 +82,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
78
82
79
83
// Generate the coverage map header, which contains the filenames used by
80
84
// 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) ;
85
+ generate_covmap_record ( cx, covmap_version, filenames_size, filenames_val) ;
83
86
84
87
let mut unused_function_names = Vec :: new ( ) ;
85
88
let covfun_section_name = coverageinfo:: covfun_section_name ( cx) ;
@@ -111,7 +114,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
111
114
unused_function_names. push ( mangled_function_name) ;
112
115
}
113
116
114
- save_function_record (
117
+ generate_covfun_record (
115
118
cx,
116
119
& covfun_section_name,
117
120
mangled_function_name,
@@ -308,15 +311,15 @@ fn encode_mappings_for_function(
308
311
} )
309
312
}
310
313
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 > (
314
+ /// Generates the contents of the covmap record for this CGU, which mostly
315
+ /// consists of a header and a list of filenames. The record is then stored
316
+ /// as a global variable in the `__llvm_covmap` section .
317
+ fn generate_covmap_record < ' ll > (
315
318
cx : & CodegenCx < ' ll , ' _ > ,
316
319
version : u32 ,
317
320
filenames_size : usize ,
318
321
filenames_val : & ' ll llvm:: Value ,
319
- ) -> & ' ll llvm :: Value {
322
+ ) {
320
323
debug ! ( "cov map: filenames_size = {}, 0-based version = {}" , filenames_size, version) ;
321
324
322
325
// Create the coverage data header (Note, fields 0 and 2 are now always zero,
@@ -331,13 +334,35 @@ fn generate_coverage_map<'ll>(
331
334
) ;
332
335
333
336
// 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 )
337
+ let covmap_data =
338
+ cx. const_struct ( & [ cov_data_header_val, filenames_val] , /*packed=*/ false ) ;
339
+
340
+ let covmap_var_name = CString :: new ( llvm:: build_byte_buffer ( |s| unsafe {
341
+ llvm:: LLVMRustCoverageWriteMappingVarNameToString ( s) ;
342
+ } ) )
343
+ . unwrap ( ) ;
344
+ debug ! ( "covmap var name: {:?}" , covmap_var_name) ;
345
+
346
+ let covmap_section_name = CString :: new ( llvm:: build_byte_buffer ( |s| unsafe {
347
+ llvm:: LLVMRustCoverageWriteMapSectionNameToString ( cx. llmod , s) ;
348
+ } ) )
349
+ . expect ( "covmap section name should not contain NUL" ) ;
350
+ debug ! ( "covmap section name: {:?}" , covmap_section_name) ;
351
+
352
+ let llglobal = llvm:: add_global ( cx. llmod , cx. val_ty ( covmap_data) , & covmap_var_name) ;
353
+ llvm:: set_initializer ( llglobal, covmap_data) ;
354
+ llvm:: set_global_constant ( llglobal, true ) ;
355
+ llvm:: set_linkage ( llglobal, llvm:: Linkage :: PrivateLinkage ) ;
356
+ llvm:: set_section ( llglobal, & covmap_section_name) ;
357
+ // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
358
+ llvm:: set_alignment ( llglobal, Align :: EIGHT ) ;
359
+ cx. add_used_global ( llglobal) ;
335
360
}
336
361
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 (
362
+ /// Generates the contents of the covfun record for this function, which
363
+ /// contains the function's coverage mapping data. The record is then stored
364
+ /// as a global variable in the `__llvm_covfun` section .
365
+ fn generate_covfun_record (
341
366
cx : & CodegenCx < ' _ , ' _ > ,
342
367
covfun_section_name : & CStr ,
343
368
mangled_function_name : & str ,
@@ -366,13 +391,27 @@ fn save_function_record(
366
391
/*packed=*/ true ,
367
392
) ;
368
393
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
- ) ;
394
+ // Choose a variable name to hold this function's covfun data.
395
+ // Functions that are used have a suffix ("u") to distinguish them from
396
+ // unused copies of the same function (from different CGUs), so that if a
397
+ // linker sees both it won't discard the used copy's data.
398
+ let func_record_var_name =
399
+ CString :: new ( format ! ( "__covrec_{:X}{}" , func_name_hash, if is_used { "u" } else { "" } ) )
400
+ . unwrap ( ) ;
401
+ debug ! ( "function record var name: {:?}" , func_record_var_name) ;
402
+
403
+ let llglobal = llvm:: add_global ( cx. llmod , cx. val_ty ( func_record_val) , & func_record_var_name) ;
404
+ llvm:: set_initializer ( llglobal, func_record_val) ;
405
+ llvm:: set_global_constant ( llglobal, true ) ;
406
+ llvm:: set_linkage ( llglobal, llvm:: Linkage :: LinkOnceODRLinkage ) ;
407
+ llvm:: set_visibility ( llglobal, llvm:: Visibility :: Hidden ) ;
408
+ llvm:: set_section ( llglobal, covfun_section_name) ;
409
+ // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
410
+ llvm:: set_alignment ( llglobal, Align :: EIGHT ) ;
411
+ if cx. target_spec ( ) . supports_comdat ( ) {
412
+ llvm:: set_comdat ( cx. llmod , llglobal, & func_record_var_name) ;
413
+ }
414
+ cx. add_used_global ( llglobal) ;
376
415
}
377
416
378
417
/// Each CGU will normally only emit coverage metadata for the functions that it actually generates.
0 commit comments