@@ -12,8 +12,10 @@ use rustc_index::IndexVec;
1212use rustc_middle::mir::coverage::MappingKind;
1313use rustc_middle::ty::{self, TyCtxt};
1414use rustc_middle::{bug, mir};
15- use rustc_span::Symbol;
15+ use rustc_session::RemapFileNameExt;
16+ use rustc_session::config::RemapPathScopeComponents;
1617use rustc_span::def_id::DefIdSet;
18+ use rustc_span::{Span, Symbol};
1719use rustc_target::spec::HasTargetSpec;
1820use tracing::debug;
1921
@@ -70,8 +72,10 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
7072 .map(|(instance, function_coverage)| (instance, function_coverage.into_finished()))
7173 .collect::<Vec<_>>();
7274
73- let all_file_names =
74- function_coverage_entries.iter().flat_map(|(_, fn_cov)| fn_cov.all_file_names());
75+ let all_file_names = function_coverage_entries
76+ .iter()
77+ .map(|(_, fn_cov)| fn_cov.function_coverage_info.body_span)
78+ .map(|span| span_file_name(tcx, span));
7579 let global_file_table = GlobalFileTable::new(all_file_names);
7680
7781 // Encode all filenames referenced by coverage mappings in this CGU.
@@ -96,7 +100,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
96100 let is_used = function_coverage.is_used();
97101
98102 let coverage_mapping_buffer =
99- encode_mappings_for_function(&global_file_table, &function_coverage);
103+ encode_mappings_for_function(tcx, &global_file_table, &function_coverage);
100104
101105 if coverage_mapping_buffer.is_empty() {
102106 if function_coverage.is_used() {
@@ -164,13 +168,13 @@ impl GlobalFileTable {
164168 Self { raw_file_table }
165169 }
166170
167- fn global_file_id_for_file_name(&self, file_name: Symbol) -> u32 {
171+ fn global_file_id_for_file_name(&self, file_name: Symbol) -> GlobalFileId {
168172 let raw_id = self.raw_file_table.get_index_of(&file_name).unwrap_or_else(|| {
169173 bug!("file name not found in prepared global file table: {file_name}");
170174 });
171175 // The raw file table doesn't include an entry for the working dir
172176 // (which has ID 0), so add 1 to get the correct ID.
173- (raw_id + 1) as u32
177+ GlobalFileId::from_usize (raw_id + 1)
174178 }
175179
176180 fn make_filenames_buffer(&self, tcx: TyCtxt<'_>) -> Vec<u8> {
@@ -196,36 +200,54 @@ impl GlobalFileTable {
196200}
197201
198202rustc_index::newtype_index! {
199- struct LocalFileId {}
203+ /// An index into the CGU's overall list of file paths. The underlying paths
204+ /// will be embedded in the `__llvm_covmap` linker section.
205+ struct GlobalFileId {}
206+ }
207+ rustc_index::newtype_index! {
208+ /// An index into a function's list of global file IDs. That underlying list
209+ /// of local-to-global mappings will be embedded in the function's record in
210+ /// the `__llvm_covfun` linker section.
211+ pub(crate) struct LocalFileId {}
200212}
201213
202214/// Holds a mapping from "local" (per-function) file IDs to "global" (per-CGU)
203215/// file IDs.
204216#[derive(Default)]
205217struct VirtualFileMapping {
206- local_to_global: IndexVec<LocalFileId, u32 >,
207- global_to_local: FxIndexMap<u32 , LocalFileId>,
218+ local_to_global: IndexVec<LocalFileId, GlobalFileId >,
219+ global_to_local: FxIndexMap<GlobalFileId , LocalFileId>,
208220}
209221
210222impl VirtualFileMapping {
211- fn local_id_for_global(&mut self, global_file_id: u32 ) -> LocalFileId {
223+ fn local_id_for_global(&mut self, global_file_id: GlobalFileId ) -> LocalFileId {
212224 *self
213225 .global_to_local
214226 .entry(global_file_id)
215227 .or_insert_with(|| self.local_to_global.push(global_file_id))
216228 }
217229
218230 fn into_vec(self) -> Vec<u32> {
219- self.local_to_global.raw
231+ // This conversion should be optimized away to ~zero overhead.
232+ // In any case, it's probably not hot enough to worry about.
233+ self.local_to_global.into_iter().map(|global| global.as_u32()).collect()
220234 }
221235}
222236
237+ fn span_file_name(tcx: TyCtxt<'_>, span: Span) -> Symbol {
238+ let source_file = tcx.sess.source_map().lookup_source_file(span.lo());
239+ let name =
240+ source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy();
241+ Symbol::intern(&name)
242+ }
243+
223244/// Using the expressions and counter regions collected for a single function,
224245/// generate the variable-sized payload of its corresponding `__llvm_covfun`
225246/// entry. The payload is returned as a vector of bytes.
226247///
227248/// Newly-encountered filenames will be added to the global file table.
228249fn encode_mappings_for_function(
250+ tcx: TyCtxt<'_>,
229251 global_file_table: &GlobalFileTable,
230252 function_coverage: &FunctionCoverage<'_>,
231253) -> Vec<u8> {
@@ -242,53 +264,45 @@ fn encode_mappings_for_function(
242264 let mut mcdc_branch_regions = vec![];
243265 let mut mcdc_decision_regions = vec![];
244266
245- // Group mappings into runs with the same filename, preserving the order
246- // yielded by `FunctionCoverage`.
247- // Prepare file IDs for each filename, and prepare the mapping data so that
248- // we can pass it through FFI to LLVM.
249- for (file_name, counter_regions_for_file) in
250- &counter_regions.group_by(|(_, region)| region.file_name)
251- {
252- // Look up the global file ID for this filename.
253- let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
254-
255- // Associate that global file ID with a local file ID for this function.
256- let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id);
257- debug!(" file id: {local_file_id:?} => global {global_file_id} = '{file_name:?}'");
258-
259- // For each counter/region pair in this function+file, convert it to a
260- // form suitable for FFI.
261- for (mapping_kind, region) in counter_regions_for_file {
262- debug!("Adding counter {mapping_kind:?} to map for {region:?}");
263- let span = ffi::CoverageSpan::from_source_region(local_file_id.as_u32(), region);
264- match mapping_kind {
265- MappingKind::Code(term) => {
266- code_regions
267- .push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) });
268- }
269- MappingKind::Branch { true_term, false_term } => {
270- branch_regions.push(ffi::BranchRegion {
271- span,
272- true_counter: ffi::Counter::from_term(true_term),
273- false_counter: ffi::Counter::from_term(false_term),
274- });
275- }
276- MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
277- mcdc_branch_regions.push(ffi::MCDCBranchRegion {
278- span,
279- true_counter: ffi::Counter::from_term(true_term),
280- false_counter: ffi::Counter::from_term(false_term),
281- mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
282- });
283- }
284- MappingKind::MCDCDecision(mcdc_decision_params) => {
285- mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
286- span,
287- mcdc_decision_params: ffi::mcdc::DecisionParameters::from(
288- mcdc_decision_params,
289- ),
290- });
291- }
267+ // Currently a function's mappings must all be in the same file as its body span.
268+ let file_name = span_file_name(tcx, function_coverage.function_coverage_info.body_span);
269+
270+ // Look up the global file ID for that filename.
271+ let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
272+
273+ // Associate that global file ID with a local file ID for this function.
274+ let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id);
275+ debug!(" file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'");
276+
277+ // For each counter/region pair in this function+file, convert it to a
278+ // form suitable for FFI.
279+ for (mapping_kind, region) in counter_regions {
280+ debug!("Adding counter {mapping_kind:?} to map for {region:?}");
281+ let span = ffi::CoverageSpan::from_source_region(local_file_id, region);
282+ match mapping_kind {
283+ MappingKind::Code(term) => {
284+ code_regions.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) });
285+ }
286+ MappingKind::Branch { true_term, false_term } => {
287+ branch_regions.push(ffi::BranchRegion {
288+ span,
289+ true_counter: ffi::Counter::from_term(true_term),
290+ false_counter: ffi::Counter::from_term(false_term),
291+ });
292+ }
293+ MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
294+ mcdc_branch_regions.push(ffi::MCDCBranchRegion {
295+ span,
296+ true_counter: ffi::Counter::from_term(true_term),
297+ false_counter: ffi::Counter::from_term(false_term),
298+ mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
299+ });
300+ }
301+ MappingKind::MCDCDecision(mcdc_decision_params) => {
302+ mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
303+ span,
304+ mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params),
305+ });
292306 }
293307 }
294308 }
0 commit comments