1 /* 2 * Copyright (c) 2009, 2018, 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 24 25 package org.graalvm.compiler.lir.alloc.lsra; 26 27 import static jdk.vm.ci.code.ValueUtil.asRegister; 28 import static jdk.vm.ci.code.ValueUtil.isRegister; 29 30 import java.util.ArrayList; 31 import java.util.EnumSet; 32 33 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; 34 import org.graalvm.compiler.core.common.cfg.BlockMap; 35 import org.graalvm.compiler.debug.DebugContext; 36 import org.graalvm.compiler.debug.GraalError; 37 import org.graalvm.compiler.debug.Indent; 38 import org.graalvm.compiler.lir.InstructionValueConsumer; 39 import org.graalvm.compiler.lir.LIRInstruction; 40 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; 41 import org.graalvm.compiler.lir.LIRInstruction.OperandMode; 42 43 import jdk.vm.ci.code.Register; 44 import jdk.vm.ci.meta.Value; 45 46 /** 47 */ 48 final class RegisterVerifier { 49 50 LinearScan allocator; 51 ArrayList<AbstractBlockBase<?>> workList; // all blocks that must be processed 52 BlockMap<Interval[]> savedStates; // saved information of previous check 53 54 // simplified access to methods of LinearScan intervalAt(Value operand)55 Interval intervalAt(Value operand) { 56 return allocator.intervalFor(operand); 57 } 58 59 // currently, only registers are processed stateSize()60 int stateSize() { 61 return allocator.maxRegisterNumber() + 1; 62 } 63 64 // accessors stateForBlock(AbstractBlockBase<?> block)65 Interval[] stateForBlock(AbstractBlockBase<?> block) { 66 return savedStates.get(block); 67 } 68 setStateForBlock(AbstractBlockBase<?> block, Interval[] savedState)69 void setStateForBlock(AbstractBlockBase<?> block, Interval[] savedState) { 70 savedStates.put(block, savedState); 71 } 72 addToWorkList(AbstractBlockBase<?> block)73 void addToWorkList(AbstractBlockBase<?> block) { 74 if (!workList.contains(block)) { 75 workList.add(block); 76 } 77 } 78 RegisterVerifier(LinearScan allocator)79 RegisterVerifier(LinearScan allocator) { 80 this.allocator = allocator; 81 workList = new ArrayList<>(16); 82 this.savedStates = new BlockMap<>(allocator.getLIR().getControlFlowGraph()); 83 84 } 85 86 @SuppressWarnings("try") verify(AbstractBlockBase<?> start)87 void verify(AbstractBlockBase<?> start) { 88 DebugContext debug = allocator.getDebug(); 89 try (DebugContext.Scope s = debug.scope("RegisterVerifier")) { 90 // setup input registers (method arguments) for first block 91 Interval[] inputState = new Interval[stateSize()]; 92 setStateForBlock(start, inputState); 93 addToWorkList(start); 94 95 // main loop for verification 96 do { 97 AbstractBlockBase<?> block = workList.get(0); 98 workList.remove(0); 99 100 processBlock(block); 101 } while (!workList.isEmpty()); 102 } 103 } 104 105 @SuppressWarnings("try") processBlock(AbstractBlockBase<?> block)106 private void processBlock(AbstractBlockBase<?> block) { 107 DebugContext debug = allocator.getDebug(); 108 try (Indent indent = debug.logAndIndent("processBlock B%d", block.getId())) { 109 // must copy state because it is modified 110 Interval[] inputState = copy(stateForBlock(block)); 111 112 try (Indent indent2 = debug.logAndIndent("Input-State of intervals:")) { 113 printState(inputState); 114 } 115 116 // process all operations of the block 117 processOperations(block, inputState); 118 119 try (Indent indent2 = debug.logAndIndent("Output-State of intervals:")) { 120 printState(inputState); 121 } 122 123 // iterate all successors 124 for (AbstractBlockBase<?> succ : block.getSuccessors()) { 125 processSuccessor(succ, inputState); 126 } 127 } 128 } 129 printState(Interval[] inputState)130 protected void printState(Interval[] inputState) { 131 DebugContext debug = allocator.getDebug(); 132 for (int i = 0; i < stateSize(); i++) { 133 Register reg = allocator.getRegisters().get(i); 134 assert reg.number == i; 135 if (inputState[i] != null) { 136 debug.log(" %6s %4d -- %s", reg, inputState[i].operandNumber, inputState[i]); 137 } else { 138 debug.log(" %6s __", reg); 139 } 140 } 141 } 142 processSuccessor(AbstractBlockBase<?> block, Interval[] inputState)143 private void processSuccessor(AbstractBlockBase<?> block, Interval[] inputState) { 144 DebugContext debug = allocator.getDebug(); 145 Interval[] savedState = stateForBlock(block); 146 147 if (savedState != null) { 148 // this block was already processed before. 149 // check if new inputState is consistent with savedState 150 151 boolean savedStateCorrect = true; 152 for (int i = 0; i < stateSize(); i++) { 153 if (inputState[i] != savedState[i]) { 154 // current inputState and previous savedState assume a different 155 // interval in this register . assume that this register is invalid 156 if (savedState[i] != null) { 157 // invalidate old calculation only if it assumed that 158 // register was valid. when the register was already invalid, 159 // then the old calculation was correct. 160 savedStateCorrect = false; 161 savedState[i] = null; 162 163 debug.log("processSuccessor B%d: invalidating slot %d", block.getId(), i); 164 } 165 } 166 } 167 168 if (savedStateCorrect) { 169 // already processed block with correct inputState 170 debug.log("processSuccessor B%d: previous visit already correct", block.getId()); 171 } else { 172 // must re-visit this block 173 debug.log("processSuccessor B%d: must re-visit because input state changed", block.getId()); 174 addToWorkList(block); 175 } 176 177 } else { 178 // block was not processed before, so set initial inputState 179 debug.log("processSuccessor B%d: initial visit", block.getId()); 180 181 setStateForBlock(block, copy(inputState)); 182 addToWorkList(block); 183 } 184 } 185 copy(Interval[] inputState)186 static Interval[] copy(Interval[] inputState) { 187 return inputState.clone(); 188 } 189 statePut(DebugContext debug, Interval[] inputState, Value location, Interval interval)190 static void statePut(DebugContext debug, Interval[] inputState, Value location, Interval interval) { 191 if (location != null && isRegister(location)) { 192 Register reg = asRegister(location); 193 int regNum = reg.number; 194 if (interval != null) { 195 debug.log("%s = %s", reg, interval.operand); 196 } else if (inputState[regNum] != null) { 197 debug.log("%s = null", reg); 198 } 199 200 inputState[regNum] = interval; 201 } 202 } 203 checkState(AbstractBlockBase<?> block, LIRInstruction op, Interval[] inputState, Value operand, Value reg, Interval interval)204 static boolean checkState(AbstractBlockBase<?> block, LIRInstruction op, Interval[] inputState, Value operand, Value reg, Interval interval) { 205 if (reg != null && isRegister(reg)) { 206 if (inputState[asRegister(reg).number] != interval) { 207 throw new GraalError( 208 "Error in register allocation: operation (%s) in block %s expected register %s (operand %s) to contain the value of interval %s but data-flow says it contains interval %s", 209 op, block, reg, operand, interval, inputState[asRegister(reg).number]); 210 } 211 } 212 return true; 213 } 214 processOperations(AbstractBlockBase<?> block, final Interval[] inputState)215 void processOperations(AbstractBlockBase<?> block, final Interval[] inputState) { 216 ArrayList<LIRInstruction> ops = allocator.getLIR().getLIRforBlock(block); 217 DebugContext debug = allocator.getDebug(); 218 InstructionValueConsumer useConsumer = new InstructionValueConsumer() { 219 220 @Override 221 public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) { 222 // we skip spill moves inserted by the spill position optimization 223 if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand) && op.id() != LinearScan.DOMINATOR_SPILL_MOVE_ID) { 224 Interval interval = intervalAt(operand); 225 if (op.id() != -1) { 226 interval = interval.getSplitChildAtOpId(op.id(), mode, allocator); 227 } 228 229 assert checkState(block, op, inputState, interval.operand, interval.location(), interval.splitParent()); 230 } 231 } 232 }; 233 234 InstructionValueConsumer defConsumer = (op, operand, mode, flags) -> { 235 if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) { 236 Interval interval = intervalAt(operand); 237 if (op.id() != -1) { 238 interval = interval.getSplitChildAtOpId(op.id(), mode, allocator); 239 } 240 241 statePut(debug, inputState, interval.location(), interval.splitParent()); 242 } 243 }; 244 245 // visit all instructions of the block 246 for (int i = 0; i < ops.size(); i++) { 247 final LIRInstruction op = ops.get(i); 248 249 if (debug.isLogEnabled()) { 250 debug.log("%s", op.toStringWithIdPrefix()); 251 } 252 253 // check if input operands are correct 254 op.visitEachInput(useConsumer); 255 // invalidate all caller save registers at calls 256 if (op.destroysCallerSavedRegisters()) { 257 for (Register r : allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters()) { 258 statePut(debug, inputState, r.asValue(), null); 259 } 260 } 261 op.visitEachAlive(useConsumer); 262 // set temp operands (some operations use temp operands also as output operands, so 263 // can't set them null) 264 op.visitEachTemp(defConsumer); 265 // set output operands 266 op.visitEachOutput(defConsumer); 267 } 268 } 269 } 270