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 : "Dominator must be in a loop. Possible cause is a missing loop exit node.";
 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             // Fortify: Suppress Null Dereference false positive (every block apart from the first
 321             // is guaranteed to have a predecessor)
 322             assert dominator != null;
 323 
 324             // Set dominator.
 325             block.setDominator(dominator);
 326 
 327             // Keep dominated linked list sorted by block ID such that predecessor blocks are always
 328             // before successor blocks.
 329             Block currentDominated = dominator.getFirstDominated();
 330             if (currentDominated != null && currentDominated.getId() < block.getId()) {
 331                 while (currentDominated.getDominatedSibling() != null && currentDominated.getDominatedSibling().getId() < block.getId()) {
 332                     currentDominated = currentDominated.getDominatedSibling();
 333                 }
 334                 block.setDominatedSibling(currentDominated.getDominatedSibling());
 335                 currentDominated.setDominatedSibling(block);
 336             } else {
 337                 block.setDominatedSibling(dominator.getFirstDominated());
 338                 dominator.setFirstDominated(block);
 339             }
 340 
 341             curMaxDominatorDepth = Math.max(curMaxDominatorDepth, block.getDominatorDepth());
 342         }
 343         this.maxDominatorDepth = curMaxDominatorDepth;
 344         calcDominatorRanges(getStartBlock(), reversePostOrder.length);
 345     }
 346 
 347     private static void calcDominatorRanges(Block block, int size) {
 348         Block[] stack = new Block[size];
 349         stack[0] = block;
 350         int tos = 0;
 351         int myNumber = 0;
 352 
 353         do {
 354             Block cur = stack[tos];
 355             Block dominated = cur.getFirstDominated();
 356 
 357             if (cur.getDominatorNumber() == -1) {
 358                 cur.setDominatorNumber(myNumber);
 359                 if (dominated != null) {
 360                     // Push children onto stack.
 361                     do {
 362                         stack[++tos] = dominated;
 363                         dominated = dominated.getDominatedSibling();
 364                     } while (dominated != null);
 365                 } else {
 366                     cur.setMaxChildDomNumber(myNumber);
 367                     --tos;
 368                 }
 369                 ++myNumber;
 370             } else {
 371                 cur.setMaxChildDomNumber(dominated.getMaxChildDominatorNumber());
 372                 --tos;
 373             }
 374         } while (tos >= 0);
 375     }
 376 
 377     private static Block commonDominatorRaw(Block a, Block b) {
 378         int aDomDepth = a.getDominatorDepth();
 379         int bDomDepth = b.getDominatorDepth();
 380         if (aDomDepth > bDomDepth) {
 381             return commonDominatorRawSameDepth(a.getDominator(aDomDepth - bDomDepth), b);
 382         } else {
 383             return commonDominatorRawSameDepth(a, b.getDominator(bDomDepth - aDomDepth));
 384         }
 385     }
 386 
 387     private static Block commonDominatorRawSameDepth(Block a, Block b) {
 388         Block iterA = a;
 389         Block iterB = b;
 390         while (iterA != iterB) {
 391             iterA = iterA.getDominator();
 392             iterB = iterB.getDominator();
 393         }
 394         return iterA;
 395     }
 396 
 397     @Override
 398     public Block[] getBlocks() {
 399         return reversePostOrder;
 400     }
 401 
 402     @Override
 403     public Block getStartBlock() {
 404         return reversePostOrder[0];
 405     }
 406 
 407     public Block[] reversePostOrder() {
 408         return reversePostOrder;
 409     }
 410 
 411     public NodeMap<Block> getNodeToBlock() {
 412         return nodeToBlock;
 413     }
 414 
 415     public Block blockFor(Node node) {
 416         return nodeToBlock.get(node);
 417     }
 418 
 419     @Override
 420     public List<Loop<Block>> getLoops() {
 421         return loops;
 422     }
 423 
 424     public int getMaxDominatorDepth() {
 425         return maxDominatorDepth;
 426     }
 427 
 428     private void identifyBlock(Block block) {
 429         FixedWithNextNode cur = block.getBeginNode();
 430         while (true) {
 431             assert cur.isAlive() : cur;
 432             assert nodeToBlock.get(cur) == null;
 433             nodeToBlock.set(cur, block);
 434             FixedNode next = cur.next();
 435             if (next instanceof AbstractBeginNode) {
 436                 block.endNode = cur;
 437                 return;
 438             } else if (next instanceof FixedWithNextNode) {
 439                 cur = (FixedWithNextNode) next;
 440             } else {
 441                 nodeToBlock.set(next, block);
 442                 block.endNode = next;
 443                 return;
 444             }
 445         }
 446     }
 447 
 448     /**
 449      * Identify and connect blocks (including loop backward edges). Predecessors need to be in the
 450      * order expected when iterating phi inputs.
 451      */
 452     private void identifyBlocks() {
 453         // Find all block headers.
 454         int numBlocks = 0;
 455         for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.TYPE)) {
 456             Block block = new Block(begin);
 457             identifyBlock(block);
 458             numBlocks++;
 459         }
 460 
 461         // Compute reverse post order.
 462         int count = 0;
 463         NodeMap<Block> nodeMap = this.nodeToBlock;
 464         Block[] stack = new Block[numBlocks];
 465         int tos = 0;
 466         Block startBlock = blockFor(graph.start());
 467         stack[0] = startBlock;
 468         startBlock.setPredecessors(Block.EMPTY_ARRAY);
 469         do {
 470             Block block = stack[tos];
 471             int id = block.getId();
 472             if (id == BLOCK_ID_INITIAL) {
 473                 // First time we see this block: push all successors.
 474                 FixedNode last = block.getEndNode();
 475                 if (last instanceof EndNode) {
 476                     EndNode endNode = (EndNode) last;
 477                     Block suxBlock = nodeMap.get(endNode.merge());
 478                     if (suxBlock.getId() == BLOCK_ID_INITIAL) {
 479                         stack[++tos] = suxBlock;
 480                     }
 481                     block.setSuccessors(new Block[]{suxBlock});
 482                 } else if (last instanceof IfNode) {
 483                     IfNode ifNode = (IfNode) last;
 484                     Block trueSucc = nodeMap.get(ifNode.trueSuccessor());
 485                     stack[++tos] = trueSucc;
 486                     Block falseSucc = nodeMap.get(ifNode.falseSuccessor());
 487                     stack[++tos] = falseSucc;
 488                     block.setSuccessors(new Block[]{trueSucc, falseSucc});
 489                     Block[] ifPred = new Block[]{block};
 490                     trueSucc.setPredecessors(ifPred);
 491                     falseSucc.setPredecessors(ifPred);
 492                 } else if (last instanceof LoopEndNode) {
 493                     LoopEndNode loopEndNode = (LoopEndNode) last;
 494                     block.setSuccessors(new Block[]{nodeMap.get(loopEndNode.loopBegin())});
 495                     // Nothing to do push onto the stack.
 496                 } else if (last instanceof ControlSinkNode) {
 497                     block.setSuccessors(Block.EMPTY_ARRAY);
 498                 } else {
 499                     assert !(last instanceof AbstractEndNode) : "Algorithm only supports EndNode and LoopEndNode.";
 500                     int startTos = tos;
 501                     Block[] ifPred = new Block[]{block};
 502                     for (Node suxNode : last.successors()) {
 503                         Block sux = nodeMap.get(suxNode);
 504                         stack[++tos] = sux;
 505                         sux.setPredecessors(ifPred);
 506                     }
 507                     int suxCount = tos - startTos;
 508                     Block[] successors = new Block[suxCount];
 509                     System.arraycopy(stack, startTos + 1, successors, 0, suxCount);
 510                     block.setSuccessors(successors);
 511                 }
 512                 block.setId(BLOCK_ID_VISITED);
 513                 AbstractBeginNode beginNode = block.getBeginNode();
 514                 if (beginNode instanceof LoopBeginNode) {
 515                     computeLoopPredecessors(nodeMap, block, (LoopBeginNode) beginNode);
 516                 } else if (beginNode instanceof MergeNode) {
 517                     MergeNode mergeNode = (MergeNode) beginNode;
 518                     int forwardEndCount = mergeNode.forwardEndCount();
 519                     Block[] predecessors = new Block[forwardEndCount];
 520                     for (int i = 0; i < forwardEndCount; ++i) {
 521                         predecessors[i] = nodeMap.get(mergeNode.forwardEndAt(i));
 522                     }
 523                     block.setPredecessors(predecessors);
 524                 }
 525 
 526             } else if (id == BLOCK_ID_VISITED) {
 527                 // Second time we see this block: All successors have been processed, so add block
 528                 // to result list. Can safely reuse the stack for this.
 529                 --tos;
 530                 count++;
 531                 int index = numBlocks - count;
 532                 stack[index] = block;
 533                 block.setId(index);
 534             } else {
 535                 throw GraalError.shouldNotReachHere();
 536             }
 537         } while (tos >= 0);
 538 
 539         // Compute reverse postorder and number blocks.
 540         assert count == numBlocks : "all blocks must be reachable";
 541         this.reversePostOrder = stack;
 542     }
 543 
 544     private static void computeLoopPredecessors(NodeMap<Block> nodeMap, Block block, LoopBeginNode loopBeginNode) {
 545         int forwardEndCount = loopBeginNode.forwardEndCount();
 546         LoopEndNode[] loopEnds = loopBeginNode.orderedLoopEnds();
 547         Block[] predecessors = new Block[forwardEndCount + loopEnds.length];
 548         for (int i = 0; i < forwardEndCount; ++i) {
 549             predecessors[i] = nodeMap.get(loopBeginNode.forwardEndAt(i));
 550         }
 551         for (int i = 0; i < loopEnds.length; ++i) {
 552             predecessors[i + forwardEndCount] = nodeMap.get(loopEnds[i]);
 553         }
 554         block.setPredecessors(predecessors);
 555     }
 556 
 557     /**
 558      * Computes the frequencies of all blocks relative to the start block. It uses the probability
 559      * information attached to control flow splits to calculate the frequency of a block based on
 560      * the frequency of its predecessor and the probability of its incoming control flow branch.
 561      */
 562     private void computeFrequencies() {
 563 
 564         for (Block block : reversePostOrder) {
 565             Block[] predecessors = block.getPredecessors();
 566 
 567             double relativeFrequency;
 568             if (predecessors.length == 0) {
 569                 relativeFrequency = 1D;
 570             } else if (predecessors.length == 1) {
 571                 Block pred = predecessors[0];
 572                 relativeFrequency = pred.relativeFrequency;
 573                 if (pred.getSuccessorCount() > 1) {
 574                     assert pred.getEndNode() instanceof ControlSplitNode;
 575                     ControlSplitNode controlSplit = (ControlSplitNode) pred.getEndNode();
 576                     relativeFrequency = multiplyRelativeFrequencies(relativeFrequency, controlSplit.probability(block.getBeginNode()));
 577                 }
 578             } else {
 579                 relativeFrequency = predecessors[0].relativeFrequency;
 580                 for (int i = 1; i < predecessors.length; ++i) {
 581                     relativeFrequency += predecessors[i].relativeFrequency;
 582                 }
 583 
 584                 if (block.getBeginNode() instanceof LoopBeginNode) {
 585                     LoopBeginNode loopBegin = (LoopBeginNode) block.getBeginNode();
 586                     relativeFrequency = multiplyRelativeFrequencies(relativeFrequency, loopBegin.loopFrequency());
 587                 }
 588             }
 589             if (relativeFrequency < MIN_RELATIVE_FREQUENCY) {
 590                 relativeFrequency = MIN_RELATIVE_FREQUENCY;
 591             } else if (relativeFrequency > MAX_RELATIVE_FREQUENCY) {
 592                 relativeFrequency = MAX_RELATIVE_FREQUENCY;
 593             }
 594             block.setRelativeFrequency(relativeFrequency);
 595         }
 596 
 597     }
 598 
 599     private void computeLoopInformation() {
 600         loops = new ArrayList<>();
 601         if (graph.hasLoops()) {
 602             Block[] stack = new Block[this.reversePostOrder.length];
 603             for (Block block : reversePostOrder) {
 604                 AbstractBeginNode beginNode = block.getBeginNode();
 605                 if (beginNode instanceof LoopBeginNode) {
 606                     Loop<Block> parent = block.getLoop();
 607                     Loop<Block> loop = new HIRLoop(parent, loops.size(), block);
 608                     if (parent != null) {
 609                         parent.getChildren().add(loop);
 610                     }
 611                     loops.add(loop);
 612                     block.setLoop(loop);
 613                     loop.getBlocks().add(block);
 614 
 615                     LoopBeginNode loopBegin = (LoopBeginNode) beginNode;
 616                     for (LoopEndNode end : loopBegin.loopEnds()) {
 617                         Block endBlock = nodeToBlock.get(end);
 618                         computeLoopBlocks(endBlock, loop, stack, true);
 619                     }
 620 
 621                     // Note that at this point, due to traversal order, child loops of `loop` have
 622                     // not been discovered yet.
 623                     for (Block b : loop.getBlocks()) {
 624                         for (Block sux : b.getSuccessors()) {
 625                             if (sux.getLoop() != loop) {
 626                                 assert sux.getLoopDepth() < loop.getDepth();
 627                                 loop.getNaturalExits().add(sux);
 628                             }
 629                         }
 630                     }
 631                     loop.getNaturalExits().sort(BLOCK_ID_COMPARATOR);
 632 
 633                     if (!graph.getGuardsStage().areFrameStatesAtDeopts()) {
 634                         for (LoopExitNode exit : loopBegin.loopExits()) {
 635                             Block exitBlock = nodeToBlock.get(exit);
 636                             assert exitBlock.getPredecessorCount() == 1;
 637                             computeLoopBlocks(exitBlock.getFirstPredecessor(), loop, stack, true);
 638                             loop.getLoopExits().add(exitBlock);
 639                         }
 640                         loop.getLoopExits().sort(BLOCK_ID_COMPARATOR);
 641 
 642                         // The following loop can add new blocks to the end of the loop's block
 643                         // list.
 644                         int size = loop.getBlocks().size();
 645                         for (int i = 0; i < size; ++i) {
 646                             Block b = loop.getBlocks().get(i);
 647                             for (Block sux : b.getSuccessors()) {
 648                                 if (sux.getLoop() != loop) {
 649                                     AbstractBeginNode begin = sux.getBeginNode();
 650                                     if (!loopBegin.isLoopExit(begin)) {
 651                                         assert !(begin instanceof LoopBeginNode);
 652                                         assert sux.getLoopDepth() < loop.getDepth();
 653                                         graph.getDebug().log(DebugContext.VERBOSE_LEVEL, "Unexpected loop exit with %s, including whole branch in the loop", sux);
 654                                         computeLoopBlocks(sux, loop, stack, false);
 655                                     }
 656                                 }
 657                             }
 658                         }
 659                     } else {
 660                         loop.getLoopExits().addAll(loop.getNaturalExits());
 661                     }
 662                 }
 663             }
 664         }
 665     }
 666 
 667     private static void computeLoopBlocks(Block start, Loop<Block> loop, Block[] stack, boolean usePred) {
 668         if (start.getLoop() != loop) {
 669             start.setLoop(loop);
 670             stack[0] = start;
 671             loop.getBlocks().add(start);
 672             int tos = 0;
 673             do {
 674                 Block block = stack[tos--];
 675 
 676                 // Add predecessors or successors to the loop.
 677                 for (Block b : (usePred ? block.getPredecessors() : block.getSuccessors())) {
 678                     if (b.getLoop() != loop) {
 679                         stack[++tos] = b;
 680                         b.setLoop(loop);
 681                         loop.getBlocks().add(b);
 682                     }
 683                 }
 684             } while (tos >= 0);
 685         }
 686     }
 687 
 688     public void computePostdominators() {
 689 
 690         Block[] reversePostOrderTmp = this.reversePostOrder;
 691         outer: for (int j = reversePostOrderTmp.length - 1; j >= 0; --j) {
 692             Block block = reversePostOrderTmp[j];
 693             if (block.isLoopEnd()) {
 694                 // We do not want the loop header registered as the postdominator of the loop end.
 695                 continue;
 696             }
 697             if (block.getSuccessorCount() == 0) {
 698                 // No successors => no postdominator.
 699                 continue;
 700             }
 701             Block firstSucc = block.getSuccessors()[0];
 702             if (block.getSuccessorCount() == 1) {
 703                 block.postdominator = firstSucc;
 704                 continue;
 705             }
 706             Block postdominator = firstSucc;
 707             for (Block sux : block.getSuccessors()) {
 708                 postdominator = commonPostdominator(postdominator, sux);
 709                 if (postdominator == null) {
 710                     // There is a dead end => no postdominator available.
 711                     continue outer;
 712                 }
 713             }
 714             assert !Arrays.asList(block.getSuccessors()).contains(postdominator) : "Block " + block + " has a wrong post dominator: " + postdominator;
 715             block.setPostDominator(postdominator);
 716         }
 717     }
 718 
 719     private static Block commonPostdominator(Block a, Block b) {
 720         Block iterA = a;
 721         Block iterB = b;
 722         while (iterA != iterB) {
 723             if (iterA.getId() < iterB.getId()) {
 724                 iterA = iterA.getPostdominator();
 725                 if (iterA == null) {
 726                     return null;
 727                 }
 728             } else {
 729                 assert iterB.getId() < iterA.getId();
 730                 iterB = iterB.getPostdominator();
 731                 if (iterB == null) {
 732                     return null;
 733                 }
 734             }
 735         }
 736         return iterA;
 737     }
 738 
 739     public void setNodeToBlock(NodeMap<Block> nodeMap) {
 740         this.nodeToBlock = nodeMap;
 741     }
 742 
 743     /**
 744      * Multiplies a and b and clamps the between {@link ControlFlowGraph#MIN_RELATIVE_FREQUENCY} and
 745      * {@link ControlFlowGraph#MAX_RELATIVE_FREQUENCY}.
 746      */
 747     public static double multiplyRelativeFrequencies(double a, double b) {
 748         assert !Double.isNaN(a) && !Double.isNaN(b) && Double.isFinite(a) && Double.isFinite(b) : a + " " + b;
 749         double r = a * b;
 750         if (r > MAX_RELATIVE_FREQUENCY) {
 751             return MAX_RELATIVE_FREQUENCY;
 752         }
 753         if (r < MIN_RELATIVE_FREQUENCY) {
 754             return MIN_RELATIVE_FREQUENCY;
 755         }
 756         return r;
 757     }
 758 }