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.ssa; 014 015import java.util.ArrayList; 016import java.util.Enumeration; 017import java.util.HashMap; 018import java.util.Iterator; 019import java.util.Stack; 020import org.jikesrvm.VM; 021import org.jikesrvm.compilers.opt.ir.IR; 022import org.jikesrvm.compilers.opt.ir.Instruction; 023import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand; 024import org.jikesrvm.compilers.opt.util.GraphNode; 025 026/** 027 * This class holds the results of global value numbering. 028 * ala Alpern, Wegman and Zadeck, PoPL 88. 029 * See Muchnick p.348 for a discussion (which is quite buggy, should 030 * have stuck to the dragon book, which gives a high-level description of 031 * the correct algorithm on page 143). 032 */ 033public final class GlobalValueNumberState { 034 /** 035 * Constant used to flag "unknown" value numbers 036 */ 037 public static final int UNKNOWN = -1; 038 /** 039 * Print verbose debugging output? 040 */ 041 private static final boolean DEBUG = false; 042 /** 043 * Assume parameters are not aliased? 044 */ 045 private static final boolean NO_PARAM_ALIAS = false; 046 047 /** 048 * ArrayList of GVCongruenceClass, indexed by value number. 049 */ 050 private final ArrayList<GVCongruenceClass> B; 051 /** 052 * The value graph. 053 */ 054 final ValueGraph valueGraph; 055 /** 056 * Stack used for a work list. 057 */ 058 private final Stack<GVCongruenceClass> workList; 059 060 /** 061 * Construct a structure to hold global value number results for an IR. 062 * 063 * @param ir governing IR 064 */ 065 GlobalValueNumberState(IR ir) { 066 B = new ArrayList<GVCongruenceClass>(); 067 workList = new Stack<GVCongruenceClass>(); 068 valueGraph = new ValueGraph(ir); 069 globalValueNumber(); 070 } 071 072 /** 073 * Compute node congruence over the value number graph. 074 * 075 * <p> Algorithm: Muchnick pp. 348-355 076 * <p> Note: the Muchnick algorithm is buggy. In particular, it 077 * does not put all needed congruence classes on the worklist. 078 * 079 * <p> Two nodes in the value graph are congruent if one of the 080 * following holds: 081 * <ul> 082 * <li> they are the same node 083 * <li> their labels are identical constants 084 * <li> they have the same operators and their operands are 085 * congruent 086 * </ul> 087 * 088 * <p> Optimistic algorithm: 089 * <ul> 090 * <li> Initially assume all nodes with the same label are congruent 091 * <li> start a work list with all congruence classes that 092 * have multiple operands 093 * <li> choose a congruence class from the worklist. partition its 094 * elements into new congruence classes if we can discover that 095 * they are not congruent. 096 * <li> Add any newly created congruence classes to the work list. 097 * <li> (Here's the step Muchnick omits:) 098 * For each class C which has a dependence on any of the newly 099 * created congruence classes, add C to the work list 100 * <li> repeat until work list is empty 101 * </ul> 102 * 103 * <p> The following method breaks Muchnick's algorithm, which will 104 * assign m and n the same value number. Muchnick's problem is that 105 * it does not put the congruence class for 'int_mul' back on the worklist 106 * when we discover, for example, that i is not congruent to k 107 * <pre> 108 * public int foo(int a, int b, int c, int d, int e, int f, int g, int h) { 109 * int i = a+b; 110 * int j = c+d; 111 * int k = e+f; 112 * int l = g+h; 113 * int m = i * j; 114 * int n = k * l; 115 * int o = m/n; 116 * return o; 117 * } 118 * </pre> 119 */ 120 private void globalValueNumber() { 121 if (DEBUG) { 122 VM.sysWrite(valueGraph.toString()); 123 } 124 // initialize the congurence classes 125 initialize(); 126 // initialize the work list 127 initializeWorkList(); 128 // drain the work list 129 while (!workList.empty()) { 130 GVCongruenceClass partition = workList.pop(); 131 partitionClass(partition); 132 } 133 // all done 134 if (DEBUG) { 135 printValueNumbers(); 136 } 137 } 138 139 void mergeClasses(ValueGraphVertex v1, ValueGraphVertex v2) { 140 if (DEBUG) { 141 System.out.println("@@@@ mergeClasses called with v1 = " + v1 + " ; v2 = " + v2); 142 } 143 144 int val1 = v1.getValueNumber(); 145 int val2 = v2.getValueNumber(); 146 if (val1 == val2) return; 147 148 GVCongruenceClass class1 = B.get(val1); 149 150 while (true) { 151 GVCongruenceClass class2 = B.get(val2); 152 Iterator<ValueGraphVertex> i = class2.iterator(); 153 if (!i.hasNext()) break; 154 ValueGraphVertex v = i.next(); 155 if (DEBUG) { 156 System.out.println("@@@@ moving vertex " + v + " from class " + val2 + " to class " + val1); 157 } 158 class1.addVertex(v); 159 class2.removeVertex(v); 160 v.setValueNumber(val1); 161 } 162 163 // Null out entry for val2 164 B.set(val2, null); 165 } 166 167 /** 168 * Definitely-same relation. 169 * @param name1 first variable 170 * @param name2 second variable 171 * @return true iff the value numbers for two variables are equal 172 */ 173 boolean DS(Object name1, Object name2) { 174 ValueGraphVertex v1 = valueGraph.getVertex(name1); 175 ValueGraphVertex v2 = valueGraph.getVertex(name2); 176 return v1.getValueNumber() == v2.getValueNumber(); 177 } 178 179 /** 180 * Definitely-different relation for two value numbers. 181 * Returns true for the following cases: 182 * <ul> 183 * <li> v1 and v2 are both constants, but don't match 184 * <li> v1 and v2 both result from NEW statements, but don't match 185 * <li> one of v1 and v2 is a parameter, and the other results from a 186 * new statement 187 * </ul> 188 * <p> TODO: add more smarts 189 * @param v1 first value number 190 * @param v2 second value number 191 * @return true iff the value numbers for two variables are definitely 192 * different 193 */ 194 boolean DD(int v1, int v2) { 195 if ((v1 == -1) || (v2 == -1)) { 196 return false; 197 } 198 GVCongruenceClass class1 = B.get(v1); 199 GVCongruenceClass class2 = B.get(v2); 200 Object label1 = class1.getLabel(); 201 Object label2 = class2.getLabel(); 202 // if one is a constant, they must both be ... 203 if (isConstant(label1) && !isConstant(label2)) { 204 return false; 205 } 206 if (!isConstant(label1) && isConstant(label2)) { 207 return false; 208 } 209 if (isConstant(label1)) { 210 return (v1 != v2); 211 } 212 // handle DD for allocations 213 if (isBornAtAllocation(label1)) { 214 if (isBornAtAllocation(label2)) { 215 // both are NEW. Are they dd? 216 return (v1 != v2); 217 } else if (class2.containsParameter()) { 218 // one is NEW, other is parameter. They are DD. 219 return true; 220 } 221 } else { 222 if (isBornAtAllocation(label2)) { 223 if (class1.containsParameter()) { 224 // one is NEW, other is parameter. They are DD. 225 return true; 226 } 227 } 228 } 229 // assume parameters are not aliased? 230 if (NO_PARAM_ALIAS) { 231 if (v1 != v2) { 232 if (class1.containsParameter()) { 233 if (class2.containsParameter()) { 234 return true; 235 } 236 } 237 } 238 } 239 240 // if we haven't figured out they're DD, return false; 241 return false; 242 } 243 244 /** 245 * Definitely-different relation. 246 * Returns true for the following cases: 247 * <ul> 248 * <li> name1 and name2 are both constants, but don't match 249 * <li> name1 and name2 both result from NEW statements, but don't match 250 * <li> one of name1 and name2 is a parameter, and the other results from a 251 * new statement 252 * </ul> 253 * <p> TODO: add more smarts 254 * @param name1 name of first object to compare 255 * @param name2 name of second object to compare 256 * @return true iff the value numbers for two variables are definitely 257 * different 258 */ 259 boolean DD(Object name1, Object name2) { 260 ValueGraphVertex v1 = valueGraph.getVertex(name1); 261 ValueGraphVertex v2 = valueGraph.getVertex(name2); 262 return DD(v1.getValueNumber(), v2.getValueNumber()); 263 } 264 265 GVCongruenceClass congruenceClass(Object name) { 266 ValueGraphVertex v = valueGraph.getVertex(name); 267 return B.get(v.getValueNumber()); 268 } 269 270 /** 271 * Return the (integer) value number for a given variable 272 * 273 * @param name name of the variable to look up 274 * @return its value number 275 */ 276 int getValueNumber(Object name) { 277 ValueGraphVertex v = valueGraph.getVertex(name); 278 if (v == null) { 279 return UNKNOWN; 280 } 281 return v.getValueNumber(); 282 } 283 284 /** 285 * Print the value numbers for each node in the value graph. 286 */ 287 void printValueNumbers() { 288 for (Enumeration<GraphNode> e = valueGraph.enumerateVertices(); e.hasMoreElements();) { 289 ValueGraphVertex v = (ValueGraphVertex) e.nextElement(); 290 int valueNumber = v.getValueNumber(); 291 GVCongruenceClass c = B.get(valueNumber); 292 System.out.println(v.getName() + " " + valueNumber + " " + c.getLabel()); 293 } 294 } 295 296 /** 297 * Initialize the congruence classes, assuming that all nodes 298 * with the same label are congruent. 299 */ 300 private void initialize() { 301 // store a map from label -> congruenceClass 302 HashMap<Object, GVCongruenceClass> labelMap = new HashMap<Object, GVCongruenceClass>(10); 303 for (Enumeration<GraphNode> e = valueGraph.enumerateVertices(); e.hasMoreElements();) { 304 ValueGraphVertex v = (ValueGraphVertex) e.nextElement(); 305 Object label = v.getLabel(); 306 GVCongruenceClass c = findOrCreateCongruenceClass(label, labelMap); 307 // add this node to the congruence class 308 c.addVertex(v); 309 // set the value number for the node 310 v.setValueNumber(c.getValueNumber()); 311 } 312 } 313 314 /** 315 * Given a label, return the congruence class for that label. 316 * Create one if needed. 317 * 318 * @param label the label of a congruence class 319 * @param labelMap a mapping from labels to congruence class 320 * @return the congruence class for the label. 321 */ 322 private GVCongruenceClass findOrCreateCongruenceClass(Object label, 323 HashMap<Object, GVCongruenceClass> labelMap) { 324 GVCongruenceClass result = labelMap.get(label); 325 if ((result == null) || (label == null)) { 326 result = createCongruenceClass(label); 327 labelMap.put(label, result); 328 } 329 return result; 330 } 331 332 /** 333 * Given a label, return a new congruence class for that label. 334 * @param label the label of a congruence class 335 * @return the congruence class for the label. 336 */ 337 private GVCongruenceClass createCongruenceClass(Object label) { 338 // create a new congruence class, and update data structures 339 int index = B.size(); 340 GVCongruenceClass result = new GVCongruenceClass(index, label); 341 B.add(result); 342 return result; 343 } 344 345 /** 346 * Initialize the work list. 347 * A congruence class gets put on the work list if any two nodes 348 * in the class point to corresponding targets in separate partitions. 349 */ 350 private void initializeWorkList() { 351 for (GVCongruenceClass c : B) { 352 if (c.size() == 1) { 353 continue; 354 } 355 // store a reference to the first node in c 356 Iterator<ValueGraphVertex> i = c.iterator(); 357 ValueGraphVertex first = i.next(); 358 // now check that each other target matches the first element 359 // if not, add this class to the work list 360 // 361 while (i.hasNext()) { 362 ValueGraphVertex v = i.next(); 363 if (!checkCongruence(first, v)) { 364 workList.push(c); 365 break; 366 } 367 } 368 } 369 } 370 371 /** 372 * Partition a congruence class. 373 * @param partition the class to partition 374 */ 375 private void partitionClass(GVCongruenceClass partition) { 376 // store a reference to the first node in c, which will serve 377 // as a representative for this class 378 Iterator<ValueGraphVertex> i = partition.iterator(); 379 ValueGraphVertex first = i.next(); 380 ArrayList<GVCongruenceClass> newClasses = new ArrayList<GVCongruenceClass>(); 381 // now check each other node in c, to see if it matches the 382 // representative 383 ArrayList<ValueGraphVertex> toRemove = new ArrayList<ValueGraphVertex>(); 384 while (i.hasNext()) { 385 ValueGraphVertex v = i.next(); 386 if (!checkCongruence(first, v)) { 387 // NOT CONGRUENT!! split the partition. first check if 388 // v fits in any other newly created congruence classes 389 int index = findCongruenceMatch(newClasses, v); 390 if (index > -1) { 391 // MATCH FOUND!! place v in newClasses[index] 392 GVCongruenceClass match = B.get(index); 393 match.addVertex(v); 394 v.setValueNumber(match.getValueNumber()); 395 } else { 396 // NO MATCH FOUND!! create a new congruence class 397 // find the appropriate label for the new congruence class 398 // and create a new congruence class with this label 399 GVCongruenceClass c = createCongruenceClass(v); 400 newClasses.add(c); 401 c.addVertex(v); 402 v.setValueNumber(c.getValueNumber()); 403 } 404 // mark v as to be removed from partition 405 // (Can't remove it yet while iterating over the set); 406 toRemove.add(v); 407 } 408 } 409 // remove necessary vertices 410 for (ValueGraphVertex v : toRemove) { 411 partition.removeVertex(v); 412 } 413 // if needed place the original partition back on the work list 414 if ((!newClasses.isEmpty()) && (partition.size() > 1)) { 415 workList.push(partition); 416 } 417 // place any new congruence classes with size > 1 on the worklist 418 // also place any classes which might indirectly be affected 419 for (GVCongruenceClass c : newClasses) { 420 if (c.size() > 1) { 421 workList.push(c); 422 } 423 addDependentClassesToWorklist(c); 424 } 425 } 426 427 /** 428 * Assuming congruence class c has changed: find all other classes 429 * that might be affected, and add them to the worklist 430 * @param c the congruence class that has changed 431 */ 432 private void addDependentClassesToWorklist(GVCongruenceClass c) { 433 // for each element of this congruence class: 434 for (ValueGraphVertex v : c) { 435 // for each vertex which points to v in the value graph 436 for (Enumeration<GraphNode> e = v.inNodes(); e.hasMoreElements();) { 437 ValueGraphVertex in = (ValueGraphVertex) e.nextElement(); 438 int vn = in.getValueNumber(); 439 GVCongruenceClass x = B.get(vn); 440 workList.push(x); 441 } 442 } 443 } 444 445 /** 446 * Does vertex v belong to any congruence class in a vector? 447 * If so, returns the value number of the matching congruence class. 448 * If none found, returns -1. 449 * @param vector a vector of congruence classes 450 * @param v the vertex to search for 451 * @return the value number corresponding to the congruence class 452 * containing v. -1 iff no such class is found. 453 */ 454 private int findCongruenceMatch(ArrayList<GVCongruenceClass> vector, ValueGraphVertex v) { 455 for (GVCongruenceClass klass : vector) { 456 if (checkCongruence(v, klass)) { 457 return klass.getValueNumber(); 458 } 459 } 460 return -1; 461 } 462 463 /** 464 * Does the current state of the algorithm optimistically assume 465 * that a vertex v is congruent to the vertices in a congruence 466 * class? Note: this can return true even if 467 * if the value numbers don't currently match. 468 * @param v the vertex in question 469 * @param c the congurence class to check 470 * @return true or false 471 */ 472 private boolean checkCongruence(ValueGraphVertex v, GVCongruenceClass c) { 473 ValueGraphVertex r = c.getRepresentative(); 474 boolean result = checkCongruence(r, v); 475 return result; 476 } 477 478 /** 479 * Does the current state of the algorithm optimistically assume 480 * that two nodes are congruent? Note: this can return false 481 * even if the value numbers are currently the same. 482 * @param v1 first vertex 483 * @param v2 second vertex 484 * @return whether the notes are assumed to be congruent 485 */ 486 private boolean checkCongruence(ValueGraphVertex v1, ValueGraphVertex v2) { 487 if (v1 == v2) { 488 return true; 489 } 490 // make sure the two nodes have the same label 491 if (v1.getLabel() != v2.getLabel()) { 492 return false; 493 } 494 // make sure that the operands match 495 int arity = v1.getArity(); 496 for (int i = 0; i < arity; i++) { 497 ValueGraphVertex target1 = v1.getTarget(i); 498 ValueGraphVertex target2 = v2.getTarget(i); 499 // if either target is null, then that particular control 500 // flow path is never realized, so assume TOP 501 if ((target1 == null) || (target2 == null)) { 502 continue; 503 } 504 if (target1.getValueNumber() != target2.getValueNumber()) { 505 return false; 506 } 507 } 508 return true; 509 } 510 511 /** 512 * @param label a label 513 * @return whether a given label indicates that the object has a constant value 514 */ 515 private static boolean isConstant(Object label) { 516 return (label instanceof ConstantOperand); 517 } 518 519 /** 520 * @param label a label 521 * @return whether a given label indicates that the object is created at an 522 * allocation site 523 524 */ 525 private static boolean isBornAtAllocation(Object label) { 526 return (label instanceof Instruction); 527 } 528}