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