001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.compilers.opt.dfsolver; 014 015import java.util.Comparator; 016import java.util.Enumeration; 017import java.util.HashSet; 018import java.util.Iterator; 019import java.util.TreeSet; 020 021import org.jikesrvm.compilers.opt.util.FilterEnumerator; 022import org.jikesrvm.compilers.opt.util.Graph; 023import org.jikesrvm.compilers.opt.util.GraphNode; 024import org.jikesrvm.compilers.opt.util.GraphUtilities; 025import org.jikesrvm.compilers.opt.util.ReverseDFSenumerateByFinish; 026 027/** 028 * Represents a system of Data Flow equations 029 * 030 * <p> Implementation Note: 031 * The set of equations is internally represented as a graph 032 * (actually a SpaceEffGraph). Each dataflow equation is a node in the 033 * graph. If a dataflow equation produces a lattice cell value 034 * that is used by another equation, the graph has a directed edge 035 * from the producer to the consumer. Fixed-point iteration proceeds 036 * in a topological order according to these edges. 037 */ 038public abstract class DF_System { 039 private static final boolean DEBUG = false; 040 041 private final boolean EAGER; 042 043 /** 044 * The equations that comprise this dataflow system. 045 */ 046 private final Graph equations = new DF_Graph(); 047 048 /** 049 * Set of equations pending evaluation 050 */ 051 protected final TreeSet<DF_Equation> workList = new TreeSet<DF_Equation>(dfComparator); 052 053 /** 054 * Set of equations considered "new" 055 */ 056 private final HashSet<DF_Equation> newEquations = new HashSet<DF_Equation>(); 057 058 /** 059 * The lattice cells of the system: Mapping from Object to DF_LatticeCell 060 */ 061 protected final DF_Solution cells = new DF_Solution(); 062 063 public DF_System() { 064 EAGER = false; 065 } 066 067 public DF_System(boolean eager) { 068 EAGER = eager; 069 } 070 071 /** 072 * Solve the set of dataflow equations. 073 * <p> PRECONDITION: equations are set up 074 */ 075 public void solve() { 076 // addGraphEdges(); 077 numberEquationsTopological(); 078 initializeLatticeCells(); 079 initializeWorkList(); 080 while (!workList.isEmpty()) { 081 DF_Equation eq = workList.first(); 082 workList.remove(eq); 083 boolean change = eq.evaluate(); 084 if (DEBUG) { 085 System.out.println("After evaluation " + eq); 086 } 087 if (change) { 088 updateWorkList(eq); 089 } 090 } 091 } 092 093 /** 094 * Return the solution of the dataflow equation system. 095 * This is only valid after calling solve() 096 * 097 * @return the solution 098 */ 099 public DF_Solution getSolution() { 100 return cells; 101 } 102 103 /** 104 * Return a string representation of the system 105 * @return a string representation of the system 106 */ 107 @Override 108 public String toString() { 109 StringBuilder result = new StringBuilder("EQUATIONS:\n"); 110 Enumeration<GraphNode> v = equations.enumerateNodes(); 111 for (int i = 0; i < equations.numberOfNodes(); i++) { 112 result.append(i); 113 result.append(" : "); 114 result.append(v.nextElement()); 115 result.append('\n'); 116 } 117 return result.toString(); 118 } 119 120 /** 121 * Return an Enumeration over the equations in this system. 122 * @return an Enumeration over the equations in this system 123 */ 124 public Enumeration<DF_Equation> getEquations() { 125 return new FilterEnumerator<GraphNode, DF_Equation>(equations.enumerateNodes(), 126 new FilterEnumerator.Filter<GraphNode, DF_Equation>() { 127 @Override 128 public boolean isElement(GraphNode x) { 129 return x instanceof DF_Equation; 130 } 131 }); 132 } 133 134 /** 135 * Get the number of equations in this system 136 * @return the number of equations in this system 137 */ 138 public int getNumberOfEquations() { 139 return equations.numberOfNodes(); 140 } 141 142 /** 143 * Add an equation to the work list. 144 * @param eq the equation to add 145 */ 146 public void addToWorkList(DF_Equation eq) { 147 workList.add(eq); 148 } 149 150 /** 151 * Add all new equations to the work list. 152 */ 153 public void addNewEquationsToWorkList() { 154 if (DEBUG) { 155 System.out.println("new equations:"); 156 } 157 for (DF_Equation eq : newEquations) { 158 if (DEBUG) { 159 System.out.println(eq.toString()); 160 } 161 addToWorkList(eq); 162 } 163 newEquations.clear(); 164 if (DEBUG) { 165 System.out.println("end of new equations"); 166 } 167 } 168 169 /** 170 * Add all equations to the work list. 171 */ 172 public void addAllEquationsToWorkList() { 173 for (Enumeration<DF_Equation> e = getEquations(); e.hasMoreElements();) { 174 DF_Equation eq = e.nextElement(); 175 addToWorkList(eq); 176 } 177 } 178 179 /** 180 * Call this method when the contents of a lattice cell 181 * changes. This routine adds all equations using this cell 182 * to the set of new equations. 183 * @param cell the lattice cell that has changed 184 */ 185 public void changedCell(DF_LatticeCell cell) { 186 Iterator<DF_Equation> e = cell.getUses(); 187 while (e.hasNext()) { 188 newEquations.add(e.next()); 189 } 190 } 191 192 /** 193 * Finds the cell matching this key. If none found, creates one. 194 * 195 * @param key the key for the lattice cell 196 * @return a suitable cell 197 */ 198 protected DF_LatticeCell findOrCreateCell(Object key) { 199 DF_LatticeCell result = cells.get(key); 200 if (result == null) { 201 result = makeCell(key); 202 cells.put(key, result); 203 } 204 return result; 205 } 206 207 /** 208 * Add an equation with one operand on the right-hand side. 209 * 210 * @param lhs the lattice cell set by this equation 211 * @param operator the equation operator 212 * @param op1 first operand on the rhs 213 */ 214 protected void newEquation(DF_LatticeCell lhs, DF_Operator operator, DF_LatticeCell op1) { 215 // add to the list of equations 216 DF_Equation eq = new DF_Equation(lhs, operator, op1); 217 equations.addGraphNode(eq); 218 equations.addGraphNode(lhs); 219 equations.addGraphNode(op1); 220 newEquations.add(eq); 221 // add lattice cells for the operands to the working solution 222 // cells.put(lhs.getKey(),lhs); 223 // cells.put(op1.getKey(),op1); 224 op1.addUse(eq); 225 lhs.addDef(eq); 226 if (EAGER && eq.evaluate()) changedCell(lhs); 227 } 228 229 /** 230 * Add an equation with two operands on the right-hand side. 231 * 232 * @param lhs the lattice cell set by this equation 233 * @param operator the equation operator 234 * @param op1 first operand on the rhs 235 * @param op2 second operand on the rhs 236 */ 237 void newEquation(DF_LatticeCell lhs, DF_Operator operator, DF_LatticeCell op1, DF_LatticeCell op2) { 238 // add to the list of equations 239 DF_Equation eq = new DF_Equation(lhs, operator, op1, op2); 240 equations.addGraphNode(eq); 241 equations.addGraphNode(lhs); 242 equations.addGraphNode(op1); 243 equations.addGraphNode(op2); 244 newEquations.add(eq); 245 // add lattice cells for the operands to the working solution 246 // cells.put(lhs.getKey(),lhs); 247 // cells.put(op1.getKey(),op1); 248 op1.addUse(eq); 249 // cells.put(op2.getKey(),op2); 250 op2.addUse(eq); 251 lhs.addDef(eq); 252 if (EAGER && eq.evaluate()) changedCell(lhs); 253 } 254 255 /** 256 * Add an equation with three operands on the right-hand side. 257 * 258 * @param lhs the lattice cell set by this equation 259 * @param operator the equation operator 260 * @param op1 first operand on the rhs 261 * @param op2 second operand on the rhs 262 * @param op3 third operand on the rhs 263 */ 264 void newEquation(DF_LatticeCell lhs, DF_Operator operator, DF_LatticeCell op1, DF_LatticeCell op2, 265 DF_LatticeCell op3) { 266 // add to the list of equations 267 DF_Equation eq = new DF_Equation(lhs, operator, op1, op2, op3); 268 equations.addGraphNode(eq); 269 equations.addGraphNode(lhs); 270 equations.addGraphNode(op1); 271 equations.addGraphNode(op2); 272 equations.addGraphNode(op3); 273 newEquations.add(eq); 274 // add lattice cells for the operands to the working solution 275 // cells.put(lhs.getKey(),lhs); 276 // cells.put(op1.getKey(),op1); 277 op1.addUse(eq); 278 // cells.put(op2.getKey(),op2); 279 op2.addUse(eq); 280 // cells.put(op3.getKey(),op3); 281 op3.addUse(eq); 282 lhs.addDef(eq); 283 if (EAGER && eq.evaluate()) changedCell(lhs); 284 } 285 286 /** 287 * Add an equation to the system with an arbitrary number of operands on 288 * the right-hand side. 289 * 290 * @param lhs lattice cell set by this equation 291 * @param operator the equation operator 292 * @param rhs the operands on the rhs 293 */ 294 protected void newEquation(DF_LatticeCell lhs, DF_Operator operator, DF_LatticeCell[] rhs) { 295 // add to the list of equations 296 DF_Equation eq = new DF_Equation(lhs, operator, rhs); 297 equations.addGraphNode(eq); 298 equations.addGraphNode(lhs); 299 newEquations.add(eq); 300 // add the operands to the working solution 301 // cells.put(lhs.getKey(),lhs); 302 for (DF_LatticeCell rh : rhs) { 303 // cells.put(rhs[i].getKey(),rhs[i]); 304 rh.addUse(eq); 305 equations.addGraphNode(rh); 306 } 307 lhs.addDef(eq); 308 if (EAGER && eq.evaluate()) changedCell(lhs); 309 } 310 311 /** 312 * Add an existing equation to the system 313 * 314 * @param eq the equation 315 */ 316 void addEquation(DF_Equation eq) { 317 equations.addGraphNode(eq); 318 newEquations.add(eq); 319 320 DF_LatticeCell lhs = eq.getLHS(); 321 if (!(lhs.getDefs().hasNext() || lhs.getUses().hasNext())) { 322 lhs.addDef(eq); 323 equations.addGraphNode(lhs); 324 } else { 325 lhs.addDef(eq); 326 } 327 328 DF_LatticeCell[] operands = eq.getOperands(); 329 for (int i = 1; i < operands.length; i++) { 330 DF_LatticeCell op = operands[i]; 331 if (!(op.getDefs().hasNext() || op.getUses().hasNext())) { 332 op.addUse(eq); 333 equations.addGraphNode(op); 334 } else { 335 op.addUse(eq); 336 } 337 } 338 339 if (EAGER && eq.evaluate()) changedCell(lhs); 340 } 341 342 /** 343 * Return the DF_LatticeCell corresponding to a key. 344 * 345 * @param key the key 346 * @return the LatticeCell if found. null otherwise 347 */ 348 public DF_LatticeCell getCell(Object key) { 349 return cells.get(key); 350 } 351 352 /** 353 * Add all equations which contain a given cell to the work list. 354 * @param cell the cell in question 355 */ 356 public void addCellAppearancesToWorkList(DF_LatticeCell cell) { 357 for (Enumeration<DF_Equation> e = getEquations(); e.hasMoreElements();) { 358 DF_Equation eq = e.nextElement(); 359 if (eq.hasCell(cell)) { 360 addToWorkList(eq); 361 } 362 } 363 } 364 365 private static final Comparator<DF_Equation> dfComparator = new Comparator<DF_Equation>() { 366 @Override 367 public int compare(DF_Equation o1, DF_Equation o2) { 368 DF_Equation eq1 = o1; 369 DF_Equation eq2 = o2; 370 return (eq1.topologicalNumber - eq2.topologicalNumber); 371 } 372 }; 373 374 /** 375 * Initialize all lattice cells in the system. 376 */ 377 protected abstract void initializeLatticeCells(); 378 379 /** 380 * Initialize the work list for iteration.j 381 */ 382 protected abstract void initializeWorkList(); 383 384 /** 385 * Create a new lattice cell, referenced by a given key 386 * @param key key to look up the new cell with 387 * @return the newly created lattice cell 388 */ 389 protected abstract DF_LatticeCell makeCell(Object key); 390 391 /** 392 * Update the worklist, assuming that a particular equation 393 * has been re-evaluated 394 * 395 * @param eq the equation that has been re-evaluated. 396 */ 397 protected void updateWorkList(DF_Equation eq) { 398 // find each equation which uses this lattice cell, and 399 // add it to the work list 400 Iterator<DF_Equation> e = eq.getLHS().getUses(); 401 while (e.hasNext()) { 402 workList.add(e.next()); 403 } 404 } 405 406 /** 407 * Number the equations in topological order. 408 * 409 * <p> PRECONDITION: Already called addGraphEdges() 410 * 411 * <p>Algorithm: 412 * <ul> 413 * <li> 1. create a DAG of SCCs 414 * <li> 2. number this DAG topologically 415 * <li> 3. walk through the DAG and number nodes as they are 416 * encountered 417 * </ul> 418 */ 419 private void numberEquationsTopological() { 420 Enumeration<GraphNode> topOrder = GraphUtilities. 421 enumerateTopSort(equations); 422 Enumeration<GraphNode> rev = new ReverseDFSenumerateByFinish(equations, topOrder); 423 int number = 0; 424 while (rev.hasMoreElements()) { 425 GraphNode elt = rev.nextElement(); 426 if (elt instanceof DF_Equation) { 427 DF_Equation eq = (DF_Equation) elt; 428 eq.setTopologicalNumber(number++); 429 } 430 } 431 } 432 433 /** 434 * Debugging aid: print statistics about the dataflow system. 435 */ 436 void showGraphStats() { 437 System.out.println("graph has " + equations.numberOfNodes() + " nodes"); 438 int count = 0; 439 for (Enumeration<GraphNode> e = equations.enumerateNodes(); e.hasMoreElements();) { 440 GraphNode eq = e.nextElement(); 441 Enumeration<GraphNode> outs = eq.outNodes(); 442 while (outs.hasMoreElements()) { 443 count++; 444 outs.nextElement(); 445 } 446 } 447 System.out.println("graph has " + count + " edges"); 448 } 449}