8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
+ //! A pass that removes various redundancies in the CFG. It should be
12
+ //! called after every significant CFG modification to tidy things
13
+ //! up.
14
+ //!
15
+ //! This pass must also be run before any analysis passes because it removes
16
+ //! dead blocks, and some of these can be ill-typed.
17
+ //!
18
+ //! The cause of that is that typeck lets most blocks whose end is not
19
+ //! reachable have an arbitrary return type, rather than having the
20
+ //! usual () return type (as a note, typeck's notion of reachability
21
+ //! is in fact slightly weaker than MIR CFG reachability - see #31617).
22
+ //!
23
+ //! A standard example of the situation is:
24
+ //! ```rust
25
+ //! fn example() {
26
+ //! let _a: char = { return; };
27
+ //! }
28
+ //! ```
29
+ //!
30
+ //! Here the block (`{ return; }`) has the return type `char`,
31
+ //! rather than `()`, but the MIR we naively generate still contains
32
+ //! the `_a = ()` write in the unreachable block "after" the return.
33
+
34
+
11
35
use rustc_data_structures:: bitvec:: BitVector ;
12
36
use rustc:: middle:: const_val:: ConstVal ;
13
37
use rustc:: ty:: TyCtxt ;
@@ -16,32 +40,31 @@ use rustc::mir::transform::{MirPass, MirSource, Pass};
16
40
use pretty;
17
41
use std:: mem;
18
42
19
- use super :: remove_dead_blocks:: RemoveDeadBlocks ;
20
-
21
43
use traversal;
22
44
23
- pub struct SimplifyCfg ;
45
+ pub struct SimplifyCfg < ' a > { label : & ' a str }
24
46
25
- impl SimplifyCfg {
26
- pub fn new ( ) -> SimplifyCfg {
27
- SimplifyCfg
47
+ impl < ' a > SimplifyCfg < ' a > {
48
+ pub fn new ( label : & ' a str ) -> Self {
49
+ SimplifyCfg { label : label }
28
50
}
29
51
}
30
52
31
- impl < ' tcx > MirPass < ' tcx > for SimplifyCfg {
53
+ impl < ' l , ' tcx > MirPass < ' tcx > for SimplifyCfg < ' l > {
32
54
fn run_pass < ' a > ( & mut self , tcx : TyCtxt < ' a , ' tcx , ' tcx > , src : MirSource , mir : & mut Mir < ' tcx > ) {
55
+ pretty:: dump_mir ( tcx, "simplify_cfg" , & format ! ( "{}-before" , self . label) , src, mir, None ) ;
33
56
simplify_branches ( mir) ;
34
- RemoveDeadBlocks . run_pass ( tcx , src , mir) ;
57
+ remove_dead_blocks ( mir) ;
35
58
merge_consecutive_blocks ( mir) ;
36
- RemoveDeadBlocks . run_pass ( tcx , src , mir) ;
37
- pretty:: dump_mir ( tcx, "simplify_cfg" , & 0 , src, mir, None ) ;
59
+ remove_dead_blocks ( mir) ;
60
+ pretty:: dump_mir ( tcx, "simplify_cfg" , & format ! ( "{}-after" , self . label ) , src, mir, None ) ;
38
61
39
62
// FIXME: Should probably be moved into some kind of pass manager
40
63
mir. basic_blocks . shrink_to_fit ( ) ;
41
64
}
42
65
}
43
66
44
- impl Pass for SimplifyCfg { }
67
+ impl < ' l > Pass for SimplifyCfg < ' l > { }
45
68
46
69
fn merge_consecutive_blocks ( mir : & mut Mir ) {
47
70
// Build the precedecessor map for the MIR
@@ -203,3 +226,31 @@ fn simplify_branches(mir: &mut Mir) {
203
226
}
204
227
}
205
228
}
229
+
230
+ fn remove_dead_blocks ( mir : & mut Mir ) {
231
+ let mut seen = BitVector :: new ( mir. basic_blocks . len ( ) ) ;
232
+ for ( bb, _) in traversal:: preorder ( mir) {
233
+ seen. insert ( bb. index ( ) ) ;
234
+ }
235
+
236
+ let num_blocks = mir. basic_blocks . len ( ) ;
237
+
238
+ let mut replacements: Vec < _ > = ( 0 ..num_blocks) . map ( BasicBlock :: new) . collect ( ) ;
239
+ let mut used_blocks = 0 ;
240
+ for alive_index in seen. iter ( ) {
241
+ replacements[ alive_index] = BasicBlock :: new ( used_blocks) ;
242
+ if alive_index != used_blocks {
243
+ // Swap the next alive block data with the current available slot. Since alive_index is
244
+ // non-decreasing this is a valid operation.
245
+ mir. basic_blocks . swap ( alive_index, used_blocks) ;
246
+ }
247
+ used_blocks += 1 ;
248
+ }
249
+ mir. basic_blocks . truncate ( used_blocks) ;
250
+
251
+ for bb in mir. all_basic_blocks ( ) {
252
+ for target in mir. basic_block_data_mut ( bb) . terminator_mut ( ) . successors_mut ( ) {
253
+ * target = replacements[ target. index ( ) ] ;
254
+ }
255
+ }
256
+ }
0 commit comments