001/* 002 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.nodes.cfg; 024 025import java.util.*; 026 027import jdk.internal.jvmci.common.*; 028import com.oracle.graal.debug.*; 029 030import com.oracle.graal.compiler.common.cfg.*; 031import com.oracle.graal.graph.*; 032import com.oracle.graal.nodes.*; 033 034public class ControlFlowGraph implements AbstractControlFlowGraph<Block> { 035 /** 036 * Don't allow probability values to be become too small as this makes frequency calculations 037 * large enough that they can overflow the range of a double. This commonly happens with 038 * infinite loops within infinite loops. 039 */ 040 public static final double MIN_PROBABILITY = 0.000001; 041 042 public final StructuredGraph graph; 043 044 private NodeMap<Block> nodeToBlock; 045 private List<Block> reversePostOrder; 046 private List<Loop<Block>> loops; 047 048 public static ControlFlowGraph compute(StructuredGraph graph, boolean connectBlocks, boolean computeLoops, boolean computeDominators, boolean computePostdominators) { 049 ControlFlowGraph cfg = new ControlFlowGraph(graph); 050 cfg.identifyBlocks(); 051 052 if (connectBlocks || computeLoops || computeDominators || computePostdominators) { 053 cfg.connectBlocks(); 054 } 055 if (computeLoops) { 056 cfg.computeLoopInformation(); 057 } 058 if (computeDominators) { 059 AbstractControlFlowGraph.computeDominators(cfg); 060 } 061 if (computePostdominators) { 062 cfg.computePostdominators(); 063 } 064 // there's not much to verify when connectBlocks == false 065 assert !(connectBlocks || computeLoops || computeDominators || computePostdominators) || CFGVerifier.verify(cfg); 066 return cfg; 067 } 068 069 protected ControlFlowGraph(StructuredGraph graph) { 070 this.graph = graph; 071 this.nodeToBlock = graph.createNodeMap(); 072 } 073 074 public List<Block> getBlocks() { 075 return reversePostOrder; 076 } 077 078 public Block getStartBlock() { 079 return reversePostOrder.get(0); 080 } 081 082 public Iterable<Block> reversePostOrder() { 083 return reversePostOrder; 084 } 085 086 public Iterable<Block> postOrder() { 087 return new Iterable<Block>() { 088 089 @Override 090 public Iterator<Block> iterator() { 091 return new Iterator<Block>() { 092 093 private ListIterator<Block> it = reversePostOrder.listIterator(reversePostOrder.size()); 094 095 @Override 096 public boolean hasNext() { 097 return it.hasPrevious(); 098 } 099 100 @Override 101 public Block next() { 102 return it.previous(); 103 } 104 105 @Override 106 public void remove() { 107 throw new UnsupportedOperationException(); 108 } 109 }; 110 } 111 }; 112 } 113 114 public NodeMap<Block> getNodeToBlock() { 115 return nodeToBlock; 116 } 117 118 public Block blockFor(Node node) { 119 return nodeToBlock.get(node); 120 } 121 122 public double frequencyFor(FixedNode node) { 123 return blockFor(node).probability(); 124 } 125 126 public List<Loop<Block>> getLoops() { 127 return loops; 128 } 129 130 private void identifyBlock(Block block) { 131 AbstractBeginNode start = block.getBeginNode(); 132 133 // assign proxies of a loop exit to this block 134 if (start instanceof LoopExitNode) { 135 for (Node usage : start.usages()) { 136 if (usage instanceof ProxyNode) { 137 nodeToBlock.set(usage, block); 138 } 139 } 140 } else if (start instanceof AbstractMergeNode) { 141 for (PhiNode phi : ((AbstractMergeNode) start).phis()) { 142 nodeToBlock.set(phi, block); 143 } 144 } 145 146 FixedWithNextNode cur = start; 147 while (true) { 148 assert !cur.isDeleted(); 149 assert nodeToBlock.get(cur) == null; 150 nodeToBlock.set(cur, block); 151 FixedNode next = cur.next(); 152 if (next instanceof AbstractBeginNode) { 153 block.endNode = cur; 154 return; 155 } else if (next instanceof FixedWithNextNode) { 156 cur = (FixedWithNextNode) next; 157 } else { 158 nodeToBlock.set(next, block); 159 block.endNode = next; 160 return; 161 } 162 } 163 } 164 165 private void identifyBlocks() { 166 // Find all block headers 167 int numBlocks = 0; 168 for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.TYPE)) { 169 Block block = new Block(begin); 170 numBlocks++; 171 identifyBlock(block); 172 } 173 174 // Compute postorder. 175 ArrayList<Block> postOrder = new ArrayList<>(numBlocks); 176 ArrayList<Block> stack = new ArrayList<>(); 177 stack.add(blockFor(graph.start())); 178 179 do { 180 Block block = stack.get(stack.size() - 1); 181 if (block.getId() == BLOCK_ID_INITIAL) { 182 // First time we see this block: push all successors. 183 for (Node suxNode : block.getEndNode().cfgSuccessors()) { 184 Block suxBlock = blockFor(suxNode); 185 assert suxBlock != null : suxNode; 186 if (suxBlock.getId() == BLOCK_ID_INITIAL) { 187 stack.add(suxBlock); 188 } 189 } 190 block.setId(BLOCK_ID_VISITED); 191 } else if (block.getId() == BLOCK_ID_VISITED) { 192 // Second time we see this block: All successors have been processed, so add block 193 // to postorder list. 194 stack.remove(stack.size() - 1); 195 postOrder.add(block); 196 } else { 197 throw JVMCIError.shouldNotReachHere(); 198 } 199 } while (!stack.isEmpty()); 200 201 // Compute reverse postorder and number blocks. 202 assert postOrder.size() <= numBlocks : "some blocks originally created can be unreachable, so actual block list can be shorter"; 203 numBlocks = postOrder.size(); 204 reversePostOrder = new ArrayList<>(numBlocks); 205 for (int i = 0; i < numBlocks; i++) { 206 Block block = postOrder.get(numBlocks - i - 1); 207 block.setId(i); 208 reversePostOrder.add(block); 209 } 210 } 211 212 // Connect blocks (including loop backward edges), but ignoring dead code (blocks with id < 0). 213 // Predecessors need to be in the order expected when iterating phi inputs. 214 private void connectBlocks() { 215 for (Block block : reversePostOrder) { 216 List<Block> predecessors = new ArrayList<>(1); 217 double probability = block.getBeginNode() instanceof StartNode ? 1D : 0D; 218 for (Node predNode : block.getBeginNode().cfgPredecessors()) { 219 Block predBlock = nodeToBlock.get(predNode); 220 if (predBlock.getId() >= 0) { 221 predecessors.add(predBlock); 222 if (predBlock.getSuccessors() == null) { 223 predBlock.setSuccessors(new ArrayList<>(1)); 224 } 225 predBlock.getSuccessors().add(block); 226 probability += predBlock.probability; 227 } 228 } 229 if (predecessors.size() == 1 && predecessors.get(0).getEndNode() instanceof ControlSplitNode) { 230 probability *= ((ControlSplitNode) predecessors.get(0).getEndNode()).probability(block.getBeginNode()); 231 } 232 if (block.getBeginNode() instanceof LoopBeginNode) { 233 LoopBeginNode loopBegin = (LoopBeginNode) block.getBeginNode(); 234 probability *= loopBegin.loopFrequency(); 235 for (LoopEndNode predNode : loopBegin.orderedLoopEnds()) { 236 Block predBlock = nodeToBlock.get(predNode); 237 assert predBlock != null : predNode; 238 if (predBlock.getId() >= 0) { 239 predecessors.add(predBlock); 240 if (predBlock.getSuccessors() == null) { 241 predBlock.setSuccessors(new ArrayList<>(1)); 242 } 243 predBlock.getSuccessors().add(block); 244 } 245 } 246 } 247 if (probability > 1. / MIN_PROBABILITY) { 248 probability = 1. / MIN_PROBABILITY; 249 } 250 block.setPredecessors(predecessors); 251 block.setProbability(probability); 252 if (block.getSuccessors() == null) { 253 block.setSuccessors(new ArrayList<>(1)); 254 } 255 } 256 } 257 258 private void computeLoopInformation() { 259 loops = new ArrayList<>(); 260 for (Block block : reversePostOrder) { 261 AbstractBeginNode beginNode = block.getBeginNode(); 262 if (beginNode instanceof LoopBeginNode) { 263 Loop<Block> loop = new HIRLoop(block.getLoop(), loops.size(), block); 264 loops.add(loop); 265 266 LoopBeginNode loopBegin = (LoopBeginNode) beginNode; 267 for (LoopEndNode end : loopBegin.loopEnds()) { 268 Block endBlock = nodeToBlock.get(end); 269 computeLoopBlocks(endBlock, loop); 270 } 271 272 for (LoopExitNode exit : loopBegin.loopExits()) { 273 Block exitBlock = nodeToBlock.get(exit); 274 assert exitBlock.getPredecessorCount() == 1; 275 computeLoopBlocks(exitBlock.getFirstPredecessor(), loop); 276 loop.getExits().add(exitBlock); 277 } 278 279 // The following loop can add new blocks to the end of the loop's block list. 280 int size = loop.getBlocks().size(); 281 for (int i = 0; i < size; ++i) { 282 Block b = loop.getBlocks().get(i); 283 for (Block sux : b.getSuccessors()) { 284 if (sux.loop != loop) { 285 AbstractBeginNode begin = sux.getBeginNode(); 286 if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) { 287 Debug.log(3, "Unexpected loop exit with %s, including whole branch in the loop", sux); 288 addBranchToLoop(loop, sux); 289 } 290 } 291 } 292 } 293 } 294 } 295 } 296 297 private static void addBranchToLoop(Loop<Block> l, Block b) { 298 if (b.loop == l) { 299 return; 300 } 301 assert !(l.getBlocks().contains(b)); 302 l.getBlocks().add(b); 303 b.loop = l; 304 for (Block sux : b.getSuccessors()) { 305 addBranchToLoop(l, sux); 306 } 307 } 308 309 private static void computeLoopBlocks(Block ablock, Loop<Block> aloop) { 310 final int process = 0; 311 final int stepOut = 1; 312 class Frame { 313 final Iterator<Block> blocks; 314 final Loop<Block> loop; 315 final Frame parent; 316 317 public Frame(Iterator<Block> blocks, Loop<Block> loop, Frame parent) { 318 this.blocks = blocks; 319 this.loop = loop; 320 this.parent = parent; 321 } 322 } 323 int state = process; 324 Frame c = new Frame(Arrays.asList(ablock).iterator(), aloop, null); 325 while (c != null) { 326 int nextState = state; 327 if (state == process) { 328 Loop<Block> loop = c.loop; 329 Block block = c.blocks.next(); 330 if (block.getLoop() == loop) { 331 nextState = stepOut; 332 } else { 333 assert block.loop == loop.getParent(); 334 block.loop = c.loop; 335 336 assert !c.loop.getBlocks().contains(block); 337 c.loop.getBlocks().add(block); 338 339 if (block != c.loop.getHeader()) { 340 c = new Frame(block.getPredecessors().iterator(), loop, c); 341 } else { 342 nextState = stepOut; 343 } 344 } 345 } else if (state == stepOut) { 346 if (c.blocks.hasNext()) { 347 nextState = process; 348 } else { 349 c = c.parent; 350 } 351 } else { 352 JVMCIError.shouldNotReachHere(); 353 } 354 state = nextState; 355 } 356 } 357 358 public void computePostdominators() { 359 outer: for (Block block : postOrder()) { 360 if (block.isLoopEnd()) { 361 // We do not want the loop header registered as the postdominator of the loop end. 362 continue; 363 } 364 if (block.getSuccessorCount() == 0) { 365 // No successors => no postdominator. 366 continue; 367 } 368 Block firstSucc = block.getSuccessors().get(0); 369 if (block.getSuccessorCount() == 1) { 370 block.postdominator = firstSucc; 371 continue; 372 } 373 Block postdominator = firstSucc; 374 for (Block sux : block.getSuccessors()) { 375 postdominator = commonPostdominator(postdominator, sux); 376 if (postdominator == null) { 377 // There is a dead end => no postdominator available. 378 continue outer; 379 } 380 } 381 assert !block.getSuccessors().contains(postdominator) : "Block " + block + " has a wrong post dominator: " + postdominator; 382 block.postdominator = postdominator; 383 } 384 } 385 386 private static Block commonPostdominator(Block a, Block b) { 387 Block iterA = a; 388 Block iterB = b; 389 while (iterA != iterB) { 390 if (iterA.getId() < iterB.getId()) { 391 iterA = iterA.getPostdominator(); 392 if (iterA == null) { 393 return null; 394 } 395 } else { 396 assert iterB.getId() < iterA.getId(); 397 iterB = iterB.getPostdominator(); 398 if (iterB == null) { 399 return null; 400 } 401 } 402 } 403 return iterA; 404 } 405 406 public void setNodeToBlock(NodeMap<Block> nodeMap) { 407 this.nodeToBlock = nodeMap; 408 } 409}