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.Debug; 31 import org.graalvm.compiler.debug.Debug.Scope; 32 import org.graalvm.compiler.lir.LIR; 33 import org.graalvm.compiler.lir.LIRInstruction; 34 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; 35 import org.graalvm.compiler.lir.LIRInstruction.OperandMode; 36 import org.graalvm.compiler.lir.LIRValueUtil; 37 import org.graalvm.compiler.lir.ValueConsumer; 38 import org.graalvm.compiler.lir.Variable; 39 40 import jdk.vm.ci.meta.Value; 41 42 /** 43 * Stores live in/live out variables and locations for each basic block. 44 * 45 * <em>Live variable information</em> is stored as an integer array containing <em>variable 46 * indices</em>. The information is only stored once per <em>control-flow split</em> or 47 * <em>control-merge</em>. In other words the live sets at the end of the source block and the 48 * beginning of the target block of an edge are the same. 49 */ 50 public final class GlobalLivenessInfo { 51 52 public static final class Builder { 53 private GlobalLivenessInfo info; 54 public final int[] emptySet; 55 56 public Builder(LIR lir) { 57 info = new GlobalLivenessInfo(lir); 58 emptySet = new int[0]; 59 } 60 61 public GlobalLivenessInfo createLivenessInfo() { 62 GlobalLivenessInfo livenessInfo = info; 63 info = null; 64 return livenessInfo; 65 } 66 67 public void setIncoming(AbstractBlockBase<?> block, int[] varsIn) { 68 assert info.blockToVarIn[block.getId()] == null; 69 assert verifyVars(varsIn); 70 assert storesIncoming(block) || info.blockToVarOut[block.getPredecessors()[0].getId()] == varsIn; 71 info.blockToVarIn[block.getId()] = varsIn; 72 } 73 74 public void setOutgoing(AbstractBlockBase<?> block, int[] varsOut) { 75 assert info.blockToVarOut[block.getId()] == null; 76 assert verifyVars(varsOut); 77 assert storesOutgoing(block) || info.blockToVarIn[block.getSuccessors()[0].getId()] == varsOut; 78 info.blockToVarOut[block.getId()] = varsOut; 79 } 80 81 private static boolean verifyVars(int[] vars) { 82 for (int var : vars) { 83 assert var >= 0; 84 } 85 return true; 86 } 87 88 @SuppressWarnings("unused") 89 public void addVariable(LIRInstruction op, Variable var) { 90 info.variables[var.index] = var; 91 } 92 93 } 94 95 private final Variable[] variables; 96 private final int[][] blockToVarIn; 97 private final int[][] blockToVarOut; 98 private final Value[][] blockToLocIn; 99 private final Value[][] blockToLocOut; 100 101 private GlobalLivenessInfo(LIR lir) { 102 int numVariables = lir.numVariables(); 103 variables = new Variable[numVariables]; 104 int numBlocks = lir.getControlFlowGraph().getBlocks().length; 105 blockToVarIn = new int[numBlocks][]; 106 blockToVarOut = new int[numBlocks][]; 107 blockToLocIn = new Value[numBlocks][]; 108 blockToLocOut = new Value[numBlocks][]; 109 } 110 111 public Variable getVariable(int varNum) { 112 return variables[varNum]; 113 } 114 115 public int[] getBlockOut(AbstractBlockBase<?> block) { 116 return blockToVarOut[block.getId()]; 117 } 118 119 public int[] getBlockIn(AbstractBlockBase<?> block) { 120 return blockToVarIn[block.getId()]; 121 } 122 123 public void setInLocations(AbstractBlockBase<?> block, Value[] values) { 124 blockToLocIn[block.getId()] = values; 125 } 126 127 public void setOutLocations(AbstractBlockBase<?> block, Value[] values) { 128 blockToLocOut[block.getId()] = values; 129 } 130 131 public Value[] getInLocation(AbstractBlockBase<?> block) { 132 return blockToLocIn[block.getId()]; 133 } 134 135 public Value[] getOutLocation(AbstractBlockBase<?> block) { 136 return blockToLocOut[block.getId()]; 137 } 138 139 public static boolean storesIncoming(AbstractBlockBase<?> block) { 140 assert block.getPredecessorCount() >= 0; 141 return block.getPredecessorCount() != 1; 142 } 143 144 public static boolean storesOutgoing(AbstractBlockBase<?> block) { 145 assert block.getSuccessorCount() >= 0; 146 /* 147 * The second condition handles non-critical empty blocks, introduced, e.g., by two 148 * consecutive loop-exits. 149 */ 150 return block.getSuccessorCount() != 1 || block.getSuccessors()[0].getPredecessorCount() == 1; 151 } 152 153 /** 154 * Verifies that the local liveness information is correct, i.e., that all variables used in a 155 * block {@code b} are either defined in {@code b} or in the incoming live set. 156 */ 157 @SuppressWarnings("try") 158 public boolean verify(LIR lir) { 159 try (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 }