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 */ 013 package org.jikesrvm.compilers.opt.dfsolver; 014 015 import java.util.Comparator; 016 import java.util.Enumeration; 017 import java.util.HashSet; 018 import java.util.Iterator; 019 import java.util.TreeSet; 020 021 import org.jikesrvm.compilers.opt.util.FilterEnumerator; 022 import org.jikesrvm.compilers.opt.util.Graph; 023 import org.jikesrvm.compilers.opt.util.GraphNode; 024 import org.jikesrvm.compilers.opt.util.GraphUtilities; 025 import 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 */ 038 public 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 String result = "EQUATIONS:\n"; 110 Enumeration<GraphNode> v = equations.enumerateNodes(); 111 for (int i = 0; i < equations.numberOfNodes(); i++) { 112 result = result + i + " : " + v.nextElement() + "\n"; 113 } 114 return result; 115 } 116 117 /** 118 * Return an Enumeration over the equations in this system. 119 * @return an Enumeration over the equations in this system 120 */ 121 public Enumeration<DF_Equation> getEquations() { 122 return new FilterEnumerator<GraphNode, DF_Equation>(equations.enumerateNodes(), 123 new FilterEnumerator.Filter<GraphNode, DF_Equation>() { 124 @Override 125 public boolean isElement(GraphNode x) { 126 return x instanceof DF_Equation; 127 } 128 }); 129 } 130 131 /** 132 * Get the number of equations in this system 133 * @return the number of equations in this system 134 */ 135 public int getNumberOfEquations() { 136 return equations.numberOfNodes(); 137 } 138 139 /** 140 * Add an equation to the work list. 141 * @param eq the equation to add 142 */ 143 public void addToWorkList(DF_Equation eq) { 144 workList.add(eq); 145 } 146 147 /** 148 * Add all new equations to the work list. 149 */ 150 public void addNewEquationsToWorkList() { 151 if (DEBUG) { 152 System.out.println("new equations:"); 153 } 154 for (DF_Equation eq : newEquations) { 155 if (DEBUG) { 156 System.out.println(eq.toString()); 157 } 158 addToWorkList(eq); 159 } 160 newEquations.clear(); 161 if (DEBUG) { 162 System.out.println("end of new equations"); 163 } 164 } 165 166 /** 167 * Add all equations to the work list. 168 */ 169 public void addAllEquationsToWorkList() { 170 for (Enumeration<DF_Equation> e = getEquations(); e.hasMoreElements();) { 171 DF_Equation eq = e.nextElement(); 172 addToWorkList(eq); 173 } 174 } 175 176 /** 177 * Call this method when the contents of a lattice cell 178 * changes. This routine adds all equations using this cell 179 * to the set of new equations. 180 * @param cell the lattice cell that has changed 181 */ 182 public void changedCell(DF_LatticeCell cell) { 183 Iterator<DF_Equation> e = cell.getUses(); 184 while (e.hasNext()) { 185 newEquations.add(e.next()); 186 } 187 } 188 189 /** 190 * Find the cell matching this key. If none found, create one. 191 * 192 * @param key the key for the lattice cell. 193 */ 194 protected DF_LatticeCell findOrCreateCell(Object key) { 195 DF_LatticeCell result = cells.get(key); 196 if (result == null) { 197 result = makeCell(key); 198 cells.put(key, result); 199 } 200 return result; 201 } 202 203 /** 204 * Add an equation with one operand on the right-hand side. 205 * 206 * @param lhs the lattice cell set by this equation 207 * @param operator the equation operator 208 * @param op1 first operand on the rhs 209 */ 210 protected void newEquation(DF_LatticeCell lhs, DF_Operator operator, DF_LatticeCell op1) { 211 // add to the list of equations 212 DF_Equation eq = new DF_Equation(lhs, operator, op1); 213 equations.addGraphNode(eq); 214 equations.addGraphNode(lhs); 215 equations.addGraphNode(op1); 216 newEquations.add(eq); 217 // add lattice cells for the operands to the working solution 218 // cells.put(lhs.getKey(),lhs); 219 // cells.put(op1.getKey(),op1); 220 op1.addUse(eq); 221 lhs.addDef(eq); 222 if (EAGER && eq.evaluate()) changedCell(lhs); 223 } 224 225 /** 226 * Add an equation with two operands on the right-hand side. 227 * 228 * @param lhs the lattice cell set by this equation 229 * @param operator the equation operator 230 * @param op1 first operand on the rhs 231 * @param op2 second operand on the rhs 232 */ 233 void newEquation(DF_LatticeCell lhs, DF_Operator operator, DF_LatticeCell op1, DF_LatticeCell op2) { 234 // add to the list of equations 235 DF_Equation eq = new DF_Equation(lhs, operator, op1, op2); 236 equations.addGraphNode(eq); 237 equations.addGraphNode(lhs); 238 equations.addGraphNode(op1); 239 equations.addGraphNode(op2); 240 newEquations.add(eq); 241 // add lattice cells for the operands to the working solution 242 // cells.put(lhs.getKey(),lhs); 243 // cells.put(op1.getKey(),op1); 244 op1.addUse(eq); 245 // cells.put(op2.getKey(),op2); 246 op2.addUse(eq); 247 lhs.addDef(eq); 248 if (EAGER && eq.evaluate()) changedCell(lhs); 249 } 250 251 /** 252 * Add an equation with three operands on the right-hand side. 253 * 254 * @param lhs the lattice cell set by this equation 255 * @param operator the equation operator 256 * @param op1 first operand on the rhs 257 * @param op2 second operand on the rhs 258 * @param op3 third operand on the rhs 259 */ 260 void newEquation(DF_LatticeCell lhs, DF_Operator operator, DF_LatticeCell op1, DF_LatticeCell op2, 261 DF_LatticeCell op3) { 262 // add to the list of equations 263 DF_Equation eq = new DF_Equation(lhs, operator, op1, op2, op3); 264 equations.addGraphNode(eq); 265 equations.addGraphNode(lhs); 266 equations.addGraphNode(op1); 267 equations.addGraphNode(op2); 268 equations.addGraphNode(op3); 269 newEquations.add(eq); 270 // add lattice cells for the operands to the working solution 271 // cells.put(lhs.getKey(),lhs); 272 // cells.put(op1.getKey(),op1); 273 op1.addUse(eq); 274 // cells.put(op2.getKey(),op2); 275 op2.addUse(eq); 276 // cells.put(op3.getKey(),op3); 277 op3.addUse(eq); 278 lhs.addDef(eq); 279 if (EAGER && eq.evaluate()) changedCell(lhs); 280 } 281 282 /** 283 * Add an equation to the system with an arbitrary number of operands on 284 * the right-hand side. 285 * 286 * @param lhs lattice cell set by this equation 287 * @param operator the equation operator 288 * @param rhs the operands on the rhs 289 */ 290 protected void newEquation(DF_LatticeCell lhs, DF_Operator operator, DF_LatticeCell[] rhs) { 291 // add to the list of equations 292 DF_Equation eq = new DF_Equation(lhs, operator, rhs); 293 equations.addGraphNode(eq); 294 equations.addGraphNode(lhs); 295 newEquations.add(eq); 296 // add the operands to the working solution 297 // cells.put(lhs.getKey(),lhs); 298 for (DF_LatticeCell rh : rhs) { 299 // cells.put(rhs[i].getKey(),rhs[i]); 300 rh.addUse(eq); 301 equations.addGraphNode(rh); 302 } 303 lhs.addDef(eq); 304 if (EAGER && eq.evaluate()) changedCell(lhs); 305 } 306 307 /** 308 * Add an existing equation to the system 309 * 310 * @param eq the equation 311 */ 312 void addEquation(DF_Equation eq) { 313 equations.addGraphNode(eq); 314 newEquations.add(eq); 315 316 DF_LatticeCell lhs = eq.getLHS(); 317 if (!(lhs.getDefs().hasNext() || lhs.getUses().hasNext())) { 318 lhs.addDef(eq); 319 equations.addGraphNode(lhs); 320 } else { 321 lhs.addDef(eq); 322 } 323 324 DF_LatticeCell[] operands = eq.getOperands(); 325 for (int i = 1; i < operands.length; i++) { 326 DF_LatticeCell op = operands[i]; 327 if (!(op.getDefs().hasNext() || op.getUses().hasNext())) { 328 op.addUse(eq); 329 equations.addGraphNode(op); 330 } else { 331 op.addUse(eq); 332 } 333 } 334 335 if (EAGER && eq.evaluate()) changedCell(lhs); 336 } 337 338 /** 339 * Return the DF_LatticeCell corresponding to a key. 340 * 341 * @param key the key 342 * @return the LatticeCell if found. null otherwise 343 */ 344 public DF_LatticeCell getCell(Object key) { 345 return cells.get(key); 346 } 347 348 /** 349 * Add all equations which contain a given cell to the work list. 350 * @param cell the cell in question 351 */ 352 public void addCellAppearancesToWorkList(DF_LatticeCell cell) { 353 for (Enumeration<DF_Equation> e = getEquations(); e.hasMoreElements();) { 354 DF_Equation eq = e.nextElement(); 355 if (eq.hasCell(cell)) { 356 addToWorkList(eq); 357 } 358 } 359 } 360 361 private static final Comparator<DF_Equation> dfComparator = new Comparator<DF_Equation>() { 362 @Override 363 public int compare(DF_Equation o1, DF_Equation o2) { 364 DF_Equation eq1 = o1; 365 DF_Equation eq2 = o2; 366 return (eq1.topologicalNumber - eq2.topologicalNumber); 367 } 368 }; 369 370 /** 371 * Initialize all lattice cells in the system. 372 */ 373 protected abstract void initializeLatticeCells(); 374 375 /** 376 * Initialize the work list for iteration.j 377 */ 378 protected abstract void initializeWorkList(); 379 380 /** 381 * Create a new lattice cell, referenced by a given key 382 * @param key key to look up the new cell with 383 * @return the newly created lattice cell 384 */ 385 protected abstract DF_LatticeCell makeCell(Object key); 386 387 /** 388 * Update the worklist, assuming that a particular equation 389 * has been re-evaluated 390 * 391 * @param eq the equation that has been re-evaluated. 392 */ 393 protected void updateWorkList(DF_Equation eq) { 394 // find each equation which uses this lattice cell, and 395 // add it to the work list 396 Iterator<DF_Equation> e = eq.getLHS().getUses(); 397 while (e.hasNext()) { 398 workList.add(e.next()); 399 } 400 } 401 402 /** 403 * Number the equations in topological order. 404 * 405 * <p> PRECONDITION: Already called addGraphEdges() 406 * 407 * <p>Algorithm: 408 * <ul> 409 * <li> 1. create a DAG of SCCs 410 * <li> 2. number this DAG topologically 411 * <li> 3. walk through the DAG and number nodes as they are 412 * encountered 413 * </ul> 414 */ 415 private void numberEquationsTopological() { 416 Enumeration<GraphNode> topOrder = GraphUtilities. 417 enumerateTopSort(equations); 418 Enumeration<GraphNode> rev = new ReverseDFSenumerateByFinish(equations, topOrder); 419 int number = 0; 420 while (rev.hasMoreElements()) { 421 GraphNode elt = rev.nextElement(); 422 if (elt instanceof DF_Equation) { 423 DF_Equation eq = (DF_Equation) elt; 424 eq.setTopologicalNumber(number++); 425 } 426 } 427 } 428 429 /** 430 * Debugging aid: print statistics about the dataflow system. 431 */ 432 void showGraphStats() { 433 System.out.println("graph has " + equations.numberOfNodes() + " nodes"); 434 int count = 0; 435 for (Enumeration<GraphNode> e = equations.enumerateNodes(); e.hasMoreElements();) { 436 GraphNode eq = e.nextElement(); 437 Enumeration<GraphNode> outs = eq.outNodes(); 438 while (outs.hasMoreElements()) { 439 count++; 440 outs.nextElement(); 441 } 442 } 443 System.out.println("graph has " + count + " edges"); 444 } 445 }