001/*
002 * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.lir;
024
025import static com.oracle.graal.lir.LIRValueUtil.*;
026import static jdk.internal.jvmci.code.ValueUtil.*;
027
028import java.util.*;
029
030import jdk.internal.jvmci.code.*;
031import jdk.internal.jvmci.common.*;
032import jdk.internal.jvmci.meta.*;
033
034import com.oracle.graal.compiler.common.cfg.*;
035import com.oracle.graal.debug.*;
036import com.oracle.graal.lir.LIRInstruction.OperandFlag;
037import com.oracle.graal.lir.LIRInstruction.OperandMode;
038import com.oracle.graal.lir.framemap.*;
039import com.oracle.graal.lir.ssa.*;
040
041public final class LIRVerifier {
042
043    private final LIR lir;
044    private final FrameMap frameMap;
045
046    private final boolean beforeRegisterAllocation;
047
048    private final BitSet[] blockLiveOut;
049    private final Object[] variableDefinitions;
050
051    private BitSet liveOutFor(AbstractBlockBase<?> block) {
052        return blockLiveOut[block.getId()];
053    }
054
055    private void setLiveOutFor(AbstractBlockBase<?> block, BitSet liveOut) {
056        blockLiveOut[block.getId()] = liveOut;
057    }
058
059    private int maxRegisterNum() {
060        return frameMap.getTarget().arch.getRegisters().length;
061    }
062
063    private boolean isAllocatableRegister(Value value) {
064        return isRegister(value) && frameMap.getRegisterConfig().getAttributesMap()[asRegister(value).number].isAllocatable();
065    }
066
067    public static boolean verify(final LIRInstruction op) {
068
069        op.visitEachInput(LIRVerifier::allowed);
070        op.visitEachAlive(LIRVerifier::allowed);
071        op.visitEachState(LIRVerifier::allowed);
072        op.visitEachTemp(LIRVerifier::allowed);
073        op.visitEachOutput(LIRVerifier::allowed);
074
075        op.verify();
076        return true;
077    }
078
079    public static boolean verify(boolean beforeRegisterAllocation, LIR lir, FrameMap frameMap) {
080        LIRVerifier verifier = new LIRVerifier(beforeRegisterAllocation, lir, frameMap);
081        verifier.verify();
082        return true;
083    }
084
085    private LIRVerifier(boolean beforeRegisterAllocation, LIR lir, FrameMap frameMap) {
086        this.beforeRegisterAllocation = beforeRegisterAllocation;
087        this.lir = lir;
088        this.frameMap = frameMap;
089        this.blockLiveOut = new BitSet[lir.linearScanOrder().size()];
090        this.variableDefinitions = new Object[lir.numVariables()];
091    }
092
093    private BitSet curVariablesLive;
094    private Value[] curRegistersLive;
095
096    private AbstractBlockBase<?> curBlock;
097    private Object curInstruction;
098    private BitSet curRegistersDefined;
099
100    private void verify() {
101        ValueConsumer useConsumer = new ValueConsumer() {
102
103            @Override
104            public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
105                use(value, mode, flags);
106            }
107        };
108        ValueConsumer defConsumer = new ValueConsumer() {
109
110            @Override
111            public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
112                def(value, mode, flags);
113            }
114        };
115
116        int maxRegisterNum = maxRegisterNum();
117        curRegistersDefined = new BitSet();
118        for (AbstractBlockBase<?> block : lir.linearScanOrder()) {
119            curBlock = block;
120            curVariablesLive = new BitSet();
121            curRegistersLive = new Value[maxRegisterNum];
122
123            if (block.getDominator() != null) {
124                curVariablesLive.or(liveOutFor(block.getDominator()));
125            }
126
127            assert lir.getLIRforBlock(block).get(0) instanceof StandardOp.LabelOp : "block must start with label";
128
129            if (block.getSuccessorCount() > 0) {
130                LIRInstruction last = lir.getLIRforBlock(block).get(lir.getLIRforBlock(block).size() - 1);
131                assert last instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump";
132            }
133            if (block.getPredecessorCount() > 1) {
134                SSAUtil.verifyPhi(lir, block);
135            }
136
137            for (LIRInstruction op : lir.getLIRforBlock(block)) {
138                curInstruction = op;
139
140                op.visitEachInput(useConsumer);
141                if (op.destroysCallerSavedRegisters()) {
142                    for (Register register : frameMap.getRegisterConfig().getCallerSaveRegisters()) {
143                        curRegistersLive[register.number] = null;
144                    }
145                }
146                curRegistersDefined.clear();
147                op.visitEachAlive(useConsumer);
148                op.visitEachState(useConsumer);
149                op.visitEachTemp(defConsumer);
150                op.visitEachOutput(defConsumer);
151
152                curInstruction = null;
153            }
154
155            setLiveOutFor(block, curVariablesLive);
156        }
157    }
158
159    private void use(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
160        allowed(curInstruction, value, mode, flags);
161
162        if (isVariable(value)) {
163            assert beforeRegisterAllocation;
164
165            int variableIdx = asVariable(value).index;
166            if (!curVariablesLive.get(variableIdx)) {
167                TTY.println("block %s  instruction %s", curBlock, curInstruction);
168                TTY.println("live variables: %s", curVariablesLive);
169                if (variableDefinitions[variableIdx] != null) {
170                    TTY.println("definition of %s: %s", value, variableDefinitions[variableIdx]);
171                }
172                TTY.println("ERROR: Use of variable %s that is not defined in dominator", value);
173                throw JVMCIError.shouldNotReachHere();
174            }
175
176        } else if (isAllocatableRegister(value)) {
177            int regNum = asRegister(value).number;
178            if (mode == OperandMode.ALIVE) {
179                curRegistersDefined.set(regNum);
180            }
181
182            if (beforeRegisterAllocation && !curRegistersLive[regNum].equals(value)) {
183                TTY.println("block %s  instruction %s", curBlock, curInstruction);
184                TTY.println("live registers: %s", Arrays.toString(curRegistersLive));
185                TTY.println("ERROR: Use of fixed register %s that is not defined in this block", value);
186                throw JVMCIError.shouldNotReachHere();
187            }
188        }
189    }
190
191    private void def(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
192        allowed(curInstruction, value, mode, flags);
193
194        if (isVariable(value)) {
195            assert beforeRegisterAllocation;
196
197            int variableIdx = asVariable(value).index;
198            if (variableDefinitions[variableIdx] != null) {
199                TTY.println("block %s  instruction %s", curBlock, curInstruction);
200                TTY.println("live variables: %s", curVariablesLive);
201                TTY.println("definition of %s: %s", value, variableDefinitions[variableIdx]);
202                TTY.println("ERROR: Variable %s defined multiple times", value);
203                throw JVMCIError.shouldNotReachHere();
204            }
205            assert curInstruction != null;
206            variableDefinitions[variableIdx] = curInstruction;
207            assert !curVariablesLive.get(variableIdx);
208            if (mode == OperandMode.DEF) {
209                curVariablesLive.set(variableIdx);
210            }
211
212        } else if (isAllocatableRegister(value)) {
213            int regNum = asRegister(value).number;
214            if (curRegistersDefined.get(regNum)) {
215                TTY.println("block %s  instruction %s", curBlock, curInstruction);
216                TTY.println("ERROR: Same register defined twice in the same instruction: %s", value);
217                throw JVMCIError.shouldNotReachHere();
218            }
219            curRegistersDefined.set(regNum);
220
221            if (beforeRegisterAllocation) {
222                if (mode == OperandMode.DEF) {
223                    curRegistersLive[regNum] = value;
224                } else {
225                    curRegistersLive[regNum] = null;
226                }
227            }
228        }
229    }
230
231    // @formatter:off
232    private static void allowed(Object op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
233        if ((isVariable(value) && flags.contains(OperandFlag.REG)) ||
234            (isRegister(value) && flags.contains(OperandFlag.REG)) ||
235            (isStackSlotValue(value) && flags.contains(OperandFlag.STACK)) ||
236            (isConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) ||
237            (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL))) {
238            return;
239        }
240        throw new JVMCIError("Invalid LIR%n  Instruction: %s%n  Mode: %s%n  Flags: %s%n  Unexpected value: %s %s",
241                        op, mode, flags, value.getClass().getSimpleName(), value);
242    }
243    // @formatter:on
244}