use of org.graalvm.compiler.core.common.cfg.AbstractBlockBase in project graal by oracle.
the class BiDirectionalTraceBuilder method findTrace.
/**
* Build a new trace starting at {@code block}.
*
* @param debug
*/
@SuppressWarnings("try")
private Collection<AbstractBlockBase<?>> findTrace(DebugContext debug, AbstractBlockBase<?> initBlock) {
ArrayDeque<AbstractBlockBase<?>> trace = new ArrayDeque<>();
try (Indent i = debug.logAndIndent("StartTrace: %s", initBlock)) {
try (Indent indentFront = debug.logAndIndent("Head:")) {
for (AbstractBlockBase<?> block = initBlock; block != null; block = selectPredecessor(block)) {
addBlockToTrace(debug, block);
trace.addFirst(block);
}
}
/* Number head blocks. Can not do this in the loop as we go backwards. */
int blockNr = 0;
for (AbstractBlockBase<?> b : trace) {
b.setLinearScanNumber(blockNr++);
}
try (Indent indentBack = debug.logAndIndent("Tail:")) {
for (AbstractBlockBase<?> block = selectSuccessor(initBlock); block != null; block = selectSuccessor(block)) {
addBlockToTrace(debug, block);
trace.addLast(block);
/* This time we can number the blocks immediately as we go forwards. */
block.setLinearScanNumber(blockNr++);
}
}
}
debug.log("Trace: %s", trace);
return trace;
}
use of org.graalvm.compiler.core.common.cfg.AbstractBlockBase in project graal by oracle.
the class LinearScanLifetimeAnalysisPhase method numberInstructions.
/**
* Numbers all instructions in all blocks. The numbering follows the
* {@linkplain ComputeBlockOrder linear scan order}.
*/
protected void numberInstructions() {
allocator.initIntervals();
ValueConsumer setVariableConsumer = (value, mode, flags) -> {
if (isVariable(value)) {
allocator.getOrCreateInterval(asVariable(value));
}
};
// Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node.
int numInstructions = 0;
for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
numInstructions += allocator.getLIR().getLIRforBlock(block).size();
}
// initialize with correct length
allocator.initOpIdMaps(numInstructions);
int opId = 0;
int index = 0;
for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
allocator.initBlockData(block);
ArrayList<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
int numInst = instructions.size();
for (int j = 0; j < numInst; j++) {
LIRInstruction op = instructions.get(j);
op.setId(opId);
allocator.putOpIdMaps(index, op, block);
assert allocator.instructionForId(opId) == op : "must match";
op.visitEachTemp(setVariableConsumer);
op.visitEachOutput(setVariableConsumer);
index++;
// numbering of lirOps by two
opId += 2;
}
}
assert index == numInstructions : "must match";
assert (index << 1) == opId : "must match: " + (index << 1);
}
use of org.graalvm.compiler.core.common.cfg.AbstractBlockBase in project graal by oracle.
the class LinearScanLifetimeAnalysisPhase method buildIntervals.
@SuppressWarnings("try")
protected void buildIntervals(boolean detailedAsserts) {
try (Indent indent = debug.logAndIndent("build intervals")) {
InstructionValueConsumer outputConsumer = (op, operand, mode, flags) -> {
if (LinearScan.isVariableOrRegister(operand)) {
addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getValueKind(), detailedAsserts);
addRegisterHint(op, operand, mode, flags, true);
}
};
InstructionValueConsumer tempConsumer = (op, operand, mode, flags) -> {
if (LinearScan.isVariableOrRegister(operand)) {
addTemp((AllocatableValue) operand, op.id(), RegisterPriority.MustHaveRegister, operand.getValueKind(), detailedAsserts);
addRegisterHint(op, operand, mode, flags, false);
}
};
InstructionValueConsumer aliveConsumer = (op, operand, mode, flags) -> {
if (LinearScan.isVariableOrRegister(operand)) {
RegisterPriority p = registerPriorityOfInputOperand(flags);
int opId = op.id();
int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getValueKind(), detailedAsserts);
addRegisterHint(op, operand, mode, flags, false);
}
};
InstructionValueConsumer inputConsumer = (op, operand, mode, flags) -> {
if (LinearScan.isVariableOrRegister(operand)) {
int opId = op.id();
int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
RegisterPriority p = registerPriorityOfInputOperand(flags);
addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getValueKind(), detailedAsserts);
addRegisterHint(op, operand, mode, flags, false);
}
};
InstructionValueConsumer stateProc = (op, operand, mode, flags) -> {
if (LinearScan.isVariableOrRegister(operand)) {
int opId = op.id();
int blockFrom = allocator.getFirstLirInstructionId((allocator.blockForId(opId)));
addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getValueKind(), detailedAsserts);
}
};
// create a list with all caller-save registers (cpu, fpu, xmm)
RegisterArray callerSaveRegs = allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters();
// iterate all blocks in reverse order
for (int i = allocator.blockCount() - 1; i >= 0; i--) {
AbstractBlockBase<?> block = allocator.blockAt(i);
try (Indent indent2 = debug.logAndIndent("handle block %d", block.getId())) {
ArrayList<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
final int blockFrom = allocator.getFirstLirInstructionId(block);
int blockTo = allocator.getLastLirInstructionId(block);
assert blockFrom == instructions.get(0).id();
assert blockTo == instructions.get(instructions.size() - 1).id();
// Update intervals for operands live at the end of this block;
BitSet live = allocator.getBlockData(block).liveOut;
for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) {
assert live.get(operandNum) : "should not stop here otherwise";
AllocatableValue operand = allocator.intervalFor(operandNum).operand;
if (debug.isLogEnabled()) {
debug.log("live in %d: %s", operandNum, operand);
}
addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, LIRKind.Illegal, detailedAsserts);
/*
* Add special use positions for loop-end blocks when the interval is used
* anywhere inside this loop. It's possible that the block was part of a
* non-natural loop, so it might have an invalid loop index.
*/
if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().getIndex())) {
allocator.intervalFor(operandNum).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd, detailedAsserts);
}
}
/*
* Iterate all instructions of the block in reverse order. definitions of
* intervals are processed before uses.
*/
for (int j = instructions.size() - 1; j >= 0; j--) {
final LIRInstruction op = instructions.get(j);
final int opId = op.id();
try (Indent indent3 = debug.logAndIndent("handle inst %d: %s", opId, op)) {
// caller-save registers
if (op.destroysCallerSavedRegisters()) {
for (Register r : callerSaveRegs) {
if (allocator.attributes(r).isAllocatable()) {
addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal, detailedAsserts);
}
}
if (debug.isLogEnabled()) {
debug.log("operation destroys all caller-save registers");
}
}
op.visitEachOutput(outputConsumer);
op.visitEachTemp(tempConsumer);
op.visitEachAlive(aliveConsumer);
op.visitEachInput(inputConsumer);
/*
* Add uses of live locals from interpreter's point of view for proper
* debug information generation. Treat these operands as temp values (if
* the live range is extended to a call site, the value would be in a
* register at the call otherwise).
*/
op.visitEachState(stateProc);
// special steps for some instructions (especially moves)
handleMethodArguments(op);
}
}
// end of instruction iteration
}
}
/*
* Add the range [0, 1] to all fixed intervals. the register allocator need not handle
* unhandled fixed intervals.
*/
for (Interval interval : allocator.intervals()) {
if (interval != null && isRegister(interval.operand)) {
interval.addRange(0, 1);
}
}
}
}
use of org.graalvm.compiler.core.common.cfg.AbstractBlockBase in project graal by oracle.
the class LinearScanLifetimeAnalysisPhase method computeLocalLiveSets.
/**
* Computes local live sets (i.e. {@link BlockData#liveGen} and {@link BlockData#liveKill})
* separately for each block.
*/
@SuppressWarnings("try")
void computeLocalLiveSets() {
int liveSize = allocator.liveSetSize();
intervalInLoop = new BitMap2D(allocator.operandSize(), allocator.numLoops());
try {
// iterate all blocks
for (final AbstractBlockBase<?> block : allocator.sortedBlocks()) {
try (Indent indent = debug.logAndIndent("compute local live sets for block %s", block)) {
final BitSet liveGen = new BitSet(liveSize);
final BitSet liveKill = new BitSet(liveSize);
ArrayList<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
int numInst = instructions.size();
ValueConsumer useConsumer = (operand, mode, flags) -> {
if (isVariable(operand)) {
int operandNum = allocator.operandNumber(operand);
if (!liveKill.get(operandNum)) {
liveGen.set(operandNum);
if (debug.isLogEnabled()) {
debug.log("liveGen for operand %d(%s)", operandNum, operand);
}
}
if (block.getLoop() != null) {
intervalInLoop.setBit(operandNum, block.getLoop().getIndex());
}
}
if (allocator.detailedAsserts) {
verifyInput(block, liveKill, operand);
}
};
ValueConsumer stateConsumer = (operand, mode, flags) -> {
if (LinearScan.isVariableOrRegister(operand)) {
int operandNum = allocator.operandNumber(operand);
if (!liveKill.get(operandNum)) {
liveGen.set(operandNum);
if (debug.isLogEnabled()) {
debug.log("liveGen in state for operand %d(%s)", operandNum, operand);
}
}
}
};
ValueConsumer defConsumer = (operand, mode, flags) -> {
if (isVariable(operand)) {
int varNum = allocator.operandNumber(operand);
liveKill.set(varNum);
if (debug.isLogEnabled()) {
debug.log("liveKill for operand %d(%s)", varNum, operand);
}
if (block.getLoop() != null) {
intervalInLoop.setBit(varNum, block.getLoop().getIndex());
}
}
if (allocator.detailedAsserts) {
/*
* Fixed intervals are never live at block boundaries, so they need not
* be processed in live sets. Process them only in debug mode so that
* this can be checked
*/
verifyTemp(liveKill, operand);
}
};
// iterate all instructions of the block
for (int j = 0; j < numInst; j++) {
final LIRInstruction op = instructions.get(j);
try (Indent indent2 = debug.logAndIndent("handle op %d: %s", op.id(), op)) {
op.visitEachInput(useConsumer);
op.visitEachAlive(useConsumer);
/*
* Add uses of live locals from interpreter's point of view for proper
* debug information generation.
*/
op.visitEachState(stateConsumer);
op.visitEachTemp(defConsumer);
op.visitEachOutput(defConsumer);
}
}
// end of instruction iteration
BlockData blockSets = allocator.getBlockData(block);
blockSets.liveGen = liveGen;
blockSets.liveKill = liveKill;
blockSets.liveIn = new BitSet(liveSize);
blockSets.liveOut = new BitSet(liveSize);
if (debug.isLogEnabled()) {
debug.log("liveGen B%d %s", block.getId(), blockSets.liveGen);
debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill);
}
}
}
// end of block iteration
} catch (OutOfMemoryError oom) {
throw new PermanentBailoutException(oom, "Out-of-memory during live set allocation of size %d", liveSize);
}
}
use of org.graalvm.compiler.core.common.cfg.AbstractBlockBase in project graal by oracle.
the class LinearScanLifetimeAnalysisPhase method reportFailure.
@SuppressWarnings("try")
protected void reportFailure(int numBlocks) {
try (DebugContext.Scope s = debug.forceLog()) {
try (Indent indent = debug.logAndIndent("report failure")) {
BitSet startBlockLiveIn = allocator.getBlockData(allocator.getLIR().getControlFlowGraph().getStartBlock()).liveIn;
try (Indent indent2 = debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) {
for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
Interval interval = allocator.intervalFor(operandNum);
if (interval != null) {
Value operand = interval.operand;
debug.log("var %d; operand=%s; node=%s", operandNum, operand, getSourceForOperandFromDebugContext(debug, operand));
} else {
debug.log("var %d; missing operand", operandNum);
}
}
}
// print some additional information to simplify debugging
for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
Interval interval = allocator.intervalFor(operandNum);
Value operand = null;
Object valueForOperandFromDebugContext = null;
if (interval != null) {
operand = interval.operand;
valueForOperandFromDebugContext = getSourceForOperandFromDebugContext(debug, operand);
}
try (Indent indent2 = debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, valueForOperandFromDebugContext)) {
ArrayDeque<AbstractBlockBase<?>> definedIn = new ArrayDeque<>();
EconomicSet<AbstractBlockBase<?>> usedIn = EconomicSet.create(Equivalence.IDENTITY);
for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
if (allocator.getBlockData(block).liveGen.get(operandNum)) {
usedIn.add(block);
try (Indent indent3 = debug.logAndIndent("used in block B%d", block.getId())) {
for (LIRInstruction ins : allocator.getLIR().getLIRforBlock(block)) {
try (Indent indent4 = debug.logAndIndent("%d: %s", ins.id(), ins)) {
ins.forEachState((liveStateOperand, mode, flags) -> {
debug.log("operand=%s", liveStateOperand);
return liveStateOperand;
});
}
}
}
}
if (allocator.getBlockData(block).liveKill.get(operandNum)) {
definedIn.add(block);
try (Indent indent3 = debug.logAndIndent("defined in block B%d", block.getId())) {
for (LIRInstruction ins : allocator.getLIR().getLIRforBlock(block)) {
debug.log("%d: %s", ins.id(), ins);
}
}
}
}
int[] hitCount = new int[numBlocks];
while (!definedIn.isEmpty()) {
AbstractBlockBase<?> block = definedIn.removeFirst();
usedIn.remove(block);
for (AbstractBlockBase<?> successor : block.getSuccessors()) {
if (successor.isLoopHeader()) {
if (!block.isLoopEnd()) {
definedIn.add(successor);
}
} else {
if (++hitCount[successor.getId()] == successor.getPredecessorCount()) {
definedIn.add(successor);
}
}
}
}
try (Indent indent3 = debug.logAndIndent("**** offending usages are in: ")) {
for (AbstractBlockBase<?> block : usedIn) {
debug.log("B%d", block.getId());
}
}
}
}
}
} catch (Throwable e) {
throw debug.handle(e);
}
}
Aggregations