Skip to content

Commit 325bbc7

Browse files
committed
coverage: Emit branch mappings
1 parent 077c95c commit 325bbc7

File tree

6 files changed

+140
-10
lines changed

6 files changed

+140
-10
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

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
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;
56
use rustc_middle::mir;
67
use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP};
@@ -9,9 +10,18 @@ use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
910

1011
mod from_mir;
1112

13+
pub(super) struct BcbBranchSpan {
14+
pub(super) span: Span,
15+
pub(super) true_bcb: BasicCoverageBlock,
16+
pub(super) false_bcb: BasicCoverageBlock,
17+
}
18+
1219
pub(super) struct CoverageSpans {
1320
/// Map from BCBs to their list of coverage spans.
1421
bcb_to_spans: IndexVec<BasicCoverageBlock, Vec<Span>>,
22+
23+
bcbs_with_branch_spans: BitSet<BasicCoverageBlock>,
24+
branch_spans: Vec<BcbBranchSpan>,
1525
}
1626

1727
impl CoverageSpans {
@@ -34,16 +44,23 @@ impl CoverageSpans {
3444
bcb_to_spans[bcb].push(span);
3545
}
3646

37-
Self { bcb_to_spans }
47+
let (bcbs_with_branch_spans, branch_spans) =
48+
from_mir::extract_branch_spans(mir_body, body_span, basic_coverage_blocks);
49+
50+
Self { bcb_to_spans, bcbs_with_branch_spans, branch_spans }
3851
}
3952

4053
pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool {
41-
!self.bcb_to_spans[bcb].is_empty()
54+
!self.bcb_to_spans[bcb].is_empty() || self.bcbs_with_branch_spans.contains(bcb)
4255
}
4356

4457
pub(super) fn spans_for_bcb(&self, bcb: BasicCoverageBlock) -> &[Span] {
4558
&self.bcb_to_spans[bcb]
4659
}
60+
61+
pub(super) fn branch_spans(&self) -> &[BcbBranchSpan] {
62+
&self.branch_spans
63+
}
4764
}
4865

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

compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs

+53-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
use rustc_data_structures::captures::Captures;
2+
use rustc_data_structures::graph::WithNumNodes;
3+
use rustc_index::bit_set::BitSet;
4+
use rustc_index::IndexVec;
5+
use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind};
26
use rustc_middle::mir::{
3-
self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
7+
self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
48
TerminatorKind,
59
};
610
use rustc_span::Span;
711

812
use crate::coverage::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
9-
use crate::coverage::spans::CoverageSpan;
13+
use crate::coverage::spans::{BcbBranchSpan, CoverageSpan};
1014

1115
pub(super) fn mir_to_initial_sorted_coverage_spans(
1216
mir_body: &mir::Body<'_>,
@@ -191,3 +195,50 @@ fn function_source_span(span: Span, body_span: Span) -> Option<Span> {
191195
let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
192196
body_span.contains(original_span).then_some(original_span)
193197
}
198+
199+
pub(super) fn extract_branch_spans(
200+
mir_body: &mir::Body<'_>,
201+
body_span: Span,
202+
basic_coverage_blocks: &CoverageGraph,
203+
) -> (BitSet<BasicCoverageBlock>, Vec<BcbBranchSpan>) {
204+
let mut bcbs_with_branch_spans = BitSet::new_empty(basic_coverage_blocks.num_nodes());
205+
let mut branch_spans = Vec::new();
206+
207+
if let Some(coverage_hir_info) = mir_body.coverage_hir_info.as_deref() {
208+
let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n(
209+
None,
210+
coverage_hir_info.num_block_markers,
211+
);
212+
213+
for (bb, data) in mir_body.basic_blocks.iter_enumerated() {
214+
for statement in &data.statements {
215+
if let StatementKind::Coverage(coverage) = &statement.kind {
216+
if let CoverageKind::BlockMarker { id } = coverage.kind {
217+
block_markers[id] = Some(bb);
218+
}
219+
}
220+
}
221+
}
222+
223+
// Assume that most branch spans will resolve successfully.
224+
branch_spans.reserve(coverage_hir_info.branch_spans.len());
225+
branch_spans.extend(coverage_hir_info.branch_spans.iter().filter_map(
226+
|&BranchSpan { span: raw_span, true_marker, false_marker }| {
227+
let span = function_source_span(raw_span, body_span)?;
228+
229+
let bcb_from_marker = |marker: BlockMarkerId| {
230+
Some(basic_coverage_blocks.bcb_from_bb(block_markers[marker]?)?)
231+
};
232+
233+
let true_bcb = bcb_from_marker(true_marker)?;
234+
let false_bcb = bcb_from_marker(false_marker)?;
235+
236+
bcbs_with_branch_spans.insert(true_bcb);
237+
bcbs_with_branch_spans.insert(false_bcb);
238+
Some(BcbBranchSpan { span, true_bcb, false_bcb })
239+
},
240+
));
241+
}
242+
243+
(bcbs_with_branch_spans, branch_spans)
244+
}

0 commit comments

Comments
 (0)