1 cananian 1.1.2.1 // CacheEquivalence.java, created Wed Jun 6 15:06:02 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.Tree; 5 cananian 1.1.2.1 6 cananian 1.1.2.17 import harpoon.Analysis.ClassHierarchy; 7 cananian 1.1.2.1 import harpoon.Analysis.DomTree; 8 cananian 1.1.2.4 import harpoon.Analysis.ReachingDefs; 9 cananian 1.1.2.4 import harpoon.Analysis.ReachingDefsAltImpl; 10 cananian 1.1.2.1 import harpoon.Analysis.Maps.Derivation.DList; 11 cananian 1.1.2.5 import harpoon.Backend.Generic.Runtime.TreeBuilder; 12 cananian 1.1.2.4 import harpoon.ClassFile.HClass; 13 cananian 1.3.2.2 import harpoon.ClassFile.HCode; 14 cananian 1.1.2.4 import harpoon.ClassFile.HCode.PrintCallback; 15 cananian 1.1.2.1 import harpoon.ClassFile.HCodeElement; 16 cananian 1.1.2.4 import harpoon.IR.Properties.CFGrapher; 17 cananian 1.1.2.4 import harpoon.IR.Properties.UseDefer; 18 cananian 1.1.2.4 import harpoon.IR.Tree.BINOP; 19 cananian 1.1.2.4 import harpoon.IR.Tree.Bop; 20 cananian 1.1.2.4 import harpoon.IR.Tree.CALL; 21 cananian 1.1.2.4 import harpoon.IR.Tree.CONST; 22 cananian 1.1.2.1 import harpoon.IR.Tree.Code; 23 cananian 1.1.2.4 import harpoon.IR.Tree.ESEQ; 24 cananian 1.1.2.1 import harpoon.IR.Tree.Exp; 25 cananian 1.1.2.1 import harpoon.IR.Tree.ExpList; 26 cananian 1.1.2.4 import harpoon.IR.Tree.INVOCATION; 27 cananian 1.1.2.1 import harpoon.IR.Tree.MEM; 28 cananian 1.1.2.4 import harpoon.IR.Tree.METHOD; 29 cananian 1.1.2.1 import harpoon.IR.Tree.MOVE; 30 cananian 1.1.2.4 import harpoon.IR.Tree.NAME; 31 cananian 1.1.2.4 import harpoon.IR.Tree.Print; 32 cananian 1.1.2.1 import harpoon.IR.Tree.Stm; 33 cananian 1.1.2.1 import harpoon.IR.Tree.TEMP; 34 cananian 1.1.2.1 import harpoon.IR.Tree.Tree; 35 cananian 1.1.2.1 import harpoon.IR.Tree.TreeDerivation; 36 cananian 1.1.2.1 import harpoon.IR.Tree.TreeKind; 37 cananian 1.1.2.4 import harpoon.IR.Tree.TreeVisitor; 38 cananian 1.1.2.4 import harpoon.IR.Tree.Type; 39 cananian 1.1.2.4 import harpoon.IR.Tree.UNOP; 40 cananian 1.1.2.4 import harpoon.IR.Tree.Uop; 41 cananian 1.1.2.4 import harpoon.Temp.Label; 42 cananian 1.1.2.1 import harpoon.Temp.Temp; 43 cananian 1.5 import net.cscott.jutil.GenericMultiMap; 44 cananian 1.5 import net.cscott.jutil.MultiMap; 45 cananian 1.5 import net.cscott.jutil.Default; 46 cananian 1.5 import net.cscott.jutil.Environment; 47 cananian 1.5 import net.cscott.jutil.HashEnvironment; 48 cananian 1.1.2.4 import harpoon.Util.Util; 49 cananian 1.5 import net.cscott.jutil.WorkSet; 50 cananian 1.1.2.1 51 cananian 1.1.2.14 import java.util.Arrays; 52 cananian 1.1.2.4 import java.util.Collection; 53 cananian 1.1.2.2 import java.util.Collections; 54 cananian 1.1.2.1 import java.util.HashMap; 55 cananian 1.1.2.1 import java.util.HashSet; 56 cananian 1.1.2.4 import java.util.Iterator; 57 cananian 1.1.2.4 import java.util.List; 58 cananian 1.1.2.1 import java.util.Map; 59 cananian 1.1.2.1 import java.util.Set; 60 cananian 1.1.2.1 /** 61 cananian 1.1.2.1 * <code>CacheEquivalence</code> creates tag-check equivalence classes 62 cananian 1.1.2.1 * for MEM operations in a Tree. 63 cananian 1.1.2.1 * 64 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 65 cananian 1.5 * @version $Id: CacheEquivalence.java,v 1.5 2004/02/08 01:54:28 cananian Exp $ 66 cananian 1.1.2.1 */ 67 cananian 1.1.2.1 public class CacheEquivalence { 68 cananian 1.1.2.4 private static final boolean DEBUG=false; 69 cananian 1.1.2.5 private static final int CACHE_LINE_SIZE = 32; /* bytes */ 70 cananian 1.1.2.4 71 cananian 1.1.2.1 /** Creates a <code>CacheEquivalence</code>. */ 72 cananian 1.1.2.17 public CacheEquivalence(harpoon.IR.Tree.Code code, ClassHierarchy ch) { 73 cananian 1.3.2.2 CFGrapher<Tree> cfg = code.getGrapher(); 74 cananian 1.3.2.2 UseDefer<Tree> udr = code.getUseDefer(); 75 cananian 1.1.2.1 TreeDerivation td = code.getTreeDerivation(); 76 cananian 1.1.2.4 /* new analysis */ 77 cananian 1.3.2.3 final AlignmentAnalysis df = new AlignmentAnalysis(code, cfg, udr, td); 78 cananian 1.1.2.16 /*- construct cache eq -*/ 79 cananian 1.1.2.17 new TagDominate(code, cfg, td, ch, df); 80 cananian 1.1.2.16 /* debugging information dump */ 81 cananian 1.1.2.4 if (DEBUG) { 82 cananian 1.1.2.4 harpoon.IR.Tree.Print.print(new java.io.PrintWriter(System.out), 83 cananian 1.1.2.4 code, new PrintCallback() { 84 cananian 1.1.2.4 public void printAfter(java.io.PrintWriter pw, 85 cananian 1.1.2.4 HCodeElement hce) { 86 cananian 1.1.2.4 if (hce instanceof Exp) { 87 cananian 1.1.2.4 Exp e = (Exp) hce; 88 cananian 1.1.2.4 Tree t = e; 89 cananian 1.1.2.4 while (!(t instanceof Stm)) 90 cananian 1.1.2.4 t = t.getParent(); 91 cananian 1.1.2.4 pw.print(" [VAL: "+df.valueOf(e, (Stm)t)+"]"); 92 cananian 1.1.2.4 } 93 cananian 1.1.2.16 if (hce instanceof MEM) { 94 cananian 1.1.2.16 pw.print(" [CQ: "+cache_equiv.get(hce)+"]"); 95 cananian 1.1.2.16 } 96 cananian 1.1.2.4 } 97 cananian 1.1.2.4 }); 98 cananian 1.1.2.4 } 99 cananian 1.1.2.1 } 100 cananian 1.1.2.5 /* -------- cache equivalence pass ------- */ 101 cananian 1.1.2.5 private class TagDominate { 102 cananian 1.1.2.17 final ClassHierarchy ch; 103 cananian 1.1.2.5 final TreeDerivation td; 104 cananian 1.3.2.3 final AlignmentAnalysis df; 105 cananian 1.1.2.5 final DomTree dt; 106 cananian 1.1.2.5 final TreeBuilder tb; 107 cananian 1.1.2.17 TagDominate(Code c, CFGrapher cfg, TreeDerivation td, 108 cananian 1.3.2.3 ClassHierarchy ch, AlignmentAnalysis df) { 109 cananian 1.1.2.17 this.ch = ch; 110 cananian 1.1.2.5 this.td = td; 111 cananian 1.1.2.5 this.df = df; 112 cananian 1.1.2.18 this.tb = c.getFrame().getRuntime().getTreeBuilder(); 113 cananian 1.1.2.5 this.dt = new DomTree(c, cfg, false); 114 cananian 1.1.2.1 115 cananian 1.1.2.5 final Environment e = new HashEnvironment(); 116 cananian 1.1.2.5 HCodeElement[] roots = dt.roots(); 117 cananian 1.1.2.5 for (int i=0; i<roots.length; i++) 118 cananian 1.1.2.5 traverseDT((Stm) roots[i], e); 119 cananian 1.1.2.5 } 120 cananian 1.1.2.5 /* analyze stms travelling down the dominator tree */ 121 cananian 1.1.2.5 void traverseDT(Stm stm, Environment e) { 122 cananian 1.1.2.5 /* save environment */ 123 cananian 1.1.2.5 Environment.Mark mark = e.getMark(); 124 cananian 1.1.2.5 /* do analysis */ 125 cananian 1.1.2.5 analyze(stm, e); 126 cananian 1.1.2.5 /* recurse */ 127 cananian 1.1.2.5 HCodeElement[] child = dt.children(stm); 128 cananian 1.1.2.5 for (int i=0; i<child.length; i++) 129 cananian 1.1.2.5 traverseDT((Stm)child[i], e); 130 cananian 1.1.2.5 /* restore environment */ 131 cananian 1.1.2.5 e.undoToMark(mark); 132 cananian 1.1.2.5 /* done! */ 133 cananian 1.1.2.5 return; 134 cananian 1.1.2.5 } 135 cananian 1.1.2.5 /* analyze one statement in the environment defined by map m */ 136 cananian 1.1.2.5 void analyze(Stm stm, Map pre) { 137 cananian 1.1.2.5 Map post = new HashMap(); 138 cananian 1.1.2.5 /* first look for all *reads* */ 139 cananian 1.1.2.5 /* There is NO ORDER defined for any of these. */ 140 cananian 1.1.2.5 for (ExpList el=stm.kids(); el!=null; el=el.tail) { 141 cananian 1.1.2.5 add(stm, el.head, pre, post, true); 142 cananian 1.1.2.5 } 143 cananian 1.1.2.5 /* now all post mappings get added to pre */ 144 cananian 1.1.2.5 pre.putAll(post); post.clear(); 145 cananian 1.1.2.5 /* now look for writes (which must happen after reads) */ 146 cananian 1.1.2.5 if (stm.kind()==TreeKind.MOVE) 147 cananian 1.1.2.5 add(stm, ((MOVE)stm).getDst(), pre, post, false); 148 cananian 1.1.2.5 pre.putAll(post); post.clear(); 149 cananian 1.1.2.5 } 150 cananian 1.1.2.5 void add(Stm root, Exp e, Map pre, Map post, boolean recurse) { 151 cananian 1.1.2.5 if (e.kind()==TreeKind.MEM) { 152 cananian 1.1.2.5 MEM mem = (MEM) e; Exp memexp = mem.getExp(); 153 cananian 1.3.2.3 AlignmentAnalysis.Value v = df.valueOf(memexp, root); 154 cananian 1.1.2.5 // cases: 155 cananian 1.1.2.14 // 1a) known base & known offset. 156 cananian 1.1.2.14 // 1b) known base & offset mod N, in a kgroup. 157 cananian 1.1.2.14 // (N mod CACHE_LINE_SIZE must be zero) 158 cananian 1.1.2.14 // 1c) known base & offset mod N, in a kgroup. 159 cananian 1.1.2.14 // (where CACHE_LINE_SIZE mod N must be zero) 160 cananian 1.1.2.5 // 2) known base & unknown offset, but object is smaller 161 cananian 1.1.2.5 // than cache line size. 162 cananian 1.1.2.5 // 3) all others. 163 cananian 1.3.2.3 AlignmentAnalysis.DefPoint dp = null; 164 cananian 1.3.2.3 AlignmentAnalysis.KGroup kgroup = null; 165 cananian 1.1.2.14 long line=0; long modulus=0; 166 cananian 1.1.2.14 if (v.isBaseKnown() && 167 cananian 1.3.2.3 ((AlignmentAnalysis.BaseAndOffset)v).def.isWellTyped()) { 168 cananian 1.3.2.3 AlignmentAnalysis.BaseAndOffset bao = (AlignmentAnalysis.BaseAndOffset) v; 169 cananian 1.1.2.17 if (maxObjSize(bao.def.type()) <= CACHE_LINE_SIZE 170 cananian 1.1.2.14 // arrays can't count as small because 171 cananian 1.1.2.14 // length is not statically known. 172 cananian 1.1.2.14 && !bao.def.type().isArray()) { 173 cananian 1.1.2.14 /* case 2 */ 174 cananian 1.3.2.3 assert (bao.offset instanceof AlignmentAnalysis.Constant ? 175 cananian 1.3.2.3 ((AlignmentAnalysis.Constant)bao.offset) 176 cananian 1.1.2.17 .number < CACHE_LINE_SIZE : true); 177 cananian 1.1.2.14 dp = bao.def; line = 0; // case 2 178 cananian 1.3.2.3 } else if (bao.offset instanceof AlignmentAnalysis.Constant) { 179 cananian 1.1.2.14 /* case 1a */ 180 cananian 1.3.2.3 AlignmentAnalysis.Constant c = (AlignmentAnalysis.Constant) bao.offset; 181 cananian 1.1.2.14 dp = bao.def; line = c.number/CACHE_LINE_SIZE; 182 cananian 1.3.2.3 } else if (bao.offset instanceof AlignmentAnalysis.ConstantModuloN){ 183 cananian 1.3.2.3 AlignmentAnalysis.ConstantModuloN cmn = 184 cananian 1.3.2.3 (AlignmentAnalysis.ConstantModuloN) bao.offset; 185 cananian 1.1.2.14 if (cmn.kgroup!=null) { 186 cananian 1.1.2.14 if (0==(cmn.modulus % CACHE_LINE_SIZE)) { 187 cananian 1.1.2.14 /* case 1b */ 188 cananian 1.1.2.14 dp = bao.def; kgroup=cmn.kgroup; 189 cananian 1.1.2.14 line = cmn.number / CACHE_LINE_SIZE; 190 cananian 1.1.2.14 modulus = cmn.modulus; 191 cananian 1.1.2.14 } else if (0==(CACHE_LINE_SIZE % cmn.modulus)) { 192 cananian 1.1.2.14 /* case 1c */ 193 cananian 1.1.2.14 dp = bao.def; kgroup=cmn.kgroup; 194 cananian 1.1.2.14 // note that we can't guarantee that 195 cananian 1.1.2.14 // k*modulus is on a cache line boundary. 196 cananian 1.1.2.14 line = cmn.number / cmn.modulus; 197 cananian 1.1.2.14 modulus = cmn.modulus; 198 cananian 1.1.2.14 } 199 cananian 1.1.2.5 } 200 cananian 1.1.2.5 } 201 cananian 1.1.2.5 } 202 cananian 1.1.2.14 if (dp!=null) { // cases 1abc and 2 203 cananian 1.1.2.14 List key = Arrays.asList(new Object[] { 204 cananian 1.1.2.14 dp, new Long(line), new Long(modulus), kgroup 205 cananian 1.1.2.14 }); 206 cananian 1.1.2.14 CacheEquivSet ces = (CacheEquivSet) pre.get(key); 207 cananian 1.1.2.5 if (ces==null) ces = new CacheEquivSet(mem); 208 cananian 1.1.2.5 else ces.others.add(mem); 209 cananian 1.1.2.5 cache_equiv.put(mem, ces); 210 cananian 1.1.2.14 post.put(key, ces); 211 cananian 1.1.2.5 } else { // case 3 212 cananian 1.1.2.5 cache_equiv.put(mem, new CacheEquivSet(mem)); 213 cananian 1.1.2.5 } 214 cananian 1.1.2.5 } 215 cananian 1.1.2.5 if (recurse) 216 cananian 1.1.2.5 for (Tree tp=e.getFirstChild(); tp!=null; tp=tp.getSibling()) 217 cananian 1.1.2.5 add(root, (Exp)tp, pre, post, recurse); 218 cananian 1.1.2.5 } 219 cananian 1.1.2.17 // returns the size of an object of the specified class. 220 cananian 1.1.2.5 int objSize(HClass hc) { return tb.headerSize(hc)+tb.objectSize(hc); } 221 cananian 1.1.2.17 // returns the maximum size of an object of the specified type. 222 cananian 1.1.2.17 // this must account for any subclasses of the type, which likely 223 cananian 1.1.2.17 // are larger than it is. 224 cananian 1.1.2.17 int maxObjSize(HClass hc) { 225 cananian 1.1.2.17 if (!sizeCache.containsKey(hc)) { 226 cananian 1.1.2.17 // compute maximum object size recursively. 227 cananian 1.1.2.17 int size = objSize(hc); 228 cananian 1.3.2.3 for (Iterator<HClass> it=ch.children(hc).iterator(); 229 cananian 1.3.2.3 it.hasNext(); ) 230 cananian 1.3.2.3 size = Math.max(size, maxObjSize(it.next())); 231 cananian 1.1.2.17 sizeCache.put(hc, new Integer(size)); 232 cananian 1.1.2.17 } 233 cananian 1.3.2.3 return sizeCache.get(hc).intValue(); 234 cananian 1.1.2.17 } 235 cananian 1.1.2.17 // keep an object size cache for speed. 236 cananian 1.3.2.3 private final Map<HClass,Integer> sizeCache = 237 cananian 1.3.2.3 new HashMap<HClass,Integer>(); 238 cananian 1.1.2.5 } 239 cananian 1.1.2.4 240 cananian 1.1.2.4 /*----------------------------------------------------------------*/ 241 cananian 1.1.2.4 242 cananian 1.1.2.4 /** defines the properties of cache-equivalence sets */ 243 cananian 1.1.2.1 static class CacheEquivSet { 244 cananian 1.1.2.1 public final MEM first; 245 cananian 1.1.2.1 public final Set others = new HashSet(); 246 cananian 1.1.2.1 public CacheEquivSet(MEM mem) { this.first = mem; } 247 cananian 1.1.2.16 public String toString() { 248 cananian 1.1.2.16 return "<TAG DEF:"+first+"; USE:"+others+">"; 249 cananian 1.1.2.16 } 250 cananian 1.1.2.1 } 251 cananian 1.1.2.1 final Map cache_equiv = new HashMap(); 252 cananian 1.1.2.1 253 cananian 1.1.2.1 /** Returns the number of memory operations which share the same 254 cananian 1.1.2.1 * tag as this memory operation. 1 indicates no sharing possible. */ 255 cananian 1.1.2.2 public int num_using_this_tag(MEM mem) { 256 cananian 1.1.2.1 return ((CacheEquivSet) cache_equiv.get(mem)).others.size() + 1; 257 cananian 1.1.2.1 } 258 cananian 1.1.2.1 /** Returns 'true' if this operation requires a tag check. If 259 cananian 1.1.2.1 * ops_using_this_tag(mem) is also true, then you should store the 260 cananian 1.1.2.1 * result of the tag check some where for further use. */ 261 cananian 1.1.2.1 public boolean needs_tag_check(MEM mem) { 262 cananian 1.1.2.1 return whose_tag_check(mem) == mem; 263 cananian 1.1.2.1 } 264 cananian 1.1.2.1 /** Returns the MEM operation which should have stored the 265 cananian 1.1.2.1 * necessary tag information for this MEM operation. */ 266 cananian 1.1.2.1 public MEM whose_tag_check(MEM mem) { 267 cananian 1.1.2.1 return ((CacheEquivSet) cache_equiv.get(mem)).first; 268 cananian 1.1.2.2 } 269 cananian 1.1.2.2 /** Returns all the MEM operations which use the tag defined 270 cananian 1.1.2.2 * by whose_tag_check(mem) */ 271 cananian 1.1.2.2 public Set ops_using_this_tag(MEM mem) { 272 cananian 1.1.2.2 return Collections.unmodifiableSet 273 cananian 1.1.2.2 (((CacheEquivSet) cache_equiv.get(mem)).others); 274 cananian 1.1.2.1 } 275 cananian 1.2 }