1 cananian 1.1.2.1 /* 2 cananian 1.1.2.1 * RegAlloc/Liveness.java 3 cananian 1.1.2.1 * examine flow graph to determine liveness of temporaries. 4 cananian 1.1.2.1 * 5 cananian 1.1.2.1 * ALGORITHM: Worklist-based algorithm utilizing node pre-sorting 6 cananian 1.1.2.1 * with a DFS for speed. 7 cananian 1.1.2.1 * 8 cananian 1.1.2.1 * C. Scott Ananian, cananian@princeton.edu, COS320 9 cananian 1.1.2.1 */ 10 cananian 1.1.2.1 11 cananian 1.1.2.2 package harpoon.Backend.CSAHack.RegAlloc; 12 cananian 1.1.2.1 13 cananian 1.1.2.2 import harpoon.Temp.Temp; 14 cananian 1.1.2.2 import harpoon.Temp.TempList; 15 cananian 1.1.2.1 16 cananian 1.1.2.2 import harpoon.Backend.CSAHack.Graph.Node; 17 cananian 1.1.2.2 import harpoon.Backend.CSAHack.Graph.NodeList; 18 cananian 1.1.2.2 import harpoon.Backend.CSAHack.FlowGraph.FlowGraph; 19 cananian 1.1.2.2 20 cananian 1.1.2.5 import harpoon.Util.Collections.WorkSet; 21 cananian 1.1.2.1 22 cananian 1.1.2.1 import java.util.Vector; 23 cananian 1.1.2.1 import java.util.Hashtable; 24 cananian 1.1.2.1 import java.util.Enumeration; 25 cananian 1.1.2.1 26 cananian 1.1.2.1 /** 27 cananian 1.1.2.1 * An interference graph by examination of liveness of nodes 28 cananian 1.1.2.1 * in a flow graph. 29 cananian 1.1.2.1 * @version 1.00, 25 Nov 1996 30 cananian 1.1.2.1 * @author C. Scott Ananian 31 cananian 1.1.2.1 */ 32 cananian 1.1.2.1 public class Liveness extends InterferenceGraph { 33 cananian 1.1.2.1 Hashtable temp2node = new Hashtable(); 34 cananian 1.1.2.1 Hashtable nodeuses = new Hashtable(); 35 cananian 1.1.2.1 36 cananian 1.1.2.1 MoveList movelist = null; 37 cananian 1.1.2.1 38 cananian 1.1.2.1 boolean debug = false; // set to true to dump debug information. 39 cananian 1.1.2.1 40 cananian 1.1.2.1 /** 41 cananian 1.1.2.1 * Construct interference graph from flow graph. 42 cananian 1.1.2.1 */ 43 cananian 1.1.2.1 public Liveness(FlowGraph flow) { 44 cananian 1.1.2.1 45 cananian 1.1.2.2 WorkSet worklist = new WorkSet(); 46 cananian 1.1.2.4 DFS(flow.nodes().head, worklist); // add some nodes to worklist. 47 cananian 1.1.2.1 48 cananian 1.1.2.1 // create table of TempSets to represent liveIn and liveOut 49 cananian 1.1.2.1 Hashtable liveIn = new Hashtable(); 50 cananian 1.1.2.1 Hashtable liveOut= new Hashtable(); 51 cananian 1.1.2.1 for (NodeList nl=flow.nodes(); nl!=null; nl=nl.tail) { 52 cananian 1.1.2.1 liveIn.put(nl.head, new TempSet()); 53 cananian 1.1.2.1 liveOut.put(nl.head,new TempSet()); 54 cananian 1.1.2.1 } 55 cananian 1.1.2.1 56 cananian 1.1.2.1 // Worklist algorithm for computing liveness. 57 cananian 1.1.2.1 while(!worklist.isEmpty()) { 58 cananian 1.1.2.2 Node n = (Node) worklist.pop(); 59 cananian 1.1.2.1 60 cananian 1.1.2.1 TempSet out= (TempSet) liveOut.get(n); 61 cananian 1.1.2.1 TempSet in = (TempSet) liveIn.get(n); 62 cananian 1.1.2.1 63 cananian 1.1.2.1 in.resetChange(); 64 cananian 1.1.2.1 65 cananian 1.1.2.1 // compute new out set... 66 cananian 1.1.2.1 for (NodeList nl = n.succ(); nl!=null; nl=nl.tail) 67 cananian 1.1.2.1 out.union((TempSet)liveIn.get(nl.head)); 68 cananian 1.1.2.1 69 cananian 1.1.2.1 // compute the new in set (in = in union (out - def) 70 cananian 1.1.2.1 TempSet t = new TempSet(); 71 cananian 1.1.2.1 t.union(out); 72 cananian 1.1.2.1 t.not(flow.def(n)); 73 cananian 1.1.2.1 74 cananian 1.1.2.1 in.union(flow.use(n)); 75 cananian 1.1.2.1 in.union(t); 76 cananian 1.1.2.1 77 cananian 1.1.2.1 // if new in set included more members than the old... 78 cananian 1.1.2.1 if (in.hasChanged()) { 79 cananian 1.1.2.1 // add all the predecessors of this node to the worklist. 80 cananian 1.1.2.1 for (NodeList nl = n.pred(); nl!=null; nl=nl.tail) 81 cananian 1.1.2.2 worklist.add(nl.head); 82 cananian 1.1.2.1 } 83 cananian 1.1.2.1 } 84 cananian 1.1.2.1 // done! 85 cananian 1.1.2.1 86 cananian 1.1.2.1 // show me the liveOut sets. 87 cananian 1.1.2.1 if (debug) 88 cananian 1.1.2.1 show_liveOut(flow, liveOut); 89 cananian 1.1.2.1 90 cananian 1.1.2.1 // Make interference graph. 91 cananian 1.1.2.1 createGraph(flow, liveIn, liveOut); 92 cananian 1.1.2.1 93 cananian 1.1.2.1 // assemble movelist. 94 cananian 1.1.2.1 makeMoveList(flow); 95 cananian 1.1.2.1 96 cananian 1.1.2.1 // show(System.out); 97 cananian 1.1.2.1 } 98 cananian 1.1.2.1 99 cananian 1.1.2.1 // dump the live-out sets for debugging. 100 cananian 1.1.2.1 private void show_liveOut(FlowGraph flow, Hashtable liveOut) { 101 cananian 1.1.2.1 for(NodeList nl=flow.nodes(); nl!=null; nl=nl.tail) { 102 cananian 1.1.2.1 System.out.println(nl.head.toString()+":"); 103 cananian 1.1.2.1 for (TempList tl=((TempSet)liveOut.get(nl.head)).members(); 104 cananian 1.1.2.1 tl!=null; tl=tl.tail) 105 cananian 1.1.2.1 System.out.print(" "+tl.head.toString()); 106 cananian 1.1.2.1 System.out.print("\n"); 107 cananian 1.1.2.1 } 108 cananian 1.1.2.1 } 109 cananian 1.1.2.1 110 cananian 1.1.2.1 // examine nodes to create move list 111 cananian 1.1.2.1 private void makeMoveList(FlowGraph flow) { 112 cananian 1.1.2.1 for (NodeList nl = flow.nodes(); nl!=null; nl=nl.tail) 113 cananian 1.1.2.1 if (flow.isMove(nl.head)) 114 cananian 1.1.2.1 movelist = new MoveList(tnode(flow.use(nl.head).head), 115 cananian 1.1.2.1 tnode(flow.def(nl.head).head), 116 cananian 1.1.2.1 movelist); 117 cananian 1.1.2.1 } 118 cananian 1.1.2.2 119 cananian 1.1.2.2 // add all nodes in (reverse) DFS order. 120 cananian 1.1.2.4 private void DFS(Node n, WorkSet worklist) { 121 cananian 1.1.2.4 WorkSet stack = new WorkSet(); 122 cananian 1.1.2.4 stack.add(n); 123 cananian 1.1.2.4 while (!stack.isEmpty()) { 124 cananian 1.1.2.4 Node nn = (Node) stack.pop(); 125 cananian 1.1.2.4 worklist.add(nn); 126 cananian 1.1.2.4 for (NodeList nl=nn.succ(); nl!=null; nl=nl.tail) 127 cananian 1.1.2.4 if (!worklist.contains(nl.head)) 128 cananian 1.1.2.4 stack.add(nl.head); 129 cananian 1.1.2.1 } 130 cananian 1.1.2.1 } 131 cananian 1.1.2.1 132 cananian 1.1.2.1 // Create nodes and edges of interference graph from the liveness 133 cananian 1.1.2.1 // information. 134 cananian 1.1.2.1 private void createGraph(FlowGraph flow, 135 cananian 1.1.2.1 Hashtable liveIn, Hashtable liveOut) { 136 cananian 1.1.2.1 // for each node in the flow graph 137 cananian 1.1.2.1 for (NodeList nl = flow.nodes(); nl!=null; nl=nl.tail) 138 cananian 1.1.2.1 // for each definition in that node 139 cananian 1.1.2.1 for (TempList dl = flow.def(nl.head); dl!=null; dl=dl.tail) 140 cananian 1.1.2.1 // for each live temporary at that node 141 cananian 1.1.2.1 for (TempList tl = ((TempSet)liveOut.get(nl.head)).members(); 142 cananian 1.1.2.1 tl!=null; tl=tl.tail) 143 cananian 1.1.2.1 // add interference edges, conditionally 144 cananian 1.1.2.1 addSomeEdges(flow, nl.head, dl.head, tl.head); 145 cananian 1.1.2.1 146 cananian 1.1.2.1 //------------------------------------------------------- 147 cananian 1.1.2.1 148 cananian 1.1.2.1 // Now count defs and uses of each variable, to aid in the 149 cananian 1.1.2.1 // later computation of spillCost() 150 cananian 1.1.2.1 151 cananian 1.1.2.1 // for each node in the flow graph 152 cananian 1.1.2.1 for (NodeList nl = flow.nodes(); nl!=null; nl=nl.tail) { 153 cananian 1.1.2.1 // for each definition in that node 154 cananian 1.1.2.1 for (TempList dl = flow.def(nl.head); dl!=null; dl=dl.tail) { 155 cananian 1.1.2.1 // increment the nodeuse 156 cananian 1.1.2.1 Node defnode = tnode(dl.head); 157 cananian 1.1.2.1 Integer n = (Integer) nodeuses.get(defnode); 158 cananian 1.1.2.1 if (n==null) n=new Integer(0); 159 cananian 1.1.2.1 nodeuses.put(defnode, new Integer(n.intValue()+1)); 160 cananian 1.1.2.1 } 161 cananian 1.1.2.1 // for each use in that node 162 cananian 1.1.2.1 for (TempList dl = flow.use(nl.head); dl!=null; dl=dl.tail) { 163 cananian 1.1.2.1 // increment the nodeuse 164 cananian 1.1.2.1 Node usenode = tnode(dl.head); 165 cananian 1.1.2.1 Integer n = (Integer) nodeuses.get(usenode); 166 cananian 1.1.2.1 if (n==null) n=new Integer(0); 167 cananian 1.1.2.1 nodeuses.put(usenode, new Integer(n.intValue()+1)); 168 cananian 1.1.2.1 } 169 cananian 1.1.2.1 } 170 cananian 1.1.2.1 } 171 cananian 1.1.2.1 private void addSomeEdges(FlowGraph flow, Node flownode, 172 cananian 1.1.2.1 Temp deftemp, Temp livetemp) { 173 cananian 1.1.2.1 // if this is a move instruction, maybe we don't want to add this edge 174 cananian 1.1.2.1 if (flow.isMove(flownode)) 175 cananian 1.1.2.1 // see if this livetemp is part of the source of this move 176 cananian 1.1.2.1 for (TempList sl = flow.use(flownode); sl!=null; sl=sl.tail) 177 cananian 1.1.2.1 // if so, don't add an edge 178 cananian 1.1.2.1 if (sl.head == livetemp) 179 cananian 1.1.2.1 return; 180 cananian 1.1.2.1 181 cananian 1.1.2.1 // tests okay, add the edge. 182 cananian 1.1.2.1 addEdge(tnode(deftemp), tnode(livetemp)); 183 cananian 1.1.2.1 addEdge(tnode(livetemp),tnode(deftemp)); 184 cananian 1.1.2.1 } 185 cananian 1.1.2.1 186 cananian 1.1.2.1 /** 187 cananian 1.1.2.1 * @param temp a temporary used in the flow graph 188 cananian 1.1.2.1 * @return the interference graph node corresponding to the temporary. 189 cananian 1.1.2.1 */ 190 cananian 1.1.2.1 public Node tnode(Temp temp) { 191 cananian 1.1.2.1 Node n = (Node) temp2node.get(temp); 192 cananian 1.1.2.1 if (n==null) 193 cananian 1.1.2.1 // make new nodes on demand. 194 cananian 1.1.2.1 return newNode(temp); 195 cananian 1.1.2.1 else return n; 196 cananian 1.1.2.1 } 197 cananian 1.1.2.1 /** 198 cananian 1.1.2.1 * @param node a node in the interference graph. 199 cananian 1.1.2.1 * @return the temporary corresponding to the node. 200 cananian 1.1.2.1 */ 201 cananian 1.1.2.1 public Temp gtemp(Node node) { 202 cananian 1.1.2.1 if (!(node instanceof TempNode)) 203 cananian 1.1.2.1 throw new Error("Node "+node.toString()+" not a member of graph."); 204 cananian 1.1.2.1 else return ((TempNode)node).temp; 205 cananian 1.1.2.1 } 206 cananian 1.1.2.1 /** 207 cananian 1.1.2.1 * @param node a node in the interference graph. 208 cananian 1.1.2.1 * @return an estimate of the cost of spilling this node. 209 cananian 1.1.2.1 */ 210 cananian 1.1.2.1 public int spillCost(Node node) { 211 cananian 1.1.2.1 // Our heuristic: the number of uses and defs of this node, divided by 212 cananian 1.1.2.1 // degree (to make more conflicted nodes better to spill). 213 cananian 1.1.2.1 // Scaled by 1000 to accomodate integer division. 214 cananian 1.1.2.1 Integer numuses = (Integer) nodeuses.get(node); 215 cananian 1.1.2.1 return 1000*numuses.intValue()/node.degree(); 216 cananian 1.1.2.1 } 217 cananian 1.1.2.1 /** 218 cananian 1.1.2.1 * @return a list of moves found in the flow graph. 219 cananian 1.1.2.1 */ 220 cananian 1.1.2.1 public MoveList moves() { 221 cananian 1.1.2.1 return movelist; 222 cananian 1.1.2.1 } 223 cananian 1.1.2.1 public Node newNode(Temp t) { 224 cananian 1.1.2.1 TempNode n = new TempNode(this, t); 225 cananian 1.1.2.1 temp2node.put(t, n); 226 cananian 1.1.2.1 return n; 227 cananian 1.1.2.1 } 228 cananian 1.1.2.1 } 229 cananian 1.1.2.1 230 cananian 1.1.2.1 /** 231 cananian 1.1.2.1 * Sub-class to associate a temporary with a Graph.Node. 232 cananian 1.1.2.2 * @see harpoon.Temp.Temp 233 cananian 1.1.2.1 */ 234 cananian 1.1.2.2 class TempNode extends harpoon.Backend.CSAHack.Graph.Node { 235 cananian 1.1.2.1 Temp temp; 236 cananian 1.1.2.2 TempNode(harpoon.Backend.CSAHack.Graph.Graph g, Temp t) { 237 cananian 1.1.2.1 super(g); 238 cananian 1.1.2.1 temp = t; 239 cananian 1.1.2.1 } 240 cananian 1.1.2.1 public String toString() { 241 cananian 1.1.2.1 return temp.toString(); // +"("+super.toString()+")"; 242 cananian 1.1.2.1 } 243 cananian 1.1.2.3 public int hashCode() { return temp.hashCode(); } 244 cananian 1.1.2.1 } 245 cananian 1.1.2.1 246 cananian 1.1.2.1 /** 247 cananian 1.1.2.1 * A set of temporaries, based on a hashtable. 248 cananian 1.1.2.1 */ 249 cananian 1.1.2.1 class TempSet { 250 cananian 1.1.2.1 boolean dirty = false; 251 cananian 1.1.2.1 Hashtable h = new Hashtable(); 252 cananian 1.1.2.1 253 cananian 1.1.2.1 /** 254 cananian 1.1.2.1 * create a new empty set. 255 cananian 1.1.2.1 */ 256 cananian 1.1.2.1 TempSet() { } 257 cananian 1.1.2.1 /** 258 cananian 1.1.2.1 * create a new set. 259 cananian 1.1.2.1 * @param tl a list of initial members of the set. 260 cananian 1.1.2.1 */ 261 cananian 1.1.2.1 TempSet(TempList tl) { union(tl); } 262 cananian 1.1.2.1 263 cananian 1.1.2.1 /** 264 cananian 1.1.2.1 * add a member to the set, if not previously present. 265 cananian 1.1.2.1 * @param t a temporary to add to the set. 266 cananian 1.1.2.1 */ 267 cananian 1.1.2.1 void add(Temp t) { 268 cananian 1.1.2.1 if (!contains(t)) { 269 cananian 1.1.2.1 h.put(t, new Object()); 270 cananian 1.1.2.1 dirty=true; 271 cananian 1.1.2.1 } 272 cananian 1.1.2.1 } 273 cananian 1.1.2.1 /** 274 cananian 1.1.2.1 * remove an element, if it is a member of the set. 275 cananian 1.1.2.1 * @param t a temporary to be removed from the set. 276 cananian 1.1.2.1 */ 277 cananian 1.1.2.1 void remove(Temp t) { 278 cananian 1.1.2.1 if (contains(t)) { 279 cananian 1.1.2.1 h.remove(t); 280 cananian 1.1.2.1 dirty=true; 281 cananian 1.1.2.1 } 282 cananian 1.1.2.1 } 283 cananian 1.1.2.1 /** 284 cananian 1.1.2.1 * add to this set all the members of another. 285 cananian 1.1.2.1 */ 286 cananian 1.1.2.1 void union(TempSet ts) { union(ts.members()); } 287 cananian 1.1.2.1 /** 288 cananian 1.1.2.1 * add a list of temporaries to this set. 289 cananian 1.1.2.1 */ 290 cananian 1.1.2.1 void union(TempList tl) { 291 cananian 1.1.2.1 for ( ; tl!=null; tl=tl.tail) 292 cananian 1.1.2.1 add(tl.head); 293 cananian 1.1.2.1 } 294 cananian 1.1.2.1 /** 295 cananian 1.1.2.1 * remove from this set all the members of another. 296 cananian 1.1.2.1 */ 297 cananian 1.1.2.1 void not(TempSet ts) { not(ts.members()); } 298 cananian 1.1.2.1 /** 299 cananian 1.1.2.1 * remove a list of temporaries from this set. 300 cananian 1.1.2.1 */ 301 cananian 1.1.2.1 void not(TempList tl) { 302 cananian 1.1.2.1 for ( ; tl!=null; tl=tl.tail) 303 cananian 1.1.2.1 remove(tl.head); 304 cananian 1.1.2.1 } 305 cananian 1.1.2.1 /** 306 cananian 1.1.2.1 * Create a list of the members of this set. 307 cananian 1.1.2.1 */ 308 cananian 1.1.2.1 TempList members() { 309 cananian 1.1.2.1 TempList m = null; 310 cananian 1.1.2.1 Enumeration e=h.keys(); 311 cananian 1.1.2.1 while( e.hasMoreElements() ) 312 cananian 1.1.2.1 m = new TempList((Temp)e.nextElement(), m); 313 cananian 1.1.2.1 return m; 314 cananian 1.1.2.1 } 315 cananian 1.1.2.1 /** 316 cananian 1.1.2.1 * @param t a temporary 317 cananian 1.1.2.1 * @return true if t is a member of the set. 318 cananian 1.1.2.1 */ 319 cananian 1.1.2.1 boolean contains(Temp t) { 320 cananian 1.1.2.1 return h.get(t)!=null; 321 cananian 1.1.2.1 } 322 cananian 1.1.2.1 void resetChange() { dirty = false; } 323 cananian 1.1.2.1 /** 324 cananian 1.1.2.1 * @return true if members have been added or removed since the last call to resetChange(); false otherwise. 325 cananian 1.1.2.1 */ 326 cananian 1.1.2.1 boolean hasChanged() { return dirty; } 327 cananian 1.1.2.1 } 328 cananian 1.2