-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[WIP] [MIR] Generic lattice-based dataflow framework, rebased #34164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
+1,098
−182
Closed
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
bb183e2
Distinct CFG type for MIR, traversals to librustc
nagisa d7a0466
Impl a generic lattice-based DF framework
nagisa 060d840
Implement a ACS propagation pass
nagisa e20d181
Remove use of specialization in Lattice to avoid use of unstable feat…
gereeter ea689a0
Remove DataflowPass
gereeter c1bb060
Add &self arguments to Transfer and Rewrite and start taking them by …
gereeter 52eff47
Remove unused and buggy support for dataflow passes that introduce mu…
gereeter 6413fe6
Let ar_forward generate its own queue
gereeter 0756739
Change the fully capitalized ACS to the partially capitalized Acs, ma…
gereeter a0eebd3
Fix various nits in MIR Dataflow
gereeter 7cbcb4b
Actually rewrite constants in AcsPropagate
gereeter 4af1473
Remove some unnecessary `pub`s in AcsPropagate
gereeter ad37533
Invalidate values in AcsLattice that are overwritten, either by a wri…
gereeter 9b3ecda
Temporarily completely disable Backward dataflow to fix unused varian…
gereeter b0fbbae
Rewrite AcsLattice to be more correct
gereeter 7f1d4c8
Further correctness improvements to AcsRewrite
gereeter cfcf7cd
Remove unused import left over from rebase
gereeter ae0c91c
Properly reset basic blocks optimized based on overspeculative inform…
gereeter ffc2406
Implement MIR's CFG::swap correctly
gereeter 3bd906c
Mutably update blocks when analyzing instead of creating new ones. ru…
gereeter 07d073e
Fix make tidy
gereeter 282d51d
Also clear the Acs cache on DropAndReplace
gereeter f4452c8
Use the generic WBottom for AcsLattice
gereeter c045fa4
Properly implement intersection in AcsLattice::join
gereeter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
use mir::repr::*; | ||
|
||
use std::ops::{Index, IndexMut}; | ||
use syntax::codemap::Span; | ||
|
||
#[derive(Clone, RustcEncodable, RustcDecodable)] | ||
pub struct CFG<'tcx> { | ||
pub basic_blocks: Vec<BasicBlockData<'tcx>>, | ||
} | ||
|
||
pub struct PredecessorIter(::std::vec::IntoIter<BasicBlock>); | ||
impl Iterator for PredecessorIter { | ||
type Item = BasicBlock; | ||
fn next(&mut self) -> Option<BasicBlock> { | ||
self.0.next() | ||
} | ||
} | ||
|
||
pub struct SuccessorIter(::std::vec::IntoIter<BasicBlock>); | ||
impl<'a> Iterator for SuccessorIter { | ||
type Item = BasicBlock; | ||
fn next(&mut self) -> Option<BasicBlock> { | ||
self.0.next() | ||
} | ||
} | ||
|
||
pub struct SuccessorIterMut<'a>(::std::vec::IntoIter<&'a mut BasicBlock>); | ||
impl<'a> Iterator for SuccessorIterMut<'a> { | ||
type Item = &'a mut BasicBlock; | ||
fn next(&mut self) -> Option<&'a mut BasicBlock> { | ||
self.0.next() | ||
} | ||
} | ||
|
||
impl<'tcx> CFG<'tcx> { | ||
pub fn len(&self) -> usize { | ||
self.basic_blocks.len() | ||
} | ||
|
||
pub fn predecessors(&self, b: BasicBlock) -> PredecessorIter { | ||
let mut preds = vec![]; | ||
for idx in 0..self.len() { | ||
let bb = BasicBlock::new(idx); | ||
if let Some(_) = self.successors(bb).find(|&x| x == b) { | ||
preds.push(bb) | ||
} | ||
} | ||
PredecessorIter(preds.into_iter()) | ||
} | ||
|
||
pub fn successors(&self, b: BasicBlock) -> SuccessorIter { | ||
let v: Vec<BasicBlock> = self[b].terminator().kind.successors().into_owned(); | ||
SuccessorIter(v.into_iter()) | ||
} | ||
|
||
pub fn successors_mut(&mut self, b: BasicBlock) -> SuccessorIterMut { | ||
SuccessorIterMut(self[b].terminator_mut().kind.successors_mut().into_iter()) | ||
} | ||
|
||
|
||
pub fn swap(&mut self, b1: BasicBlock, b2: BasicBlock) { | ||
if b1 != b2 { | ||
for idx in 0..self.len() { | ||
let bb = BasicBlock::new(idx); | ||
for target in self.successors_mut(bb) { | ||
if *target == b1 { | ||
*target = b2; | ||
} else if *target == b2 { | ||
*target = b1; | ||
} | ||
} | ||
} | ||
self.basic_blocks.swap(b1.index(), b2.index()); | ||
} | ||
} | ||
|
||
pub fn start_new_block(&mut self) -> BasicBlock { | ||
let node_index = self.basic_blocks.len(); | ||
self.basic_blocks.push(BasicBlockData::new(None)); | ||
BasicBlock::new(node_index) | ||
} | ||
|
||
pub fn start_new_cleanup_block(&mut self) -> BasicBlock { | ||
let bb = self.start_new_block(); | ||
self[bb].is_cleanup = true; | ||
bb | ||
} | ||
|
||
pub fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) { | ||
debug!("push({:?}, {:?})", block, statement); | ||
self[block].statements.push(statement); | ||
} | ||
|
||
pub fn terminate(&mut self, | ||
block: BasicBlock, | ||
scope: ScopeId, | ||
span: Span, | ||
kind: TerminatorKind<'tcx>) { | ||
debug_assert!(self[block].terminator.is_none(), | ||
"terminate: block {:?} already has a terminator set", block); | ||
self[block].terminator = Some(Terminator { | ||
span: span, | ||
scope: scope, | ||
kind: kind, | ||
}); | ||
} | ||
|
||
pub fn push_assign(&mut self, | ||
block: BasicBlock, | ||
scope: ScopeId, | ||
span: Span, | ||
lvalue: &Lvalue<'tcx>, | ||
rvalue: Rvalue<'tcx>) { | ||
self.push(block, Statement { | ||
scope: scope, | ||
span: span, | ||
kind: StatementKind::Assign(lvalue.clone(), rvalue) | ||
}); | ||
} | ||
|
||
pub fn push_assign_constant(&mut self, | ||
block: BasicBlock, | ||
scope: ScopeId, | ||
span: Span, | ||
temp: &Lvalue<'tcx>, | ||
constant: Constant<'tcx>) { | ||
self.push_assign(block, scope, span, temp, | ||
Rvalue::Use(Operand::Constant(constant))); | ||
} | ||
|
||
pub fn push_assign_unit(&mut self, | ||
block: BasicBlock, | ||
scope: ScopeId, | ||
span: Span, | ||
lvalue: &Lvalue<'tcx>) { | ||
self.push_assign(block, scope, span, lvalue, Rvalue::Aggregate( | ||
AggregateKind::Tuple, vec![] | ||
)); | ||
} | ||
} | ||
|
||
impl<'tcx> Index<BasicBlock> for CFG<'tcx> { | ||
type Output = BasicBlockData<'tcx>; | ||
|
||
#[inline] | ||
fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { | ||
&self.basic_blocks[index.index()] | ||
} | ||
} | ||
|
||
impl<'tcx> IndexMut<BasicBlock> for CFG<'tcx> { | ||
#[inline] | ||
fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> { | ||
&mut self.basic_blocks[index.index()] | ||
} | ||
} | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
use std::fmt::{Debug, Formatter}; | ||
use std::collections::hash_map::Entry; | ||
use std::collections::HashMap; | ||
|
||
pub trait Lattice: Clone { | ||
fn bottom() -> Self; | ||
fn join(&mut self, other: &Self) -> bool; | ||
} | ||
|
||
/// Extend the type with a Top point. | ||
#[derive(Clone, PartialEq)] | ||
pub enum WTop<T> { | ||
Top, | ||
Value(T) | ||
} | ||
|
||
impl<T: Lattice> Lattice for WTop<T> { | ||
fn bottom() -> Self { | ||
WTop::Value(<T as Lattice>::bottom()) | ||
} | ||
|
||
/// V + V = join(v, v) | ||
/// ⊤ + V = ⊤ (no change) | ||
/// V + ⊤ = ⊤ | ||
/// ⊤ + ⊤ = ⊤ (no change) | ||
fn join(&mut self, other: &Self) -> bool { | ||
match (self, other) { | ||
(&mut WTop::Value(ref mut this), &WTop::Value(ref o)) => <T as Lattice>::join(this, o), | ||
(&mut WTop::Top, _) => false, | ||
(this, &WTop::Top) => { | ||
*this = WTop::Top; | ||
true | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl<T: Debug> Debug for WTop<T> { | ||
fn fmt(&self, f: &mut Formatter) -> ::std::fmt::Result { | ||
match *self { | ||
WTop::Top => f.write_str("⊤"), | ||
WTop::Value(ref t) => <T as Debug>::fmt(t, f) | ||
} | ||
} | ||
} | ||
|
||
/// Extend the type with a bottom point | ||
/// | ||
/// This guarantees the bottom() of the underlying lattice won’t get called so it may be | ||
/// implemented as a `panic!()` or something. | ||
#[derive(Clone, PartialEq)] | ||
pub enum WBottom<T> { | ||
Bottom, | ||
Value(T) | ||
} | ||
|
||
impl<T: Lattice> Lattice for WBottom<T> { | ||
fn bottom() -> Self { | ||
WBottom::Bottom | ||
} | ||
|
||
/// V + V = join(v, v) | ||
/// ⊥ + V = V | ||
/// V + ⊥ = V (no change) | ||
/// ⊥ + ⊥ = ⊥ (no change) | ||
fn join(&mut self, other: &Self) -> bool { | ||
match (self, other) { | ||
(&mut WBottom::Value(ref mut this), &WBottom::Value(ref o)) => | ||
<T as Lattice>::join(this, o), | ||
(_, &WBottom::Bottom) => false, | ||
(this, o) => { | ||
*this = o.clone(); | ||
true | ||
} | ||
} | ||
} | ||
|
||
} | ||
|
||
impl<T: Debug> Debug for WBottom<T> { | ||
fn fmt(&self, f: &mut Formatter) -> ::std::fmt::Result { | ||
match *self { | ||
WBottom::Bottom => f.write_str("⊥"), | ||
WBottom::Value(ref t) => <T as Debug>::fmt(t, f) | ||
} | ||
} | ||
} | ||
|
||
/// Extend the type with both bottom and top points. | ||
type WTopBottom<T> = WTop<WBottom<T>>; | ||
|
||
impl<K, T, H> Lattice for HashMap<K, T, H> | ||
where K: Clone + Eq + ::std::hash::Hash, | ||
T: Lattice, | ||
H: Clone + ::std::hash::BuildHasher + ::std::default::Default | ||
{ | ||
fn bottom() -> Self { | ||
HashMap::default() | ||
} | ||
fn join(&mut self, other: &Self) -> bool { | ||
let mut changed = false; | ||
for (key, val) in other.iter() { | ||
match self.entry(key.clone()) { | ||
Entry::Vacant(e) => { | ||
e.insert(val.clone()); | ||
changed = true | ||
} | ||
Entry::Occupied(mut e) => changed |= e.get_mut().join(val) | ||
} | ||
} | ||
changed | ||
} | ||
} | ||
|
||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,4 +49,3 @@ mod hair; | |
pub mod mir_map; | ||
pub mod pretty; | ||
pub mod transform; | ||
pub mod traversal; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,314 @@ | ||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
//! This is Alias-Constant-Simplify propagation pass. This is a composition of three distinct | ||
//! dataflow passes: alias-propagation, constant-propagation and terminator simplification. | ||
//! | ||
//! All these are very similar in their nature: | ||
//! | ||
//! | Constant | Alias | Simplify | | ||
//!|----------------|-----------|----------|-----------| | ||
//!| Lattice Domain | Lvalue | Lvalue | Lvalue | | ||
//!| Lattice Value | Constant | Lvalue | Constant | | ||
//!| Transfer | x = const | x = lval | x = const | | ||
//!| Rewrite | x → const | x → lval | T(x) → T' | | ||
//!| Bottom | {} | {} | {} | | ||
//! | ||
//! For all of them we will be using a lattice of Hashmap from Lvalue to | ||
//! WTop<Either<Lvalue, Constant>> | ||
//! | ||
//! 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 rustc_data_structures::fnv::FnvHashMap; | ||
use rustc::mir::repr::*; | ||
use rustc::mir::visit::{MutVisitor, LvalueContext}; | ||
use rustc::mir::transform::lattice::{Lattice, WBottom}; | ||
use rustc::mir::transform::dataflow::*; | ||
use rustc::mir::transform::{Pass, MirPass, MirSource}; | ||
use rustc::ty::TyCtxt; | ||
use rustc::middle::const_val::ConstVal; | ||
use pretty; | ||
|
||
#[derive(PartialEq, Debug, Eq, Clone)] | ||
enum Either<'tcx> { | ||
Lvalue(Lvalue<'tcx>), | ||
Const(Constant<'tcx>), | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
struct AcsLattice<'tcx> { | ||
known_values: FnvHashMap<Lvalue<'tcx>, Either<'tcx>> | ||
} | ||
|
||
impl<'tcx> Lattice for AcsLattice<'tcx> { | ||
fn bottom() -> Self { unimplemented!() } | ||
fn join(&mut self, other: &Self) -> bool { | ||
let mut to_remove = vec![]; | ||
|
||
for (k, v) in &self.known_values { | ||
if other.known_values.get(k).map_or(true, |other_v| other_v != v) { | ||
to_remove.push(k.clone()); | ||
} | ||
} | ||
|
||
for k in &to_remove { | ||
self.known_values.remove(k); | ||
} | ||
|
||
!to_remove.is_empty() | ||
} | ||
} | ||
|
||
pub struct AcsPropagate; | ||
|
||
impl Pass 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 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); | ||
} | ||
|
||
} | ||
|
||
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<Lvalue<'tcx>, 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); | ||
} | ||
} | ||
|
||
impl<'tcx> Transfer<'tcx> for AcsPropagateTransfer { | ||
type Lattice = WBottom<AcsLattice<'tcx>>; | ||
|
||
fn stmt(&self, s: &Statement<'tcx>, lat: WBottom<AcsLattice<'tcx>>) -> WBottom<AcsLattice<'tcx>> { | ||
let mut lat_map = match lat { | ||
WBottom::Bottom => FnvHashMap::default(), | ||
WBottom::Value(lat) => lat.known_values | ||
}; | ||
|
||
let StatementKind::Assign(ref lval, ref rval) = s.kind; | ||
invalidate(&mut lat_map, base_lvalue(lval)); | ||
|
||
if let &Lvalue::Projection(_) = lval { | ||
return WBottom::Value(AcsLattice { | ||
known_values: lat_map | ||
}); | ||
} | ||
|
||
match *rval { | ||
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())); | ||
}, | ||
_ => { } | ||
}; | ||
|
||
WBottom::Value(AcsLattice { | ||
known_values: lat_map | ||
}) | ||
} | ||
|
||
fn term(&self, t: &Terminator<'tcx>, mut lat: WBottom<AcsLattice<'tcx>>) -> Vec<WBottom<AcsLattice<'tcx>>> { | ||
match t.kind { | ||
TerminatorKind::Call { .. } | | ||
TerminatorKind::Drop { .. } | | ||
TerminatorKind::DropAndReplace { .. } => { | ||
// FIXME: Be smarter here by using an alias analysis | ||
lat = WBottom::Value(AcsLattice { | ||
known_values: 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. | ||
let mut ret = vec![]; | ||
ret.resize(t.successors().len(), lat); | ||
ret | ||
} | ||
} | ||
|
||
struct AliasRewrite; | ||
|
||
impl<'tcx> Rewrite<'tcx, WBottom<AcsLattice<'tcx>>> for AliasRewrite { | ||
fn stmt(&self, s: &Statement<'tcx>, l: &WBottom<AcsLattice<'tcx>>, _: &mut CFG<'tcx>) | ||
-> StatementChange<'tcx> { | ||
if let &WBottom::Value(ref lat) = l { | ||
let mut ns = s.clone(); | ||
let mut vis = RewriteAliasVisitor(&lat.known_values, false); | ||
vis.visit_statement(START_BLOCK, &mut ns); | ||
if vis.1 { | ||
return StatementChange::Statement(ns); | ||
} | ||
} | ||
StatementChange::None | ||
} | ||
|
||
fn term(&self, t: &Terminator<'tcx>, l: &WBottom<AcsLattice<'tcx>>, _: &mut CFG<'tcx>) | ||
-> TerminatorChange<'tcx> { | ||
if let &WBottom::Value(ref lat) = l { | ||
let mut nt = t.clone(); | ||
let mut vis = RewriteAliasVisitor(&lat.known_values, false); | ||
vis.visit_terminator(START_BLOCK, &mut nt); | ||
if vis.1 { | ||
return TerminatorChange::Terminator(nt); | ||
} | ||
} | ||
TerminatorChange::None | ||
} | ||
} | ||
|
||
struct RewriteAliasVisitor<'a, 'tcx: 'a>(&'a FnvHashMap<Lvalue<'tcx>, 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::Consume => { | ||
if let Some(&Either::Lvalue(ref nlval)) = self.0.get(lvalue) { | ||
self.1 = true; | ||
*lvalue = nlval.clone(); | ||
} | ||
}, | ||
_ => { } | ||
} | ||
self.super_lvalue(lvalue, context); | ||
} | ||
} | ||
|
||
struct ConstRewrite; | ||
|
||
impl<'tcx> Rewrite<'tcx, WBottom<AcsLattice<'tcx>>> for ConstRewrite { | ||
fn stmt(&self, s: &Statement<'tcx>, l: &WBottom<AcsLattice<'tcx>>, _: &mut CFG<'tcx>) | ||
-> StatementChange<'tcx> { | ||
if let &WBottom::Value(ref lat) = l { | ||
let mut ns = s.clone(); | ||
let mut vis = RewriteConstVisitor(&lat.known_values, false); | ||
vis.visit_statement(START_BLOCK, &mut ns); | ||
if vis.1 { | ||
return StatementChange::Statement(ns); | ||
} | ||
} | ||
StatementChange::None | ||
} | ||
|
||
fn term(&self, t: &Terminator<'tcx>, l: &WBottom<AcsLattice<'tcx>>, _: &mut CFG<'tcx>) | ||
-> TerminatorChange<'tcx> { | ||
if let &WBottom::Value(ref lat) = l { | ||
let mut nt = t.clone(); | ||
let mut vis = RewriteConstVisitor(&lat.known_values, false); | ||
vis.visit_terminator(START_BLOCK, &mut nt); | ||
if vis.1 { | ||
return TerminatorChange::Terminator(nt); | ||
} | ||
} | ||
TerminatorChange::None | ||
} | ||
} | ||
|
||
struct RewriteConstVisitor<'a, 'tcx: 'a>(&'a FnvHashMap<Lvalue<'tcx>, 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()) | ||
} else { | ||
None | ||
} | ||
} else { | ||
None | ||
}; | ||
if let Some(c) = repl { | ||
self.1 = true; | ||
*op = Operand::Constant(c); | ||
} | ||
|
||
self.super_operand(op); | ||
} | ||
} | ||
|
||
|
||
struct SimplifyRewrite; | ||
|
||
impl<'tcx, L: Lattice> Rewrite<'tcx, L> for SimplifyRewrite { | ||
fn stmt(&self, _: &Statement<'tcx>, _: &L, _: &mut CFG<'tcx>) | ||
-> StatementChange<'tcx> { | ||
StatementChange::None | ||
} | ||
|
||
fn term(&self, t: &Terminator<'tcx>, _: &L, _: &mut CFG<'tcx>) | ||
-> TerminatorChange<'tcx> { | ||
match t.kind { | ||
TerminatorKind::If { ref targets, .. } if targets.0 == targets.1 => { | ||
let mut nt = t.clone(); | ||
nt.kind = TerminatorKind::Goto { target: targets.0 }; | ||
TerminatorChange::Terminator(nt) | ||
} | ||
TerminatorKind::If { ref targets, cond: Operand::Constant(Constant { | ||
literal: Literal::Value { | ||
value: ConstVal::Bool(cond) | ||
}, .. | ||
}) } => { | ||
let mut nt = t.clone(); | ||
if cond { | ||
nt.kind = TerminatorKind::Goto { target: targets.0 }; | ||
} else { | ||
nt.kind = TerminatorKind::Goto { target: targets.1 }; | ||
} | ||
TerminatorChange::Terminator(nt) | ||
} | ||
TerminatorKind::SwitchInt { ref targets, .. } if targets.len() == 1 => { | ||
let mut nt = t.clone(); | ||
nt.kind = TerminatorKind::Goto { target: targets[0] }; | ||
TerminatorChange::Terminator(nt) | ||
} | ||
_ => TerminatorChange::None | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,7 +42,7 @@ pub struct RemoveDeadBlocks; | |
impl<'tcx> MirPass<'tcx> for RemoveDeadBlocks { | ||
fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, | ||
_: MirSource, mir: &mut Mir<'tcx>) { | ||
let mut seen = BitVector::new(mir.basic_blocks.len()); | ||
let mut seen = BitVector::new(mir.cfg.basic_blocks.len()); | ||
// This block is always required. | ||
seen.insert(START_BLOCK.index()); | ||
|
||
|
@@ -63,7 +63,7 @@ impl Pass for RemoveDeadBlocks {} | |
|
||
/// Mass removal of basic blocks to keep the ID-remapping cheap. | ||
fn retain_basic_blocks(mir: &mut Mir, keep: &BitVector) { | ||
let num_blocks = mir.basic_blocks.len(); | ||
let num_blocks = mir.cfg.basic_blocks.len(); | ||
|
||
let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); | ||
let mut used_blocks = 0; | ||
|
@@ -72,11 +72,11 @@ fn retain_basic_blocks(mir: &mut Mir, keep: &BitVector) { | |
if alive_index != used_blocks { | ||
// Swap the next alive block data with the current available slot. Since alive_index is | ||
// non-decreasing this is a valid operation. | ||
mir.basic_blocks.swap(alive_index, used_blocks); | ||
mir.cfg.basic_blocks.swap(alive_index, used_blocks); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer having |
||
} | ||
used_blocks += 1; | ||
} | ||
mir.basic_blocks.truncate(used_blocks); | ||
mir.cfg.basic_blocks.truncate(used_blocks); | ||
|
||
for bb in mir.all_basic_blocks() { | ||
for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() { | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be reasonable to just add this as a method on
Lvalue
since other transformations will almost certainly find it useful as well.