Search in sources :

Example 6 with LIRInstruction

use of org.graalvm.compiler.lir.LIRInstruction in project graal by oracle.

the class MoveResolver method resolveMappings.

@SuppressWarnings("try")
private void resolveMappings() {
    DebugContext debug = allocator.getDebug();
    try (Indent indent = debug.logAndIndent("resolveMapping")) {
        assert verifyBeforeResolve();
        if (debug.isLogEnabled()) {
            printMapping();
        }
        // Block all registers that are used as input operands of a move.
        // When a register is blocked, no move to this register is emitted.
        // This is necessary for detecting cycles in moves.
        int i;
        for (i = mappingFrom.size() - 1; i >= 0; i--) {
            Interval fromInterval = mappingFrom.get(i);
            if (fromInterval != null) {
                blockRegisters(fromInterval);
            }
        }
        ArrayList<AllocatableValue> busySpillSlots = null;
        while (mappingFrom.size() > 0) {
            boolean processedInterval = false;
            int spillCandidate = -1;
            for (i = mappingFrom.size() - 1; i >= 0; i--) {
                Interval fromInterval = mappingFrom.get(i);
                Interval toInterval = mappingTo.get(i);
                if (safeToProcessMove(fromInterval, toInterval)) {
                    // this interval can be processed because target is free
                    final LIRInstruction move;
                    if (fromInterval != null) {
                        move = insertMove(fromInterval, toInterval);
                        unblockRegisters(fromInterval);
                    } else {
                        move = insertMove(mappingFromOpr.get(i), toInterval);
                    }
                    move.setComment(res, "MoveResolver resolve mapping");
                    if (LIRValueUtil.isStackSlotValue(toInterval.location())) {
                        if (busySpillSlots == null) {
                            busySpillSlots = new ArrayList<>(2);
                        }
                        busySpillSlots.add(toInterval.location());
                    }
                    mappingFrom.remove(i);
                    mappingFromOpr.remove(i);
                    mappingTo.remove(i);
                    processedInterval = true;
                } else if (fromInterval != null && isRegister(fromInterval.location()) && (busySpillSlots == null || !busySpillSlots.contains(fromInterval.spillSlot()))) {
                    // this interval cannot be processed now because target is not free
                    // it starts in a register, so it is a possible candidate for spilling
                    spillCandidate = i;
                }
            }
            if (!processedInterval) {
                breakCycle(spillCandidate);
            }
        }
    }
    // reset to default value
    multipleReadsAllowed = false;
    // check that all intervals have been processed
    assert checkEmpty();
}
Also used : Indent(org.graalvm.compiler.debug.Indent) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) DebugContext(org.graalvm.compiler.debug.DebugContext) AllocatableValue(jdk.vm.ci.meta.AllocatableValue)

Example 7 with LIRInstruction

use of org.graalvm.compiler.lir.LIRInstruction in project graal by oracle.

the class SSALinearScanLifetimeAnalysisPhase method addRegisterHint.

@Override
protected void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags, final boolean hintAtDef) {
    super.addRegisterHint(op, targetValue, mode, flags, hintAtDef);
    if (hintAtDef && op instanceof LabelOp) {
        LabelOp label = (LabelOp) op;
        Interval to = allocator.getOrCreateInterval((AllocatableValue) targetValue);
        SSAUtil.forEachPhiRegisterHint(allocator.getLIR(), allocator.blockForId(label.id()), label, targetValue, mode, (ValueConsumer) (registerHint, valueMode, valueFlags) -> {
            if (LinearScan.isVariableOrRegister(registerHint)) {
                Interval from = allocator.getOrCreateInterval((AllocatableValue) registerHint);
                setHint(debug, op, to, from);
                setHint(debug, op, from, to);
            }
        });
    }
}
Also used : OperandMode(org.graalvm.compiler.lir.LIRInstruction.OperandMode) Interval(org.graalvm.compiler.lir.alloc.lsra.Interval) ValueConsumer(org.graalvm.compiler.lir.ValueConsumer) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) RegisterPriority(org.graalvm.compiler.lir.alloc.lsra.Interval.RegisterPriority) Value(jdk.vm.ci.meta.Value) OperandFlag(org.graalvm.compiler.lir.LIRInstruction.OperandFlag) DebugContext(org.graalvm.compiler.debug.DebugContext) LinearScan(org.graalvm.compiler.lir.alloc.lsra.LinearScan) LinearScanLifetimeAnalysisPhase(org.graalvm.compiler.lir.alloc.lsra.LinearScanLifetimeAnalysisPhase) SSAUtil(org.graalvm.compiler.lir.ssa.SSAUtil) EnumSet(java.util.EnumSet) AllocatableValue(jdk.vm.ci.meta.AllocatableValue) LabelOp(org.graalvm.compiler.lir.StandardOp.LabelOp) LabelOp(org.graalvm.compiler.lir.StandardOp.LabelOp) AllocatableValue(jdk.vm.ci.meta.AllocatableValue) Interval(org.graalvm.compiler.lir.alloc.lsra.Interval)

Example 8 with LIRInstruction

use of org.graalvm.compiler.lir.LIRInstruction in project graal by oracle.

the class SSALinearScanResolveDataFlowPhase method resolveCollectMappings.

@Override
protected void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, AbstractBlockBase<?> midBlock, MoveResolver moveResolver) {
    super.resolveCollectMappings(fromBlock, toBlock, midBlock, moveResolver);
    if (toBlock.getPredecessorCount() > 1) {
        int toBlockFirstInstructionId = allocator.getFirstLirInstructionId(toBlock);
        int fromBlockLastInstructionId = allocator.getLastLirInstructionId(fromBlock) + 1;
        AbstractBlockBase<?> phiOutBlock = midBlock != null ? midBlock : fromBlock;
        ArrayList<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(phiOutBlock);
        int phiOutIdx = SSAUtil.phiOutIndex(allocator.getLIR(), phiOutBlock);
        int phiOutId = midBlock != null ? fromBlockLastInstructionId : instructions.get(phiOutIdx).id();
        assert phiOutId >= 0;
        PhiValueVisitor visitor = new PhiValueVisitor() {

            @Override
            public void visit(Value phiIn, Value phiOut) {
                assert !isRegister(phiOut) : "phiOut is a register: " + phiOut;
                assert !isRegister(phiIn) : "phiIn is a register: " + phiIn;
                Interval toInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiIn), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF);
                DebugContext debug = allocator.getDebug();
                if (isConstantValue(phiOut)) {
                    numPhiResolutionMoves.increment(debug);
                    moveResolver.addMapping(asConstant(phiOut), toInterval);
                } else {
                    Interval fromInterval = allocator.splitChildAtOpId(allocator.intervalFor(phiOut), phiOutId, LIRInstruction.OperandMode.DEF);
                    if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
                        numPhiResolutionMoves.increment(debug);
                        if (!(isStackSlotValue(toInterval.location()) && isStackSlotValue(fromInterval.location()))) {
                            moveResolver.addMapping(fromInterval, toInterval);
                        } else {
                            numStackToStackMoves.increment(debug);
                            moveResolver.addMapping(fromInterval, toInterval);
                        }
                    }
                }
            }
        };
        SSAUtil.forEachPhiValuePair(allocator.getLIR(), toBlock, phiOutBlock, visitor);
        SSAUtil.removePhiOut(allocator.getLIR(), phiOutBlock);
    }
}
Also used : LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) LIRValueUtil.isStackSlotValue(org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue) LIRValueUtil.isConstantValue(org.graalvm.compiler.lir.LIRValueUtil.isConstantValue) Value(jdk.vm.ci.meta.Value) DebugContext(org.graalvm.compiler.debug.DebugContext) PhiValueVisitor(org.graalvm.compiler.lir.ssa.SSAUtil.PhiValueVisitor) Interval(org.graalvm.compiler.lir.alloc.lsra.Interval)

Example 9 with LIRInstruction

use of org.graalvm.compiler.lir.LIRInstruction in project graal by oracle.

the class LinearScan method verifyNoOopsInFixedIntervals.

@SuppressWarnings("try")
void verifyNoOopsInFixedIntervals() {
    try (Indent indent = debug.logAndIndent("verifying that no oops are in fixed intervals *")) {
        CheckConsumer checkConsumer = new CheckConsumer();
        Interval fixedIntervals;
        Interval otherIntervals;
        fixedIntervals = createUnhandledLists(IS_PRECOLORED_INTERVAL, null).getLeft();
        // to ensure a walking until the last instruction id, add a dummy interval
        // with a high operation id
        otherIntervals = new Interval(Value.ILLEGAL, -1, intervalEndMarker, rangeEndMarker);
        otherIntervals.addRange(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1);
        IntervalWalker iw = new IntervalWalker(this, fixedIntervals, otherIntervals);
        for (AbstractBlockBase<?> block : sortedBlocks) {
            ArrayList<LIRInstruction> instructions = ir.getLIRforBlock(block);
            for (int j = 0; j < instructions.size(); j++) {
                LIRInstruction op = instructions.get(j);
                if (op.hasState()) {
                    iw.walkBefore(op.id());
                    boolean checkLive = true;
                    /*
                         * Make sure none of the fixed registers is live across an oopmap since we
                         * can't handle that correctly.
                         */
                    if (checkLive) {
                        for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); !interval.isEndMarker(); interval = interval.next) {
                            if (interval.currentTo() > op.id() + 1) {
                                /*
                                     * This interval is live out of this op so make sure that this
                                     * interval represents some value that's referenced by this op
                                     * either as an input or output.
                                     */
                                checkConsumer.curInterval = interval;
                                checkConsumer.ok = false;
                                op.visitEachInput(checkConsumer);
                                op.visitEachAlive(checkConsumer);
                                op.visitEachTemp(checkConsumer);
                                op.visitEachOutput(checkConsumer);
                                assert checkConsumer.ok : "fixed intervals should never be live across an oopmap point";
                            }
                        }
                    }
                }
            }
        }
    }
}
Also used : Indent(org.graalvm.compiler.debug.Indent) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction)

Example 10 with LIRInstruction

use of org.graalvm.compiler.lir.LIRInstruction in project graal by oracle.

the class LinearScanOptimizeSpillPositionPhase method optimizeInterval.

@SuppressWarnings("try")
private void optimizeInterval(LIRInsertionBuffer[] insertionBuffers, Interval interval, LIRGenerationResult res) {
    if (interval == null || !interval.isSplitParent() || interval.spillState() != SpillState.SpillInDominator) {
        return;
    }
    AbstractBlockBase<?> defBlock = allocator.blockForId(interval.spillDefinitionPos());
    AbstractBlockBase<?> spillBlock = null;
    Interval firstSpillChild = null;
    try (Indent indent = debug.logAndIndent("interval %s (%s)", interval, defBlock)) {
        for (Interval splitChild : interval.getSplitChildren()) {
            if (isStackSlotValue(splitChild.location())) {
                if (firstSpillChild == null || splitChild.from() < firstSpillChild.from()) {
                    firstSpillChild = splitChild;
                } else {
                    assert firstSpillChild.from() < splitChild.from();
                }
                // iterate all blocks where the interval has use positions
                for (AbstractBlockBase<?> splitBlock : blocksForInterval(splitChild)) {
                    if (dominates(defBlock, splitBlock)) {
                        debug.log("Split interval %s, block %s", splitChild, splitBlock);
                        if (spillBlock == null) {
                            spillBlock = splitBlock;
                        } else {
                            spillBlock = commonDominator(spillBlock, splitBlock);
                            assert spillBlock != null;
                        }
                    }
                }
            }
        }
        if (spillBlock == null) {
            debug.log("not spill interval found");
            // no spill interval
            interval.setSpillState(SpillState.StoreAtDefinition);
            return;
        }
        debug.log(DebugContext.VERBOSE_LEVEL, "Spill block candidate (initial): %s", spillBlock);
        // move out of loops
        if (defBlock.getLoopDepth() < spillBlock.getLoopDepth()) {
            spillBlock = moveSpillOutOfLoop(defBlock, spillBlock);
        }
        debug.log(DebugContext.VERBOSE_LEVEL, "Spill block candidate (after loop optimizaton): %s", spillBlock);
        /*
             * The spill block is the begin of the first split child (aka the value is on the
             * stack).
             *
             * The problem is that if spill block has more than one predecessor, the values at the
             * end of the predecessors might differ. Therefore, we would need a spill move in all
             * predecessors. To avoid this we spill in the dominator.
             */
        assert firstSpillChild != null;
        if (!defBlock.equals(spillBlock) && spillBlock.equals(allocator.blockForId(firstSpillChild.from()))) {
            AbstractBlockBase<?> dom = spillBlock.getDominator();
            if (debug.isLogEnabled()) {
                debug.log("Spill block (%s) is the beginning of a spill child -> use dominator (%s)", spillBlock, dom);
            }
            spillBlock = dom;
        }
        if (defBlock.equals(spillBlock)) {
            debug.log(DebugContext.VERBOSE_LEVEL, "Definition is the best choice: %s", defBlock);
            // definition is the best choice
            interval.setSpillState(SpillState.StoreAtDefinition);
            return;
        }
        assert dominates(defBlock, spillBlock);
        betterSpillPos.increment(debug);
        if (debug.isLogEnabled()) {
            debug.log("Better spill position found (Block %s)", spillBlock);
        }
        if (defBlock.probability() <= spillBlock.probability()) {
            debug.log(DebugContext.VERBOSE_LEVEL, "Definition has lower probability %s (%f) is lower than spill block %s (%f)", defBlock, defBlock.probability(), spillBlock, spillBlock.probability());
            // better spill block has the same probability -> do nothing
            interval.setSpillState(SpillState.StoreAtDefinition);
            return;
        }
        LIRInsertionBuffer insertionBuffer = insertionBuffers[spillBlock.getId()];
        if (insertionBuffer == null) {
            insertionBuffer = new LIRInsertionBuffer();
            insertionBuffers[spillBlock.getId()] = insertionBuffer;
            insertionBuffer.init(allocator.getLIR().getLIRforBlock(spillBlock));
        }
        int spillOpId = allocator.getFirstLirInstructionId(spillBlock);
        // insert spill move
        AllocatableValue fromLocation = interval.getSplitChildAtOpId(spillOpId, OperandMode.DEF, allocator).location();
        AllocatableValue toLocation = LinearScan.canonicalSpillOpr(interval);
        LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation);
        move.setComment(res, "LSRAOptimizeSpillPos: optimize spill pos");
        debug.log(DebugContext.VERBOSE_LEVEL, "Insert spill move %s", move);
        move.setId(LinearScan.DOMINATOR_SPILL_MOVE_ID);
        /*
             * We can use the insertion buffer directly because we always insert at position 1.
             */
        insertionBuffer.append(1, move);
        betterSpillPosWithLowerProbability.increment(debug);
        interval.setSpillDefinitionPos(spillOpId);
    }
}
Also used : Indent(org.graalvm.compiler.debug.Indent) LIRInsertionBuffer(org.graalvm.compiler.lir.LIRInsertionBuffer) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) AllocatableValue(jdk.vm.ci.meta.AllocatableValue)

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