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