--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstruction.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,459 @@
+/*
+ * 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 jdk.vm.ci.code.ValueUtil.isStackSlot;
+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 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.graph.NodeSourcePosition;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.StandardOp.MoveOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+
+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<OperandMode, EnumSet<OperandFlag>> 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<OperandFlag> 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;
+
+ /**
+ * Constructs a new LIR instruction.
+ */
+ public LIRInstruction(LIRInstructionClass<? extends LIRInstruction> c) {
+ 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);
+ }
+
+ // Checkstyle: stop
+ /**
+ * Returns {@code true} if the instruction is a {@link MoveOp}.
+ *
+ * This function is preferred to {@code instanceof MoveOp} since the type check is more
+ * expensive than reading a field from {@link LIRInstructionClass}.
+ */
+ public final boolean isMoveOp() {
+ return instructionClass.isMoveOp();
+ }
+
+ /**
+ * Returns {@code true} if the instruction is a {@link ValueMoveOp}.
+ *
+ * This function is preferred to {@code instanceof ValueMoveOp} since the type check is more
+ * expensive than reading a field from {@link LIRInstructionClass}.
+ */
+ public final boolean isValueMoveOp() {
+ return instructionClass.isValueMoveOp();
+ }
+
+ /**
+ * Returns {@code true} if the instruction is a {@link LoadConstantOp}.
+ *
+ * This function is preferred to {@code instanceof LoadConstantOp} since the type check is more
+ * expensive than reading a field from {@link LIRInstructionClass}.
+ */
+ public final boolean isLoadConstantOp() {
+ return instructionClass.isLoadConstantOp();
+ }
+ // Checkstyle: resume
+
+ /**
+ * 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() {
+ }
+
+ /**
+ * Adds a comment to this instruction.
+ */
+ public final void setComment(LIRGenerationResult res, String comment) {
+ res.setComment(this, comment);
+ }
+
+ /**
+ * Gets the comment attached to this instruction.
+ */
+ public final String getComment(LIRGenerationResult res) {
+ return res.getComment(this);
+ }
+
+ 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 String toString(LIRGenerationResult res) {
+ String toString = toString();
+ if (res == null) {
+ return toString;
+ }
+ String comment = getComment(res);
+ if (comment == null) {
+ return toString;
+ }
+ return String.format("%s // %s", toString, comment);
+ }
+
+ public LIRInstructionClass<?> getLIRInstructionClass() {
+ return instructionClass;
+ }
+
+ @Override
+ public int hashCode() {
+ return id;
+ }
+}