Mercurial > hg > graal-compiler
diff graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/CiXirAssembler.java @ 4199:aaac4894175c
Renamed cri packages from sun to oracle.
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Tue, 03 Jan 2012 16:29:28 +0100 |
parents | graal/com.oracle.max.cri/src/com/sun/cri/xir/CiXirAssembler.java@bc8527f3071c |
children | 744dade427b8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/CiXirAssembler.java Tue Jan 03 16:29:28 2012 +0100 @@ -0,0 +1,989 @@ +/* + * Copyright (c) 2009, 2011, 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 com.oracle.max.cri.xir; + +import static com.oracle.max.cri.xir.CiXirAssembler.XirOp.*; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ci.CiAddress.*; +import com.oracle.max.cri.ri.*; + +/** + * Represents an assembler that allows a client such as the runtime system to + * create {@link XirTemplate XIR templates}. + */ +public abstract class CiXirAssembler { + + protected XirOperand resultOperand; + protected boolean allocateResultOperand; + + protected final List<XirInstruction> instructions = new ArrayList<>(); + protected final List<XirLabel> labels = new ArrayList<>(5); + protected final List<XirParameter> parameters = new ArrayList<>(5); + protected final List<XirTemp> temps = new ArrayList<>(5); + protected final List<XirConstant> constants = new ArrayList<>(5); + protected final List<XirMark> marks = new ArrayList<>(5); + + protected int outgoingStackSize = 0; + + /** + * Increases by one for every {@link XirOperand operand} created. + */ + protected int variableCount; + + /** + * Marks the assembly complete. + */ + protected boolean finished = true; + + protected final CiTarget target; + + public CiXirAssembler(CiTarget target) { + this.target = target; + } + + public static class RuntimeCallInformation { + public final Object target; + public final boolean useInfoAfter; + + public RuntimeCallInformation(Object target, boolean useInfoAfter) { + this.target = target; + this.useInfoAfter = useInfoAfter; + } + } + + /** + * Represents additional address calculation information. + */ + public static final class AddressAccessInformation { + + /** + * The scaling factor for the scaled-index part of an address computation. + */ + public final Scale scale; + + /** + * The constant byte-sized displacement part of an address computation. + */ + public final int disp; + + /** + * Determines if the memory access through the address can trap. + */ + public final boolean canTrap; + + private AddressAccessInformation(boolean canTrap) { + this.canTrap = canTrap; + this.scale = Scale.Times1; + this.disp = 0; + } + + private AddressAccessInformation(boolean canTrap, int disp) { + this.canTrap = canTrap; + this.scale = Scale.Times1; + this.disp = disp; + } + + private AddressAccessInformation(boolean canTrap, int disp, Scale scale) { + this.canTrap = canTrap; + this.scale = scale; + this.disp = disp; + } + } + + /** + * A label that is the target of a control flow instruction. + */ + public static final class XirLabel { + public static final String TrueSuccessor = "TrueSuccessor"; + public static final String FalseSuccessor = "FalseSuccessor"; + public final String name; + public final int index; + /** + * If {@code true} the label is to an instruction in the fast path sequence, otherwise to the slow path. + */ + public final boolean inline; + + private XirLabel(String name, int index, boolean inline) { + this.name = name; + this.index = index; + this.inline = inline; + } + + @Override + public String toString() { + return name; + } + } + + /** + * Tagging interface that indicates that an {@link XirOperand} is a constant. + */ + public interface XirConstantOperand { + int getIndex(); + } + + public static final XirOperand VOID = null; + + /** + * Operands for {@link XirInstruction instructions}. + * There are three basic variants, {@link XirConstant constant}, {@link XirParameter parameter} and {@link XirTemp}. + */ + public abstract static class XirOperand { + + public final CiKind kind; + + /** + * Unique id in range {@code 0} to {@link #variableCount variableCount - 1}. + */ + public final int index; + + /** + * Value whose {@link #toString()} method provides a name for this operand. + */ + public final Object name; + + public XirOperand(CiXirAssembler asm, Object name, CiKind kind) { + this.kind = kind; + this.name = name; + this.index = asm.variableCount++; + } + + @Override + public String toString() { + return String.valueOf(name); + } + + public String detailedToString() { + + StringBuffer sb = new StringBuffer(); + + sb.append(name); + sb.append('$'); + sb.append(kind.typeChar); + return sb.toString(); + } + } + + /** + * Parameters to {@link XirTemplate templates}. + */ + public static class XirParameter extends XirOperand { + /** + * Unique id in range {@code 0} to {@code parameters.Size() - 1}. + */ + public final int parameterIndex; + + public final boolean canBeConstant; + + XirParameter(CiXirAssembler asm, String name, CiKind kind, boolean canBeConstant) { + super(asm, name, kind); + this.parameterIndex = asm.parameters.size(); + this.canBeConstant = canBeConstant; + asm.parameters.add(this); + } + + } + + public static class XirConstantParameter extends XirParameter implements XirConstantOperand { + XirConstantParameter(CiXirAssembler asm, String name, CiKind kind) { + super(asm, name, kind, true); + } + + public int getIndex() { + return index; + } + } + + public static class XirVariableParameter extends XirParameter { + XirVariableParameter(CiXirAssembler asm, String name, CiKind kind, boolean canBeConstant) { + super(asm, name, kind, canBeConstant); + } + } + + public static class XirConstant extends XirOperand implements XirConstantOperand { + public final CiConstant value; + + XirConstant(CiXirAssembler asm, CiConstant value) { + super(asm, value, value.kind); + this.value = value; + } + + public int getIndex() { + return index; + } + } + + public static class XirTemp extends XirOperand { + public final boolean reserve; + + XirTemp(CiXirAssembler asm, String name, CiKind kind, boolean reserve) { + super(asm, name, kind); + this.reserve = reserve; + } + } + + public static class XirRegister extends XirTemp { + public final CiValue register; + + XirRegister(CiXirAssembler asm, String name, CiRegisterValue register, boolean reserve) { + super(asm, name, register.kind, reserve); + this.register = register; + } + } + + /** + * Start a new assembly with no initial {@link #resultOperand result operand}. + */ + public void restart() { + reset(); + resultOperand = null; + } + + /** + * Start a new assembly with a {@link #resultOperand result operand} of type {@code kind}. + * @param kind the result kind + * @return an {@code XirOperand} for the result operand + */ + public XirOperand restart(CiKind kind) { + reset(); + resultOperand = new XirTemp(this, "result", kind, true); + allocateResultOperand = true; + return resultOperand; + } + + /** + * Reset the state of the class to the initial conditions to facilitate a new assembly. + */ + private void reset() { + assert finished : "must be finished before!"; + variableCount = 0; + allocateResultOperand = false; + finished = false; + instructions.clear(); + labels.clear(); + parameters.clear(); + temps.clear(); + constants.clear(); + marks.clear(); + outgoingStackSize = 0; + } + + /** + * Represents an XIR instruction, characterized by an {@link XirOp operation}, a {@link CiKind kind}, an optional {@link XirOperand result}, a variable number of {@link XirOperand arguments}, + * and some optional instruction-specific state. The {@link #x}, {@link #y} and {@link #z} methods are convenient ways to access the first, second and third + * arguments, respectively. Only the {@link XirOp#CallStub} and {@link XirOp#CallRuntime} instructions can have more than three arguments. + * + */ + public static final class XirInstruction { + /** + * The {@link CiKind kind} of values the instruction operates on. + */ + public final CiKind kind; + /** + * The {@link XirOp operation}. + */ + public final XirOp op; + /** + * The result, if any. + */ + public final XirOperand result; + /** + * The arguments. + */ + public final XirOperand[] arguments; + /** + * Arbitrary additional data associated with the instruction. + */ + public final Object extra; + + public XirInstruction(CiKind kind, XirOp op, XirOperand result, XirOperand... arguments) { + this(kind, null, op, result, arguments); + } + + public XirInstruction(CiKind kind, Object extra, XirOp op, XirOperand result, XirOperand... arguments) { + this.extra = extra; + this.kind = kind; + this.op = op; + this.result = result; + this.arguments = arguments; + } + + public XirOperand x() { + assert arguments.length > 0 : "no x operand for this instruction"; + return arguments[0]; + } + + public XirOperand y() { + assert arguments.length > 1 : "no y operand for this instruction"; + return arguments[1]; + } + + public XirOperand z() { + assert arguments.length > 2 : "no z operand for this instruction"; + return arguments[2]; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + + if (result != null) { + sb.append(result.toString()); + sb.append(" = "); + } + + sb.append(op.name()); + + if (kind != CiKind.Void) { + sb.append('$'); + sb.append(kind.typeChar); + } + + if (arguments != null && arguments.length > 0) { + sb.append("("); + + for (int i = 0; i < arguments.length; i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(arguments[i]); + } + + sb.append(")"); + } + + if (extra != null) { + sb.append(" "); + sb.append(extra); + } + + return sb.toString(); + } + } + + /** + * These marks let the RiXirGenerator mark positions in the generated native code and bring them in relationship with on another. + * This is necessary for code patching, etc. + */ + public static class XirMark { + public final XirMark[] references; + public final Object id; + + // special mark used to refer to the actual call site of an invoke + public static final XirMark CALLSITE = new XirMark(null); + + public XirMark(Object id, XirMark... references) { + this.id = id; + this.references = references; + } + } + + /** + * The set of opcodes for XIR instructions. + * {@link XirInstruction} defines {@code x}, {@code y} and {@code z} as the first, second and third arguments, respectively. + * We use these mnemonics, plus {@code args} for the complete set of arguments, {@code r} for the result, and {@code extra} + * for the instruction-specific extra data, in the opcode specifications. Note that the opcodes that operate on values do not directly + * specify the size (kind) of the data operated on; this is is encoded in {@link XirInstruction#kind}. + * Note: If the instruction kind differs from the argument/result kinds, the behavior is undefined. + * + */ + public enum XirOp { + /** + * Move {@code x} to {@code r}. + */ + Mov, + /** + * Add {@code y} to {@code x} and put the result in {@code r}. + */ + Add, + /** + * Subtract {@code y} from {@code x} and put the result in {@code r}. + */ + Sub, + /** + * Divide {@code y} by {@code x} and put the result in {@code r}. + */ + Div, + /** + * Multiply {@code y} by {@code x} and put the result in {@code r}. + */ + Mul, + /** + * {@code y} modulus {@code x} and put the result in {@code r}. + */ + Mod, + /** + * Shift {@code y} left by {@code x} and put the result in {@code r}. + */ + Shl, + /** + * Arithmetic shift {@code y} right by {@code x} and put the result in {@code r}. + */ + Sar, + /** + * Shift {@code y} right by {@code x} and put the result in {@code r}. + */ + Shr, + /** + * And {@code y} by {@code x} and put the result in {@code r}. + */ + And, + /** + * Or {@code y} by {@code x} and put the result in {@code r}. + */ + Or, + /** + * Exclusive Or {@code y} by {@code x} and put the result in {@code r}. + */ + Xor, + /** + * Null check on {@code x}. + */ + NullCheck, + /** + * Load value at address {@code x} and put the result in {@code r}. + */ + PointerLoad, + /** + * Store {@code y} at address {@code x}. + */ + PointerStore, + /** + * Load value at an effective address defined by base {@code x} and either a scaled index {@code y} plus displacement + * or an offset {@code y} and put the result in {@code r}. + */ + PointerLoadDisp, + /** + * Load an effective address defined by base {@code x} and either a scaled index {@code y} plus displacement + * or an offset {@code y} and put the result in {@code r}. + */ + LoadEffectiveAddress, + /** + * Store {@code z} at address defined by base {@code x} and index {@code y}. + */ + PointerStoreDisp, + /** + * Repeat move from {@code x} to {@code y} using {@code z} words. + */ + RepeatMoveWords, + /** + * Repeat move from {@code x} to {@code y} using {@code z} words. + */ + RepeatMoveBytes, + /** + * Compare value at at address {@code x} with value in {@code y} and store value {@code z} at address {@code x} + * if it was equal to {@code y}. + */ + PointerCAS, + /** + * Call the {@link XirTemplate.GlobalFlags#GLOBAL_STUB shared stub} defined by {@code extra} with {@code args} and put the result in {@code r}. + */ + CallStub, + /** + * Call the {@link RiMethod} defined by {@code extra} with {@code args} and put the result in {@code r}. + */ + CallRuntime, + /** + * Transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}. + */ + Jmp, + /** + * If {@code x == y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}. + */ + Jeq, + /** + * If {@code x != y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}. + */ + Jneq, + /** + * If {@code x > y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}. + */ + Jgt, + /** + * If {@code x >= y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}. + */ + Jgteq, + /** + * If {@code x unsigned >= y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}. + */ + Jugteq, + /** + * If {@code x < y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}. + */ + Jlt, + /** + * If {@code x <= y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}. + */ + Jlteq, + /** + * Decreases the input by one and jumps to the target if the input is not 0. + */ + DecAndJumpNotZero, + /** + * If bit designated by {@code z} at effective address defined by base {@code x} and offset {@code y} + * is set transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}. + */ + Jbset, + /** + * Bind the {@link XirLabel label} identified by {@code extra} to the current instruction and update any references to it. + * A label may be bound more than once to the same location. + */ + Bind, + /** + * Record a safepoint. + */ + Safepoint, + /** + * Align the code following this instruction to a multiple of (int)extra. + */ + Align, + /** + * Creates the stack banging overflow check. + */ + StackOverflowCheck, + /** + * Creates the stack frame for the method and spills callee-save registers (if any) to the {@linkplain CiRegisterSaveArea register save area}. + */ + PushFrame, + /** + * Restores all callee-save registers (if any) and removes the stack frame of the method. + */ + PopFrame, + /** + * Inserts an array of bytes directly into the code output. + */ + RawBytes, + /** + * Pushes a value onto the stack. + */ + Push, + /** + * Pops a value from the stack. + */ + Pop, + /** + * Marks a position in the generated native code. + */ + Mark, + /** + * Load instruction pointer of the next instruction in a destination register. + */ + Here, + /** + * Inserts nop instructions, with the given size in bytes. + */ + Nop, + /** + * This instruction should never be reached, this is useful for debugging purposes. + */ + ShouldNotReachHere + } + + public/*private*/ void append(XirInstruction xirInstruction) { + assert !finished : "no instructions can be added to finished template"; + instructions.add(xirInstruction); + } + + public XirLabel createInlineLabel(String name) { + final XirLabel result = new XirLabel(name, this.labels.size(), true); + labels.add(result); + return result; + } + + public XirLabel createOutOfLineLabel(String name) { + final XirLabel result = new XirLabel(name, this.labels.size(), false); + labels.add(result); + return result; + } + + public void mov(XirOperand result, XirOperand a) { + append(new XirInstruction(result.kind, Mov, result, a)); + } + + public void add(XirOperand result, XirOperand a, XirOperand b) { + append(new XirInstruction(result.kind, Add, result, a, b)); + } + + public void sub(XirOperand result, XirOperand a, XirOperand b) { + append(new XirInstruction(result.kind, Sub, result, a, b)); + } + + public void div(XirOperand result, XirOperand a, XirOperand b) { + append(new XirInstruction(result.kind, Div, result, a, b)); + } + + public void mul(XirOperand result, XirOperand a, XirOperand b) { + append(new XirInstruction(result.kind, Mul, result, a, b)); + } + + public void mod(XirOperand result, XirOperand a, XirOperand b) { + append(new XirInstruction(result.kind, Mod, result, a, b)); + } + + public void shl(XirOperand result, XirOperand a, XirOperand b) { + append(new XirInstruction(result.kind, Shl, result, a, b)); + } + + public void shr(XirOperand result, XirOperand a, XirOperand b) { + append(new XirInstruction(result.kind, Shr, result, a, b)); + } + + public void and(XirOperand result, XirOperand a, XirOperand b) { + append(new XirInstruction(result.kind, And, result, a, b)); + } + + public void or(XirOperand result, XirOperand a, XirOperand b) { + append(new XirInstruction(result.kind, Or, result, a, b)); + } + + public void xor(XirOperand result, XirOperand a, XirOperand b) { + append(new XirInstruction(result.kind, Xor, result, a, b)); + } + + public void nullCheck(XirOperand pointer) { + append(new XirInstruction(CiKind.Object, NullCheck, VOID, pointer)); + } + + public void pload(CiKind kind, XirOperand result, XirOperand pointer, boolean canTrap) { + append(new XirInstruction(kind, canTrap, PointerLoad, result, pointer)); + } + + public void pstore(CiKind kind, XirOperand pointer, XirOperand value, boolean canTrap) { + append(new XirInstruction(kind, canTrap, PointerStore, null, pointer, value)); + } + + public void pload(CiKind kind, XirOperand result, XirOperand pointer, XirOperand offset, boolean canTrap) { + append(new XirInstruction(kind, new AddressAccessInformation(canTrap), PointerLoadDisp, result, pointer, offset)); + } + + public void pstore(CiKind kind, XirOperand pointer, XirOperand offset, XirOperand value, boolean canTrap) { + append(new XirInstruction(kind, new AddressAccessInformation(canTrap), PointerStoreDisp, VOID, pointer, offset, value)); + } + + public void pload(CiKind kind, XirOperand result, XirOperand pointer, XirOperand index, int disp, Scale scale, boolean canTrap) { + append(new XirInstruction(kind, new AddressAccessInformation(canTrap, disp, scale), PointerLoadDisp, result, pointer, index)); + } + + public void lea(XirOperand result, XirOperand pointer, XirOperand index, int disp, Scale scale) { + append(new XirInstruction(target.wordKind, new AddressAccessInformation(false, disp, scale), LoadEffectiveAddress, result, pointer, index)); + } + + public void repmov(XirOperand src, XirOperand dest, XirOperand length) { + append(new XirInstruction(target.wordKind, null, RepeatMoveWords, null, src, dest, length)); + } + + public void here(XirOperand dst) { + append(new XirInstruction(target.wordKind, null, Here, dst)); + } + + public void repmovb(XirOperand src, XirOperand dest, XirOperand length) { + append(new XirInstruction(target.wordKind, null, RepeatMoveBytes, null, src, dest, length)); + } + + public void pstore(CiKind kind, XirOperand pointer, XirOperand index, XirOperand value, int disp, Scale scale, boolean canTrap) { + append(new XirInstruction(kind, new AddressAccessInformation(canTrap, disp, scale), PointerStoreDisp, VOID, pointer, index, value)); + } + + public void pcas(CiKind kind, XirOperand result, XirOperand pointer, XirOperand newValue, XirOperand oldValue) { + append(new XirInstruction(kind, null, PointerCAS, result, pointer, newValue, oldValue)); + } + + public void jmp(XirLabel l) { + append(new XirInstruction(CiKind.Void, l, Jmp, null)); + } + + public void decAndJumpNotZero(XirLabel l, XirOperand val) { + append(new XirInstruction(CiKind.Void, l, DecAndJumpNotZero, null, val)); + } + + public void jmpRuntime(Object rt) { + append(new XirInstruction(CiKind.Void, rt, Jmp, null)); + } + + public void jeq(XirLabel l, XirOperand a, XirOperand b) { + jcc(Jeq, l, a, b); + } + + private void jcc(XirOp op, XirLabel l, XirOperand a, XirOperand b) { + append(new XirInstruction(CiKind.Void, l, op, null, a, b)); + } + + public void jneq(XirLabel l, XirOperand a, XirOperand b) { + jcc(Jneq, l, a, b); + } + + public void jgt(XirLabel l, XirOperand a, XirOperand b) { + jcc(Jgt, l, a, b); + } + + public void jgteq(XirLabel l, XirOperand a, XirOperand b) { + jcc(Jgteq, l, a, b); + } + + public void jugteq(XirLabel l, XirOperand a, XirOperand b) { + jcc(Jugteq, l, a, b); + } + + public void jlt(XirLabel l, XirOperand a, XirOperand b) { + jcc(Jlt, l, a, b); + } + + public void jlteq(XirLabel l, XirOperand a, XirOperand b) { + jcc(Jlteq, l, a, b); + } + + public void jbset(XirLabel l, XirOperand a, XirOperand b, XirOperand c) { + append(new XirInstruction(CiKind.Void, l, Jbset, null, a, b, c)); + } + + public void bindInline(XirLabel l) { + assert l.inline; + append(new XirInstruction(CiKind.Void, l, Bind, null)); + } + + public void bindOutOfLine(XirLabel l) { + assert !l.inline; + append(new XirInstruction(CiKind.Void, l, Bind, null)); + } + + public void safepoint() { + append(new XirInstruction(CiKind.Void, null, Safepoint, null)); + } + + public void align(int multiple) { + assert multiple > 0; + append(new XirInstruction(CiKind.Void, multiple, Align, null)); + } + + public void stackOverflowCheck() { + append(new XirInstruction(CiKind.Void, null, StackOverflowCheck, null)); + } + + public void pushFrame() { + append(new XirInstruction(CiKind.Void, null, PushFrame, null)); + } + + public void popFrame() { + append(new XirInstruction(CiKind.Void, null, PopFrame, null)); + } + + public void rawBytes(byte[] bytes) { + append(new XirInstruction(CiKind.Void, bytes, RawBytes, null)); + } + + public void push(XirOperand value) { + append(new XirInstruction(CiKind.Void, Push, VOID, value)); + } + + public void pop(XirOperand result) { + append(new XirInstruction(result.kind, Pop, result)); + } + + public XirMark mark(Object id, XirMark... references) { + XirMark mark = new XirMark(id, references); + marks.add(mark); + append(new XirInstruction(CiKind.Void, mark, Mark, null)); + return mark; + } + + public void nop(int size) { + append(new XirInstruction(CiKind.Void, size, Nop, null)); + } + + public void shouldNotReachHere() { + append(new XirInstruction(CiKind.Void, null, ShouldNotReachHere, null)); + } + + public void shouldNotReachHere(String message) { + append(new XirInstruction(CiKind.Void, message, ShouldNotReachHere, null)); + } + + public void callStub(XirTemplate stub, XirOperand result, XirOperand... args) { + CiKind resultKind = result == null ? CiKind.Void : result.kind; + append(new XirInstruction(resultKind, stub, CallStub, result, args)); + } + + public void callRuntime(Object rt, XirOperand result, XirOperand... args) { + callRuntime(rt, result, false, args); + } + + public void callRuntime(Object rt, XirOperand result, boolean useInfoAfter, XirOperand... args) { + CiKind resultKind = result == null ? CiKind.Void : result.kind; + append(new XirInstruction(resultKind, new RuntimeCallInformation(rt, useInfoAfter), CallRuntime, result, args)); + } + + /** + * Terminates the assembly, checking invariants, in particular that {@link resultOperand} is set, and setting {@link #finished} to {@code true}. + */ + private void end() { + assert !finished : "template may only be finished once!"; + assert resultOperand != null : "result operand should be set"; + finished = true; + } + + /** + * Creates an {@link XirVariableParameter variable input parameter} of given name and {@link CiKind kind}. + * @param name a name for the parameter + * @param kind the parameter kind + * @return the {@link XirVariableParameter} + */ + public XirVariableParameter createInputParameter(String name, CiKind kind, boolean canBeConstant) { + assert !finished; + return new XirVariableParameter(this, name, kind, canBeConstant); + } + + public XirVariableParameter createInputParameter(String name, CiKind kind) { + return createInputParameter(name, kind, false); + } + + /** + * Creates an {@link XirConstantParameter constant input parameter} of given name and {@link CiKind kind}. + * @param name a name for the parameter + * @param kind the parameter kind + * @return the {@link XirConstantParameter} + */ + public XirConstantParameter createConstantInputParameter(String name, CiKind kind) { + assert !finished; + return new XirConstantParameter(this, name, kind); + } + + public XirConstant createConstant(CiConstant constant) { + assert !finished; + XirConstant temp = new XirConstant(this, constant); + constants.add(temp); + return temp; + } + + public XirOperand createTemp(String name, CiKind kind) { + assert !finished; + XirTemp temp = new XirTemp(this, name, kind, true); + temps.add(temp); + return temp; + } + + public XirOperand createRegister(String name, CiKind kind, CiRegister register) { + return createRegister(name, kind, register, false); + } + + public XirOperand createRegisterTemp(String name, CiKind kind, CiRegister register) { + return createRegister(name, kind, register, true); + } + + private XirOperand createRegister(String name, CiKind kind, CiRegister register, boolean reserve) { + assert !finished; + XirRegister fixed = new XirRegister(this, name, register.asValue(kind), reserve); + temps.add(fixed); + return fixed; + } + + public XirParameter getParameter(String name) { + for (XirParameter param : parameters) { + if (param.name.toString().equals(name)) { + return param; + } + } + throw new IllegalArgumentException("no parameter: " + name); + } + + public XirTemp getTemp(String name) { + for (XirTemp temp : temps) { + if (temp.name.toString().equals(name)) { + return temp; + } + } + throw new IllegalArgumentException("no temp: " + name); + } + + public XirConstant i(int v) { + return createConstant(CiConstant.forInt(v)); + } + + public XirConstant l(int v) { + return createConstant(CiConstant.forLong(v)); + } + + public XirConstant b(boolean v) { + return createConstant(CiConstant.forBoolean(v)); + } + + public XirConstant o(Object obj) { + return createConstant(CiConstant.forObject(obj)); + } + + public void reserveOutgoingStack(int size) { + outgoingStackSize = Math.max(outgoingStackSize, size); + } + + /** + * Finishes the assembly of a non-stub template, providing the {@link #resultOperand} and constructs the {@link XirTemplate}. + * @param result the {@link XirOperand} to be set as the {@link #resultOperand} + * @param name the name of the template + * @return the generated template + */ + public XirTemplate finishTemplate(XirOperand result, String name) { + assert this.resultOperand == null; + assert result != null; + this.resultOperand = result; + final XirTemplate template = buildTemplate(name, false); + end(); + return template; + } + + /** + * Finishes the assembly of a non-stub template and constructs the {@link XirTemplate}. + * @param name the name of the template + * @return the generated template + */ + public XirTemplate finishTemplate(String name) { + final XirTemplate template = buildTemplate(name, false); + end(); + return template; + } + + /** + * Finishes the assembly of a {@link XirTemplate.GlobalFlags#GLOBAL_STUB stub} and constructs the {@link XirTemplate}. + * @param name the name of the template + * @return the generated template + */ + public XirTemplate finishStub(String name) { + final XirTemplate template = buildTemplate(name, true); + end(); + return template; + } + + /** + * Builds the {@link XirTemplate} from the assembly state in this object. + * The actual assembly is dependent on the target architecture and implemented + * in a concrete subclass. + * @param name the name of the template + * @param isStub {@code true} if the template represents a {@link XirTemplate.GlobalFlags#GLOBAL_STUB stub} + * @return the generated template + */ + protected abstract XirTemplate buildTemplate(String name, boolean isStub); + + public abstract CiXirAssembler copy(); + +}