001/*
002 * Copyright (c) 2009, 2011, 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 */
023
024package com.oracle.graal.compiler.common.alloc;
025
026import java.util.*;
027
028import com.oracle.graal.compiler.common.cfg.*;
029
030/**
031 * Computes an ordering of the block that can be used by the linear scan register allocator and the
032 * machine code generator. The machine code generation order will start with the first block and
033 * produce a straight sequence always following the most likely successor. Then it will continue
034 * with the most likely path that was left out during this process. The process iteratively
035 * continues until all blocks are scheduled. Additionally, it is guaranteed that all blocks of a
036 * loop are scheduled before any block following the loop is scheduled.
037 *
038 * The machine code generator order includes reordering of loop headers such that the backward jump
039 * is a conditional jump if there is only one loop end block. Additionally, the target of loop
040 * backward jumps are always marked as aligned. Aligning the target of conditional jumps does not
041 * bring a measurable benefit and is therefore avoided to keep the code size small.
042 *
043 * The linear scan register allocator order has an additional mechanism that prevents merge nodes
044 * from being scheduled if there is at least one highly likely predecessor still unscheduled. This
045 * increases the probability that the merge node and the corresponding predecessor are more closely
046 * together in the schedule thus decreasing the probability for inserted phi moves. Also, the
047 * algorithm sets the linear scan order number of the block that corresponds to its index in the
048 * linear scan order.
049 */
050public final class ComputeBlockOrder {
051
052    /**
053     * The initial capacities of the worklists used for iteratively finding the block order.
054     */
055    private static final int INITIAL_WORKLIST_CAPACITY = 10;
056
057    /**
058     * Divisor used for degrading the probability of the current path versus unscheduled paths at a
059     * merge node when calculating the linear scan order. A high value means that predecessors of
060     * merge nodes are more likely to be scheduled before the merge node.
061     */
062    private static final int PENALTY_VERSUS_UNSCHEDULED = 10;
063
064    /**
065     * Computes the block order used for the linear scan register allocator.
066     *
067     * @return sorted list of blocks
068     */
069    public static <T extends AbstractBlockBase<T>> List<T> computeLinearScanOrder(int blockCount, T startBlock) {
070        List<T> order = new ArrayList<>();
071        BitSet visitedBlocks = new BitSet(blockCount);
072        PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks);
073        computeLinearScanOrder(order, worklist, visitedBlocks);
074        assert checkOrder(order, blockCount);
075        return order;
076    }
077
078    /**
079     * Computes the block order used for code emission.
080     *
081     * @return sorted list of blocks
082     */
083    public static <T extends AbstractBlockBase<T>> List<T> computeCodeEmittingOrder(int blockCount, T startBlock) {
084        List<T> order = new ArrayList<>();
085        BitSet visitedBlocks = new BitSet(blockCount);
086        PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks);
087        computeCodeEmittingOrder(order, worklist, visitedBlocks);
088        assert checkOrder(order, blockCount);
089        return order;
090    }
091
092    /**
093     * Iteratively adds paths to the code emission block order.
094     */
095    private static <T extends AbstractBlockBase<T>> void computeCodeEmittingOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
096        while (!worklist.isEmpty()) {
097            T nextImportantPath = worklist.poll();
098            addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks);
099        }
100    }
101
102    /**
103     * Iteratively adds paths to the linear scan block order.
104     */
105    private static <T extends AbstractBlockBase<T>> void computeLinearScanOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
106        while (!worklist.isEmpty()) {
107            T nextImportantPath = worklist.poll();
108            addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks);
109        }
110    }
111
112    /**
113     * Initializes the priority queue used for the work list of blocks and adds the start block.
114     */
115    private static <T extends AbstractBlockBase<T>> PriorityQueue<T> initializeWorklist(T startBlock, BitSet visitedBlocks) {
116        PriorityQueue<T> result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator<>());
117        result.add(startBlock);
118        visitedBlocks.set(startBlock.getId());
119        return result;
120    }
121
122    /**
123     * Add a linear path to the linear scan order greedily following the most likely successor.
124     */
125    private static <T extends AbstractBlockBase<T>> void addPathToLinearScanOrder(T block, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
126        block.setLinearScanNumber(order.size());
127        order.add(block);
128        T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks);
129        enqueueSuccessors(block, worklist, visitedBlocks);
130        if (mostLikelySuccessor != null) {
131            if (!mostLikelySuccessor.isLoopHeader() && mostLikelySuccessor.getPredecessorCount() > 1) {
132                // We are at a merge. Check probabilities of predecessors that are not yet
133                // scheduled.
134                double unscheduledSum = 0.0;
135                for (T pred : mostLikelySuccessor.getPredecessors()) {
136                    if (pred.getLinearScanNumber() == -1) {
137                        unscheduledSum += pred.probability();
138                    }
139                }
140
141                if (unscheduledSum > block.probability() / PENALTY_VERSUS_UNSCHEDULED) {
142                    // Add this merge only after at least one additional predecessor gets scheduled.
143                    visitedBlocks.clear(mostLikelySuccessor.getId());
144                    return;
145                }
146            }
147            addPathToLinearScanOrder(mostLikelySuccessor, order, worklist, visitedBlocks);
148        }
149    }
150
151    /**
152     * Add a linear path to the code emission order greedily following the most likely successor.
153     */
154    private static <T extends AbstractBlockBase<T>> void addPathToCodeEmittingOrder(T initialBlock, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
155        T block = initialBlock;
156        while (block != null) {
157            // Skip loop headers if there is only a single loop end block to
158            // make the backward jump be a conditional jump.
159            if (!skipLoopHeader(block)) {
160
161                // Align unskipped loop headers as they are the target of the backward jump.
162                if (block.isLoopHeader()) {
163                    block.setAlign(true);
164                }
165                addBlock(block, order);
166            }
167
168            Loop<T> loop = block.getLoop();
169            if (block.isLoopEnd() && skipLoopHeader(loop.getHeader())) {
170
171                // This is the only loop end of a skipped loop header.
172                // Add the header immediately afterwards.
173                addBlock(loop.getHeader(), order);
174
175                // Make sure the loop successors of the loop header are aligned
176                // as they are the target
177                // of the backward jump.
178                for (T successor : loop.getHeader().getSuccessors()) {
179                    if (successor.getLoopDepth() == block.getLoopDepth()) {
180                        successor.setAlign(true);
181                    }
182                }
183            }
184
185            T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks);
186            enqueueSuccessors(block, worklist, visitedBlocks);
187            block = mostLikelySuccessor;
188        }
189    }
190
191    /**
192     * Adds a block to the ordering.
193     */
194    private static <T extends AbstractBlockBase<T>> void addBlock(T header, List<T> order) {
195        assert !order.contains(header) : "Cannot insert block twice";
196        order.add(header);
197    }
198
199    /**
200     * Find the highest likely unvisited successor block of a given block.
201     */
202    private static <T extends AbstractBlockBase<T>> T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks) {
203        T result = null;
204        for (T successor : block.getSuccessors()) {
205            assert successor.probability() >= 0.0 : "Probabilities must be positive";
206            if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() && (result == null || successor.probability() >= result.probability())) {
207                result = successor;
208            }
209        }
210        if (result != null) {
211            visitedBlocks.set(result.getId());
212        }
213        return result;
214    }
215
216    /**
217     * Add successor blocks into the given work list if they are not already marked as visited.
218     */
219    private static <T extends AbstractBlockBase<T>> void enqueueSuccessors(T block, PriorityQueue<T> worklist, BitSet visitedBlocks) {
220        for (T successor : block.getSuccessors()) {
221            if (!visitedBlocks.get(successor.getId())) {
222                visitedBlocks.set(successor.getId());
223                worklist.add(successor);
224            }
225        }
226    }
227
228    /**
229     * Skip the loop header block if the loop consists of more than one block and it has only a
230     * single loop end block.
231     */
232    private static <T extends AbstractBlockBase<T>> boolean skipLoopHeader(AbstractBlockBase<T> block) {
233        return (block.isLoopHeader() && !block.isLoopEnd() && block.getLoop().numBackedges() == 1);
234    }
235
236    /**
237     * Checks that the ordering contains the expected number of blocks.
238     */
239    private static boolean checkOrder(List<? extends AbstractBlockBase<?>> order, int expectedBlockCount) {
240        assert order.size() == expectedBlockCount : String.format("Number of blocks in ordering (%d) does not match expected block count (%d)", order.size(), expectedBlockCount);
241        return true;
242    }
243
244    /**
245     * Comparator for sorting blocks based on loop depth and probability.
246     */
247    private static class BlockOrderComparator<T extends AbstractBlockBase<T>> implements Comparator<T> {
248
249        @Override
250        public int compare(T a, T b) {
251            // Loop blocks before any loop exit block.
252            int diff = b.getLoopDepth() - a.getLoopDepth();
253            if (diff != 0) {
254                return diff;
255            }
256
257            // Blocks with high probability before blocks with low probability.
258            if (a.probability() > b.probability()) {
259                return -1;
260            } else {
261                return 1;
262            }
263        }
264    }
265}