+static void
+_instr(jit_state_t *_jit, jit_int32_t op)
+{
+ if (_jitc->inst.pend)
+ ii(_jitc->inst.op);
+ else
+ _jitc->inst.pend = 1;
+ _jitc->inst.op = op;
+}
+
+static void
+_flush(jit_state_t *_jit)
+{
+ if (_jitc->inst.pend) {
+ ii(_jitc->inst.op);
+ _jitc->inst.pend = 0;
+ }
+}
+
+static jit_int32_t
+_pending(jit_state_t *_jit)
+{
+ jit_int32_t op;
+ if (_jitc->inst.pend) {
+ op = _jitc->inst.op;
+ _jitc->inst.pend = 0;
+ }
+ else
+ op = 0;
+ return (op);
+}
+
+static void
+_delay(jit_state_t *_jit, jit_int32_t op)
+{
+ assert(_jitc->inst.pend);
+ ii(_jitc->inst.op);
+ _jitc->inst.pend = 0;
+ ii(op);
+}
+
+static jit_int32_t
+_jit_get_reg_for_delay_slot(jit_state_t *_jit, jit_int32_t mask,
+ jit_int32_t reg0, jit_int32_t reg1)
+{
+ jit_instr_t i;
+ jit_int32_t reg, r0, r1, r2/*, xreg*/, regs[3];
+ /* If will emit a pending instruction */
+ if (_jitc->inst.pend)
+ i.op = _jitc->inst.op;
+ /* Else if at least one instruction emited, check it */
+ else if (_jit->pc.uc > _jit->code.ptr)
+ i.op = _jit->pc.ui[-1];
+ /* Else, a nop */
+ else
+ i.op = 0;
+ regs[0] = regs[1] = regs[2]/* = xreg*/ = -1;
+ switch (i.hc.b) {
+ case MIPS_SPECIAL: /* 00 */
+ switch (i.tc.b) {
+ case MIPS_SLLV: /* 04 */
+ case MIPS_SRLV: /* 06 */
+ case MIPS_SRAV: /* 07 */
+ case MIPS_DSLLV: /* 14 */
+ case MIPS_DSRLV: /* 16 */
+ case MIPS_DSRAV: /* 17 */
+ case MIPS_ADDU: /* 21 */
+ case MIPS_SUBU: /* 23 */
+ case MIPS_AND: /* 24 */
+ case MIPS_OR: /* 25 */
+ case MIPS_XOR: /* 26 */
+ case MIPS_NOR: /* 27 */
+ case MIPS_SLT: /* 2a */
+ case MIPS_SLTU: /* 2b */
+ case MIPS_DADDU: /* 2d */
+ case MIPS_DSUBU: /* 2f */
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = i.rd.b;
+ }
+ break;
+ /* MUL MUH */
+ case MIPS_MULT: /* 18 */
+ /* MULU MUHU */
+ case MIPS_MULTU: /* 19 */
+ /* DIV MOD */
+ case MIPS_DIV: /* 1a */
+ /* DIVU MODU */
+ case MIPS_DIVU: /* 1b */
+ /* DMUL DMUH */
+ case MIPS_DMULT: /* 1c */
+ /* DMULU DMUHU */
+ case MIPS_DMULTU: /* 1d */
+ /* DDIV DMOD */
+ case MIPS_DDIV: /* 1e */
+ /* DDIVU DMODU */
+ case MIPS_DDIVU: /* 1f */
+ if (jit_mips6_p()) {
+ assert(i.ic.b == 2 || i.ic.b == 3);
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = i.rd.b;
+ }
+ }
+ else {
+ assert(i.rd.b == 0);
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = 0;
+ }
+ }
+ break;
+ /* CLZ */
+ case MIPS_MFHI: /* 10 */
+ /* CLO */
+ case MIPS_MTHI: /* 11 */
+ /* DCLZ */
+ case MIPS_MFLO: /* 12 */
+ /* DCLO */
+ case MIPS_MTLO: /* 13 */
+ if (mask & jit_class_gpr) {
+ if (jit_mips6_p()) {
+ assert(i.ic.b == 1);
+ regs[1] = i.rd.b;
+ }
+ else {
+ assert(!i.rs.b && !i.rt.b);
+ regs[1] = 0;
+ }
+ regs[0] = i.rd.b;
+ regs[1] = 0;
+ }
+ break;
+ case MIPS_JR: /* 08 */
+ assert(!jit_mips6_p());
+ case MIPS_JALR: /* 09 */
+ /* check for proper/known encondig */
+ assert(!i.ic.b);
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = i.rd.b;
+ }
+ break;
+ case MIPS_SLL: /* 00 */
+ /* If cannot have a shift in delay slot */
+ if (!jit_cpu.sll_delay)
+ flush();
+ case MIPS_SRL: /* 02 */
+ case MIPS_SRA: /* 03 */
+ case MIPS_DSLL: /* 38 */
+ case MIPS_DSRL: /* 3a */
+ case MIPS_DSRA: /* 3b */
+ case MIPS_DSLL32: /* 3c */
+ case MIPS_DSRA32: /* 3f */
+ case MIPS_DSRL32: /* 3e */
+ /* shift (or rotate if i.rs.b == 1) */
+ assert(i.rs.b == 0 || i.rs.b == 1);
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rt.b;
+ regs[1] = i.rd.b;
+ regs[2] = 0;
+ }
+ break;
+ case MIPS_SYNC: /* 0f */
+ assert(i.rs.b == 0 && i.rt.b == 0 && i.rd.b == 0);
+ if (mask & jit_class_gpr)
+ regs[0] = regs[1] = regs[2] = 0;
+ break;
+ case MIPS_MOVZ: /* 0a */
+ case MIPS_MOVN: /* 0b */
+ assert(!jit_mips6_p() && i.ic.b == 0);
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = i.rd.b;
+ }
+ break;
+ /* SELEQZ */
+ case 53: /* 35 */
+ /* SELNEZ */
+ case 55: /* 37 */
+ assert(jit_mips6_p() && i.ic.b == 0);
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = i.rd.b;
+ }
+ break;
+ default:
+ abort();
+ }
+ break;
+ case MIPS_REGIMM: /* 01 */
+ switch (i.rt.b) {
+ /* DAHI */
+ case 6: /* 06 */
+ /* DATI */
+ case 15: /* 1e */
+ assert(jit_mips6_p());
+ case MIPS_BLTZ: /* 00 */
+ case MIPS_BGEZ: /* 01 */
+ case MIPS_BGEZAL: /* 11 */
+ break;
+ default:
+ abort();
+ }
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = regs[2] = 0;
+ }
+ break;
+ case MIPS_BC_R6: /* 32 */
+ case MIPS_BALC: /* 3a */
+ assert(jit_mips6_p());
+ case MIPS_J: /* 02 */
+ case MIPS_JAL: /* 03 */
+ if (mask & jit_class_gpr)
+ regs[0] = regs[1] = regs[2] = 0;
+ break;
+ case MIPS_LUI: /* 0f */
+ assert(jit_mips6_p() || i.rs.b == 0);
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rt.b;
+ regs[1] = i.rs.b; /* AUI if non zero */
+ regs[1] = 0;
+ }
+ break;
+ case MIPS_SPECIAL2: /* 1c */
+ switch (i.tc.b) {
+ case MIPS_CLZ: /* 20 */
+ case MIPS_CLO: /* 21 */
+ case MIPS_DCLZ: /* 24 */
+ case MIPS_DCLO: /* 25 */
+ assert(!jit_mips6_p() && i.rt.b == i.rd.b && i.ic.b == 0);
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rd.b;
+ regs[2] = 0;
+ }
+ break;
+ case MIPS_MUL: /* 02 */
+ assert(jit_mips2_p() && i.ic.b == 0);
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = i.rd.b;
+ }
+ break;
+ default:
+ abort();
+ }
+ break;
+ case MIPS_SPECIAL3: /* 1f */
+ switch (i.tc.b) {
+ case MIPS_EXT: /* 00 */
+ case MIPS_DEXTM: /* 01 */
+ case MIPS_DEXTU: /* 02 */
+ case MIPS_DEXT: /* 03 */
+ case MIPS_INS: /* 04 */
+ case MIPS_DINSM: /* 05 */
+ case MIPS_DINSU: /* 06 */
+ case MIPS_DINS: /* 07 */
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = 0;
+ }
+ break;
+ /* BITSWAP */
+ case MIPS_BSHFL: /* 20 */
+ /* DBITSWAP */
+ case MIPS_DBSHFL: /* 24 */
+ switch (i.ic.b) {
+ /* DSBH */
+ case MIPS_WSBH: /* 02 */
+ case MIPS_DSHD: /* 05 */
+ case MIPS_SEB: /* 10 */
+ case MIPS_SEH: /* 18 */
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rt.b;
+ regs[1] = i.rd.b;
+ regs[2] = 0;
+ }
+ break;
+ /* BITSWAP DBITSWAP */
+ case 0:
+ assert(jit_mips6_p() && i.rt.b == 0);
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rd.b;
+ regs[2] = 0;
+ }
+ break;
+ default:
+ abort();
+ }
+ break;
+ /* SC */
+ case 38: /* 26 */
+ /* SCD */
+ case 39: /* 27 */
+ /* LD */
+ case 54: /* 36 */
+ /* LLD */
+ case 55: /* 37 */
+ assert(jit_mips6_p());
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = 0;
+ }
+ break;
+ default:
+ abort();
+ }
+ break;
+ case MIPS_COP1: /* 11 */
+ switch (i.tc.b) {
+ case MIPS_ADD_fmt: /* 00 */
+ switch (i.rs.b) {
+ case MIPS_MF: /* 00 */
+ case MIPS_DMF: /* 01 */
+ case MIPS_MFH: /* 03 */
+ case MIPS_MT: /* 04 */
+ case MIPS_DMT: /* 05 */
+ case MIPS_MTH: /* 07 */
+ assert(i.ic.b == 0);
+ /* If these cop1 instructions in delay slot
+ * wont work */
+ if (!jit_cpu.cop1_delay)
+ flush();
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rt.b;
+ regs[1] = regs[2] = 0;
+ }
+ else
+ regs[0] = i.rd.b;
+ break;
+ default:
+ goto three_fprs;
+ }
+ break;
+ case MIPS_MADDF: /* 18 */
+ case MIPS_MSUBF: /* 19 */
+ assert(jit_mips6_p());
+ case MIPS_SUB_fmt: /* 01 */
+ case MIPS_MUL_fmt: /* 02 */
+ case MIPS_DIV_fmt: /* 03 */
+ three_fprs:
+ /* 10 */
+ assert(i.rs.b == MIPS_fmt_S ||
+ /* 11 */
+ i.rs.b == MIPS_fmt_D);
+ if (mask & jit_class_gpr)
+ regs[0] = regs[1] = regs[2] = 0;
+ else {
+ regs[0] = i.rt.b;
+ regs[1] = i.rd.b;
+ regs[2] = i.ic.b;
+ }
+ break;
+ case MIPS_SQRT_fmt: /* 04 */
+ case MIPS_ABS_fmt: /* 05 */
+ case MIPS_MOV_fmt: /* 06 */
+ case MIPS_NEG_fmt: /* 07 */
+ assert((i.rs.b == MIPS_fmt_S || i.rs.b == MIPS_fmt_D) &&
+ i.rt.b == 0);
+ if (mask & jit_class_gpr)
+ regs[0] = regs[1] = regs[2] = 0;
+ else {
+ regs[0] = i.rd.b;
+ regs[1] = i.ic.b;
+ }
+ break;
+ case MIPS_CVT_fmt_S: /* 20 */
+ case MIPS_CVT_fmt_D: /* 21 */
+ case MIPS_CVT_fmt_W: /* 24 */
+ case MIPS_CVT_fmt_L: /* 25 */
+ switch (i.rs.b) {
+ case MIPS_fmt_S:/* 10 */
+ case MIPS_fmt_D:/* 11 */
+ case MIPS_fmt_W:/* 14 */
+ case MIPS_fmt_L:/* 15 */
+ break;
+ default:
+ abort();
+ }
+ assert(i.rt.b == 0);
+ if (mask & jit_class_gpr)
+ regs[0] = regs[1] = regs[2] = 0;
+ else {
+ regs[0] = i.rd.b;
+ regs[1] = i.ic.b;
+ }
+ break;
+ case MIPS_cond_F: /* 30 */
+ case MIPS_cond_UN: /* 31 */
+ case MIPS_cond_EQ: /* 32 */
+ case MIPS_cond_UEQ: /* 33 */
+ case MIPS_cond_OLT: /* 34 */
+ case MIPS_cond_ULT: /* 35 */
+ case MIPS_cond_OLE: /* 36 */
+ case MIPS_cond_ULE: /* 37 */
+ case MIPS_cond_SF: /* 38 */
+ case MIPS_cond_NGLE: /* 39 */
+ case MIPS_cond_SEQ: /* 3a */
+ case MIPS_cond_NGL: /* 3b */
+ case MIPS_cond_LT: /* 3c */
+ case MIPS_cond_NGE: /* 3d */
+ case MIPS_cond_LE: /* 3e */
+ case MIPS_cond_UGT: /* 3f */
+ assert(!jit_mips6_p() &&
+ /* 10 */
+ (i.fm.b == MIPS_fmt_S ||
+ /* 11 */
+ i.fm.b == MIPS_fmt_D));
+ if (mask & jit_class_gpr)
+ regs[0] = regs[1] = regs[2] = 0;
+ else {
+ regs[0] = i.ft.b;
+ regs[1] = i.fs.b;
+ }
+ break;
+ default:
+ switch (i.ic.b) {
+ case MIPS_cmp_AF: /* 00 */
+ case MIPS_cmp_UN: /* 01 */
+ case MIPS_cmp_EQ: /* 02 */
+ case MIPS_cmp_UEQ: /* 03 */
+ case MIPS_cmp_LT: /* 04 */
+ case MIPS_cmp_ULT: /* 05 */
+ case MIPS_cmp_LE: /* 06 */
+ case MIPS_cmp_ULE: /* 07 */
+ case MIPS_cmp_SAF: /* 08 */
+ case MIPS_cmp_SUN: /* 09 */
+ case MIPS_cmp_SEQ: /* 0a */
+ case MIPS_cmp_SUEQ:/* 0b */
+ case MIPS_cmp_SLT: /* 0c */
+ case MIPS_cmp_SULT:/* 0d */
+ case MIPS_cmp_SLE: /* 0e */
+ case MIPS_cmp_SULE:/* 0f */
+ assert(jit_mips6_p() &&
+ /* 14 */
+ (i.rs.b == MIPS_condn_S ||
+ /* 15 */
+ i.rs.b == MIPS_condn_D));
+ if (mask & jit_class_gpr)
+ regs[0] = regs[1] = regs[2] = 0;
+ else {
+ regs[0] = i.ft.b;
+ regs[1] = i.fs.b;
+ regs[2] = i.fd.b;
+ }
+ goto done;
+ default:
+ break;
+ }
+ switch (i.rt.b) {
+ case MIPS_BC: /* 08 */
+ assert(!jit_mips6_p() &&
+ /* 00 */
+ (i.rs.b == MIPS_BCF ||
+ /* 01 */
+ i.rs.b == MIPS_BCT));
+ if (mask & jit_class_gpr)
+ regs[0] = regs[1] = regs[2] = 0;
+ else {
+ regs[0] = i.rt.b;
+ regs[1] = i.rd.b;
+ }
+ break;
+ case MIPS_BC1EQZ:/* 09 */
+ case MIPS_BC1NEZ:/* 0a */
+ assert(jit_mips6_p());
+ if (mask & jit_class_gpr)
+ regs[0] = regs[1] = regs[2] = 0;
+ else
+ regs[0] = i.rt.b;
+ break;
+ default:
+ abort();
+ }
+ break;
+ }
+ break;
+ case MIPS_COP1X: /* 13 */
+ switch (i.tc.b) {
+ case MIPS_MADD_fmt_S:
+ case MIPS_MADD_fmt_D:
+ case MIPS_MSUB_fmt_S:
+ case MIPS_MSUB_fmt_D:
+ case MIPS_NMADD_fmt_S:
+ case MIPS_NMADD_fmt_D:
+ case MIPS_NMSUB_fmt_S:
+ case MIPS_NMSUB_fmt_D:
+ assert(!jit_mips6_p());
+ if (mask & jit_class_gpr)
+ regs[0] = regs[1] = regs[2] = 0;
+ else {
+ regs[0] = i.ft.b;
+ regs[1] = i.fs.b;
+ regs[2] = i.fd.b;
+ /* FIXME No need to compute and check it.
+ * If asking for a tmeporary fpr, code will
+ * be flushed. */
+ /* xreg = i.fr.b; */
+ }
+ break;
+ default:
+ abort();
+ }
+ break;
+ case MIPS_DAUI: /* JALX */ /* 1d */
+ /* Do not generate JALX. No microMIPS64 or MIPS16e support */
+ assert(jit_mips6_p() && i.rs.b != 0);
+ case MIPS_ADDIU: /* 09 */
+ case MIPS_SLTI: /* 0a */
+ case MIPS_SLTIU: /* 0b */
+ case MIPS_ANDI: /* 0c */
+ case MIPS_ORI: /* 0d */
+ case MIPS_XORI: /* 0e */
+ case MIPS_DADDIU: /* 18 */
+ case MIPS_LDL: /* 1a */
+ case MIPS_LDR: /* 1b */
+ case MIPS_LB: /* 20 */
+ case MIPS_LH: /* 21 */
+ case MIPS_LW: /* 23 */
+ case MIPS_LBU: /* 24 */
+ case MIPS_LHU: /* 25 */
+ case MIPS_LWU: /* 27 */
+ case MIPS_SB: /* 28 */
+ case MIPS_SH: // 29 */
+ case MIPS_SW: /* 2b */
+ case MIPS_LD: /* 37 */
+ case MIPS_SD: /* 3f */
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = 0;
+ }
+ break;
+ case MIPS_LWL: /* 22 */
+ case MIPS_LWR: /* 26 */
+ if (!jit_cpu.lwl_lwr_delay)
+ flush();
+ case MIPS_SWL: /* 2a */
+ case MIPS_SWR: /* 2e */
+ case MIPS_SDL: /* 2c */
+ case MIPS_SDR: /* 2d */
+ assert(!(jit_mips6_p()));
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = 0;
+ }
+ break;
+ case MIPS_LL: /* 30 */
+ case MIPS_LLD: /* 34 */
+ case MIPS_SC: /* 38 */
+ case MIPS_SCD: /* 3c */
+ assert(!jit_mips6_p() && i.ic.b == 0);
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = 0;
+ }
+ break;
+ case MIPS_BLEZ: /* 06 */
+ case MIPS_BGTZ: /* 07 */
+ assert(i.rt.b == 0);
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = regs[2] = 0;
+ }
+ break;
+ case MIPS_LWC1: /* 31 */
+ case MIPS_LDC1: /* 35 */
+ case MIPS_SWC1: /* 39 */
+ case MIPS_SDC1: /* 3d */
+ /* If these cop1 instructions in delay wont not work */
+ if (!jit_cpu.cop1_delay)
+ flush();
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = 0;
+ }
+ else
+ regs[0] = i.rt.b;
+ break;
+ case MIPS_BEQ: /* 04 */
+ case MIPS_BNE: /* 05 */
+ assert(i.rt.b == 0);
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = i.rt.b;
+ regs[2] = 0;
+ }
+ else
+ regs[0] = i.rt.b;
+ break;
+ case MIPS_PCREL: /* 0x3b */
+ assert(jit_mips6_p());
+ switch (i.rt.b) {
+ case 0x1e: /* AUIPC */
+ case 0x1f: /* ALUIPC */
+ break;
+ default:
+ assert(i.pD.b == 1 ||/* LDPC */
+ i.pW.b == 0 ||/* ADDIUPC */
+ i.pW.b == 1 ||/* LWPC */
+ i.pW.b == 2); /* LWUPC */
+ break;
+ }
+ if (mask & jit_class_gpr) {
+ regs[0] = i.rs.b;
+ regs[1] = regs[2] = 0;
+ }
+ break;
+ default:
+ abort();
+ }
+done:
+ /* If cannot move instruction do delay slot */
+ if (_jitc->inst.pend &&
+ (((mask & jit_class_fpr) || reg0) &&
+ (reg0 == regs[0] || reg0 == regs[1] || reg0 == regs[2])) ||
+ (((mask & jit_class_fpr) || reg1) &&
+ (reg1 == regs[0] || reg1 == regs[1] || reg1 == regs[2]))) {
+ flush();
+ }
+ /* Get a temporary register */
+retry:
+ reg = jit_get_reg(mask|jit_class_nospill);
+ /* Make sure will not use a register in use by delay slot */
+ if (_jitc->inst.pend) {
+ if (rn(reg) == regs[0] ||
+ rn(reg) == regs[1] || rn(reg) == regs[2]) {
+ r0 = reg;
+ reg = jit_get_reg(mask|jit_class_nospill);
+ if (rn(reg) == regs[0] ||
+ rn(reg) == regs[1] || rn(reg) == regs[2]) {
+ r1 = reg;
+ reg = jit_get_reg(mask|jit_class_nospill);
+ if (rn(reg) == regs[0] ||
+ rn(reg) == regs[1] || rn(reg) == regs[2]) {
+ r2 = reg;
+ reg = jit_get_reg(mask|jit_class_nospill);
+ jit_unget_reg(r2);
+ }
+ jit_unget_reg(r1);
+ }
+ jit_unget_reg(r0);
+ }
+ }
+ if (reg == JIT_NOREG) {
+ /* Cannot get a register to optimize delay slot */
+ flush();
+ /* Must find a free register */
+ if (!(mask & jit_class_chk))
+ goto retry;
+ }
+ assert(reg != JIT_NOREG || (mask & jit_class_chk));
+ return (reg);
+}
+