1 cananian 1.1.2.1 // Prune.java, created Fri Jun 30 19:15:56 2000 by cananian 2 cananian 1.1.2.1 // Copyright (C) 2000 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.2.1 package harpoon.IR.Quads; 5 cananian 1.1.2.1 6 cananian 1.1.2.1 import harpoon.ClassFile.HCode; 7 cananian 1.1.2.1 import harpoon.Temp.Temp; 8 cananian 1.7 import net.cscott.jutil.BitSetFactory; 9 cananian 1.7 import net.cscott.jutil.SetFactory; 10 cananian 1.7 import net.cscott.jutil.UniqueVector; 11 cananian 1.1.2.1 import harpoon.Util.Util; 12 cananian 1.1.2.1 import java.util.HashMap; 13 cananian 1.1.2.1 import java.util.HashSet; 14 cananian 1.1.2.1 import java.util.Iterator; 15 cananian 1.1.2.1 import java.util.Map; 16 cananian 1.1.2.1 import java.util.Set; 17 cananian 1.1.2.1 /** 18 cananian 1.1.2.1 * <code>Prune</code> quickly prunes dead variable assignments from the 19 cananian 1.1.2.1 * quad graph. It doesn't do a full liveness analysis, so it doesn't 20 cananian 1.1.2.1 * get *everything*, but it works in linear time (well, O(EV) time) 21 cananian 1.1.2.1 * and gets most of the egregious dead vars. 22 cananian 1.1.2.1 * 23 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 24 cananian 1.8 * @version $Id: Prune.java,v 1.8 2004/02/08 03:21:24 cananian Exp $ 25 cananian 1.1.2.1 */ 26 cananian 1.1.2.1 class Prune { 27 cananian 1.1.2.1 private final static boolean DEBUG=false; 28 cananian 1.1.2.1 29 cananian 1.1.2.1 /** one one can create an instance of this class */ 30 cananian 1.1.2.1 private Prune() { } 31 cananian 1.1.2.1 32 cananian 1.1.2.1 /** Remove quads which do nothing but define dead variables from 33 cananian 1.1.2.1 * the CFG. */ 34 cananian 1.1.2.1 static void prune(HCode hc) { 35 cananian 1.1.2.1 // the State object does the analysis. 36 cananian 1.1.2.1 State s = new State(hc); 37 cananian 1.1.2.1 // now trim out useless quads. 38 cananian 1.8 for (Object qO : s.useless) { 39 cananian 1.8 Quad q = (Quad) qO; 40 cananian 1.1.2.1 if (DEBUG) System.err.println("PRUNING: #"+q.getID()+" "+q); 41 cananian 1.3.2.1 assert q.nextLength()==1 && q.prevLength()==1; 42 cananian 1.1.2.1 Edge fromE = q.prevEdge(0), toE = q.nextEdge(0); 43 cananian 1.1.2.1 Quad.addEdge((Quad)fromE.from(), fromE.which_succ(), 44 cananian 1.1.2.1 (Quad)toE.to(), toE.which_pred()); 45 cananian 1.1.2.1 } 46 cananian 1.1.2.1 // done! 47 cananian 1.1.2.1 } 48 cananian 1.1.2.1 49 cananian 1.1.2.1 private static class State { 50 cananian 1.1.2.1 private final SetFactory sf; 51 cananian 1.1.2.1 private final Map seen = new HashMap(); 52 cananian 1.1.2.1 private final Set EMPTY_SET, FULL_SET; 53 cananian 1.1.2.1 /** useless quads, as determined by our analysis. */ 54 cananian 1.1.2.1 final Set useless = new HashSet(); 55 cananian 1.1.2.1 State(HCode hc) { 56 cananian 1.1.2.1 // create Temp universe. 57 cananian 1.1.2.1 Set universe = new HashSet(); 58 cananian 1.1.2.1 for (Iterator it=hc.getElementsI(); it.hasNext(); ) { 59 cananian 1.1.2.1 Quad q = (Quad) it.next(); 60 cananian 1.1.2.1 universe.addAll(q.defC()); 61 cananian 1.1.2.1 universe.addAll(q.useC()); 62 cananian 1.1.2.1 } 63 cananian 1.1.2.1 // create BitSetFactory 64 cananian 1.1.2.1 this.sf = new BitSetFactory(universe, Temp.INDEXER); 65 cananian 1.1.2.1 this.EMPTY_SET = sf.makeSet(); 66 cananian 1.1.2.1 this.FULL_SET = sf.makeSet(universe); 67 cananian 1.1.2.1 // okay, do the thing that we do. 68 cananian 1.5 // This command will suffice: 69 cananian 1.5 //------------------------------------- 70 cananian 1.5 //knownDeadInto((Quad)hc.getRootElement()); 71 cananian 1.5 //------------------------------------- 72 cananian 1.5 // Instead of directly doing the above, we're going to 73 cananian 1.5 // first visit all PHIs in post-order DFS. This will 74 cananian 1.5 // limit the amount of on-stack recursion required for 75 cananian 1.5 // the algorithm, without changing any of the results. 76 cananian 1.5 // (or the running time, hopefully!) 77 cananian 1.5 78 cananian 1.5 UniqueVector worklist = new UniqueVector(); 79 cananian 1.6 // order nodes in reverse post-order. 80 cananian 1.5 worklist.add(hc.getRootElement()); 81 cananian 1.5 for (int i=0; i<worklist.size(); i++) { 82 cananian 1.5 Quad q = (Quad) worklist.get(i); 83 cananian 1.6 for (int j=q.nextLength()-1; j>=0; j--) 84 cananian 1.5 worklist.add(q.next(j)); 85 cananian 1.5 } 86 cananian 1.6 // reverse order of worklist to get post-order dfs. 87 cananian 1.5 // so, do knownDeadInto() in that order. 88 cananian 1.5 for (int i=worklist.size()-1; i>=0; i--) { 89 cananian 1.5 Quad q = (Quad) worklist.get(i); 90 cananian 1.5 if (q instanceof PHI || q instanceof HEADER) 91 cananian 1.5 knownDeadInto(q); 92 cananian 1.5 } 93 cananian 1.5 94 cananian 1.1.2.1 // now we've got a useless set. 95 cananian 1.1.2.1 } 96 cananian 1.1.2.1 97 cananian 1.1.2.1 /** main body of the analysis is a post-order dfs search */ 98 cananian 1.1.2.1 private Set knownDeadInto(Quad q) { 99 cananian 1.1.2.1 if (seen.containsKey(q)) return sf.makeSet((Set) seen.get(q)); 100 cananian 1.1.2.1 if (q.prevLength()>1) seen.put(q, EMPTY_SET); 101 cananian 1.1.2.3 Set r = (q.nextLength()<1) ? sf.makeSet(FULL_SET) : 102 cananian 1.1.2.3 knownDeadInto(q.next(0)); 103 cananian 1.1.2.3 for (int i=1; i<q.nextLength(); i++) 104 cananian 1.1.2.3 r.retainAll(knownDeadInto(q.next(i))); 105 cananian 1.1.2.1 // now we have the knownDeadOutOf set. 106 cananian 1.1.2.1 if (isUseless(q, r)) useless.add(q); 107 cananian 1.1.2.1 // construct knownDeadInto set: 108 cananian 1.1.2.1 // all defs of this instr are known dead into this. 109 cananian 1.1.2.1 r.addAll(q.defC()); 110 cananian 1.1.2.1 // all uses of this instr are live into this. 111 cananian 1.1.2.1 // (note that the simpler r.removeAll(q.useC()) uses time 112 cananian 1.1.2.1 // proportional to the size of *r*, which is not what we want) 113 cananian 1.1.2.1 for (Iterator it=q.useC().iterator(); it.hasNext(); ) 114 cananian 1.1.2.1 r.remove(it.next()); 115 cananian 1.1.2.1 if (DEBUG) 116 cananian 1.1.2.1 System.err.println("DEAD INTO #"+q.getID()+" is "+r+ 117 cananian 1.1.2.1 " (using "+q.useC()+")"); 118 cananian 1.1.2.1 // if this is a phi, record the set. 119 cananian 1.1.2.1 if (q.prevLength()>1) seen.put(q, sf.makeSet(r)); 120 cananian 1.1.2.1 // okay, this is it! 121 cananian 1.1.2.1 return r; 122 cananian 1.1.2.1 } 123 cananian 1.1.2.1 124 cananian 1.1.2.1 private static boolean isUseless(Quad q, Set knownDeadOut) { 125 cananian 1.1.2.1 // quads defining live variables are not useless. 126 cananian 1.1.2.1 if (!knownDeadOut.containsAll(q.defC())) return false; 127 cananian 1.1.2.1 // also, quads with side effects are not useless. 128 cananian 1.1.2.1 if (q instanceof ARRAYINIT || q instanceof ASET || 129 cananian 1.1.2.1 q instanceof SIGMA || q instanceof PHI || 130 cananian 1.1.2.1 q instanceof DEBUG || q instanceof HANDLER || 131 cananian 1.1.2.1 q instanceof HEADER || q instanceof FOOTER || 132 cananian 1.1.2.1 q instanceof LABEL || q instanceof METHOD || 133 cananian 1.1.2.1 q instanceof MONITORENTER || q instanceof MONITOREXIT || 134 cananian 1.1.2.1 q instanceof TYPECAST || q instanceof RETURN || 135 cananian 1.1.2.1 q instanceof SET || q instanceof THROW) 136 cananian 1.1.2.1 return false; 137 cananian 1.1.2.1 // otherwise, it's useless! 138 cananian 1.1.2.1 if (DEBUG) 139 cananian 1.1.2.1 System.err.println("#"+q.getID()+" is useless because all of "+ 140 cananian 1.1.2.1 q.defC()+" are in "+knownDeadOut); 141 cananian 1.1.2.1 return true; 142 cananian 1.1.2.1 } 143 cananian 1.1.2.1 } 144 cananian 1.2 }