1 cananian 1.1.2.1 // SCCOptimize.java, created Sun Sep 20 21:41:44 1998 by cananian 2 cananian 1.1.2.1 // Copyright (C) 1998 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.Analysis.Quads.SCC; 5 cananian 1.1.2.1 6 cananian 1.1.2.1 import harpoon.Analysis.Maps.ConstMap; 7 cananian 1.1.2.1 import harpoon.Analysis.Maps.ExecMap; 8 cananian 1.1.2.1 import harpoon.Analysis.Maps.TypeMap; 9 cananian 1.1.2.1 import harpoon.Analysis.Maps.UseDefMap; 10 cananian 1.1.2.1 import harpoon.Analysis.Quads.DeadCode; 11 cananian 1.1.2.4 import harpoon.ClassFile.HClass; 12 cananian 1.1.2.4 import harpoon.ClassFile.HCode; 13 cananian 1.1.2.4 import harpoon.ClassFile.HCodeEdge; 14 cananian 1.1.2.4 import harpoon.ClassFile.HCodeElement; 15 cananian 1.1.2.4 import harpoon.ClassFile.HCodeFactory; 16 cananian 1.1.2.4 import harpoon.ClassFile.HMethod; 17 cananian 1.1.2.11 import harpoon.IR.Quads.CALL; 18 cananian 1.1.2.4 import harpoon.IR.Quads.CONST; 19 cananian 1.1.2.4 import harpoon.IR.Quads.Edge; 20 cananian 1.1.2.4 import harpoon.IR.Quads.FOOTER; 21 cananian 1.1.2.10 import harpoon.IR.Quads.METHOD; 22 cananian 1.1.2.4 import harpoon.IR.Quads.MOVE; 23 cananian 1.1.2.4 import harpoon.IR.Quads.PHI; 24 cananian 1.1.2.4 import harpoon.IR.Quads.Quad; 25 cananian 1.1.2.4 import harpoon.IR.Quads.QuadFactory; 26 cananian 1.1.2.4 import harpoon.IR.Quads.QuadVisitor; 27 cananian 1.1.2.4 import harpoon.IR.Quads.SIGMA; 28 cananian 1.1.2.13 import harpoon.IR.Quads.SWITCH; 29 cananian 1.1.2.7 import harpoon.IR.Quads.TYPESWITCH; 30 cananian 1.1.2.1 import harpoon.Temp.Temp; 31 cananian 1.6 import net.cscott.jutil.SnapshotIterator; 32 cananian 1.1.2.1 import harpoon.Util.Util; 33 cananian 1.1.2.5 34 cananian 1.1.2.7 import java.util.ArrayList; 35 cananian 1.1.2.5 import java.util.HashSet; 36 cananian 1.5 import java.util.Iterator; 37 cananian 1.1.2.7 import java.util.List; 38 cananian 1.1.2.5 import java.util.Set; 39 cananian 1.1.2.1 /** 40 cananian 1.1.2.1 * <code>SCCOptimize</code> optimizes the code after <code>SCCAnalysis</code>. 41 cananian 1.1.2.1 * The optimization invalidates the <code>ExecMap</code> used. 42 cananian 1.1.2.1 * All edges in the graph after optimization are executable. 43 cananian 1.1.2.12 * (Edges leaving a <code>CALL</code> quad may be an exception if your 44 cananian 1.1.2.12 * <code>ExecMap</code> marks one or both of the edges leaving the 45 cananian 1.1.2.12 * <code>CALL</code> non-executable.) 46 cananian 1.1.2.1 * 47 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 48 cananian 1.6 * @version $Id: SCCOptimize.java,v 1.6 2004/02/08 01:53:44 cananian Exp $ 49 cananian 1.1.2.1 */ 50 cananian 1.1.2.9 public final class SCCOptimize implements ExecMap { 51 cananian 1.1.2.1 TypeMap ti; 52 cananian 1.1.2.1 ConstMap cm; 53 cananian 1.1.2.1 ExecMap em; 54 cananian 1.1.2.1 55 cananian 1.1.2.1 /** Creates an <code>SCCOptimize</code>. */ 56 cananian 1.1.2.1 public SCCOptimize(TypeMap ti, ConstMap cm, ExecMap em) { 57 cananian 1.1.2.1 this.ti = ti; 58 cananian 1.1.2.1 this.cm = cm; 59 cananian 1.1.2.1 this.em = em; 60 cananian 1.1.2.1 } 61 cananian 1.1.2.1 public SCCOptimize(SCCAnalysis scc) { this(scc, scc, scc); } 62 cananian 1.1.2.1 63 cananian 1.1.2.1 /** Returns a code factory that uses SCCOptimize. */ 64 cananian 1.1.2.1 public static HCodeFactory codeFactory(final HCodeFactory parent) { 65 cananian 1.1.2.1 return new HCodeFactory() { 66 cananian 1.1.2.1 public HCode convert(HMethod m) { 67 cananian 1.1.2.1 HCode hc = parent.convert(m); 68 cananian 1.1.2.1 if (hc!=null) { 69 cananian 1.1.2.1 harpoon.Analysis.UseDef ud = new harpoon.Analysis.UseDef(); 70 cananian 1.1.2.1 (new SCCOptimize(new SCCAnalysis(hc, ud))).optimize(hc); 71 cananian 1.1.2.1 } 72 cananian 1.1.2.1 return hc; 73 cananian 1.1.2.1 } 74 cananian 1.1.2.1 public String getCodeName() { return parent.getCodeName(); } 75 cananian 1.1.2.1 public void clear(HMethod m) { parent.clear(m); } 76 cananian 1.1.2.1 }; 77 cananian 1.1.2.1 } 78 cananian 1.1.2.1 79 cananian 1.1.2.1 Set Ee = new HashSet(); 80 cananian 1.1.2.9 public boolean execMap(HCodeEdge e) { 81 cananian 1.1.2.1 if (Ee.contains(e)) return true; 82 cananian 1.1.2.1 else return em.execMap(e); 83 cananian 1.1.2.1 } 84 cananian 1.1.2.9 public boolean execMap(HCodeElement node) { 85 cananian 1.1.2.3 HCodeEdge[] pred = ((harpoon.IR.Properties.CFGraphable)node).pred(); 86 cananian 1.1.2.1 for (int i=0; i<pred.length; i++) 87 cananian 1.1.2.1 if (execMap(pred[i])) 88 cananian 1.1.2.1 return true; 89 cananian 1.1.2.1 return false; 90 cananian 1.1.2.1 } 91 cananian 1.1.2.1 92 cananian 1.1.2.1 // Utility class 93 cananian 1.1.2.1 private CONST newCONST(QuadFactory qf, HCodeElement source, 94 cananian 1.1.2.1 Temp dst, Object val, HClass type) { 95 cananian 1.1.2.1 if (type==HClass.Boolean) type=HClass.Int; 96 cananian 1.1.2.1 return new CONST(qf, source, dst, val, type); 97 cananian 1.1.2.1 } 98 cananian 1.1.2.1 99 cananian 1.1.2.1 public void optimize(final HCode hc) { 100 cananian 1.1.2.1 101 cananian 1.1.2.1 QuadVisitor visitor = new QuadVisitor() { 102 cananian 1.1.2.1 public void visit(Quad q) { 103 cananian 1.1.2.1 // if all defs are constants, replace the statement 104 cananian 1.1.2.1 // with a series of CONSTs. 105 cananian 1.1.2.1 Temp d[] = q.def(); 106 cananian 1.1.2.1 if (d.length == 0) return; // nothing to do here. 107 cananian 1.1.2.1 int i; for (i=0; i<d.length; i++) 108 cananian 1.1.2.1 if (!cm.isConst(q, d[i])) 109 cananian 1.1.2.1 break; 110 cananian 1.1.2.1 if (i!=d.length) // not all args are constant 111 cananian 1.1.2.1 return; 112 cananian 1.1.2.1 113 cananian 1.1.2.1 // ok. Replace with a series of CONSTs. 114 cananian 1.3.2.1 assert q.next().length==1 && q.prev().length==1; 115 cananian 1.1.2.1 Quad header = q.prev(0); 116 cananian 1.1.2.1 int which_succ = q.prevEdge(0).which_succ(); 117 cananian 1.1.2.1 Quad successor = q.next(0); 118 cananian 1.1.2.1 int which_pred = q.nextEdge(0).which_pred(); 119 cananian 1.1.2.1 120 cananian 1.1.2.1 for (i=0; i<d.length; i++) { 121 cananian 1.1.2.1 Quad qq = newCONST(q.getFactory(), q, d[i], 122 cananian 1.1.2.1 cm.constMap(q, d[i]), 123 cananian 1.1.2.1 ti.typeMap(q, d[i]) ); 124 cananian 1.1.2.1 Quad.addEdge(header, which_succ, qq, 0); 125 cananian 1.1.2.5 Ee.add(header.nextEdge(which_succ)); 126 cananian 1.1.2.1 header = qq; which_succ = 0; 127 cananian 1.1.2.1 } 128 cananian 1.1.2.1 // link to successor. 129 cananian 1.1.2.1 Quad.addEdge(header, which_succ, successor, which_pred); 130 cananian 1.1.2.5 Ee.add(header.nextEdge(which_succ)); 131 cananian 1.1.2.1 // done. 132 cananian 1.1.2.1 } // END VISIT quad. 133 cananian 1.1.2.1 public void visit(CONST q) { /* do nothing. */ } 134 cananian 1.1.2.11 public void visit(METHOD q) { 135 cananian 1.1.2.11 // can't optimize if entire method is not executable. 136 cananian 1.3.2.1 assert execMap(q) && execMap(q.nextEdge(0)); 137 cananian 1.1.2.11 /* do nothing. */ 138 cananian 1.1.2.11 } 139 cananian 1.1.2.1 public void visit(FOOTER q) { 140 cananian 1.1.2.1 // remove unexecutable FOOTER edges. 141 cananian 1.1.2.1 FOOTER newF = q; 142 cananian 1.1.2.1 Edge[] prv = q.prevEdge(); 143 cananian 1.1.2.1 for (int i=prv.length-1; i>=0; i--) 144 cananian 1.1.2.1 if (!execMap(prv[i])) 145 cananian 1.1.2.1 newF = newF.remove(i); 146 cananian 1.1.2.1 // add new executable edges to set. 147 cananian 1.1.2.1 for (int i=0; i<newF.prevLength(); i++) 148 cananian 1.1.2.5 Ee.add(newF.prevEdge(i)); 149 cananian 1.1.2.7 } 150 cananian 1.1.2.7 public void visit(TYPESWITCH q) { 151 cananian 1.1.2.7 /* multiple edges of this SIGMA may be executable */ 152 cananian 1.1.2.7 List keylist = new ArrayList(q.arity()); 153 cananian 1.1.2.7 List edgelist = new ArrayList(q.arity()); 154 cananian 1.1.2.7 // collect executable edges. 155 cananian 1.1.2.7 for (int i=0; i < q.arity(); i++) 156 cananian 1.1.2.7 if (execMap(q.nextEdge(i))) { 157 cananian 1.1.2.7 if (i<q.keysLength()) 158 cananian 1.1.2.7 keylist.add(q.keys(i)); 159 cananian 1.1.2.7 edgelist.add(q.nextEdge(i)); 160 cananian 1.1.2.7 } 161 cananian 1.1.2.8 // default edge may not be executable. 162 cananian 1.1.2.8 boolean hasDefault = !(keylist.size() == edgelist.size()); 163 cananian 1.1.2.7 // make new keys and edge array. 164 cananian 1.1.2.7 HClass[] nkeys = 165 cananian 1.1.2.7 (HClass[]) keylist.toArray(new HClass[keylist.size()]); 166 cananian 1.1.2.7 Edge[] edges = 167 cananian 1.1.2.7 (Edge[]) edgelist.toArray(new Edge[edgelist.size()]); 168 cananian 1.1.2.7 // make new dst[][] array for sigmas 169 cananian 1.1.2.7 Temp[][] ndst = new Temp[q.numSigmas()][edgelist.size()]; 170 cananian 1.1.2.7 for (int i=0; i < q.numSigmas(); i++) 171 cananian 1.1.2.7 for (int j=0; j < edges.length; j++) 172 cananian 1.1.2.7 ndst[i][j] = q.dst(i, edges[j].which_succ()); 173 cananian 1.1.2.7 // make new TYPESWITCH 174 cananian 1.1.2.7 TYPESWITCH nts = new TYPESWITCH(q.getFactory(), q, q.index(), 175 cananian 1.1.2.8 nkeys, ndst, q.src(), 176 cananian 1.1.2.8 hasDefault); 177 cananian 1.1.2.7 // and link the new TYPESWITCH. 178 cananian 1.1.2.7 Edge pedge = q.prevEdge(0); 179 cananian 1.1.2.7 Quad.addEdge((Quad)pedge.from(), pedge.which_succ(), nts, 0); 180 cananian 1.1.2.7 Ee.add(nts.prevEdge(0)); 181 cananian 1.1.2.7 for (int i=0; i < edges.length; i++) { 182 cananian 1.1.2.7 Quad.addEdge(nts, i, 183 cananian 1.1.2.7 (Quad) edges[i].to(), edges[i].which_pred()); 184 cananian 1.1.2.7 Ee.add(nts.nextEdge(i)); 185 cananian 1.1.2.7 } 186 cananian 1.1.2.7 // visit(SIGMA) to trim out TYPESWITCH iff only one edge is 187 cananian 1.1.2.7 // executable 188 cananian 1.1.2.8 // (no-default typeswitch with one edge is an *assertion*. 189 cananian 1.1.2.8 // we don't want to delete it.) 190 cananian 1.1.2.8 if (hasDefault) visit((SIGMA)nts); 191 cananian 1.1.2.7 // ta-da! 192 cananian 1.1.2.12 } 193 cananian 1.1.2.13 public void visit(SWITCH q) { 194 cananian 1.1.2.13 /* multiple edges of this SIGMA may be executable */ 195 cananian 1.1.2.13 List keylist = new ArrayList(q.arity()); 196 cananian 1.1.2.13 List edgelist = new ArrayList(q.arity()); 197 cananian 1.1.2.13 // collect executable edges. 198 cananian 1.1.2.13 for (int i=0; i < q.arity(); i++) 199 cananian 1.1.2.13 if (execMap(q.nextEdge(i))) { 200 cananian 1.1.2.13 if (i<q.keysLength()) 201 cananian 1.1.2.13 keylist.add(new Integer(q.keys(i))); 202 cananian 1.1.2.13 edgelist.add(q.nextEdge(i)); 203 cananian 1.1.2.13 } 204 cananian 1.1.2.13 // default edge may not be executable. 205 cananian 1.1.2.13 boolean hasDefault = !(keylist.size() == edgelist.size()); 206 cananian 1.1.2.13 // if default edge isn't executable, remove last key to make 207 cananian 1.1.2.13 // new default edge. 208 cananian 1.1.2.13 if (!hasDefault) keylist.remove(keylist.size()-1); 209 cananian 1.3.2.1 assert keylist.size()+1 == edgelist.size(); 210 cananian 1.1.2.13 // make new keys and edge array. 211 cananian 1.1.2.13 int[] nkeys = new int[keylist.size()]; 212 cananian 1.1.2.13 for (int i=0; i<nkeys.length; i++) 213 cananian 1.1.2.13 nkeys[i] = ((Integer)keylist.get(i)).intValue(); 214 cananian 1.1.2.13 Edge[] edges = 215 cananian 1.1.2.13 (Edge[]) edgelist.toArray(new Edge[edgelist.size()]); 216 cananian 1.1.2.13 // make new dst[][] array for sigmas 217 cananian 1.1.2.13 Temp[][] ndst = new Temp[q.numSigmas()][edgelist.size()]; 218 cananian 1.1.2.13 for (int i=0; i < q.numSigmas(); i++) 219 cananian 1.1.2.13 for (int j=0; j < edges.length; j++) 220 cananian 1.1.2.13 ndst[i][j] = q.dst(i, edges[j].which_succ()); 221 cananian 1.1.2.13 // make new SWITCH 222 cananian 1.1.2.13 SWITCH nsw = new SWITCH(q.getFactory(), q, q.index(), 223 cananian 1.1.2.13 nkeys, ndst, q.src()); 224 cananian 1.1.2.13 // and link the new SWITCH. 225 cananian 1.1.2.13 Edge pedge = q.prevEdge(0); 226 cananian 1.1.2.13 Quad.addEdge((Quad)pedge.from(), pedge.which_succ(), nsw, 0); 227 cananian 1.1.2.13 Ee.add(nsw.prevEdge(0)); 228 cananian 1.1.2.13 for (int i=0; i < edges.length; i++) { 229 cananian 1.1.2.13 Quad.addEdge(nsw, i, 230 cananian 1.1.2.13 (Quad) edges[i].to(), edges[i].which_pred()); 231 cananian 1.1.2.13 Ee.add(nsw.nextEdge(i)); 232 cananian 1.1.2.13 } 233 cananian 1.1.2.13 // visit(SIGMA) to trim out SWITCH iff only one edge is 234 cananian 1.1.2.13 // executable 235 cananian 1.1.2.13 if (edgelist.size()==1) visit((SIGMA)nsw); 236 cananian 1.1.2.13 // ta-da! 237 cananian 1.1.2.13 } 238 cananian 1.1.2.12 public void visit(CALL q) { 239 cananian 1.1.2.12 // calls are like sigmas, but we can't actually 240 cananian 1.1.2.12 // remove either of the edges. 241 cananian 1.1.2.12 // Instead, we must stub out the bogus edge with an 242 cananian 1.1.2.12 // infinite loop. 243 cananian 1.1.2.12 for (int i=0; i<q.nextLength(); i++) { 244 cananian 1.1.2.12 if (!execMap(q.nextEdge(i))) { 245 cananian 1.1.2.12 Quad loop = new PHI(q.getFactory(), q, new Temp[0], 2); 246 cananian 1.1.2.12 Quad.addEdge(q, i, loop, 0); 247 cananian 1.1.2.12 Quad.addEdge(loop, 0, loop, 1); 248 cananian 1.1.2.12 // don't add these edges to Ee because they're still 249 cananian 1.1.2.12 // not executable. 250 cananian 1.1.2.12 } 251 cananian 1.1.2.12 } 252 cananian 1.1.2.1 } 253 cananian 1.1.2.1 public void visit(SIGMA q) { 254 cananian 1.1.2.1 // if the condition is constant, link this sigma (cjmp/switch) 255 cananian 1.1.2.1 // out of existence. Either all or exactly one edge will be 256 cananian 1.1.2.1 // executable. 257 cananian 1.1.2.1 Edge[] next = q.nextEdge(); 258 cananian 1.1.2.1 int i; for (i=0; i < next.length; i++) 259 cananian 1.1.2.1 if (execMap(next[i])) 260 cananian 1.1.2.1 break; 261 cananian 1.3.2.1 assert i!=next.length : q/*NO EDGES EXECUTABLE!*/; 262 cananian 1.1.2.1 if (i==next.length-1 || !execMap(next[i+1])) { 263 cananian 1.1.2.13 for (int j=i+1; j<next.length; j++) 264 cananian 1.3.2.1 assert !execMap(next[j]); 265 cananian 1.1.2.1 // only one edge is executable. 266 cananian 1.1.2.1 int liveEdge = i; 267 cananian 1.3.2.1 assert !(q instanceof CALL); 268 cananian 1.1.2.1 269 cananian 1.1.2.1 // Grab the link information from the original CJMP/SWITCH. 270 cananian 1.1.2.1 Quad header = q.prev(0); 271 cananian 1.1.2.1 int which_succ = q.prevEdge(0).which_succ(); 272 cananian 1.1.2.1 Quad successor = q.next(liveEdge); 273 cananian 1.1.2.1 int which_pred = q.nextEdge(liveEdge).which_pred(); 274 cananian 1.1.2.1 275 cananian 1.1.2.1 // insert a series of MOVEs to implement SIGMAs 276 cananian 1.1.2.1 for (i=0; i < q.numSigmas(); i++) { 277 cananian 1.1.2.1 Quad qq = new MOVE(q.getFactory(), q, 278 cananian 1.1.2.1 q.dst(i,liveEdge), q.src(i)); 279 cananian 1.1.2.1 Quad.addEdge(header, which_succ, qq, 0); 280 cananian 1.1.2.5 Ee.add(header.nextEdge(which_succ)); 281 cananian 1.1.2.1 header = qq; which_succ = 0; 282 cananian 1.1.2.1 } 283 cananian 1.1.2.1 // link to successor. 284 cananian 1.1.2.1 Quad.addEdge(header, which_succ, successor, which_pred); 285 cananian 1.1.2.5 Ee.add(header.nextEdge(which_succ)); 286 cananian 1.1.2.1 } 287 cananian 1.1.2.1 } // end VISIT SIGMA 288 cananian 1.1.2.1 public void visit(PHI q) { 289 cananian 1.1.2.1 // remove non-executable edges into this PHI. 290 cananian 1.1.2.1 for (int i=0; i < q.prev().length; ) { 291 cananian 1.1.2.1 if (!execMap(q.prevEdge(i))) 292 cananian 1.1.2.1 q.removePred(i); 293 cananian 1.1.2.1 else i++; 294 cananian 1.1.2.1 } 295 cananian 1.1.2.1 // replace any phi's with constant args with a CONST. 296 cananian 1.1.2.1 for (int i=0; i < q.numPhis(); ) { 297 cananian 1.1.2.1 if (cm.isConst(q, q.dst(i))) { 298 cananian 1.1.2.1 // insert CONST. 299 cananian 1.1.2.1 Quad qq = newCONST(q.getFactory(), q, q.dst(i), 300 cananian 1.1.2.1 cm.constMap(q, q.dst(i)), 301 cananian 1.1.2.1 ti.typeMap(q, q.dst(i)) ); 302 cananian 1.1.2.1 Edge edge = q.nextEdge(0); 303 cananian 1.1.2.1 Quad.addEdge(qq, 0,(Quad)edge.to(), edge.which_pred()); 304 cananian 1.1.2.1 Quad.addEdge(q, 0, qq, 0); 305 cananian 1.1.2.5 Ee.add(q.nextEdge(0)); 306 cananian 1.1.2.5 Ee.add(qq.nextEdge(0)); 307 cananian 1.1.2.1 q.removePhi(i); // remove i'th phi function. 308 cananian 1.1.2.1 } else i++; 309 cananian 1.1.2.1 } 310 cananian 1.1.2.1 } // end VISIT PHI. 311 cananian 1.1.2.1 }; 312 cananian 1.1.2.1 313 cananian 1.1.2.1 // actual traversal code. 314 cananian 1.5 for (Iterator it=new SnapshotIterator(hc.getElementsI()); 315 cananian 1.5 it.hasNext(); ) { 316 cananian 1.5 Quad q = (Quad) it.next(); 317 cananian 1.5 if (execMap(q)) 318 cananian 1.5 q.accept(visitor); 319 cananian 1.5 } 320 cananian 1.1.2.1 321 cananian 1.1.2.1 // clean up the mess 322 cananian 1.1.2.6 DeadCode.optimize((harpoon.IR.Quads.Code)hc, 323 cananian 1.1.2.6 null /* throw away AllocationInformation */); 324 cananian 1.1.2.1 } 325 cananian 1.2 }