1 /* 2 * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.nodes.cfg; 26 27 import java.util.ArrayList; 28 import java.util.Arrays; 29 import java.util.BitSet; 30 import java.util.List; 31 32 import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph; 33 import org.graalvm.compiler.core.common.cfg.CFGVerifier; 34 import org.graalvm.compiler.core.common.cfg.Loop; 35 import org.graalvm.compiler.debug.DebugContext; 36 import org.graalvm.compiler.debug.GraalError; 37 import org.graalvm.compiler.graph.Node; 38 import org.graalvm.compiler.graph.NodeMap; 39 import org.graalvm.compiler.nodes.AbstractBeginNode; 40 import org.graalvm.compiler.nodes.AbstractEndNode; 41 import org.graalvm.compiler.nodes.ControlSinkNode; 42 import org.graalvm.compiler.nodes.ControlSplitNode; 43 import org.graalvm.compiler.nodes.EndNode; 44 import org.graalvm.compiler.nodes.FixedNode; 45 import org.graalvm.compiler.nodes.FixedWithNextNode; 46 import org.graalvm.compiler.nodes.IfNode; 47 import org.graalvm.compiler.nodes.LoopBeginNode; 48 import org.graalvm.compiler.nodes.LoopEndNode; 49 import org.graalvm.compiler.nodes.LoopExitNode; 50 import org.graalvm.compiler.nodes.MergeNode; 51 import org.graalvm.compiler.nodes.StructuredGraph; 52 import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage; 53 54 public final class ControlFlowGraph implements AbstractControlFlowGraph<Block> { 55 /** 56 * Don't allow relative frequency values to be become too small or too high as this makes 57 * frequency calculations over- or underflow the range of a double. This commonly happens with 58 * infinite loops within infinite loops. The value is chosen a bit lower than half the maximum 59 * exponent supported by double. That way we can never overflow to infinity when multiplying two 60 * relative frequency values. 61 */ 62 public static final double MIN_RELATIVE_FREQUENCY = 0x1.0p-500; 63 public static final double MAX_RELATIVE_FREQUENCY = 1 / MIN_RELATIVE_FREQUENCY; 64 65 public final StructuredGraph graph; 66 67 private NodeMap<Block> nodeToBlock; 68 private Block[] reversePostOrder; 69 private List<Loop<Block>> loops; 70 private int maxDominatorDepth; 71 72 public interface RecursiveVisitor<V> { 73 V enter(Block b); 74 75 void exit(Block b, V value); 76 } 77 78 public static ControlFlowGraph compute(StructuredGraph graph, boolean connectBlocks, boolean computeLoops, boolean computeDominators, boolean computePostdominators) { 79 ControlFlowGraph cfg = new ControlFlowGraph(graph); 80 cfg.identifyBlocks(); 81 cfg.computeFrequencies(); 82 83 if (computeLoops) { 84 cfg.computeLoopInformation(); 85 } 86 if (computeDominators) { 87 cfg.computeDominators(); 88 } 89 if (computePostdominators) { 90 cfg.computePostdominators(); 91 } 92 93 // there's not much to verify when connectBlocks == false 94 assert !(connectBlocks || computeLoops || computeDominators || computePostdominators) || CFGVerifier.verify(cfg); 95 return cfg; 96 } 97 98 public String dominatorTreeString() { 99 return dominatorTreeString(getStartBlock()); 100 } 101 102 private static String dominatorTreeString(Block b) { 103 StringBuilder sb = new StringBuilder(); 104 sb.append(b); 105 sb.append("("); 106 Block firstDominated = b.getFirstDominated(); 107 while (firstDominated != null) { 108 if (firstDominated.getDominator().getPostdominator() == firstDominated) { 109 sb.append("!"); 110 } 111 sb.append(dominatorTreeString(firstDominated)); 112 firstDominated = firstDominated.getDominatedSibling(); 113 } 114 sb.append(") "); 115 return sb.toString(); 116 } 117 118 @SuppressWarnings("unchecked") 119 public <V> void visitDominatorTreeDefault(RecursiveVisitor<V> visitor) { 120 121 Block[] stack = new Block[maxDominatorDepth + 1]; 122 Block current = getStartBlock(); 123 int tos = 0; 124 Object[] values = null; 125 int valuesTOS = 0; 126 127 while (tos >= 0) { 128 Block state = stack[tos]; 129 if (state == null || state.getDominator() == null || state.getDominator().getPostdominator() != state) { 130 if (state == null) { 131 // We enter this block for the first time. 132 V value = visitor.enter(current); 133 if (value != null || values != null) { 134 if (values == null) { 135 values = new Object[maxDominatorDepth + 1]; 136 } 137 values[valuesTOS++] = value; 138 } 139 140 Block dominated = skipPostDom(current.getFirstDominated()); 141 if (dominated != null) { 142 // Descend into dominated. 143 stack[tos] = dominated; 144 current = dominated; 145 stack[++tos] = null; 146 continue; 147 } 148 } else { 149 Block next = skipPostDom(state.getDominatedSibling()); 150 if (next != null) { 151 // Descend into dominated. 152 stack[tos] = next; 153 current = next; 154 stack[++tos] = null; 155 continue; 156 } 157 } 158 159 // Finished processing all normal dominators. 160 Block postDom = current.getPostdominator(); 161 if (postDom != null && postDom.getDominator() == current) { 162 // Descend into post dominator. 163 stack[tos] = postDom; 164 current = postDom; 165 stack[++tos] = null; 166 continue; 167 } 168 } 169 170 // Finished processing this node, exit and pop from stack. 171 V value = null; 172 if (values != null && valuesTOS > 0) { 173 value = (V) values[--valuesTOS]; 174 } 175 visitor.exit(current, value); 176 current = current.getDominator(); 177 --tos; 178 } 179 } 180 181 private static Block skipPostDom(Block block) { 182 if (block != null && block.getDominator().getPostdominator() == block) { 183 // This is an always reached block. 184 return block.getDominatedSibling(); 185 } 186 return block; 187 } 188 189 public static final class DeferredExit { 190 191 public DeferredExit(Block block, DeferredExit next) { 192 this.block = block; 193 this.next = next; 194 } 195 196 private final Block block; 197 private final DeferredExit next; 198 199 public Block getBlock() { 200 return block; 201 } 202 203 public DeferredExit getNext() { 204 return next; 205 } 206 207 } 208 209 public static void addDeferredExit(DeferredExit[] deferredExits, Block b) { 210 Loop<Block> outermostExited = b.getDominator().getLoop(); 211 Loop<Block> exitBlockLoop = b.getLoop(); 212 assert outermostExited != null; 213 while (outermostExited.getParent() != null && outermostExited.getParent() != exitBlockLoop) { 214 outermostExited = outermostExited.getParent(); 215 } 216 int loopIndex = outermostExited.getIndex(); 217 deferredExits[loopIndex] = new DeferredExit(b, deferredExits[loopIndex]); 218 } 219 220 @SuppressWarnings({"unchecked"}) 221 public <V> void visitDominatorTreeDeferLoopExits(RecursiveVisitor<V> visitor) { 222 Block[] stack = new Block[getBlocks().length]; 223 int tos = 0; 224 BitSet visited = new BitSet(getBlocks().length); 225 int loopCount = getLoops().size(); 226 DeferredExit[] deferredExits = new DeferredExit[loopCount]; 227 Object[] values = null; 228 int valuesTOS = 0; 229 stack[0] = getStartBlock(); 230 231 while (tos >= 0) { 232 Block cur = stack[tos]; 233 int curId = cur.getId(); 234 if (visited.get(curId)) { 235 V value = null; 236 if (values != null && valuesTOS > 0) { 237 value = (V) values[--valuesTOS]; 238 } 239 visitor.exit(cur, value); 240 --tos; 241 if (cur.isLoopHeader()) { 242 int loopIndex = cur.getLoop().getIndex(); 243 DeferredExit deferredExit = deferredExits[loopIndex]; 244 if (deferredExit != null) { 245 while (deferredExit != null) { 246 stack[++tos] = deferredExit.block; 247 deferredExit = deferredExit.next; 248 } 249 deferredExits[loopIndex] = null; 250 } 251 } 252 } else { 253 visited.set(curId); 254 V value = visitor.enter(cur); 255 if (value != null || values != null) { 256 if (values == null) { 257 values = new Object[maxDominatorDepth + 1]; 258 } 259 values[valuesTOS++] = value; 260 } 261 262 Block alwaysReached = cur.getPostdominator(); 263 if (alwaysReached != null) { 264 if (alwaysReached.getDominator() != cur) { 265 alwaysReached = null; 266 } else if (isDominatorTreeLoopExit(alwaysReached)) { 267 addDeferredExit(deferredExits, alwaysReached); 268 } else { 269 stack[++tos] = alwaysReached; 270 } 271 } 272 273 Block b = cur.getFirstDominated(); 274 while (b != null) { 275 if (b != alwaysReached) { 276 if (isDominatorTreeLoopExit(b)) { 277 addDeferredExit(deferredExits, b); 278 } else { 279 stack[++tos] = b; 280 } 281 } 282 b = b.getDominatedSibling(); 283 } 284 } 285 } 286 } 287 288 public <V> void visitDominatorTree(RecursiveVisitor<V> visitor, boolean deferLoopExits) { 289 if (deferLoopExits && this.getLoops().size() > 0) { 290 visitDominatorTreeDeferLoopExits(visitor); 291 } else { 292 visitDominatorTreeDefault(visitor); 293 } 294 } 295 296 public static boolean isDominatorTreeLoopExit(Block b) { 297 Block dominator = b.getDominator(); 298 return dominator != null && b.getLoop() != dominator.getLoop() && (!b.isLoopHeader() || dominator.getLoopDepth() >= b.getLoopDepth()); 299 } 300 301 private ControlFlowGraph(StructuredGraph graph) { 302 this.graph = graph; 303 this.nodeToBlock = graph.createNodeMap(); 304 } 305 306 private void computeDominators() { 307 assert reversePostOrder[0].getPredecessorCount() == 0 : "start block has no predecessor and therefore no dominator"; 308 Block[] blocks = reversePostOrder; 309 int curMaxDominatorDepth = 0; 310 for (int i = 1; i < blocks.length; i++) { 311 Block block = blocks[i]; 312 assert block.getPredecessorCount() > 0; 313 Block dominator = null; 314 for (Block pred : block.getPredecessors()) { 315 if (!pred.isLoopEnd()) { 316 dominator = ((dominator == null) ? pred : commonDominatorRaw(dominator, pred)); 317 } 318 } 319 320 // Set dominator. 321 block.setDominator(dominator); 322 323 // Keep dominated linked list sorted by block ID such that predecessor blocks are always 324 // before successor blocks. 325 Block currentDominated = dominator.getFirstDominated(); 326 if (currentDominated != null && currentDominated.getId() < block.getId()) { 327 while (currentDominated.getDominatedSibling() != null && currentDominated.getDominatedSibling().getId() < block.getId()) { 328 currentDominated = currentDominated.getDominatedSibling(); 329 } 330 block.setDominatedSibling(currentDominated.getDominatedSibling()); 331 currentDominated.setDominatedSibling(block); 332 } else { 333 block.setDominatedSibling(dominator.getFirstDominated()); 334 dominator.setFirstDominated(block); 335 } 336 337 curMaxDominatorDepth = Math.max(curMaxDominatorDepth, block.getDominatorDepth()); 338 } 339 this.maxDominatorDepth = curMaxDominatorDepth; 340 calcDominatorRanges(getStartBlock(), reversePostOrder.length); 341 } 342 343 private static void calcDominatorRanges(Block block, int size) { 344 Block[] stack = new Block[size]; 345 stack[0] = block; 346 int tos = 0; 347 int myNumber = 0; 348 349 do { 350 Block cur = stack[tos]; 351 Block dominated = cur.getFirstDominated(); 352 353 if (cur.getDominatorNumber() == -1) { 354 cur.setDominatorNumber(myNumber); 355 if (dominated != null) { 356 // Push children onto stack. 357 do { 358 stack[++tos] = dominated; 359 dominated = dominated.getDominatedSibling(); 360 } while (dominated != null); 361 } else { 362 cur.setMaxChildDomNumber(myNumber); 363 --tos; 364 } 365 ++myNumber; 366 } else { 367 cur.setMaxChildDomNumber(dominated.getMaxChildDominatorNumber()); 368 --tos; 369 } 370 } while (tos >= 0); 371 } 372 373 private static Block commonDominatorRaw(Block a, Block b) { 374 int aDomDepth = a.getDominatorDepth(); 375 int bDomDepth = b.getDominatorDepth(); 376 if (aDomDepth > bDomDepth) { 377 return commonDominatorRawSameDepth(a.getDominator(aDomDepth - bDomDepth), b); 378 } else { 379 return commonDominatorRawSameDepth(a, b.getDominator(bDomDepth - aDomDepth)); 380 } 381 } 382 383 private static Block commonDominatorRawSameDepth(Block a, Block b) { 384 Block iterA = a; 385 Block iterB = b; 386 while (iterA != iterB) { 387 iterA = iterA.getDominator(); 388 iterB = iterB.getDominator(); 389 } 390 return iterA; 391 } 392 393 @Override 394 public Block[] getBlocks() { 395 return reversePostOrder; 396 } 397 398 @Override 399 public Block getStartBlock() { 400 return reversePostOrder[0]; 401 } 402 403 public Block[] reversePostOrder() { 404 return reversePostOrder; 405 } 406 407 public NodeMap<Block> getNodeToBlock() { 408 return nodeToBlock; 409 } 410 411 public Block blockFor(Node node) { 412 return nodeToBlock.get(node); 413 } 414 415 @Override 416 public List<Loop<Block>> getLoops() { 417 return loops; 418 } 419 420 public int getMaxDominatorDepth() { 421 return maxDominatorDepth; 422 } 423 424 private void identifyBlock(Block block) { 425 FixedWithNextNode cur = block.getBeginNode(); 426 while (true) { 427 assert cur.isAlive() : cur; 428 assert nodeToBlock.get(cur) == null; 429 nodeToBlock.set(cur, block); 430 FixedNode next = cur.next(); 431 if (next instanceof AbstractBeginNode) { 432 block.endNode = cur; 433 return; 434 } else if (next instanceof FixedWithNextNode) { 435 cur = (FixedWithNextNode) next; 436 } else { 437 nodeToBlock.set(next, block); 438 block.endNode = next; 439 return; 440 } 441 } 442 } 443 444 /** 445 * Identify and connect blocks (including loop backward edges). Predecessors need to be in the 446 * order expected when iterating phi inputs. 447 */ 448 private void identifyBlocks() { 449 // Find all block headers. 450 int numBlocks = 0; 451 for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.TYPE)) { 452 Block block = new Block(begin); 453 identifyBlock(block); 454 numBlocks++; 455 } 456 457 // Compute reverse post order. 458 int count = 0; 459 NodeMap<Block> nodeMap = this.nodeToBlock; 460 Block[] stack = new Block[numBlocks]; 461 int tos = 0; 462 Block startBlock = blockFor(graph.start()); 463 stack[0] = startBlock; 464 startBlock.setPredecessors(Block.EMPTY_ARRAY); 465 do { 466 Block block = stack[tos]; 467 int id = block.getId(); 468 if (id == BLOCK_ID_INITIAL) { 469 // First time we see this block: push all successors. 470 FixedNode last = block.getEndNode(); 471 if (last instanceof EndNode) { 472 EndNode endNode = (EndNode) last; 473 Block suxBlock = nodeMap.get(endNode.merge()); 474 if (suxBlock.getId() == BLOCK_ID_INITIAL) { 475 stack[++tos] = suxBlock; 476 } 477 block.setSuccessors(new Block[]{suxBlock}); 478 } else if (last instanceof IfNode) { 479 IfNode ifNode = (IfNode) last; 480 Block trueSucc = nodeMap.get(ifNode.trueSuccessor()); 481 stack[++tos] = trueSucc; 482 Block falseSucc = nodeMap.get(ifNode.falseSuccessor()); 483 stack[++tos] = falseSucc; 484 block.setSuccessors(new Block[]{trueSucc, falseSucc}); 485 Block[] ifPred = new Block[]{block}; 486 trueSucc.setPredecessors(ifPred); 487 falseSucc.setPredecessors(ifPred); 488 } else if (last instanceof LoopEndNode) { 489 LoopEndNode loopEndNode = (LoopEndNode) last; 490 block.setSuccessors(new Block[]{nodeMap.get(loopEndNode.loopBegin())}); 491 // Nothing to do push onto the stack. 492 } else if (last instanceof ControlSinkNode) { 493 block.setSuccessors(Block.EMPTY_ARRAY); 494 } else { 495 assert !(last instanceof AbstractEndNode) : "Algorithm only supports EndNode and LoopEndNode."; 496 int startTos = tos; 497 Block[] ifPred = new Block[]{block}; 498 for (Node suxNode : last.successors()) { 499 Block sux = nodeMap.get(suxNode); 500 stack[++tos] = sux; 501 sux.setPredecessors(ifPred); 502 } 503 int suxCount = tos - startTos; 504 Block[] successors = new Block[suxCount]; 505 System.arraycopy(stack, startTos + 1, successors, 0, suxCount); 506 block.setSuccessors(successors); 507 } 508 block.setId(BLOCK_ID_VISITED); 509 AbstractBeginNode beginNode = block.getBeginNode(); 510 if (beginNode instanceof LoopBeginNode) { 511 computeLoopPredecessors(nodeMap, block, (LoopBeginNode) beginNode); 512 } else if (beginNode instanceof MergeNode) { 513 MergeNode mergeNode = (MergeNode) beginNode; 514 int forwardEndCount = mergeNode.forwardEndCount(); 515 Block[] predecessors = new Block[forwardEndCount]; 516 for (int i = 0; i < forwardEndCount; ++i) { 517 predecessors[i] = nodeMap.get(mergeNode.forwardEndAt(i)); 518 } 519 block.setPredecessors(predecessors); 520 } 521 522 } else if (id == BLOCK_ID_VISITED) { 523 // Second time we see this block: All successors have been processed, so add block 524 // to result list. Can safely reuse the stack for this. 525 --tos; 526 count++; 527 int index = numBlocks - count; 528 stack[index] = block; 529 block.setId(index); 530 } else { 531 throw GraalError.shouldNotReachHere(); 532 } 533 } while (tos >= 0); 534 535 // Compute reverse postorder and number blocks. 536 assert count == numBlocks : "all blocks must be reachable"; 537 this.reversePostOrder = stack; 538 } 539 540 private static void computeLoopPredecessors(NodeMap<Block> nodeMap, Block block, LoopBeginNode loopBeginNode) { 541 int forwardEndCount = loopBeginNode.forwardEndCount(); 542 LoopEndNode[] loopEnds = loopBeginNode.orderedLoopEnds(); 543 Block[] predecessors = new Block[forwardEndCount + loopEnds.length]; 544 for (int i = 0; i < forwardEndCount; ++i) { 545 predecessors[i] = nodeMap.get(loopBeginNode.forwardEndAt(i)); 546 } 547 for (int i = 0; i < loopEnds.length; ++i) { 548 predecessors[i + forwardEndCount] = nodeMap.get(loopEnds[i]); 549 } 550 block.setPredecessors(predecessors); 551 } 552 553 /** 554 * Computes the frequencies of all blocks relative to the start block. It uses the probability 555 * information attached to control flow splits to calculate the frequency of a block based on 556 * the frequency of its predecessor and the probability of its incoming control flow branch. 557 */ 558 private void computeFrequencies() { 559 560 for (Block block : reversePostOrder) { 561 Block[] predecessors = block.getPredecessors(); 562 563 double relativeFrequency; 564 if (predecessors.length == 0) { 565 relativeFrequency = 1D; 566 } else if (predecessors.length == 1) { 567 Block pred = predecessors[0]; 568 relativeFrequency = pred.relativeFrequency; 569 if (pred.getSuccessorCount() > 1) { 570 assert pred.getEndNode() instanceof ControlSplitNode; 571 ControlSplitNode controlSplit = (ControlSplitNode) pred.getEndNode(); 572 relativeFrequency = multiplyRelativeFrequencies(relativeFrequency, controlSplit.probability(block.getBeginNode())); 573 } 574 } else { 575 relativeFrequency = predecessors[0].relativeFrequency; 576 for (int i = 1; i < predecessors.length; ++i) { 577 relativeFrequency += predecessors[i].relativeFrequency; 578 } 579 580 if (block.getBeginNode() instanceof LoopBeginNode) { 581 LoopBeginNode loopBegin = (LoopBeginNode) block.getBeginNode(); 582 relativeFrequency = multiplyRelativeFrequencies(relativeFrequency, loopBegin.loopFrequency()); 583 } 584 } 585 if (relativeFrequency < MIN_RELATIVE_FREQUENCY) { 586 relativeFrequency = MIN_RELATIVE_FREQUENCY; 587 } else if (relativeFrequency > MAX_RELATIVE_FREQUENCY) { 588 relativeFrequency = MAX_RELATIVE_FREQUENCY; 589 } 590 block.setRelativeFrequency(relativeFrequency); 591 } 592 593 } 594 595 private void computeLoopInformation() { 596 loops = new ArrayList<>(); 597 if (graph.hasLoops()) { 598 Block[] stack = new Block[this.reversePostOrder.length]; 599 for (Block block : reversePostOrder) { 600 AbstractBeginNode beginNode = block.getBeginNode(); 601 if (beginNode instanceof LoopBeginNode) { 602 Loop<Block> parent = block.getLoop(); 603 Loop<Block> loop = new HIRLoop(parent, loops.size(), block); 604 if (parent != null) { 605 parent.getChildren().add(loop); 606 } 607 loops.add(loop); 608 block.setLoop(loop); 609 loop.getBlocks().add(block); 610 611 LoopBeginNode loopBegin = (LoopBeginNode) beginNode; 612 for (LoopEndNode end : loopBegin.loopEnds()) { 613 Block endBlock = nodeToBlock.get(end); 614 computeLoopBlocks(endBlock, loop, stack, true); 615 } 616 617 if (graph.getGuardsStage() != GuardsStage.AFTER_FSA) { 618 for (LoopExitNode exit : loopBegin.loopExits()) { 619 Block exitBlock = nodeToBlock.get(exit); 620 assert exitBlock.getPredecessorCount() == 1; 621 computeLoopBlocks(exitBlock.getFirstPredecessor(), loop, stack, true); 622 loop.addExit(exitBlock); 623 } 624 625 // The following loop can add new blocks to the end of the loop's block 626 // list. 627 int size = loop.getBlocks().size(); 628 for (int i = 0; i < size; ++i) { 629 Block b = loop.getBlocks().get(i); 630 for (Block sux : b.getSuccessors()) { 631 if (sux.getLoop() != loop) { 632 AbstractBeginNode begin = sux.getBeginNode(); 633 if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) { 634 graph.getDebug().log(DebugContext.VERBOSE_LEVEL, "Unexpected loop exit with %s, including whole branch in the loop", sux); 635 computeLoopBlocks(sux, loop, stack, false); 636 } 637 } 638 } 639 } 640 } 641 } 642 } 643 } 644 645 /* 646 * Compute the loop exit blocks after FSA. 647 */ 648 if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) { 649 for (Block b : reversePostOrder) { 650 if (b.getLoop() != null) { 651 for (Block succ : b.getSuccessors()) { 652 // if the loop of the succ is a different one (or none) 653 if (b.getLoop() != succ.getLoop()) { 654 // and the succ loop is not a child loop of the curr one 655 if (succ.getLoop() == null) { 656 // we might exit multiple loops if b.loops is not a loop at depth 0 657 Loop<Block> curr = b.getLoop(); 658 while (curr != null) { 659 curr.addExit(succ); 660 curr = curr.getParent(); 661 } 662 } else { 663 /* 664 * succ also has a loop, might be a child loop 665 * 666 * if it is a child loop we do not exit a loop. if it is a loop 667 * different than b.loop and not a child loop it must be a parent 668 * loop, thus we exit all loops between b.loop and succ.loop 669 * 670 * if we exit multiple loops immediately after each other the 671 * bytecode parser might generate loop exit nodes after another and 672 * the CFG will identify them as separate blocks, we just take the 673 * first one and exit all loops at this one 674 */ 675 if (succ.getLoop().getParent() != b.getLoop()) { 676 assert succ.getLoop().getDepth() < b.getLoop().getDepth(); 677 // b.loop must not be a transitive parent of succ.loop 678 assert !Loop.transitiveParentLoop(succ.getLoop(), b.getLoop()); 679 Loop<Block> curr = b.getLoop(); 680 while (curr != null && curr != succ.getLoop()) { 681 curr.addExit(succ); 682 curr = curr.getParent(); 683 } 684 } 685 } 686 } 687 } 688 } 689 } 690 } 691 692 } 693 694 private static void computeLoopBlocks(Block start, Loop<Block> loop, Block[] stack, boolean usePred) { 695 if (start.getLoop() != loop) { 696 start.setLoop(loop); 697 stack[0] = start; 698 loop.getBlocks().add(start); 699 int tos = 0; 700 do { 701 Block block = stack[tos--]; 702 703 // Add predecessors or successors to the loop. 704 for (Block b : (usePred ? block.getPredecessors() : block.getSuccessors())) { 705 if (b.getLoop() != loop) { 706 stack[++tos] = b; 707 b.setLoop(loop); 708 loop.getBlocks().add(b); 709 } 710 } 711 } while (tos >= 0); 712 } 713 } 714 715 public void computePostdominators() { 716 717 Block[] reversePostOrderTmp = this.reversePostOrder; 718 outer: for (int j = reversePostOrderTmp.length - 1; j >= 0; --j) { 719 Block block = reversePostOrderTmp[j]; 720 if (block.isLoopEnd()) { 721 // We do not want the loop header registered as the postdominator of the loop end. 722 continue; 723 } 724 if (block.getSuccessorCount() == 0) { 725 // No successors => no postdominator. 726 continue; 727 } 728 Block firstSucc = block.getSuccessors()[0]; 729 if (block.getSuccessorCount() == 1) { 730 block.postdominator = firstSucc; 731 continue; 732 } 733 Block postdominator = firstSucc; 734 for (Block sux : block.getSuccessors()) { 735 postdominator = commonPostdominator(postdominator, sux); 736 if (postdominator == null) { 737 // There is a dead end => no postdominator available. 738 continue outer; 739 } 740 } 741 assert !Arrays.asList(block.getSuccessors()).contains(postdominator) : "Block " + block + " has a wrong post dominator: " + postdominator; 742 block.setPostDominator(postdominator); 743 } 744 } 745 746 private static Block commonPostdominator(Block a, Block b) { 747 Block iterA = a; 748 Block iterB = b; 749 while (iterA != iterB) { 750 if (iterA.getId() < iterB.getId()) { 751 iterA = iterA.getPostdominator(); 752 if (iterA == null) { 753 return null; 754 } 755 } else { 756 assert iterB.getId() < iterA.getId(); 757 iterB = iterB.getPostdominator(); 758 if (iterB == null) { 759 return null; 760 } 761 } 762 } 763 return iterA; 764 } 765 766 public void setNodeToBlock(NodeMap<Block> nodeMap) { 767 this.nodeToBlock = nodeMap; 768 } 769 770 /** 771 * Multiplies a and b and clamps the between {@link ControlFlowGraph#MIN_RELATIVE_FREQUENCY} and 772 * {@link ControlFlowGraph#MAX_RELATIVE_FREQUENCY}. 773 */ 774 public static double multiplyRelativeFrequencies(double a, double b) { 775 assert !Double.isNaN(a) && !Double.isNaN(b) && Double.isFinite(a) && Double.isFinite(b) : a + " " + b; 776 double r = a * b; 777 if (r > MAX_RELATIVE_FREQUENCY) { 778 return MAX_RELATIVE_FREQUENCY; 779 } 780 if (r < MIN_RELATIVE_FREQUENCY) { 781 return MIN_RELATIVE_FREQUENCY; 782 } 783 return r; 784 } 785 }