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}