diff graal/com.oracle.max.cri/src/com/sun/cri/xir/CiXirAssembler.java @ 3733:e233f5660da4

Added Java files from Maxine project.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sat, 17 Dec 2011 19:59:18 +0100
parents
children bc8527f3071c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.cri/src/com/sun/cri/xir/CiXirAssembler.java	Sat Dec 17 19:59:18 2011 +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.sun.cri.xir;
+
+import static com.sun.cri.xir.CiXirAssembler.XirOp.*;
+
+import java.util.*;
+
+import com.sun.cri.ci.*;
+import com.sun.cri.ci.CiAddress.*;
+import com.sun.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<XirInstruction>();
+    protected final List<XirLabel> labels = new ArrayList<XirLabel>(5);
+    protected final List<XirParameter> parameters = new ArrayList<XirParameter>(5);
+    protected final List<XirTemp> temps = new ArrayList<XirTemp>(5);
+    protected final List<XirConstant> constants = new ArrayList<XirConstant>(5);
+    protected final List<XirMark> marks = new ArrayList<XirMark>(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();
+
+}