88
99use rustc_data_structures:: graph;
1010use rustc_index:: bit_set:: DenseBitSet ;
11- use rustc_index:: { Idx , IndexVec } ;
11+ use rustc_index:: { Idx , IndexSlice , IndexVec } ;
1212use rustc_middle:: mir:: coverage:: Op ;
1313
1414use crate :: coverage:: counters:: iter_nodes:: IterNodes ;
@@ -17,8 +17,8 @@ use crate::coverage::counters::union_find::UnionFind;
1717#[ cfg( test) ]
1818mod tests;
1919
20- /// View of some underlying graph, in which each node's successors have been
21- /// merged into a single "supernode".
20+ /// Data representing a view of some underlying graph, in which each node's
21+ /// successors have been merged into a single "supernode".
2222///
2323/// The resulting supernodes have no obvious meaning on their own.
2424/// However, merging successor nodes means that a node's out-edges can all
@@ -29,7 +29,7 @@ mod tests;
2929/// in the merged graph, it becomes possible to analyze the original node flows
3030/// using techniques for analyzing edge flows.
3131#[ derive( Debug ) ]
32- pub ( crate ) struct MergedNodeFlowGraph < Node : Idx > {
32+ pub ( crate ) struct NodeFlowData < Node : Idx > {
3333 /// Maps each node to the supernode that contains it, indicated by some
3434 /// arbitrary "root" node that is part of that supernode.
3535 supernodes : IndexVec < Node , Node > ,
@@ -41,66 +41,59 @@ pub(crate) struct MergedNodeFlowGraph<Node: Idx> {
4141 succ_supernodes : IndexVec < Node , Node > ,
4242}
4343
44- impl < Node : Idx > MergedNodeFlowGraph < Node > {
45- /// Creates a "merged" view of an underlying graph.
46- ///
47- /// The given graph is assumed to have [“balanced flow”](balanced-flow),
48- /// though it does not necessarily have to be a `BalancedFlowGraph`.
49- ///
50- /// [balanced-flow]: `crate::coverage::counters::balanced_flow::BalancedFlowGraph`.
51- pub ( crate ) fn for_balanced_graph < G > ( graph : G ) -> Self
52- where
53- G : graph:: DirectedGraph < Node = Node > + graph:: Successors ,
54- {
55- let mut supernodes = UnionFind :: < G :: Node > :: new ( graph. num_nodes ( ) ) ;
56-
57- // For each node, merge its successors into a single supernode, and
58- // arbitrarily choose one of those successors to represent all of them.
59- let successors = graph
60- . iter_nodes ( )
61- . map ( |node| {
62- graph
63- . successors ( node)
64- . reduce ( |a, b| supernodes. unify ( a, b) )
65- . expect ( "each node in a balanced graph must have at least one out-edge" )
66- } )
67- . collect :: < IndexVec < G :: Node , G :: Node > > ( ) ;
68-
69- // Now that unification is complete, take a snapshot of the supernode forest,
70- // and resolve each arbitrarily-chosen successor to its canonical root.
71- // (This avoids having to explicitly resolve them later.)
72- let supernodes = supernodes. snapshot ( ) ;
73- let succ_supernodes = successors. into_iter ( ) . map ( |succ| supernodes[ succ] ) . collect ( ) ;
74-
75- Self { supernodes, succ_supernodes }
76- }
77-
78- fn num_nodes ( & self ) -> usize {
79- self . succ_supernodes . len ( )
80- }
44+ /// Creates a "merged" view of an underlying graph.
45+ ///
46+ /// The given graph is assumed to have [“balanced flow”](balanced-flow),
47+ /// though it does not necessarily have to be a `BalancedFlowGraph`.
48+ ///
49+ /// [balanced-flow]: `crate::coverage::counters::balanced_flow::BalancedFlowGraph`.
50+ pub ( crate ) fn node_flow_data_for_balanced_graph < G > ( graph : G ) -> NodeFlowData < G :: Node >
51+ where
52+ G : graph:: Successors ,
53+ {
54+ let mut supernodes = UnionFind :: < G :: Node > :: new ( graph. num_nodes ( ) ) ;
55+
56+ // For each node, merge its successors into a single supernode, and
57+ // arbitrarily choose one of those successors to represent all of them.
58+ let successors = graph
59+ . iter_nodes ( )
60+ . map ( |node| {
61+ graph
62+ . successors ( node)
63+ . reduce ( |a, b| supernodes. unify ( a, b) )
64+ . expect ( "each node in a balanced graph must have at least one out-edge" )
65+ } )
66+ . collect :: < IndexVec < G :: Node , G :: Node > > ( ) ;
67+
68+ // Now that unification is complete, take a snapshot of the supernode forest,
69+ // and resolve each arbitrarily-chosen successor to its canonical root.
70+ // (This avoids having to explicitly resolve them later.)
71+ let supernodes = supernodes. snapshot ( ) ;
72+ let succ_supernodes = successors. into_iter ( ) . map ( |succ| supernodes[ succ] ) . collect ( ) ;
73+
74+ NodeFlowData { supernodes, succ_supernodes }
75+ }
8176
82- fn is_supernode ( & self , node : Node ) -> bool {
83- self . supernodes [ node] == node
77+ /// Uses the graph information in `node_flow_data`, together with a given
78+ /// permutation of all nodes in the graph, to create physical counters and
79+ /// counter expressions for each node in the underlying graph.
80+ ///
81+ /// The given list must contain exactly one copy of each node in the
82+ /// underlying balanced-flow graph. The order of nodes is used as a hint to
83+ /// influence counter allocation:
84+ /// - Earlier nodes are more likely to receive counter expressions.
85+ /// - Later nodes are more likely to receive physical counters.
86+ pub ( crate ) fn make_node_counters < Node : Idx > (
87+ node_flow_data : & NodeFlowData < Node > ,
88+ priority_list : & [ Node ] ,
89+ ) -> NodeCounters < Node > {
90+ let mut builder = SpantreeBuilder :: new ( node_flow_data) ;
91+
92+ for & node in priority_list {
93+ builder. visit_node ( node) ;
8494 }
8595
86- /// Using the information in this merged graph, together with a given
87- /// permutation of all nodes in the graph, to create physical counters and
88- /// counter expressions for each node in the underlying graph.
89- ///
90- /// The given list must contain exactly one copy of each node in the
91- /// underlying balanced-flow graph. The order of nodes is used as a hint to
92- /// influence counter allocation:
93- /// - Earlier nodes are more likely to receive counter expressions.
94- /// - Later nodes are more likely to receive physical counters.
95- pub ( crate ) fn make_node_counters ( & self , all_nodes_permutation : & [ Node ] ) -> NodeCounters < Node > {
96- let mut builder = SpantreeBuilder :: new ( self ) ;
97-
98- for & node in all_nodes_permutation {
99- builder. visit_node ( node) ;
100- }
101-
102- NodeCounters { counter_terms : builder. finish ( ) }
103- }
96+ NodeCounters { counter_terms : builder. finish ( ) }
10497}
10598
10699/// End result of allocating physical counters and counter expressions for the
@@ -141,7 +134,9 @@ pub(crate) struct CounterTerm<Node> {
141134
142135#[ derive( Debug ) ]
143136struct SpantreeBuilder < ' a , Node : Idx > {
144- graph : & ' a MergedNodeFlowGraph < Node > ,
137+ supernodes : & ' a IndexSlice < Node , Node > ,
138+ succ_supernodes : & ' a IndexSlice < Node , Node > ,
139+
145140 is_unvisited : DenseBitSet < Node > ,
146141 /// Links supernodes to each other, gradually forming a spanning tree of
147142 /// the merged-flow graph.
@@ -157,22 +152,28 @@ struct SpantreeBuilder<'a, Node: Idx> {
157152}
158153
159154impl < ' a , Node : Idx > SpantreeBuilder < ' a , Node > {
160- fn new ( graph : & ' a MergedNodeFlowGraph < Node > ) -> Self {
161- let num_nodes = graph. num_nodes ( ) ;
155+ fn new ( node_flow_data : & ' a NodeFlowData < Node > ) -> Self {
156+ let NodeFlowData { supernodes, succ_supernodes } = node_flow_data;
157+ let num_nodes = supernodes. len ( ) ;
162158 Self {
163- graph,
159+ supernodes,
160+ succ_supernodes,
164161 is_unvisited : DenseBitSet :: new_filled ( num_nodes) ,
165162 span_edges : IndexVec :: from_fn_n ( |_| None , num_nodes) ,
166163 yank_buffer : vec ! [ ] ,
167164 counter_terms : IndexVec :: from_fn_n ( |_| vec ! [ ] , num_nodes) ,
168165 }
169166 }
170167
168+ fn is_supernode ( & self , node : Node ) -> bool {
169+ self . supernodes [ node] == node
170+ }
171+
171172 /// Given a supernode, finds the supernode that is the "root" of its
172173 /// spantree component. Two nodes that have the same spantree root are
173174 /// connected in the spantree.
174175 fn spantree_root ( & self , this : Node ) -> Node {
175- debug_assert ! ( self . graph . is_supernode( this) ) ;
176+ debug_assert ! ( self . is_supernode( this) ) ;
176177
177178 match self . span_edges [ this] {
178179 None => this,
@@ -183,7 +184,7 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
183184 /// Rotates edges in the spantree so that `this` is the root of its
184185 /// spantree component.
185186 fn yank_to_spantree_root ( & mut self , this : Node ) {
186- debug_assert ! ( self . graph . is_supernode( this) ) ;
187+ debug_assert ! ( self . is_supernode( this) ) ;
187188
188189 // The rotation is done iteratively, by first traversing from `this` to
189190 // its root and storing the path in a buffer, and then traversing the
@@ -225,12 +226,12 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
225226
226227 // Get the supernode containing `this`, and make it the root of its
227228 // component of the spantree.
228- let this_supernode = self . graph . supernodes [ this] ;
229+ let this_supernode = self . supernodes [ this] ;
229230 self . yank_to_spantree_root ( this_supernode) ;
230231
231232 // Get the supernode containing all of this's successors.
232- let succ_supernode = self . graph . succ_supernodes [ this] ;
233- debug_assert ! ( self . graph . is_supernode( succ_supernode) ) ;
233+ let succ_supernode = self . succ_supernodes [ this] ;
234+ debug_assert ! ( self . is_supernode( succ_supernode) ) ;
234235
235236 // If two supernodes are already connected in the spantree, they will
236237 // have the same spantree root. (Each supernode is connected to itself.)
@@ -279,18 +280,19 @@ impl<'a, Node: Idx> SpantreeBuilder<'a, Node> {
279280 /// Asserts that all nodes have been visited, and returns the computed
280281 /// counter expressions (made up of physical counters) for each node.
281282 fn finish ( self ) -> IndexVec < Node , Vec < CounterTerm < Node > > > {
282- let Self { graph , is_unvisited , span_edges, yank_buffer : _ , counter_terms } = self ;
283+ let Self { ref span_edges, ref is_unvisited , ref counter_terms, .. } = self ;
283284 assert ! ( is_unvisited. is_empty( ) , "some nodes were never visited: {is_unvisited:?}" ) ;
284285 debug_assert ! (
285286 span_edges
286287 . iter_enumerated( )
287- . all( |( node, span_edge) | { span_edge. is_some( ) <= graph . is_supernode( node) } ) ,
288+ . all( |( node, span_edge) | { span_edge. is_some( ) <= self . is_supernode( node) } ) ,
288289 "only supernodes can have a span edge" ,
289290 ) ;
290291 debug_assert ! (
291292 counter_terms. iter( ) . all( |terms| !terms. is_empty( ) ) ,
292293 "after visiting all nodes, every node should have at least one term" ,
293294 ) ;
294- counter_terms
295+
296+ self . counter_terms
295297 }
296298}
0 commit comments