Skip to content

Commit 21a0d20

Browse files
committed
coverage: Discard spans for BCBs that are guaranteed to panic/diverge
1 parent 12c79dc commit 21a0d20

21 files changed

+264
-290
lines changed

compiler/rustc_mir_transform/src/coverage/graph.rs

+46-9
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ impl CoverageGraph {
5656

5757
this.dominators = Some(dominators::dominators(&this));
5858

59+
// Initialize the `must_diverge` flag for each BCB. Post-order traversal
60+
// ensures that each node's successors have been processed first.
61+
for bcb in graph::iterate::post_order_from(&this, this.start_node()) {
62+
let terminator = mir_body[this[bcb].last_bb()].terminator();
63+
64+
// A BCB is assumed to always diverge if its terminator is not a
65+
// return, and all of its successors always diverge.
66+
let must_diverge = !bcb_filtered_successors(terminator).has_return_arc()
67+
&& this.successors[bcb].iter().all(|&s| this[s].must_diverge);
68+
this[bcb].must_diverge = must_diverge;
69+
}
70+
5971
// The coverage graph's entry-point node (bcb0) always starts with bb0,
6072
// which never has predecessors. Any other blocks merged into bcb0 can't
6173
// have multiple (coverage-relevant) predecessors, so bcb0 always has
@@ -273,13 +285,15 @@ rustc_index::newtype_index! {
273285
/// significance.
274286
#[derive(Debug, Clone)]
275287
pub(super) struct BasicCoverageBlockData {
288+
pub(super) must_diverge: bool,
276289
pub basic_blocks: Vec<BasicBlock>,
277290
}
278291

279292
impl BasicCoverageBlockData {
280293
pub fn from(basic_blocks: Vec<BasicBlock>) -> Self {
281294
assert!(basic_blocks.len() > 0);
282-
Self { basic_blocks }
295+
// `must_diverge` is set by a separate postprocessing step.
296+
Self { must_diverge: false, basic_blocks }
283297
}
284298

285299
#[inline(always)]
@@ -302,14 +316,23 @@ enum CoverageSuccessors<'a> {
302316
/// potentially be combined into the same BCB as that successor.
303317
Chainable(BasicBlock),
304318
/// The block cannot be combined into the same BCB as its successor(s).
305-
NotChainable(&'a [BasicBlock]),
319+
NotChainable { has_return_arc: bool, successors: &'a [BasicBlock] },
306320
}
307321

308322
impl CoverageSuccessors<'_> {
309323
fn is_chainable(&self) -> bool {
310324
match self {
311325
Self::Chainable(_) => true,
312-
Self::NotChainable(_) => false,
326+
Self::NotChainable { .. } => false,
327+
}
328+
}
329+
330+
/// If true, the block's terminator can return, so it should not be
331+
/// assumed to diverge even if all of its successors diverge.
332+
fn has_return_arc(&self) -> bool {
333+
match *self {
334+
Self::Chainable(_) => false,
335+
Self::NotChainable { has_return_arc, .. } => has_return_arc,
313336
}
314337
}
315338
}
@@ -321,7 +344,9 @@ impl IntoIterator for CoverageSuccessors<'_> {
321344
fn into_iter(self) -> Self::IntoIter {
322345
match self {
323346
Self::Chainable(bb) => Some(bb).into_iter().chain((&[]).iter().copied()),
324-
Self::NotChainable(bbs) => None.into_iter().chain(bbs.iter().copied()),
347+
Self::NotChainable { successors, .. } => {
348+
None.into_iter().chain(successors.iter().copied())
349+
}
325350
}
326351
}
327352
}
@@ -335,11 +360,17 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera
335360
match terminator.kind {
336361
// A switch terminator can have many coverage-relevant successors.
337362
// (If there is exactly one successor, we still treat it as not chainable.)
338-
SwitchInt { ref targets, .. } => CoverageSuccessors::NotChainable(targets.all_targets()),
363+
SwitchInt { ref targets, .. } => CoverageSuccessors::NotChainable {
364+
has_return_arc: false,
365+
successors: targets.all_targets(),
366+
},
339367

340368
// A yield terminator has exactly 1 successor, but should not be chained,
341369
// because its resume edge has a different execution count.
342-
Yield { ref resume, .. } => CoverageSuccessors::NotChainable(std::slice::from_ref(resume)),
370+
Yield { ref resume, .. } => CoverageSuccessors::NotChainable {
371+
has_return_arc: true,
372+
successors: std::slice::from_ref(resume),
373+
},
343374

344375
// These terminators have exactly one coverage-relevant successor,
345376
// and can be chained into it.
@@ -354,13 +385,19 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera
354385
Call { target: maybe_target, .. } | InlineAsm { destination: maybe_target, .. } => {
355386
match maybe_target {
356387
Some(target) => CoverageSuccessors::Chainable(target),
357-
None => CoverageSuccessors::NotChainable(&[]),
388+
None => CoverageSuccessors::NotChainable { has_return_arc: false, successors: &[] },
358389
}
359390
}
360391

392+
// These terminators have no actual coverage-relevant successors,
393+
// but they do return from their enclosing function.
394+
CoroutineDrop | Return => {
395+
CoverageSuccessors::NotChainable { has_return_arc: true, successors: &[] }
396+
}
397+
361398
// These terminators have no coverage-relevant successors.
362-
CoroutineDrop | Return | Unreachable | UnwindResume | UnwindTerminate(_) => {
363-
CoverageSuccessors::NotChainable(&[])
399+
Unreachable | UnwindResume | UnwindTerminate(_) => {
400+
CoverageSuccessors::NotChainable { has_return_arc: false, successors: &[] }
364401
}
365402
}
366403
}

compiler/rustc_mir_transform/src/coverage/spans.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,11 @@ impl<'a> CoverageSpansGenerator<'a> {
217217
refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
218218
};
219219

220-
coverage_spans.to_refined_spans()
220+
let mut refined_spans = coverage_spans.to_refined_spans();
221+
222+
// After refinement, discard spans associated with BCBs that must panic/diverge.
223+
refined_spans.retain(|covspan| !basic_coverage_blocks[covspan.bcb].must_diverge);
224+
refined_spans
221225
}
222226

223227
/// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and

tests/coverage/abort.cov-map

+3-4
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,13 @@ Number of file 0 mappings: 13
4444
- Code(Counter(3)) at (prev + 2, 5) to (start + 1, 2)
4545

4646
Function name: abort::might_abort
47-
Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 01, 14, 05, 02, 09, 01, 24, 02, 02, 0c, 03, 02]
47+
Raw bytes (16): 0x[01, 01, 01, 01, 05, 02, 01, 04, 01, 01, 14, 02, 04, 0c, 03, 02]
4848
Number of files: 1
4949
- file 0 => global file 1
5050
Number of expressions: 1
5151
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
52-
Number of file 0 mappings: 3
52+
Number of file 0 mappings: 2
5353
- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20)
54-
- Code(Counter(1)) at (prev + 2, 9) to (start + 1, 36)
55-
- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2)
54+
- Code(Expression(0, Sub)) at (prev + 4, 12) to (start + 3, 2)
5655
= (c0 - c1)
5756

tests/coverage/abort.coverage

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
LL| |
44
LL| 12|extern "C" fn might_abort(should_abort: bool) {
55
LL| 12| if should_abort {
6-
LL| 0| println!("aborting...");
7-
LL| 0| panic!("panics and aborts");
6+
LL| | println!("aborting...");
7+
LL| | panic!("panics and aborts");
88
LL| 12| } else {
99
LL| 12| println!("Don't Panic");
1010
LL| 12| }

tests/coverage/assert.cov-map

+4-7
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,11 @@ Number of file 0 mappings: 9
2727
- Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2)
2828

2929
Function name: assert::might_fail_assert
30-
Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 02, 0f, 02, 02, 25, 00, 3d, 05, 01, 01, 00, 02]
30+
Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 01, 02, 0f, 05, 03, 01, 00, 02]
3131
Number of files: 1
3232
- file 0 => global file 1
33-
Number of expressions: 1
34-
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
35-
Number of file 0 mappings: 3
33+
Number of expressions: 0
34+
Number of file 0 mappings: 2
3635
- Code(Counter(0)) at (prev + 4, 1) to (start + 2, 15)
37-
- Code(Expression(0, Sub)) at (prev + 2, 37) to (start + 0, 61)
38-
= (c0 - c1)
39-
- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
36+
- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2)
4037

tests/coverage/assert.coverage

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
LL| 4|fn might_fail_assert(one_plus_one: u32) {
55
LL| 4| println!("does 1 + 1 = {}?", one_plus_one);
66
LL| 4| assert_eq!(1 + 1, one_plus_one, "the argument was wrong");
7-
^1
87
LL| 3|}
98
LL| |
109
LL| 1|fn main() -> Result<(), u8> {

tests/coverage/bad_counter_ids.cov-map

+13-19
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,13 @@ Number of file 0 mappings: 2
2424
- Code(Zero) at (prev + 3, 1) to (start + 0, 2)
2525

2626
Function name: bad_counter_ids::eq_bad_message
27-
Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 28, 01, 02, 0f, 02, 02, 20, 00, 2b, 00, 01, 01, 00, 02]
27+
Raw bytes (14): 0x[01, 01, 00, 02, 01, 28, 01, 02, 0f, 00, 03, 01, 00, 02]
2828
Number of files: 1
2929
- file 0 => global file 1
30-
Number of expressions: 1
31-
- expression 0 operands: lhs = Counter(0), rhs = Zero
32-
Number of file 0 mappings: 3
30+
Number of expressions: 0
31+
Number of file 0 mappings: 2
3332
- Code(Counter(0)) at (prev + 40, 1) to (start + 2, 15)
34-
- Code(Expression(0, Sub)) at (prev + 2, 32) to (start + 0, 43)
35-
= (c0 - Zero)
36-
- Code(Zero) at (prev + 1, 1) to (start + 0, 2)
33+
- Code(Zero) at (prev + 3, 1) to (start + 0, 2)
3734

3835
Function name: bad_counter_ids::eq_good
3936
Raw bytes (14): 0x[01, 01, 00, 02, 01, 0f, 01, 02, 1f, 05, 03, 01, 00, 02]
@@ -45,14 +42,13 @@ Number of file 0 mappings: 2
4542
- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2)
4643

4744
Function name: bad_counter_ids::eq_good_message
48-
Raw bytes (19): 0x[01, 01, 00, 03, 01, 14, 01, 02, 0f, 00, 02, 20, 00, 2b, 05, 01, 01, 00, 02]
45+
Raw bytes (14): 0x[01, 01, 00, 02, 01, 14, 01, 02, 0f, 05, 03, 01, 00, 02]
4946
Number of files: 1
5047
- file 0 => global file 1
5148
Number of expressions: 0
52-
Number of file 0 mappings: 3
49+
Number of file 0 mappings: 2
5350
- Code(Counter(0)) at (prev + 20, 1) to (start + 2, 15)
54-
- Code(Zero) at (prev + 2, 32) to (start + 0, 43)
55-
- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
51+
- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2)
5652

5753
Function name: bad_counter_ids::ne_bad
5854
Raw bytes (14): 0x[01, 01, 00, 02, 01, 2d, 01, 02, 1f, 00, 03, 01, 00, 02]
@@ -64,14 +60,13 @@ Number of file 0 mappings: 2
6460
- Code(Zero) at (prev + 3, 1) to (start + 0, 2)
6561

6662
Function name: bad_counter_ids::ne_bad_message
67-
Raw bytes (19): 0x[01, 01, 00, 03, 01, 32, 01, 02, 0f, 05, 02, 20, 00, 2b, 00, 01, 01, 00, 02]
63+
Raw bytes (14): 0x[01, 01, 00, 02, 01, 32, 01, 02, 0f, 00, 03, 01, 00, 02]
6864
Number of files: 1
6965
- file 0 => global file 1
7066
Number of expressions: 0
71-
Number of file 0 mappings: 3
67+
Number of file 0 mappings: 2
7268
- Code(Counter(0)) at (prev + 50, 1) to (start + 2, 15)
73-
- Code(Counter(1)) at (prev + 2, 32) to (start + 0, 43)
74-
- Code(Zero) at (prev + 1, 1) to (start + 0, 2)
69+
- Code(Zero) at (prev + 3, 1) to (start + 0, 2)
7570

7671
Function name: bad_counter_ids::ne_good
7772
Raw bytes (16): 0x[01, 01, 01, 01, 00, 02, 01, 19, 01, 02, 1f, 02, 03, 01, 00, 02]
@@ -85,14 +80,13 @@ Number of file 0 mappings: 2
8580
= (c0 - Zero)
8681

8782
Function name: bad_counter_ids::ne_good_message
88-
Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 1e, 01, 02, 0f, 00, 02, 20, 00, 2b, 02, 01, 01, 00, 02]
83+
Raw bytes (16): 0x[01, 01, 01, 01, 00, 02, 01, 1e, 01, 02, 0f, 02, 03, 01, 00, 02]
8984
Number of files: 1
9085
- file 0 => global file 1
9186
Number of expressions: 1
9287
- expression 0 operands: lhs = Counter(0), rhs = Zero
93-
Number of file 0 mappings: 3
88+
Number of file 0 mappings: 2
9489
- Code(Counter(0)) at (prev + 30, 1) to (start + 2, 15)
95-
- Code(Zero) at (prev + 2, 32) to (start + 0, 43)
96-
- Code(Expression(0, Sub)) at (prev + 1, 1) to (start + 0, 2)
90+
- Code(Expression(0, Sub)) at (prev + 3, 1) to (start + 0, 2)
9791
= (c0 - Zero)
9892

tests/coverage/bad_counter_ids.coverage

-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
LL| 1|fn eq_good_message() {
2121
LL| 1| println!("b");
2222
LL| 1| assert_eq!(Foo(1), Foo(1), "message b");
23-
^0
2423
LL| 1|}
2524
LL| |
2625
LL| 1|fn ne_good() {
@@ -31,7 +30,6 @@
3130
LL| 1|fn ne_good_message() {
3231
LL| 1| println!("d");
3332
LL| 1| assert_ne!(Foo(1), Foo(3), "message d");
34-
^0
3533
LL| 1|}
3634
LL| |
3735
LL| 1|fn eq_bad() {

tests/coverage/coroutine.cov-map

+10-23
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,20 @@ Number of file 0 mappings: 4
1414
= (c1 + (c0 - c1))
1515

1616
Function name: coroutine::main
17-
Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 0f, 01, 02, 16, 01, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02]
17+
Raw bytes (41): 0x[01, 01, 01, 09, 0d, 07, 01, 0f, 01, 02, 16, 01, 07, 0b, 00, 2e, 09, 01, 2b, 00, 2d, 09, 03, 0b, 00, 2e, 02, 01, 22, 00, 27, 11, 00, 2c, 00, 2e, 11, 03, 01, 00, 02]
1818
Number of files: 1
1919
- file 0 => global file 1
20-
Number of expressions: 8
21-
- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3)
22-
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
23-
- expression 2 operands: lhs = Counter(4), rhs = Counter(5)
24-
- expression 3 operands: lhs = Expression(7, Sub), rhs = Counter(6)
25-
- expression 4 operands: lhs = Counter(4), rhs = Counter(5)
26-
- expression 5 operands: lhs = Counter(5), rhs = Counter(6)
27-
- expression 6 operands: lhs = Expression(7, Sub), rhs = Counter(6)
28-
- expression 7 operands: lhs = Counter(4), rhs = Counter(5)
29-
Number of file 0 mappings: 9
20+
Number of expressions: 1
21+
- expression 0 operands: lhs = Counter(2), rhs = Counter(3)
22+
Number of file 0 mappings: 7
3023
- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 22)
3124
- Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46)
32-
- Code(Counter(4)) at (prev + 1, 43) to (start + 0, 45)
33-
- Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 53)
34-
= ((c1 + c2) + c3)
35-
- Code(Counter(4)) at (prev + 2, 11) to (start + 0, 46)
36-
- Code(Expression(7, Sub)) at (prev + 1, 34) to (start + 0, 39)
37-
= (c4 - c5)
38-
- Code(Expression(6, Sub)) at (prev + 0, 44) to (start + 0, 46)
39-
= ((c4 - c5) - c6)
40-
- Code(Expression(5, Add)) at (prev + 1, 14) to (start + 0, 53)
41-
= (c5 + c6)
42-
- Code(Expression(6, Sub)) at (prev + 2, 1) to (start + 0, 2)
43-
= ((c4 - c5) - c6)
25+
- Code(Counter(2)) at (prev + 1, 43) to (start + 0, 45)
26+
- Code(Counter(2)) at (prev + 3, 11) to (start + 0, 46)
27+
- Code(Expression(0, Sub)) at (prev + 1, 34) to (start + 0, 39)
28+
= (c2 - c3)
29+
- Code(Counter(4)) at (prev + 0, 44) to (start + 0, 46)
30+
- Code(Counter(4)) at (prev + 3, 1) to (start + 0, 2)
4431

4532
Function name: coroutine::main::{closure#0}
4633
Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 1c, 01, 1f, 05, 02, 10, 01, 06]

tests/coverage/coroutine.coverage

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@
2222
LL| |
2323
LL| 1| match Pin::new(&mut coroutine).resume(()) {
2424
LL| 1| CoroutineState::Yielded(Ok(1)) => {}
25-
LL| 0| _ => panic!("unexpected return from resume"),
25+
LL| | _ => panic!("unexpected return from resume"),
2626
LL| | }
2727
LL| 1| match Pin::new(&mut coroutine).resume(()) {
2828
LL| 1| CoroutineState::Complete("foo") => {}
29-
LL| 0| _ => panic!("unexpected return from resume"),
29+
LL| | _ => panic!("unexpected return from resume"),
3030
LL| | }
3131
LL| 1|}
3232

tests/coverage/inline.cov-map

-8
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,6 @@ Number of file 0 mappings: 5
1414
- Code(Expression(1, Sub)) at (prev + 3, 5) to (start + 1, 2)
1515
= ((c0 + c1) - c1)
1616

17-
Function name: inline::error
18-
Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 01, 14]
19-
Number of files: 1
20-
- file 0 => global file 1
21-
Number of expressions: 0
22-
Number of file 0 mappings: 1
23-
- Code(Counter(0)) at (prev + 49, 1) to (start + 1, 20)
24-
2517
Function name: inline::length::<char>
2618
Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 01, 02, 02]
2719
Number of files: 1

tests/coverage/inline.coverage

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
LL| 6|}
4949
LL| |
5050
LL| |#[inline(always)]
51-
LL| 0|fn error() {
52-
LL| 0| panic!("error");
51+
LL| |fn error() {
52+
LL| | panic!("error");
5353
LL| |}
5454

0 commit comments

Comments
 (0)