use of org.graalvm.compiler.lir.LIRInstruction 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.lir.LIRInstruction 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);
}
}
use of org.graalvm.compiler.lir.LIRInstruction in project graal by oracle.
the class MoveResolver method spillInterval.
protected void spillInterval(int spillCandidate, Interval fromInterval, AllocatableValue spillSlot) {
assert mappingFrom.get(spillCandidate).equals(fromInterval);
Interval spillInterval = getAllocator().createDerivedInterval(fromInterval);
spillInterval.setKind(fromInterval.kind());
// add a dummy range because real position is difficult to calculate
// Note: this range is a special case when the integrity of the allocation is
// checked
spillInterval.addRange(1, 2);
spillInterval.assignLocation(spillSlot);
DebugContext debug = allocator.getDebug();
if (debug.isLogEnabled()) {
debug.log("created new Interval for spilling: %s", spillInterval);
}
blockRegisters(spillInterval);
// insert a move from register to stack and update the mapping
LIRInstruction move = insertMove(fromInterval, spillInterval);
mappingFrom.set(spillCandidate, spillInterval);
unblockRegisters(fromInterval);
move.setComment(res, "MoveResolver break cycle");
}
use of org.graalvm.compiler.lir.LIRInstruction in project graal by oracle.
the class MoveResolver method insertMove.
private LIRInstruction insertMove(Constant fromOpr, Interval toInterval) {
assert insertIdx != -1 : "must setup insert position first";
AllocatableValue toOpr = toInterval.operand;
LIRInstruction move;
if (LIRValueUtil.isStackSlotValue(toInterval.location())) {
move = getAllocator().getSpillMoveFactory().createStackLoad(toOpr, fromOpr);
} else {
move = getAllocator().getSpillMoveFactory().createLoad(toOpr, fromOpr);
}
insertionBuffer.append(insertIdx, move);
DebugContext debug = allocator.getDebug();
if (debug.isLogEnabled()) {
debug.log("insert move from value %s to %s at %d", fromOpr, toInterval, insertIdx);
}
return move;
}
use of org.graalvm.compiler.lir.LIRInstruction in project graal by oracle.
the class RegisterVerifier method processOperations.
void processOperations(AbstractBlockBase<?> block, final Interval[] inputState) {
ArrayList<LIRInstruction> ops = allocator.getLIR().getLIRforBlock(block);
DebugContext debug = allocator.getDebug();
InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
@Override
public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
// we skip spill moves inserted by the spill position optimization
if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand) && op.id() != LinearScan.DOMINATOR_SPILL_MOVE_ID) {
Interval interval = intervalAt(operand);
if (op.id() != -1) {
interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
}
assert checkState(block, op, inputState, interval.operand, interval.location(), interval.splitParent());
}
}
};
InstructionValueConsumer defConsumer = (op, operand, mode, flags) -> {
if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
Interval interval = intervalAt(operand);
if (op.id() != -1) {
interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
}
statePut(debug, inputState, interval.location(), interval.splitParent());
}
};
// visit all instructions of the block
for (int i = 0; i < ops.size(); i++) {
final LIRInstruction op = ops.get(i);
if (debug.isLogEnabled()) {
debug.log("%s", op.toStringWithIdPrefix());
}
// check if input operands are correct
op.visitEachInput(useConsumer);
// invalidate all caller save registers at calls
if (op.destroysCallerSavedRegisters()) {
for (Register r : allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters()) {
statePut(debug, inputState, r.asValue(), null);
}
}
op.visitEachAlive(useConsumer);
// set temp operands (some operations use temp operands also as output operands, so
// can't set them null)
op.visitEachTemp(defConsumer);
// set output operands
op.visitEachOutput(defConsumer);
}
}
Aggregations