1 /*
   2  * Copyright (c) 2009, 2015, 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;
  24 
  25 import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
  26 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
  27 import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
  28 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
  29 import static jdk.vm.ci.code.ValueUtil.asRegister;
  30 import static jdk.vm.ci.code.ValueUtil.isIllegal;
  31 import static jdk.vm.ci.code.ValueUtil.isRegister;
  32 
  33 import java.util.Arrays;
  34 import java.util.BitSet;
  35 import java.util.EnumSet;
  36 
  37 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  38 import org.graalvm.compiler.debug.GraalError;
  39 import org.graalvm.compiler.debug.TTY;
  40 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
  41 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
  42 import org.graalvm.compiler.lir.framemap.FrameMap;
  43 import org.graalvm.compiler.lir.ssa.SSAUtil;
  44 
  45 import jdk.vm.ci.code.Register;
  46 import jdk.vm.ci.meta.Value;
  47 
  48 public final class LIRVerifier {
  49 
  50     private final LIR lir;
  51     private final FrameMap frameMap;
  52 
  53     private final boolean beforeRegisterAllocation;
  54 
  55     private final BitSet[] blockLiveOut;
  56     private final Object[] variableDefinitions;
  57 
  58     private BitSet liveOutFor(AbstractBlockBase<?> block) {
  59         return blockLiveOut[block.getId()];
  60     }
  61 
  62     private void setLiveOutFor(AbstractBlockBase<?> block, BitSet liveOut) {
  63         blockLiveOut[block.getId()] = liveOut;
  64     }
  65 
  66     private int maxRegisterNum() {
  67         return frameMap.getTarget().arch.getRegisters().size();
  68     }
  69 
  70     private boolean isAllocatableRegister(Value value) {
  71         return isRegister(value) && frameMap.getRegisterConfig().getAttributesMap()[asRegister(value).number].isAllocatable();
  72     }
  73 
  74     public static boolean verify(final LIRInstruction op) {
  75 
  76         op.visitEachInput(LIRVerifier::allowed);
  77         op.visitEachAlive(LIRVerifier::allowed);
  78         op.visitEachState(LIRVerifier::allowed);
  79         op.visitEachTemp(LIRVerifier::allowed);
  80         op.visitEachOutput(LIRVerifier::allowed);
  81 
  82         op.verify();
  83         return true;
  84     }
  85 
  86     public static boolean verify(boolean beforeRegisterAllocation, LIR lir, FrameMap frameMap) {
  87         LIRVerifier verifier = new LIRVerifier(beforeRegisterAllocation, lir, frameMap);
  88         verifier.verify();
  89         return true;
  90     }
  91 
  92     private LIRVerifier(boolean beforeRegisterAllocation, LIR lir, FrameMap frameMap) {
  93         this.beforeRegisterAllocation = beforeRegisterAllocation;
  94         this.lir = lir;
  95         this.frameMap = frameMap;
  96         this.blockLiveOut = new BitSet[lir.linearScanOrder().length];
  97         this.variableDefinitions = new Object[lir.numVariables()];
  98     }
  99 
 100     private BitSet curVariablesLive;
 101     private Value[] curRegistersLive;
 102 
 103     private AbstractBlockBase<?> curBlock;
 104     private Object curInstruction;
 105     private BitSet curRegistersDefined;
 106 
 107     private void verify() {
 108         ValueConsumer useConsumer = new ValueConsumer() {
 109 
 110             @Override
 111             public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
 112                 use(value, mode, flags);
 113             }
 114         };
 115         ValueConsumer defConsumer = new ValueConsumer() {
 116 
 117             @Override
 118             public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
 119                 def(value, mode, flags);
 120             }
 121         };
 122 
 123         int maxRegisterNum = maxRegisterNum();
 124         curRegistersDefined = new BitSet();
 125         for (AbstractBlockBase<?> block : lir.linearScanOrder()) {
 126             curBlock = block;
 127             curVariablesLive = new BitSet();
 128             curRegistersLive = new Value[maxRegisterNum];
 129 
 130             if (block.getDominator() != null) {
 131                 curVariablesLive.or(liveOutFor(block.getDominator()));
 132             }
 133 
 134             assert lir.getLIRforBlock(block).get(0) instanceof StandardOp.LabelOp : "block must start with label";
 135 
 136             if (block.getSuccessorCount() > 0) {
 137                 LIRInstruction last = lir.getLIRforBlock(block).get(lir.getLIRforBlock(block).size() - 1);
 138                 assert last instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump";
 139             }
 140             if (block.getPredecessorCount() > 1) {
 141                 SSAUtil.verifyPhi(lir, block);
 142             }
 143 
 144             for (LIRInstruction op : lir.getLIRforBlock(block)) {
 145                 curInstruction = op;
 146 
 147                 op.visitEachInput(useConsumer);
 148                 if (op.destroysCallerSavedRegisters()) {
 149                     for (Register register : frameMap.getRegisterConfig().getCallerSaveRegisters()) {
 150                         curRegistersLive[register.number] = null;
 151                     }
 152                 }
 153                 curRegistersDefined.clear();
 154                 op.visitEachAlive(useConsumer);
 155                 op.visitEachState(useConsumer);
 156                 op.visitEachTemp(defConsumer);
 157                 op.visitEachOutput(defConsumer);
 158 
 159                 curInstruction = null;
 160             }
 161 
 162             setLiveOutFor(block, curVariablesLive);
 163         }
 164     }
 165 
 166     private void use(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
 167         allowed(curInstruction, value, mode, flags);
 168 
 169         if (isVariable(value)) {
 170             assert beforeRegisterAllocation;
 171 
 172             int variableIdx = asVariable(value).index;
 173             if (!curVariablesLive.get(variableIdx)) {
 174                 TTY.println("block %s  instruction %s", curBlock, curInstruction);
 175                 TTY.println("live variables: %s", curVariablesLive);
 176                 if (variableDefinitions[variableIdx] != null) {
 177                     TTY.println("definition of %s: %s", value, variableDefinitions[variableIdx]);
 178                 }
 179                 TTY.println("ERROR: Use of variable %s that is not defined in dominator", value);
 180                 throw GraalError.shouldNotReachHere();
 181             }
 182 
 183         } else if (isAllocatableRegister(value)) {
 184             int regNum = asRegister(value).number;
 185             if (mode == OperandMode.ALIVE) {
 186                 curRegistersDefined.set(regNum);
 187             }
 188 
 189             if (beforeRegisterAllocation && !curRegistersLive[regNum].equals(value)) {
 190                 TTY.println("block %s  instruction %s", curBlock, curInstruction);
 191                 TTY.println("live registers: %s", Arrays.toString(curRegistersLive));
 192                 TTY.println("ERROR: Use of fixed register %s that is not defined in this block", value);
 193                 throw GraalError.shouldNotReachHere();
 194             }
 195         }
 196     }
 197 
 198     private void def(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
 199         allowed(curInstruction, value, mode, flags);
 200 
 201         if (isVariable(value)) {
 202             assert beforeRegisterAllocation;
 203 
 204             int variableIdx = asVariable(value).index;
 205             if (variableDefinitions[variableIdx] != null) {
 206                 TTY.println("block %s  instruction %s", curBlock, curInstruction);
 207                 TTY.println("live variables: %s", curVariablesLive);
 208                 TTY.println("definition of %s: %s", value, variableDefinitions[variableIdx]);
 209                 TTY.println("ERROR: Variable %s defined multiple times", value);
 210                 throw GraalError.shouldNotReachHere();
 211             }
 212             assert curInstruction != null;
 213             variableDefinitions[variableIdx] = curInstruction;
 214             assert !curVariablesLive.get(variableIdx);
 215             if (mode == OperandMode.DEF) {
 216                 curVariablesLive.set(variableIdx);
 217             }
 218 
 219         } else if (isAllocatableRegister(value)) {
 220             int regNum = asRegister(value).number;
 221             if (curRegistersDefined.get(regNum)) {
 222                 TTY.println("block %s  instruction %s", curBlock, curInstruction);
 223                 TTY.println("ERROR: Same register defined twice in the same instruction: %s", value);
 224                 throw GraalError.shouldNotReachHere();
 225             }
 226             curRegistersDefined.set(regNum);
 227 
 228             if (beforeRegisterAllocation) {
 229                 if (mode == OperandMode.DEF) {
 230                     curRegistersLive[regNum] = value;
 231                 } else {
 232                     curRegistersLive[regNum] = null;
 233                 }
 234             }
 235         }
 236     }
 237 
 238     // @formatter:off
 239     private static void allowed(Object op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
 240         if ((isVariable(value) && flags.contains(OperandFlag.REG)) ||
 241             (isRegister(value) && flags.contains(OperandFlag.REG)) ||
 242             (isStackSlotValue(value) && flags.contains(OperandFlag.STACK)) ||
 243             (isJavaConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) ||
 244             (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL))) {
 245             return;
 246         }
 247         throw new GraalError("Invalid LIR%n  Instruction: %s%n  Mode: %s%n  Flags: %s%n  Unexpected value: %s %s",
 248                         op, mode, flags, value.getClass().getSimpleName(), value);
 249     }
 250     // @formatter:on
 251 }