Search in sources :

Example 36 with LIRInstruction

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));
    }
}
Also used : LIRInstruction(org.graalvm.compiler.lir.LIRInstruction)

Example 37 with LIRInstruction

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();
}
Also used : LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) ConstantValue(org.graalvm.compiler.lir.ConstantValue)

Example 38 with LIRInstruction

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";
    }
}
Also used : Indent(org.graalvm.compiler.debug.Indent) LIRInsertionBuffer(org.graalvm.compiler.lir.LIRInsertionBuffer) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) LoadConstantOp(org.graalvm.compiler.lir.StandardOp.LoadConstantOp) MoveOp(org.graalvm.compiler.lir.StandardOp.MoveOp) ValueMoveOp(org.graalvm.compiler.lir.StandardOp.ValueMoveOp) DebugContext(org.graalvm.compiler.debug.DebugContext) ValueMoveOp(org.graalvm.compiler.lir.StandardOp.ValueMoveOp) AllocatableValue(jdk.vm.ci.meta.AllocatableValue)

Example 39 with LIRInstruction

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);
}
Also used : AbstractBlockBase(org.graalvm.compiler.core.common.cfg.AbstractBlockBase) PermanentBailoutException(org.graalvm.compiler.core.common.PermanentBailoutException) Constant(jdk.vm.ci.meta.Constant) LoadConstantOp(org.graalvm.compiler.lir.StandardOp.LoadConstantOp) BitMap2D(org.graalvm.compiler.core.common.util.BitMap2D) LIRValueUtil.asVariable(org.graalvm.compiler.lir.LIRValueUtil.asVariable) EconomicSet(org.graalvm.collections.EconomicSet) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) LIRGenerationResult(org.graalvm.compiler.lir.gen.LIRGenerationResult) Register(jdk.vm.ci.code.Register) Assertions(org.graalvm.compiler.debug.Assertions) ValueUtil.asStackSlot(jdk.vm.ci.code.ValueUtil.asStackSlot) ArrayList(java.util.ArrayList) InstructionValueConsumer(org.graalvm.compiler.lir.InstructionValueConsumer) SpillState(org.graalvm.compiler.lir.alloc.lsra.Interval.SpillState) OperandFlag(org.graalvm.compiler.lir.LIRInstruction.OperandFlag) DebugContext(org.graalvm.compiler.debug.DebugContext) RegisterArray(jdk.vm.ci.code.RegisterArray) ValueUtil.isRegister(jdk.vm.ci.code.ValueUtil.isRegister) ValueUtil.asRegister(jdk.vm.ci.code.ValueUtil.asRegister) ComputeBlockOrder(org.graalvm.compiler.core.common.alloc.ComputeBlockOrder) BlockData(org.graalvm.compiler.lir.alloc.lsra.LinearScan.BlockData) LIRGenerationDebugContext.getSourceForOperandFromDebugContext(org.graalvm.compiler.lir.debug.LIRGenerationDebugContext.getSourceForOperandFromDebugContext) Equivalence(org.graalvm.collections.Equivalence) EnumSet(java.util.EnumSet) ValueUtil.isStackSlot(jdk.vm.ci.code.ValueUtil.isStackSlot) OperandMode(org.graalvm.compiler.lir.LIRInstruction.OperandMode) ValueConsumer(org.graalvm.compiler.lir.ValueConsumer) LIRValueUtil.isVariable(org.graalvm.compiler.lir.LIRValueUtil.isVariable) LIRKind(org.graalvm.compiler.core.common.LIRKind) AllocationContext(org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext) TargetDescription(jdk.vm.ci.code.TargetDescription) JavaConstant(jdk.vm.ci.meta.JavaConstant) RegisterPriority(org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterPriority) Value(jdk.vm.ci.meta.Value) ValueMoveOp(org.graalvm.compiler.lir.StandardOp.ValueMoveOp) Indent(org.graalvm.compiler.debug.Indent) GraalError(org.graalvm.compiler.debug.GraalError) StackSlot(jdk.vm.ci.code.StackSlot) BitSet(java.util.BitSet) ArrayDeque(java.util.ArrayDeque) ValueKind(jdk.vm.ci.meta.ValueKind) AllocatableValue(jdk.vm.ci.meta.AllocatableValue) InstructionValueConsumer(org.graalvm.compiler.lir.InstructionValueConsumer) ValueConsumer(org.graalvm.compiler.lir.ValueConsumer) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction)

Example 40 with LIRInstruction

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);
            }
        }
    }
}
Also used : AbstractBlockBase(org.graalvm.compiler.core.common.cfg.AbstractBlockBase) PermanentBailoutException(org.graalvm.compiler.core.common.PermanentBailoutException) Constant(jdk.vm.ci.meta.Constant) LoadConstantOp(org.graalvm.compiler.lir.StandardOp.LoadConstantOp) BitMap2D(org.graalvm.compiler.core.common.util.BitMap2D) LIRValueUtil.asVariable(org.graalvm.compiler.lir.LIRValueUtil.asVariable) EconomicSet(org.graalvm.collections.EconomicSet) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) LIRGenerationResult(org.graalvm.compiler.lir.gen.LIRGenerationResult) Register(jdk.vm.ci.code.Register) Assertions(org.graalvm.compiler.debug.Assertions) ValueUtil.asStackSlot(jdk.vm.ci.code.ValueUtil.asStackSlot) ArrayList(java.util.ArrayList) InstructionValueConsumer(org.graalvm.compiler.lir.InstructionValueConsumer) SpillState(org.graalvm.compiler.lir.alloc.lsra.Interval.SpillState) OperandFlag(org.graalvm.compiler.lir.LIRInstruction.OperandFlag) DebugContext(org.graalvm.compiler.debug.DebugContext) RegisterArray(jdk.vm.ci.code.RegisterArray) ValueUtil.isRegister(jdk.vm.ci.code.ValueUtil.isRegister) ValueUtil.asRegister(jdk.vm.ci.code.ValueUtil.asRegister) ComputeBlockOrder(org.graalvm.compiler.core.common.alloc.ComputeBlockOrder) BlockData(org.graalvm.compiler.lir.alloc.lsra.LinearScan.BlockData) LIRGenerationDebugContext.getSourceForOperandFromDebugContext(org.graalvm.compiler.lir.debug.LIRGenerationDebugContext.getSourceForOperandFromDebugContext) Equivalence(org.graalvm.collections.Equivalence) EnumSet(java.util.EnumSet) ValueUtil.isStackSlot(jdk.vm.ci.code.ValueUtil.isStackSlot) OperandMode(org.graalvm.compiler.lir.LIRInstruction.OperandMode) ValueConsumer(org.graalvm.compiler.lir.ValueConsumer) LIRValueUtil.isVariable(org.graalvm.compiler.lir.LIRValueUtil.isVariable) LIRKind(org.graalvm.compiler.core.common.LIRKind) AllocationContext(org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext) TargetDescription(jdk.vm.ci.code.TargetDescription) JavaConstant(jdk.vm.ci.meta.JavaConstant) RegisterPriority(org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterPriority) Value(jdk.vm.ci.meta.Value) ValueMoveOp(org.graalvm.compiler.lir.StandardOp.ValueMoveOp) Indent(org.graalvm.compiler.debug.Indent) GraalError(org.graalvm.compiler.debug.GraalError) StackSlot(jdk.vm.ci.code.StackSlot) BitSet(java.util.BitSet) ArrayDeque(java.util.ArrayDeque) ValueKind(jdk.vm.ci.meta.ValueKind) AllocatableValue(jdk.vm.ci.meta.AllocatableValue) RegisterPriority(org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterPriority) Indent(org.graalvm.compiler.debug.Indent) InstructionValueConsumer(org.graalvm.compiler.lir.InstructionValueConsumer) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) BitSet(java.util.BitSet) RegisterArray(jdk.vm.ci.code.RegisterArray) AllocatableValue(jdk.vm.ci.meta.AllocatableValue) Register(jdk.vm.ci.code.Register) ValueUtil.isRegister(jdk.vm.ci.code.ValueUtil.isRegister) ValueUtil.asRegister(jdk.vm.ci.code.ValueUtil.asRegister)

Aggregations

LIRInstruction (org.graalvm.compiler.lir.LIRInstruction)55 DebugContext (org.graalvm.compiler.debug.DebugContext)25 Indent (org.graalvm.compiler.debug.Indent)19 AllocatableValue (jdk.vm.ci.meta.AllocatableValue)15 Value (jdk.vm.ci.meta.Value)15 OperandMode (org.graalvm.compiler.lir.LIRInstruction.OperandMode)10 EnumSet (java.util.EnumSet)8 Register (jdk.vm.ci.code.Register)8 AbstractBlockBase (org.graalvm.compiler.core.common.cfg.AbstractBlockBase)8 OperandFlag (org.graalvm.compiler.lir.LIRInstruction.OperandFlag)7 BitSet (java.util.BitSet)6 GraalError (org.graalvm.compiler.debug.GraalError)6 InstructionValueConsumer (org.graalvm.compiler.lir.InstructionValueConsumer)6 LIR (org.graalvm.compiler.lir.LIR)6 LIRInsertionBuffer (org.graalvm.compiler.lir.LIRInsertionBuffer)6 ValueConsumer (org.graalvm.compiler.lir.ValueConsumer)6 ArrayList (java.util.ArrayList)5 ValueUtil.asRegister (jdk.vm.ci.code.ValueUtil.asRegister)5 ValueUtil.isRegister (jdk.vm.ci.code.ValueUtil.isRegister)5 LoadConstantOp (org.graalvm.compiler.lir.StandardOp.LoadConstantOp)5