diff graal/com.oracle.jvmci.asm.sparc/src/com/oracle/jvmci/asm/sparc/SPARCAssembler.java @ 21708:6df25b1418be

moved com.oracle.asm.** to jvmci-util.jar (JBS:GRAAL-53)
author Doug Simon <doug.simon@oracle.com>
date Wed, 03 Jun 2015 18:06:44 +0200
parents graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java@5024c80224c7
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.jvmci.asm.sparc/src/com/oracle/jvmci/asm/sparc/SPARCAssembler.java	Wed Jun 03 18:06:44 2015 +0200
@@ -0,0 +1,1747 @@
+/*
+ * Copyright (c) 2009, 2014, 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.jvmci.asm.sparc;
+
+import static com.oracle.jvmci.asm.sparc.SPARCAssembler.CC.*;
+import static com.oracle.jvmci.asm.sparc.SPARCAssembler.ConditionFlag.*;
+import static com.oracle.jvmci.asm.sparc.SPARCAssembler.Op.*;
+import static com.oracle.jvmci.asm.sparc.SPARCAssembler.Op3s.*;
+import static com.oracle.jvmci.asm.sparc.SPARCAssembler.Opfs.*;
+import static com.oracle.jvmci.sparc.SPARC.*;
+import static java.lang.String.*;
+
+import com.oracle.jvmci.asm.*;
+import com.oracle.jvmci.code.*;
+import com.oracle.jvmci.meta.*;
+import com.oracle.jvmci.sparc.*;
+import com.oracle.jvmci.sparc.SPARC.CPUFeature;
+
+/**
+ * This class implements an assembler that can encode most SPARC instructions.
+ */
+public abstract class SPARCAssembler extends Assembler {
+
+    /**
+     * Constructs an assembler for the SPARC architecture.
+     *
+     * @param registerConfig the register configuration used to bind {@link Register#Frame} and
+     *            {@link Register#CallerFrame} to physical registers. This value can be null if this
+     *            assembler instance will not be used to assemble instructions using these logical
+     *            registers.
+     */
+    public SPARCAssembler(TargetDescription target, RegisterConfig registerConfig) {
+        super(target);
+    }
+
+    public static final int CCR_ICC_SHIFT = 0;
+    public static final int CCR_XCC_SHIFT = 4;
+    public static final int CCR_C_SHIFT = 0;
+    public static final int CCR_V_SHIFT = 1;
+    public static final int CCR_Z_SHIFT = 2;
+    public static final int CCR_N_SHIFT = 3;
+
+    protected static final int OP_SHIFT = 30;
+    protected static final int CBCOND_SHIFT = 28;
+    protected static final int OP2_SHIFT = 22;
+    protected static final int A_SHIFT = 29;
+
+    protected static final int A_MASK = 0b0010_0000_0000_0000_0000_0000_0000_0000;
+    protected static final int OP_MASK = 0b1100_0000_0000_0000_0000_0000_0000_0000;
+    protected static final int CBCOND_MASK = 0b0001_0000_0000_0000_0000_0000_0000_0000; // Used for
+    // distinguish CBcond and BPr instructions
+    protected static final int OP2_MASK = 0b0000_0001_1100_0000_0000_0000_0000_0000;
+
+    protected static final int DISP22_SHIFT = 0;
+    protected static final int DISP22_MASK = 0b00000000001111111111111111111111;
+
+    protected static final int DISP19_SHIFT = 0;
+    protected static final int DISP19_MASK = 0b00000000000001111111111111111111;
+
+    protected static final int D16HI_SHIFT = 20;
+    protected static final int D16HI_MASK = 0b0000_0000_0011_0000_0000_0000_0000_0000;
+    protected static final int D16LO_SHIFT = 0;
+    protected static final int D16LO_MASK = 0b0000_0000_0000_0000_0011_1111_1111_1111;
+
+    protected static final int D10LO_MASK = 0b0000_0000_0000_0000_0001_1111_1110_0000;
+    protected static final int D10HI_MASK = 0b0000_0000_0001_1000_0000_0000_0000_0000;
+    protected static final int D10LO_SHIFT = 5;
+    protected static final int D10HI_SHIFT = 19;
+
+    public enum Ops {
+        // @formatter:off
+
+        BranchOp(0b00),
+        CallOp(0b01),
+        ArithOp(0b10),
+        LdstOp(0b11);
+
+        // @formatter:on
+
+        private final int value;
+
+        private Ops(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public boolean appliesTo(int instructionWord) {
+            int opShift = 30;
+            return (instructionWord >>> opShift) == value;
+        }
+    }
+
+    public enum Op {
+        Op00(0b00),
+        Op01(0b01),
+        Op10(0b10),
+        Op11(0b11);
+        int op;
+
+        Op(int op) {
+            this.op = op;
+        }
+    }
+
+    public enum Op2s {
+        // @formatter:off
+
+        Illtrap(0b000),
+        Bpr    (0b011),
+        Fb     (0b110),
+        Fbp    (0b101),
+        Br     (0b010),
+        Bp     (0b001),
+        Cb     (0b111),
+        Sethi  (0b100);
+
+
+        // @formatter:on
+
+        private final int value;
+
+        private Op2s(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public static Op2s byValue(int value) {
+            for (Op2s op : values()) {
+                if (op.getValue() == value) {
+                    return op;
+                }
+            }
+            return null;
+        }
+    }
+
+    public enum Op3s {
+        // @formatter:off
+
+        Add(0x00, "add", Op10),
+        And(0x01, "and", Op10),
+        Or(0x02, "or", Op10),
+        Xor(0x03, "xor", Op10),
+        Sub(0x04, "sub", Op10),
+        Andn(0x05, "andn", Op10),
+        Orn(0x06, "orn", Op10),
+        Xnor(0x07, "xnor", Op10),
+        Addc(0x08, "addc", Op10),
+        Mulx(0x09, "mulx", Op10),
+        Umul(0x0A, "umul", Op10),
+        Smul(0x0B, "smul", Op10),
+        Subc(0x0C, "subc", Op10),
+        Udivx(0x0D, "udivx", Op10),
+        Udiv(0x0E, "udiv", Op10),
+        Sdiv(0x0F, "sdiv", Op10),
+
+        Addcc(0x10, "addcc", Op10),
+        Andcc(0x11, "andcc", Op10),
+        Orcc(0x12, "orcc", Op10),
+        Xorcc(0x13, "xorcc", Op10),
+        Subcc(0x14, "subcc", Op10),
+        Andncc(0x15, "andncc", Op10),
+        Orncc(0x16, "orncc", Op10),
+        Xnorcc(0x17, "xnorcc", Op10),
+        Addccc(0x18, "addccc", Op10),
+
+        Umulcc(0x1A, "umulcc", Op10),
+        Smulcc(0x1B, "smulcc", Op10),
+        Subccc(0x1C, "subccc", Op10),
+        Udivcc(0x1E, "udivcc", Op10),
+        Sdivcc(0x1F, "sdivcc", Op10),
+
+        Taddcc(0x20, "taddcc", Op10),
+        Tsubcc(0x21, "tsubcc", Op10),
+        Taddcctv(0x22, "taddcctv", Op10),
+        Tsubcctv(0x23, "tsubcctv", Op10),
+        Mulscc(0x24, "mulscc", Op10),
+        Sll(0x25, "sll", Op10),
+        Sllx(0x25, "sllx", Op10),
+        Srl(0x26, "srl", Op10),
+        Srlx(0x26, "srlx", Op10),
+        Sra(0x27, "srax", Op10),
+        Srax(0x27, "srax", Op10),
+        Membar(0x28, "membar", Op10),
+
+        Flushw(0x2B, "flushw", Op10),
+        Movcc(0x2C, "movcc", Op10),
+        Sdivx(0x2D, "sdivx", Op10),
+        Popc(0x2E, "popc", Op10),
+        Movr(0x2F, "movr", Op10),
+
+        Fpop1(0b11_0100, "fpop1", Op10),
+        Fpop2(0b11_0101, "fpop2", Op10),
+        Impdep1(0b11_0110, "impdep1", Op10),
+        Impdep2(0b11_0111, "impdep2", Op10),
+        Jmpl(0x38, "jmpl", Op10),
+        Rett(0x39, "rett", Op10),
+        Trap(0x3a, "trap", Op10),
+        Flush(0x3b, "flush", Op10),
+        Save(0x3c, "save", Op10),
+        Restore(0x3d, "restore", Op10),
+        Retry(0x3e, "retry", Op10),
+
+
+        Casa(0b111100, "casa", Op11),
+        Casxa(0b111110, "casxa", Op11),
+        Prefetch(0b101101, "prefetch", Op11),
+        Prefetcha(0b111101, "prefetcha", Op11),
+
+        Lduw  (0b00_0000, "lduw", Op11),
+        Ldub  (0b00_0001, "ldub", Op11),
+        Lduh  (0b00_0010, "lduh", Op11),
+        Stw   (0b00_0100, "stw", Op11),
+        Stb   (0b00_0101, "stb", Op11),
+        Sth   (0b00_0110, "sth", Op11),
+        Ldsw  (0b00_1000, "ldsw", Op11),
+        Ldsb  (0b00_1001, "ldsb", Op11),
+        Ldsh  (0b00_1010, "ldsh", Op11),
+        Ldx   (0b00_1011, "ldx", Op11),
+        Stx   (0b00_1110, "stx", Op11),
+
+        Ldf   (0b10_0000, "ldf", Op11),
+        Ldfsr (0b10_0001, "ldfsr", Op11),
+        Ldaf  (0b10_0010, "ldaf", Op11),
+        Lddf  (0b10_0011, "lddf", Op11),
+        Stf   (0b10_0100, "stf", Op11),
+        Stfsr (0b10_0101, "stfsr", Op11),
+        Staf  (0x10_0110, "staf", Op11),
+        Stdf  (0b10_0111, "stdf", Op11),
+
+        Rd    (0b10_1000, "rd", Op10),
+        Wr    (0b11_0000, "wr", Op10),
+        Fcmp  (0b11_0101, "fcmp", Op10),
+
+        Ldxa  (0b01_1011, "ldxa", Op11),
+        Lduwa (0b01_0000, "lduwa", Op11),
+
+        Tcc(0b11_1010, "tcc", Op10);
+
+        // @formatter:on
+
+        private final int value;
+        private final String operator;
+        private final Op op;
+
+        private Op3s(int value, String name, Op op) {
+            this.value = value;
+            this.operator = name;
+            this.op = op;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+
+        public boolean appliesTo(int instructionWord) {
+            return ((instructionWord >>> 19) & 0b1_1111) == value;
+        }
+    }
+
+    public enum Opfs {
+        // @formatter:off
+
+        Fmovs(0b0_0000_0001, "fmovs"),
+        Fmovd(0b0_0000_0010, "fmovd"),
+        Fmovq(0b0_0000_0011, "fmovq"),
+        Fmovscc(0b00_0001, "fmovscc"),
+        Fmovdcc(0b00_0010, "fmovdcc"),
+        Fnegs(0x05, "fnegs"),
+        Fnegd(0x06, "fnegd"),
+        Fnegq(0x07, "fnegq"),
+        Fabss(0x09, "fabss"),
+        Fabsd(0x0A, "fabsd"),
+        Fabsq(0x0B, "fabsq"),
+
+        // start VIS1
+        Edge8cc(0x0, "edge8cc"),
+        Edge8n(0x1, "edge8n"),
+        Edge8lcc(0x2, "edge8lcc"),
+        Edge8ln(0x3, "edge8ln"),
+        Edge16cc(0x4, "edge16cc"),
+        Edge16n(0x5, "edge16n"),
+        Edge16lcc(0x6, "edge16lcc"),
+        Edge16ln(0x7, "edge16ln"),
+        Edge32cc(0x8, "edge32cc"),
+        Edge32n(0x9, "edge32n"),
+        Edge32lcc(0xA, "edge32lcc"),
+        Edge32ln(0xB, "edge32ln"),
+        Array8(0x10, "array8"),
+        Array16(0x12, "array16"),
+        Array32(0x14, "array32"),
+        AlignAddress(0x18, "alignaddress"),
+        AlignAddressLittle(0x1A, "alignaddress_little"),
+        Fpcmple16(0x20, "fpcmple16"),
+        Fpcmpne16(0x22, "fpcmpne16"),
+        Fpcmple32(0x24, "fpcmple32"),
+        Fpcmpne32(0x26, "fpcmpne32"),
+        Fpcmpgt16(0x28, "fpcmpgt16"),
+        Fpcmpeq16(0x2A, "fpcmpeq16"),
+        Fpcmpgt32(0x2C, "fpcmpgt32"),
+        Fpcmpeq32(0x2E, "fpcmpeq32"),
+        Fmul8x16(0x31, "fmul8x16"),
+        Fmul8x16au(0x33, "fmul8x16au"),
+        Fmul8x16al(0x35, "fmul8x16al"),
+        Fmul8sux16(0x36, "fmul8sux16"),
+        Fmul8ulx16(0x37, "fmul8ulx16"),
+        Fmuld8sux16(0x38, "fmuld8sux16"),
+        Fmuld8ulx16(0x39, "fmuld8ulx16"),
+        Fpack32(0x3A, "fpack32"),
+        Fpack16(0x3B, "fpack16"),
+        Fpackfix(0x3D, "fpackfix"),
+        Faligndatag(0x48, "faligndata"),
+        Fpmerge(0x4B, "fpmerge"),
+        Fpadd16(0x50, "fpadd16"),
+        Fpadd16s(0x51, "fpadd16s"),
+        Fpadd32(0x52, "fpadd32"),
+        Fpadd32s(0x53, "fpadd32s"),
+        Fpsub16(0x54, "fpadd16"),
+        Fpsub16s(0x55, "fpadd16s"),
+        Fpsub32(0x56, "fpadd32"),
+        Fpsub32s(0x57, "fpadd32s"),
+        Fzerod(0x60, "fzerod"),
+        Fzeros(0x61, "fzeros"),
+        Fnot2d(0x66, "fnot1d"),
+        Fnot2s(0x67, "fnot1s"),
+        Fnot1d(0x6A, "fnot1d"),
+        Fnot1s(0x6B, "fnot1s"),
+        Fsrc1d(0x74, "fsrc1d"),
+        Fsrc1s(0x75, "fsrc1s"),
+        Fsrc2d(0x78, "fsrc2d"),
+        Fsrc2s(0x79, "fsrc2s"),
+        Foned(0x7E, "foned"),
+        Fones(0x7F, "fones"),
+        Fandd(0b0_0111_0000, "fandd"),
+        Fands(0b0_0111_0001, "fands"),
+        Fxord(0b0_0110_1100, "fxord"),
+        Fxors(0b0_0110_1101, "fxors"),
+        // end VIS1
+
+        // start VIS2
+        Bmask(0x19, "bmask"),
+        Bshuffle(0x4c, "bshuffle"),
+        // end VIS2 only
+
+        // start VIS3
+        Addxc(0x11, "addxc"),
+        Addxccc(0x13, "addxccc"),
+        Cmask8(0x1B, "cmask8"),
+        Cmask16(0x1D, "cmask16"),
+        Cmask32(0x1F, "cmask32"),
+        Fmean16(0x40, "fmean16"),
+        Fnadds(0x51, "fnadds"),
+        Fnaddd(0x52, "fnaddd"),
+        Fnmuls(0x59, "fnmuls"),
+        Fnmuld(0x5A, "fnmuld"),
+        Fnsmuld(0x79, "fnsmuld"),
+        Fnhadds(0x71, "fnhadds"),
+        Fnhaddd(0x72, "fnhaddd"),
+        Movdtox(0x110, "movdtox"),
+        Movstouw(0x111, "movstouw"),
+        Movstosw(0x113, "movstosw"),
+        Movxtod(0x118, "movxtod"),
+        Movwtos(0b1_0001_1001, "movwtos"),
+        UMulxhi(0b0_0001_0110, "umulxhi"),
+        Lzcnt  (0b0_0001_0111, "lzcnt"),
+        // end VIS3
+
+        // start CAMMELLIA
+        CammelliaFl(0x13C, "cammelia_fl"),
+        CammelliaFli(0x13D, "cammellia_fli"),
+        // end CAMMELLIA
+
+        // start CRYPTO
+        Crc32c(0x147, "crc32c"),
+        // end CRYPTO
+
+        // start OSA 2011
+        Fpadd64(0x44, "fpadd64"),
+        Fpsub64(0x46, "fpsub64"),
+        Fpadds16(0x58, "fpadds16"),
+        Fpadds16s(0x59, "fpadds16"),
+        Fpadds32(0x5A, "fpadds32"),
+        Fpadds32s(0x5B, "fpadds32s"),
+        Fpsubs16(0x5C, "fpsubs16"),
+        Fpsubs16s(0x5D, "fpsubs16s"),
+        Fpsubs32(0x5E, "fpsubs32"),
+        Fpsubs32s(0x5F, "fpsubs32s"),
+        Fpcmpne8(0x122, "fpcmpne8"),
+        Fpcmpeq8(0x12C, "fpcmpeq8"),
+        // end OSA 2011
+
+        Fadds(0x41, "fadds"),
+        Faddd(0x42, "faddd"),
+        Faddq(0x43, "faddq"),
+        Fsubs(0x45, "fsubs"),
+        Fsubd(0x46, "fsubd"),
+        Fsubq(0x47, "fsubq"),
+        Fmuls(0x49, "fmuls"),
+        Fmuld(0x4A, "fmuld"),
+        Fdivs(0x4D, "fdivs"),
+        Fdivd(0x4E, "fdivd"),
+        Fdivq(0x4F, "fdivq"),
+
+        Fsqrts(0x29, "fsqrts"),
+        Fsqrtd(0x2A, "fsqrtd"),
+        Fsqrtq(0x2B, "fsqrtq"),
+
+        Fsmuld(0x69, "fsmuld"),
+        Fmulq(0x6B, "fmulq"),
+        Fdmuldq(0x6E, "fdmulq"),
+
+        Fstoi(0xD1, "fstoi"),
+        Fdtoi(0xD2, "fdtoi"),
+        Fstox(0x81, "fstox"),
+        Fdtox(0x82, "fdtox"),
+        Fxtos(0x84, "fxtos"),
+        Fxtod(0x88, "fxtod"),
+        Fxtoq(0x8C, "fxtoq"),
+        Fitos(0xC4, "fitos"),
+        Fdtos(0xC6, "fdtos"),
+        Fitod(0xC8, "fitod"),
+        Fstod(0xC9, "fstod"),
+        Fitoq(0xCC, "fitoq"),
+
+
+        Fcmps(0x51, "fcmps"),
+        Fcmpd(0x52, "fcmpd"),
+        Fcmpq(0x53, "fcmpq");
+
+        // @formatter:on
+
+        private final int value;
+        private final String operator;
+
+        private Opfs(int value, String op) {
+            this.value = value;
+            this.operator = op;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+    }
+
+    public enum Annul {
+        ANNUL(1),
+        NOT_ANNUL(0);
+        public final int flag;
+
+        Annul(int flag) {
+            this.flag = flag;
+        }
+    }
+
+    public enum BranchPredict {
+        PREDICT_TAKEN(1),
+        PREDICT_NOT_TAKEN(0);
+        public final int flag;
+
+        BranchPredict(int flag) {
+            this.flag = flag;
+        }
+    }
+
+    public enum MembarMask {
+        // @formatter:off
+
+        StoreStore(1 << 3, "storestore"),
+        LoadStore(1 << 2, "loadstore"),
+        StoreLoad(1 << 1, "storeload"),
+        LoadLoad(1 << 0, "loadload"),
+        Sync(1 << 6, "sync"),
+        MemIssue(1 << 5, "memissue"),
+        LookAside(1 << 4, "lookaside");
+
+        // @formatter:on
+
+        private final int value;
+        private final String operator;
+
+        private MembarMask(int value, String op) {
+            this.value = value;
+            this.operator = op;
+        }
+
+        public int getValue() {
+            return value | 0x2000;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+    }
+
+    /**
+     * Condition Codes to use for instruction.
+     */
+    public enum CC {
+        // @formatter:off
+        /**
+         * Condition is considered as 32bit operation condition.
+         */
+        Icc(0b00, "icc", false),
+        /**
+         * Condition is considered as 64bit operation condition.
+         */
+        Xcc(0b10, "xcc", false),
+        Fcc0(0b00, "fcc0", true),
+        Fcc1(0b01, "fcc1", true),
+        Fcc2(0b10, "fcc2", true),
+        Fcc3(0b11, "fcc3", true);
+
+        // @formatter:on
+
+        private final int value;
+        private final String operator;
+        private boolean isFloat;
+
+        private CC(int value, String op, boolean isFloat) {
+            this.value = value;
+            this.operator = op;
+            this.isFloat = isFloat;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+
+        public static CC forKind(Kind kind) {
+            boolean isInt = kind == Kind.Boolean || kind == Kind.Byte || kind == Kind.Char || kind == Kind.Short || kind == Kind.Int;
+            boolean isFloat = kind == Kind.Float || kind == Kind.Double;
+            boolean isLong = kind == Kind.Long || kind == Kind.Object;
+            assert isInt || isFloat || isLong;
+            if (isLong) {
+                return Xcc;
+            } else if (isInt) {
+                return Icc;
+            } else if (isFloat) {
+                return Fcc0;
+            } else {
+                throw new InternalError();
+            }
+        }
+    }
+
+    public enum ConditionFlag {
+        // @formatter:off
+
+        // for FBfcc & FBPfcc instruction
+        F_Never(0, "f_never"),
+        F_NotEqual(1, "f_notEqual"),
+        F_LessOrGreater(2, "f_lessOrGreater"),
+        F_UnorderedOrLess(3, "f_unorderedOrLess"),
+        F_Less(4, "f_less"),
+        F_UnorderedOrGreater(5, "f_unorderedOrGreater"),
+        F_Greater(6, "f_greater"),
+        F_Unordered(7, "f_unordered"),
+        F_Always(8, "f_always"),
+        F_Equal(9, "f_equal"),
+        F_UnorderedOrEqual(10, "f_unorderedOrEqual"),
+        F_GreaterOrEqual(11, "f_greaterOrEqual"),
+        F_UnorderedGreaterOrEqual(12, "f_unorderedGreaterOrEqual"),
+        F_LessOrEqual(13, "f_lessOrEqual"),
+        F_UnorderedOrLessOrEqual(14, "f_unorderedOrLessOrEqual"),
+        F_Ordered(15, "f_ordered"),
+
+        // for integers
+        Never(0, "never"),
+        Equal(1, "equal", true),
+        Zero(1, "zero"),
+        LessEqual(2, "lessEqual", true),
+        Less(3, "less", true),
+        LessEqualUnsigned(4, "lessEqualUnsigned", true),
+        LessUnsigned(5, "lessUnsigned", true),
+        CarrySet(5, "carrySet"),
+        Negative(6, "negative", true),
+        OverflowSet(7, "overflowSet", true),
+        Always(8, "always"),
+        NotEqual(9, "notEqual", true),
+        NotZero(9, "notZero"),
+        Greater(10, "greater", true),
+        GreaterEqual(11, "greaterEqual", true),
+        GreaterUnsigned(12, "greaterUnsigned", true),
+        GreaterEqualUnsigned(13, "greaterEqualUnsigned", true),
+        CarryClear(13, "carryClear"),
+        Positive(14, "positive", true),
+        OverflowClear(15, "overflowClear", true);
+
+        // @formatter:on
+
+        private final int value;
+        private final String operator;
+        private boolean forCBcond = false;
+
+        private ConditionFlag(int value, String op) {
+            this(value, op, false);
+        }
+
+        private ConditionFlag(int value, String op, boolean cbcond) {
+            this.value = value;
+            this.operator = op;
+            this.forCBcond = cbcond;
+        }
+
+        public boolean isCBCond() {
+            return forCBcond;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+
+        public ConditionFlag negate() {
+            //@formatter:off
+            switch (this) {
+                case F_Never                  : return F_Always;
+                case F_Always                 : return F_Never;
+                case F_NotEqual               : return F_Equal;
+                case F_Equal                  : return F_NotEqual;
+                case F_LessOrGreater          : return F_UnorderedOrEqual;
+                case F_UnorderedOrEqual       : return F_LessOrGreater;
+                case F_Less                   : return F_UnorderedGreaterOrEqual;
+                case F_UnorderedGreaterOrEqual: return F_Less;
+                case F_LessOrEqual            : return F_UnorderedOrGreater;
+                case F_UnorderedOrGreater     : return F_LessOrEqual;
+                case F_Greater                : return F_UnorderedOrLessOrEqual;
+                case F_UnorderedOrLessOrEqual : return F_Greater;
+                case F_GreaterOrEqual         : return F_UnorderedOrLess;
+                case F_UnorderedOrLess        : return F_GreaterOrEqual;
+                case F_Unordered              : return F_Ordered;
+                case F_Ordered                : return F_Unordered;
+                case Never                    : return Always;
+                case Always                   : return Never;
+                case Equal                    : return NotEqual;
+                case NotEqual                 : return Equal;
+                case Zero                     : return NotZero;
+                case NotZero                  : return Zero;
+                case LessEqual                : return Greater;
+                case Greater                  : return LessEqual;
+                case Less                     : return GreaterEqual;
+                case GreaterEqual             : return Less;
+                case LessEqualUnsigned        : return GreaterUnsigned;
+                case GreaterUnsigned          : return LessEqualUnsigned;
+                case LessUnsigned             : return GreaterEqualUnsigned;
+                case GreaterEqualUnsigned     : return LessUnsigned;
+                case CarrySet                 : return CarryClear;
+                case CarryClear               : return CarrySet;
+                case Negative                 : return Positive;
+                case Positive                 : return Negative;
+                case OverflowSet              : return OverflowClear;
+                case OverflowClear            : return OverflowSet;
+                default:
+                    throw new InternalError();
+            }
+            //@formatter:on
+        }
+
+        public ConditionFlag mirror() {
+            switch (this) {
+            //@formatter:off
+                case F_Less                   : return F_Greater;
+                case F_Greater                : return F_Less;
+                case F_LessOrEqual            : return F_GreaterOrEqual;
+                case F_UnorderedGreaterOrEqual: return F_UnorderedOrLessOrEqual;
+                case F_UnorderedOrGreater     : return F_UnorderedOrLess;
+                case F_UnorderedOrLessOrEqual : return F_UnorderedGreaterOrEqual;
+                case F_GreaterOrEqual         : return F_LessOrEqual;
+                case F_UnorderedOrLess        : return F_UnorderedOrGreater;
+                case LessEqual                : return GreaterEqual;
+                case Greater                  : return Less;
+                case Less                     : return Greater;
+                case GreaterEqual             : return LessEqual;
+                case LessEqualUnsigned        : return GreaterEqualUnsigned;
+                case GreaterUnsigned          : return LessUnsigned;
+                case LessUnsigned             : return GreaterUnsigned;
+                case GreaterEqualUnsigned     : return LessEqualUnsigned;
+                default:
+                    return this;
+                //@formatter:on
+            }
+        }
+
+    }
+
+    public enum RCondition {
+        // @formatter:off
+
+        Rc_z(0b001, "rc_z"),
+        Rc_lez(0b010, "rc_lez"),
+        Rc_lz(0b011, "rc_lz"),
+        Rc_nz(0b101, "rc_nz"),
+        Rc_gz(0b110, "rc_gz"),
+        Rc_gez(0b111, "rc_gez"),
+        Rc_last(Rc_gez.getValue(), "rc_last");
+
+        // @formatter:on
+
+        private final int value;
+        private final String operator;
+
+        private RCondition(int value, String op) {
+            this.value = value;
+            this.operator = op;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+    }
+
+    /**
+     * Represents the <b>Address Space Identifier</b> defined in the SPARC architecture.
+     */
+    public enum Asi {
+        // @formatter:off
+
+        INVALID(-1),
+        ASI_PRIMARY(0x80),
+        ASI_PRIMARY_NOFAULT(0x82),
+        ASI_PRIMARY_LITTLE(0x88),
+        // Block initializing store
+        ASI_ST_BLKINIT_PRIMARY(0xE2),
+        // Most-Recently-Used (MRU) BIS variant
+        ASI_ST_BLKINIT_MRU_PRIMARY(0xF2);
+
+        // @formatter:on
+
+        private final int value;
+
+        private Asi(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public boolean isValid() {
+            return value != INVALID.getValue();
+        }
+    }
+
+    public enum Fcn {
+        SeveralWritesAndPossiblyReads(2),
+        SeveralReadsWeak(0),
+        OneRead(1),
+        OneWrite(3),
+        Page(4),
+        NearestUnifiedCache(17),
+        SeveralReadsStrong(20),
+        OneReadStrong(21),
+        SeveralWritesAndPossiblyReadsStrong(22),
+        OneWriteStrong(23);
+
+        private final int value;
+
+        private Fcn(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+    }
+
+    public boolean hasFeature(CPUFeature feature) {
+        return ((SPARC) this.target.arch).features.contains(feature);
+    }
+
+    public static final int simm(int x, int nbits) {
+        // assert_signed_range(x, nbits);
+        return x & ((1 << nbits) - 1);
+    }
+
+    public static final boolean isImm(int x, int nbits) {
+        // assert_signed_range(x, nbits);
+        return simm(x, nbits) == x;
+    }
+
+    /**
+     * Minimum value for signed immediate ranges.
+     */
+    public static long minSimm(long nbits) {
+        return -(1L << (nbits - 1));
+    }
+
+    /**
+     * Maximum value for signed immediate ranges.
+     */
+    public static long maxSimm(long nbits) {
+        return (1L << (nbits - 1)) - 1;
+    }
+
+    /**
+     * Test if imm is within signed immediate range for nbits.
+     */
+    public static boolean isSimm(long imm, int nbits) {
+        return minSimm(nbits) <= imm && imm <= maxSimm(nbits);
+    }
+
+    public static boolean isSimm10(long imm) {
+        return isSimm(imm, 10);
+    }
+
+    public static boolean isSimm11(long imm) {
+        return isSimm(imm, 11);
+    }
+
+    public static boolean isSimm11(JavaConstant constant) {
+        return constant.isNull() || isSimm11(constant.asLong());
+    }
+
+    public static boolean isSimm5(JavaConstant constant) {
+        return constant.isNull() || isSimm(constant.asLong(), 5);
+    }
+
+    public static boolean isSimm13(int imm) {
+        return isSimm(imm, 13);
+    }
+
+    public static boolean isSimm13(JavaConstant constant) {
+        return constant.isNull() || isSimm13(constant.asLong());
+    }
+
+    public static boolean isSimm13(long imm) {
+        return NumUtil.isInt(imm) && isSimm(imm, 13);
+    }
+
+    public static boolean isWordDisp30(long imm) {
+        return isSimm(imm, 30 + 2);
+    }
+
+    public static final int hi22(int x) {
+        return x >>> 10;
+    }
+
+    public static final int lo10(int x) {
+        return x & ((1 << 10) - 1);
+    }
+
+    // @formatter:off
+    /**
+     * Instruction format for Fmt00 instructions. This abstraction is needed as it
+     * makes the patching easier later on.
+     * <pre>
+     * | 00  |    a   | op2 |               b                         |
+     * |31 30|29    25|24 22|21                                      0|
+     * </pre>
+     */
+    // @formatter:on
+    protected void fmt00(int a, int op2, int b) {
+        assert isImm(a, 5) && isImm(op2, 3) && isImm(b, 22) : String.format("a: 0x%x op2: 0x%x b: 0x%x", a, op2, b);
+        this.emitInt(a << 25 | op2 << 22 | b);
+    }
+
+    private void op3(Op3s op3, Opfs opf, Register rs1, Register rs2, Register rd) {
+        int b = opf.value << 5 | (rs2 == null ? 0 : rs2.encoding);
+        fmt(op3.op.op, rd.encoding, op3.value, rs1 == null ? 0 : rs1.encoding, b);
+    }
+
+    protected void op3(Op3s op3, Register rs1, Register rs2, Register rd) {
+        int b = rs2 == null ? 0 : rs2.encoding;
+        int xBit = getXBit(op3);
+        fmt(op3.op.op, rd.encoding, op3.value, rs1 == null ? 0 : rs1.encoding, b | xBit);
+    }
+
+    protected void op3(Op3s op3, Register rs1, int simm13, Register rd) {
+        assert isSimm13(simm13);
+        int i = 1 << 13;
+        int simm13WithX = simm13 | getXBit(op3);
+        fmt(op3.op.op, rd.encoding, op3.value, rs1.encoding, i | simm13WithX & ((1 << 13) - 1));
+    }
+
+    // @formatter:off
+    /**
+     * Branch on Integer Condition Codes.
+     * <pre>
+     * | 00  |annul| cond| 010 |               disp22                 |
+     * |31 30|29   |28 25|24 22|21                                   0|
+     * </pre>
+     */
+    // @formatter:on
+    public void bicc(ConditionFlag cond, Annul annul, Label l) {
+        bcc(Op2s.Br, cond, annul, l);
+    }
+
+    // @formatter:off
+    /**
+     * Branch on Floating-Point Condition Codes.
+     * <pre>
+     * | 00  |annul| cond| 110 |               disp22                 |
+     * |31 30|29   |28 25|24 22|21                                   0|
+     * </pre>
+     */
+    // @formatter:on
+    public void fbcc(ConditionFlag cond, Annul annul, Label l) {
+        bcc(Op2s.Fb, cond, annul, l);
+    }
+
+    // @formatter:off
+    /**
+     * Branch on (Integer|Floatingpoint) Condition Codes.
+     * <pre>
+     * | 00  |annul| cond| op2 |               disp22                 |
+     * |31 30|29   |28 25|24 22|21                                   0|
+     * </pre>
+     */
+    // @formatter:on
+    private void bcc(Op2s op2, ConditionFlag cond, Annul annul, Label l) {
+        int pos = !l.isBound() ? patchUnbound(l) : (l.position() - position()) / 4;
+        final int disp = 22;
+        assert isSimm(pos, disp);
+        pos &= (1 << disp) - 1;
+        int a = (annul.flag << 4) | cond.getValue();
+        fmt00(a, op2.getValue(), pos);
+    }
+
+    // @formatter:off
+    /**
+     * Branch on Integer Condition Codes with Prediction.
+     * <pre>
+     * | 00  |an|cond | 001 |cc1 2|p |           disp19               |
+     * |31 30|29|28 25|24 22|21 20|19|                               0|
+     * </pre>
+     */
+    // @formatter:on
+    public void bpcc(ConditionFlag cond, Annul annul, Label l, CC cc, BranchPredict predictTaken) {
+        bpcc(Op2s.Bp, cond, annul, l, cc, predictTaken);
+    }
+
+    // @formatter:off
+    /**
+     * Branch on Integer Condition Codes with Prediction.
+     * <pre>
+     * | 00  |an|cond | 101 |cc1 2|p |           disp19               |
+     * |31 30|29|28 25|24 22|21 20|19|                               0|
+     * </pre>
+     */
+    // @formatter:on
+    public void fbpcc(ConditionFlag cond, Annul annul, Label l, CC cc, BranchPredict predictTaken) {
+        bpcc(Op2s.Fbp, cond, annul, l, cc, predictTaken);
+    }
+
+    // @formatter:off
+    /**
+     * Used for fbpcc (Float) and bpcc (Integer).
+     * <pre>
+     * | 00  |an|cond | op2 |cc1 2|p |           disp19               |
+     * |31 30|29|28 25|24 22|21 20|19|                               0|
+     * </pre>
+     */
+    // @formatter:on
+    private void bpcc(Op2s op2, ConditionFlag cond, Annul annul, Label l, CC cc, BranchPredict predictTaken) {
+        int pos = !l.isBound() ? patchUnbound(l) : (l.position() - position()) / 4;
+        final int disp = 19;
+        assert isSimm(pos, disp);
+        pos &= (1 << disp) - 1;
+        int a = (annul.flag << 4) | cond.getValue();
+        int b = (cc.getValue() << 20) | ((predictTaken.flag) << 19) | pos;
+        fmt00(a, op2.getValue(), b);
+    }
+
+    // @formatter:off
+    /**
+     * Branch on Integer Register with Prediction.
+     * <pre>
+     * | 00  |an| 0|rcond | 011 |d16hi|p | rs1 |    d16lo             |
+     * |31 30|29|28|27 25 |24 22|21 20|19|18 14|                     0|
+     * </pre>
+     */
+    // @formatter:on
+    public void bpr(RCondition cond, Annul annul, Label l, BranchPredict predictTaken, Register rs1) {
+        int pos = !l.isBound() ? patchUnbound(l) : (l.position() - position()) / 4;
+        final int disp = 16;
+        assert isSimm(pos, disp);
+        pos &= (1 << disp) - 1;
+        int a = (annul.flag << 4) | cond.getValue();
+        int d16hi = (pos >> 13) << 13;
+        int d16lo = d16hi ^ pos;
+        int b = (d16hi << 20) | (predictTaken.flag << 19) | (rs1.encoding() << 14) | d16lo;
+        fmt00(a, Op2s.Bpr.getValue(), b);
+    }
+
+    private int patchUnbound(Label label) {
+        label.addPatchAt(position());
+        return 0;
+    }
+
+    public void cbcondw(ConditionFlag cf, Register rs1, Register rs2, Label lab) {
+        cbcond(0, 0, cf, rs1, rs2.encoding, lab);
+    }
+
+    public void cbcondw(ConditionFlag cf, Register rs1, int rs2, Label lab) {
+        assert isSimm(rs2, 5);
+        cbcond(0, 1, cf, rs1, rs2 & ((1 << 5) - 1), lab);
+    }
+
+    public void cbcondx(ConditionFlag cf, Register rs1, Register rs2, Label lab) {
+        cbcond(1, 0, cf, rs1, rs2.encoding, lab);
+    }
+
+    public void cbcondx(ConditionFlag cf, Register rs1, int rs2, Label lab) {
+        assert isSimm(rs2, 5);
+        cbcond(1, 1, cf, rs1, rs2 & ((1 << 5) - 1), lab);
+    }
+
+    private void cbcond(int cc2, int i, ConditionFlag cf, Register rs1, int rs2, Label l) {
+        int disp10 = !l.isBound() ? patchUnbound(l) : (l.position() - position()) / 4;
+        assert isSimm(disp10, 10) && isImm(rs2, 5);
+        disp10 &= (1 << 10) - 1;
+        final int cLo = cf.value & 0b111;
+        final int cHi = cf.value >> 3;
+        final int d10Lo = disp10 & ((1 << 8) - 1);
+        final int d10Hi = disp10 >> 8;
+        int a = cHi << 4 | 0b1000 | cLo;
+        int b = cc2 << 21 | d10Hi << D10HI_SHIFT | rs1.encoding << 14 | i << 13 | d10Lo << D10LO_SHIFT | rs2;
+        fmt00(a, Op2s.Bpr.value, b);
+    }
+
+    // @formatter:off
+    /**
+     * NOP.
+     * <pre>
+     * | 00  |00000| 100 |                0                    |
+     * |31 30|29 25|24 22|21                                  0|
+     * </pre>
+     */
+    // @formatter:on
+    public void nop() {
+        emitInt(1 << 24);
+    }
+
+    public void sethi(int imm22, Register dst) {
+        fmt00(dst.encoding, Op2s.Sethi.value, imm22);
+    }
+
+    // @formatter:off
+    /**
+     * Instruction format for calls.
+     * <pre>
+     * | 01  |                      disp30                             |
+     * |31 30|29                                                      0|
+     * </pre>
+     */
+    // @formatter:on
+    public void call(int disp30) {
+        assert isImm(disp30, 30);
+        int instr = 1 << 30;
+        instr |= disp30;
+        emitInt(instr);
+    }
+
+    public void add(Register rs1, Register rs2, Register rd) {
+        op3(Add, rs1, rs2, rd);
+    }
+
+    public void add(Register rs1, int simm13, Register rd) {
+        op3(Add, rs1, simm13, rd);
+    }
+
+    public void addc(Register rs1, Register rs2, Register rd) {
+        op3(Addc, rs1, rs2, rd);
+    }
+
+    public void addc(Register rs1, int simm13, Register rd) {
+        op3(Addc, rs1, simm13, rd);
+    }
+
+    public void addcc(Register rs1, Register rs2, Register rd) {
+        op3(Addcc, rs1, rs2, rd);
+    }
+
+    public void addcc(Register rs1, int simm13, Register rd) {
+        op3(Addcc, rs1, simm13, rd);
+    }
+
+    public void and(Register rs1, Register rs2, Register rd) {
+        op3(And, rs1, rs2, rd);
+    }
+
+    public void and(Register rs1, int simm13, Register rd) {
+        op3(And, rs1, simm13, rd);
+    }
+
+    public void andcc(Register rs1, Register rs2, Register rd) {
+        op3(Andcc, rs1, rs2, rd);
+    }
+
+    public void andcc(Register rs1, int simm13, Register rd) {
+        op3(Andcc, rs1, simm13, rd);
+    }
+
+    public void andn(Register rs1, Register rs2, Register rd) {
+        op3(Andn, rs1, rs2, rd);
+    }
+
+    public void andn(Register rs1, int simm13, Register rd) {
+        op3(Andn, rs1, simm13, rd);
+    }
+
+    public void andncc(Register rs1, Register rs2, Register rd) {
+        op3(Andncc, rs1, rs2, rd);
+    }
+
+    public void andncc(Register rs1, int simm13, Register rd) {
+        op3(Andncc, rs1, simm13, rd);
+    }
+
+    public void movwtos(Register rs2, Register rd) {
+        assert isSingleFloatRegister(rd) && isCPURegister(rs2) : String.format("%s %s", rs2, rd);
+        op3(Impdep1, Movwtos, null, rs2, rd);
+    }
+
+    public void umulxhi(Register rs1, Register rs2, Register rd) {
+        op3(Impdep1, UMulxhi, rs1, rs2, rd);
+    }
+
+    public void fdtos(Register rs2, Register rd) {
+        assert isSingleFloatRegister(rd) && isDoubleFloatRegister(rs2) : String.format("%s %s", rs2, rd);
+        op3(Fpop1, Fdtos, null, rs2, rd);
+    }
+
+    public void movstouw(Register rs2, Register rd) {
+        assert isSingleFloatRegister(rs2) && isCPURegister(rd) : String.format("%s %s", rs2, rd);
+        op3(Impdep1, Movstosw, null, rs2, rd);
+    }
+
+    public void movstosw(Register rs2, Register rd) {
+        assert isSingleFloatRegister(rs2) && isCPURegister(rd) : String.format("%s %s", rs2, rd);
+        op3(Impdep1, Movstosw, null, rs2, rd);
+    }
+
+    public void movdtox(Register rs2, Register rd) {
+        assert isDoubleFloatRegister(rs2) && isCPURegister(rd) : String.format("%s %s", rs2, rd);
+        op3(Impdep1, Movdtox, null, rs2, rd);
+    }
+
+    public void movxtod(Register rs2, Register rd) {
+        assert isCPURegister(rs2) && isDoubleFloatRegister(rd) : String.format("%s %s", rs2, rd);
+        op3(Impdep1, Movxtod, null, rs2, rd);
+    }
+
+    public void fadds(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fadds, rs1, rs2, rd);
+    }
+
+    public void faddd(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Faddd, rs1, rs2, rd);
+    }
+
+    public void faddq(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Faddq, rs1, rs2, rd);
+    }
+
+    public void fdivs(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fdivs, rs1, rs2, rd);
+    }
+
+    public void fdivd(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fdivd, rs1, rs2, rd);
+    }
+
+    public void fmovs(Register rs2, Register rd) {
+        op3(Fpop1, Fmovs, null, rs2, rd);
+    }
+
+    public void fmovd(Register rs2, Register rd) {
+        op3(Fpop1, Fmovd, null, rs2, rd);
+    }
+
+    public void fmuls(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fmuls, rs1, rs2, rd);
+    }
+
+    public void fsmuld(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fsmuld, rs1, rs2, rd);
+    }
+
+    public void fmuld(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fmuld, rs1, rs2, rd);
+    }
+
+    public void fnegs(Register rs2, Register rd) {
+        op3(Fpop1, Fnegs, null, rs2, rd);
+    }
+
+    public void fnegd(Register rs2, Register rd) {
+        op3(Fpop1, Fnegd, null, rs2, rd);
+    }
+
+    /**
+     * Helper method to determine if the instruction needs the X bit set.
+     */
+    private static int getXBit(Op3s op3) {
+        switch (op3) {
+            case Sllx:
+            case Srax:
+            case Srlx:
+                return 1 << 12;
+            default:
+                return 0;
+        }
+    }
+
+    public void fstoi(Register rs2, Register rd) {
+        op3(Fpop1, Fstoi, null, rs2, rd);
+    }
+
+    public void fstox(Register rs2, Register rd) {
+        op3(Fpop1, Fstox, null, rs2, rd);
+    }
+
+    public void fdtox(Register rs2, Register rd) {
+        op3(Fpop1, Fdtox, null, rs2, rd);
+    }
+
+    public void fstod(Register rs2, Register rd) {
+        op3(Fpop1, Fstod, null, rs2, rd);
+    }
+
+    public void fdtoi(Register rs2, Register rd) {
+        op3(Fpop1, Fdtoi, null, rs2, rd);
+    }
+
+    public void fitos(Register rs2, Register rd) {
+        op3(Fpop1, Fitos, null, rs2, rd);
+    }
+
+    public void fitod(Register rs2, Register rd) {
+        op3(Fpop1, Fitod, null, rs2, rd);
+    }
+
+    public void fxtos(Register rs2, Register rd) {
+        op3(Fpop1, Fxtos, null, rs2, rd);
+    }
+
+    public void fxtod(Register rs2, Register rd) {
+        op3(Fpop1, Fxtod, null, rs2, rd);
+    }
+
+    public void fzeros(Register rd) {
+        op3(Impdep1, Fzeros, null, null, rd);
+    }
+
+    public void fzerod(Register rd) {
+        op3(Impdep1, Fzerod, null, null, rd);
+    }
+
+    public void flushw() {
+        op3(Flushw, g0, g0, g0);
+    }
+
+    public void fsqrtd(Register rs2, Register rd) {
+        op3(Fpop1, Fsqrtd, null, rs2, rd);
+    }
+
+    public void fsqrts(Register rs2, Register rd) {
+        op3(Fpop1, Fsqrts, null, rs2, rd);
+    }
+
+    public void fabss(Register rs2, Register rd) {
+        op3(Fpop1, Fabss, null, rs2, rd);
+    }
+
+    public void fabsd(Register rs2, Register rd) {
+        op3(Fpop1, Fabsd, null, rs2, rd);
+    }
+
+    public void fsubs(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fsubs, rs1, rs2, rd);
+    }
+
+    public void fsubd(Register rs1, Register rs2, Register rd) {
+        op3(Fpop1, Fsubd, rs1, rs2, rd);
+    }
+
+    // @formatter:off
+    /**
+     * Instruction format for fcmp.
+     * <pre>
+     * | 10  | --- |cc1|cc0|desc |   rs1   |   opf  | rs2 |
+     * |31 30|29 27|26 |25 |24 19|18     14|13     5|4   0|
+     * </pre>
+     */
+    // @formatter:on
+    public void fcmp(CC cc, Opfs opf, Register rs1, Register rs2) {
+        int a = cc.value;
+        int b = opf.value << 5 | rs2.encoding;
+        fmt10(a, Fcmp.value, rs1.encoding, b);
+    }
+
+    // @formatter:off
+    /**
+     * Instruction format for most arithmetic stuff.
+     * <pre>
+     * |  10 | rd  | op3 | rs1 |   b   |
+     * |31 30|29 25|24 19|18 14|13    0|
+     * </pre>
+     */
+    // @formatter:on
+    protected void fmt10(int rd, int op3, int rs1, int b) {
+        fmt(0b10, rd, op3, rs1, b);
+    }
+
+    // @formatter:off
+    /**
+     * Instruction format for most arithmetic stuff.
+     * <pre>
+     * |  op | rd  | op3 | rs1 |   b   |
+     * |31 30|29 25|24 19|18 14|13    0|
+     * </pre>
+     */
+    // @formatter:on
+    protected void fmt(int op, int rd, int op3, int rs1, int b) {
+        assert isImm(rd, 5) && isImm(op3, 6) && isImm(b, 14) : String.format("rd: 0x%x op3: 0x%x b: 0x%x", rd, op3, b);
+        int instr = op << 30 | rd << 25 | op3 << 19 | rs1 << 14 | b;
+        emitInt(instr);
+    }
+
+    public void illtrap(int const22) {
+        fmt00(0, Op2s.Illtrap.value, const22);
+    }
+
+    public void jmpl(Register rs1, Register rs2, Register rd) {
+        op3(Jmpl, rs1, rs2, rd);
+    }
+
+    public void jmpl(Register rs1, int simm13, Register rd) {
+        op3(Jmpl, rs1, simm13, rd);
+    }
+
+    public void fmovdcc(ConditionFlag cond, CC cc, Register rs2, Register rd) {
+        fmovcc(cond, cc, rs2, rd, Fmovdcc.value);
+    }
+
+    public void fmovscc(ConditionFlag cond, CC cc, Register rs2, Register rd) {
+        fmovcc(cond, cc, rs2, rd, Fmovscc.value);
+    }
+
+    private void fmovcc(ConditionFlag cond, CC cc, Register rs2, Register rd, int opfLow) {
+        int opfCC = cc.value;
+        int a = opfCC << 11 | opfLow << 5 | rs2.encoding;
+        fmt10(rd.encoding, Fpop2.value, cond.value, a);
+    }
+
+    public void movcc(ConditionFlag conditionFlag, CC cc, Register rs2, Register rd) {
+        movcc(conditionFlag, cc, 0, rs2.encoding, rd);
+    }
+
+    public void movcc(ConditionFlag conditionFlag, CC cc, int simm11, Register rd) {
+        assert isSimm11(simm11);
+        movcc(conditionFlag, cc, 1, simm11 & ((1 << 11) - 1), rd);
+    }
+
+    private void movcc(ConditionFlag conditionFlag, CC cc, int i, int imm, Register rd) {
+        int cc01 = 0b11 & cc.value;
+        int cc2 = cc.isFloat ? 0 : 1;
+        int a = cc2 << 4 | conditionFlag.value;
+        int b = cc01 << 11 | i << 13 | imm;
+        fmt10(rd.encoding, Movcc.value, a, b);
+    }
+
+    public void mulx(Register rs1, Register rs2, Register rd) {
+        op3(Mulx, rs1, rs2, rd);
+    }
+
+    public void mulx(Register rs1, int simm13, Register rd) {
+        op3(Mulx, rs1, simm13, rd);
+    }
+
+    public void or(Register rs1, Register rs2, Register rd) {
+        assert isCPURegister(rs1, rs2, rd) : String.format("%s %s %s", rs1, rs2, rd);
+        op3(Or, rs1, rs2, rd);
+    }
+
+    public void or(Register rs1, int simm13, Register rd) {
+        assert isCPURegister(rs1, rd) : String.format("%s %s", rs1, rd);
+        op3(Or, rs1, simm13, rd);
+    }
+
+    public void popc(Register rs2, Register rd) {
+        op3(Popc, g0, rs2, rd);
+    }
+
+    public void popc(int simm13, Register rd) {
+        op3(Popc, g0, simm13, rd);
+    }
+
+    public void prefetch(SPARCAddress addr, Fcn fcn) {
+        Register rs1 = addr.getBase();
+        if (addr.getIndex().equals(Register.None)) {
+            int dis = addr.getDisplacement();
+            assert isSimm13(dis);
+            fmt(Prefetch.op.op, fcn.value, Prefetch.value, rs1.encoding, 1 << 13 | dis & ((1 << 13) - 1));
+        } else {
+            Register rs2 = addr.getIndex();
+            fmt(Prefetch.op.op, fcn.value, Prefetch.value, rs1.encoding, rs2.encoding);
+        }
+    }
+
+    // A.44 Read State Register
+
+    public void rdpc(Register rd) {
+        op3(Rd, r5, g0, rd);
+    }
+
+    public void restore(Register rs1, Register rs2, Register rd) {
+        op3(Restore, rs1, rs2, rd);
+    }
+
+    public static final int PC_RETURN_OFFSET = 8;
+
+    public void save(Register rs1, Register rs2, Register rd) {
+        op3(Save, rs1, rs2, rd);
+    }
+
+    public void save(Register rs1, int simm13, Register rd) {
+        op3(Save, rs1, simm13, rd);
+    }
+
+    public void sdivx(Register rs1, Register rs2, Register rd) {
+        op3(Sdivx, rs1, rs2, rd);
+    }
+
+    public void sdivx(Register rs1, int simm13, Register rd) {
+        op3(Sdivx, rs1, simm13, rd);
+    }
+
+    public void udivx(Register rs1, Register rs2, Register rd) {
+        op3(Udivx, rs1, rs2, rd);
+    }
+
+    public void udivx(Register rs1, int simm13, Register rd) {
+        op3(Udivx, rs1, simm13, rd);
+    }
+
+    public void sll(Register rs1, Register rs2, Register rd) {
+        op3(Sll, rs1, rs2, rd);
+    }
+
+    public void sll(Register rs1, int shcnt32, Register rd) {
+        assert isImm(shcnt32, 5);
+        op3(Sll, rs1, shcnt32, rd);
+    }
+
+    public void sllx(Register rs1, Register rs2, Register rd) {
+        op3(Sllx, rs1, rs2, rd);
+    }
+
+    public void sllx(Register rs1, int shcnt64, Register rd) {
+        assert isImm(shcnt64, 6);
+        op3(Sllx, rs1, shcnt64, rd);
+    }
+
+    public void sra(Register rs1, Register rs2, Register rd) {
+        op3(Sra, rs1, rs2, rd);
+    }
+
+    public void sra(Register rs1, int simm13, Register rd) {
+        op3(Sra, rs1, simm13, rd);
+    }
+
+    public void srax(Register rs1, Register rs2, Register rd) {
+        op3(Srax, rs1, rs2, rd);
+    }
+
+    public void srax(Register rs1, int shcnt64, Register rd) {
+        assert isImm(shcnt64, 6);
+        op3(Srax, rs1, shcnt64, rd);
+    }
+
+    public void srl(Register rs1, Register rs2, Register rd) {
+        op3(Srl, rs1, rs2, rd);
+    }
+
+    public void srl(Register rs1, int simm13, Register rd) {
+        op3(Srl, rs1, simm13, rd);
+    }
+
+    public void srlx(Register rs1, Register rs2, Register rd) {
+        op3(Srlx, rs1, rs2, rd);
+    }
+
+    public void srlx(Register rs1, int shcnt64, Register rd) {
+        assert isImm(shcnt64, 6);
+        op3(Srlx, rs1, shcnt64, rd);
+    }
+
+    public void fandd(Register rs1, Register rs2, Register rd) {
+        op3(Impdep1, Fandd, rs1, rs2, rd);
+    }
+
+    public void sub(Register rs1, Register rs2, Register rd) {
+        op3(Sub, rs1, rs2, rd);
+    }
+
+    public void sub(Register rs1, int simm13, Register rd) {
+        op3(Sub, rs1, simm13, rd);
+    }
+
+    public void subcc(Register rs1, Register rs2, Register rd) {
+        op3(Subcc, rs1, rs2, rd);
+    }
+
+    public void subcc(Register rs1, int simm13, Register rd) {
+        op3(Subcc, rs1, simm13, rd);
+    }
+
+    public void ta(int trap) {
+        tcc(Icc, Always, trap);
+    }
+
+    public void tcc(CC cc, ConditionFlag flag, int trap) {
+        assert isImm(trap, 8);
+        int b = cc.value << 11;
+        b |= 1 << 13;
+        b |= trap;
+        fmt10(flag.value, Op3s.Tcc.getValue(), 0, b);
+    }
+
+    public void wrccr(Register rs1, Register rs2) {
+        op3(Wr, rs1, rs2, r2);
+    }
+
+    public void wrccr(Register rs1, int simm13) {
+        op3(Wr, rs1, simm13, r2);
+    }
+
+    public void xor(Register rs1, Register rs2, Register rd) {
+        op3(Xor, rs1, rs2, rd);
+    }
+
+    public void xor(Register rs1, int simm13, Register rd) {
+        op3(Xor, rs1, simm13, rd);
+    }
+
+    public void xorcc(Register rs1, Register rs2, Register rd) {
+        op3(Xorcc, rs1, rs2, rd);
+    }
+
+    public void xorcc(Register rs1, int simm13, Register rd) {
+        op3(Xorcc, rs1, simm13, rd);
+    }
+
+    public void xnor(Register rs1, Register rs2, Register rd) {
+        op3(Xnor, rs1, rs2, rd);
+    }
+
+    public void xnor(Register rs1, int simm13, Register rd) {
+        op3(Xnor, rs1, simm13, rd);
+    }
+
+    /*
+     * Load/Store
+     */
+    protected void ld(Op3s op3, SPARCAddress addr, Register rd, Asi asi) {
+        Register rs1 = addr.getBase();
+        if (!addr.getIndex().equals(Register.None)) {
+            Register rs2 = addr.getIndex();
+            if (asi != null) {
+                int b = rs2.encoding;
+                b |= asi.value << 5;
+                fmt(op3.op.op, rd.encoding, op3.value, rs1.encoding, b);
+            } else {
+                op3(op3, rs1, rs2, rd);
+            }
+        } else {
+            int imm = addr.getDisplacement();
+            op3(op3, rs1, imm, rd);
+        }
+    }
+
+    protected void ld(Op3s op3, SPARCAddress addr, Register rd) {
+        ld(op3, addr, rd, null);
+    }
+
+    public void lddf(SPARCAddress src, Register dst) {
+        assert isDoubleFloatRegister(dst) : dst;
+        ld(Lddf, src, dst);
+    }
+
+    public void ldf(SPARCAddress src, Register dst) {
+        assert isSingleFloatRegister(dst) : dst;
+        ld(Ldf, src, dst);
+    }
+
+    public void lduh(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Lduh, src, dst);
+    }
+
+    public void ldsh(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Ldsh, src, dst);
+    }
+
+    public void ldub(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Ldub, src, dst);
+    }
+
+    public void ldsb(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Ldsb, src, dst);
+    }
+
+    public void lduw(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Lduw, src, dst);
+    }
+
+    public void ldsw(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Ldsw, src, dst);
+    }
+
+    public void ldx(SPARCAddress src, Register dst) {
+        assert isCPURegister(dst) : dst;
+        ld(Ldx, src, dst);
+    }
+
+    public void ldxa(Register rs1, Register rs2, Register rd, Asi asi) {
+        assert SPARC.isCPURegister(rs1, rs2, rd) : format("%s %s %s", rs1, rs2, rd);
+        ld(Ldxa, new SPARCAddress(rs1, rs2), rd, asi);
+    }
+
+    public void lduwa(Register rs1, Register rs2, Register rd, Asi asi) {
+        assert SPARC.isCPURegister(rs1, rs2, rd) : format("%s %s %s", rs1, rs2, rd);
+        ld(Lduwa, new SPARCAddress(rs1, rs2), rd, asi);
+    }
+
+    protected void st(Op3s op3, Register rs1, SPARCAddress dest) {
+        ld(op3, dest, rs1);
+    }
+
+    public void stdf(Register rd, SPARCAddress addr) {
+        assert isDoubleFloatRegister(rd) : rd;
+        st(Stdf, rd, addr);
+    }
+
+    public void stf(Register rd, SPARCAddress addr) {
+        assert isSingleFloatRegister(rd) : rd;
+        st(Stf, rd, addr);
+    }
+
+    public void stb(Register rd, SPARCAddress addr) {
+        assert isCPURegister(rd) : rd;
+        st(Stb, rd, addr);
+    }
+
+    public void sth(Register rd, SPARCAddress addr) {
+        assert isCPURegister(rd) : rd;
+        st(Sth, rd, addr);
+    }
+
+    public void stw(Register rd, SPARCAddress addr) {
+        assert isCPURegister(rd) : rd;
+        st(Stw, rd, addr);
+    }
+
+    public void stx(Register rd, SPARCAddress addr) {
+        assert isCPURegister(rd) : rd;
+        st(Stx, rd, addr);
+    }
+
+    public void membar(int barriers) {
+        op3(Membar, r15, barriers, g0);
+    }
+
+    public void casa(Register rs1, Register rs2, Register rd, Asi asi) {
+        ld(Casa, new SPARCAddress(rs1, rs2), rd, asi);
+    }
+
+    public void casxa(Register rs1, Register rs2, Register rd, Asi asi) {
+        ld(Casxa, new SPARCAddress(rs1, rs2), rd, asi);
+    }
+
+    @Override
+    public InstructionCounter getInstructionCounter() {
+        return new SPARCInstructionCounter(this);
+    }
+
+    public void patchAddImmediate(int position, int simm13) {
+        int inst = getInt(position);
+        assert SPARCAssembler.isSimm13(simm13) : simm13;
+        assert (inst >>> 30) == 0b10 : String.format("0x%x", inst);
+        assert ((inst >>> 18) & 0b11_1111) == 0 : String.format("0x%x", inst);
+        assert (inst & (1 << 13)) != 0 : String.format("0x%x", inst);
+        inst = inst & (~((1 << 13) - 1));
+        inst |= simm13 & ((1 << 12) - 1);
+        emitInt(inst, position);
+    }
+
+    public void fpadd32(Register rs1, Register rs2, Register rd) {
+        op3(Impdep1, Fpadd32, rs1, rs2, rd);
+    }
+
+    public boolean isCbcond(int i) {
+        return (i & 0xC1C00000) == 0xC00000;
+    }
+}