1 /*
   2  * Copyright (c) 2017, 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 java.util.Arrays;
  26 import java.util.BitSet;
  27 import java.util.EnumSet;
  28 
  29 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  30 import org.graalvm.compiler.debug.DebugContext;
  31 import org.graalvm.compiler.lir.LIR;
  32 import org.graalvm.compiler.lir.LIRInstruction;
  33 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
  34 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
  35 import org.graalvm.compiler.lir.LIRValueUtil;
  36 import org.graalvm.compiler.lir.ValueConsumer;
  37 import org.graalvm.compiler.lir.Variable;
  38 
  39 import jdk.vm.ci.meta.Value;
  40 
  41 /**
  42  * Stores live in/live out variables and locations for each basic block.
  43  *
  44  * <em>Live variable information</em> is stored as an integer array containing <em>variable
  45  * indices</em>. The information is only stored once per <em>control-flow split</em> or
  46  * <em>control-merge</em>. In other words the live sets at the end of the source block and the
  47  * beginning of the target block of an edge are the same.
  48  */
  49 public final class GlobalLivenessInfo {
  50 
  51     public static final class Builder {
  52         private GlobalLivenessInfo info;
  53         public final int[] emptySet;
  54 
  55         public Builder(LIR lir) {
  56             info = new GlobalLivenessInfo(lir);
  57             emptySet = new int[0];
  58         }
  59 
  60         public GlobalLivenessInfo createLivenessInfo() {
  61             GlobalLivenessInfo livenessInfo = info;
  62             info = null;
  63             return livenessInfo;
  64         }
  65 
  66         public void setIncoming(AbstractBlockBase<?> block, int[] varsIn) {
  67             assert info.blockToVarIn[block.getId()] == null;
  68             assert verifyVars(varsIn);
  69             assert storesIncoming(block) || info.blockToVarOut[block.getPredecessors()[0].getId()] == varsIn;
  70             info.blockToVarIn[block.getId()] = varsIn;
  71         }
  72 
  73         public void setOutgoing(AbstractBlockBase<?> block, int[] varsOut) {
  74             assert info.blockToVarOut[block.getId()] == null;
  75             assert verifyVars(varsOut);
  76             assert storesOutgoing(block) || info.blockToVarIn[block.getSuccessors()[0].getId()] == varsOut;
  77             info.blockToVarOut[block.getId()] = varsOut;
  78         }
  79 
  80         private static boolean verifyVars(int[] vars) {
  81             for (int var : vars) {
  82                 assert var >= 0;
  83             }
  84             return true;
  85         }
  86 
  87         @SuppressWarnings("unused")
  88         public void addVariable(LIRInstruction op, Variable var) {
  89             info.variables[var.index] = var;
  90         }
  91 
  92     }
  93 
  94     private final Variable[] variables;
  95     private final int[][] blockToVarIn;
  96     private final int[][] blockToVarOut;
  97     private final Value[][] blockToLocIn;
  98     private final Value[][] blockToLocOut;
  99 
 100     private GlobalLivenessInfo(LIR lir) {
 101         int numVariables = lir.numVariables();
 102         variables = new Variable[numVariables];
 103         int numBlocks = lir.getControlFlowGraph().getBlocks().length;
 104         blockToVarIn = new int[numBlocks][];
 105         blockToVarOut = new int[numBlocks][];
 106         blockToLocIn = new Value[numBlocks][];
 107         blockToLocOut = new Value[numBlocks][];
 108     }
 109 
 110     public Variable getVariable(int varNum) {
 111         return variables[varNum];
 112     }
 113 
 114     public int[] getBlockOut(AbstractBlockBase<?> block) {
 115         return blockToVarOut[block.getId()];
 116     }
 117 
 118     public int[] getBlockIn(AbstractBlockBase<?> block) {
 119         return blockToVarIn[block.getId()];
 120     }
 121 
 122     public void setInLocations(AbstractBlockBase<?> block, Value[] values) {
 123         blockToLocIn[block.getId()] = values;
 124     }
 125 
 126     public void setOutLocations(AbstractBlockBase<?> block, Value[] values) {
 127         blockToLocOut[block.getId()] = values;
 128     }
 129 
 130     public Value[] getInLocation(AbstractBlockBase<?> block) {
 131         return blockToLocIn[block.getId()];
 132     }
 133 
 134     public Value[] getOutLocation(AbstractBlockBase<?> block) {
 135         return blockToLocOut[block.getId()];
 136     }
 137 
 138     public static boolean storesIncoming(AbstractBlockBase<?> block) {
 139         assert block.getPredecessorCount() >= 0;
 140         return block.getPredecessorCount() != 1;
 141     }
 142 
 143     public static boolean storesOutgoing(AbstractBlockBase<?> block) {
 144         assert block.getSuccessorCount() >= 0;
 145         /*
 146          * The second condition handles non-critical empty blocks, introduced, e.g., by two
 147          * consecutive loop-exits.
 148          */
 149         return block.getSuccessorCount() != 1 || block.getSuccessors()[0].getPredecessorCount() == 1;
 150     }
 151 
 152     /**
 153      * Verifies that the local liveness information is correct, i.e., that all variables used in a
 154      * block {@code b} are either defined in {@code b} or in the incoming live set.
 155      */
 156     @SuppressWarnings("try")
 157     public boolean verify(LIR lir) {
 158         DebugContext debug = lir.getDebug();
 159         try (DebugContext.Scope s = debug.scope("Verify GlobalLivenessInfo", this)) {
 160             for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
 161                 assert verifyBlock(block, lir);
 162             }
 163         } catch (Throwable e) {
 164             throw debug.handle(e);
 165         }
 166         return true;
 167     }
 168 
 169     private boolean verifyBlock(AbstractBlockBase<?> block, LIR lir) {
 170         BitSet liveSet = new BitSet(lir.numVariables());
 171         int[] liveIn = getBlockIn(block);
 172         for (int varNum : liveIn) {
 173             liveSet.set(varNum);
 174         }
 175         ValueConsumer proc = new ValueConsumer() {
 176 
 177             @Override
 178             public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
 179                 if (LIRValueUtil.isVariable(value)) {
 180                     Variable var = LIRValueUtil.asVariable(value);
 181                     if (mode == OperandMode.DEF) {
 182                         liveSet.set(var.index);
 183                     } else {
 184                         assert liveSet.get(var.index) : String.format("Variable %s but not defined in block %s (liveIn: %s)", var, block, Arrays.toString(liveIn));
 185                     }
 186                 }
 187             }
 188 
 189         };
 190         for (LIRInstruction op : lir.getLIRforBlock(block)) {
 191             op.visitEachInput(proc);
 192             op.visitEachAlive(proc);
 193             op.visitEachState(proc);
 194             op.visitEachOutput(proc);
 195             // no need for checking temp
 196         }
 197         return true;
 198     }
 199 }