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