001/* 002 * Copyright (c) 2015, 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.compiler.common.alloc; 024 025import java.util.*; 026 027import com.oracle.graal.compiler.common.cfg.*; 028import com.oracle.graal.debug.*; 029import com.oracle.graal.debug.Debug.Scope; 030 031public final class TraceBuilder<T extends AbstractBlockBase<T>> { 032 033 public static final class TraceBuilderResult<T extends AbstractBlockBase<T>> { 034 private final List<List<T>> traces; 035 private final int[] blockToTrace; 036 037 private TraceBuilderResult(List<List<T>> traces, int[] blockToTrace) { 038 this.traces = traces; 039 this.blockToTrace = blockToTrace; 040 } 041 042 public int getTraceForBlock(AbstractBlockBase<?> block) { 043 return blockToTrace[block.getId()]; 044 } 045 046 public List<List<T>> getTraces() { 047 return traces; 048 } 049 } 050 051 /** 052 * Build traces of sequentially executed blocks. 053 */ 054 public static <T extends AbstractBlockBase<T>> TraceBuilderResult<T> computeTraces(T startBlock, List<T> blocks) { 055 return new TraceBuilder<>(blocks).build(startBlock); 056 } 057 058 private final PriorityQueue<T> worklist; 059 private final BitSet processed; 060 /** 061 * Contains the number of unprocessed predecessors for every {@link AbstractBlockBase#getId() 062 * block}. 063 */ 064 private final int[] blocked; 065 private final int[] blockToTrace; 066 067 private TraceBuilder(List<T> blocks) { 068 processed = new BitSet(blocks.size()); 069 worklist = new PriorityQueue<T>(TraceBuilder::compare); 070 blocked = new int[blocks.size()]; 071 blockToTrace = new int[blocks.size()]; 072 for (T block : blocks) { 073 blocked[block.getId()] = block.getPredecessorCount(); 074 } 075 } 076 077 private static <T extends AbstractBlockBase<T>> int compare(T a, T b) { 078 return Double.compare(b.probability(), a.probability()); 079 } 080 081 private boolean processed(T b) { 082 return processed.get(b.getId()); 083 } 084 085 private TraceBuilderResult<T> build(T startBlock) { 086 try (Scope s = Debug.scope("TraceBuilder"); Indent i = Debug.logAndIndent("start trace building: " + startBlock)) { 087 ArrayList<List<T>> traces = buildTraces(startBlock); 088 089 assert verify(traces); 090 return new TraceBuilderResult<>(traces, blockToTrace); 091 } 092 } 093 094 private boolean verify(ArrayList<List<T>> traces) { 095 assert traces.stream().flatMap(l -> l.stream()).distinct().count() == blocked.length : "Not all blocks assigned to traces!"; 096 for (List<T> trace : traces) { 097 T last = null; 098 for (T current : trace) { 099 assert last == null || current.getPredecessors().contains(last); 100 last = current; 101 } 102 } 103 return true; 104 } 105 106 protected ArrayList<List<T>> buildTraces(T startBlock) { 107 ArrayList<List<T>> traces = new ArrayList<>(); 108 // add start block 109 worklist.add(startBlock); 110 // process worklist 111 while (!worklist.isEmpty()) { 112 T block = worklist.poll(); 113 assert block != null; 114 traces.add(startTrace(block, traces.size())); 115 } 116 return traces; 117 } 118 119 /** 120 * Build a new trace starting at {@code block}. 121 */ 122 private List<T> startTrace(T block, int traceNumber) { 123 assert block.getPredecessors().stream().allMatch(this::processed) : "Predecessor unscheduled: " + block.getPredecessors().stream().filter(this::processed).findFirst().get(); 124 ArrayList<T> trace = new ArrayList<>(); 125 int blockNumber = 0; 126 try (Indent i = Debug.logAndIndent("StartTrace: " + block)) { 127 for (T currentBlock = block; currentBlock != null; currentBlock = selectNext(currentBlock)) { 128 Debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability()); 129 processed.set(currentBlock.getId()); 130 worklist.remove(currentBlock); 131 trace.add(currentBlock); 132 unblock(currentBlock); 133 currentBlock.setLinearScanNumber(blockNumber++); 134 blockToTrace[currentBlock.getId()] = traceNumber; 135 } 136 } 137 return trace; 138 } 139 140 /** 141 * Decrease the {@link #blocked} count for all predecessors and add them to the worklist once 142 * the count reaches 0. 143 */ 144 private void unblock(T currentBlock) { 145 for (T successor : currentBlock.getSuccessors()) { 146 if (!processed(successor)) { 147 int blockCount = --blocked[successor.getId()]; 148 assert blockCount >= 0; 149 if (blockCount == 0) { 150 worklist.add(successor); 151 } 152 } 153 } 154 } 155 156 /** 157 * @return The unprocessed predecessor with the highest probability, or {@code null}. 158 */ 159 private T selectNext(T currentBlock) { 160 T next = null; 161 for (T succ : currentBlock.getSuccessors()) { 162 if (!processed(succ) && (next == null || succ.probability() > next.probability())) { 163 next = succ; 164 } 165 } 166 return next; 167 } 168}