--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstruction.java 2016-12-09 00:54:00.103249448 -0800 @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.lir; + +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.OUTGOING; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED; +import static org.graalvm.compiler.lir.LIRInstruction.OperandMode.ALIVE; +import static org.graalvm.compiler.lir.LIRInstruction.OperandMode.DEF; +import static org.graalvm.compiler.lir.LIRInstruction.OperandMode.TEMP; +import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.EnumSet; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.code.RegisterValue; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.Value; + +/** + * The base class for an {@code LIRInstruction}. + */ +public abstract class LIRInstruction { + /** + * Constants denoting how a LIR instruction uses an operand. + */ + public enum OperandMode { + /** + * The value must have been defined before. It is alive before the instruction until the + * beginning of the instruction, but not necessarily throughout the instruction. A register + * assigned to it can also be assigned to a {@link #TEMP} or {@link #DEF} operand. The value + * can be used again after the instruction, so the instruction must not modify the register. + */ + USE, + + /** + * The value must have been defined before. It is alive before the instruction and + * throughout the instruction. A register assigned to it cannot be assigned to a + * {@link #TEMP} or {@link #DEF} operand. The value can be used again after the instruction, + * so the instruction must not modify the register. + */ + ALIVE, + + /** + * The value must not have been defined before, and must not be used after the instruction. + * The instruction can do whatever it wants with the register assigned to it (or not use it + * at all). + */ + TEMP, + + /** + * The value must not have been defined before. The instruction has to assign a value to the + * register. The value can (and most likely will) be used after the instruction. + */ + DEF, + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public static @interface Use { + + OperandFlag[] value() default OperandFlag.REG; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public static @interface Alive { + + OperandFlag[] value() default OperandFlag.REG; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public static @interface Temp { + + OperandFlag[] value() default OperandFlag.REG; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public static @interface Def { + + OperandFlag[] value() default OperandFlag.REG; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public static @interface State { + } + + /** + * Flags for an operand. + */ + public enum OperandFlag { + /** + * The value can be a {@link RegisterValue}. + */ + REG, + + /** + * The value can be a {@link StackSlot}. + */ + STACK, + + /** + * The value can be a {@link CompositeValue}. + */ + COMPOSITE, + + /** + * The value can be a {@link JavaConstant}. + */ + CONST, + + /** + * The value can be {@link Value#ILLEGAL}. + */ + ILLEGAL, + + /** + * The register allocator should try to assign a certain register to improve code quality. + * Use {@link LIRInstruction#forEachRegisterHint} to access the register hints. + */ + HINT, + + /** + * The value can be uninitialized, e.g., a stack slot that has not written to before. This + * is only used to avoid false positives in verification code. + */ + UNINITIALIZED, + + /** Outgoing block value. */ + OUTGOING, + } + + /** + * For validity checking of the operand flags defined by instruction subclasses. + */ + protected static final EnumMap> ALLOWED_FLAGS; + + static { + ALLOWED_FLAGS = new EnumMap<>(OperandMode.class); + ALLOWED_FLAGS.put(OperandMode.USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED)); + ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED, OUTGOING)); + ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT)); + ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT)); + } + + /** + * The flags of the base and index value of an address. + */ + protected static final EnumSet ADDRESS_FLAGS = EnumSet.of(REG, ILLEGAL); + + private final LIRInstructionClass instructionClass; + + /** + * Instruction id for register allocation. + */ + private int id; + + /** + * The source position of the code that generated this instruction. + */ + private NodeSourcePosition position; + + private static final DebugCounter LIR_NODE_COUNT = Debug.counter("LIRNodes"); + + /** + * Constructs a new LIR instruction. + */ + public LIRInstruction(LIRInstructionClass c) { + LIR_NODE_COUNT.increment(); + instructionClass = c; + assert c.getClazz() == this.getClass(); + id = -1; + } + + public abstract void emitCode(CompilationResultBuilder crb); + + public final int id() { + return id; + } + + public final void setId(int id) { + this.id = id; + } + + public final NodeSourcePosition getPosition() { + return position; + } + + public final void setPosition(NodeSourcePosition position) { + this.position = position; + } + + public final String name() { + return instructionClass.getOpcode(this); + } + + public final boolean hasOperands() { + return instructionClass.hasOperands() || hasState() || destroysCallerSavedRegisters(); + } + + public final boolean hasState() { + return instructionClass.hasState(this); + } + + public boolean destroysCallerSavedRegisters() { + return false; + } + + // InstructionValueProcedures + public final void forEachInput(InstructionValueProcedure proc) { + instructionClass.forEachUse(this, proc); + } + + public final void forEachAlive(InstructionValueProcedure proc) { + instructionClass.forEachAlive(this, proc); + } + + public final void forEachTemp(InstructionValueProcedure proc) { + instructionClass.forEachTemp(this, proc); + } + + public final void forEachOutput(InstructionValueProcedure proc) { + instructionClass.forEachDef(this, proc); + } + + public final void forEachState(InstructionValueProcedure proc) { + instructionClass.forEachState(this, proc); + } + + // ValueProcedures + public final void forEachInput(ValueProcedure proc) { + instructionClass.forEachUse(this, proc); + } + + public final void forEachAlive(ValueProcedure proc) { + instructionClass.forEachAlive(this, proc); + } + + public final void forEachTemp(ValueProcedure proc) { + instructionClass.forEachTemp(this, proc); + } + + public final void forEachOutput(ValueProcedure proc) { + instructionClass.forEachDef(this, proc); + } + + public final void forEachState(ValueProcedure proc) { + instructionClass.forEachState(this, proc); + } + + // States + public final void forEachState(InstructionStateProcedure proc) { + instructionClass.forEachState(this, proc); + } + + public final void forEachState(StateProcedure proc) { + instructionClass.forEachState(this, proc); + } + + // InstructionValueConsumers + public final void visitEachInput(InstructionValueConsumer proc) { + instructionClass.visitEachUse(this, proc); + } + + public final void visitEachAlive(InstructionValueConsumer proc) { + instructionClass.visitEachAlive(this, proc); + } + + public final void visitEachTemp(InstructionValueConsumer proc) { + instructionClass.visitEachTemp(this, proc); + } + + public final void visitEachOutput(InstructionValueConsumer proc) { + instructionClass.visitEachDef(this, proc); + } + + public final void visitEachState(InstructionValueConsumer proc) { + instructionClass.visitEachState(this, proc); + } + + // ValueConsumers + public final void visitEachInput(ValueConsumer proc) { + instructionClass.visitEachUse(this, proc); + } + + public final void visitEachAlive(ValueConsumer proc) { + instructionClass.visitEachAlive(this, proc); + } + + public final void visitEachTemp(ValueConsumer proc) { + instructionClass.visitEachTemp(this, proc); + } + + public final void visitEachOutput(ValueConsumer proc) { + instructionClass.visitEachDef(this, proc); + } + + public final void visitEachState(ValueConsumer proc) { + instructionClass.visitEachState(this, proc); + } + + @SuppressWarnings("unused") + public final Value forEachRegisterHint(Value value, OperandMode mode, InstructionValueProcedure proc) { + return instructionClass.forEachRegisterHint(this, mode, proc); + } + + @SuppressWarnings("unused") + public final Value forEachRegisterHint(Value value, OperandMode mode, ValueProcedure proc) { + return instructionClass.forEachRegisterHint(this, mode, proc); + } + + /** + * Utility method to add stack arguments to a list of temporaries. Useful for modeling calling + * conventions that kill outgoing argument space. + * + * @return additional temporaries + */ + protected static Value[] addStackSlotsToTemporaries(Value[] parameters, Value[] temporaries) { + int extraTemps = 0; + for (Value p : parameters) { + if (isStackSlot(p)) { + extraTemps++; + } + assert !isVirtualStackSlot(p) : "only real stack slots in calling convention"; + } + if (extraTemps != 0) { + int index = temporaries.length; + Value[] newTemporaries = Arrays.copyOf(temporaries, temporaries.length + extraTemps); + for (Value p : parameters) { + if (isStackSlot(p)) { + newTemporaries[index++] = p; + } + } + return newTemporaries; + } + return temporaries; + } + + public void verify() { + } + + public final String toStringWithIdPrefix() { + if (id != -1) { + return String.format("%4d %s", id, toString()); + } + return " " + toString(); + } + + @Override + public String toString() { + return instructionClass.toString(this); + } + + public LIRInstructionClass getLIRInstructionClass() { + return instructionClass; + } +}