Skip to content

Commit d92aa56

Browse files
authored
Rollup merge of rust-lang#126538 - Zalathar:graph, r=nnethercote
coverage: Several small improvements to graph code This PR combines a few small improvements to coverage graph handling code: - Remove some low-value implementation tests that were getting in the way of other changes. - Clean up `pub` visibility. - Flatten some code using let-else. - Prefer `.copied()` over `.cloned()`. `@rustbot` label +A-code-coverage
2 parents d9af579 + e5b43c3 commit d92aa56

File tree

3 files changed

+46
-154
lines changed

3 files changed

+46
-154
lines changed

compiler/rustc_mir_transform/src/coverage/counters.rs

-5
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,6 @@ impl CoverageCounters {
168168
self.counter_increment_sites.len()
169169
}
170170

171-
#[cfg(test)]
172-
pub(super) fn num_expressions(&self) -> usize {
173-
self.expressions.len()
174-
}
175-
176171
fn set_bcb_counter(&mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter) -> BcbCounter {
177172
if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) {
178173
bug!(

compiler/rustc_mir_transform/src/coverage/graph.rs

+46-43
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ use std::ops::{Index, IndexMut};
1414
/// A coverage-specific simplification of the MIR control flow graph (CFG). The `CoverageGraph`s
1515
/// nodes are `BasicCoverageBlock`s, which encompass one or more MIR `BasicBlock`s.
1616
#[derive(Debug)]
17-
pub(super) struct CoverageGraph {
17+
pub(crate) struct CoverageGraph {
1818
bcbs: IndexVec<BasicCoverageBlock, BasicCoverageBlockData>,
1919
bb_to_bcb: IndexVec<BasicBlock, Option<BasicCoverageBlock>>,
20-
pub successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
21-
pub predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
20+
pub(crate) successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
21+
pub(crate) predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
2222
dominators: Option<Dominators<BasicCoverageBlock>>,
2323
}
2424

2525
impl CoverageGraph {
26-
pub fn from_mir(mir_body: &mir::Body<'_>) -> Self {
26+
pub(crate) fn from_mir(mir_body: &mir::Body<'_>) -> Self {
2727
let (bcbs, bb_to_bcb) = Self::compute_basic_coverage_blocks(mir_body);
2828

2929
// Pre-transform MIR `BasicBlock` successors and predecessors into the BasicCoverageBlock
@@ -135,24 +135,28 @@ impl CoverageGraph {
135135
}
136136

137137
#[inline(always)]
138-
pub fn iter_enumerated(
138+
pub(crate) fn iter_enumerated(
139139
&self,
140140
) -> impl Iterator<Item = (BasicCoverageBlock, &BasicCoverageBlockData)> {
141141
self.bcbs.iter_enumerated()
142142
}
143143

144144
#[inline(always)]
145-
pub fn bcb_from_bb(&self, bb: BasicBlock) -> Option<BasicCoverageBlock> {
145+
pub(crate) fn bcb_from_bb(&self, bb: BasicBlock) -> Option<BasicCoverageBlock> {
146146
if bb.index() < self.bb_to_bcb.len() { self.bb_to_bcb[bb] } else { None }
147147
}
148148

149149
#[inline(always)]
150-
pub fn dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool {
150+
pub(crate) fn dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool {
151151
self.dominators.as_ref().unwrap().dominates(dom, node)
152152
}
153153

154154
#[inline(always)]
155-
pub fn cmp_in_dominator_order(&self, a: BasicCoverageBlock, b: BasicCoverageBlock) -> Ordering {
155+
pub(crate) fn cmp_in_dominator_order(
156+
&self,
157+
a: BasicCoverageBlock,
158+
b: BasicCoverageBlock,
159+
) -> Ordering {
156160
self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b)
157161
}
158162

@@ -166,7 +170,7 @@ impl CoverageGraph {
166170
///
167171
/// FIXME: That assumption might not be true for [`TerminatorKind::Yield`]?
168172
#[inline(always)]
169-
pub(super) fn bcb_has_multiple_in_edges(&self, bcb: BasicCoverageBlock) -> bool {
173+
pub(crate) fn bcb_has_multiple_in_edges(&self, bcb: BasicCoverageBlock) -> bool {
170174
// Even though bcb0 conceptually has an extra virtual in-edge due to
171175
// being the entry point, we've already asserted that it has no _other_
172176
// in-edges, so there's no possibility of it having _multiple_ in-edges.
@@ -212,7 +216,7 @@ impl graph::StartNode for CoverageGraph {
212216
impl graph::Successors for CoverageGraph {
213217
#[inline]
214218
fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
215-
self.successors[node].iter().cloned()
219+
self.successors[node].iter().copied()
216220
}
217221
}
218222

@@ -227,7 +231,7 @@ rustc_index::newtype_index! {
227231
/// A node in the control-flow graph of CoverageGraph.
228232
#[orderable]
229233
#[debug_format = "bcb{}"]
230-
pub(super) struct BasicCoverageBlock {
234+
pub(crate) struct BasicCoverageBlock {
231235
const START_BCB = 0;
232236
}
233237
}
@@ -259,23 +263,23 @@ rustc_index::newtype_index! {
259263
/// queries (`dominates()`, `predecessors`, `successors`, etc.) have branch (control flow)
260264
/// significance.
261265
#[derive(Debug, Clone)]
262-
pub(super) struct BasicCoverageBlockData {
263-
pub basic_blocks: Vec<BasicBlock>,
266+
pub(crate) struct BasicCoverageBlockData {
267+
pub(crate) basic_blocks: Vec<BasicBlock>,
264268
}
265269

266270
impl BasicCoverageBlockData {
267-
pub fn from(basic_blocks: Vec<BasicBlock>) -> Self {
271+
fn from(basic_blocks: Vec<BasicBlock>) -> Self {
268272
assert!(basic_blocks.len() > 0);
269273
Self { basic_blocks }
270274
}
271275

272276
#[inline(always)]
273-
pub fn leader_bb(&self) -> BasicBlock {
277+
pub(crate) fn leader_bb(&self) -> BasicBlock {
274278
self.basic_blocks[0]
275279
}
276280

277281
#[inline(always)]
278-
pub fn last_bb(&self) -> BasicBlock {
282+
pub(crate) fn last_bb(&self) -> BasicBlock {
279283
*self.basic_blocks.last().unwrap()
280284
}
281285
}
@@ -364,7 +368,7 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera
364368
/// CoverageGraph outside all loops. This supports traversing the BCB CFG in a way that
365369
/// ensures a loop is completely traversed before processing Blocks after the end of the loop.
366370
#[derive(Debug)]
367-
pub(super) struct TraversalContext {
371+
struct TraversalContext {
368372
/// BCB with one or more incoming loop backedges, indicating which loop
369373
/// this context is for.
370374
///
@@ -375,7 +379,7 @@ pub(super) struct TraversalContext {
375379
worklist: VecDeque<BasicCoverageBlock>,
376380
}
377381

378-
pub(super) struct TraverseCoverageGraphWithLoops<'a> {
382+
pub(crate) struct TraverseCoverageGraphWithLoops<'a> {
379383
basic_coverage_blocks: &'a CoverageGraph,
380384

381385
backedges: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
@@ -384,7 +388,7 @@ pub(super) struct TraverseCoverageGraphWithLoops<'a> {
384388
}
385389

386390
impl<'a> TraverseCoverageGraphWithLoops<'a> {
387-
pub(super) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self {
391+
pub(crate) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self {
388392
let backedges = find_loop_backedges(basic_coverage_blocks);
389393

390394
let worklist = VecDeque::from([basic_coverage_blocks.start_node()]);
@@ -400,47 +404,46 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> {
400404

401405
/// For each loop on the loop context stack (top-down), yields a list of BCBs
402406
/// within that loop that have an outgoing edge back to the loop header.
403-
pub(super) fn reloop_bcbs_per_loop(&self) -> impl Iterator<Item = &[BasicCoverageBlock]> {
407+
pub(crate) fn reloop_bcbs_per_loop(&self) -> impl Iterator<Item = &[BasicCoverageBlock]> {
404408
self.context_stack
405409
.iter()
406410
.rev()
407411
.filter_map(|context| context.loop_header)
408412
.map(|header_bcb| self.backedges[header_bcb].as_slice())
409413
}
410414

411-
pub(super) fn next(&mut self) -> Option<BasicCoverageBlock> {
415+
pub(crate) fn next(&mut self) -> Option<BasicCoverageBlock> {
412416
debug!(
413417
"TraverseCoverageGraphWithLoops::next - context_stack: {:?}",
414418
self.context_stack.iter().rev().collect::<Vec<_>>()
415419
);
416420

417421
while let Some(context) = self.context_stack.last_mut() {
418-
if let Some(bcb) = context.worklist.pop_front() {
419-
if !self.visited.insert(bcb) {
420-
debug!("Already visited: {bcb:?}");
421-
continue;
422-
}
423-
debug!("Visiting {bcb:?}");
424-
425-
if self.backedges[bcb].len() > 0 {
426-
debug!("{bcb:?} is a loop header! Start a new TraversalContext...");
427-
self.context_stack.push(TraversalContext {
428-
loop_header: Some(bcb),
429-
worklist: VecDeque::new(),
430-
});
431-
}
432-
self.add_successors_to_worklists(bcb);
433-
return Some(bcb);
434-
} else {
435-
// Strip contexts with empty worklists from the top of the stack
422+
let Some(bcb) = context.worklist.pop_front() else {
423+
// This stack level is exhausted; pop it and try the next one.
436424
self.context_stack.pop();
425+
continue;
426+
};
427+
428+
if !self.visited.insert(bcb) {
429+
debug!("Already visited: {bcb:?}");
430+
continue;
431+
}
432+
debug!("Visiting {bcb:?}");
433+
434+
if self.backedges[bcb].len() > 0 {
435+
debug!("{bcb:?} is a loop header! Start a new TraversalContext...");
436+
self.context_stack
437+
.push(TraversalContext { loop_header: Some(bcb), worklist: VecDeque::new() });
437438
}
439+
self.add_successors_to_worklists(bcb);
440+
return Some(bcb);
438441
}
439442

440443
None
441444
}
442445

443-
pub fn add_successors_to_worklists(&mut self, bcb: BasicCoverageBlock) {
446+
fn add_successors_to_worklists(&mut self, bcb: BasicCoverageBlock) {
444447
let successors = &self.basic_coverage_blocks.successors[bcb];
445448
debug!("{:?} has {} successors:", bcb, successors.len());
446449

@@ -494,19 +497,19 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> {
494497
}
495498
}
496499

497-
pub fn is_complete(&self) -> bool {
500+
pub(crate) fn is_complete(&self) -> bool {
498501
self.visited.count() == self.visited.domain_size()
499502
}
500503

501-
pub fn unvisited(&self) -> Vec<BasicCoverageBlock> {
504+
pub(crate) fn unvisited(&self) -> Vec<BasicCoverageBlock> {
502505
let mut unvisited_set: BitSet<BasicCoverageBlock> =
503506
BitSet::new_filled(self.visited.domain_size());
504507
unvisited_set.subtract(&self.visited);
505508
unvisited_set.iter().collect::<Vec<_>>()
506509
}
507510
}
508511

509-
pub(super) fn find_loop_backedges(
512+
fn find_loop_backedges(
510513
basic_coverage_blocks: &CoverageGraph,
511514
) -> IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>> {
512515
let num_bcbs = basic_coverage_blocks.num_nodes();

compiler/rustc_mir_transform/src/coverage/tests.rs

-106
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
//! globals is comparatively simpler. The easiest way is to wrap the test in a closure argument
2525
//! to: `rustc_span::create_default_session_globals_then(|| { test_here(); })`.
2626
27-
use super::counters;
2827
use super::graph::{self, BasicCoverageBlock};
2928

3029
use itertools::Itertools;
@@ -551,108 +550,3 @@ fn test_covgraph_switchint_loop_then_inner_loop_else_break() {
551550
assert_successors(&basic_coverage_blocks, bcb(5), &[bcb(1)]);
552551
assert_successors(&basic_coverage_blocks, bcb(6), &[bcb(4)]);
553552
}
554-
555-
#[test]
556-
fn test_find_loop_backedges_none() {
557-
let mir_body = goto_switchint();
558-
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
559-
if false {
560-
eprintln!(
561-
"basic_coverage_blocks = {:?}",
562-
basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
563-
);
564-
eprintln!("successors = {:?}", basic_coverage_blocks.successors);
565-
}
566-
let backedges = graph::find_loop_backedges(&basic_coverage_blocks);
567-
assert_eq!(
568-
backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::<usize>(),
569-
0,
570-
"backedges: {:?}",
571-
backedges
572-
);
573-
}
574-
575-
#[test]
576-
fn test_find_loop_backedges_one() {
577-
let mir_body = switchint_then_loop_else_return();
578-
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
579-
let backedges = graph::find_loop_backedges(&basic_coverage_blocks);
580-
assert_eq!(
581-
backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::<usize>(),
582-
1,
583-
"backedges: {:?}",
584-
backedges
585-
);
586-
587-
assert_eq!(backedges[bcb(1)], &[bcb(3)]);
588-
}
589-
590-
#[test]
591-
fn test_find_loop_backedges_two() {
592-
let mir_body = switchint_loop_then_inner_loop_else_break();
593-
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
594-
let backedges = graph::find_loop_backedges(&basic_coverage_blocks);
595-
assert_eq!(
596-
backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::<usize>(),
597-
2,
598-
"backedges: {:?}",
599-
backedges
600-
);
601-
602-
assert_eq!(backedges[bcb(1)], &[bcb(5)]);
603-
assert_eq!(backedges[bcb(4)], &[bcb(6)]);
604-
}
605-
606-
#[test]
607-
fn test_traverse_coverage_with_loops() {
608-
let mir_body = switchint_loop_then_inner_loop_else_break();
609-
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
610-
let mut traversed_in_order = Vec::new();
611-
let mut traversal = graph::TraverseCoverageGraphWithLoops::new(&basic_coverage_blocks);
612-
while let Some(bcb) = traversal.next() {
613-
traversed_in_order.push(bcb);
614-
}
615-
616-
// bcb0 is visited first. Then bcb1 starts the first loop, and all remaining nodes, *except*
617-
// bcb6 are inside the first loop.
618-
assert_eq!(
619-
*traversed_in_order.last().expect("should have elements"),
620-
bcb(6),
621-
"bcb6 should not be visited until all nodes inside the first loop have been visited"
622-
);
623-
}
624-
625-
#[test]
626-
fn test_make_bcb_counters() {
627-
rustc_span::create_default_session_globals_then(|| {
628-
let mir_body = goto_switchint();
629-
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
630-
// Historically this test would use `spans` internals to set up fake
631-
// coverage spans for BCBs 1 and 2. Now we skip that step and just tell
632-
// BCB counter construction that those BCBs have spans.
633-
let bcb_has_coverage_spans = |bcb: BasicCoverageBlock| (1..=2).contains(&bcb.as_usize());
634-
let coverage_counters = counters::CoverageCounters::make_bcb_counters(
635-
&basic_coverage_blocks,
636-
bcb_has_coverage_spans,
637-
);
638-
assert_eq!(coverage_counters.num_expressions(), 0);
639-
640-
assert_eq!(
641-
0, // bcb1 has a `Counter` with id = 0
642-
match coverage_counters.bcb_counter(bcb(1)).expect("should have a counter") {
643-
counters::BcbCounter::Counter { id, .. } => id,
644-
_ => panic!("expected a Counter"),
645-
}
646-
.as_u32()
647-
);
648-
649-
assert_eq!(
650-
1, // bcb2 has a `Counter` with id = 1
651-
match coverage_counters.bcb_counter(bcb(2)).expect("should have a counter") {
652-
counters::BcbCounter::Counter { id, .. } => id,
653-
_ => panic!("expected a Counter"),
654-
}
655-
.as_u32()
656-
);
657-
});
658-
}

0 commit comments

Comments
 (0)