1 cananian 1.1.2.1 // MostlyZeroFinder.java, created Thu Oct 25 14:37:24 2001 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.Analysis.SizeOpt; 5 cananian 1.1.2.1 6 cananian 1.1.2.3 import harpoon.Analysis.ClassHierarchy; 7 cananian 1.1.2.1 import harpoon.Analysis.Counters.CounterFactory; 8 cananian 1.1.2.3 import harpoon.Analysis.Quads.DefiniteInitOracle; 9 cananian 1.1.2.1 import harpoon.Analysis.Transactions.BitFieldNumbering; 10 cananian 1.1.2.1 import harpoon.Analysis.Transactions.BitFieldNumbering.BitFieldTuple; 11 cananian 1.1.2.2 import harpoon.Analysis.Transformation.MethodMutator; 12 cananian 1.1.2.1 import harpoon.Backend.Generic.Frame; 13 cananian 1.1.2.3 import harpoon.ClassFile.CachingCodeFactory; 14 cananian 1.1.2.2 import harpoon.ClassFile.HClass; 15 cananian 1.1.2.2 import harpoon.ClassFile.HCode; 16 cananian 1.1.2.2 import harpoon.ClassFile.HCodeAndMaps; 17 cananian 1.1.2.2 import harpoon.ClassFile.HCodeElement; 18 cananian 1.1.2.2 import harpoon.ClassFile.HCodeFactory; 19 cananian 1.1.2.2 import harpoon.ClassFile.HField; 20 cananian 1.1.2.2 import harpoon.ClassFile.HMethod; 21 cananian 1.1.2.2 import harpoon.IR.Quads.CJMP; 22 cananian 1.1.2.2 import harpoon.IR.Quads.CONST; 23 cananian 1.1.2.2 import harpoon.IR.Quads.Edge; 24 cananian 1.1.2.2 import harpoon.IR.Quads.GET; 25 cananian 1.1.2.2 import harpoon.IR.Quads.NEW; 26 cananian 1.1.2.2 import harpoon.IR.Quads.OPER; 27 cananian 1.1.2.2 import harpoon.IR.Quads.PHI; 28 cananian 1.1.2.2 import harpoon.IR.Quads.Qop; 29 cananian 1.1.2.2 import harpoon.IR.Quads.Quad; 30 cananian 1.1.2.2 import harpoon.IR.Quads.QuadFactory; 31 cananian 1.1.2.2 import harpoon.IR.Quads.QuadNoSSA; 32 cananian 1.1.2.2 import harpoon.IR.Quads.QuadVisitor; 33 cananian 1.1.2.2 import harpoon.IR.Quads.SET; 34 cananian 1.1.2.2 import harpoon.Temp.Temp; 35 cananian 1.1.2.2 import harpoon.Util.ArrayIterator; 36 cananian 1.8 import net.cscott.jutil.SnapshotIterator; 37 cananian 1.1.2.2 import harpoon.Util.Util; 38 cananian 1.1.2.1 39 cananian 1.1.2.2 import java.util.Iterator; 40 cananian 1.1.2.1 /** 41 cananian 1.1.2.3 * The <code>MostlyZeroFinder</code> will add counters to find fields 42 cananian 1.1.2.3 * which are mostly zero (or mostly 1, 2, etc). 43 cananian 1.1.2.1 * 44 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 45 cananian 1.9 * @version $Id: MostlyZeroFinder.java,v 1.9 2004/02/08 03:20:22 cananian Exp $ 46 cananian 1.1.2.1 */ 47 cananian 1.5 public class MostlyZeroFinder extends MethodMutator<Quad> { 48 cananian 1.1.2.3 /** the mostly-zero analysis can actually find mostly-N fields. this 49 cananian 1.1.2.3 * parameter lets you chose what 'N' should be. */ 50 cananian 1.1.2.3 final static int MOSTLY_WHAT = 51 cananian 1.1.2.3 Integer.parseInt(System.getProperty("harpoon.mzf.lookfor", "0")); 52 cananian 1.1.2.1 final BitFieldNumbering bfn; 53 cananian 1.1.2.1 final boolean pointersAreLong; 54 cananian 1.1.2.1 final String suffix = "$mzf"; 55 cananian 1.1.2.3 final DefiniteInitOracle dio; 56 cananian 1.1.2.1 57 cananian 1.1.2.3 /** Creates a <code>MostlyZeroFinder</code> using the given 58 cananian 1.1.2.3 * code factory, class hierarchy, and frame. */ 59 cananian 1.1.2.3 public MostlyZeroFinder(HCodeFactory parent, ClassHierarchy ch, 60 cananian 1.1.2.3 Frame frame) { 61 cananian 1.7 // force a caching quad-no-ssa code factory. 62 cananian 1.1.2.3 this(new CachingCodeFactory(QuadNoSSA.codeFactory(parent)), ch, frame); 63 cananian 1.1.2.3 } 64 cananian 1.1.2.3 // the private constructor knows the code factory is cached and produces 65 cananian 1.7 // quad-no-ssa form. 66 cananian 1.1.2.3 private MostlyZeroFinder(CachingCodeFactory parent, ClassHierarchy ch, 67 cananian 1.1.2.3 Frame frame) { 68 cananian 1.1.2.3 super(parent); 69 cananian 1.1.2.1 this.bfn = new BitFieldNumbering(frame.getLinker(), suffix); 70 cananian 1.1.2.1 this.pointersAreLong = frame.pointersAreLong(); 71 cananian 1.1.2.3 this.dio = (MOSTLY_WHAT==0) ? null : 72 cananian 1.1.2.3 new DefiniteInitOracle(parent, ch); 73 cananian 1.1.2.1 } 74 cananian 1.5 protected HCode<Quad> mutateHCode(HCodeAndMaps<Quad> input) { 75 cananian 1.5 HCode<Quad> hc = input.hcode(); 76 cananian 1.1.2.1 // prevent instrumentation of the instrumentation code. 77 cananian 1.1.2.1 if ("harpoon.Runtime.Counters".equals 78 cananian 1.1.2.1 (hc.getMethod().getDeclaringClass().getName())) 79 cananian 1.1.2.1 return hc; 80 cananian 1.1.2.1 // use visitor. 81 cananian 1.1.2.1 Visitor v = new Visitor(hc); 82 cananian 1.6 // use snapshot while visiting so as not to confuse iterator 83 cananian 1.6 for (Iterator<Quad> it=new SnapshotIterator<Quad> 84 cananian 1.6 (hc.getElementsI()); it.hasNext(); ) 85 cananian 1.6 it.next().accept(v); 86 cananian 1.1.2.1 // done! 87 cananian 1.1.2.1 return hc; 88 cananian 1.1.2.1 } 89 cananian 1.1.2.1 private class Visitor extends QuadVisitor { 90 cananian 1.1.2.1 final QuadFactory qf; 91 cananian 1.5 Visitor(HCode<Quad> hc) { qf=hc.getRootElement().getFactory(); } 92 cananian 1.1.2.1 public void visit(Quad q) { /* do nothing */ } 93 cananian 1.1.2.1 // xxx: should we treat fields of subclasses differently? 94 cananian 1.1.2.1 // perhaps a superclass never uses field x, but subclasses do? 95 cananian 1.1.2.1 public void visit(NEW q) { 96 cananian 1.1.2.1 // add 1 to 'alloc field' 97 cananian 1.1.2.1 addFieldAllocCounters(q.nextEdge(0), q.hclass()); 98 cananian 1.1.2.1 } 99 cananian 1.1.2.1 Edge addFieldAllocCounters(Edge e, HClass hc) { 100 cananian 1.1.2.1 if (hc==null) return e; // recursion termination condition. 101 cananian 1.3.2.1 assert !hc.isInterface() && !hc.isArray(); 102 cananian 1.1.2.1 // one counter per declared non-static field. 103 cananian 1.9 for (HField hf : hc.getDeclaredFields()) { 104 cananian 1.3.2.1 assert hc==hf.getDeclaringClass(); 105 cananian 1.1.2.1 if (hf.isStatic()) continue; 106 cananian 1.1.2.1 if (hf.getName().endsWith(suffix)) continue;//don't count bits 107 cananian 1.1.2.3 if (!isOkay(hf)) continue; // some limits if MOSTLY_WHAT!=0 108 cananian 1.1.2.1 e = CounterFactory.spliceIncrement 109 cananian 1.1.2.1 (qf, e, "mzf.alloc."+hc.getName()+"."+hf.getName()); 110 cananian 1.1.2.1 e = CounterFactory.spliceIncrement 111 cananian 1.1.2.1 (qf, e, "mzf.savedbytes."+hc.getName()+"."+hf.getName(), 112 cananian 1.1.2.1 sizeOf(hf.getType())); 113 cananian 1.1.2.1 } 114 cananian 1.1.2.1 // recurse. 115 cananian 1.1.2.1 return addFieldAllocCounters(e, hc.getSuperclass()); 116 cananian 1.1.2.1 } 117 cananian 1.1.2.1 public void visit(SET q) { 118 cananian 1.1.2.1 // skip static fields. 119 cananian 1.1.2.1 if (q.field().isStatic()) return; 120 cananian 1.1.2.3 // skip non-definitely-initialized fields if MOSTLY_WHAT != 0 121 cananian 1.1.2.3 if (!isOkay(q.field())) return; 122 cananian 1.1.2.1 123 cananian 1.1.2.1 // get bit. 124 cananian 1.1.2.1 // if zero and x != 0 125 cananian 1.1.2.1 // inc 'nonzero' counter 126 cananian 1.1.2.1 // set bit. 127 cananian 1.1.2.1 // do set 128 cananian 1.1.2.1 Edge e = q.prevEdge(0); 129 cananian 1.1.2.1 BitFieldTuple bft = bfn.bfLoc(q.field()); 130 cananian 1.1.2.1 Temp bitT = new Temp(qf.tempFactory(), "mzf_bit"); 131 cananian 1.1.2.1 Temp maskT = new Temp(qf.tempFactory(), "mzf_mask"); 132 cananian 1.1.2.1 Temp cmpT = new Temp(qf.tempFactory(), "mzf_cmp"); 133 cananian 1.1.2.1 e = addAt(e, new GET(qf, q, bitT, bft.field, q.objectref())); 134 cananian 1.1.2.1 e = addAt(e, new CONST(qf, q, maskT, 135 cananian 1.1.2.1 new Integer(1<<bft.bit), HClass.Int)); 136 cananian 1.1.2.1 e = addAt(e, new OPER(qf, q, Qop.IAND, cmpT, 137 cananian 1.1.2.1 new Temp[] {bitT, maskT})); 138 cananian 1.1.2.1 e = addAt(e, new OPER(qf, q, Qop.ICMPEQ, cmpT, 139 cananian 1.1.2.1 new Temp[] {cmpT, maskT})); 140 cananian 1.1.2.1 Quad qH = new CJMP(qf, q, cmpT, new Temp[0]); 141 cananian 1.1.2.1 e = addAt(e, 0, qH, 1); 142 cananian 1.1.2.1 Quad qF = new PHI(qf, q, new Temp[0], 3); 143 cananian 1.1.2.1 e = addAt(e, qF); 144 cananian 1.1.2.1 // okay, handle case that bit is 0. 145 cananian 1.1.2.1 Temp zeroT = new Temp(qf.tempFactory(), "mzf_zero"); 146 cananian 1.1.2.1 Quad q0 = zeroConst(qf, q, zeroT, q.field().getType()); 147 cananian 1.1.2.1 Quad q1 = new OPER(qf, q, cmpEqOp(q.field().getType()), cmpT, 148 cananian 1.1.2.1 new Temp[] {zeroT, q.src()}); 149 cananian 1.1.2.1 Quad q2 = new CJMP(qf, q, cmpT, new Temp[0]); 150 cananian 1.1.2.1 // bail if new value (q.src()) is zero. 151 cananian 1.1.2.1 Quad.addEdge(qH, 0, q0, 0); 152 cananian 1.1.2.1 Quad.addEdge(q0, 0, q1, 0); 153 cananian 1.1.2.1 Quad.addEdge(q1, 0, q2, 0); 154 cananian 1.1.2.1 Quad.addEdge(q2, 1, qF, 1); 155 cananian 1.1.2.1 // set bit and increment counter. XXX: NOT THREAD SAFE!!! 156 cananian 1.1.2.1 Quad q3 = new OPER(qf, q, Qop.IOR, bitT, new Temp[] {bitT, maskT}); 157 cananian 1.1.2.1 Quad q4 = new SET(qf, q, bft.field, q.objectref(), bitT); 158 cananian 1.1.2.1 Quad.addEdge(q2, 0, q3, 0); 159 cananian 1.1.2.1 Quad.addEdge(q3, 0, q4, 0); 160 cananian 1.1.2.1 Quad.addEdge(q4, 0, qF, 2); 161 cananian 1.1.2.1 HField hf = q.field(); 162 cananian 1.1.2.1 e = CounterFactory.spliceIncrement 163 cananian 1.1.2.1 (qf, q4.nextEdge(0), 164 cananian 1.1.2.1 "mzf.nonzero."+hf.getDeclaringClass().getName()+ 165 cananian 1.1.2.1 "."+hf.getName()); 166 cananian 1.1.2.1 e = CounterFactory.spliceIncrement 167 cananian 1.1.2.1 (qf, e, "mzf.savedbytes."+hf.getDeclaringClass().getName()+ 168 cananian 1.1.2.1 "."+hf.getName(), -sizeOf(hf.getType())); 169 cananian 1.1.2.1 } 170 cananian 1.1.2.1 } 171 cananian 1.1.2.3 // we can only compile meaningful numbers for primitive fields that 172 cananian 1.1.2.3 // are definitely-initialized if MOSTLY_WHAT is not zero. 173 cananian 1.1.2.3 private boolean isOkay(HField hf) { 174 cananian 1.1.2.3 if (MOSTLY_WHAT!=0) 175 cananian 1.1.2.3 return dio.isDefinitelyInitialized(hf) && 176 cananian 1.1.2.3 hf.getType().isPrimitive(); 177 cananian 1.1.2.3 return true; 178 cananian 1.1.2.3 } 179 cananian 1.1.2.1 private static CONST zeroConst(QuadFactory qf, HCodeElement src, 180 cananian 1.1.2.1 Temp dst, HClass type) { 181 cananian 1.1.2.3 // psst: here's a secret. the 'zeroConst' is actually not 182 cananian 1.1.2.3 // zero if MOSTLY_WHAT is not zero. 183 cananian 1.1.2.1 if (!type.isPrimitive()) 184 cananian 1.1.2.1 return new CONST(qf, src, dst, null, HClass.Void); 185 cananian 1.1.2.1 if (type==HClass.Boolean || type==HClass.Byte || 186 cananian 1.1.2.1 type==HClass.Short || type==HClass.Int || type==HClass.Char) 187 cananian 1.1.2.3 return new CONST(qf, src, dst, 188 cananian 1.1.2.3 new Integer(MOSTLY_WHAT), HClass.Int); 189 cananian 1.1.2.1 if (type==HClass.Long) 190 cananian 1.1.2.3 return new CONST(qf, src, dst, 191 cananian 1.1.2.3 new Long(MOSTLY_WHAT), HClass.Long); 192 cananian 1.1.2.1 if (type==HClass.Float) 193 cananian 1.1.2.3 return new CONST(qf, src, dst, 194 cananian 1.1.2.3 new Float(MOSTLY_WHAT), HClass.Float); 195 cananian 1.1.2.1 if (type==HClass.Double) 196 cananian 1.1.2.3 return new CONST(qf, src, dst, 197 cananian 1.1.2.3 new Double(MOSTLY_WHAT), HClass.Double); 198 cananian 1.3.2.1 assert false : "forgot a primitive type?"; 199 cananian 1.1.2.1 return null; 200 cananian 1.1.2.1 } 201 cananian 1.1.2.1 private static int cmpEqOp(HClass type) { 202 cananian 1.1.2.1 if (!type.isPrimitive()) return Qop.ACMPEQ; 203 cananian 1.1.2.1 if (type==HClass.Boolean || type==HClass.Byte || type==HClass.Char || 204 cananian 1.1.2.1 type==HClass.Short || type==HClass.Int) return Qop.ICMPEQ; 205 cananian 1.1.2.1 if (type==HClass.Long) return Qop.LCMPEQ; 206 cananian 1.1.2.1 if (type==HClass.Float) return Qop.FCMPEQ; 207 cananian 1.1.2.1 if (type==HClass.Double) return Qop.DCMPEQ; 208 cananian 1.3.2.1 assert false : "forgot a primitive type?"; 209 cananian 1.1.2.1 return -1; 210 cananian 1.1.2.1 } 211 cananian 1.1.2.1 private int sizeOf(HClass type) { 212 cananian 1.1.2.1 if (!type.isPrimitive()) return pointersAreLong ? 8 : 4; 213 cananian 1.1.2.1 if (type==HClass.Boolean || type==HClass.Byte) return 1; 214 cananian 1.1.2.1 if (type==HClass.Char || type==HClass.Short) return 2; 215 cananian 1.1.2.1 if (type==HClass.Int || type==HClass.Float) return 4; 216 cananian 1.1.2.1 if (type==HClass.Long || type==HClass.Double) return 8; 217 cananian 1.3.2.1 assert false : "forgot a primitive type?"; 218 cananian 1.1.2.1 return 0; 219 cananian 1.1.2.1 } 220 cananian 1.1.2.1 // private helper functions. 221 cananian 1.1.2.1 private static Edge addAt(Edge e, Quad q) { return addAt(e, 0, q, 0); } 222 cananian 1.1.2.1 private static Edge addAt(Edge e, int which_pred, Quad q, int which_succ) { 223 cananian 1.5 Quad frm = e.from(); int frm_succ = e.which_succ(); 224 cananian 1.5 Quad to = e.to(); int to_pred = e.which_pred(); 225 cananian 1.1.2.1 Quad.addEdge(frm, frm_succ, q, which_pred); 226 cananian 1.1.2.1 Quad.addEdge(q, which_succ, to, to_pred); 227 cananian 1.1.2.1 return to.prevEdge(to_pred); 228 cananian 1.1.2.1 } 229 cananian 1.2 }