Skip to content

Commit 3d8cb68

Browse files
committed
coverage: Convert CoverageMapGenerator to GlobalFileTable
This struct was only being used to hold the global file table, and one of its methods didn't even use the table. Changing its methods to ordinary functions makes it easier to see where the table is mutated.
1 parent b0b8c52 commit 3d8cb68

File tree

1 file changed

+96
-76
lines changed
  • compiler/rustc_codegen_llvm/src/coverageinfo

1 file changed

+96
-76
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs

Lines changed: 96 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
5555
return;
5656
}
5757

58-
let mut mapgen = CoverageMapGenerator::new(tcx);
58+
let mut global_file_table = GlobalFileTable::new(tcx);
5959

6060
// Encode coverage mappings and generate function records
6161
let mut function_data = Vec::new();
@@ -68,7 +68,12 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
6868
function_coverage.get_expressions_and_counter_regions();
6969

7070
let coverage_mapping_buffer = llvm::build_byte_buffer(|coverage_mapping_buffer| {
71-
mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer);
71+
write_coverage_mapping(
72+
&mut global_file_table,
73+
expressions,
74+
counter_regions,
75+
coverage_mapping_buffer,
76+
);
7277
});
7378

7479
if coverage_mapping_buffer.is_empty() {
@@ -87,19 +92,14 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
8792
}
8893

8994
// Encode all filenames referenced by counters/expressions in this module
90-
let filenames_buffer = llvm::build_byte_buffer(|filenames_buffer| {
91-
coverageinfo::write_filenames_section_to_buffer(
92-
mapgen.filenames.iter().map(Symbol::as_str),
93-
filenames_buffer,
94-
);
95-
});
95+
let filenames_buffer = global_file_table.into_filenames_buffer();
9696

9797
let filenames_size = filenames_buffer.len();
9898
let filenames_val = cx.const_bytes(&filenames_buffer);
9999
let filenames_ref = coverageinfo::hash_bytes(&filenames_buffer);
100100

101101
// Generate the LLVM IR representation of the coverage map and store it in a well-known global
102-
let cov_data_val = mapgen.generate_coverage_map(cx, version, filenames_size, filenames_val);
102+
let cov_data_val = generate_coverage_map(cx, version, filenames_size, filenames_val);
103103

104104
let covfun_section_name = coverageinfo::covfun_section_name(cx);
105105
for (mangled_function_name, source_hash, is_used, coverage_mapping_buffer) in function_data {
@@ -118,13 +118,13 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
118118
coverageinfo::save_cov_data_to_mod(cx, cov_data_val);
119119
}
120120

121-
struct CoverageMapGenerator {
122-
filenames: FxIndexSet<Symbol>,
121+
struct GlobalFileTable {
122+
global_file_table: FxIndexSet<Symbol>,
123123
}
124124

125-
impl CoverageMapGenerator {
125+
impl GlobalFileTable {
126126
fn new(tcx: TyCtxt<'_>) -> Self {
127-
let mut filenames = FxIndexSet::default();
127+
let mut global_file_table = FxIndexSet::default();
128128
// LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
129129
// requires setting the first filename to the compilation directory.
130130
// Since rustc generates coverage maps with relative paths, the
@@ -133,48 +133,67 @@ impl CoverageMapGenerator {
133133
let working_dir = Symbol::intern(
134134
&tcx.sess.opts.working_dir.remapped_path_if_available().to_string_lossy(),
135135
);
136-
filenames.insert(working_dir);
137-
Self { filenames }
136+
global_file_table.insert(working_dir);
137+
Self { global_file_table }
138138
}
139139

140-
/// Using the `expressions` and `counter_regions` collected for the current function, generate
141-
/// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use
142-
/// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into
143-
/// the given `coverage_mapping` byte buffer, compliant with the LLVM Coverage Mapping format.
144-
fn write_coverage_mapping<'a>(
145-
&mut self,
146-
expressions: Vec<CounterExpression>,
147-
counter_regions: impl Iterator<Item = (Counter, &'a CodeRegion)>,
148-
coverage_mapping_buffer: &RustString,
149-
) {
150-
let mut counter_regions = counter_regions.collect::<Vec<_>>();
151-
if counter_regions.is_empty() {
152-
return;
153-
}
140+
fn global_file_id_for_file_name(&mut self, file_name: Symbol) -> u32 {
141+
let (global_file_id, _) = self.global_file_table.insert_full(file_name);
142+
global_file_id as u32
143+
}
144+
145+
fn into_filenames_buffer(self) -> Vec<u8> {
146+
// This method takes `self` so that the caller can't accidentally
147+
// modify the original file table after encoding it into a buffer.
148+
149+
llvm::build_byte_buffer(|buffer| {
150+
coverageinfo::write_filenames_section_to_buffer(
151+
self.global_file_table.iter().map(Symbol::as_str),
152+
buffer,
153+
);
154+
})
155+
}
156+
}
157+
158+
/// Using the `expressions` and `counter_regions` collected for the current function, generate
159+
/// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use
160+
/// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into
161+
/// the given `coverage_mapping` byte buffer, compliant with the LLVM Coverage Mapping format.
162+
fn write_coverage_mapping<'a>(
163+
global_file_table: &mut GlobalFileTable,
164+
expressions: Vec<CounterExpression>,
165+
counter_regions: impl Iterator<Item = (Counter, &'a CodeRegion)>,
166+
coverage_mapping_buffer: &RustString,
167+
) {
168+
let mut counter_regions = counter_regions.collect::<Vec<_>>();
169+
if counter_regions.is_empty() {
170+
return;
171+
}
154172

155-
let mut virtual_file_mapping = Vec::new();
156-
let mut mapping_regions = Vec::new();
157-
let mut current_file_name = None;
158-
let mut current_file_id = 0;
159-
160-
// Convert the list of (Counter, CodeRegion) pairs to an array of `CounterMappingRegion`, sorted
161-
// by filename and position. Capture any new files to compute the `CounterMappingRegion`s
162-
// `file_id` (indexing files referenced by the current function), and construct the
163-
// function-specific `virtual_file_mapping` from `file_id` to its index in the module's
164-
// `filenames` array.
165-
counter_regions.sort_unstable_by_key(|(_counter, region)| *region);
166-
for (counter, region) in counter_regions {
167-
let CodeRegion { file_name, start_line, start_col, end_line, end_col } = *region;
168-
let same_file = current_file_name.is_some_and(|p| p == file_name);
169-
if !same_file {
170-
if current_file_name.is_some() {
171-
current_file_id += 1;
172-
}
173-
current_file_name = Some(file_name);
174-
debug!(" file_id: {} = '{:?}'", current_file_id, file_name);
175-
let (filenames_index, _) = self.filenames.insert_full(file_name);
176-
virtual_file_mapping.push(filenames_index as u32);
173+
let mut virtual_file_mapping = Vec::new();
174+
let mut mapping_regions = Vec::new();
175+
let mut current_file_name = None;
176+
let mut current_file_id = 0;
177+
178+
// Convert the list of (Counter, CodeRegion) pairs to an array of `CounterMappingRegion`, sorted
179+
// by filename and position. Capture any new files to compute the `CounterMappingRegion`s
180+
// `file_id` (indexing files referenced by the current function), and construct the
181+
// function-specific `virtual_file_mapping` from `file_id` to its index in the module's
182+
// `filenames` array.
183+
counter_regions.sort_unstable_by_key(|(_counter, region)| *region);
184+
for (counter, region) in counter_regions {
185+
let CodeRegion { file_name, start_line, start_col, end_line, end_col } = *region;
186+
let same_file = current_file_name.is_some_and(|p| p == file_name);
187+
if !same_file {
188+
if current_file_name.is_some() {
189+
current_file_id += 1;
177190
}
191+
current_file_name = Some(file_name);
192+
debug!(" file_id: {} = '{:?}'", current_file_id, file_name);
193+
let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
194+
virtual_file_mapping.push(global_file_id);
195+
}
196+
{
178197
debug!("Adding counter {:?} to map for {:?}", counter, region);
179198
mapping_regions.push(CounterMappingRegion::code_region(
180199
counter,
@@ -185,7 +204,9 @@ impl CoverageMapGenerator {
185204
end_col,
186205
));
187206
}
207+
}
188208

209+
{
189210
// Encode and append the current function's coverage mapping data
190211
coverageinfo::write_mapping_to_buffer(
191212
virtual_file_mapping,
@@ -194,33 +215,32 @@ impl CoverageMapGenerator {
194215
coverage_mapping_buffer,
195216
);
196217
}
218+
}
197219

198-
/// Construct coverage map header and the array of function records, and combine them into the
199-
/// coverage map. Save the coverage map data into the LLVM IR as a static global using a
200-
/// specific, well-known section and name.
201-
fn generate_coverage_map<'ll>(
202-
self,
203-
cx: &CodegenCx<'ll, '_>,
204-
version: u32,
205-
filenames_size: usize,
206-
filenames_val: &'ll llvm::Value,
207-
) -> &'ll llvm::Value {
208-
debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
209-
210-
// Create the coverage data header (Note, fields 0 and 2 are now always zero,
211-
// as of `llvm::coverage::CovMapVersion::Version4`.)
212-
let zero_was_n_records_val = cx.const_u32(0);
213-
let filenames_size_val = cx.const_u32(filenames_size as u32);
214-
let zero_was_coverage_size_val = cx.const_u32(0);
215-
let version_val = cx.const_u32(version);
216-
let cov_data_header_val = cx.const_struct(
217-
&[zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val],
218-
/*packed=*/ false,
219-
);
220+
/// Construct coverage map header and the array of function records, and combine them into the
221+
/// coverage map. Save the coverage map data into the LLVM IR as a static global using a
222+
/// specific, well-known section and name.
223+
fn generate_coverage_map<'ll>(
224+
cx: &CodegenCx<'ll, '_>,
225+
version: u32,
226+
filenames_size: usize,
227+
filenames_val: &'ll llvm::Value,
228+
) -> &'ll llvm::Value {
229+
debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
230+
231+
// Create the coverage data header (Note, fields 0 and 2 are now always zero,
232+
// as of `llvm::coverage::CovMapVersion::Version4`.)
233+
let zero_was_n_records_val = cx.const_u32(0);
234+
let filenames_size_val = cx.const_u32(filenames_size as u32);
235+
let zero_was_coverage_size_val = cx.const_u32(0);
236+
let version_val = cx.const_u32(version);
237+
let cov_data_header_val = cx.const_struct(
238+
&[zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val],
239+
/*packed=*/ false,
240+
);
220241

221-
// Create the complete LLVM coverage data value to add to the LLVM IR
222-
cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false)
223-
}
242+
// Create the complete LLVM coverage data value to add to the LLVM IR
243+
cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false)
224244
}
225245

226246
/// Construct a function record and combine it with the function's coverage mapping data.

0 commit comments

Comments
 (0)