@@ -104,36 +104,46 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
104
104
/// ```
105
105
///
106
106
/// A Postorder traversal of this graph is `D B C A` or `D C B A`
107
- pub struct Postorder < ' a , ' tcx > {
107
+ pub struct Postorder < ' a , ' tcx , C > {
108
108
basic_blocks : & ' a IndexSlice < BasicBlock , BasicBlockData < ' tcx > > ,
109
109
visited : BitSet < BasicBlock > ,
110
110
visit_stack : Vec < ( BasicBlock , Successors < ' a > ) > ,
111
111
root_is_start_block : bool ,
112
+ extra : C ,
112
113
}
113
114
114
- impl < ' a , ' tcx > Postorder < ' a , ' tcx > {
115
+ impl < ' a , ' tcx , C > Postorder < ' a , ' tcx , C >
116
+ where
117
+ C : Customization < ' tcx > ,
118
+ {
115
119
pub fn new (
116
120
basic_blocks : & ' a IndexSlice < BasicBlock , BasicBlockData < ' tcx > > ,
117
121
root : BasicBlock ,
118
- ) -> Postorder < ' a , ' tcx > {
122
+ extra : C ,
123
+ ) -> Postorder < ' a , ' tcx , C > {
119
124
let mut po = Postorder {
120
125
basic_blocks,
121
126
visited : BitSet :: new_empty ( basic_blocks. len ( ) ) ,
122
127
visit_stack : Vec :: new ( ) ,
123
128
root_is_start_block : root == START_BLOCK ,
129
+ extra,
124
130
} ;
125
131
126
- let data = & po. basic_blocks [ root] ;
127
-
128
- if let Some ( ref term) = data. terminator {
129
- po. visited . insert ( root) ;
130
- po. visit_stack . push ( ( root, term. successors ( ) ) ) ;
131
- po. traverse_successor ( ) ;
132
- }
132
+ po. visit ( root) ;
133
+ po. traverse_successor ( ) ;
133
134
134
135
po
135
136
}
136
137
138
+ fn visit ( & mut self , bb : BasicBlock ) {
139
+ if !self . visited . insert ( bb) {
140
+ return ;
141
+ }
142
+ let data = & self . basic_blocks [ bb] ;
143
+ let successors = C :: successors ( data, self . extra ) ;
144
+ self . visit_stack . push ( ( bb, successors) ) ;
145
+ }
146
+
137
147
fn traverse_successor ( & mut self ) {
138
148
// This is quite a complex loop due to 1. the borrow checker not liking it much
139
149
// and 2. what exactly is going on is not clear
@@ -183,16 +193,15 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
183
193
// since we've already visited `E`, that child isn't added to the stack. The last
184
194
// two iterations yield `B` and finally `A` for a final traversal of [E, D, C, B, A]
185
195
while let Some ( bb) = self . visit_stack . last_mut ( ) . and_then ( |( _, iter) | iter. next_back ( ) ) {
186
- if self . visited . insert ( bb) {
187
- if let Some ( term) = & self . basic_blocks [ bb] . terminator {
188
- self . visit_stack . push ( ( bb, term. successors ( ) ) ) ;
189
- }
190
- }
196
+ self . visit ( bb) ;
191
197
}
192
198
}
193
199
}
194
200
195
- impl < ' tcx > Iterator for Postorder < ' _ , ' tcx > {
201
+ impl < ' tcx , C > Iterator for Postorder < ' _ , ' tcx , C >
202
+ where
203
+ C : Customization < ' tcx > ,
204
+ {
196
205
type Item = BasicBlock ;
197
206
198
207
fn next ( & mut self ) -> Option < BasicBlock > {
@@ -232,57 +241,23 @@ pub fn postorder<'a, 'tcx>(
232
241
reverse_postorder ( body) . rev ( )
233
242
}
234
243
235
- struct MonoReachablePostorder < ' a , ' tcx > {
236
- basic_blocks : & ' a IndexSlice < BasicBlock , BasicBlockData < ' tcx > > ,
237
- visited : BitSet < BasicBlock > ,
238
- visit_stack : Vec < ( BasicBlock , Successors < ' a > ) > ,
239
- tcx : TyCtxt < ' tcx > ,
240
- instance : Instance < ' tcx > ,
244
+ /// Lets us plug in some additional logic and data into a Postorder traversal. Or not.
245
+ pub trait Customization < ' tcx > : Copy {
246
+ fn successors < ' a > ( _: & ' a BasicBlockData < ' tcx > , _: Self ) -> Successors < ' a > ;
241
247
}
242
248
243
- impl < ' a , ' tcx > MonoReachablePostorder < ' a , ' tcx > {
244
- fn new (
245
- body : & ' a Body < ' tcx > ,
246
- tcx : TyCtxt < ' tcx > ,
247
- instance : Instance < ' tcx > ,
248
- ) -> MonoReachablePostorder < ' a , ' tcx > {
249
- let basic_blocks = & body. basic_blocks ;
250
- let mut po = MonoReachablePostorder {
251
- basic_blocks,
252
- visited : BitSet :: new_empty ( basic_blocks. len ( ) ) ,
253
- visit_stack : Vec :: new ( ) ,
254
- tcx,
255
- instance,
256
- } ;
257
-
258
- po. visit ( START_BLOCK ) ;
259
- po. traverse_successor ( ) ;
260
- po
261
- }
262
-
263
- fn visit ( & mut self , bb : BasicBlock ) {
264
- if !self . visited . insert ( bb) {
265
- return ;
266
- }
267
- let data = & self . basic_blocks [ bb] ;
268
- let successors = data. mono_successors ( self . tcx , self . instance ) ;
269
- self . visit_stack . push ( ( bb, successors) ) ;
270
- }
271
-
272
- fn traverse_successor ( & mut self ) {
273
- while let Some ( bb) = self . visit_stack . last_mut ( ) . and_then ( |( _, iter) | iter. next_back ( ) ) {
274
- self . visit ( bb) ;
275
- }
249
+ impl < ' tcx > Customization < ' tcx > for ( ) {
250
+ fn successors < ' a > ( data : & ' a BasicBlockData < ' tcx > , _: ( ) ) -> Successors < ' a > {
251
+ data. terminator ( ) . successors ( )
276
252
}
277
253
}
278
254
279
- impl < ' tcx > Iterator for MonoReachablePostorder < ' _ , ' tcx > {
280
- type Item = BasicBlock ;
281
-
282
- fn next ( & mut self ) -> Option < BasicBlock > {
283
- let ( bb, _) = self . visit_stack . pop ( ) ?;
284
- self . traverse_successor ( ) ;
285
- Some ( bb)
255
+ impl < ' tcx > Customization < ' tcx > for ( TyCtxt < ' tcx > , Instance < ' tcx > ) {
256
+ fn successors < ' a > (
257
+ data : & ' a BasicBlockData < ' tcx > ,
258
+ ( tcx, instance) : ( TyCtxt < ' tcx > , Instance < ' tcx > ) ,
259
+ ) -> Successors < ' a > {
260
+ data. mono_successors ( tcx, instance)
286
261
}
287
262
}
288
263
@@ -291,7 +266,7 @@ pub fn mono_reachable_reverse_postorder<'a, 'tcx>(
291
266
tcx : TyCtxt < ' tcx > ,
292
267
instance : Instance < ' tcx > ,
293
268
) -> Vec < BasicBlock > {
294
- let mut iter = MonoReachablePostorder :: new ( body, tcx, instance) ;
269
+ let mut iter = Postorder :: new ( & body. basic_blocks , START_BLOCK , ( tcx, instance) ) ;
295
270
let mut items = Vec :: with_capacity ( body. basic_blocks . len ( ) ) ;
296
271
while let Some ( block) = iter. next ( ) {
297
272
items. push ( block) ;
0 commit comments