package org.graalvm.compiler.core.common.alloc;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import java.util.PriorityQueue;
import org.graalvm.compiler.core.common.alloc.TraceBuilderResult.TrivialTracePredicate;
import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.Indent;
public final class UniDirectionalTraceBuilder {
public static TraceBuilderResult computeTraces(DebugContext debug, AbstractBlockBase<?> startBlock, AbstractBlockBase<?>[] blocks, TrivialTracePredicate pred) {
return new UniDirectionalTraceBuilder(blocks).build(debug, startBlock, blocks, pred);
}
private final PriorityQueue<AbstractBlockBase<?>> worklist;
private final BitSet processed;
private final int[] blocked;
private final Trace[] blockToTrace;
private UniDirectionalTraceBuilder(AbstractBlockBase<?>[] blocks) {
processed = new BitSet(blocks.length);
worklist = new PriorityQueue<>(UniDirectionalTraceBuilder::compare);
assert (worklist != null);
blocked = new int[blocks.length];
blockToTrace = new Trace[blocks.length];
for (AbstractBlockBase<?> block : blocks) {
blocked[block.getId()] = block.getPredecessorCount();
}
}
private static int compare(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
return Double.compare(b.getRelativeFrequency(), a.getRelativeFrequency());
}
private boolean processed(AbstractBlockBase<?> b) {
return processed.get(b.getId());
}
@SuppressWarnings("try")
private TraceBuilderResult build(DebugContext debug, AbstractBlockBase<?> startBlock, AbstractBlockBase<?>[] blocks, TrivialTracePredicate pred) {
try (Indent indent = debug.logAndIndent("UniDirectionalTraceBuilder: start trace building: %s", startBlock)) {
ArrayList<Trace> traces = buildTraces(debug, startBlock);
return TraceBuilderResult.create(debug, blocks, traces, blockToTrace, pred);
}
}
protected ArrayList<Trace> buildTraces(DebugContext debug, AbstractBlockBase<?> startBlock) {
ArrayList<Trace> traces = new ArrayList<>();
worklist.add(startBlock);
while (!worklist.isEmpty()) {
AbstractBlockBase<?> block = worklist.poll();
assert block != null;
if (!processed(block)) {
Trace trace = new Trace(findTrace(debug, block));
for (AbstractBlockBase<?> traceBlock : trace.getBlocks()) {
blockToTrace[traceBlock.getId()] = trace;
}
trace.setId(traces.size());
traces.add(trace);
}
}
return traces;
}
@SuppressWarnings("try")
private List<AbstractBlockBase<?>> findTrace(DebugContext debug, AbstractBlockBase<?> traceStart) {
assert checkPredecessorsProcessed(traceStart);
ArrayList<AbstractBlockBase<?>> trace = new ArrayList<>();
int blockNumber = 0;
try (Indent i = debug.logAndIndent("StartTrace: %s", traceStart)) {
for (AbstractBlockBase<?> block = traceStart; block != null; block = selectNext(block)) {
debug.log("add %s (freq: %f)", block, block.getRelativeFrequency());
processed.set(block.getId());
trace.add(block);
unblock(block);
block.setLinearScanNumber(blockNumber++);
}
}
return trace;
}
private boolean checkPredecessorsProcessed(AbstractBlockBase<?> block) {
for (AbstractBlockBase<?> pred : block.getPredecessors()) {
assert processed(pred) : "Predecessor unscheduled: " + pred;
}
return true;
}
private void unblock(AbstractBlockBase<?> block) {
for (AbstractBlockBase<?> successor : block.getSuccessors()) {
if (!processed(successor)) {
int blockCount = --blocked[successor.getId()];
assert blockCount >= 0;
if (blockCount == 0) {
worklist.add(successor);
}
}
}
}
private AbstractBlockBase<?> selectNext(AbstractBlockBase<?> block) {
AbstractBlockBase<?> next = null;
for (AbstractBlockBase<?> successor : block.getSuccessors()) {
if (!processed(successor) && (next == null || successor.getRelativeFrequency() > next.getRelativeFrequency())) {
next = successor;
}
}
return next;
}
}