--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssi/FastSSIBuilder.java 2016-12-09 00:54:31.904651227 -0800 @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +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 { + + /** + * Bit map specifying which operands are live upon entry to this block. These are values used in + * this block or any of its successors where such value are not defined in this block. The bit + * index of an operand is its {@linkplain #operandNumber operand number}. + */ + private final BitSet[] liveIns; + + /** + * Bit map specifying which operands are live upon exit from this block. These are values used + * in a successor block that are either defined in this block or were live upon entry to this + * block. The bit index of an operand is its {@linkplain #operandNumber operand number}. + */ + 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(); + } + + /** + * Gets the size of the {@link #liveIns} and {@link #liveOuts} sets for a basic block. + */ + 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); + } + + /** + * Computes live sets for each block. + */ + @SuppressWarnings("try") + private void computeLiveness() { + // iterate all blocks + 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 flags) { + processUse(liveIn, operand); + } + }; + InstructionValueConsumer defConsumer = new InstructionValueConsumer() { + @Override + public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet flags) { + processDef(liveIn, operand, operands); + } + }; + if (Debug.isLogEnabled()) { + Debug.log(LOG_LEVEL, "liveOut B%d %s", block.getId(), getLiveOut(block)); + } + + // iterate all instructions of the block + ArrayList 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); + } + } // end of instruction iteration + + 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)); + } + + } + } // end of block iteration + } + + /** + * All variables live at the beginning of a loop are live throughout the loop. + */ + 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); + } + } + } +}