use of org.graalvm.compiler.lir.LIRInstruction in project graal by oracle.
the class LinearScanAssignLocationsPhase method assignLocations.
private void assignLocations(ArrayList<LIRInstruction> instructions) {
int numInst = instructions.size();
boolean hasDead = false;
for (int j = 0; j < numInst; j++) {
final LIRInstruction op = instructions.get(j);
if (op == null) {
/*
* this can happen when spill-moves are removed in eliminateSpillMoves
*/
hasDead = true;
} else if (assignLocations(op)) {
instructions.set(j, null);
hasDead = true;
}
}
if (hasDead) {
// Remove null values from the list.
instructions.removeAll(Collections.singleton(null));
}
}
use of org.graalvm.compiler.lir.LIRInstruction in project graal by oracle.
the class LinearScanAssignLocationsPhase method colorLirOperand.
/**
* Assigns the allocated location for an LIR instruction operand back into the instruction.
*
* @param op current {@link LIRInstruction}
* @param operand an LIR instruction operand
* @param mode the usage mode for {@code operand} by the instruction
* @return the location assigned for the operand
*/
protected Value colorLirOperand(LIRInstruction op, Variable operand, OperandMode mode) {
int opId = op.id();
Interval interval = allocator.intervalFor(operand);
assert interval != null : "interval must exist";
if (opId != -1) {
if (allocator.detailedAsserts) {
AbstractBlockBase<?> block = allocator.blockForId(opId);
if (block.getSuccessorCount() <= 1 && opId == allocator.getLastLirInstructionId(block)) {
/*
* Check if spill moves could have been appended at the end of this block, but
* before the branch instruction. So the split child information for this branch
* would be incorrect.
*/
LIRInstruction instr = allocator.getLIR().getLIRforBlock(block).get(allocator.getLIR().getLIRforBlock(block).size() - 1);
if (instr instanceof StandardOp.JumpOp) {
if (allocator.getBlockData(block).liveOut.get(allocator.operandNumber(operand))) {
assert false : String.format("can't get split child for the last branch of a block because the information would be incorrect (moves are inserted before the branch in resolveDataFlow) block=%s, instruction=%s, operand=%s", block, instr, operand);
}
}
}
}
/*
* Operands are not changed when an interval is split during allocation, so search the
* right interval here.
*/
interval = allocator.splitChildAtOpId(interval, opId, mode);
}
if (isIllegal(interval.location()) && interval.canMaterialize()) {
assert mode != OperandMode.DEF;
return new ConstantValue(interval.kind(), interval.getMaterializedValue());
}
return interval.location();
}
use of org.graalvm.compiler.lir.LIRInstruction in project graal by oracle.
the class LinearScanEliminateSpillMovePhase method eliminateSpillMoves.
// called once before assignment of register numbers
@SuppressWarnings("try")
void eliminateSpillMoves(LIRGenerationResult res) {
DebugContext debug = allocator.getDebug();
try (Indent indent = debug.logAndIndent("Eliminating unnecessary spill moves")) {
/*
* collect all intervals that must be stored after their definition. The list is sorted
* by Interval.spillDefinitionPos.
*/
Interval interval;
interval = allocator.createUnhandledLists(mustStoreAtDefinition, null).getLeft();
if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) {
checkIntervals(debug, interval);
}
LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer();
for (AbstractBlockBase<?> block : allocator.sortedBlocks()) {
try (Indent indent1 = debug.logAndIndent("Handle %s", block)) {
ArrayList<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
int numInst = instructions.size();
// iterate all instructions of the block.
for (int j = firstInstructionOfInterest(); j < numInst; j++) {
LIRInstruction op = instructions.get(j);
int opId = op.id();
if (opId == -1) {
MoveOp move = MoveOp.asMoveOp(op);
/*
* Remove move from register to stack if the stack slot is guaranteed to
* be correct. Only moves that have been inserted by LinearScan can be
* removed.
*/
if (Options.LIROptLSRAEliminateSpillMoves.getValue(allocator.getOptions()) && canEliminateSpillMove(block, move)) {
/*
* Move target is a stack slot that is always correct, so eliminate
* instruction.
*/
if (debug.isLogEnabled()) {
if (ValueMoveOp.isValueMoveOp(op)) {
ValueMoveOp vmove = ValueMoveOp.asValueMoveOp(op);
debug.log("eliminating move from interval %d (%s) to %d (%s) in block %s", allocator.operandNumber(vmove.getInput()), vmove.getInput(), allocator.operandNumber(vmove.getResult()), vmove.getResult(), block);
} else {
LoadConstantOp load = LoadConstantOp.asLoadConstantOp(op);
debug.log("eliminating constant load from %s to %d (%s) in block %s", load.getConstant(), allocator.operandNumber(load.getResult()), load.getResult(), block);
}
}
// null-instructions are deleted by assignRegNum
instructions.set(j, null);
}
} else {
/*
* Insert move from register to stack just after the beginning of the
* interval.
*/
assert interval.isEndMarker() || interval.spillDefinitionPos() >= opId : "invalid order";
assert interval.isEndMarker() || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval";
while (!interval.isEndMarker() && interval.spillDefinitionPos() == opId) {
if (!interval.canMaterialize()) {
if (!insertionBuffer.initialized()) {
/*
* prepare insertion buffer (appended when all instructions
* in the block are processed)
*/
insertionBuffer.init(instructions);
}
AllocatableValue fromLocation = interval.location();
AllocatableValue toLocation = LinearScan.canonicalSpillOpr(interval);
if (!fromLocation.equals(toLocation)) {
assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState();
assert isStackSlotValue(toLocation) : "to operand must be a stack slot";
LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation);
insertionBuffer.append(j + 1, move);
move.setComment(res, "LSRAEliminateSpillMove: store at definition");
if (debug.isLogEnabled()) {
debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);
}
}
}
interval = interval.next;
}
}
}
if (insertionBuffer.initialized()) {
insertionBuffer.finish();
}
}
}
assert interval.isEndMarker() : "missed an interval";
}
}
use of org.graalvm.compiler.lir.LIRInstruction 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.lir.LIRInstruction 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);
}
}
}
}
Aggregations