@@ -4,7 +4,7 @@ use crate::llvm;
4
4
5
5
use llvm:: coverageinfo:: CounterMappingRegion ;
6
6
use rustc_codegen_ssa:: coverageinfo:: map:: { Counter , CounterExpression } ;
7
- use rustc_codegen_ssa:: traits:: { BaseTypeMethods , ConstMethods } ;
7
+ use rustc_codegen_ssa:: traits:: ConstMethods ;
8
8
use rustc_data_structures:: fx:: FxIndexSet ;
9
9
use rustc_llvm:: RustString ;
10
10
use rustc_middle:: mir:: coverage:: CodeRegion ;
@@ -38,46 +38,50 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
38
38
let mut mapgen = CoverageMapGenerator :: new ( ) ;
39
39
40
40
// Encode coverage mappings and generate function records
41
- let mut function_records = Vec :: < & ' ll llvm:: Value > :: new ( ) ;
42
- let coverage_mappings_buffer = llvm:: build_byte_buffer ( |coverage_mappings_buffer| {
43
- for ( instance, function_coverage) in function_coverage_map. into_iter ( ) {
44
- debug ! ( "Generate coverage map for: {:?}" , instance) ;
45
-
46
- let mangled_function_name = cx. tcx . symbol_name ( instance) . to_string ( ) ;
47
- let function_source_hash = function_coverage. source_hash ( ) ;
48
- let ( expressions, counter_regions) =
49
- function_coverage. get_expressions_and_counter_regions ( ) ;
50
-
51
- let old_len = coverage_mappings_buffer. len ( ) ;
52
- mapgen. write_coverage_mappings ( expressions, counter_regions, coverage_mappings_buffer) ;
53
- let mapping_data_size = coverage_mappings_buffer. len ( ) - old_len;
54
- debug_assert ! (
55
- mapping_data_size > 0 ,
56
- "Every `FunctionCoverage` should have at least one counter"
57
- ) ;
58
-
59
- let function_record = mapgen. make_function_record (
60
- cx,
61
- mangled_function_name,
62
- function_source_hash,
63
- mapping_data_size,
64
- ) ;
65
- function_records. push ( function_record) ;
66
- }
67
- } ) ;
41
+ let mut function_data = Vec :: new ( ) ;
42
+ for ( instance, function_coverage) in function_coverage_map. into_iter ( ) {
43
+ debug ! ( "Generate coverage map for: {:?}" , instance) ;
44
+
45
+ let mangled_function_name = cx. tcx . symbol_name ( instance) . to_string ( ) ;
46
+ let function_source_hash = function_coverage. source_hash ( ) ;
47
+ let ( expressions, counter_regions) =
48
+ function_coverage. get_expressions_and_counter_regions ( ) ;
49
+
50
+ let coverage_mapping_buffer = llvm:: build_byte_buffer ( |coverage_mapping_buffer| {
51
+ mapgen. write_coverage_mapping ( expressions, counter_regions, coverage_mapping_buffer) ;
52
+ } ) ;
53
+ debug_assert ! (
54
+ coverage_mapping_buffer. len( ) > 0 ,
55
+ "Every `FunctionCoverage` should have at least one counter"
56
+ ) ;
57
+
58
+ function_data. push ( ( mangled_function_name, function_source_hash, coverage_mapping_buffer) ) ;
59
+ }
68
60
69
61
// Encode all filenames referenced by counters/expressions in this module
70
62
let filenames_buffer = llvm:: build_byte_buffer ( |filenames_buffer| {
71
63
coverageinfo:: write_filenames_section_to_buffer ( & mapgen. filenames , filenames_buffer) ;
72
64
} ) ;
73
65
66
+ let filenames_size = filenames_buffer. len ( ) ;
67
+ let filenames_val = cx. const_bytes ( & filenames_buffer[ ..] ) ;
68
+ let filenames_ref = coverageinfo:: hash_bytes ( filenames_buffer) ;
69
+
74
70
// Generate the LLVM IR representation of the coverage map and store it in a well-known global
75
- mapgen. save_generated_coverage_map (
76
- cx,
77
- function_records,
78
- filenames_buffer,
79
- coverage_mappings_buffer,
80
- ) ;
71
+ let cov_data_val = mapgen. generate_coverage_map ( cx, filenames_size, filenames_val) ;
72
+
73
+ for ( mangled_function_name, function_source_hash, coverage_mapping_buffer) in function_data {
74
+ save_function_record (
75
+ cx,
76
+ mangled_function_name,
77
+ function_source_hash,
78
+ filenames_ref,
79
+ coverage_mapping_buffer,
80
+ ) ;
81
+ }
82
+
83
+ // Save the coverage data value to LLVM IR
84
+ coverageinfo:: save_cov_data_to_mod ( cx, cov_data_val) ;
81
85
}
82
86
83
87
struct CoverageMapGenerator {
@@ -92,12 +96,12 @@ impl CoverageMapGenerator {
92
96
/// Using the `expressions` and `counter_regions` collected for the current function, generate
93
97
/// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use
94
98
/// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into
95
- /// the given `coverage_mappings ` byte buffer, compliant with the LLVM Coverage Mapping format.
96
- fn write_coverage_mappings (
99
+ /// the given `coverage_mapping ` byte buffer, compliant with the LLVM Coverage Mapping format.
100
+ fn write_coverage_mapping (
97
101
& mut self ,
98
102
expressions : Vec < CounterExpression > ,
99
103
counter_regions : impl Iterator < Item = ( Counter , & ' a CodeRegion ) > ,
100
- coverage_mappings_buffer : & RustString ,
104
+ coverage_mapping_buffer : & RustString ,
101
105
) {
102
106
let mut counter_regions = counter_regions. collect :: < Vec < _ > > ( ) ;
103
107
if counter_regions. is_empty ( ) {
@@ -145,89 +149,78 @@ impl CoverageMapGenerator {
145
149
virtual_file_mapping,
146
150
expressions,
147
151
mapping_regions,
148
- coverage_mappings_buffer ,
152
+ coverage_mapping_buffer ,
149
153
) ;
150
154
}
151
155
152
- /// Generate and return the function record `Value`
153
- fn make_function_record (
154
- & mut self ,
155
- cx : & CodegenCx < ' ll , ' tcx > ,
156
- mangled_function_name : String ,
157
- function_source_hash : u64 ,
158
- mapping_data_size : usize ,
159
- ) -> & ' ll llvm:: Value {
160
- let name_ref = coverageinfo:: compute_hash ( & mangled_function_name) ;
161
- let name_ref_val = cx. const_u64 ( name_ref) ;
162
- let mapping_data_size_val = cx. const_u32 ( mapping_data_size as u32 ) ;
163
- let func_hash_val = cx. const_u64 ( function_source_hash) ;
164
- cx. const_struct (
165
- & [ name_ref_val, mapping_data_size_val, func_hash_val] ,
166
- /*packed=*/ true ,
167
- )
168
- }
169
-
170
- /// Combine the filenames and coverage mappings buffers, construct coverage map header and the
171
- /// array of function records, and combine everything into the complete coverage map. Save the
172
- /// coverage map data into the LLVM IR as a static global using a specific, well-known section
173
- /// and name.
174
- fn save_generated_coverage_map (
156
+ /// Construct coverage map header and the array of function records, and combine them into the
157
+ /// coverage map. Save the coverage map data into the LLVM IR as a static global using a
158
+ /// specific, well-known section and name.
159
+ fn generate_coverage_map (
175
160
self ,
176
161
cx : & CodegenCx < ' ll , ' tcx > ,
177
- function_records : Vec < & ' ll llvm:: Value > ,
178
- filenames_buffer : Vec < u8 > ,
179
- mut coverage_mappings_buffer : Vec < u8 > ,
180
- ) {
181
- // Concatenate the encoded filenames and encoded coverage mappings, and add additional zero
182
- // bytes as-needed to ensure 8-byte alignment.
183
- let mut coverage_size = coverage_mappings_buffer. len ( ) ;
184
- let filenames_size = filenames_buffer. len ( ) ;
185
- let remaining_bytes =
186
- ( filenames_size + coverage_size) % coverageinfo:: COVMAP_VAR_ALIGN_BYTES ;
187
- if remaining_bytes > 0 {
188
- let pad = coverageinfo:: COVMAP_VAR_ALIGN_BYTES - remaining_bytes;
189
- coverage_mappings_buffer. append ( & mut [ 0 ] . repeat ( pad) ) ;
190
- coverage_size += pad;
191
- }
192
- let filenames_and_coverage_mappings = [ filenames_buffer, coverage_mappings_buffer] . concat ( ) ;
193
- let filenames_and_coverage_mappings_val =
194
- cx. const_bytes ( & filenames_and_coverage_mappings[ ..] ) ;
195
-
162
+ filenames_size : usize ,
163
+ filenames_val : & ' ll llvm:: Value ,
164
+ ) -> & ' ll llvm:: Value {
196
165
debug ! (
197
- "cov map: n_records = {}, filenames_size = {}, coverage_size = {}, 0-based version = {}" ,
198
- function_records. len( ) ,
166
+ "cov map: filenames_size = {}, 0-based version = {}" ,
199
167
filenames_size,
200
- coverage_size,
201
168
coverageinfo:: mapping_version( )
202
169
) ;
203
170
204
- // Create the coverage data header
205
- let n_records_val = cx. const_u32 ( function_records. len ( ) as u32 ) ;
171
+ // Create the coverage data header (Note, fields 0 and 2 are now always zero,
172
+ // as of `llvm::coverage::CovMapVersion::Version4`.
173
+ let zero_was_n_records_val = cx. const_u32 ( 0 ) ;
206
174
let filenames_size_val = cx. const_u32 ( filenames_size as u32 ) ;
207
- let coverage_size_val = cx. const_u32 ( coverage_size as u32 ) ;
175
+ let zero_was_coverage_size_val = cx. const_u32 ( 0 as u32 ) ;
208
176
let version_val = cx. const_u32 ( coverageinfo:: mapping_version ( ) ) ;
209
177
let cov_data_header_val = cx. const_struct (
210
- & [ n_records_val , filenames_size_val, coverage_size_val , version_val] ,
178
+ & [ zero_was_n_records_val , filenames_size_val, zero_was_coverage_size_val , version_val] ,
211
179
/*packed=*/ false ,
212
180
) ;
213
181
214
- // Create the function records array
215
- let name_ref_from_u64 = cx. type_i64 ( ) ;
216
- let mapping_data_size_from_u32 = cx. type_i32 ( ) ;
217
- let func_hash_from_u64 = cx. type_i64 ( ) ;
218
- let function_record_ty = cx. type_struct (
219
- & [ name_ref_from_u64, mapping_data_size_from_u32, func_hash_from_u64] ,
220
- /*packed=*/ true ,
221
- ) ;
222
- let function_records_val = cx. const_array ( function_record_ty, & function_records[ ..] ) ;
223
-
224
182
// Create the complete LLVM coverage data value to add to the LLVM IR
225
- let cov_data_val = cx. const_struct (
226
- & [ cov_data_header_val, function_records_val, filenames_and_coverage_mappings_val] ,
227
- /*packed=*/ false ,
228
- ) ;
229
-
230
- // Save the coverage data value to LLVM IR
231
- coverageinfo:: save_map_to_mod ( cx, cov_data_val) ;
183
+ cx. const_struct ( & [ cov_data_header_val, filenames_val] , /*packed=*/ false )
232
184
}
233
185
}
186
+
187
+ /// Construct a function record and combine it with the function's coverage mapping data.
188
+ /// Save the function record into the LLVM IR as a static global using a
189
+ /// specific, well-known section and name.
190
+ fn save_function_record (
191
+ cx : & CodegenCx < ' ll , ' tcx > ,
192
+ mangled_function_name : String ,
193
+ function_source_hash : u64 ,
194
+ filenames_ref : u64 ,
195
+ coverage_mapping_buffer : Vec < u8 > ,
196
+ ) {
197
+ // Concatenate the encoded coverage mappings
198
+ let coverage_mapping_size = coverage_mapping_buffer. len ( ) ;
199
+ let coverage_mapping_val = cx. const_bytes ( & coverage_mapping_buffer[ ..] ) ;
200
+
201
+ let func_name_hash = coverageinfo:: hash_str ( & mangled_function_name) ;
202
+ let func_name_hash_val = cx. const_u64 ( func_name_hash) ;
203
+ let coverage_mapping_size_val = cx. const_u32 ( coverage_mapping_size as u32 ) ;
204
+ let func_hash_val = cx. const_u64 ( function_source_hash) ;
205
+ let filenames_ref_val = cx. const_u64 ( filenames_ref) ;
206
+ let func_record_val = cx. const_struct (
207
+ & [
208
+ func_name_hash_val,
209
+ coverage_mapping_size_val,
210
+ func_hash_val,
211
+ filenames_ref_val,
212
+ coverage_mapping_val,
213
+ ] ,
214
+ /*packed=*/ true ,
215
+ ) ;
216
+
217
+ // At the present time, the coverage map for Rust assumes every instrumented function `is_used`.
218
+ // Note that Clang marks functions as "unused" in `CodeGenPGO::emitEmptyCounterMapping`. (See:
219
+ // https://github.com/rust-lang/llvm-project/blob/de02a75e398415bad4df27b4547c25b896c8bf3b/clang%2Flib%2FCodeGen%2FCodeGenPGO.cpp#L877-L878
220
+ // for example.)
221
+ //
222
+ // It's not yet clear if or how this may be applied to Rust in the future, but the `is_used`
223
+ // argument is available and handled similarly.
224
+ let is_used = true ;
225
+ coverageinfo:: save_func_record_to_mod ( cx, func_name_hash, func_record_val, is_used) ;
226
+ }
0 commit comments