package polyglot.visit; import polyglot.ast.*; import polyglot.frontend.Job; import polyglot.main.Report; import polyglot.types.*; import polyglot.util.InternalCompilerError; import polyglot.util.Position; import java.util.*; /** * Visitor which performs dead code elimination. */ public class DeadCodeEliminator extends DataFlow { public DeadCodeEliminator(Job job, TypeSystem ts, NodeFactory nf) { super(job, ts, nf, false /* backward analysis */, true /* perform dataflow on entry to CodeDecls */); } protected static class DataFlowItem extends Item { // Set of LocalInstances of live variables. private Set liveVars; // Set of LocalInstances of live declarations. A LocalDecl is live if // the declared local is ever live. private Set liveDecls; /** * Constructor for creating an empty set. */ protected DataFlowItem() { this.liveVars = new HashSet(); this.liveDecls = new HashSet(); } /** * Deep copy constructor. */ protected DataFlowItem(DataFlowItem dfi) { liveVars = new HashSet(dfi.liveVars); liveDecls = new HashSet(dfi.liveDecls); } public void add(LocalInstance li) { liveVars.add(li); liveDecls.add(li); } public void addAll(Set lis) { liveVars.addAll(lis); liveDecls.addAll(lis); } public void remove(LocalInstance li) { liveVars.remove(li); } public void removeAll(Set lis) { liveVars.removeAll(lis); } public void removeDecl(LocalInstance li) { liveVars.remove(li); liveDecls.remove(li); } public void union(DataFlowItem dfi) { liveVars.addAll(dfi.liveVars); liveDecls.addAll(dfi.liveDecls); } protected boolean needDecl(LocalInstance li) { return liveDecls.contains(li); } protected boolean needDef(LocalInstance li) { return liveVars.contains(li); } public int hashCode() { int result = 0; for (Iterator it = liveVars.iterator(); it.hasNext(); ) { result = 31*result + it.next().hashCode(); } for (Iterator it = liveDecls.iterator(); it.hasNext(); ) { result = 31*result + it.next().hashCode(); } return result; } public boolean equals(Object o) { if (!(o instanceof DataFlowItem)) return false; DataFlowItem dfi = (DataFlowItem)o; return liveVars.equals(dfi.liveVars) && liveDecls.equals(dfi.liveDecls); } public String toString() { return "<vars=" + liveVars + " ; decls=" + liveDecls + ">"; } } public Item createInitialItem(FlowGraph graph, Term node) { return new DataFlowItem(); } public Item confluence(List inItems, Term node, FlowGraph graph) { DataFlowItem result = null; for (Iterator it = inItems.iterator(); it.hasNext(); ) { DataFlowItem inItem = (DataFlowItem)it.next(); if (result == null) { result = new DataFlowItem(inItem); } else { result.union(inItem); } } return result; } public Map flow(Item in, FlowGraph graph, Term t, Set succEdgeKeys) { return itemToMap(flow(in, graph, t), succEdgeKeys); } protected DataFlowItem flow(Item in, FlowGraph graph, Term t) { DataFlowItem result = new DataFlowItem((DataFlowItem)in); Set[] du = null; if (t instanceof LocalDecl) { LocalDecl n = (LocalDecl)t; LocalInstance to = n.localInstance(); result.removeDecl(to); du = getDefUse(n.init()); } else if (t instanceof Stmt && !(t instanceof CompoundStmt)) { du = getDefUse((Stmt)t); } else if (t instanceof CompoundStmt) { if (t instanceof If) { du = getDefUse(((If)t).cond()); } else if (t instanceof Switch) { du = getDefUse(((Switch)t).expr()); } else if (t instanceof Do) { du = getDefUse(((Do)t).cond()); } else if (t instanceof For) { du = getDefUse(((For)t).cond()); } else if (t instanceof While) { du = getDefUse(((While)t).cond()); } } if (du != null) { result.removeAll(du[0]); result.addAll(du[1]); } return result; } public void post(FlowGraph graph, Term root) throws SemanticException { // No need to do any checking. if (Report.should_report(Report.cfg, 2)) { dumpFlowGraph(graph, root); } } public void check(FlowGraph graph, Term n, Item inItem, Map outItems) throws SemanticException { throw new InternalCompilerError("DeadCodeEliminator.check should " + "never be called."); } private DataFlowItem getItem(Term n) { FlowGraph g = currentFlowGraph(); if (g == null) return null; Collection peers = g.peers(n); if (peers == null || peers.isEmpty()) return null; List items = new ArrayList(); for (Iterator it = peers.iterator(); it.hasNext(); ) { FlowGraph.Peer p = (FlowGraph.Peer)it.next(); if (p.inItem() != null) items.add(p.inItem()); } return (DataFlowItem)confluence(items, n, g); } public Node leaveCall(Node old, Node n, NodeVisitor v) throws SemanticException { if (n instanceof LocalDecl) { LocalDecl ld = (LocalDecl)n; DataFlowItem in = getItem(ld); if (in == null || in.needDecl(ld.localInstance())) return n; return getEffects(ld.init()); } if (n instanceof Eval) { Eval eval = (Eval)n; Expr expr = eval.expr(); Local local; Expr right = null; if (expr instanceof Assign) { Assign assign = (Assign)expr; Expr left = assign.left(); right = assign.right(); if (!(left instanceof Local)) return n; local = (Local)left; } else if (expr instanceof Unary) { Unary unary = (Unary)expr; expr = unary.expr(); if (!(expr instanceof Local)) return n; local = (Local)expr; } else { return n; } DataFlowItem in = getItem(eval); if (in == null || in.needDef(local.localInstance())) return n; if (right != null) { return getEffects(right); } return nf.Empty(Position.COMPILER_GENERATED); } if (n instanceof Block) { // Get rid of empty statements. Block b = (Block)n; List stmts = new ArrayList(b.statements()); for (Iterator it = stmts.iterator(); it.hasNext(); ) { if (it.next() instanceof Empty) it.remove(); } return b.statements(stmts); } return n; } /** * Returns array of sets of local instances. * Element 0 is the set of local instances DEFined by the node. * Element 1 is the set of local instances USEd by the node. */ protected Set[] getDefUse(Node n) { final Set def = new HashSet(); final Set use = new HashSet(); if (n != null) { n.visit(createDefUseFinder(def, use)); } return new Set[] {def, use}; } protected NodeVisitor createDefUseFinder(Set def, Set use) { return new DefUseFinder(def, use); } protected static class DefUseFinder extends HaltingVisitor { protected Set def; protected Set use; public DefUseFinder(Set def, Set use) { this.def = def; this.use = use; } public NodeVisitor enter(Node n) { if (n instanceof LocalAssign) { return bypass(((Assign)n).left()); } return super.enter(n); } public Node leave(Node old, Node n, NodeVisitor v) { if (n instanceof Local) { use.add(((Local)n).localInstance()); } else if (n instanceof Assign) { Expr left = ((Assign)n).left(); if (left instanceof Local) { def.add(((Local)left).localInstance()); } } return n; } } /** * Returns a statement that is side-effect-equivalent to the given * expression. */ protected Stmt getEffects(Expr expr) { Stmt empty = nf.Empty(Position.COMPILER_GENERATED); if (expr == null) return empty; final List result = new LinkedList(); final Position pos = Position.COMPILER_GENERATED; NodeVisitor v = new HaltingVisitor() { public NodeVisitor enter(Node n) { if (n instanceof Assign || n instanceof ProcedureCall) { return bypassChildren(n); } // XXX Cast if (n instanceof Unary) { Unary.Operator op = ((Unary)n).operator(); if (op == Unary.POST_INC || op == Unary.POST_DEC || op == Unary.PRE_INC || op == Unary.PRE_INC) { return bypassChildren(n); } } return this; } public Node leave(Node old, Node n, NodeVisitor v) { if (n instanceof Assign || n instanceof ProcedureCall) { result.add(nf.Eval(pos, (Expr)n)); } else if (n instanceof Unary) { Unary.Operator op = ((Unary)n).operator(); if (op == Unary.POST_INC || op == Unary.POST_DEC || op == Unary.PRE_INC || op == Unary.PRE_INC) { result.add(nf.Eval(pos, (Expr)n)); } } // XXX Cast return n; } }; expr.visit(v); if (result.isEmpty()) return empty; if (result.size() == 1) return (Stmt)result.get(0); return nf.Block(Position.COMPILER_GENERATED, result); } }