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);
}
}
}
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);
}
}
Aggregations