1
+ use std:: collections:: BTreeMap ;
2
+ use std:: fmt:: Debug ;
3
+ use std:: mem:: swap;
4
+
1
5
use rustc_hir:: { HirId , HirIdMap } ;
2
6
use rustc_index:: bit_set:: BitSet ;
3
7
use rustc_index:: vec:: IndexVec ;
@@ -20,6 +24,19 @@ rustc_index::newtype_index! {
20
24
pub struct DropRanges {
21
25
hir_id_map : HirIdMap < HirIdIndex > ,
22
26
nodes : IndexVec < PostOrderId , NodeInfo > ,
27
+ deferred_edges : Vec < ( usize , HirId ) > ,
28
+ // FIXME: This should only be used for loops and break/continue.
29
+ post_order_map : HirIdMap < usize > ,
30
+ }
31
+
32
+ impl Debug for DropRanges {
33
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
34
+ f. debug_struct ( "DropRanges" )
35
+ . field ( "hir_id_map" , & self . hir_id_map )
36
+ . field ( "post_order_maps" , & self . post_order_map )
37
+ . field ( "nodes" , & self . nodes . iter_enumerated ( ) . collect :: < BTreeMap < _ , _ > > ( ) )
38
+ . finish ( )
39
+ }
23
40
}
24
41
25
42
/// DropRanges keeps track of what values are definitely dropped at each point in the code.
@@ -29,7 +46,7 @@ pub struct DropRanges {
29
46
/// (hir_id, post_order_id) -> bool, where a true value indicates that the value is definitely
30
47
/// dropped at the point of the node identified by post_order_id.
31
48
impl DropRanges {
32
- pub fn new ( hir_ids : impl Iterator < Item = HirId > , hir : & Map < ' _ > ) -> Self {
49
+ pub fn new ( hir_ids : impl Iterator < Item = HirId > , hir : & Map < ' _ > , num_exprs : usize ) -> Self {
33
50
let mut hir_id_map = HirIdMap :: < HirIdIndex > :: default ( ) ;
34
51
let mut next = <_ >:: from ( 0u32 ) ;
35
52
for hir_id in hir_ids {
@@ -41,7 +58,13 @@ impl DropRanges {
41
58
} ) ;
42
59
}
43
60
debug ! ( "hir_id_map: {:?}" , hir_id_map) ;
44
- Self { hir_id_map, nodes : <_ >:: default ( ) }
61
+ let num_values = hir_id_map. len ( ) ;
62
+ Self {
63
+ hir_id_map,
64
+ nodes : IndexVec :: from_fn_n ( |_| NodeInfo :: new ( num_values) , num_exprs + 1 ) ,
65
+ deferred_edges : <_ >:: default ( ) ,
66
+ post_order_map : <_ >:: default ( ) ,
67
+ }
45
68
}
46
69
47
70
fn hidx ( & self , hir_id : HirId ) -> HirIdIndex {
@@ -52,17 +75,23 @@ impl DropRanges {
52
75
self . hir_id_map
53
76
. get ( & hir_id)
54
77
. copied ( )
55
- . map_or ( false , |hir_id| self . node ( location. into ( ) ) . drop_state . contains ( hir_id) )
78
+ . map_or ( false , |hir_id| self . expect_node ( location. into ( ) ) . drop_state . contains ( hir_id) )
56
79
}
57
80
58
81
/// Returns the number of values (hir_ids) that are tracked
59
82
fn num_values ( & self ) -> usize {
60
83
self . hir_id_map . len ( )
61
84
}
62
85
63
- fn node ( & mut self , id : PostOrderId ) -> & NodeInfo {
64
- let size = self . num_values ( ) ;
65
- self . nodes . ensure_contains_elem ( id, || NodeInfo :: new ( size) ) ;
86
+ /// Adds an entry in the mapping from HirIds to PostOrderIds
87
+ ///
88
+ /// Needed so that `add_control_edge_hir_id` can work.
89
+ pub fn add_node_mapping ( & mut self , hir_id : HirId , post_order_id : usize ) {
90
+ self . post_order_map . insert ( hir_id, post_order_id) ;
91
+ }
92
+
93
+ /// Returns a reference to the NodeInfo for a node, panicking if it does not exist
94
+ fn expect_node ( & self , id : PostOrderId ) -> & NodeInfo {
66
95
& self . nodes [ id]
67
96
}
68
97
@@ -73,9 +102,32 @@ impl DropRanges {
73
102
}
74
103
75
104
pub fn add_control_edge ( & mut self , from : usize , to : usize ) {
105
+ trace ! ( "adding control edge from {} to {}" , from, to) ;
76
106
self . node_mut ( from. into ( ) ) . successors . push ( to. into ( ) ) ;
77
107
}
78
108
109
+ /// Like add_control_edge, but uses a hir_id as the target.
110
+ ///
111
+ /// This can be used for branches where we do not know the PostOrderId of the target yet,
112
+ /// such as when handling `break` or `continue`.
113
+ pub fn add_control_edge_hir_id ( & mut self , from : usize , to : HirId ) {
114
+ self . deferred_edges . push ( ( from, to) ) ;
115
+ }
116
+
117
+ /// Looks up PostOrderId for any control edges added by HirId and adds a proper edge for them.
118
+ ///
119
+ /// Should be called after visiting the HIR but before solving the control flow, otherwise some
120
+ /// edges will be missed.
121
+ fn process_deferred_edges ( & mut self ) {
122
+ let mut edges = vec ! [ ] ;
123
+ swap ( & mut edges, & mut self . deferred_edges ) ;
124
+ edges. into_iter ( ) . for_each ( |( from, to) | {
125
+ let to = * self . post_order_map . get ( & to) . expect ( "Expression ID not found" ) ;
126
+ trace ! ( "Adding deferred edge from {} to {}" , from, to) ;
127
+ self . add_control_edge ( from, to)
128
+ } ) ;
129
+ }
130
+
79
131
pub fn drop_at ( & mut self , value : HirId , location : usize ) {
80
132
let value = self . hidx ( value) ;
81
133
self . node_mut ( location. into ( ) ) . drops . push ( value) ;
@@ -92,40 +144,65 @@ impl DropRanges {
92
144
}
93
145
94
146
pub fn propagate_to_fixpoint ( & mut self ) {
95
- while self . propagate ( ) { }
96
- }
147
+ trace ! ( "before fixpoint: {:#?}" , self ) ;
148
+ self . process_deferred_edges ( ) ;
149
+ let preds = self . compute_predecessors ( ) ;
150
+
151
+ trace ! ( "predecessors: {:#?}" , preds. iter_enumerated( ) . collect:: <BTreeMap <_, _>>( ) ) ;
152
+
153
+ let mut propagate = || {
154
+ let mut changed = false ;
155
+ for id in self . nodes . indices ( ) {
156
+ let old_state = self . nodes [ id] . drop_state . clone ( ) ;
157
+ if preds[ id] . len ( ) != 0 {
158
+ self . nodes [ id] . drop_state = self . nodes [ preds[ id] [ 0 ] ] . drop_state . clone ( ) ;
159
+ for pred in & preds[ id] [ 1 ..] {
160
+ let state = self . nodes [ * pred] . drop_state . clone ( ) ;
161
+ self . nodes [ id] . drop_state . intersect ( & state) ;
162
+ }
163
+ } else {
164
+ self . nodes [ id] . drop_state = if id. index ( ) == 0 {
165
+ BitSet :: new_empty ( self . num_values ( ) )
166
+ } else {
167
+ // If we are not the start node and we have no predecessors, treat
168
+ // everything as dropped because there's no way to get here anyway.
169
+ BitSet :: new_filled ( self . num_values ( ) )
170
+ } ;
171
+ } ;
172
+ for drop in & self . nodes [ id] . drops . clone ( ) {
173
+ self . nodes [ id] . drop_state . insert ( * drop) ;
174
+ }
175
+ for reinit in & self . nodes [ id] . reinits . clone ( ) {
176
+ self . nodes [ id] . drop_state . remove ( * reinit) ;
177
+ }
97
178
98
- fn propagate ( & mut self ) -> bool {
99
- let mut visited = BitSet :: new_empty ( self . nodes . len ( ) ) ;
179
+ changed |= old_state != self . nodes [ id ] . drop_state ;
180
+ }
100
181
101
- self . visit ( & mut visited , PostOrderId :: from ( 0usize ) , PostOrderId :: from ( 0usize ) , false )
102
- }
182
+ changed
183
+ } ;
103
184
104
- fn visit (
105
- & mut self ,
106
- visited : & mut BitSet < PostOrderId > ,
107
- id : PostOrderId ,
108
- pred_id : PostOrderId ,
109
- mut changed : bool ,
110
- ) -> bool {
111
- if visited. contains ( id) {
112
- return changed;
113
- }
114
- visited. insert ( id) ;
185
+ while propagate ( ) { }
115
186
116
- changed &= self . nodes [ id] . merge_with ( & self . nodes [ pred_id] ) ;
187
+ trace ! ( "after fixpoint: {:#?}" , self ) ;
188
+ }
117
189
118
- if self . nodes [ id] . successors . len ( ) == 0 {
119
- self . visit ( visited, PostOrderId :: from ( id. index ( ) + 1 ) , id, changed)
120
- } else {
121
- self . nodes [ id]
122
- . successors
123
- . iter ( )
124
- . fold ( changed, |changed, & succ| self . visit ( visited, succ, id, changed) )
190
+ fn compute_predecessors ( & self ) -> IndexVec < PostOrderId , Vec < PostOrderId > > {
191
+ let mut preds = IndexVec :: from_fn_n ( |_| vec ! [ ] , self . nodes . len ( ) ) ;
192
+ for ( id, node) in self . nodes . iter_enumerated ( ) {
193
+ if node. successors . len ( ) == 0 && id. index ( ) != self . nodes . len ( ) - 1 {
194
+ preds[ <_ >:: from ( id. index ( ) + 1 ) ] . push ( id) ;
195
+ } else {
196
+ for succ in & node. successors {
197
+ preds[ * succ] . push ( id) ;
198
+ }
199
+ }
125
200
}
201
+ preds
126
202
}
127
203
}
128
204
205
+ #[ derive( Debug ) ]
129
206
struct NodeInfo {
130
207
/// IDs of nodes that can follow this one in the control flow
131
208
///
@@ -148,26 +225,7 @@ impl NodeInfo {
148
225
successors : vec ! [ ] ,
149
226
drops : vec ! [ ] ,
150
227
reinits : vec ! [ ] ,
151
- drop_state : BitSet :: new_empty ( num_values) ,
228
+ drop_state : BitSet :: new_filled ( num_values) ,
152
229
}
153
230
}
154
-
155
- fn merge_with ( & mut self , other : & NodeInfo ) -> bool {
156
- let mut changed = false ;
157
- for place in & self . drops {
158
- if !self . drop_state . contains ( place) && !self . reinits . contains ( & place) {
159
- changed = true ;
160
- self . drop_state . insert ( place) ;
161
- }
162
- }
163
-
164
- for place in & self . reinits {
165
- if self . drop_state . contains ( place) {
166
- changed = true ;
167
- self . drop_state . remove ( place) ;
168
- }
169
- }
170
-
171
- changed
172
- }
173
231
}
0 commit comments