Skip to content

Commit ffafc9e

Browse files
committed
Output Branch Regions from Coverage Instrumentation
1 parent 4152c4d commit ffafc9e

File tree

5 files changed

+79
-13
lines changed

5 files changed

+79
-13
lines changed

compiler/rustc_mir_transform/src/coverage/counters.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,31 @@ impl CoverageCounters {
6969
&mut self,
7070
basic_coverage_blocks: &CoverageGraph,
7171
coverage_spans: &[CoverageSpan],
72-
) -> Result<(), Error> {
73-
MakeBcbCounters::new(self, basic_coverage_blocks).make_bcb_counters(coverage_spans)
72+
) -> Result<Vec<(BasicCoverageBlock, CoverageKind)>, Error> {
73+
let mut make_counters = MakeBcbCounters::new(self, basic_coverage_blocks);
74+
make_counters.make_bcb_counters(coverage_spans)?;
75+
76+
let branches: Vec<_> = basic_coverage_blocks
77+
.iter_enumerated()
78+
.filter_map(|(bcb, _data)| {
79+
let branches = make_counters.bcb_branches(bcb);
80+
if branches.len() != 2 {
81+
return None;
82+
}
83+
let mut branch_counters =
84+
branches.iter().filter_map(|branch| make_counters.branch_counter(branch));
85+
86+
// FIXME(swatinem): figure out what the correct ordering here is?
87+
// In simple testing, the `false` (aka `0`) branch of `SwitchInt` seems to be first.
88+
let false_ = branch_counters.next()?.as_operand();
89+
let true_ = branch_counters.next()?.as_operand();
90+
91+
let branch = CoverageKind::Branch { true_, false_ };
92+
Some((bcb, branch))
93+
})
94+
.collect();
95+
96+
Ok(branches)
7497
}
7598

7699
fn make_counter<F>(&mut self, debug_block_label_fn: F) -> CoverageKind

compiler/rustc_mir_transform/src/coverage/mod.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,11 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
202202
//
203203
// Intermediate expressions (used to compute other `Expression` values), which have no
204204
// direct association with any `BasicCoverageBlock`, are accumulated inside `coverage_counters`.
205-
let result = self
205+
let mut result = self
206206
.coverage_counters
207207
.make_bcb_counters(&mut self.basic_coverage_blocks, &coverage_spans);
208208

209-
if let Ok(()) = result {
209+
if let Ok(branches) = result.as_mut() {
210210
// If debugging, add any intermediate expressions (which are not associated with any
211211
// BCB) to the `debug_used_expressions` map.
212212
if debug_used_expressions.is_enabled() {
@@ -231,6 +231,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
231231
&mut debug_used_expressions,
232232
);
233233

234+
self.inject_branch_counters(std::mem::take(branches));
235+
234236
////////////////////////////////////////////////////
235237
// For any remaining `BasicCoverageBlock` counters (that were not associated with
236238
// any `CoverageSpan`), inject `Coverage` statements (_without_ code region `Span`s)
@@ -275,6 +277,27 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
275277
}
276278
}
277279

280+
fn inject_branch_counters(&mut self, branches: Vec<(BasicCoverageBlock, CoverageKind)>) {
281+
let tcx = self.tcx;
282+
let source_map = tcx.sess.source_map();
283+
let body_span = self.body_span;
284+
let file_name = Symbol::intern(&self.source_file.name.prefer_remapped().to_string_lossy());
285+
286+
for branch in branches {
287+
let bcb_data = self.bcb_data(branch.0);
288+
let terminator = bcb_data.terminator(self.mir_body);
289+
290+
let span = terminator.source_info.span;
291+
292+
// FIXME(swatinem): figure out what a good span for the conditional is.
293+
// For trivial code examples, the `terminator` seems to be sufficient.
294+
let code_region =
295+
Some(make_code_region(source_map, file_name, &self.source_file, span, body_span));
296+
297+
inject_statement(self.mir_body, branch.1, bcb_data.last_bb(), code_region);
298+
}
299+
}
300+
278301
/// Inject a counter for each `CoverageSpan`. There can be multiple `CoverageSpan`s for a given
279302
/// BCB, but only one actual counter needs to be incremented per BCB. `bb_counters` maps each
280303
/// `bcb` to its `Counter`, when injected. Subsequent `CoverageSpan`s for a BCB that already has

compiler/rustc_mir_transform/src/coverage/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ fn test_make_bcb_counters() {
676676
}
677677
}
678678
let mut coverage_counters = counters::CoverageCounters::new(0, &basic_coverage_blocks);
679-
let () = coverage_counters
679+
let _ = coverage_counters
680680
.make_bcb_counters(&mut basic_coverage_blocks, &coverage_spans)
681681
.expect("should be Ok");
682682
assert_eq!(coverage_counters.intermediate_expressions.len(), 0);

src/tools/compiletest/src/runtest.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use crate::ColorConfig;
1818
use regex::{Captures, Regex};
1919
use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
2020

21-
use std::borrow::Cow;
2221
use std::collections::hash_map::DefaultHasher;
2322
use std::collections::{HashMap, HashSet};
2423
use std::env;
@@ -564,7 +563,12 @@ impl<'test> TestCx<'test> {
564563

565564
// Run `llvm-cov show` to produce a coverage report in text format.
566565
let proc_res = self.run_llvm_tool("llvm-cov", |cmd| {
567-
cmd.args(["show", "--format=text", "--show-line-counts-or-regions"]);
566+
cmd.args([
567+
"show",
568+
"--format=text",
569+
"--show-line-counts-or-regions",
570+
"--show-branches=count",
571+
]);
568572

569573
cmd.arg("--Xdemangler");
570574
cmd.arg(self.config.rust_demangler_path.as_ref().unwrap());
@@ -723,7 +727,7 @@ impl<'test> TestCx<'test> {
723727

724728
/// Replace line numbers in coverage reports with the placeholder `LL`,
725729
/// so that the tests are less sensitive to lines being added/removed.
726-
fn anonymize_coverage_line_numbers(coverage: &str) -> Cow<'_, str> {
730+
fn anonymize_coverage_line_numbers(line: &str) -> String {
727731
// The coverage reporter prints line numbers at the start of a line.
728732
// They are truncated or left-padded to occupy exactly 5 columns.
729733
// (`LineNumberColumnWidth` in `SourceCoverageViewText.cpp`.)
@@ -733,7 +737,10 @@ impl<'test> TestCx<'test> {
733737
// have an additional prefix of ` |` for each nesting level.
734738
static LINE_NUMBER_RE: Lazy<Regex> =
735739
Lazy::new(|| Regex::new(r"(?m:^)(?<prefix>(?: \|)*) *[0-9]+\|").unwrap());
736-
LINE_NUMBER_RE.replace_all(coverage, "$prefix LL|")
740+
static BRANCH_LINE_RE: Lazy<Regex> =
741+
Lazy::new(|| Regex::new(r"(?m:^)(?<prefix>(?: \|)*) Branch \([0-9]+:").unwrap());
742+
let line = LINE_NUMBER_RE.replace_all(line, "$prefix LL|");
743+
BRANCH_LINE_RE.replace_all(&line, "$prefix Branch (LL:").into_owned()
737744
}
738745

739746
/// Coverage reports can describe multiple source files, separated by

src/tools/coverage-dump/src/covfun.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ pub(crate) fn dump_covfun_mappings(
6565
// If the mapping contains expressions, also print the resolved
6666
// form of those expressions
6767
kind.for_each_operand(|label, operand| {
68-
if matches!(operand, Operand::Expression { .. }) {
68+
if matches!(operand, Operand::Expression { .. })
69+
|| matches!(kind, MappingKind::Branch { .. })
70+
{
6971
let pad = if label.is_empty() { "" } else { " " };
7072
let resolved = expression_resolver.format_operand(operand);
7173
println!(" {label}{pad}= {resolved}");
@@ -207,7 +209,6 @@ impl Operand {
207209
}
208210
}
209211

210-
#[derive(Debug)]
211212
enum MappingKind {
212213
Code(Operand),
213214
Gap(Operand),
@@ -216,6 +217,18 @@ enum MappingKind {
216217
Branch { true_: Operand, false_: Operand },
217218
}
218219

220+
impl Debug for MappingKind {
221+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222+
match self {
223+
Self::Code(operand) => f.debug_tuple("Code").field(operand).finish(),
224+
Self::Gap(operand) => f.debug_tuple("Gap").field(operand).finish(),
225+
Self::Expansion(expansion) => f.debug_tuple("Expansion").field(expansion).finish(),
226+
Self::Skip => write!(f, "Skip"),
227+
Self::Branch { .. } => f.debug_tuple("Branch").finish(),
228+
}
229+
}
230+
}
231+
219232
impl MappingKind {
220233
/// Visits each operand directly contained in this mapping, along with
221234
/// a string label (possibly empty).
@@ -226,8 +239,8 @@ impl MappingKind {
226239
Self::Expansion(_) => (),
227240
Self::Skip => (),
228241
Self::Branch { true_, false_ } => {
229-
func("true_ ", true_);
230-
func("false_", false_);
242+
func("true ", true_);
243+
func("false", false_);
231244
}
232245
}
233246
}

0 commit comments

Comments
 (0)