Search in sources :

Example 66 with AllocatableValue

use of jdk.vm.ci.meta.AllocatableValue 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)

Example 67 with AllocatableValue

use of jdk.vm.ci.meta.AllocatableValue in project graal by oracle.

the class MoveResolver method breakCycle.

protected void breakCycle(int spillCandidate) {
    // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory
    assert spillCandidate != -1 : "no interval in register for spilling found";
    // create a new spill interval and assign a stack slot to it
    Interval fromInterval = mappingFrom.get(spillCandidate);
    // do not allocate a new spill slot for temporary interval, but
    // use spill slot assigned to fromInterval. Otherwise moves from
    // one stack slot to another can happen (not allowed by LIRAssembler
    AllocatableValue spillSlot = fromInterval.spillSlot();
    if (spillSlot == null) {
        spillSlot = getAllocator().getFrameMapBuilder().allocateSpillSlot(fromInterval.kind());
        fromInterval.setSpillSlot(spillSlot);
        cycleBreakingSlotsAllocated.increment(allocator.getDebug());
    }
    spillInterval(spillCandidate, fromInterval, spillSlot);
}
Also used : AllocatableValue(jdk.vm.ci.meta.AllocatableValue)

Example 68 with AllocatableValue

use of jdk.vm.ci.meta.AllocatableValue 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;
}
Also used : LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) DebugContext(org.graalvm.compiler.debug.DebugContext) AllocatableValue(jdk.vm.ci.meta.AllocatableValue)

Example 69 with AllocatableValue

use of jdk.vm.ci.meta.AllocatableValue in project graal by oracle.

the class OptimizingLinearScanWalker method optimize.

@SuppressWarnings("try")
private boolean optimize(int currentPos, AbstractBlockBase<?> currentBlock, Interval currentInterval, RegisterBinding binding) {
    // BEGIN initialize and sanity checks
    assert currentBlock != null : "block must not be null";
    assert currentInterval != null : "interval must not be null";
    assert currentBlock.getPredecessorCount() == 1 : "more than one predecessors -> optimization not possible";
    if (!currentInterval.isSplitChild()) {
        // interval is not a split child -> no need for optimization
        return false;
    }
    if (currentInterval.from() == currentPos) {
        // the interval starts at the current position so no need for splitting
        return false;
    }
    // get current location
    AllocatableValue currentLocation = currentInterval.location();
    assert currentLocation != null : "active intervals must have a location assigned!";
    // get predecessor stuff
    AbstractBlockBase<?> predecessorBlock = currentBlock.getPredecessors()[0];
    int predEndId = allocator.getLastLirInstructionId(predecessorBlock);
    Interval predecessorInterval = currentInterval.getIntervalCoveringOpId(predEndId);
    assert predecessorInterval != null : "variable not live at the end of the only predecessor! " + predecessorBlock + " -> " + currentBlock + " interval: " + currentInterval;
    AllocatableValue predecessorLocation = predecessorInterval.location();
    assert predecessorLocation != null : "handled intervals must have a location assigned!";
    if (currentLocation.equals(predecessorLocation)) {
        // locations are already equal -> nothing to optimize
        return false;
    }
    if (!isStackSlotValue(predecessorLocation) && !isRegister(predecessorLocation)) {
        assert predecessorInterval.canMaterialize();
        // value is materialized -> no need for optimization
        return false;
    }
    assert isStackSlotValue(currentLocation) || isRegister(currentLocation) : "current location not a register or stack slot " + currentLocation;
    DebugContext debug = allocator.getDebug();
    try (Indent indent = debug.logAndIndent("location differs: %s vs. %s", predecessorLocation, currentLocation)) {
        // split current interval at current position
        debug.log("splitting at position %d", currentPos);
        assert allocator.isBlockBegin(currentPos) && ((currentPos & 1) == 0) : "split pos must be even when on block boundary";
        Interval splitPart = currentInterval.split(currentPos, allocator);
        activeLists.remove(binding, currentInterval);
        assert splitPart.from() >= currentPosition : "cannot append new interval before current walk position";
        // the currentSplitChild is needed later when moves are inserted for reloading
        assert splitPart.currentSplitChild() == currentInterval : "overwriting wrong currentSplitChild";
        splitPart.makeCurrentSplitChild();
        if (debug.isLogEnabled()) {
            debug.log("left interval  : %s", currentInterval.logString(allocator));
            debug.log("right interval : %s", splitPart.logString(allocator));
        }
        if (Options.LSRAOptSplitOnly.getValue(allocator.getOptions())) {
            // just add the split interval to the unhandled list
            unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart);
        } else {
            if (isRegister(predecessorLocation)) {
                splitRegisterInterval(splitPart, asRegister(predecessorLocation));
            } else {
                assert isStackSlotValue(predecessorLocation);
                debug.log("assigning interval %s to %s", splitPart, predecessorLocation);
                splitPart.assignLocation(predecessorLocation);
                // activate interval
                activeLists.addToListSortedByCurrentFromPositions(RegisterBinding.Stack, splitPart);
                splitPart.state = State.Active;
                splitStackInterval(splitPart);
            }
        }
    }
    return true;
}
Also used : Indent(org.graalvm.compiler.debug.Indent) DebugContext(org.graalvm.compiler.debug.DebugContext) AllocatableValue(jdk.vm.ci.meta.AllocatableValue)

Example 70 with AllocatableValue

use of jdk.vm.ci.meta.AllocatableValue in project graal by oracle.

the class TraceGlobalMoveResolver method breakCycle.

@SuppressWarnings("try")
private void breakCycle(int spillCandidate) {
    // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory
    assert spillCandidate != -1 : "no interval in register for spilling found";
    // create a new spill interval and assign a stack slot to it
    Value from = mappingFrom.get(spillCandidate);
    try (Indent indent = debug.logAndIndent("BreakCycle: %s", from)) {
        AllocatableValue spillSlot = null;
        if (TraceRegisterAllocationPhase.Options.TraceRAreuseStackSlotsForMoveResolutionCycleBreaking.getValue(options) && !isStackSlotValue(from)) {
            // don't use the stack slot if from is already the stack slot
            Value fromStack = mappingFromStack.get(spillCandidate);
            if (fromStack != null) {
                spillSlot = (AllocatableValue) fromStack;
                cycleBreakingSlotsReused.increment(debug);
                debug.log("reuse slot for spilling: %s", spillSlot);
            }
        }
        if (spillSlot == null) {
            spillSlot = frameMapBuilder.allocateSpillSlot(from.getValueKind());
            cycleBreakingSlotsAllocated.increment(debug);
            debug.log("created new slot for spilling: %s", spillSlot);
            // insert a move from register to stack and update the mapping
            LIRInstruction move = insertMove(from, spillSlot);
            move.setComment(res, "TraceGlobalMoveResolver: breakCycle");
        }
        block(spillSlot);
        mappingFrom.set(spillCandidate, spillSlot);
        unblock(from);
    }
}
Also used : Indent(org.graalvm.compiler.debug.Indent) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) LIRValueUtil.isStackSlotValue(org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue) TraceUtil.isShadowedRegisterValue(org.graalvm.compiler.lir.alloc.trace.TraceUtil.isShadowedRegisterValue) TraceUtil.asShadowedRegisterValue(org.graalvm.compiler.lir.alloc.trace.TraceUtil.asShadowedRegisterValue) ValueUtil.asAllocatableValue(jdk.vm.ci.code.ValueUtil.asAllocatableValue) Value(jdk.vm.ci.meta.Value) AllocatableValue(jdk.vm.ci.meta.AllocatableValue) ValueUtil.asAllocatableValue(jdk.vm.ci.code.ValueUtil.asAllocatableValue) AllocatableValue(jdk.vm.ci.meta.AllocatableValue)

Aggregations

AllocatableValue (jdk.vm.ci.meta.AllocatableValue)87 Value (jdk.vm.ci.meta.Value)22 Variable (org.graalvm.compiler.lir.Variable)20 LIRKind (org.graalvm.compiler.core.common.LIRKind)13 LIRInstruction (org.graalvm.compiler.lir.LIRInstruction)11 Indent (org.graalvm.compiler.debug.Indent)10 RegisterValue (jdk.vm.ci.code.RegisterValue)9 ValueUtil.asAllocatableValue (jdk.vm.ci.code.ValueUtil.asAllocatableValue)8 DebugContext (org.graalvm.compiler.debug.DebugContext)8 Register (jdk.vm.ci.code.Register)6 JavaConstant (jdk.vm.ci.meta.JavaConstant)6 AMD64MathIntrinsicUnaryOp (org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp)5 LIRValueUtil.asJavaConstant (org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant)4 LIRValueUtil.isJavaConstant (org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant)4 ValueMoveOp (org.graalvm.compiler.lir.StandardOp.ValueMoveOp)4 ArithmeticLIRGenerator (org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator)4 LIRGenerator (org.graalvm.compiler.lir.gen.LIRGenerator)4 SPARCAddressValue (org.graalvm.compiler.lir.sparc.SPARCAddressValue)4 AMD64Kind (jdk.vm.ci.amd64.AMD64Kind)3 ValueUtil.isAllocatableValue (jdk.vm.ci.code.ValueUtil.isAllocatableValue)3