1 /*
   2  * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.lir.alloc.trace;
  24 
  25 import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
  26 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
  27 
  28 import java.util.ArrayList;
  29 import java.util.BitSet;
  30 import java.util.EnumSet;
  31 
  32 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  33 import org.graalvm.compiler.core.common.cfg.Loop;
  34 import org.graalvm.compiler.debug.Debug;
  35 import org.graalvm.compiler.debug.GraalError;
  36 import org.graalvm.compiler.debug.Indent;
  37 import org.graalvm.compiler.lir.InstructionValueConsumer;
  38 import org.graalvm.compiler.lir.LIR;
  39 import org.graalvm.compiler.lir.LIRInstruction;
  40 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
  41 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
  42 import org.graalvm.compiler.lir.Variable;
  43 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  44 import org.graalvm.compiler.lir.phases.AllocationPhase;
  45 import org.graalvm.compiler.lir.ssa.SSAUtil;
  46 
  47 import jdk.vm.ci.code.TargetDescription;
  48 import jdk.vm.ci.meta.Value;
  49 
  50 /**
  51  * Constructs {@link GlobalLivenessInfo global liveness information}.
  52  */
  53 public final class GlobalLivenessAnalysisPhase extends AllocationPhase {
  54 
  55     @Override
  56     protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
  57         assert SSAUtil.verifySSAForm(lirGenRes.getLIR());
  58         Analyser ssiBuilder = new Analyser(lirGenRes.getLIR());
  59         ssiBuilder.build();
  60         ssiBuilder.finish();
  61         GlobalLivenessInfo livenessInfo = ssiBuilder.getLivenessInfo();
  62         assert livenessInfo.verify(lirGenRes.getLIR());
  63         context.contextAdd(livenessInfo);
  64     }
  65 
  66     private final class Analyser {
  67 
  68         private static final int LOG_LEVEL = Debug.INFO_LEVEL;
  69 
  70         /**
  71          * Bit map specifying which operands are live upon entry to this block. These are values
  72          * used in this block or any of its successors where such value are not defined in this
  73          * block. The bit index of an operand is its {@linkplain #operandNumber operand number}.
  74          */
  75         private final BitSet[] liveIns;
  76 
  77         /**
  78          * Bit map specifying which operands are live upon exit from this block. These are values
  79          * used in a successor block that are either defined in this block or were live upon entry
  80          * to this block. The bit index of an operand is its {@linkplain #operandNumber operand
  81          * number}.
  82          */
  83         private final BitSet[] liveOuts;
  84 
  85         private final AbstractBlockBase<?>[] blocks;
  86 
  87         private final Value[] operands;
  88 
  89         private final LIR lir;
  90 
  91         private final GlobalLivenessInfo.Builder livenessInfoBuilder;
  92 
  93         Analyser(LIR lir) {
  94             int numBlocks = lir.getControlFlowGraph().getBlocks().length;
  95             this.liveIns = new BitSet[numBlocks];
  96             this.liveOuts = new BitSet[numBlocks];
  97             this.blocks = lir.getControlFlowGraph().getBlocks();
  98             this.lir = lir;
  99             this.operands = new Value[lir.numVariables()];
 100             this.livenessInfoBuilder = new GlobalLivenessInfo.Builder(lir);
 101         }
 102 
 103         private BitSet getLiveIn(final AbstractBlockBase<?> block) {
 104             return liveIns[block.getId()];
 105         }
 106 
 107         private BitSet getLiveOut(final AbstractBlockBase<?> block) {
 108             return liveOuts[block.getId()];
 109         }
 110 
 111         private void setLiveIn(final AbstractBlockBase<?> block, final BitSet liveIn) {
 112             liveIns[block.getId()] = liveIn;
 113         }
 114 
 115         private void setLiveOut(final AbstractBlockBase<?> block, final BitSet liveOut) {
 116             liveOuts[block.getId()] = liveOut;
 117         }
 118 
 119         private void buildIntern() {
 120             computeLiveness();
 121         }
 122 
 123         /**
 124          * Gets the size of the {@link #liveIns} and {@link #liveOuts} sets for a basic block.
 125          */
 126         private int liveSetSize() {
 127             return lir.numVariables();
 128         }
 129 
 130         private int operandNumber(Value operand) {
 131             if (isVariable(operand)) {
 132                 return asVariable(operand).index;
 133             }
 134             throw GraalError.shouldNotReachHere("Can only handle Variables: " + operand);
 135         }
 136 
 137         /**
 138          * Computes live sets for each block.
 139          */
 140         @SuppressWarnings("try")
 141         private void computeLiveness() {
 142             // iterate all blocks
 143             for (int i = blocks.length - 1; i >= 0; i--) {
 144                 final AbstractBlockBase<?> block = blocks[i];
 145                 try (Indent indent = Debug.logAndIndent(LOG_LEVEL, "compute local live sets for block %s", block)) {
 146 
 147                     final BitSet liveIn = mergeLiveSets(block);
 148                     setLiveOut(block, (BitSet) liveIn.clone());
 149 
 150                     InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
 151                         @Override
 152                         public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
 153                             processUse(liveIn, operand);
 154                         }
 155                     };
 156                     InstructionValueConsumer defConsumer = new InstructionValueConsumer() {
 157                         @Override
 158                         public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
 159                             processDef(liveIn, op, operand);
 160                         }
 161                     };
 162                     if (Debug.isLogEnabled()) {
 163                         Debug.log(LOG_LEVEL, "liveOut B%d %s", block.getId(), getLiveOut(block));
 164                     }
 165 
 166                     // iterate all instructions of the block
 167                     ArrayList<LIRInstruction> instructions = getLIR().getLIRforBlock(block);
 168                     for (int j = instructions.size() - 1; j >= 0; j--) {
 169                         final LIRInstruction op = instructions.get(j);
 170 
 171                         try (Indent indent2 = Debug.logAndIndent(LOG_LEVEL, "handle op %d: %s", op.id(), op)) {
 172                             op.visitEachOutput(defConsumer);
 173                             op.visitEachTemp(defConsumer);
 174                             op.visitEachState(useConsumer);
 175                             op.visitEachAlive(useConsumer);
 176                             op.visitEachInput(useConsumer);
 177                         }
 178                     } // end of instruction iteration
 179 
 180                     setLiveIn(block, liveIn);
 181                     if (block.isLoopHeader()) {
 182                         handleLoopHeader(block.getLoop(), liveIn);
 183                     }
 184 
 185                     if (Debug.isLogEnabled()) {
 186                         Debug.log(LOG_LEVEL, "liveIn  B%d %s", block.getId(), getLiveIn(block));
 187                     }
 188 
 189                 }
 190             } // end of block iteration
 191         }
 192 
 193         /**
 194          * All variables live at the beginning of a loop are live throughout the loop.
 195          */
 196         private void handleLoopHeader(Loop<?> loop, BitSet live) {
 197             for (AbstractBlockBase<?> block : loop.getBlocks()) {
 198                 getLiveIn(block).or(live);
 199                 getLiveOut(block).or(live);
 200             }
 201         }
 202 
 203         private BitSet mergeLiveSets(final AbstractBlockBase<?> block) {
 204             assert block != null;
 205             final BitSet liveOut = new BitSet(liveSetSize());
 206             for (AbstractBlockBase<?> successor : block.getSuccessors()) {
 207                 BitSet succLiveIn = getLiveIn(successor);
 208                 if (succLiveIn != null) {
 209                     liveOut.or(succLiveIn);
 210                 } else {
 211                     assert successor.isLoopHeader() : "Successor of " + block + " not yet processed and not loop header: " + successor;
 212                 }
 213             }
 214             return liveOut;
 215         }
 216 
 217         private void processUse(final BitSet liveGen, Value operand) {
 218             if (isVariable(operand)) {
 219                 int operandNum = operandNumber(operand);
 220                 liveGen.set(operandNum);
 221                 if (Debug.isLogEnabled()) {
 222                     Debug.log(LOG_LEVEL, "liveGen for operand %d(%s)", operandNum, operand);
 223                 }
 224             }
 225         }
 226 
 227         private void processDef(final BitSet liveGen, LIRInstruction op, Value operand) {
 228             if (isVariable(operand)) {
 229                 recordVariable(op, asVariable(operand));
 230                 int operandNum = operandNumber(operand);
 231                 if (operands[operandNum] == null) {
 232                     operands[operandNum] = operand;
 233                 }
 234                 liveGen.clear(operandNum);
 235                 if (Debug.isLogEnabled()) {
 236                     Debug.log(LOG_LEVEL, "liveKill for operand %d(%s)", operandNum, operand);
 237                 }
 238             }
 239         }
 240 
 241         private LIR getLIR() {
 242             return lir;
 243         }
 244 
 245         public void build() {
 246             buildIntern();
 247             // check that the liveIn set of the first block is empty
 248             AbstractBlockBase<?> startBlock = getLIR().getControlFlowGraph().getStartBlock();
 249             if (getLiveIn(startBlock).cardinality() != 0) {
 250                 // bailout if this occurs in product mode.
 251                 throw new GraalError("liveIn set of first block must be empty: " + getLiveIn(startBlock));
 252             }
 253         }
 254 
 255         @SuppressWarnings("try")
 256         public void finish() {
 257             // iterate all blocks in reverse order
 258             for (AbstractBlockBase<?> block : (AbstractBlockBase<?>[]) lir.getControlFlowGraph().getBlocks()) {
 259                 try (Indent indent = Debug.logAndIndent(LOG_LEVEL, "Finish Block %s", block)) {
 260                     buildIncoming(block);
 261                     buildOutgoing(block);
 262                 }
 263             }
 264         }
 265 
 266         public GlobalLivenessInfo getLivenessInfo() {
 267             assert livenessInfoBuilder != null : "No liveness info collected";
 268             return livenessInfoBuilder.createLivenessInfo();
 269         }
 270 
 271         private void buildIncoming(AbstractBlockBase<?> block) {
 272             if (!GlobalLivenessInfo.storesIncoming(block)) {
 273                 assert block.getPredecessorCount() == 1;
 274                 assert GlobalLivenessInfo.storesOutgoing(block.getPredecessors()[0]) : "No incoming liveness info: " + block;
 275                 return;
 276             }
 277 
 278             final int[] liveInArray;
 279             if (block.getPredecessorCount() == 0) {
 280                 // start block
 281                 assert getLiveIn(block).isEmpty() : "liveIn for start block is not empty? " + getLiveIn(block);
 282                 liveInArray = livenessInfoBuilder.emptySet;
 283             } else {
 284                 /*
 285                  * Collect live out of predecessors since there might be values not used in this
 286                  * block which might cause out/in mismatch. Per construction the live sets of all
 287                  * predecessors are equal.
 288                  */
 289                 BitSet predLiveOut = getLiveOut(block.getPredecessors()[0]);
 290                 liveInArray = predLiveOut.isEmpty() ? livenessInfoBuilder.emptySet : bitSetToIntArray(predLiveOut);
 291             }
 292 
 293             livenessInfoBuilder.setIncoming(block, liveInArray);
 294             // reuse the same array for outgoing variables in predecessors
 295             for (AbstractBlockBase<?> pred : block.getPredecessors()) {
 296                 livenessInfoBuilder.setOutgoing(pred, liveInArray);
 297             }
 298         }
 299 
 300         private void buildOutgoing(AbstractBlockBase<?> block) {
 301             BitSet liveOut = getLiveOut(block);
 302             if (!GlobalLivenessInfo.storesOutgoing(block)) {
 303                 assert GlobalLivenessInfo.storesOutgoing(block) || block.getSuccessorCount() == 1;
 304                 assert GlobalLivenessInfo.storesOutgoing(block) || GlobalLivenessInfo.storesIncoming(block.getSuccessors()[0]) : "No outgoing liveness info: " + block;
 305                 return;
 306             }
 307             int[] liveOutArray = liveOut.isEmpty() ? livenessInfoBuilder.emptySet : bitSetToIntArray(liveOut);
 308 
 309             livenessInfoBuilder.setOutgoing(block, liveOutArray);
 310             // reuse the same array for incoming variables in successors
 311             for (AbstractBlockBase<?> succ : block.getSuccessors()) {
 312                 livenessInfoBuilder.setIncoming(succ, liveOutArray);
 313             }
 314         }
 315 
 316         private int[] bitSetToIntArray(BitSet live) {
 317             int[] vars = new int[live.cardinality()];
 318             int cnt = 0;
 319             for (int i = live.nextSetBit(0); i >= 0; i = live.nextSetBit(i + 1), cnt++) {
 320                 vars[cnt] = i;
 321             }
 322             return vars;
 323         }
 324 
 325         private void recordVariable(LIRInstruction op, Variable var) {
 326             livenessInfoBuilder.addVariable(op, var);
 327         }
 328     }
 329 
 330 }