001/*
002 * Copyright (c) 2014, 2014, 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.compiler.common.cfg;
024
025import java.util.*;
026
027public interface AbstractControlFlowGraph<T extends AbstractBlockBase<T>> {
028
029    int BLOCK_ID_INITIAL = -1;
030    int BLOCK_ID_VISITED = -2;
031
032    /**
033     * Returns the list blocks contained in this control flow graph.
034     *
035     * It is {@linkplain CFGVerifier guaranteed} that the blocks are numbered and ordered according
036     * to a reverse post order traversal of the control flow graph.
037     *
038     * @see CFGVerifier
039     */
040    List<T> getBlocks();
041
042    Collection<Loop<T>> getLoops();
043
044    T getStartBlock();
045
046    /**
047     * Computes the dominators of control flow graph.
048     */
049    @SuppressWarnings("unchecked")
050    static <T extends AbstractBlockBase<T>> void computeDominators(AbstractControlFlowGraph<T> cfg) {
051        List<T> reversePostOrder = cfg.getBlocks();
052        assert reversePostOrder.get(0).getPredecessorCount() == 0 : "start block has no predecessor and therefore no dominator";
053        for (int i = 1; i < reversePostOrder.size(); i++) {
054            T block = reversePostOrder.get(i);
055            assert block.getPredecessorCount() > 0;
056            T dominator = null;
057            for (T pred : block.getPredecessors()) {
058                if (!pred.isLoopEnd()) {
059                    dominator = (T) ((dominator == null) ? pred : commonDominatorRaw(dominator, pred));
060                }
061            }
062            // set dominator
063            block.setDominator(dominator);
064            if (dominator.getDominated().equals(Collections.emptyList())) {
065                dominator.setDominated(new ArrayList<>());
066            }
067            dominator.getDominated().add(block);
068        }
069        calcDominatorRanges(cfg.getStartBlock());
070    }
071
072    static <T extends AbstractBlockBase<T>> void calcDominatorRanges(T block) {
073        final class Frame {
074            int myNumber;
075            int maxNumber;
076            T block;
077            Iterator<T> dominated;
078            Frame parent;
079
080            public Frame(int myNumber, T block, Iterator<T> dominated, Frame parent) {
081                super();
082                this.myNumber = myNumber;
083                this.maxNumber = myNumber;
084                this.block = block;
085                this.dominated = dominated;
086                this.parent = parent;
087            }
088        }
089        Frame f = new Frame(0, block, block.getDominated().iterator(), null);
090        while (f != null) {
091            if (!f.dominated.hasNext()) { // Retreat
092                f.block.setDominatorNumbers(f.myNumber, f.maxNumber);
093                if (f.parent != null) {
094                    f.parent.maxNumber = f.maxNumber;
095                }
096                f = f.parent;
097            } else {
098                T d = f.dominated.next();
099                List<T> dd = d.getDominated();
100                f = new Frame(f.maxNumber + 1, d, dd.iterator(), f);
101            }
102        }
103    }
104
105    /**
106     * True if block {@code a} is dominated by block {@code b}.
107     */
108    static boolean isDominatedBy(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
109        int domNumberA = a.getDominatorNumber();
110        int domNumberB = b.getDominatorNumber();
111        return domNumberA >= domNumberB && domNumberA <= b.getMaxChildDominatorNumber();
112    }
113
114    /**
115     * True if block {@code a} dominates block {@code b} and {@code a} is not identical block to
116     * {@code b}.
117     */
118    static boolean strictlyDominates(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
119        return a != b && dominates(a, b);
120    }
121
122    /**
123     * True if block {@code a} dominates block {@code b}.
124     */
125    static boolean dominates(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
126        assert a != null && b != null;
127        return isDominatedBy(b, a);
128    }
129
130    /**
131     * Calculates the common dominator of two blocks.
132     *
133     * Note that this algorithm makes use of special properties regarding the numbering of blocks.
134     *
135     * @see #getBlocks()
136     * @see CFGVerifier
137     */
138    static AbstractBlockBase<?> commonDominator(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
139        if (a == null) {
140            return b;
141        } else if (b == null) {
142            return a;
143        } else {
144            int aDomDepth = a.getDominatorDepth();
145            int bDomDepth = b.getDominatorDepth();
146            AbstractBlockBase<?> aTemp;
147            AbstractBlockBase<?> bTemp;
148            if (aDomDepth > bDomDepth) {
149                aTemp = a;
150                bTemp = b;
151            } else {
152                aTemp = b;
153                bTemp = a;
154            }
155            return commonDominatorHelper(aTemp, bTemp);
156        }
157    }
158
159    static AbstractBlockBase<?> commonDominatorHelper(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
160        int domNumberA = a.getDominatorNumber();
161        AbstractBlockBase<?> result = b;
162        while (domNumberA < result.getDominatorNumber()) {
163            result = result.getDominator();
164        }
165        while (domNumberA > result.getMaxChildDominatorNumber()) {
166            result = result.getDominator();
167        }
168        return result;
169    }
170
171    static AbstractBlockBase<?> commonDominatorRaw(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
172        int aDomDepth = a.getDominatorDepth();
173        int bDomDepth = b.getDominatorDepth();
174        if (aDomDepth > bDomDepth) {
175            return commonDominatorRawSameDepth(a.getDominator(aDomDepth - bDomDepth), b);
176        } else {
177            return commonDominatorRawSameDepth(a, b.getDominator(bDomDepth - aDomDepth));
178        }
179    }
180
181    static AbstractBlockBase<?> commonDominatorRawSameDepth(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
182        AbstractBlockBase<?> iterA = a;
183        AbstractBlockBase<?> iterB = b;
184        while (iterA != iterB) {
185            iterA = iterA.getDominator();
186            iterB = iterB.getDominator();
187        }
188        return iterA;
189    }
190
191    /**
192     * @see AbstractControlFlowGraph#commonDominator(AbstractBlockBase, AbstractBlockBase)
193     */
194    @SuppressWarnings("unchecked")
195    static <T extends AbstractBlockBase<T>> T commonDominatorTyped(T a, T b) {
196        return (T) commonDominator(a, b);
197    }
198}