Skip to content

Commit fb6dd05

Browse files
committed
coverage: Emit branch mappings
1 parent bb03d42 commit fb6dd05

File tree

5 files changed

+123
-9
lines changed

5 files changed

+123
-9
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs

+25-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use rustc_data_structures::captures::Captures;
44
use rustc_data_structures::fx::FxIndexSet;
55
use rustc_index::bit_set::BitSet;
66
use rustc_middle::mir::coverage::{
7-
CodeRegion, CounterId, CovTerm, Expression, ExpressionId, FunctionCoverageInfo, Mapping, Op,
7+
BranchMapping, CodeRegion, CounterId, CovTerm, Expression, ExpressionId, FunctionCoverageInfo,
8+
Mapping, Op,
89
};
910
use rustc_middle::ty::Instance;
1011
use rustc_span::Symbol;
@@ -192,7 +193,18 @@ impl<'tcx> FunctionCoverage<'tcx> {
192193

193194
/// Returns an iterator over all filenames used by this function's mappings.
194195
pub(crate) fn all_file_names(&self) -> impl Iterator<Item = Symbol> + Captures<'_> {
195-
self.function_coverage_info.mappings.iter().map(|mapping| mapping.code_region.file_name)
196+
let mapping_file_names = self
197+
.function_coverage_info
198+
.mappings
199+
.iter()
200+
.map(|mapping| mapping.code_region.file_name);
201+
let branch_mapping_file_names = self
202+
.function_coverage_info
203+
.branch_mappings
204+
.iter()
205+
.map(|branch_mapping| branch_mapping.code_region.file_name);
206+
207+
mapping_file_names.chain(branch_mapping_file_names)
196208
}
197209

198210
/// Convert this function's coverage expression data into a form that can be
@@ -229,6 +241,17 @@ impl<'tcx> FunctionCoverage<'tcx> {
229241
})
230242
}
231243

244+
pub(crate) fn branch_regions(&self) -> impl Iterator<Item = (&CodeRegion, Counter, Counter)> {
245+
self.function_coverage_info.branch_mappings.iter().map(move |branch_mapping| {
246+
let &BranchMapping { ref code_region, true_arm_term, false_arm_term } = branch_mapping;
247+
(
248+
code_region,
249+
self.counter_for_term(true_arm_term),
250+
self.counter_for_term(false_arm_term),
251+
)
252+
})
253+
}
254+
232255
fn counter_for_term(&self, term: CovTerm) -> Counter {
233256
if is_zero_term(&self.counters_seen, &self.zero_expressions, term) {
234257
Counter::ZERO

compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs

+17
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,23 @@ fn encode_mappings_for_function(
263263
}
264264
}
265265

266+
for (region, true_counter, false_counter) in function_coverage.branch_regions() {
267+
let CodeRegion { file_name, start_line, start_col, end_line, end_col } = *region;
268+
269+
let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
270+
let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id);
271+
272+
mapping_regions.push(CounterMappingRegion::branch_region(
273+
true_counter,
274+
false_counter,
275+
local_file_id.as_u32(),
276+
start_line,
277+
start_col,
278+
end_line,
279+
end_col,
280+
));
281+
}
282+
266283
// Encode the function's coverage mappings into a buffer.
267284
llvm::build_byte_buffer(|buffer| {
268285
coverageinfo::write_mapping_to_buffer(

compiler/rustc_middle/src/mir/coverage.rs

+10
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,15 @@ pub struct Mapping {
173173
pub term: CovTerm,
174174
}
175175

176+
#[derive(Clone, Debug)]
177+
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
178+
pub struct BranchMapping {
179+
pub code_region: CodeRegion,
180+
181+
pub true_arm_term: CovTerm,
182+
pub false_arm_term: CovTerm,
183+
}
184+
176185
/// Stores per-function coverage information attached to a `mir::Body`,
177186
/// to be used in conjunction with the individual coverage statements injected
178187
/// into the function's basic blocks.
@@ -184,6 +193,7 @@ pub struct FunctionCoverageInfo {
184193

185194
pub expressions: IndexVec<ExpressionId, Expression>,
186195
pub mappings: Vec<Mapping>,
196+
pub branch_mappings: Vec<BranchMapping>,
187197
}
188198

189199
/// Coverage information captured from HIR/THIR during MIR building.

compiler/rustc_mir_transform/src/coverage/mod.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mod tests;
99

1010
use self::counters::{BcbCounter, CoverageCounters};
1111
use self::graph::CoverageGraph;
12-
use self::spans::CoverageSpans;
12+
use self::spans::{BcbBranchSpan, CoverageSpans};
1313

1414
use crate::MirPass;
1515

@@ -124,13 +124,15 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
124124
self.coverage_counters
125125
.make_bcb_counters(&self.basic_coverage_blocks, bcb_has_coverage_spans);
126126

127-
let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans);
127+
let (mappings, branch_mappings) =
128+
self.create_mappings_and_inject_coverage_statements(&coverage_spans);
128129

129130
self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
130131
function_source_hash: self.function_source_hash,
131132
num_counters: self.coverage_counters.num_counters(),
132133
expressions: self.coverage_counters.take_expressions(),
133134
mappings,
135+
branch_mappings,
134136
}));
135137
}
136138

@@ -140,7 +142,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
140142
fn create_mappings_and_inject_coverage_statements(
141143
&mut self,
142144
coverage_spans: &CoverageSpans,
143-
) -> Vec<Mapping> {
145+
) -> (Vec<Mapping>, Vec<BranchMapping>) {
144146
let source_map = self.tcx.sess.source_map();
145147
let body_span = self.body_span;
146148

@@ -210,7 +212,17 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
210212
inject_statement(self.mir_body, self.make_mir_coverage_kind(counter_kind), new_bb);
211213
}
212214

213-
mappings
215+
let branch_mappings = coverage_spans
216+
.branch_spans()
217+
.iter()
218+
.map(|&BcbBranchSpan { span, true_bcb, false_bcb }| BranchMapping {
219+
code_region: make_code_region(source_map, file_name, span, body_span),
220+
true_arm_term: self.coverage_counters.bcb_counter(true_bcb).unwrap().as_term(),
221+
false_arm_term: self.coverage_counters.bcb_counter(false_bcb).unwrap().as_term(),
222+
})
223+
.collect::<Vec<_>>();
224+
225+
(mappings, branch_mappings)
214226
}
215227

216228
fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind {

compiler/rustc_mir_transform/src/coverage/spans.rs

+55-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
11
use std::cell::OnceCell;
22

33
use rustc_data_structures::graph::WithNumNodes;
4+
use rustc_index::bit_set::BitSet;
45
use rustc_index::IndexVec;
5-
use rustc_middle::mir;
6+
use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind};
7+
use rustc_middle::mir::{self, BasicBlock, StatementKind};
68
use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP};
79

810
use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
911

1012
mod from_mir;
1113

14+
pub(super) struct BcbBranchSpan {
15+
pub(super) span: Span,
16+
pub(super) true_bcb: BasicCoverageBlock,
17+
pub(super) false_bcb: BasicCoverageBlock,
18+
}
19+
1220
pub(super) struct CoverageSpans {
1321
/// Map from BCBs to their list of coverage spans.
1422
bcb_to_spans: IndexVec<BasicCoverageBlock, Vec<Span>>,
23+
24+
bcbs_with_branch_spans: BitSet<BasicCoverageBlock>,
25+
branch_spans: Vec<BcbBranchSpan>,
1526
}
1627

1728
impl CoverageSpans {
@@ -34,16 +45,57 @@ impl CoverageSpans {
3445
bcb_to_spans[bcb].push(span);
3546
}
3647

37-
Self { bcb_to_spans }
48+
let mut bcbs_with_branch_spans = BitSet::new_empty(basic_coverage_blocks.num_nodes());
49+
let mut branch_spans = Vec::new();
50+
51+
if let Some(coverage_hir_info) = mir_body.coverage_hir_info.as_deref() {
52+
let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n(
53+
None,
54+
coverage_hir_info.num_block_markers,
55+
);
56+
57+
for (bb, data) in mir_body.basic_blocks.iter_enumerated() {
58+
for statement in &data.statements {
59+
if let StatementKind::Coverage(coverage) = &statement.kind {
60+
if let CoverageKind::BlockMarker { id } = coverage.kind {
61+
block_markers[id] = Some(bb);
62+
}
63+
}
64+
}
65+
}
66+
67+
// Assume that most branch spans will resolve successfully.
68+
branch_spans.reserve(coverage_hir_info.branch_spans.len());
69+
branch_spans.extend(coverage_hir_info.branch_spans.iter().filter_map(
70+
|&BranchSpan { span, true_marker, false_marker }| {
71+
let bcb_from_marker = |marker: BlockMarkerId| {
72+
Some(basic_coverage_blocks.bcb_from_bb(block_markers[marker]?)?)
73+
};
74+
75+
let true_bcb = bcb_from_marker(true_marker)?;
76+
let false_bcb = bcb_from_marker(false_marker)?;
77+
78+
bcbs_with_branch_spans.insert(true_bcb);
79+
bcbs_with_branch_spans.insert(false_bcb);
80+
Some(BcbBranchSpan { span, true_bcb, false_bcb })
81+
},
82+
));
83+
}
84+
85+
Self { bcb_to_spans, bcbs_with_branch_spans, branch_spans }
3886
}
3987

4088
pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool {
41-
!self.bcb_to_spans[bcb].is_empty()
89+
!self.bcb_to_spans[bcb].is_empty() || self.bcbs_with_branch_spans.contains(bcb)
4290
}
4391

4492
pub(super) fn spans_for_bcb(&self, bcb: BasicCoverageBlock) -> &[Span] {
4593
&self.bcb_to_spans[bcb]
4694
}
95+
96+
pub(super) fn branch_spans(&self) -> &[BcbBranchSpan] {
97+
&self.branch_spans
98+
}
4799
}
48100

49101
/// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that

0 commit comments

Comments
 (0)