001/* 002 * Copyright (c) 2015, 2015, 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.ssi; 024 025import static jdk.internal.jvmci.code.ValueUtil.*; 026 027import java.util.*; 028 029import jdk.internal.jvmci.meta.*; 030 031import com.oracle.graal.compiler.common.cfg.*; 032import com.oracle.graal.debug.*; 033import com.oracle.graal.debug.Debug.Scope; 034import com.oracle.graal.lir.*; 035import com.oracle.graal.lir.LIRInstruction.OperandFlag; 036import com.oracle.graal.lir.LIRInstruction.OperandMode; 037import com.oracle.graal.lir.StandardOp.BlockEndOp; 038import com.oracle.graal.lir.StandardOp.LabelOp; 039 040public final class SSIVerifier { 041 042 public static boolean verify(LIR lir) { 043 return new SSIVerifier(lir).verify(); 044 } 045 046 private final LIR lir; 047 048 private SSIVerifier(LIR lir) { 049 this.lir = lir; 050 } 051 052 private boolean verify() { 053 try (Scope s = Debug.scope("SSIVerifier", lir)) { 054 for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) { 055 doBlock(block); 056 } 057 } catch (Throwable e) { 058 throw Debug.handle(e); 059 } 060 return true; 061 } 062 063 private void doBlock(AbstractBlockBase<?> block) { 064 for (AbstractBlockBase<?> succ : block.getSuccessors()) { 065 verifyEdge(block, succ); 066 } 067 verifyInstructions(block); 068 } 069 070 private void verifyEdge(AbstractBlockBase<?> from, AbstractBlockBase<?> to) { 071 BlockEndOp out = SSIUtil.outgoing(lir, from); 072 LabelOp in = SSIUtil.incoming(lir, to); 073 int outgoingSize = out.getOutgoingSize(); 074 int incomingSize = in.getIncomingSize(); 075 assert outgoingSize == incomingSize : String.format("Outgoing size %d and incoming size %d do not match", outgoingSize, incomingSize); 076 077 for (int i = 0; i < outgoingSize; i++) { 078 Value incomingValue = in.getIncomingValue(i); 079 Value outgoingValue = out.getOutgoingValue(i); 080 LIRKind inLIRKind = incomingValue.getLIRKind(); 081 LIRKind outLIRKind = outgoingValue.getLIRKind(); 082 assert LIRKind.verifyMoveKinds(inLIRKind, outLIRKind) || incomingValue.equals(Value.ILLEGAL) : String.format("Outgoing LIRKind %s (%s) an and incoming LIRKind %s (%s) do not match", 083 outgoingValue, outLIRKind, incomingValue, inLIRKind); 084 } 085 } 086 087 private void verifyInstructions(AbstractBlockBase<?> block) { 088 List<LIRInstruction> instructions = lir.getLIRforBlock(block); 089 HashMap<Value, LIRInstruction> defined = new HashMap<>(); 090 091 InstructionValueConsumer useConsumer = new InstructionValueConsumer() { 092 public void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 093 if (checkUsage(value)) { 094 assert defined.containsKey(value) || flags.contains(OperandFlag.UNINITIALIZED) : String.format("Value %s is used by instruction %s in block %s but not defined.", value, 095 instruction, block); 096 } 097 } 098 }; 099 InstructionValueConsumer stateConsumer = new InstructionValueConsumer() { 100 public void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 101 if (checkUsage(value)) { 102 /* 103 * TODO (je): There are undefined stack values used for locks. Ignore them for 104 * the time being. 105 */ 106 assert defined.containsKey(value) || isVirtualStackSlot(value) : String.format("Value %s is used in state of instruction %s in block %s but not defined.", value, instruction, 107 block); 108 } 109 } 110 }; 111 112 InstructionValueConsumer defConsumer = new InstructionValueConsumer() { 113 public void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 114 if (trackDefinition(value)) { 115 assert !defined.containsKey(value) : String.format("Value %s is redefined by instruction %s in block %s but already defined by %s.", value, instruction, block, defined.get(value)); 116 defined.put(value, instruction); 117 } 118 } 119 }; 120 121 for (LIRInstruction op : instructions) { 122 op.visitEachAlive(useConsumer); 123 op.visitEachInput(useConsumer); 124 op.visitEachState(stateConsumer); 125 126 op.visitEachTemp(defConsumer); 127 op.visitEachOutput(defConsumer); 128 } 129 } 130 131 private static boolean trackDefinition(Value value) { 132 if (isRegister(value)) { 133 // registers can be redefined 134 return false; 135 } 136 if (value.equals(Value.ILLEGAL)) { 137 // Don't care about illegal values 138 return false; 139 } 140 return true; 141 } 142 143 private static boolean checkUsage(Value value) { 144 if (value instanceof Constant) { 145 // Constants do not need to be defined 146 return false; 147 } 148 if (isRegister(value)) { 149 // Assume fixed registers are correct 150 return false; 151 } 152 if (value.equals(Value.ILLEGAL)) { 153 // Don't care about illegal values 154 return false; 155 } 156 return true; 157 } 158}