Search in sources :

Example 41 with LIRInstruction

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);
    }
}
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) Indent(org.graalvm.compiler.debug.Indent) InstructionValueConsumer(org.graalvm.compiler.lir.InstructionValueConsumer) ValueConsumer(org.graalvm.compiler.lir.ValueConsumer) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) BitSet(java.util.BitSet) BitMap2D(org.graalvm.compiler.core.common.util.BitMap2D) BlockData(org.graalvm.compiler.lir.alloc.lsra.LinearScan.BlockData) PermanentBailoutException(org.graalvm.compiler.core.common.PermanentBailoutException)

Example 42 with LIRInstruction

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);
    }
}
Also used : Indent(org.graalvm.compiler.debug.Indent) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) BitSet(java.util.BitSet) DebugContext(org.graalvm.compiler.debug.DebugContext) LIRGenerationDebugContext.getSourceForOperandFromDebugContext(org.graalvm.compiler.lir.debug.LIRGenerationDebugContext.getSourceForOperandFromDebugContext) ArrayDeque(java.util.ArrayDeque) AbstractBlockBase(org.graalvm.compiler.core.common.cfg.AbstractBlockBase) Value(jdk.vm.ci.meta.Value) AllocatableValue(jdk.vm.ci.meta.AllocatableValue)

Example 43 with LIRInstruction

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

Example 44 with LIRInstruction

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

Example 45 with LIRInstruction

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);
    }
}
Also used : AbstractBlockBase(org.graalvm.compiler.core.common.cfg.AbstractBlockBase) OperandMode(org.graalvm.compiler.lir.LIRInstruction.OperandMode) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) Register(jdk.vm.ci.code.Register) ArrayList(java.util.ArrayList) BlockMap(org.graalvm.compiler.core.common.cfg.BlockMap) InstructionValueConsumer(org.graalvm.compiler.lir.InstructionValueConsumer) Value(jdk.vm.ci.meta.Value) OperandFlag(org.graalvm.compiler.lir.LIRInstruction.OperandFlag) DebugContext(org.graalvm.compiler.debug.DebugContext) ValueUtil.isRegister(jdk.vm.ci.code.ValueUtil.isRegister) Indent(org.graalvm.compiler.debug.Indent) GraalError(org.graalvm.compiler.debug.GraalError) ValueUtil.asRegister(jdk.vm.ci.code.ValueUtil.asRegister) EnumSet(java.util.EnumSet) InstructionValueConsumer(org.graalvm.compiler.lir.InstructionValueConsumer) Register(jdk.vm.ci.code.Register) ValueUtil.isRegister(jdk.vm.ci.code.ValueUtil.isRegister) ValueUtil.asRegister(jdk.vm.ci.code.ValueUtil.asRegister) LIRInstruction(org.graalvm.compiler.lir.LIRInstruction) EnumSet(java.util.EnumSet) Value(jdk.vm.ci.meta.Value) DebugContext(org.graalvm.compiler.debug.DebugContext) OperandMode(org.graalvm.compiler.lir.LIRInstruction.OperandMode)

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