package org.graalvm.compiler.lir.ssi;
import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.EnumSet;
import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
import org.graalvm.compiler.core.common.cfg.Loop;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.debug.Indent;
import org.graalvm.compiler.lir.InstructionValueConsumer;
import org.graalvm.compiler.lir.LIR;
import org.graalvm.compiler.lir.LIRInstruction;
import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
import jdk.vm.ci.meta.Value;
public final class FastSSIBuilder extends SSIBuilderBase {
private final BitSet[] liveIns;
private final BitSet[] liveOuts;
private final AbstractBlockBase<?>[] blocks;
protected FastSSIBuilder(LIR lir) {
super(lir);
int numBlocks = lir.getControlFlowGraph().getBlocks().length;
this.liveIns = new BitSet[numBlocks];
this.liveOuts = new BitSet[numBlocks];
this.blocks = lir.getControlFlowGraph().getBlocks();
}
@Override
BitSet getLiveIn(final AbstractBlockBase<?> block) {
return liveIns[block.getId()];
}
@Override
BitSet getLiveOut(final AbstractBlockBase<?> block) {
return liveOuts[block.getId()];
}
private void setLiveIn(final AbstractBlockBase<?> block, final BitSet liveIn) {
liveIns[block.getId()] = liveIn;
}
private void setLiveOut(final AbstractBlockBase<?> block, final BitSet liveOut) {
liveOuts[block.getId()] = liveOut;
}
@Override
protected void buildIntern() {
Debug.log(1, "SSIConstruction block order: %s", Arrays.asList(blocks));
computeLiveness();
}
private int liveSetSize() {
return lir.numVariables();
}
private static int operandNumber(Value operand) {
if (isVariable(operand)) {
return asVariable(operand).index;
}
throw GraalError.shouldNotReachHere("Can only handle Variables: " + operand);
}
@SuppressWarnings("try")
private void computeLiveness() {
for (int i = blocks.length - 1; i >= 0; i--) {
final AbstractBlockBase<?> block = blocks[i];
try (Indent indent = Debug.logAndIndent(LOG_LEVEL, "compute local live sets for block %s", block)) {
final BitSet liveIn = mergeLiveSets(block);
setLiveOut(block, (BitSet) liveIn.clone());
InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
@Override
public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
processUse(liveIn, operand);
}
};
InstructionValueConsumer defConsumer = new InstructionValueConsumer() {
@Override
public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
processDef(liveIn, operand, operands);
}
};
if (Debug.isLogEnabled()) {
Debug.log(LOG_LEVEL, "liveOut B%d %s", block.getId(), getLiveOut(block));
}
ArrayList<LIRInstruction> instructions = getLIR().getLIRforBlock(block);
for (int j = instructions.size() - 1; j >= 0; j--) {
final LIRInstruction op = instructions.get(j);
try (Indent indent2 = Debug.logAndIndent(LOG_LEVEL, "handle op %d: %s", op.id(), op)) {
op.visitEachOutput(defConsumer);
op.visitEachTemp(defConsumer);
op.visitEachState(useConsumer);
op.visitEachAlive(useConsumer);
op.visitEachInput(useConsumer);
}
}
setLiveIn(block, liveIn);
if (block.isLoopHeader()) {
handleLoopHeader(block.getLoop(), liveIn);
}
if (Debug.isLogEnabled()) {
Debug.log(LOG_LEVEL, "liveIn B%d %s", block.getId(), getLiveIn(block));
}
}
}
}
private void handleLoopHeader(Loop<?> loop, BitSet live) {
for (AbstractBlockBase<?> block : loop.getBlocks()) {
getLiveIn(block).or(live);
getLiveOut(block).or(live);
}
}
private BitSet mergeLiveSets(final AbstractBlockBase<?> block) {
assert block != null;
final BitSet liveOut = new BitSet(liveSetSize());
for (AbstractBlockBase<?> successor : block.getSuccessors()) {
BitSet succLiveIn = getLiveIn(successor);
if (succLiveIn != null) {
liveOut.or(succLiveIn);
} else {
assert successor.isLoopHeader() : "Successor of " + block + " not yet processed and not loop header: " + successor;
}
}
return liveOut;
}
private static void processUse(final BitSet liveGen, Value operand) {
if (isVariable(operand)) {
int operandNum = operandNumber(operand);
liveGen.set(operandNum);
if (Debug.isLogEnabled()) {
Debug.log(LOG_LEVEL, "liveGen for operand %d(%s)", operandNum, operand);
}
}
}
private static void processDef(final BitSet liveGen, Value operand, Value[] operands) {
if (isVariable(operand)) {
int operandNum = operandNumber(operand);
if (operands[operandNum] == null) {
operands[operandNum] = operand;
}
liveGen.clear(operandNum);
if (Debug.isLogEnabled()) {
Debug.log(LOG_LEVEL, "liveKill for operand %d(%s)", operandNum, operand);
}
}
}
}