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.BranchTargetOutOfBoundsException;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.core.common.NumUtil;
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;
public abstract class SPARCAssembler extends Assembler {
public SPARCAssembler(TargetDescription target) {
super(target);
}
public static final int INSTRUCTION_SIZE = 4;
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 {
BranchOp(0b00),
CallOp(0b01),
ArithOp(0b10),
LdstOp(0b11);
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 {
Illtrap(0b000),
Bpr (0b011),
Fb (0b110),
Fbp (0b101),
Br (0b010),
Bp (0b001),
Cb (0b111),
Sethi (0b100);
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 {
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);
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 {
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),
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),
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),
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);
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 {
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");
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;
}
}
public enum CC {
Icc(0b00, "icc", false),
Xcc(0b10, "xcc", false),
Fcc0(0b00, "fcc0", true),
Fcc1(0b01, "fcc1", true),
Fcc2(0b10, "fcc2", true),
Fcc3(0b11, "fcc3", true);
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 {
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"),
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);
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() {
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();
}
}
public ConditionFlag mirror() {
switch (this) {
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;
}
}
}
public enum RCondition {
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");
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;
}
}
public enum Asi {
INVALID(-1),
ASI_PRIMARY(0x80),
ASI_PRIMARY_NOFAULT(0x82),
ASI_PRIMARY_LITTLE(0x88),
ASI_ST_BLKINIT_PRIMARY(0xE2),
ASI_ST_BLKINIT_MRU_PRIMARY(0xF2);
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;
}
}
@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);
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");
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);
}
}
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;
}
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);
}
}
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);
}
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 + "]";
}
}
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 BranchTargetOutOfBoundsException(true, "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);
}
}
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() {
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)});
}
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);
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) {
return x & ((1 << nbits) - 1);
}
public static final boolean isImm(int x, int nbits) {
return simm(x, nbits) == x;
}
public static long minSimm(long nbits) {
return -(1L << (nbits - 1));
}
public static long maxSimm(long nbits) {
return (1L << (nbits - 1)) - 1;
}
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 isSimm5(long imm) {
return isSimm(imm, 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);
}
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(), this);
return 0;
}
public void nop() {
emitInt(1 << 24);
}
public void sethi(int imm22, Register dst) {
fmt00(dst.encoding, Op2s.Sethi.value, imm22);
}
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);
}
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);
}
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);
}
protected void fmt10(int rd, int op3, int rs1, int b) {
fmt(0b10, rd, op3, rs1, b);
}
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);
}
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);
}
}
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() {
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);
}
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);
}
public void peephole() {
for (int i : delaySlotOptimizationPoints) {
optimizeDelaySlot(i);
}
}
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);
inst = ctOp.setAnnul(inst, true);
emitInt(inst, i);
emitInt(branchTargetInst, delaySlotAbsolute);
}
} else if (branchTargetOp instanceof ControlTransferOp && !((ControlTransferOp) branchTargetOp).isConditional(branchTargetInst)) {
ControlTransferOp branchTargetOpBranch = (ControlTransferOp) branchTargetOp;
int btDisp = branchTargetOpBranch.getDisp(branchTargetInst);
int newDisp = disp + btDisp;
if (ctOp.isValidDisp(newDisp)) {
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);
}
}
}
}
}
}
}