/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see http://www.gnu.org/licenses/. */
package EDU.purdue.cs.bloat.trans;
import java.util.*;
import EDU.purdue.cs.bloat.cfg.*;
import EDU.purdue.cs.bloat.tree.*;
/**
* Performs copy and constant propagation on the blocks in a control flow graph.
*/
public class ExprPropagation {
public static boolean DEBUG = false;
FlowGraph cfg;
boolean changed; // Did the cfg change?
/**
* Constructor.
*
* @param cfg
* The control flow graph on which expression propagation is
* being performed.
*/
public ExprPropagation(final FlowGraph cfg) {
this.cfg = cfg;
}
/**
* Performs the propagation.
*/
public void transform() {
changed = true;
while (changed) {
changed = false;
propagate();
}
}
/**
* Propagate expressions through the control flow graph in hopes of reducing
* the number of local variables.
*/
private void propagate() {
cfg.visit(new TreeVisitor() {
Iterator iter;
public void visitTree(final Tree tree) {
iter = tree.stmts().iterator();
while (iter.hasNext()) {
final Stmt stmt = (Stmt) iter.next();
stmt.visit(this);
}
}
public void visitStoreExpr(final StoreExpr expr) {
expr.visitChildren(this);
if (!(expr.target() instanceof LocalExpr)) {
// If we're not assigning to a local variable, fergit it
return;
}
final LocalExpr lhs = (LocalExpr) expr.target();
final Expr rhs = expr.expr();
// L := (M := E)
// use L
// use M
//
// -->
//
// L := E
// use L
// use L
//
// Since we've already visited (M := E), M could not be
// eliminated. So, after propagating M to L, we won't be
// able to eliminate L either, so don't even try.
//
if (rhs instanceof StoreExpr) {
final StoreExpr store = (StoreExpr) rhs;
final MemExpr rhsLHS = store.target();
final Expr rhsRHS = store.expr();
if (rhsLHS instanceof LocalExpr) {
// Replace uses of M with L.
// We need to make a copy of the lhs since it is a
// def an consequently does not contain a pointer to
// a def.
final LocalExpr copy = (LocalExpr) lhs.clone();
copy.setDef(lhs);
if (propExpr(expr.block(), (LocalExpr) rhsLHS, copy)) {
// If all uses of the rhsRHS local variable were
// replaced, replace all occurrences of the rhs with
// the
// local variable of rhsRHS.
changed = true;
expr.visit(new ReplaceVisitor(rhs, rhsRHS));
rhsLHS.cleanup();
rhs.cleanupOnly();
}
// Be sure to cleanup the copy.
copy.cleanup();
}
}
// This next part is awful and comented out. Propagating
// local variables like this fails to take into account
// the live ranges. When we have L := M, it replaces L with
// M after M has been overwritten. Arg.
/*
* else if (rhs instanceof LeafExpr) { if
* (propExpr(expr.block(), lhs, rhs)) { // If all uses of the
* local variable in the lhs were // replaced with the LeafExpr
* in the rhs, then the store // (L := X) is useless. Replace it
* with (eval X) so it // can be removed later. changed = true;
* // Replace eval (L := X) with eval X // Dead code
* elimination will remove it. if (expr.parent() instanceof
* ExprStmt) iter.remove(); else expr.replaceWith((Expr)
* rhs.clone()); } }
*/
}
public void visitPhiStmt(final PhiStmt stmt) {
final Expr lhs = stmt.target();
if (!(lhs instanceof LocalExpr)) {
// If we're not assigning into a local variable, fergit it
return;
}
// Look at all of the operands of the PhiStmt. If all of the
// operands are either the same local variable or the same
// constant, then propagate an operand (doesn't matter which
// one because they're all the same value) to all uses of the
// target of the PhiStmt.
final Iterator e = stmt.operands().iterator();
if (!e.hasNext()) {
return;
}
final Expr rhs = (Expr) e.next();
if (!(rhs instanceof LeafExpr)) {
return;
}
while (e.hasNext()) {
final Expr operand = (Expr) e.next();
if (rhs instanceof LocalExpr) {
if (operand instanceof LocalExpr) {
if (rhs.def() != operand.def()) {
return;
}
} else {
return;
}
} else if (rhs instanceof ConstantExpr) {
if (!rhs.equalsExpr(operand)) {
return;
}
} else {
return;
}
}
if (propExpr(stmt.block(), (LocalExpr) lhs, rhs)) {
// If all uses of the PhiStmt's target were replaced, remove
// it from the expression tree.
changed = true;
iter.remove();
}
}
});
}
/**
* Propagates the expression in rhs to all uses of the lhs. Returns true, if
* all of the uses of the lhs were replaced.
*/
boolean propExpr(final Block block, final LocalExpr lhs, final Expr rhs) {
if (ExprPropagation.DEBUG) {
System.out.println("prop " + rhs + " to uses of " + lhs);
System.out.println(" uses of lhs = " + lhs.uses());
}
if (rhs instanceof LocalExpr) {
// We can't prop a local to a PhiStmt operand, so don't bother
// doing the propagation at all.
Iterator e = lhs.uses().iterator();
while (e.hasNext()) {
final LocalExpr use = (LocalExpr) e.next();
if (use.parent() instanceof PhiStmt) {
return false;
}
}
// Replaces all uses of the lhs with the rhs. Both are local
// variables.
e = lhs.uses().iterator();
while (e.hasNext()) {
final LocalExpr use = (LocalExpr) e.next();
use.replaceWith((Expr) rhs.clone());
}
return true;
} else {
boolean replacedAll = true;
final Iterator e = lhs.uses().iterator();
while (e.hasNext()) {
final LocalExpr use = (LocalExpr) e.next();
if (use.parent() instanceof PhiCatchStmt) {
replacedAll = false;
} else {
use.replaceWith((Expr) rhs.clone());
}
}
return replacedAll;
}
}
}