|
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