--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java Thu Feb 16 15:46:09 2017 -0800
@@ -0,0 +1,2694 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.asm.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Icc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Always;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Add;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Addc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Addcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.And;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Andcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Andn;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Andncc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Casa;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Casxa;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Flushw;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Fpop1;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Fpop2;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Impdep1;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Jmpl;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Lddf;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldf;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldsb;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldsh;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldsw;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldub;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Lduh;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Lduw;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Lduwa;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Ldxa;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Membar;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Movcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Mulx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Or;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Popc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Prefetch;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Rd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Restore;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Save;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sdivx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sll;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sllx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sra;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srax;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srl;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srlx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Stb;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Stdf;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Stf;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sth;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Stw;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Stx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Stxa;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sub;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Udivx;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Wr;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Xnor;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Xor;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Xorcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fabsd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fabss;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Faddd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fadds;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdivd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdivs;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdtoi;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdtos;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdtox;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitod;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitos;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmovd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmovs;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuld;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuls;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegs;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fpadd32;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsmuld;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsqrtd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsqrts;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsrc2d;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsrc2s;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fstod;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fstoi;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fstox;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsubd;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fsubs;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fxtod;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fxtos;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fzerod;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fzeros;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Movdtox;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Movstosw;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Movwtos;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Movxtod;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.UMulxhi;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Ops.ArithOp;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Ops.LdstOp;
+import static java.lang.String.format;
+import static jdk.vm.ci.sparc.SPARC.CPU;
+import static jdk.vm.ci.sparc.SPARC.FPUd;
+import static jdk.vm.ci.sparc.SPARC.FPUs;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARC.g2;
+import static jdk.vm.ci.sparc.SPARC.g5;
+import static jdk.vm.ci.sparc.SPARC.g7;
+import static jdk.vm.ci.sparc.SPARC.o7;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.NumUtil;
+import org.graalvm.compiler.common.PermanentBailoutException;
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.PlatformKind;
+import jdk.vm.ci.sparc.SPARC;
+import jdk.vm.ci.sparc.SPARC.CPUFeature;
+import jdk.vm.ci.sparc.SPARCKind;
+
+/**
+ * This class implements an assembler that can encode most SPARC instructions.
+ */
+public abstract class SPARCAssembler extends Assembler {
+
+ /**
+ * Constructs an assembler for the SPARC architecture.
+ */
+ public SPARCAssembler(TargetDescription target) {
+ super(target);
+ }
+
+ /**
+ * Size of an SPARC assembler instruction in Bytes.
+ */
+ public static final int INSTRUCTION_SIZE = 4;
+
+ /**
+ * Size in bytes which are cleared by stxa %g0, [%rd] ASI_ST_BLKINIT_PRIMARY.
+ */
+ public static final int BLOCK_ZERO_LENGTH = 64;
+
+ public static final int CCR_ICC_SHIFT = 0;
+ public static final int CCR_XCC_SHIFT = 4;
+ public static final int CCR_V_SHIFT = 1;
+
+ public static final int MEMBAR_LOAD_LOAD = 1;
+ public static final int MEMBAR_STORE_LOAD = 2;
+ public static final int MEMBAR_LOAD_STORE = 3;
+ public static final int MEMBAR_STORE_STORE = 4;
+
+ private static final Ops[] OPS;
+ private static final Op2s[] OP2S;
+ private static final Op3s[][] OP3S;
+
+ private ArrayList<Integer> delaySlotOptimizationPoints = new ArrayList<>(5);
+
+ static {
+ Ops[] ops = Ops.values();
+ OPS = new Ops[ops.length];
+ for (Ops op : ops) {
+ OPS[op.value] = op;
+ }
+ Op2s[] op2s = Op2s.values();
+ OP2S = new Op2s[op2s.length];
+ for (Op2s op2 : op2s) {
+ OP2S[op2.value] = op2;
+ }
+ OP3S = new Op3s[2][64];
+ for (Op3s op3 : Op3s.values()) {
+ if (op3.value >= 1 << 6) {
+ throw new RuntimeException("Error " + op3 + " " + op3.value);
+ }
+ OP3S[op3.op.value & 1][op3.value] = op3;
+ }
+ }
+
+ public enum Ops {
+ // @formatter:off
+ BranchOp(0b00),
+ CallOp(0b01),
+ ArithOp(0b10),
+ LdstOp(0b11);
+ // @formatter:on
+
+ private final int value;
+
+ 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 Op2s {
+ // Checkstyle: stop
+ // @formatter:off
+ Illtrap(0b000),
+ Bpr (0b011),
+ Fb (0b110),
+ Fbp (0b101),
+ Br (0b010),
+ Bp (0b001),
+ Cb (0b111),
+ Sethi (0b100);
+ // @formatter:on
+ // Checkstyle: resume
+
+ private final int value;
+
+ Op2s(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public static Op2s byValue(int value) {
+ return OP2S[value];
+ }
+ }
+
+ private static final int COMMUTATIVE = 1;
+ private static final int BINARY = 2;
+ private static final int UNARY = 4;
+ private static final int VOID_IN = 8;
+
+ public enum Op3s {
+ // Checkstyle: stop
+ // @formatter:off
+ Add(0x00, "add", ArithOp, BINARY | COMMUTATIVE),
+ And(0x01, "and", ArithOp, BINARY | COMMUTATIVE),
+ Or(0x02, "or", ArithOp, BINARY | COMMUTATIVE),
+ Xor(0x03, "xor", ArithOp, BINARY | COMMUTATIVE),
+ Sub(0x04, "sub", ArithOp, BINARY),
+ Andn(0x05, "andn", ArithOp, BINARY | COMMUTATIVE),
+ Orn(0x06, "orn", ArithOp, BINARY | COMMUTATIVE),
+ Xnor(0x07, "xnor", ArithOp, BINARY | COMMUTATIVE),
+ Addc(0x08, "addc", ArithOp, BINARY | COMMUTATIVE),
+ Mulx(0x09, "mulx", ArithOp, BINARY | COMMUTATIVE),
+ Umul(0x0A, "umul", ArithOp, BINARY | COMMUTATIVE),
+ Smul(0x0B, "smul", ArithOp, BINARY | COMMUTATIVE),
+ Subc(0x0C, "subc", ArithOp, BINARY),
+ Udivx(0x0D, "udivx", ArithOp, BINARY),
+ Udiv(0x0E, "udiv", ArithOp, BINARY),
+ Sdiv(0x0F, "sdiv", ArithOp, BINARY),
+
+ Addcc(0x10, "addcc", ArithOp, BINARY | COMMUTATIVE),
+ Andcc(0x11, "andcc", ArithOp, BINARY | COMMUTATIVE),
+ Orcc(0x12, "orcc", ArithOp, BINARY | COMMUTATIVE),
+ Xorcc(0x13, "xorcc", ArithOp, BINARY | COMMUTATIVE),
+ Subcc(0x14, "subcc", ArithOp, BINARY),
+ Andncc(0x15, "andncc", ArithOp, BINARY | COMMUTATIVE),
+ Orncc(0x16, "orncc", ArithOp, BINARY | COMMUTATIVE),
+ Xnorcc(0x17, "xnorcc", ArithOp, BINARY | COMMUTATIVE),
+ Addccc(0x18, "addccc", ArithOp, BINARY | COMMUTATIVE),
+
+ Umulcc(0x1A, "umulcc", ArithOp, BINARY | COMMUTATIVE),
+ Smulcc(0x1B, "smulcc", ArithOp, BINARY | COMMUTATIVE),
+ Subccc(0x1C, "subccc", ArithOp, BINARY),
+ Udivcc(0x1E, "udivcc", ArithOp, BINARY),
+ Sdivcc(0x1F, "sdivcc", ArithOp, BINARY),
+
+ Mulscc(0x24, "mulscc", ArithOp, BINARY | COMMUTATIVE),
+ Sll(0x25, "sll", ArithOp, BINARY),
+ Sllx(0x25, "sllx", ArithOp, BINARY),
+ Srl(0x26, "srl", ArithOp, BINARY),
+ Srlx(0x26, "srlx", ArithOp, BINARY),
+ Sra(0x27, "srax", ArithOp, BINARY),
+ Srax(0x27, "srax", ArithOp, BINARY),
+ Membar(0x28, "membar", ArithOp),
+
+ Flushw(0x2B, "flushw", ArithOp),
+ Movcc(0x2C, "movcc", ArithOp),
+ Sdivx(0x2D, "sdivx", ArithOp, BINARY),
+ Popc(0x2E, "popc", ArithOp, UNARY),
+ Movr(0x2F, "movr", ArithOp, BINARY),
+
+ Fpop1(0b11_0100, "fpop1", ArithOp),
+ Fpop2(0b11_0101, "fpop2", ArithOp),
+ Impdep1(0b11_0110, "impdep1", ArithOp),
+ Impdep2(0b11_0111, "impdep2", ArithOp),
+ Jmpl(0x38, "jmpl", ArithOp),
+ Rett(0x39, "rett", ArithOp),
+ Trap(0x3a, "trap", ArithOp),
+ Flush(0x3b, "flush", ArithOp),
+ Save(0x3c, "save", ArithOp),
+ Restore(0x3d, "restore", ArithOp),
+ Retry(0x3e, "retry", ArithOp),
+
+
+ Casa(0b111100, "casa", LdstOp),
+ Casxa(0b111110, "casxa", LdstOp),
+ Prefetch(0b101101, "prefetch", LdstOp),
+ Prefetcha(0b111101, "prefetcha", LdstOp),
+
+ Lduw (0b00_0000, "lduw", LdstOp),
+ Ldub (0b00_0001, "ldub", LdstOp),
+ Lduh (0b00_0010, "lduh", LdstOp),
+ Stw (0b00_0100, "stw", LdstOp),
+ Stb (0b00_0101, "stb", LdstOp),
+ Sth (0b00_0110, "sth", LdstOp),
+ Ldsw (0b00_1000, "ldsw", LdstOp),
+ Ldsb (0b00_1001, "ldsb", LdstOp),
+ Ldsh (0b00_1010, "ldsh", LdstOp),
+ Ldx (0b00_1011, "ldx", LdstOp),
+ Stx (0b00_1110, "stx", LdstOp),
+
+ Ldf (0b10_0000, "ldf", LdstOp),
+ Ldfsr (0b10_0001, "ldfsr", LdstOp),
+ Ldaf (0b10_0010, "ldaf", LdstOp),
+ Lddf (0b10_0011, "lddf", LdstOp),
+ Stf (0b10_0100, "stf", LdstOp),
+ Stfsr (0b10_0101, "stfsr", LdstOp),
+ Staf (0b10_0110, "staf", LdstOp),
+ Stdf (0b10_0111, "stdf", LdstOp),
+
+ Stba (0b01_0101, "stba", LdstOp),
+ Stha (0b01_0110, "stha", LdstOp),
+ Stwa (0b01_0100, "stwa", LdstOp),
+ Stxa (0b01_1110, "stxa", LdstOp),
+
+ Ldsba (0b01_1001, "ldsba", LdstOp),
+ Ldsha (0b01_1010, "ldsha", LdstOp),
+ Ldswa (0b01_1000, "ldswa", LdstOp),
+ Lduba (0b01_0001, "lduba", LdstOp),
+ Lduha (0b01_0010, "lduha", LdstOp),
+ Lduwa (0b01_0000, "lduwa", LdstOp),
+
+ Ldxa (0b01_1011, "ldxa", LdstOp),
+
+ Rd (0b10_1000, "rd", ArithOp),
+ Wr (0b11_0000, "wr", ArithOp),
+
+ Tcc(0b11_1010, "tcc", ArithOp);
+
+ // @formatter:on
+ // Checkstyle: resume
+
+ private final int value;
+ private final String operator;
+ private final Ops op;
+ private final int flags;
+
+ Op3s(int value, String name, Ops op) {
+ this(value, name, op, 0);
+ }
+
+ Op3s(int value, String name, Ops op, int flags) {
+ this.value = value;
+ this.operator = name;
+ this.op = op;
+ this.flags = flags;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public String getOperator() {
+ return operator;
+ }
+
+ public boolean throwsException() {
+ if (op == LdstOp) {
+ return true;
+ }
+ switch (this) {
+ case Udiv:
+ case Udivx:
+ case Sdiv:
+ case Sdivx:
+ case Udivcc:
+ case Sdivcc:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public boolean isBinary() {
+ return (flags & BINARY) != 0;
+ }
+
+ public boolean isUnary() {
+ return (flags & UNARY) != 0;
+ }
+
+ public boolean isCommutative() {
+ return (flags & COMMUTATIVE) != 0;
+ }
+ }
+
+ public enum Opfs {
+ // @formatter:off
+
+ Fmovs(0b0_0000_0001, "fmovs", Fpop1, UNARY),
+ Fmovd(0b0_0000_0010, "fmovd", Fpop1, UNARY),
+ Fmovq(0b0_0000_0011, "fmovq", Fpop1, UNARY),
+ Fnegs(0x05, "fnegs", Fpop1, UNARY),
+ Fnegd(0x06, "fnegd", Fpop1, UNARY),
+ Fnegq(0x07, "fnegq", Fpop1, UNARY),
+ Fabss(0x09, "fabss", Fpop1, UNARY),
+ Fabsd(0x0A, "fabsd", Fpop1, UNARY),
+ Fabsq(0x0B, "fabsq", Fpop1, UNARY),
+
+ // start VIS1
+ Fpadd32(0x52, "fpadd32", Impdep1, BINARY | COMMUTATIVE),
+ Fzerod(0x60, "fzerod", Impdep1, VOID_IN),
+ Fzeros(0x61, "fzeros", Impdep1, VOID_IN),
+ Fsrc2d(0x78, "fsrc2d", Impdep1, UNARY),
+ Fsrc2s(0x79, "fsrc2s", Impdep1, UNARY),
+ // end VIS1
+
+ // start VIS3
+ Movdtox(0x110, "movdtox", Impdep1, UNARY),
+ Movstouw(0x111, "movstouw", Impdep1, UNARY),
+ Movstosw(0x113, "movstosw", Impdep1, UNARY),
+ Movxtod(0x118, "movxtod", Impdep1, UNARY),
+ Movwtos(0b1_0001_1001, "movwtos", Impdep1, UNARY),
+ UMulxhi(0b0_0001_0110, "umulxhi", Impdep1, BINARY | COMMUTATIVE),
+ // end VIS3
+
+ Fadds(0x41, "fadds", Fpop1, BINARY | COMMUTATIVE),
+ Faddd(0x42, "faddd", Fpop1, BINARY | COMMUTATIVE),
+ Fsubs(0x45, "fsubs", Fpop1, BINARY),
+ Fsubd(0x46, "fsubd", Fpop1, BINARY),
+ Fmuls(0x49, "fmuls", Fpop1, BINARY | COMMUTATIVE),
+ Fmuld(0x4A, "fmuld", Fpop1, BINARY | COMMUTATIVE),
+ Fdivs(0x4D, "fdivs", Fpop1, BINARY),
+ Fdivd(0x4E, "fdivd", Fpop1, BINARY),
+
+ Fsqrts(0x29, "fsqrts", Fpop1, UNARY),
+ Fsqrtd(0x2A, "fsqrtd", Fpop1, UNARY),
+
+ Fsmuld(0x69, "fsmuld", Fpop1, BINARY | COMMUTATIVE),
+
+ Fstoi(0xD1, "fstoi", Fpop1, UNARY),
+ Fdtoi(0xD2, "fdtoi", Fpop1, UNARY),
+ Fstox(0x81, "fstox", Fpop1, UNARY),
+ Fdtox(0x82, "fdtox", Fpop1, UNARY),
+ Fxtos(0x84, "fxtos", Fpop1, UNARY),
+ Fxtod(0x88, "fxtod", Fpop1, UNARY),
+ Fitos(0xC4, "fitos", Fpop1, UNARY),
+ Fdtos(0xC6, "fdtos", Fpop1, UNARY),
+ Fitod(0xC8, "fitod", Fpop1, UNARY),
+ Fstod(0xC9, "fstod", Fpop1, UNARY),
+
+
+ Fcmps(0x51, "fcmps", Fpop2, BINARY),
+ Fcmpd(0x52, "fcmpd", Fpop2, BINARY);
+
+ // @formatter:on
+
+ private final int value;
+ private final String operator;
+ private final Op3s op3;
+ private final int flags;
+
+ Opfs(int value, String op, Op3s op3, int flags) {
+ this.value = value;
+ this.operator = op;
+ this.op3 = op3;
+ this.flags = flags;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public String getOperator() {
+ return operator;
+ }
+
+ public boolean isBinary() {
+ return (flags & BINARY) != 0;
+ }
+
+ public boolean isUnary() {
+ return (flags & UNARY) != 0;
+ }
+
+ public boolean isCommutative() {
+ return (flags & COMMUTATIVE) != 0;
+ }
+ }
+
+ public enum OpfLow {
+ Fmovscc(0b00_0001, "fmovscc", Fpop2),
+ Fmovdcc(0b00_0010, "fmovdcc", Fpop2);
+
+ private final int value;
+ private final String operator;
+ private final Op3s op3;
+
+ OpfLow(int value, String op, Op3s op3) {
+ this.value = value;
+ this.operator = op;
+ this.op3 = op3;
+ }
+
+ @Override
+ public String toString() {
+ 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;
+
+ 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;
+
+ 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(PlatformKind kind) {
+ if (kind.equals(SPARCKind.XWORD)) {
+ return Xcc;
+ } else if (kind.equals(SPARCKind.WORD)) {
+ return Icc;
+ } else if (kind.equals(SPARCKind.SINGLE) || kind.equals(SPARCKind.DOUBLE)) {
+ return Fcc0;
+ } else {
+ throw new IllegalArgumentException("Unknown kind: " + kind);
+ }
+ }
+ }
+
+ 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;
+
+ ConditionFlag(int value, String op) {
+ this(value, op, false);
+ }
+
+ 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;
+
+ 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;
+
+ 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;
+
+ Fcn(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+ }
+
+ /**
+ * Specifies various bit fields used in SPARC instructions.
+ */
+ @SuppressWarnings("unused")
+ public abstract static class BitSpec {
+ private static final BitSpec op = new ContinousBitSpec(31, 30, "op");
+ private static final BitSpec op2 = new ContinousBitSpec(24, 22, "op2");
+ private static final BitSpec op3 = new ContinousBitSpec(24, 19, "op3");
+ private static final BitSpec opf = new ContinousBitSpec(13, 5, "opf");
+ private static final BitSpec opfLow = new ContinousBitSpec(10, 5, "opfLow");
+ private static final BitSpec opfCC = new ContinousBitSpec(13, 11, "opfCC");
+ private static final BitSpec opfCond = new ContinousBitSpec(17, 14, "opfCond");
+ private static final BitSpec rd = new ContinousBitSpec(29, 25, "rd");
+ private static final BitSpec rs1 = new ContinousBitSpec(18, 14, "rs1");
+ private static final BitSpec rs2 = new ContinousBitSpec(4, 0, "rs2");
+ private static final BitSpec simm13 = new ContinousBitSpec(12, 0, true, "simm13");
+ private static final BitSpec shcnt32 = new ContinousBitSpec(4, 0, "shcnt32");
+ private static final BitSpec shcnt64 = new ContinousBitSpec(5, 0, "shcnt64");
+ private static final BitSpec imm22 = new ContinousBitSpec(21, 0, "imm22");
+ private static final BitSpec immAsi = new ContinousBitSpec(12, 5, "immASI");
+ private static final BitSpec i = new ContinousBitSpec(13, 13, "i");
+ private static final BitSpec disp19 = new ContinousBitSpec(18, 0, true, "disp19");
+ private static final BitSpec disp22 = new ContinousBitSpec(21, 0, true, "disp22");
+ private static final BitSpec disp30 = new ContinousBitSpec(29, 0, true, "disp30");
+ private static final BitSpec a = new ContinousBitSpec(29, 29, "a");
+ private static final BitSpec p = new ContinousBitSpec(19, 19, "p");
+ private static final BitSpec x = new ContinousBitSpec(12, 12, "x");
+ private static final BitSpec cond = new ContinousBitSpec(28, 25, "cond");
+ private static final BitSpec rcond = new ContinousBitSpec(27, 25, "rcond");
+ private static final BitSpec cc = new ContinousBitSpec(21, 20, "cc");
+ private static final BitSpec fcc = new ContinousBitSpec(26, 25, "cc");
+ private static final BitSpec d16lo = new ContinousBitSpec(13, 0, "d16lo");
+ private static final BitSpec d16hi = new ContinousBitSpec(21, 20, true, "d16hi");
+ private static final BitSpec d16 = new CompositeBitSpec(d16hi, d16lo);
+ // Movcc
+ private static final BitSpec movccLo = new ContinousBitSpec(12, 11, "cc_lo");
+ private static final BitSpec movccHi = new ContinousBitSpec(18, 18, "cc_hi");
+ private static final BitSpec movccCond = new ContinousBitSpec(17, 14, "cond");
+ private static final BitSpec simm11 = new ContinousBitSpec(10, 0, true, "simm11");
+
+ // CBCond
+ private static final BitSpec cLo = new ContinousBitSpec(27, 25, "cLo");
+ private static final BitSpec cHi = new ContinousBitSpec(29, 29, "cHi");
+ private static final BitSpec c = new CompositeBitSpec(cHi, cLo);
+ private static final BitSpec cbcond = new ContinousBitSpec(28, 28, "cbcond");
+ private static final BitSpec cc2 = new ContinousBitSpec(21, 21, "cc2");
+ private static final BitSpec d10Lo = new ContinousBitSpec(12, 5, "d10Lo");
+ private static final BitSpec d10Hi = new ContinousBitSpec(20, 19, true, "d10Hi");
+ private static final BitSpec d10 = new CompositeBitSpec(d10Hi, d10Lo);
+ private static final BitSpec simm5 = new ContinousBitSpec(4, 0, true, "simm5");
+
+ protected final boolean signExtend;
+
+ public BitSpec(boolean signExtend) {
+ super();
+ this.signExtend = signExtend;
+ }
+
+ public final boolean isSignExtend() {
+ return signExtend;
+ }
+
+ public abstract int setBits(int word, int value);
+
+ public abstract int getBits(int word);
+
+ public abstract int getWidth();
+
+ public abstract boolean valueFits(int value);
+ }
+
+ public static final class ContinousBitSpec extends BitSpec {
+ private final int hiBit;
+ private final int lowBit;
+ private final int width;
+ private final int mask;
+ private final String name;
+
+ public ContinousBitSpec(int hiBit, int lowBit, String name) {
+ this(hiBit, lowBit, false, name);
+ }
+
+ public ContinousBitSpec(int hiBit, int lowBit, boolean signExt, String name) {
+ super(signExt);
+ this.hiBit = hiBit;
+ this.lowBit = lowBit;
+ this.width = hiBit - lowBit + 1;
+ mask = ((1 << width) - 1) << lowBit;
+ this.name = name;
+ }
+
+ @Override
+ public int setBits(int word, int value) {
+ assert valueFits(value) : String.format("Value 0x%x for field %s does not fit.", value, this);
+ return (word & ~mask) | ((value << lowBit) & mask);
+ }
+
+ @Override
+ public int getBits(int word) {
+ if (signExtend) {
+ return ((word & mask) << (31 - hiBit)) >> (32 - width);
+ } else {
+ return (word & mask) >>> lowBit;
+ }
+ }
+
+ @Override
+ public int getWidth() {
+ return width;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s [%d:%d]", name, hiBit, lowBit);
+ }
+
+ @Override
+ public boolean valueFits(int value) {
+ if (signExtend) {
+ return isSimm(value, getWidth());
+ } else {
+ return isImm(value, getWidth());
+ }
+ }
+ }
+
+ public static final class CompositeBitSpec extends BitSpec {
+ private final BitSpec left;
+ private final int leftWidth;
+ private final BitSpec right;
+ private final int rightWidth;
+ private final int width;
+
+ public CompositeBitSpec(BitSpec left, BitSpec right) {
+ super(left.isSignExtend());
+ assert !right.isSignExtend() : String.format("Right field %s must not be sign extended", right);
+ this.left = left;
+ this.leftWidth = left.getWidth();
+ this.right = right;
+ this.rightWidth = right.getWidth();
+ this.width = leftWidth + rightWidth;
+ }
+
+ @Override
+ public int getBits(int word) {
+ int l = left.getBits(word);
+ int r = right.getBits(word);
+ return (l << rightWidth) | r;
+ }
+
+ @Override
+ public int setBits(int word, int value) {
+ int l = leftBits(value);
+ int r = rightBits(value);
+ return left.setBits(right.setBits(word, r), l);
+ }
+
+ private int leftBits(int value) {
+ return getBits(value, width - 1, rightWidth, signExtend);
+ }
+
+ private int rightBits(int value) {
+ return getBits(value, rightWidth - 1, 0, false);
+ }
+
+ @Override
+ public int getWidth() {
+ return width;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("CompositeBitSpec[%s, %s]", left, right);
+ }
+
+ @Override
+ public boolean valueFits(int value) {
+ int l = leftBits(value);
+ int r = rightBits(value);
+ return left.valueFits(l) && right.valueFits(r);
+ }
+
+ private static int getBits(int inst, int hiBit, int lowBit, boolean signExtended) {
+ int shifted = inst >> lowBit;
+ if (signExtended) {
+ return shifted;
+ } else {
+ return shifted & ((1 << (hiBit - lowBit + 1)) - 1);
+ }
+ }
+ }
+
+ public static class BitKey {
+ private final BitSpec spec;
+ private final int value;
+
+ public BitKey(BitSpec spec, int value) {
+ super();
+ this.spec = spec;
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("BitKey %s=%s", spec, value);
+ }
+ }
+
+ /**
+ * Represents a prefix tree of {@link BitSpec} objects to find the most accurate SPARCOp.
+ */
+ public static final class BitKeyIndex {
+ private final BitSpec spec;
+ private final Map<Integer, BitKeyIndex> nodes;
+ private SPARCOp op;
+
+ public BitKeyIndex(SPARCOp op) {
+ assert op != null;
+ this.op = op;
+ this.nodes = null;
+ this.spec = null;
+ }
+
+ public BitKeyIndex(BitSpec spec) {
+ assert spec != null;
+ this.op = null;
+ this.nodes = new HashMap<>(4);
+ this.spec = spec;
+ }
+
+ /**
+ * Adds operation to the index.
+ *
+ * @param keys Ordered by the importance
+ * @param operation Operation represented by this list of keys
+ */
+ private void addOp(List<BitKey[]> keys, SPARCOp operation) {
+ assert keys.size() > 0;
+ BitKey[] firstKeys = keys.get(0);
+ for (BitKey first : firstKeys) {
+ assert first.spec.equals(spec) : first.spec + " " + spec;
+ BitKeyIndex node;
+ if (keys.size() == 1) {
+ if (nodes.containsKey(first.value)) {
+ node = nodes.get(first.value);
+ assert node.op == null : node + " " + keys;
+ node.op = operation;
+ } else {
+ assert !nodes.containsKey(first.value) : "Index must be unique. Existing key: " + nodes.get(first.value);
+ node = new BitKeyIndex(operation);
+ }
+ } else {
+ node = nodes.get(first.value);
+ BitKey[] next = keys.get(1);
+ if (node == null) {
+ for (int i = 1; i < next.length; i++) {
+ assert next[i - 1].spec.equals(next[i].spec) : "All spec on this node must equal";
+ }
+ node = new BitKeyIndex(next[0].spec);
+ }
+ node.addOp(keys.subList(1, keys.size()), operation);
+ }
+ nodes.put(first.value, node);
+ }
+ }
+
+ /**
+ * Finds the best matching {@link SPARCOp} for this instruction.
+ */
+ public SPARCOp find(int inst) {
+ if (nodes != null) {
+ int key = spec.getBits(inst);
+ BitKeyIndex sub = nodes.get(key);
+ if (sub == null) {
+ if (op != null) {
+ return op;
+ } else {
+ throw new RuntimeException(String.format("%s 0x%x, 0x%x %s", spec, inst, key, nodes));
+ }
+ }
+ return sub.find(inst);
+ } else {
+ return this.op;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return this.op == null ? this.spec + ": " + this.nodes : this.op.toString();
+ }
+ }
+
+ public static final Bpcc BPCC = new Bpcc(Op2s.Bp);
+ public static final Bpcc FBPCC = new Bpcc(Op2s.Fbp);
+ public static final CBCond CBCOND = new CBCond();
+ public static final Bpr BPR = new Bpr();
+ public static final Br BR = new Br();
+ public static final Sethi SETHI = new Sethi();
+ public static final FMOVcc FMOVSCC = new FMOVcc(OpfLow.Fmovscc);
+ public static final FMOVcc FMOVDCC = new FMOVcc(OpfLow.Fmovdcc);
+ public static final MOVicc MOVicc = new MOVicc();
+ public static final OpfOp OPF = new OpfOp();
+ public static final Op3Op OP3 = new Op3Op();
+ public static final SPARCOp LDST = new SPARCOp(Ops.LdstOp);
+ public static final SPARCOp BRANCH = new SPARCOp(Ops.BranchOp);
+ public static final SPARCOp CALL = new SPARCOp(Ops.CallOp);
+ private static final BitKeyIndex INDEX = new BitKeyIndex(BitSpec.op);
+
+ static {
+ for (SPARCOp op : SPARCOp.OPS) {
+ INDEX.addOp(op.getKeys(), op);
+ }
+ }
+
+ public static SPARCOp getSPARCOp(int inst) {
+ return INDEX.find(inst);
+ }
+
+ /**
+ * Represents a class of SPARC instruction and gives methods to modify its fields.
+ */
+ public static class SPARCOp {
+ private final Ops op;
+ private final BitKey opKey;
+ private List<BitKey[]> keyFields;
+ private static final List<SPARCOp> OPS = new ArrayList<>();
+
+ public SPARCOp(Ops op) {
+ super();
+ this.op = op;
+ this.opKey = new BitKey(BitSpec.op, op.value);
+ OPS.add(this);
+ }
+
+ protected int setBits(int word) {
+ return BitSpec.op.setBits(word, op.value);
+ }
+
+ public boolean match(int inst) {
+ for (BitKey[] keys : keyFields) {
+ for (BitKey k : keys) {
+ if (k.spec.getBits(inst) != k.value) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ protected List<BitKey[]> getKeys() {
+ if (keyFields == null) {
+ keyFields = new ArrayList<>(4);
+ keyFields.add(new BitKey[]{opKey});
+ }
+ return keyFields;
+ }
+
+ public Ops getOp(int inst) {
+ return SPARCAssembler.OPS[BitSpec.op.getBits(inst)];
+ }
+
+ @Override
+ public String toString() {
+ String name = getClass().getName();
+ name = name.substring(name.lastIndexOf(".") + 1);
+ return name + "[op: " + op + "]";
+ }
+ }
+
+ /**
+ * Base class for control transfer operations; provides access to the disp field.
+ */
+ public abstract static class ControlTransferOp extends SPARCOp {
+ private final Op2s op2;
+ private final boolean delaySlot;
+ private final BitSpec disp;
+ private final BitKey[] op2Key;
+
+ private ControlTransferOp(Ops op, Op2s op2, boolean delaySlot, BitSpec disp) {
+ super(op);
+ this.op2 = op2;
+ this.delaySlot = delaySlot;
+ this.disp = disp;
+ this.op2Key = new BitKey[]{new BitKey(BitSpec.op2, op2.value)};
+ }
+
+ public boolean hasDelaySlot() {
+ return delaySlot;
+ }
+
+ @Override
+ protected int setBits(int word) {
+ return BitSpec.op2.setBits(super.setBits(word), op2.value);
+ }
+
+ protected int setDisp(int inst, SPARCMacroAssembler masm, Label lab) {
+ if (lab.isBound()) {
+ int d = (lab.position() - masm.position()) / 4;
+ return setDisp(inst, d);
+ } else {
+ masm.patchUnbound(lab);
+ return inst;
+ }
+ }
+
+ public int setDisp(int inst, int d) {
+ assert this.match(inst);
+ if (!isValidDisp(d)) {
+ throw new PermanentBailoutException("Too large displacement 0x%x in field %s in instruction %s", d, this.disp, this);
+ }
+ return this.disp.setBits(inst, d);
+ }
+
+ public boolean isValidDisp(int d) {
+ return this.disp.valueFits(d);
+ }
+
+ public int setAnnul(int inst, boolean a) {
+ return BitSpec.a.setBits(inst, a ? 1 : 0);
+ }
+
+ @Override
+ protected List<BitKey[]> getKeys() {
+ List<BitKey[]> keys = super.getKeys();
+ keys.add(op2Key);
+ return keys;
+ }
+
+ public int getDisp(int inst) {
+ return this.disp.getBits(inst);
+ }
+
+ public abstract boolean isAnnulable(int inst);
+
+ public abstract boolean isConditional(int inst);
+ }
+
+ public static final class Bpcc extends ControlTransferOp {
+ public Bpcc(Op2s op2) {
+ super(Ops.BranchOp, op2, true, BitSpec.disp19);
+ }
+
+ public void emit(SPARCMacroAssembler masm, CC cc, ConditionFlag cf, Annul annul, BranchPredict p, Label lab) {
+ int inst = setBits(0);
+ inst = BitSpec.a.setBits(inst, annul.flag);
+ inst = BitSpec.cond.setBits(inst, cf.value);
+ inst = BitSpec.cc.setBits(inst, cc.value);
+ inst = BitSpec.p.setBits(inst, p.flag);
+ masm.insertNopAfterCBCond();
+ masm.emitInt(setDisp(inst, masm, lab));
+ }
+
+ @Override
+ public boolean isAnnulable(int inst) {
+ return isConditional(inst);
+ }
+
+ @Override
+ public boolean isConditional(int inst) {
+ int cond = BitSpec.cond.getBits(inst);
+ return cond != ConditionFlag.Always.value && cond != ConditionFlag.Never.value;
+ }
+ }
+
+ public static final class Br extends ControlTransferOp {
+ public Br() {
+ super(Ops.BranchOp, Op2s.Br, true, BitSpec.disp22);
+ }
+
+ @Override
+ public boolean isAnnulable(int inst) {
+ return isConditional(inst);
+ }
+
+ @Override
+ public boolean isConditional(int inst) {
+ int cond = BitSpec.cond.getBits(inst);
+ return cond != ConditionFlag.Always.value && cond != ConditionFlag.Never.value;
+ }
+
+ public void emit(SPARCMacroAssembler masm, ConditionFlag cond, Annul a, Label lab) {
+ int inst = setBits(0);
+ inst = BitSpec.cond.setBits(inst, cond.value);
+ inst = BitSpec.a.setBits(inst, a.flag);
+ masm.insertNopAfterCBCond();
+ masm.emitInt(setDisp(inst, masm, lab));
+ }
+ }
+
+ public static final class Bpr extends ControlTransferOp {
+ private static final BitKey CBCOND_KEY = new BitKey(BitSpec.cbcond, 0);
+
+ public Bpr() {
+ super(Ops.BranchOp, Op2s.Bpr, true, BitSpec.d16);
+ }
+
+ public void emit(SPARCMacroAssembler masm, RCondition rcond, Annul a, BranchPredict p, Register rs1, Label lab) {
+ int inst = setBits(0);
+ inst = BitSpec.rcond.setBits(inst, rcond.value);
+ inst = BitSpec.a.setBits(inst, a.flag);
+ inst = BitSpec.p.setBits(inst, p.flag);
+ inst = BitSpec.rs1.setBits(inst, rs1.encoding);
+ masm.insertNopAfterCBCond();
+ masm.emitInt(setDisp(inst, masm, lab));
+ }
+
+ @Override
+ protected List<BitKey[]> getKeys() {
+ List<BitKey[]> keys = super.getKeys();
+ keys.add(new BitKey[]{CBCOND_KEY});
+ return keys;
+ }
+
+ @Override
+ public boolean isAnnulable(int inst) {
+ return isConditional(inst);
+ }
+
+ @Override
+ public boolean isConditional(int inst) {
+ int cond = BitSpec.cond.getBits(inst);
+ return cond != ConditionFlag.Always.value && cond != ConditionFlag.Never.value;
+ }
+ }
+
+ public static final class CBCond extends ControlTransferOp {
+ private static final BitKey CBCOND_KEY = new BitKey(BitSpec.cbcond, 1);
+
+ private CBCond() {
+ super(Ops.BranchOp, Op2s.Bpr, false, BitSpec.d10);
+ }
+
+ @Override
+ protected List<BitKey[]> getKeys() {
+ List<BitKey[]> keys = super.getKeys();
+ keys.add(new BitKey[]{CBCOND_KEY});
+ return keys;
+ }
+
+ public void emit(SPARCMacroAssembler masm, ConditionFlag cf, boolean cc2, Register rs1, Register rs2, Label lab) {
+ int inst = setBits(0, cf, cc2, rs1);
+ inst = BitSpec.rs2.setBits(inst, rs2.encoding);
+ inst = BitSpec.i.setBits(inst, 0);
+ masm.insertNopAfterCBCond();
+ emit(masm, lab, inst);
+ }
+
+ public void emit(SPARCMacroAssembler masm, ConditionFlag cf, boolean cc2, Register rs1, int simm5, Label lab) {
+ int inst = setBits(0, cf, cc2, rs1);
+ inst = BitSpec.simm5.setBits(inst, simm5);
+ inst = BitSpec.i.setBits(inst, 1);
+ emit(masm, lab, inst);
+ }
+
+ private void emit(SPARCMacroAssembler masm, Label lab, int baseInst) {
+ int inst = baseInst;
+ masm.insertNopAfterCBCond();
+ masm.emitInt(setDisp(inst, masm, lab));
+ }
+
+ private int setBits(int base, ConditionFlag cf, boolean cc2, Register rs1) {
+ int inst = super.setBits(base);
+ inst = BitSpec.rs1.setBits(inst, rs1.encoding);
+ inst = BitSpec.cc2.setBits(inst, cc2 ? 1 : 0);
+ inst = BitSpec.c.setBits(inst, cf.value);
+ return BitSpec.cbcond.setBits(inst, 1);
+ }
+
+ @Override
+ public boolean isAnnulable(int inst) {
+ return false;
+ }
+
+ @Override
+ public boolean isConditional(int inst) {
+ return true;
+ }
+ }
+
+ public static class Op2Op extends SPARCOp {
+ private final Op2s op2;
+ private final BitKey op2Key;
+
+ public Op2Op(Ops op, Op2s op2) {
+ super(op);
+ this.op2 = op2;
+ op2Key = new BitKey(BitSpec.op2, op2.value);
+ }
+
+ @Override
+ protected int setBits(int word) {
+ int result = super.setBits(word);
+ return BitSpec.op2.setBits(result, op2.value);
+ }
+
+ @Override
+ protected List<BitKey[]> getKeys() {
+ List<BitKey[]> keys = super.getKeys();
+ keys.add(new BitKey[]{op2Key});
+ return keys;
+ }
+ }
+
+ public static final class Sethi extends Op2Op {
+ public Sethi() {
+ super(Ops.BranchOp, Op2s.Sethi);
+ }
+
+ public static Register getRS1(int word) {
+ int regNum = BitSpec.rs1.getBits(word);
+ return SPARC.cpuRegisters.get(regNum);
+ }
+
+ public static int getImm22(int word) {
+ return BitSpec.imm22.getBits(word);
+ }
+
+ public static boolean isNop(int inst) {
+ return getRS1(inst).equals(g0) && getImm22(inst) == 0;
+ }
+ }
+
+ public static final class Op3Op extends SPARCOp {
+ public Op3Op() {
+ super(ArithOp);
+ }
+
+ public Op3s getOp3(int inst) {
+ assert match(inst);
+ return OP3S[ArithOp.value & 1][BitSpec.op3.getBits(inst)];
+ }
+
+ public static void emit(SPARCMacroAssembler masm, Op3s opcode, Register rs1, Register rs2, Register rd) {
+ int instruction = setBits(0, opcode, rs1, rd);
+ instruction = BitSpec.rs2.setBits(instruction, rs2.encoding);
+ instruction = BitSpec.i.setBits(instruction, 0);
+ masm.emitInt(instruction);
+ }
+
+ public static void emit(SPARCMacroAssembler masm, Op3s opcode, Register rs1, int simm13, Register rd) {
+ int instruction = setBits(0, opcode, rs1, rd);
+ instruction = BitSpec.i.setBits(instruction, 1);
+ BitSpec immediateSpec;
+ switch (opcode) {
+ case Sllx:
+ case Srlx:
+ case Srax:
+ immediateSpec = BitSpec.shcnt64;
+ break;
+ case Sll:
+ case Srl:
+ case Sra:
+ immediateSpec = BitSpec.shcnt32;
+ break;
+ default:
+ immediateSpec = BitSpec.simm13;
+ break;
+ }
+ instruction = immediateSpec.setBits(instruction, simm13);
+ masm.emitInt(instruction);
+ }
+
+ private static int setBits(int instruction, Op3s op3, Register rs1, Register rd) {
+ assert op3.op.equals(ArithOp);
+ int tmp = BitSpec.op3.setBits(instruction, op3.value);
+ switch (op3) {
+ case Sllx:
+ case Srlx:
+ case Srax:
+ tmp = BitSpec.x.setBits(tmp, 1);
+ break;
+ }
+ tmp = BitSpec.op.setBits(tmp, op3.op.value);
+ tmp = BitSpec.rd.setBits(tmp, rd.encoding);
+ return BitSpec.rs1.setBits(tmp, rs1.encoding);
+ }
+ }
+
+ /**
+ * Used for interfacing FP and GP conditional move instructions.
+ */
+ public interface CMOV {
+ void emit(SPARCMacroAssembler masm, ConditionFlag condition, CC cc, Register rs2, Register rd);
+
+ void emit(SPARCMacroAssembler masm, ConditionFlag condition, CC cc, int simm11, Register rd);
+ }
+
+ public static final class MOVicc extends SPARCOp implements CMOV {
+ private static final Op3s op3 = Movcc;
+
+ public MOVicc() {
+ super(ArithOp);
+ }
+
+ @Override
+ public void emit(SPARCMacroAssembler masm, ConditionFlag condition, CC cc, Register rs2, Register rd) {
+ int inst = setBits(0, condition, cc, rd);
+ inst = BitSpec.rs2.setBits(inst, rs2.encoding());
+ masm.emitInt(inst);
+ }
+
+ @Override
+ public void emit(SPARCMacroAssembler masm, ConditionFlag condition, CC cc, int simm11, Register rd) {
+ int inst = setBits(0, condition, cc, rd);
+ inst = BitSpec.i.setBits(inst, 1);
+ inst = BitSpec.simm11.setBits(inst, simm11);
+ masm.emitInt(inst);
+ }
+
+ protected int setBits(int word, ConditionFlag condition, CC cc, Register rd) {
+ int inst = super.setBits(word);
+ inst = BitSpec.rd.setBits(inst, rd.encoding());
+ inst = BitSpec.op3.setBits(inst, op3.value);
+ inst = BitSpec.movccCond.setBits(inst, condition.value);
+ inst = BitSpec.movccLo.setBits(inst, cc.value);
+ return BitSpec.movccHi.setBits(inst, cc.isFloat ? 0 : 1);
+ }
+
+ @Override
+ protected List<BitKey[]> getKeys() {
+ List<BitKey[]> keys = super.getKeys();
+ keys.add(new BitKey[]{new BitKey(BitSpec.op3, op3.value)});
+ return keys;
+ }
+ }
+
+ public static final class FMOVcc extends SPARCOp implements CMOV {
+ private OpfLow opfLow;
+
+ public FMOVcc(OpfLow opfLow) {
+ super(ArithOp);
+ this.opfLow = opfLow;
+ }
+
+ @Override
+ public void emit(SPARCMacroAssembler masm, ConditionFlag condition, CC cc, Register rs2, Register rd) {
+ int inst = setBits(0);
+ inst = BitSpec.rd.setBits(inst, rd.encoding());
+ inst = BitSpec.op3.setBits(inst, opfLow.op3.value);
+ inst = BitSpec.opfCond.setBits(inst, condition.value);
+ inst = BitSpec.opfCC.setBits(inst, cc.value);
+ inst = BitSpec.opfLow.setBits(inst, opfLow.value);
+ inst = BitSpec.rs2.setBits(inst, rs2.encoding());
+ masm.emitInt(inst);
+ }
+
+ @Override
+ public void emit(SPARCMacroAssembler masm, ConditionFlag condition, CC cc, int simm11, Register rd) {
+ throw new IllegalArgumentException("FMOVCC cannot be used with immediate value");
+ }
+
+ @Override
+ protected List<BitKey[]> getKeys() {
+ List<BitKey[]> keys = super.getKeys();
+ keys.add(new BitKey[]{new BitKey(BitSpec.op3, opfLow.op3.value)});
+ keys.add(new BitKey[]{new BitKey(BitSpec.opfLow, opfLow.value)});
+ return keys;
+ }
+ }
+
+ public static final class OpfOp extends SPARCOp {
+
+ private BitKey[] op3Keys;
+
+ public OpfOp(BitKey... op3Keys) {
+ super(ArithOp);
+ this.op3Keys = op3Keys;
+ }
+
+ public OpfOp() {
+ // @formatter:off
+ this(new BitKey[]{
+ new BitKey(BitSpec.op3, Op3s.Fpop1.value),
+ new BitKey(BitSpec.op3, Op3s.Fpop2.value),
+ new BitKey(BitSpec.op3, Op3s.Impdep1.value),
+ new BitKey(BitSpec.op3, Op3s.Impdep2.value)});
+ // @formatter:on
+ }
+
+ public static void emit(SPARCMacroAssembler masm, Opfs opf, Register rs1, Register rs2, Register rd) {
+ int instruction = setBits(0, opf, rs1, rs2);
+ instruction = BitSpec.rd.setBits(instruction, rd.encoding);
+ instruction = BitSpec.i.setBits(instruction, 0);
+ masm.emitInt(instruction);
+ }
+
+ public static void emitFcmp(SPARCMacroAssembler masm, Opfs opf, CC cc, Register rs1, Register rs2) {
+ assert opf.equals(Opfs.Fcmpd) || opf.equals(Opfs.Fcmps) : opf;
+ int instruction = setBits(0, opf, rs1, rs2);
+ instruction = BitSpec.fcc.setBits(instruction, cc.value);
+ masm.emitInt(instruction);
+ }
+
+ private static int setBits(int instruction, Opfs opf, Register rs1, Register rs2) {
+ int tmp = BitSpec.op.setBits(instruction, opf.op3.op.value);
+ tmp = BitSpec.op3.setBits(tmp, opf.op3.value);
+ tmp = BitSpec.opf.setBits(tmp, opf.value);
+ tmp = BitSpec.rs1.setBits(tmp, rs1.encoding);
+ return BitSpec.rs2.setBits(tmp, rs2.encoding);
+ }
+
+ @Override
+ protected List<BitKey[]> getKeys() {
+ List<BitKey[]> keys = super.getKeys();
+ keys.add(op3Keys);
+ // @formatter:on
+ return keys;
+ }
+ }
+
+ public static boolean isCPURegister(Register... regs) {
+ for (Register reg : regs) {
+ if (!isCPURegister(reg)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean isCPURegister(Register r) {
+ return r.getRegisterCategory().equals(CPU);
+ }
+
+ public static boolean isGlobalRegister(Register r) {
+ return isCPURegister(r) && g0.number <= r.number && r.number <= g7.number;
+ }
+
+ public static boolean isSingleFloatRegister(Register r) {
+ return r.getRegisterCategory().equals(FPUs);
+ }
+
+ public static boolean isDoubleFloatRegister(Register r) {
+ return r.getRegisterCategory().equals(FPUd);
+ }
+
+ 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) {
+ long bits;
+ switch (constant.getJavaKind()) {
+ case Double:
+ bits = Double.doubleToRawLongBits(constant.asDouble());
+ break;
+ case Float:
+ bits = Float.floatToRawIntBits(constant.asFloat());
+ break;
+ case Object:
+ return constant.isNull();
+ default:
+ bits = constant.asLong();
+ break;
+ }
+ return constant.isNull() || isSimm13(bits);
+ }
+
+ 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);
+ int word = 0;
+ BitSpec.op.setBits(word, 0);
+ BitSpec.rd.setBits(word, a);
+ BitSpec.op2.setBits(word, op2);
+ BitSpec.imm22.setBits(word, b);
+ 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.value, 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.value, 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) : simm13;
+ int i = 1 << 13;
+ int simm13WithX = simm13 | getXBit(op3);
+ fmt(op3.op.value, rd.encoding, op3.value, rs1.encoding, i | simm13WithX & ((1 << 13) - 1));
+ }
+
+ public void insertNopAfterCBCond() {
+ int pos = position() - INSTRUCTION_SIZE;
+ if (pos == 0) {
+ return;
+ }
+ int inst = getInt(pos);
+ if (CBCOND.match(inst)) {
+ nop();
+ }
+ }
+
+ protected int patchUnbound(Label label) {
+ label.addPatchAt(position());
+ return 0;
+ }
+
+ // @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>
+ *
+ * @return Position of the call instruction
+ */
+ // @formatter:on
+ public int call(int disp30) {
+ assert isImm(disp30, 30);
+ insertNopAfterCBCond();
+ int before = position();
+ int instr = 1 << 30;
+ instr |= disp30;
+ emitInt(instr);
+ return before;
+ }
+
+ 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 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 fsrc2s(Register rs2, Register rd) {
+ op3(Impdep1, Fsrc2s, null, rs2, rd);
+ }
+
+ public void fsrc2d(Register rs2, Register rd) {
+ op3(Impdep1, Fsrc2d, 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;
+ delaySlotOptimizationPoints.add(position());
+ fmt10(a, Fpop2.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) {
+ insertNopAfterCBCond();
+ op3(Jmpl, rs1, rs2, rd);
+ }
+
+ /**
+ * @return Position of the jmpl instruction
+ */
+ public int jmpl(Register rs1, int simm13, Register rd) {
+ insertNopAfterCBCond();
+ int before = position();
+ op3(Jmpl, rs1, simm13, rd);
+ return before;
+ }
+
+ public void fmovdcc(ConditionFlag cond, CC cc, Register rs2, Register rd) {
+ fmovcc(cond, cc, rs2, rd, OpfLow.Fmovdcc.value);
+ }
+
+ public void fmovscc(ConditionFlag cond, CC cc, Register rs2, Register rd) {
+ fmovcc(cond, cc, rs2, rd, OpfLow.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.value, fcn.value, Prefetch.value, rs1.encoding, 1 << 13 | dis & ((1 << 13) - 1));
+ } else {
+ Register rs2 = addr.getIndex();
+ fmt(Prefetch.op.value, fcn.value, Prefetch.value, rs1.encoding, rs2.encoding);
+ }
+ }
+
+ // A.44 Read State Register
+
+ public void rdpc(Register rd) {
+ op3(Rd, g5, 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 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 pause() {
+ // Maybe fmt10(rd=0b1_1011, op3=0b11_0000, rs1=0, i=1, simm13=1), or
+ // maybe op3(Wr, g0, 1, %pause).
+ // What should the count be?
+ GraalError.unimplemented("The SPARC pause instruction is not yet implemented.");
+ }
+
+ 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, g2);
+ }
+
+ public void wrccr(Register rs1, int simm13) {
+ op3(Wr, rs1, simm13, g2);
+ }
+
+ 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.value, 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 ld(SPARCAddress src, Register dst, int bytes, boolean signExtend) {
+ if (isCPURegister(dst)) {
+ if (signExtend) {
+ switch (bytes) {
+ case 1:
+ ld(Ldsb, src, dst);
+ break;
+ case 2:
+ ld(Ldsh, src, dst);
+ break;
+ case 4:
+ ld(Ldsw, src, dst);
+ break;
+ case 8:
+ ld(Ldx, src, dst);
+ break;
+ default:
+ throw new InternalError();
+ }
+ } else {
+ switch (bytes) {
+ case 1:
+ ld(Ldub, src, dst);
+ break;
+ case 2:
+ ld(Lduh, src, dst);
+ break;
+ case 4:
+ ld(Lduw, src, dst);
+ break;
+ case 8:
+ ld(Ldx, src, dst);
+ break;
+ default:
+ throw new InternalError();
+ }
+ }
+ } else if (isDoubleFloatRegister(dst) && bytes == 8) {
+ assert !signExtend;
+ ld(Lddf, src, dst);
+ } else if (isSingleFloatRegister(dst) && bytes == 4) {
+ assert !signExtend;
+ ld(Ldf, src, dst);
+ } else {
+ throw new InternalError(String.format("src: %s dst: %s bytes: %d signExtend: %b", src, dst, bytes, signExtend));
+ }
+ }
+
+ public void st(Register src, SPARCAddress dst, int bytes) {
+ if (isCPURegister(src)) {
+ switch (bytes) {
+ case 1:
+ st(Stb, src, dst);
+ break;
+ case 2:
+ st(Sth, src, dst);
+ break;
+ case 4:
+ st(Stw, src, dst);
+ break;
+ case 8:
+ st(Stx, src, dst);
+ break;
+ default:
+ throw new InternalError(Integer.toString(bytes));
+ }
+ } else if (isDoubleFloatRegister(src) && bytes == 8) {
+ st(Stdf, src, dst);
+ } else if (isSingleFloatRegister(src) && bytes == 4) {
+ st(Stf, src, dst);
+ } else {
+ throw new InternalError(String.format("src: %s dst: %s bytes: %d", src, dst, bytes));
+ }
+ }
+
+ 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 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 isCPURegister(rs1, rs2, rd) : format("%s %s %s", rs1, rs2, rd);
+ ld(Lduwa, new SPARCAddress(rs1, rs2), rd, asi);
+ }
+
+ public void stxa(Register rd, Register rs1, Register rs2, Asi asi) {
+ assert isCPURegister(rs1, rs2, rd) : format("%s %s %s", rs1, rs2, rd);
+ ld(Stxa, 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, o7, 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);
+ }
+
+ /**
+ * Does peephole optimization on code generated by this assembler. This method should be called
+ * at the end of code generation.
+ * <p>
+ * It searches for conditional branch instructions which has nop in the delay slot then looks at
+ * the instruction at branch target; if it is an arithmetic instruction, which does not throw an
+ * exception (e.g. division), it pulls this instruction into the delay slot and increments the
+ * displacement by 1.
+ */
+ public void peephole() {
+ for (int i : delaySlotOptimizationPoints) {
+ optimizeDelaySlot(i);
+ }
+ }
+
+ /**
+ * Optimizes branch instruction <i>b</t> which has a nop in the delay slot. It tries to stuff
+ * the instruction at <i>b</i>s branch target into the delay slot of <i>b</i>, set the annul
+ * flag and increments <i>b</i>s disp field by 1;
+ * <p>
+ * If <i>b</i>s branch target instruction is an unconditional branch <i>t</i>, then it tries to
+ * put <i>t</i>s delayed instruction into the delay slot of <i>b</i> and add the <i>t</i>s disp
+ * field to <i>b</i>s disp field.
+ */
+ private void optimizeDelaySlot(int i) {
+ int delaySlotAbsolute = i + INSTRUCTION_SIZE;
+ int nextInst = getInt(delaySlotAbsolute);
+ SPARCOp nextOp = getSPARCOp(nextInst);
+ if (nextOp instanceof Sethi && Sethi.isNop(nextInst)) {
+ int inst = getInt(i);
+ SPARCOp op = getSPARCOp(inst);
+ if (op instanceof ControlTransferOp && ((ControlTransferOp) op).hasDelaySlot() && ((ControlTransferOp) op).isAnnulable(inst)) {
+ ControlTransferOp ctOp = (ControlTransferOp) op;
+ int disp = ctOp.getDisp(inst);
+ int branchTargetAbsolute = i + disp * INSTRUCTION_SIZE;
+ int branchTargetInst = getInt(branchTargetAbsolute);
+ SPARCOp branchTargetOp = getSPARCOp(branchTargetInst);
+ if (branchTargetOp instanceof Op3Op) {
+ Op3s op3 = ((Op3Op) branchTargetOp).getOp3(branchTargetInst);
+ if (!op3.throwsException()) {
+ inst = ctOp.setDisp(inst, disp + 1); // Increment the offset
+ inst = ctOp.setAnnul(inst, true);
+ emitInt(inst, i);
+ emitInt(branchTargetInst, delaySlotAbsolute);
+ }
+ } else if (branchTargetOp instanceof ControlTransferOp && !((ControlTransferOp) branchTargetOp).isConditional(branchTargetInst)) {
+ // If branchtarget is a unconditional branch
+ ControlTransferOp branchTargetOpBranch = (ControlTransferOp) branchTargetOp;
+ int btDisp = branchTargetOpBranch.getDisp(branchTargetInst);
+ int newDisp = disp + btDisp;
+ if (ctOp.isValidDisp(newDisp)) { // Test if we don't exceed field size
+ int instAfter = ctOp.setDisp(inst, newDisp);
+ instAfter = ctOp.setAnnul(instAfter, true);
+ branchTargetInst = getInt(branchTargetAbsolute + INSTRUCTION_SIZE);
+ branchTargetOp = getSPARCOp(branchTargetInst);
+ if (branchTargetOp instanceof Op3Op && !((Op3Op) branchTargetOp).getOp3(branchTargetInst).throwsException()) {
+ emitInt(instAfter, i);
+ emitInt(branchTargetInst, delaySlotAbsolute);
+ }
+ }
+ }
+ }
+ }
+ }
+}