diff --git a/src/librustc/mir/transform/dataflow.rs b/src/librustc/mir/transform/dataflow.rs index 508f74e356a0f..0886a63d1b734 100644 --- a/src/librustc/mir/transform/dataflow.rs +++ b/src/librustc/mir/transform/dataflow.rs @@ -1,17 +1,10 @@ use mir::repr as mir; use mir::cfg::CFG; -use mir::repr::BasicBlock; +use mir::repr::{BasicBlock, START_BLOCK}; use rustc_data_structures::bitvec::BitVector; use mir::transform::lattice::Lattice; - -pub trait DataflowPass<'tcx> { - type Lattice: Lattice; - type Rewrite: Rewrite<'tcx, Self::Lattice>; - type Transfer: Transfer<'tcx, Self::Lattice>; -} - pub trait Rewrite<'tcx, L: Lattice> { /// The rewrite function which given a statement optionally produces an alternative graph to be /// placed in place of the original statement. @@ -23,7 +16,7 @@ pub trait Rewrite<'tcx, L: Lattice> { /// that is, given some fact `fact` true before both the statement and relacement graph, and /// a fact `fact2` which is true after the statement, the same `fact2` must be true after the /// replacement graph too. - fn stmt(&mir::Statement<'tcx>, &L, &mut CFG<'tcx>) -> StatementChange<'tcx>; + fn stmt(&self, &mir::Statement<'tcx>, &L, &mut CFG<'tcx>) -> StatementChange<'tcx>; /// The rewrite function which given a terminator optionally produces an alternative graph to /// be placed in place of the original statement. @@ -35,7 +28,11 @@ pub trait Rewrite<'tcx, L: Lattice> { /// that is, given some fact `fact` true before both the terminator and relacement graph, and /// a fact `fact2` which is true after the statement, the same `fact2` must be true after the /// replacement graph too. - fn term(&mir::Terminator<'tcx>, &L, &mut CFG<'tcx>) -> TerminatorChange<'tcx>; + fn term(&self, &mir::Terminator<'tcx>, &L, &mut CFG<'tcx>) -> TerminatorChange<'tcx>; + + fn and_then(self, other: R2) -> RewriteAndThen where Self: Sized { + RewriteAndThen(self, other) + } } /// This combinator has the following behaviour: @@ -43,41 +40,27 @@ pub trait Rewrite<'tcx, L: Lattice> { /// * Rewrite the node with the first rewriter. /// * if the first rewriter replaced the node, 2nd rewriter is used to rewrite the replacement. /// * otherwise 2nd rewriter is used to rewrite the original node. -pub struct RewriteAndThen<'tcx, R1, R2>(::std::marker::PhantomData<(&'tcx (), R1, R2)>); -impl<'tcx, L, R1, R2> Rewrite<'tcx, L> for RewriteAndThen<'tcx, R1, R2> +pub struct RewriteAndThen(R1, R2); +impl<'tcx, L, R1, R2> Rewrite<'tcx, L> for RewriteAndThen where L: Lattice, R1: Rewrite<'tcx, L>, R2: Rewrite<'tcx, L> { - fn stmt(s: &mir::Statement<'tcx>, l: &L, c: &mut CFG<'tcx>) -> StatementChange<'tcx> { - let rs = >::stmt(s, l, c); + fn stmt(&self, s: &mir::Statement<'tcx>, l: &L, c: &mut CFG<'tcx>) -> StatementChange<'tcx> { + let rs = self.0.stmt(s, l, c); match rs { - StatementChange::None => >::stmt(s, l, c), + StatementChange::None => self.1.stmt(s, l, c), StatementChange::Remove => StatementChange::Remove, StatementChange::Statement(ns) => - match >::stmt(&ns, l, c) { + match self.1.stmt(&ns, l, c) { StatementChange::None => StatementChange::Statement(ns), x => x - }, - StatementChange::Statements(nss) => { - // We expect the common case of all statements in this vector being replaced/not - // replaced by other statements 1:1 - let mut new_new_stmts = Vec::with_capacity(nss.len()); - for s in nss { - match >::stmt(&s, l, c) { - StatementChange::None => new_new_stmts.push(s), - StatementChange::Remove => {}, - StatementChange::Statement(ns) => new_new_stmts.push(ns), - StatementChange::Statements(nss) => new_new_stmts.extend(nss) - } } - StatementChange::Statements(new_new_stmts) - } } } - fn term(t: &mir::Terminator<'tcx>, l: &L, c: &mut CFG<'tcx>) -> TerminatorChange<'tcx> { - let rt = >::term(t, l, c); + fn term(&self, t: &mir::Terminator<'tcx>, l: &L, c: &mut CFG<'tcx>) -> TerminatorChange<'tcx> { + let rt = self.0.term(t, l, c); match rt { - TerminatorChange::None => >::term(t, l, c), - TerminatorChange::Terminator(nt) => match >::term(&nt, l, c) { + TerminatorChange::None => self.1.term(t, l, c), + TerminatorChange::Terminator(nt) => match self.1.term(&nt, l, c) { TerminatorChange::None => TerminatorChange::Terminator(nt), x => x } @@ -99,31 +82,14 @@ pub enum StatementChange<'tcx> { Remove, /// Replace with another single statement Statement(mir::Statement<'tcx>), - /// Replace with a list of statements - Statements(Vec>), } -impl<'tcx> StatementChange<'tcx> { - fn normalise(&mut self) { - let old = ::std::mem::replace(self, StatementChange::None); - *self = match old { - StatementChange::Statements(mut stmts) => { - match stmts.len() { - 0 => StatementChange::Remove, - 1 => StatementChange::Statement(stmts.pop().unwrap()), - _ => StatementChange::Statements(stmts) - } - } - o => o - } - } -} +pub trait Transfer<'tcx> { + type Lattice: Lattice; -pub trait Transfer<'tcx, L: Lattice> { - type TerminatorOut; /// The transfer function which given a statement and a fact produces a fact which is true /// after the statement. - fn stmt(&mir::Statement<'tcx>, L) -> L; + fn stmt(&self, &mir::Statement<'tcx>, Self::Lattice) -> Self::Lattice; /// The transfer function which given a terminator and a fact produces a fact for each /// successor of the terminator. @@ -131,7 +97,7 @@ pub trait Transfer<'tcx, L: Lattice> { /// Corectness precondtition: /// * The list of facts produced should only contain the facts for blocks which are successors /// of the terminator being transfered. - fn term(&mir::Terminator<'tcx>, L) -> Self::TerminatorOut; + fn term(&self, &mir::Terminator<'tcx>, Self::Lattice) -> Vec; } @@ -160,7 +126,7 @@ impl ::std::ops::Index for Facts { impl ::std::ops::IndexMut for Facts { fn index_mut(&mut self, index: BasicBlock) -> &mut F { - if let None = self.0.get_mut(index.index()) { + if self.0.get(index.index()).is_none() { self.put(index, ::bottom()); } self.0.get_mut(index.index()).unwrap() @@ -168,12 +134,14 @@ impl ::std::ops::IndexMut for Facts { } /// Analyse and rewrite using dataflow in the forward direction -pub fn ar_forward<'tcx, T, P>(cfg: &CFG<'tcx>, fs: Facts, mut queue: BitVector) --> (CFG<'tcx>, Facts) -// FIXME: shouldn’t need that T generic. -where T: Transfer<'tcx, P::Lattice, TerminatorOut=Vec>, - P: DataflowPass<'tcx, Transfer=T> +pub fn ar_forward<'tcx, T, R>(cfg: &CFG<'tcx>, fs: Facts, transfer: T, rewrite: R) +-> (CFG<'tcx>, Facts) +where T: Transfer<'tcx>, + R: Rewrite<'tcx, T::Lattice> { + let mut queue = BitVector::new(cfg.len()); + queue.insert(START_BLOCK.index()); + fixpoint(cfg, Direction::Forward, |bb, fact, cfg| { let new_graph = cfg.start_new_block(); let mut fact = fact.clone(); @@ -183,33 +151,25 @@ where T: Transfer<'tcx, P::Lattice, TerminatorOut=Vec>, for stmt in &old_statements { // Given a fact and statement produce a new fact and optionally a replacement // graph. - let mut new_repl = P::Rewrite::stmt(&stmt, &fact, cfg); - new_repl.normalise(); - match new_repl { + match rewrite.stmt(&stmt, &fact, cfg) { StatementChange::None => { - fact = P::Transfer::stmt(stmt, fact); + fact = transfer.stmt(stmt, fact); cfg.push(new_graph, stmt.clone()); } StatementChange::Remove => changed = true, StatementChange::Statement(stmt) => { changed = true; - fact = P::Transfer::stmt(&stmt, fact); + fact = transfer.stmt(&stmt, fact); cfg.push(new_graph, stmt); } - StatementChange::Statements(stmts) => { - changed = true; - for stmt in &stmts { fact = P::Transfer::stmt(stmt, fact); } - cfg[new_graph].statements.extend(stmts); - } - } } // Swap the statements back in. - ::std::mem::replace(&mut cfg[bb].statements, old_statements); + cfg[bb].statements = old_statements; // Handle the terminator replacement and transfer. - let terminator = ::std::mem::replace(&mut cfg[bb].terminator, None).unwrap(); - let repl = P::Rewrite::term(&terminator, &fact, cfg); + let terminator = cfg[bb].terminator.take().unwrap(); + let repl = rewrite.term(&terminator, &fact, cfg); match repl { TerminatorChange::None => { cfg[new_graph].terminator = Some(terminator.clone()); @@ -219,8 +179,8 @@ where T: Transfer<'tcx, P::Lattice, TerminatorOut=Vec>, cfg[new_graph].terminator = Some(t); } } - let new_facts = P::Transfer::term(cfg[new_graph].terminator(), fact); - ::std::mem::replace(&mut cfg[bb].terminator, Some(terminator)); + let new_facts = transfer.term(cfg[new_graph].terminator(), fact); + cfg[bb].terminator = Some(terminator); (if changed { Some(new_graph) } else { None }, new_facts) }, &mut queue, fs) @@ -350,7 +310,7 @@ where T: Transfer<'tcx, P::Lattice, TerminatorOut=Vec>, enum Direction { Forward, - Backward +// Backward } /// The fixpoint function is the engine of this whole thing. Important part of it is the `f: BF` @@ -389,16 +349,17 @@ where BF: Fn(BasicBlock, &F, &mut CFG<'tcx>) -> (Option, Vec), } // Then we record the facts in the correct direction. - if let Direction::Forward = direction { - for (f, &target) in new_facts.into_iter() - .zip(cfg[block].terminator().successors().iter()) { - let facts_changed = Lattice::join(&mut init_facts[target], &f); - if facts_changed { - to_visit.insert(target.index()); + match direction { + Direction::Forward => { + for (f, &target) in new_facts.into_iter() + .zip(cfg[block].terminator().successors().iter()) { + let facts_changed = Lattice::join(&mut init_facts[target], &f); + if facts_changed { + to_visit.insert(target.index()); + } } } - } else { - unimplemented!() + // Direction::Backward => unimplemented!() // let mut new_facts = new_facts; // let fact = new_facts.pop().unwrap().1; // for pred in cfg.predecessors(block) { diff --git a/src/librustc/mir/transform/lattice.rs b/src/librustc/mir/transform/lattice.rs index 129291b349b7f..9f6cda4abdcc9 100644 --- a/src/librustc/mir/transform/lattice.rs +++ b/src/librustc/mir/transform/lattice.rs @@ -23,7 +23,7 @@ impl Lattice for WTop { /// ⊤ + V = ⊤ (no change) /// V + ⊤ = ⊤ /// ⊤ + ⊤ = ⊤ (no change) - default fn join(&mut self, other: &Self) -> bool { + fn join(&mut self, other: &Self) -> bool { match (self, other) { (&mut WTop::Value(ref mut this), &WTop::Value(ref o)) => ::join(this, o), (&mut WTop::Top, _) => false, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index d74eb959af8e7..95759efae3b53 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -939,8 +939,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks); passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants); passes.push_pass(box mir::transform::type_check::TypeckMir); - passes.push_pass(box mir::transform::acs_propagate::ACSPropagate); - // passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg); + passes.push_pass(box mir::transform::acs_propagate::AcsPropagate); + passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg); passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks); // And run everything. passes.run_passes(tcx, &mut mir_map); diff --git a/src/librustc_mir/transform/acs_propagate.rs b/src/librustc_mir/transform/acs_propagate.rs index 38ce707f4edc5..e81004f87305e 100644 --- a/src/librustc_mir/transform/acs_propagate.rs +++ b/src/librustc_mir/transform/acs_propagate.rs @@ -24,12 +24,13 @@ //! For all of them we will be using a lattice of Hashmap from Lvalue to //! WTop> //! -//! My personal believ is that it should be possible to make a way to compose two hashmap lattices +//! My personal belief is that it should be possible to make a way to compose two hashmap lattices //! into one, but I can’t seem to get it just right yet, so we do the composing and decomposing //! manually here. +use self::AcsLattice::*; + use rustc_data_structures::fnv::FnvHashMap; -use rustc_data_structures::bitvec::BitVector; use rustc::mir::repr::*; use rustc::mir::visit::{MutVisitor, LvalueContext}; use rustc::mir::transform::lattice::Lattice; @@ -40,64 +41,140 @@ use rustc::middle::const_val::ConstVal; use pretty; #[derive(PartialEq, Debug, Eq, Clone)] -pub enum Either<'tcx> { - Top, +enum Either<'tcx> { Lvalue(Lvalue<'tcx>), Const(Constant<'tcx>), } -impl<'tcx> Lattice for Either<'tcx> { - fn bottom() -> Self { unimplemented!() } +#[derive(Debug, Clone)] +enum AcsLattice<'tcx> { + Bottom, + Wrap(FnvHashMap, Either<'tcx>>) +} + +impl<'tcx> Lattice for AcsLattice<'tcx> { + fn bottom() -> Self { Bottom } fn join(&mut self, other: &Self) -> bool { - if self == other { - false - } else { - *self = Either::Top; - true + let other_map = match *other { + Bottom => return false, + Wrap(ref map) => map + }; + let self_map = match *self { + Bottom => { + *self = Wrap(other_map.clone()); + return true; + }, + Wrap(ref mut map) => map + }; + + let mut changed = false; + + for (k, v) in other_map { + let should_remove = if let Some(cur_v) = self_map.get(k) { + cur_v != v + } else { + false + }; + if should_remove { + self_map.remove(k); + changed = true; + } } + + changed } } -pub type ACSLattice<'a> = FnvHashMap, Either<'a>>; - -pub struct ACSPropagate; +pub struct AcsPropagate; -impl Pass for ACSPropagate {} +impl Pass for AcsPropagate {} -impl<'tcx> MirPass<'tcx> for ACSPropagate { +impl<'tcx> MirPass<'tcx> for AcsPropagate { fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) { - let mut q = BitVector::new(mir.cfg.len()); - q.insert(START_BLOCK.index()); - let ret = ar_forward::(&mut mir.cfg, Facts::new(), q); + let ret = ar_forward( + &mut mir.cfg, + Facts::new(), + AcsPropagateTransfer, + AliasRewrite.and_then(ConstRewrite).and_then(SimplifyRewrite) + ); mir.cfg = ret.0; pretty::dump_mir(tcx, "acs_propagate", &0, src, mir, None); } } -impl<'tcx> DataflowPass<'tcx> for ACSPropagate { - type Lattice = ACSLattice<'tcx>; - type Rewrite = RewriteAndThen<'tcx, AliasRewrite, - RewriteAndThen<'tcx, ConstRewrite, SimplifyRewrite>>; - type Transfer = ACSPropagateTransfer; +struct AcsPropagateTransfer; + +fn base_lvalue<'a, 'tcx>(mut lval: &'a Lvalue<'tcx>) -> &'a Lvalue<'tcx> { + while let &Lvalue::Projection(ref proj) = lval { + lval = &proj.base; + } + lval +} + +fn invalidate<'tcx>(map: &mut FnvHashMap, Either<'tcx>>, lval: &Lvalue<'tcx>) { + map.remove(lval); + + let mut repl = None; + + for (k, v) in &mut *map { + if let Either::Lvalue(ref mut nlval) = *v { + if nlval == lval { + match repl { + None => { + repl = Some(k.clone()) + }, + Some(ref r) => { + *nlval = r.clone(); + } + } + } + } + } + + if let Some(repl) = repl { + map.remove(&repl); + } } -pub struct ACSPropagateTransfer; +impl<'tcx> Transfer<'tcx> for AcsPropagateTransfer { + type Lattice = AcsLattice<'tcx>; + + fn stmt(&self, s: &Statement<'tcx>, lat: AcsLattice<'tcx>) -> AcsLattice<'tcx> { + let mut lat_map = match lat { + Bottom => FnvHashMap::default(), + Wrap(map) => map + }; -impl<'tcx> Transfer<'tcx, ACSLattice<'tcx>> for ACSPropagateTransfer { - type TerminatorOut = Vec>; - fn stmt(s: &Statement<'tcx>, mut lat: ACSLattice<'tcx>) -> ACSLattice<'tcx> { let StatementKind::Assign(ref lval, ref rval) = s.kind; + invalidate(&mut lat_map, base_lvalue(lval)); + + if let &Lvalue::Projection(_) = lval { + return Wrap(lat_map); + } + match *rval { - Rvalue::Use(Operand::Consume(ref nlval)) => - lat.insert(lval.clone(), Either::Lvalue(nlval.clone())), - Rvalue::Use(Operand::Constant(ref c)) => - lat.insert(lval.clone(), Either::Const(c.clone())), - _ => lat.insert(lval.clone(), Either::Top) + Rvalue::Use(Operand::Consume(ref nlval)) => { + lat_map.insert(lval.clone(), Either::Lvalue(nlval.clone())); + }, + Rvalue::Use(Operand::Constant(ref c)) => { + lat_map.insert(lval.clone(), Either::Const(c.clone())); + }, + _ => { } }; - lat + Wrap(lat_map) } - fn term(t: &Terminator<'tcx>, lat: ACSLattice<'tcx>) -> Self::TerminatorOut { + + fn term(&self, t: &Terminator<'tcx>, mut lat: AcsLattice<'tcx>) -> Vec> { + match t.kind { + TerminatorKind::Call { .. } | + TerminatorKind::Drop { .. } => { + // FIXME: Be smarter here by using an alias analysis + lat = Wrap(FnvHashMap::default()); + }, + _ => { } + } + // FIXME: this should inspect the terminators and set their known values to constants. Esp. // for the if: in the truthy branch the operand is known to be true and in the falsy branch // the operand is known to be false. Now we just ignore the potential here. @@ -107,67 +184,86 @@ impl<'tcx> Transfer<'tcx, ACSLattice<'tcx>> for ACSPropagateTransfer { } } -pub struct AliasRewrite; +struct AliasRewrite; -impl<'tcx> Rewrite<'tcx, ACSLattice<'tcx>> for AliasRewrite { - fn stmt(s: &Statement<'tcx>, l: &ACSLattice<'tcx>, cfg: &mut CFG<'tcx>) +impl<'tcx> Rewrite<'tcx, AcsLattice<'tcx>> for AliasRewrite { + fn stmt(&self, s: &Statement<'tcx>, l: &AcsLattice<'tcx>, _: &mut CFG<'tcx>) -> StatementChange<'tcx> { - let mut ns = s.clone(); - let mut vis = RewriteAliasVisitor(&l, false); - vis.visit_statement(START_BLOCK, &mut ns); - if vis.1 { StatementChange::Statement(ns) } else { StatementChange::None } + if let Wrap(ref map) = *l { + let mut ns = s.clone(); + let mut vis = RewriteAliasVisitor(map, false); + vis.visit_statement(START_BLOCK, &mut ns); + if vis.1 { + return StatementChange::Statement(ns); + } + } + StatementChange::None } - fn term(t: &Terminator<'tcx>, l: &ACSLattice<'tcx>, cfg: &mut CFG<'tcx>) + + fn term(&self, t: &Terminator<'tcx>, l: &AcsLattice<'tcx>, _: &mut CFG<'tcx>) -> TerminatorChange<'tcx> { - let mut nt = t.clone(); - let mut vis = RewriteAliasVisitor(&l, false); - vis.visit_terminator(START_BLOCK, &mut nt); - if vis.1 { TerminatorChange::Terminator(nt) } else { TerminatorChange::None } + if let Wrap(ref map) = *l { + let mut nt = t.clone(); + let mut vis = RewriteAliasVisitor(map, false); + vis.visit_terminator(START_BLOCK, &mut nt); + if vis.1 { + return TerminatorChange::Terminator(nt); + } + } + TerminatorChange::None } } -struct RewriteAliasVisitor<'a, 'tcx: 'a>(pub &'a ACSLattice<'tcx>, pub bool); +struct RewriteAliasVisitor<'a, 'tcx: 'a>(&'a FnvHashMap, Either<'tcx>>, bool); impl<'a, 'tcx> MutVisitor<'tcx> for RewriteAliasVisitor<'a, 'tcx> { fn visit_lvalue(&mut self, lvalue: &mut Lvalue<'tcx>, context: LvalueContext) { match context { - LvalueContext::Store | LvalueContext::Call => {} - _ => { - let replacement = self.0.get(lvalue); - match replacement { - Some(&Either::Lvalue(ref nlval)) => { - self.1 = true; - *lvalue = nlval.clone(); - } - _ => {} + LvalueContext::Consume => { + if let Some(&Either::Lvalue(ref nlval)) = self.0.get(lvalue) { + self.1 = true; + *lvalue = nlval.clone(); } - } + }, + _ => { } } self.super_lvalue(lvalue, context); } } -pub struct ConstRewrite; +struct ConstRewrite; -impl<'tcx> Rewrite<'tcx, ACSLattice<'tcx>> for ConstRewrite { - fn stmt(s: &Statement<'tcx>, l: &ACSLattice<'tcx>, cfg: &mut CFG<'tcx>) +impl<'tcx> Rewrite<'tcx, AcsLattice<'tcx>> for ConstRewrite { + fn stmt(&self, s: &Statement<'tcx>, l: &AcsLattice<'tcx>, _: &mut CFG<'tcx>) -> StatementChange<'tcx> { - let mut ns = s.clone(); - let mut vis = RewriteConstVisitor(&l, false); - vis.visit_statement(START_BLOCK, &mut ns); - if vis.1 { StatementChange::Statement(ns) } else { StatementChange::None } + if let Wrap(ref map) = *l { + let mut ns = s.clone(); + let mut vis = RewriteConstVisitor(map, false); + vis.visit_statement(START_BLOCK, &mut ns); + if vis.1 { + return StatementChange::Statement(ns); + } + } + StatementChange::None } - fn term(t: &Terminator<'tcx>, l: &ACSLattice<'tcx>, cfg: &mut CFG<'tcx>) + + fn term(&self, t: &Terminator<'tcx>, l: &AcsLattice<'tcx>, _: &mut CFG<'tcx>) -> TerminatorChange<'tcx> { - let mut nt = t.clone(); - let mut vis = RewriteConstVisitor(&l, false); - vis.visit_terminator(START_BLOCK, &mut nt); - if vis.1 { TerminatorChange::Terminator(nt) } else { TerminatorChange::None } + if let Wrap(ref map) = *l { + let mut nt = t.clone(); + let mut vis = RewriteConstVisitor(map, false); + vis.visit_terminator(START_BLOCK, &mut nt); + if vis.1 { + return TerminatorChange::Terminator(nt); + } + } + TerminatorChange::None } } -struct RewriteConstVisitor<'a, 'tcx: 'a>(pub &'a ACSLattice<'tcx>, pub bool); +struct RewriteConstVisitor<'a, 'tcx: 'a>(&'a FnvHashMap, Either<'tcx>>, bool); impl<'a, 'tcx> MutVisitor<'tcx> for RewriteConstVisitor<'a, 'tcx> { fn visit_operand(&mut self, op: &mut Operand<'tcx>) { + // To satisy borrow checker, modify `op` after inspecting it let repl = if let Operand::Consume(ref lval) = *op { if let Some(&Either::Const(ref c)) = self.0.get(lval) { Some(c.clone()) @@ -178,21 +274,24 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RewriteConstVisitor<'a, 'tcx> { None }; if let Some(c) = repl { + self.1 = true; *op = Operand::Constant(c); } + self.super_operand(op); } } -pub struct SimplifyRewrite; +struct SimplifyRewrite; -impl<'tcx> Rewrite<'tcx, ACSLattice<'tcx>> for SimplifyRewrite { - fn stmt(s: &Statement<'tcx>, l: &ACSLattice<'tcx>, cfg: &mut CFG<'tcx>) +impl<'tcx, L: Lattice> Rewrite<'tcx, L> for SimplifyRewrite { + fn stmt(&self, _: &Statement<'tcx>, _: &L, _: &mut CFG<'tcx>) -> StatementChange<'tcx> { StatementChange::None } - fn term(t: &Terminator<'tcx>, l: &ACSLattice<'tcx>, cfg: &mut CFG<'tcx>) + + fn term(&self, t: &Terminator<'tcx>, _: &L, _: &mut CFG<'tcx>) -> TerminatorChange<'tcx> { match t.kind { TerminatorKind::If { ref targets, .. } if targets.0 == targets.1 => { diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index 228fca054c23d..76f5c9ec9febb 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -83,7 +83,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg { while changed { pretty::dump_mir(tcx, "simplify_cfg", &counter, src, mir, None); counter += 1; - changed |= self.remove_goto_chains(mir); + changed = self.remove_goto_chains(mir); RemoveDeadBlocks.run_pass(tcx, src, mir); } // FIXME: Should probably be moved into some kind of pass manager