1 cananian 1.1.2.1 // ArrayUnroller.java, created Thu Jun 14 22:36:15 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.Quads; 5 cananian 1.1.2.1 6 cananian 1.1.2.1 import harpoon.Analysis.Loops.LoopFinder; 7 cananian 1.1.2.1 import harpoon.Analysis.Loops.Loops; 8 cananian 1.1.2.1 import harpoon.ClassFile.HClass; 9 cananian 1.1.2.1 import harpoon.ClassFile.HCode; 10 cananian 1.1.2.1 import harpoon.ClassFile.HCodeAndMaps; 11 cananian 1.1.2.1 import harpoon.ClassFile.HCodeFactory; 12 cananian 1.1.2.1 import harpoon.IR.Quads.AGET; 13 cananian 1.1.2.1 import harpoon.IR.Quads.ASET; 14 cananian 1.1.2.1 import harpoon.IR.Quads.Edge; 15 cananian 1.1.2.1 import harpoon.IR.Quads.PHI; 16 cananian 1.1.2.1 import harpoon.IR.Quads.Quad; 17 cananian 1.1.2.1 import harpoon.IR.Quads.QuadFactory; 18 cananian 1.1.2.1 import harpoon.IR.Quads.QuadNoSSA; 19 cananian 1.1.2.1 import harpoon.Temp.Temp; 20 cananian 1.7 import net.cscott.jutil.UnmodifiableIterator; 21 cananian 1.1.2.1 import harpoon.Util.Util; 22 cananian 1.1.2.1 23 cananian 1.7 import java.util.ArrayList; 24 cananian 1.1.2.1 import java.util.HashMap; 25 cananian 1.1.2.1 import java.util.Iterator; 26 cananian 1.7 import java.util.List; 27 cananian 1.1.2.1 import java.util.Map; 28 cananian 1.1.2.1 import java.util.NoSuchElementException; 29 cananian 1.1.2.1 import java.util.Set; 30 cananian 1.1.2.1 import java.util.Stack; 31 cananian 1.1.2.1 /** 32 cananian 1.1.2.1 * <code>ArrayUnroller</code> unrolls loops containing arrays so that 33 cananian 1.1.2.1 * <code>CacheEquivalence</code> can make larger equivalence sets. 34 cananian 1.1.2.1 * 35 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 36 cananian 1.8 * @version $Id: ArrayUnroller.java,v 1.8 2004/02/08 03:20:09 cananian Exp $ 37 cananian 1.1.2.1 */ 38 cananian 1.1.2.1 public final class ArrayUnroller 39 cananian 1.6 extends harpoon.Analysis.Transformation.MethodMutator<Quad> { 40 cananian 1.1.2.1 private static final int CACHE_LINE_SIZE = 32; /* bytes */ 41 cananian 1.1.2.1 42 cananian 1.1.2.1 /** Creates a <code>ArrayUnroller</code>. */ 43 cananian 1.1.2.1 public ArrayUnroller(HCodeFactory parent) { 44 cananian 1.1.2.1 // we take in NoSSx, and output NoSSx. 45 cananian 1.1.2.1 super(harpoon.IR.Quads.QuadNoSSA.codeFactory(parent)); 46 cananian 1.1.2.1 } 47 cananian 1.6 protected HCode<Quad> mutateHCode(HCodeAndMaps<Quad> input) { 48 cananian 1.6 HCode<Quad> ahc = input.ancestorHCode(); 49 cananian 1.6 HCode<Quad> hc = input.hcode(); 50 cananian 1.1.2.1 // find loops; 51 cananian 1.1.2.1 // only interested in leaf loops (with no nested loops) 52 cananian 1.6 for (Iterator<Loops> it=loopIterator(new LoopFinder(ahc)); 53 cananian 1.6 it.hasNext(); ) { 54 cananian 1.6 Loops loop = it.next(); 55 cananian 1.1.2.3 if (loop.parentLoop()==null) continue; // skip top-level pseudoloop 56 cananian 1.1.2.1 if (loop.nestedLoops().size()>0) continue; // skip 57 cananian 1.1.2.1 // this is a leaf loop. look for array refs. 58 cananian 1.1.2.1 boolean seen=false; int width=0; 59 cananian 1.8 for (Object qO : loop.loopIncElements()) { 60 cananian 1.8 Quad q = (Quad) qO; 61 cananian 1.1.2.1 if (q instanceof AGET) { 62 cananian 1.1.2.1 seen=true; width=updateWidth(width,((AGET)q).type()); 63 cananian 1.1.2.1 } else if (q instanceof ASET) { 64 cananian 1.1.2.1 seen=true; width=updateWidth(width,((ASET)q).type()); 65 cananian 1.1.2.1 } 66 cananian 1.1.2.1 } 67 cananian 1.1.2.1 if (!seen) continue; // no array references in this loop. 68 cananian 1.1.2.3 unrollOne(input, loop, CACHE_LINE_SIZE/width); 69 cananian 1.1.2.1 } 70 cananian 1.6 harpoon.Analysis.Quads.Unreachable.prune((harpoon.IR.Quads.Code)hc); 71 cananian 1.1.2.1 return hc; 72 cananian 1.1.2.1 } 73 cananian 1.1.2.1 /** find the minimum array component width */ 74 cananian 1.1.2.1 private static int updateWidth(int width, HClass type) { 75 cananian 1.1.2.1 int nwidth=0; 76 cananian 1.1.2.1 if (type==HClass.Boolean || type==HClass.Byte) nwidth=1; 77 cananian 1.1.2.1 else if (type==HClass.Char || type==HClass.Short) nwidth=2; 78 cananian 1.1.2.1 else if (type==HClass.Int || type==HClass.Float) nwidth=4; 79 cananian 1.1.2.1 else if (type==HClass.Long || type==HClass.Double) nwidth=8; 80 cananian 1.1.2.1 else if (!type.isPrimitive()) nwidth=4; 81 cananian 1.3.2.1 else assert false; 82 cananian 1.1.2.1 return (width==0) ? nwidth : Math.min(width, nwidth); 83 cananian 1.1.2.1 } 84 cananian 1.1.2.1 /** iterate over loop and all children of loop recursively. */ 85 cananian 1.6 static Iterator<Loops> loopIterator(Loops root) { 86 cananian 1.6 final Stack<Loops> s = new Stack<Loops>(); s.push(root); 87 cananian 1.6 return new UnmodifiableIterator<Loops>() { 88 cananian 1.1.2.1 public boolean hasNext() { return !s.isEmpty(); } 89 cananian 1.6 public Loops next() { 90 cananian 1.1.2.1 if (s.empty()) throw new NoSuchElementException(); 91 cananian 1.6 Loops loop = s.pop(); 92 cananian 1.1.2.1 // push children on stack before returning. 93 cananian 1.1.2.1 s.addAll(loop.nestedLoops()); 94 cananian 1.1.2.1 return loop; 95 cananian 1.1.2.1 } 96 cananian 1.1.2.1 }; 97 cananian 1.1.2.1 } 98 cananian 1.1.2.1 // the real mccoy: 99 cananian 1.6 private void unrollOne(HCodeAndMaps<Quad> input, Loops loop, int ntimes) { 100 cananian 1.1.2.1 // step 1: copy the nodes to make a loop L' with header h' 101 cananian 1.1.2.1 // and back edges si'->h' 102 cananian 1.7 List<Map<Quad,Quad>> copies = new ArrayList<Map<Quad,Quad>>(ntimes); 103 cananian 1.7 copies.add(input.elementMap()); 104 cananian 1.1.2.1 for (int i=1; i<ntimes; i++) 105 cananian 1.7 copies.add(copy(input, loop)); 106 cananian 1.1.2.1 // step 2: change all the back edges in L from si->h to si->h' 107 cananian 1.1.2.1 // step 3: change all the back edges in L' from si'->h' to si'->h 108 cananian 1.1.2.1 for (int i=0; i<ntimes; i++) { 109 cananian 1.8 for (Object eO : loop.loopBackEdges()) { 110 cananian 1.8 Edge e = (Edge) eO; 111 cananian 1.7 Quad.addEdge(copies.get(i).get(e.from()), 112 cananian 1.1.2.1 e.which_succ(), 113 cananian 1.7 copies.get((i+1)%ntimes).get(e.to()), 114 cananian 1.1.2.1 e.which_pred()); 115 cananian 1.1.2.1 } 116 cananian 1.1.2.1 } 117 cananian 1.1.2.1 // make PHIs for the exit edges. 118 cananian 1.8 for (Object eO : loop.loopExitEdges()) { 119 cananian 1.8 Edge e = (Edge) eO; 120 cananian 1.7 QuadFactory qf = copies.get(0).get(e.from()).getFactory(); 121 cananian 1.1.2.1 PHI phi = new PHI(qf, e.from(), new Temp[0], ntimes); 122 cananian 1.7 Quad.addEdge(phi, 0, copies.get(0).get(e.to()), e.which_pred()); 123 cananian 1.1.2.1 for (int i=0; i<ntimes; i++) 124 cananian 1.7 Quad.addEdge(copies.get(i).get(e.from()), e.which_succ(), 125 cananian 1.1.2.1 phi, i); 126 cananian 1.1.2.1 } 127 cananian 1.1.2.2 // make stub PHIs for unused entrance edges 128 cananian 1.8 for (Object eO : loop.loopEntranceEdges()) { 129 cananian 1.8 Edge e = (Edge) eO; 130 cananian 1.7 QuadFactory qf = copies.get(0).get(e.to()).getFactory(); 131 cananian 1.1.2.2 for (int i=1; i<ntimes; i++) { 132 cananian 1.1.2.2 PHI phi = new PHI(qf, e.to(), new Temp[0], 0); 133 cananian 1.1.2.2 Quad.addEdge(phi, 0, 134 cananian 1.7 copies.get(i).get(e.to()), 135 cananian 1.1.2.2 e.which_pred()); 136 cananian 1.1.2.2 } 137 cananian 1.1.2.2 } 138 cananian 1.1.2.1 // we may have unconnected entrances if more than one header. 139 cananian 1.3.2.1 assert loop.loopEntrances().size()==1; 140 cananian 1.1.2.1 // done. 141 cananian 1.1.2.1 } 142 cananian 1.6 Map<Quad,Quad> copy(HCodeAndMaps<Quad> input, Loops l) { 143 cananian 1.6 Map<Quad,Quad> m = new HashMap<Quad,Quad>(); 144 cananian 1.1.2.1 // clone all elements. 145 cananian 1.8 for (Object qO : l.loopIncElements()) { 146 cananian 1.8 Quad q = (Quad) qO; 147 cananian 1.6 Quad qq = input.elementMap().get(q); 148 cananian 1.6 Quad nq = qq.clone(); 149 cananian 1.1.2.3 m.put(q, nq); // ancestor quad to newly cloned quad. 150 cananian 1.1.2.1 } 151 cananian 1.1.2.1 // clone all interior edges. 152 cananian 1.8 for (Object qO : l.loopIncElements()) { 153 cananian 1.8 Quad q = (Quad) qO; 154 cananian 1.1.2.1 for (int i=0; i<q.nextLength(); i++) { 155 cananian 1.1.2.1 Edge e = q.nextEdge(i); 156 cananian 1.3.2.1 assert m.containsKey(e.from()); 157 cananian 1.1.2.1 if (m.containsKey(e.to())) 158 cananian 1.6 Quad.addEdge(m.get(e.from()), e.which_succ(), 159 cananian 1.6 m.get(e.to()), e.which_pred()); 160 cananian 1.1.2.1 } 161 cananian 1.1.2.1 } 162 cananian 1.1.2.1 return m; 163 cananian 1.1.2.1 } 164 cananian 1.2 }