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.controlflow; 014 015 import java.util.Enumeration; 016 017 import org.jikesrvm.VM; 018 import org.jikesrvm.compilers.opt.OperationNotImplementedException; 019 import org.jikesrvm.compilers.opt.ir.BasicBlock; 020 import org.jikesrvm.compilers.opt.ir.ControlFlowGraph; 021 import org.jikesrvm.compilers.opt.ir.IR; 022 import org.jikesrvm.compilers.opt.util.Stack; 023 024 /** 025 * Calculate dominators using Langauer and Tarjan's fastest algorithm. 026 * TOPLAS 1(1), July 1979. This implementation uses path compression and 027 * results in a O(e * alpha(e,n)) complexity, where e is the number of 028 * edges in the CFG and n is the number of nodes. 029 * <p> 030 * Sources: TOPLAS article, Muchnick book 031 * <p> 032 * The current implementation (4/25/00) does not include the EXIT node 033 * in any solution despite the fact that it is part of the CFG (it has 034 * incoming edges). This is to be compatible with the old code. 035 */ 036 public class LTDominators extends Stack<BasicBlock> { 037 static final boolean DEBUG = false; 038 039 /** 040 * Indicates whether we perform the algorithm over the CFG or 041 * the reverse CFG, i.e., whether we are computing dominators or 042 * post-dominators. 043 */ 044 private final boolean forward; 045 046 /** 047 * a counter for assigning DFS numbers 048 */ 049 protected int DFSCounter; 050 051 /** 052 * a mapping from DFS number to their basic blocks 053 */ 054 private BasicBlock[] vertex; 055 056 /** 057 * a convenient place to locate the cfg to avoid passing it internally 058 */ 059 private final ControlFlowGraph cfg; 060 061 /** 062 * The constructor, called by the perform method 063 * @param ir 064 * @param forward Should we compute regular dominators, or post-dominators? 065 */ 066 LTDominators(IR ir, boolean forward) { 067 cfg = ir.cfg; // save the cfg for easy access 068 this.forward = forward; // save the forward flag 069 } 070 071 /** 072 * The entry point for this phase 073 * @param ir the IR 074 * @param forward Should we compute regular dominators, or post-dominators? 075 * @param unfactor Should we unfactor the CFG? 076 */ 077 public static void perform(IR ir, boolean forward, boolean unfactor) { 078 if (ir.hasReachableExceptionHandlers()) { 079 if (unfactor) { 080 ir.unfactor(); 081 } else { 082 throw new OperationNotImplementedException("IR with exception handlers"); 083 } 084 } 085 LTDominators dom = new LTDominators(ir, forward); 086 dom.analyze(ir); 087 } 088 089 /** 090 * Compute approximate dominator/post dominator without unfactoring 091 * exception handlers. Can only be used if what the client wants is 092 * approximate domination (ie, if it doesn't actually have to be correct...) 093 * @param ir the IR 094 * @param forward Should we compute regular dominators, or post-dominators? 095 */ 096 public static void approximate(IR ir, boolean forward) { 097 LTDominators dom = new LTDominators(ir, forward); 098 dom.analyze(ir); 099 } 100 101 /** 102 * analyze dominators 103 */ 104 protected void analyze(IR ir) { 105 if (DEBUG) { 106 System.out.println(" Here's the CFG for method: " + ir.method.getName() + "\n" + ir.cfg); 107 } 108 109 // Step 1: Perform a DFS numbering 110 step1(); 111 112 // Check to make sure all nodes were reached 113 checkReachability(ir); 114 115 // Step 2: the heart of the algorithm 116 step2(); 117 118 // Step 3: adjust immediate dominators of nodes whoe current version of 119 // the immediate dominators differs from the nodes with the depth-first 120 // number of the node's semidominator. 121 step3(); 122 123 if (DEBUG) { 124 printResults(ir); 125 } 126 } 127 128 /** 129 * Check to make sure all nodes were reached 130 */ 131 private void checkReachability(IR ir) { 132 if (!forward) { 133 if (DFSCounter != cfg.numberOfNodes()) { 134 VM.sysWrite(" *** Warning ***\n CFG for method " + 135 ir.method.getName() + 136 " in class " + 137 ir.method.getDeclaringClass() + 138 " has unreachable nodes.\n"); 139 VM.sysWrite(" Assuming pessimistic results in dominators computation\n" + " for unreachable nodes.\n"); 140 } 141 } 142 } 143 144 /** 145 * The goal of this step is to perform a DFS numbering on the CFG, 146 * starting at the root. The exit node is not included. 147 */ 148 private void step1() { 149 // allocate the vertex array, one element for each basic block, starting 150 // at 1 151 vertex = new BasicBlock[cfg.numberOfNodes() + 1]; 152 DFSCounter = 0; 153 if (DEBUG) { System.out.println("Initializing blocks:"); } 154 155 // Initialize each block with an empty set of predecessors and 156 // a 0 for a semidominator 157 for (Enumeration<BasicBlock> bbEnum = cfg.basicBlocks(); bbEnum.hasMoreElements();) { 158 BasicBlock block = bbEnum.nextElement(); 159 // We don't compute a result for the exit node in the forward direction 160 if (!forward || !block.isExit()) { 161 block.scratchObject = new LTDominatorInfo(block); 162 if (DEBUG) { 163 printNextNodes(block); 164 } 165 } 166 } 167 168 DFS(); 169 170 if (DEBUG) { 171 System.out.println("DFSCounter: " + DFSCounter + ", CFG Nodes: " + cfg.numberOfNodes()); 172 printDFSNumbers(); 173 } 174 } 175 176 private void DFS() { DFS(getFirstNode()); } 177 178 /** 179 * Get the first node, either entry or exit 180 * depending on which way we are viewing the graph 181 * @return the entry node or exit node 182 */ 183 private BasicBlock getFirstNode() { 184 if (forward) { 185 return cfg.entry(); 186 } else { 187 return cfg.exit(); 188 } 189 } 190 191 /** 192 * Print the "next" nodes (either out or in) for the passed block 193 * depending on which way we are viewing the graph 194 * @param block the basic block of interest 195 */ 196 private void printNextNodes(BasicBlock block) { 197 if (forward) { 198 System.out.print(block + " Succs:"); 199 } else { 200 System.out.print(block + " Preds:"); 201 } 202 Enumeration<BasicBlock> e = getNextNodes(block); 203 while (e.hasMoreElements()) { 204 System.out.print(" "); 205 System.out.print(e.nextElement()); 206 } 207 System.out.println(); 208 } 209 210 /** 211 * Returns an enumeration of the "next" nodes (either out or in) for the 212 * passed block depending on which way we are viewing the graph 213 * @param block the basic block of interest 214 */ 215 private Enumeration<BasicBlock> getNextNodes(BasicBlock block) { 216 Enumeration<BasicBlock> bbEnum; 217 if (forward) { 218 bbEnum = block.getOut(); 219 } else { 220 bbEnum = block.getIn(); 221 } 222 return bbEnum; 223 } 224 225 /** 226 * Returns an enumeration of the "prev" nodes (either in or out) for the 227 * passed block depending on which way we are viewing the graph 228 * @param block the basic block of interest 229 */ 230 private Enumeration<BasicBlock> getPrevNodes(BasicBlock block) { 231 Enumeration<BasicBlock> bbEnum; 232 if (forward) { 233 bbEnum = block.getIn(); 234 } else { 235 bbEnum = block.getOut(); 236 } 237 return bbEnum; 238 } 239 240 /** 241 * The non-recursive depth-first numbering code called from Step 1. 242 * The recursive version was too costly on the toba benchmark on Linux/IA32. 243 * @param block the basic block to process 244 */ 245 protected void DFS(BasicBlock block) { 246 247 // push node on to the emulated activation stack 248 push(block); 249 250 recurse: 251 while (!empty()) { 252 253 block = peek(); 254 if (DEBUG) { System.out.println(" Processing (peek)" + block); } 255 256 if (block == null) { 257 if (DEBUG) { System.out.println(" Popping"); } 258 pop(); // return 259 continue; 260 } 261 262 // The current Dominance Frontier and SSA code assumes the exit 263 // node will not be part of the (regular) dominator solution. 264 // To avoid this from happening we screen it out here for forward CFG 265 // 266 // However, it really shouldn't be in the CFG, if it isn't a node! 267 if (forward && block == cfg.exit()) { 268 if (DEBUG) { System.out.println(" Popping"); } 269 pop(); // return 270 continue; 271 } 272 273 Enumeration<BasicBlock> e; 274 e = LTDominatorInfo.getInfo(block).getEnum(); 275 276 if (e == null) { 277 if (DEBUG) { System.out.println(" Initial processing of " + block); } 278 279 DFSCounter++; 280 LTDominatorInfo.getInfo(block).setSemiDominator(DFSCounter); 281 vertex[DFSCounter] = block; 282 e = getNextNodes(block); 283 } else { 284 if (DEBUG) { System.out.println(" Resuming processing of " + block); } 285 } 286 287 while (e.hasMoreElements()) { 288 BasicBlock next = e.nextElement(); 289 290 if (DEBUG) { System.out.println(" Inspecting next node: " + next); } 291 292 // We treat the exit node as not being in the CFG for forward direction 293 if (forward && next.isExit()) { 294 continue; // inner loop 295 } 296 if (getSemi(next) == 0) { 297 LTDominatorInfo.getInfo(next).setParent(block); 298 299 // simulate a recursive call 300 // save the enumeration state for resumption later 301 LTDominatorInfo.getInfo(block).setEnum(e); 302 303 if (DEBUG) { System.out.println(" Pushing" + next); } 304 push(next); 305 continue recurse; 306 } 307 } // while more nexts 308 // "Pop" from the emulated activiation stack 309 if (DEBUG) { System.out.println(" Popping"); } 310 pop(); 311 } // while stack not empty loop 312 } 313 314 /** 315 * This is the heart of the algorithm. See sources for details. 316 */ 317 private void step2() { 318 if (DEBUG) { System.out.println(" ******* Beginning STEP 2 *******\n"); } 319 320 // Visit each node in reverse DFS order, except for the root, which 321 // has number 1 322 // for i=n downto 2 323 for (int i = DFSCounter; i > 1; i--) { 324 // block = vertex[i] 325 BasicBlock block = vertex[i]; 326 LTDominatorInfo blockInfo = LTDominatorInfo.getInfo(block); 327 328 if (DEBUG) { System.out.println(" Processing: " + block + "\n"); } 329 330 // visit each predecessor 331 Enumeration<BasicBlock> e = getPrevNodes(block); 332 while (e.hasMoreElements()) { 333 BasicBlock prev = e.nextElement(); 334 if (DEBUG) { System.out.println(" Inspecting prev: " + prev); } 335 BasicBlock u = EVAL(prev); 336 // if semi(u) < semi(block) then semi(block) = semi(u) 337 // u may be part of infinite loop and thus, is unreachable from the exit node. 338 // In this case, it will have a semi value of 0. Thus, we screen for it here 339 if (getSemi(u) != 0 && getSemi(u) < getSemi(block)) { 340 blockInfo.setSemiDominator(getSemi(u)); 341 } 342 } // while prev 343 344 // add "block" to bucket(vertex(semi(block))); 345 LTDominatorInfo.getInfo(vertex[blockInfo.getSemiDominator()]). 346 addToBucket(block); 347 348 // LINK(parent(block), block) 349 LINK(blockInfo.getParent(), block); 350 351 // foreach block2 in bucket(parent(block)) do 352 java.util.Iterator<BasicBlock> bucketEnum = LTDominatorInfo.getInfo(getParent(block)).getBucketIterator(); 353 while (bucketEnum.hasNext()) { 354 BasicBlock block2 = bucketEnum.next(); 355 356 // u = EVAL(block2) 357 BasicBlock u = EVAL(block2); 358 359 // if semi(u) < semi(block2) then 360 // dom(block2) = u 361 // else 362 // dom(block2) = parent(block) 363 if (getSemi(u) < getSemi(block2)) { 364 LTDominatorInfo.getInfo(block2).setDominator(u); 365 } else { 366 LTDominatorInfo.getInfo(block2).setDominator(getParent(block)); 367 } 368 } // while bucket has more elements 369 } // for DFSCounter .. 1 370 } // method 371 372 /** 373 * This method inspects the passed block and returns the following: 374 * <ul> 375 * <li>block, if block is a root of a tree in the forest 376 * <li>any vertex, u != r such that r is the root of the tree 377 * containing block and semi(u) is minimum on the path r -> v, 378 * otherwise 379 * </ul> 380 * <p> 381 * 382 * See TOPLAS 1(1), July 1979, p 128 for details. 383 * 384 * @param block the block to evaluate 385 * @return the block as described above 386 */ 387 private BasicBlock EVAL(BasicBlock block) { 388 if (DEBUG) { 389 System.out.println(" Evaling " + block); 390 } 391 if (getAncestor(block) == null) { 392 return getLabel(block); 393 } else { 394 compress(block); 395 if (getSemi(getLabel(getAncestor(block))) >= getSemi(getLabel(block))) { 396 return getLabel(block); 397 } else { 398 return getLabel(getAncestor(block)); 399 } 400 } 401 } 402 403 /** 404 * This recursive method performs the path compression 405 * @param block the block of interest 406 */ 407 private void compress(BasicBlock block) { 408 if (getAncestor(getAncestor(block)) != null) { 409 compress(getAncestor(block)); 410 LTDominatorInfo blockInfo = LTDominatorInfo.getInfo(block); 411 if (getSemi(getLabel(getAncestor(block))) < getSemi(getLabel(block))) { 412 blockInfo.setLabel(getLabel(getAncestor(block))); 413 } 414 blockInfo.setAncestor(getAncestor(getAncestor(block))); 415 } 416 } 417 418 /** 419 * Adds edge (block1, block2) to the forest maintained as an auxiliary 420 * data structure. This implementation uses path compression and 421 * results in a O(e * alpha(e,n)) complexity, where e is the number of 422 * edges in the CFG and n is the number of nodes. 423 * 424 * @param block1 a basic block corresponding to the source of the new edge 425 * @param block2 a basic block corresponding to the source of the new edge 426 */ 427 private void LINK(BasicBlock block1, BasicBlock block2) { 428 if (DEBUG) { 429 System.out.println(" Linking " + block1 + " with " + block2); 430 } 431 BasicBlock s = block2; 432 while (getSemi(getLabel(block2)) < getSemi(getLabel(getChild(s)))) { 433 if (getSize(s) + getSize(getChild(getChild(s))) >= 2 * getSize(getChild(s))) { 434 LTDominatorInfo.getInfo(getChild(s)).setAncestor(s); 435 LTDominatorInfo.getInfo(s).setChild(getChild(getChild(s))); 436 } else { 437 LTDominatorInfo.getInfo(getChild(s)).setSize(getSize(s)); 438 LTDominatorInfo.getInfo(s).setAncestor(getChild(s)); 439 s = getChild(s); 440 } 441 } 442 LTDominatorInfo.getInfo(s).setLabel(getLabel(block2)); 443 LTDominatorInfo.getInfo(block1).setSize(getSize(block1) + getSize(block2)); 444 if (getSize(block1) < 2 * getSize(block2)) { 445 BasicBlock tmp = s; 446 s = getChild(block1); 447 LTDominatorInfo.getInfo(block1).setChild(tmp); 448 } 449 while (s != null) { 450 LTDominatorInfo.getInfo(s).setAncestor(block1); 451 s = getChild(s); 452 } 453 if (DEBUG) { 454 System.out.println(" .... done"); 455 } 456 } 457 458 /** 459 * This final step sets the final dominator information. 460 */ 461 private void step3() { 462 // Visit each node in DFS order, except for the root, which has number 1 463 for (int i = 2; i <= DFSCounter; i++) { 464 BasicBlock block = vertex[i]; 465 // if dom(block) != vertex[semi(block)] 466 if (getDom(block) != vertex[getSemi(block)]) { 467 // dom(block) = dom(dom(block)) 468 LTDominatorInfo.getInfo(block).setDominator(getDom(getDom(block))); 469 } 470 } 471 } 472 473 // 474 // The following methods are simple helper methods to increase the 475 // readability of the code. 476 // 477 478 /** 479 * Returns the current dominator for the passed block 480 * @param block 481 * @return the domiator for the passed block 482 */ 483 private BasicBlock getDom(BasicBlock block) { 484 return LTDominatorInfo.getInfo(block).getDominator(); 485 } 486 487 /** 488 * Returns the parent for the passed block 489 * @param block 490 * @return the parent for the passed block 491 */ 492 private BasicBlock getParent(BasicBlock block) { 493 return LTDominatorInfo.getInfo(block).getParent(); 494 } 495 496 /** 497 * Returns the ancestor for the passed block 498 * @param block 499 * @return the ancestor for the passed block 500 */ 501 private BasicBlock getAncestor(BasicBlock block) { 502 return LTDominatorInfo.getInfo(block).getAncestor(); 503 } 504 505 /** 506 * returns the label for the passed block or null if the block is null 507 * @param block 508 * @return the label for the passed block or null if the block is null 509 */ 510 private BasicBlock getLabel(BasicBlock block) { 511 if (block == null) { 512 return null; 513 } 514 return LTDominatorInfo.getInfo(block).getLabel(); 515 } 516 517 /** 518 * Returns the current semidominator for the passed block 519 * @param block 520 * @return the semidominator for the passed block 521 */ 522 private int getSemi(BasicBlock block) { 523 if (block == null) { 524 return 0; 525 } 526 return LTDominatorInfo.getInfo(block).getSemiDominator(); 527 } 528 529 /** 530 * returns the size associated with the block 531 * @param block 532 * @return the size of the block or 0 if the block is null 533 */ 534 private int getSize(BasicBlock block) { 535 if (block == null) { 536 return 0; 537 } 538 return LTDominatorInfo.getInfo(block).getSize(); 539 } 540 541 /** 542 * Get the child node for this block 543 * @param block 544 * @return the child node 545 */ 546 private BasicBlock getChild(BasicBlock block) { 547 return LTDominatorInfo.getInfo(block).getChild(); 548 } 549 550 /** 551 * Print the nodes that dominate each basic block 552 * @param ir the IR 553 */ 554 private void printResults(IR ir) { 555 if (forward) { 556 System.out.println("Results of dominators computation for method " + ir.method.getName() + "\n"); 557 System.out.println(" Here's the CFG:"); 558 System.out.println(ir.cfg); 559 System.out.println("\n\n Here's the Dominator Info:"); 560 } else { 561 System.out.println("Results of Post-Dominators computation for method " + ir.method.getName() + "\n"); 562 System.out.println(" Here's the CFG:"); 563 System.out.println(ir.cfg); 564 System.out.println("\n\n Here's the Post-Dominator Info:"); 565 } 566 567 for (Enumeration<BasicBlock> bbEnum = cfg.basicBlocks(); bbEnum.hasMoreElements();) { 568 BasicBlock block = bbEnum.nextElement(); 569 // We don't compute a result for the exit node for forward direction 570 if (!forward || !block.isExit()) { 571 System.out.println("Dominators of " + block + ":" + LTDominatorInfo.getInfo(block).dominators(block, ir)); 572 } 573 } 574 System.out.println("\n"); 575 } 576 577 /** 578 * Print the result of the DFS numbering performed in Step 1 579 */ 580 private void printDFSNumbers() { 581 for (Enumeration<BasicBlock> bbEnum = cfg.basicBlocks(); bbEnum.hasMoreElements();) { 582 BasicBlock block = bbEnum.nextElement(); 583 // We don't compute a result for the exit node for forward direction 584 if (forward && block.isExit()) { 585 continue; 586 } 587 LTDominatorInfo info = (LTDominatorInfo) block.scratchObject; 588 System.out.println(" " + block + " " + info); 589 } 590 // Visit each node in reverse DFS order, except for the root, which 591 // has number 1 592 for (int i = 1; i <= DFSCounter; i++) { 593 System.out.println(" Vertex: " + i + " " + vertex[i]); 594 } 595 } 596 }