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}