|
11 | 11 | use rustc::middle::const_eval::ConstVal; |
12 | 12 | use rustc::middle::ty; |
13 | 13 | use rustc::mir::repr::*; |
| 14 | +use rustc::mir::visit::MutVisitor; |
14 | 15 | use transform::util; |
15 | 16 | use rustc::mir::transform::{MirPass, Pass}; |
16 | 17 |
|
17 | 18 | pub struct SimplifyCfg; |
18 | 19 |
|
19 | | -impl SimplifyCfg { |
20 | | - fn remove_dead_blocks(&self, mir: &mut Mir) { |
21 | | - let mut seen = vec![false; mir.basic_blocks.len()]; |
22 | | - |
23 | | - // These blocks are always required. |
24 | | - seen[START_BLOCK.index()] = true; |
25 | | - seen[END_BLOCK.index()] = true; |
| 20 | +impl Pass for SimplifyCfg { |
| 21 | + fn priority(&self) -> usize { |
| 22 | + 50 |
| 23 | + } |
| 24 | +} |
26 | 25 |
|
27 | | - let mut worklist = vec![START_BLOCK]; |
28 | | - while let Some(bb) = worklist.pop() { |
29 | | - for succ in mir.basic_block_data(bb).terminator().successors().iter() { |
30 | | - if !seen[succ.index()] { |
31 | | - seen[succ.index()] = true; |
32 | | - worklist.push(*succ); |
33 | | - } |
34 | | - } |
| 26 | +impl MirPass for SimplifyCfg { |
| 27 | + fn run_pass<'tcx>(&mut self, tcx: &ty::ctxt<'tcx>, mir: &mut Mir<'tcx>) { |
| 28 | + let mut dbr_pass = DeadBlockRemoval::new(self); |
| 29 | + let mut changed = true; |
| 30 | + while changed { |
| 31 | + changed = self.simplify_branches(mir); |
| 32 | + changed |= self.remove_goto_chains(mir); |
| 33 | + dbr_pass.run_pass(tcx, mir); |
35 | 34 | } |
36 | | - |
37 | | - util::retain_basic_blocks(mir, &seen); |
38 | 35 | } |
| 36 | +} |
39 | 37 |
|
| 38 | +impl SimplifyCfg { |
40 | 39 | fn remove_goto_chains(&self, mir: &mut Mir) -> bool { |
41 | 40 |
|
42 | 41 | // Find the target at the end of the jump chain, return None if there is a loop |
@@ -116,21 +115,94 @@ impl SimplifyCfg { |
116 | 115 | } |
117 | 116 | } |
118 | 117 |
|
119 | | -impl MirPass for SimplifyCfg { |
| 118 | +/// Remove all the unreachable blocks. |
| 119 | +/// |
| 120 | +/// You want to schedule this pass just after any pass which might introduce unreachable blocks. |
| 121 | +/// This pass is very cheap and might improve the run-time of other not-so-cheap passes. |
| 122 | +pub struct DeadBlockRemoval(usize); |
| 123 | + |
| 124 | +impl DeadBlockRemoval { |
| 125 | + fn new(run_after: &Pass) -> DeadBlockRemoval { |
| 126 | + DeadBlockRemoval(run_after.priority() + 1) |
| 127 | + } |
| 128 | +} |
| 129 | + |
| 130 | +impl Pass for DeadBlockRemoval { |
| 131 | + fn priority(&self) -> usize { |
| 132 | + self.0 |
| 133 | + } |
| 134 | +} |
| 135 | + |
| 136 | +impl MirPass for DeadBlockRemoval { |
120 | 137 | fn run_pass<'tcx>(&mut self, _: &ty::ctxt<'tcx>, mir: &mut Mir<'tcx>) { |
121 | | - let mut changed = true; |
122 | | - while changed { |
123 | | - changed = self.simplify_branches(mir); |
124 | | - changed |= self.remove_goto_chains(mir); |
125 | | - self.remove_dead_blocks(mir); |
| 138 | + let mut seen = vec![false; mir.basic_blocks.len()]; |
| 139 | + |
| 140 | + // These blocks are always required. |
| 141 | + seen[START_BLOCK.index()] = true; |
| 142 | + seen[END_BLOCK.index()] = true; |
| 143 | + |
| 144 | + let mut worklist = vec![START_BLOCK]; |
| 145 | + while let Some(bb) = worklist.pop() { |
| 146 | + for succ in mir.basic_block_data(bb).terminator().successors().iter() { |
| 147 | + if !seen[succ.index()] { |
| 148 | + seen[succ.index()] = true; |
| 149 | + worklist.push(*succ); |
| 150 | + } |
| 151 | + } |
126 | 152 | } |
127 | | - // FIXME: Should probably be moved into some kind of pass manager |
128 | | - mir.basic_blocks.shrink_to_fit(); |
| 153 | + |
| 154 | + util::retain_basic_blocks(mir, &seen); |
129 | 155 | } |
130 | 156 | } |
131 | 157 |
|
132 | | -impl Pass for SimplifyCfg { |
| 158 | +/// Reduce the memory allocated by a MIR graph. |
| 159 | +pub struct CompactMir; |
| 160 | + |
| 161 | +impl Pass for CompactMir { |
133 | 162 | fn priority(&self) -> usize { |
134 | | - 50 |
| 163 | + // We want this pass to run very late, so we give it a very high priority number. |
| 164 | + !10 |
| 165 | + } |
| 166 | +} |
| 167 | + |
| 168 | +impl MirPass for CompactMir { |
| 169 | + fn run_pass<'tcx>(&mut self, _: &ty::ctxt<'tcx>, mir: &mut Mir<'tcx>) { |
| 170 | + self.visit_mir(mir); |
| 171 | + } |
| 172 | +} |
| 173 | + |
| 174 | +impl<'tcx> MutVisitor<'tcx> for CompactMir { |
| 175 | + fn visit_mir(&mut self, mir: &mut Mir<'tcx>) { |
| 176 | + mir.basic_blocks.shrink_to_fit(); |
| 177 | + mir.var_decls.shrink_to_fit(); |
| 178 | + mir.arg_decls.shrink_to_fit(); |
| 179 | + mir.temp_decls.shrink_to_fit(); |
| 180 | + self.super_mir(mir); |
| 181 | + } |
| 182 | + |
| 183 | + fn visit_basic_block_data(&mut self, b: BasicBlock, data: &mut BasicBlockData) { |
| 184 | + data.statements.shrink_to_fit(); |
| 185 | + self.super_basic_block_data(b, data); |
| 186 | + } |
| 187 | + |
| 188 | + fn visit_terminator(&mut self, b: BasicBlock, terminator: &mut Terminator) { |
| 189 | + match *terminator { |
| 190 | + Terminator::Switch { ref mut targets, .. } => targets.shrink_to_fit(), |
| 191 | + Terminator::SwitchInt { ref mut values, ref mut targets, .. } => { |
| 192 | + values.shrink_to_fit(); |
| 193 | + targets.shrink_to_fit(); |
| 194 | + }, |
| 195 | + Terminator::Call { ref mut args, .. } => args.shrink_to_fit(), |
| 196 | + _ => {/* nothing to do */} |
| 197 | + } |
| 198 | + self.super_terminator(b, terminator); |
| 199 | + } |
| 200 | + |
| 201 | + fn visit_rvalue(&mut self, rvalue: &mut Rvalue) { |
| 202 | + match *rvalue { |
| 203 | + Rvalue::Aggregate(_, ref mut operands) => operands.shrink_to_fit(), |
| 204 | + _ => { /* nothing to do */ } |
| 205 | + } |
| 206 | + self.super_rvalue(rvalue); |
135 | 207 | } |
136 | 208 | } |
0 commit comments