Search in sources :

Example 1 with BlockData

use of org.graalvm.compiler.lir.alloc.lsra.LinearScan.BlockData in project graal by oracle.

the class LinearScanLifetimeAnalysisPhase method computeGlobalLiveSets.

/**
 * Performs a backward dataflow analysis to compute global live sets (i.e.
 * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block.
 */
@SuppressWarnings("try")
protected void computeGlobalLiveSets() {
    try (Indent indent = debug.logAndIndent("compute global live sets")) {
        int numBlocks = allocator.blockCount();
        boolean changeOccurred;
        boolean changeOccurredInBlock;
        int iterationCount = 0;
        // scratch set for calculations
        BitSet liveOut = new BitSet(allocator.liveSetSize());
        /*
             * Perform a backward dataflow analysis to compute liveOut and liveIn for each block.
             * The loop is executed until a fixpoint is reached (no changes in an iteration).
             */
        do {
            changeOccurred = false;
            try (Indent indent2 = debug.logAndIndent("new iteration %d", iterationCount)) {
                // iterate all blocks in reverse order
                for (int i = numBlocks - 1; i >= 0; i--) {
                    AbstractBlockBase<?> block = allocator.blockAt(i);
                    BlockData blockSets = allocator.getBlockData(block);
                    changeOccurredInBlock = false;
                    /*
                         * liveOut(block) is the union of liveIn(sux), for successors sux of block.
                         */
                    int n = block.getSuccessorCount();
                    if (n > 0) {
                        liveOut.clear();
                        // block has successors
                        if (n > 0) {
                            for (AbstractBlockBase<?> successor : block.getSuccessors()) {
                                liveOut.or(allocator.getBlockData(successor).liveIn);
                            }
                        }
                        if (!blockSets.liveOut.equals(liveOut)) {
                            /*
                                 * A change occurred. Swap the old and new live out sets to avoid
                                 * copying.
                                 */
                            BitSet temp = blockSets.liveOut;
                            blockSets.liveOut = liveOut;
                            liveOut = temp;
                            changeOccurred = true;
                            changeOccurredInBlock = true;
                        }
                    }
                    if (iterationCount == 0 || changeOccurredInBlock) {
                        /*
                             * liveIn(block) is the union of liveGen(block) with (liveOut(block) &
                             * !liveKill(block)).
                             *
                             * Note: liveIn has to be computed only in first iteration or if liveOut
                             * has changed!
                             */
                        BitSet liveIn = blockSets.liveIn;
                        liveIn.clear();
                        liveIn.or(blockSets.liveOut);
                        liveIn.andNot(blockSets.liveKill);
                        liveIn.or(blockSets.liveGen);
                        if (debug.isLogEnabled()) {
                            debug.log("block %d: livein = %s,  liveout = %s", block.getId(), liveIn, blockSets.liveOut);
                        }
                    }
                }
                iterationCount++;
                if (changeOccurred && iterationCount > 50) {
                    /*
                         * Very unlikely, should never happen: If it happens we cannot guarantee it
                         * won't happen again.
                         */
                    throw new PermanentBailoutException("too many iterations in computeGlobalLiveSets");
                }
            }
        } while (changeOccurred);
        if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) {
            verifyLiveness();
        }
        // check that the liveIn set of the first block is empty
        AbstractBlockBase<?> startBlock = allocator.getLIR().getControlFlowGraph().getStartBlock();
        if (allocator.getBlockData(startBlock).liveIn.cardinality() != 0) {
            if (Assertions.detailedAssertionsEnabled(allocator.getOptions())) {
                reportFailure(numBlocks);
            }
            // bailout if this occurs in product mode.
            throw new GraalError("liveIn set of first block must be empty: " + allocator.getBlockData(startBlock).liveIn);
        }
    }
}
Also used : Indent(org.graalvm.compiler.debug.Indent) GraalError(org.graalvm.compiler.debug.GraalError) BitSet(java.util.BitSet) BlockData(org.graalvm.compiler.lir.alloc.lsra.LinearScan.BlockData) PermanentBailoutException(org.graalvm.compiler.core.common.PermanentBailoutException)

Example 2 with BlockData

use of org.graalvm.compiler.lir.alloc.lsra.LinearScan.BlockData 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)

Aggregations

BitSet (java.util.BitSet)2 PermanentBailoutException (org.graalvm.compiler.core.common.PermanentBailoutException)2 GraalError (org.graalvm.compiler.debug.GraalError)2 Indent (org.graalvm.compiler.debug.Indent)2 BlockData (org.graalvm.compiler.lir.alloc.lsra.LinearScan.BlockData)2 ArrayDeque (java.util.ArrayDeque)1 ArrayList (java.util.ArrayList)1 EnumSet (java.util.EnumSet)1 Register (jdk.vm.ci.code.Register)1 RegisterArray (jdk.vm.ci.code.RegisterArray)1 StackSlot (jdk.vm.ci.code.StackSlot)1 TargetDescription (jdk.vm.ci.code.TargetDescription)1 ValueUtil.asRegister (jdk.vm.ci.code.ValueUtil.asRegister)1 ValueUtil.asStackSlot (jdk.vm.ci.code.ValueUtil.asStackSlot)1 ValueUtil.isRegister (jdk.vm.ci.code.ValueUtil.isRegister)1 ValueUtil.isStackSlot (jdk.vm.ci.code.ValueUtil.isStackSlot)1 AllocatableValue (jdk.vm.ci.meta.AllocatableValue)1 Constant (jdk.vm.ci.meta.Constant)1 JavaConstant (jdk.vm.ci.meta.JavaConstant)1 Value (jdk.vm.ci.meta.Value)1