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.gen; 024 025import static com.oracle.graal.lir.LIRValueUtil.*; 026import static jdk.internal.jvmci.code.ValueUtil.*; 027 028import java.util.*; 029 030import jdk.internal.jvmci.meta.*; 031 032import com.oracle.graal.lir.*; 033import com.oracle.graal.lir.LIRInstruction.OperandFlag; 034import com.oracle.graal.lir.LIRInstruction.OperandMode; 035import com.oracle.graal.lir.StandardOp.StackMove; 036import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; 037 038/** 039 * Base class for {@link SpillMoveFactory} that checks that the instructions created adhere to the 040 * contract of {@link SpillMoveFactory}. 041 */ 042public abstract class SpillMoveFactoryBase implements SpillMoveFactory { 043 044 public final LIRInstruction createMove(AllocatableValue result, Value input) { 045 LIRInstruction inst = createMoveIntern(result, input); 046 assert checkResult(inst, result, input); 047 return inst; 048 } 049 050 public final LIRInstruction createStackMove(AllocatableValue result, Value input) { 051 LIRInstruction inst = createStackMoveIntern(result, input); 052 assert checkResult(inst, result, input); 053 return inst; 054 } 055 056 protected abstract LIRInstruction createMoveIntern(AllocatableValue result, Value input); 057 058 protected LIRInstruction createStackMoveIntern(AllocatableValue result, Value input) { 059 return new StackMove(result, input); 060 } 061 062 /** Closure for {@link SpillMoveFactoryBase#checkResult}. */ 063 @SuppressWarnings("unused") 064 private static class CheckClosure { 065 066 private final AllocatableValue result; 067 private final Value input; 068 069 private int tempCount = 0; 070 private int aliveCount = 0; 071 private int stateCount = 0; 072 private int inputCount = 0; 073 private int outputCount = 0; 074 075 CheckClosure(AllocatableValue result, Value input) { 076 this.result = result; 077 this.input = input; 078 } 079 080 void tempProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 081 assert false : String.format("SpillMoveFactory: Instruction %s is not allowed to contain operand %s of mode %s", op, value, mode); 082 tempCount++; 083 } 084 085 void stateProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 086 assert false : String.format("SpillMoveFactory: Instruction %s is not allowed to contain operand %s of mode %s", op, value, mode); 087 stateCount++; 088 } 089 090 void aliveProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 091 assert !isVariable(value) && flags.contains(OperandFlag.UNINITIALIZED) : String.format("SpillMoveFactory: Instruction %s is not allowed to contain operand %s of mode %s", op, value, mode); 092 aliveCount++; 093 } 094 095 void inputProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 096 assert value.equals(input) || isConstant(value) : String.format("SpillMoveFactory: Instruction %s can only have %s as input, got %s", op, input, value); 097 inputCount++; 098 } 099 100 void outputProc(LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 101 assert value.equals(result) : String.format("SpillMoveFactory: Instruction %s can only have %s as input, got %s", op, input, value); 102 outputCount++; 103 } 104 } 105 106 /** Checks that the instructions adheres to the contract of {@link SpillMoveFactory}. */ 107 private static boolean checkResult(LIRInstruction inst, AllocatableValue result, Value input) { 108 109 SpillMoveFactoryBase.CheckClosure c = new CheckClosure(result, input); 110 inst.visitEachInput(c::inputProc); 111 inst.visitEachOutput(c::outputProc); 112 inst.visitEachAlive(c::aliveProc); 113 inst.visitEachTemp(c::tempProc); 114 inst.visitEachState(c::stateProc); 115 116 assert c.outputCount >= 1 : "no output produced" + inst; 117 assert c.stateCount == 0 : "SpillMoveFactory: instruction must not have a state: " + inst; 118 return true; 119 } 120}