Commit ae2dbf7f authored by ths's avatar ths
Browse files

Micro-optimize back-to-back store-load sequences.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3743 c046a42c-6fe2-441c-8c8c-71466251a162
parent 2382dc6b
......@@ -543,6 +543,8 @@ typedef struct DisasContext {
uint32_t hflags, saved_hflags;
int bstate;
target_ulong btarget;
void *last_T0_store;
int last_T0_gpr;
} DisasContext;
enum {
......@@ -572,12 +574,33 @@ do { \
ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \
} while (0)
#define GEN_LOAD_REG_TN(Tn, Rn) \
#define GEN_LOAD_REG_T0(Rn) \
do { \
if (Rn == 0) { \
glue(gen_op_reset_, Tn)(); \
gen_op_reset_T0(); \
} else { \
if (ctx->glue(last_T0, _store) != gen_opc_ptr \
|| ctx->glue(last_T0, _gpr) != Rn) { \
gen_op_load_gpr_T0(Rn); \
} \
} \
} while (0)
#define GEN_LOAD_REG_T1(Rn) \
do { \
if (Rn == 0) { \
gen_op_reset_T1(); \
} else { \
gen_op_load_gpr_T1(Rn); \
} \
} while (0)
#define GEN_LOAD_REG_T2(Rn) \
do { \
if (Rn == 0) { \
gen_op_reset_T2(); \
} else { \
glue(gen_op_load_gpr_, Tn)(Rn); \
gen_op_load_gpr_T2(Rn); \
} \
} while (0)
......@@ -612,13 +635,21 @@ do { \
} while (0)
#endif
#define GEN_STORE_TN_REG(Rn, Tn) \
#define GEN_STORE_T0_REG(Rn) \
do { \
if (Rn != 0) { \
glue(glue(gen_op_store_, Tn),_gpr)(Rn); \
glue(gen_op_store_T0,_gpr)(Rn); \
ctx->glue(last_T0,_store) = gen_opc_ptr; \
ctx->glue(last_T0,_gpr) = Rn; \
} \
} while (0)
#define GEN_STORE_T1_REG(Rn) \
do { \
if (Rn != 0) \
glue(gen_op_store_T1,_gpr)(Rn); \
} while (0)
#define GEN_STORE_TN_SRSREG(Rn, Tn) \
do { \
if (Rn != 0) { \
......@@ -855,126 +886,126 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
#if defined(TARGET_MIPS64)
case OPC_LWU:
op_ldst(lwu);
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "lwu";
break;
case OPC_LD:
op_ldst(ld);
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "ld";
break;
case OPC_LLD:
op_ldst(lld);
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "lld";
break;
case OPC_SD:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(sd);
opn = "sd";
break;
case OPC_SCD:
save_cpu_state(ctx, 1);
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(scd);
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "scd";
break;
case OPC_LDL:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(ldl);
GEN_STORE_TN_REG(rt, T1);
GEN_STORE_T1_REG(rt);
opn = "ldl";
break;
case OPC_SDL:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(sdl);
opn = "sdl";
break;
case OPC_LDR:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(ldr);
GEN_STORE_TN_REG(rt, T1);
GEN_STORE_T1_REG(rt);
opn = "ldr";
break;
case OPC_SDR:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(sdr);
opn = "sdr";
break;
#endif
case OPC_LW:
op_ldst(lw);
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "lw";
break;
case OPC_SW:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(sw);
opn = "sw";
break;
case OPC_LH:
op_ldst(lh);
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "lh";
break;
case OPC_SH:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(sh);
opn = "sh";
break;
case OPC_LHU:
op_ldst(lhu);
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "lhu";
break;
case OPC_LB:
op_ldst(lb);
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "lb";
break;
case OPC_SB:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(sb);
opn = "sb";
break;
case OPC_LBU:
op_ldst(lbu);
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "lbu";
break;
case OPC_LWL:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(lwl);
GEN_STORE_TN_REG(rt, T1);
GEN_STORE_T1_REG(rt);
opn = "lwl";
break;
case OPC_SWL:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(swl);
opn = "swr";
break;
case OPC_LWR:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(lwr);
GEN_STORE_TN_REG(rt, T1);
GEN_STORE_T1_REG(rt);
opn = "lwr";
break;
case OPC_SWR:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(swr);
opn = "swr";
break;
case OPC_LL:
op_ldst(ll);
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "ll";
break;
case OPC_SC:
save_cpu_state(ctx, 1);
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
op_ldst(sc);
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "sc";
break;
default:
......@@ -1059,7 +1090,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc,
case OPC_ANDI:
case OPC_ORI:
case OPC_XORI:
GEN_LOAD_REG_TN(T0, rs);
GEN_LOAD_REG_T0(rs);
GEN_LOAD_IMM_TN(T1, uimm);
break;
case OPC_LUI:
......@@ -1077,7 +1108,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc,
case OPC_DSRL32:
#endif
uimm &= 0x1f;
GEN_LOAD_REG_TN(T0, rs);
GEN_LOAD_REG_T0(rs);
GEN_LOAD_IMM_TN(T1, uimm);
break;
}
......@@ -1222,7 +1253,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc,
generate_exception(ctx, EXCP_RI);
return;
}
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
}
......@@ -1239,14 +1270,14 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
MIPS_DEBUG("NOP");
return;
}
GEN_LOAD_REG_TN(T0, rs);
GEN_LOAD_REG_T0(rs);
/* Specialcase the conventional move operation. */
if (rt == 0 && (opc == OPC_ADDU || opc == OPC_DADDU
|| opc == OPC_SUBU || opc == OPC_DSUBU)) {
GEN_STORE_TN_REG(rd, T0);
GEN_STORE_T0_REG(rd);
return;
}
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
switch (opc) {
case OPC_ADD:
save_cpu_state(ctx, 1);
......@@ -1389,7 +1420,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
generate_exception(ctx, EXCP_RI);
return;
}
GEN_STORE_TN_REG(rd, T0);
GEN_STORE_T0_REG(rd);
print:
MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
}
......@@ -1407,21 +1438,21 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
switch (opc) {
case OPC_MFHI:
gen_op_load_HI(0);
GEN_STORE_TN_REG(reg, T0);
GEN_STORE_T0_REG(reg);
opn = "mfhi";
break;
case OPC_MFLO:
gen_op_load_LO(0);
GEN_STORE_TN_REG(reg, T0);
GEN_STORE_T0_REG(reg);
opn = "mflo";
break;
case OPC_MTHI:
GEN_LOAD_REG_TN(T0, reg);
GEN_LOAD_REG_T0(reg);
gen_op_store_HI(0);
opn = "mthi";
break;
case OPC_MTLO:
GEN_LOAD_REG_TN(T0, reg);
GEN_LOAD_REG_T0(reg);
gen_op_store_LO(0);
opn = "mtlo";
break;
......@@ -1438,8 +1469,8 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
{
const char *opn = "mul/div";
GEN_LOAD_REG_TN(T0, rs);
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T0(rs);
GEN_LOAD_REG_T1(rt);
switch (opc) {
case OPC_DIV:
gen_op_div();
......@@ -1508,7 +1539,7 @@ static void gen_cl (DisasContext *ctx, uint32_t opc,
MIPS_DEBUG("NOP");
return;
}
GEN_LOAD_REG_TN(T0, rs);
GEN_LOAD_REG_T0(rs);
switch (opc) {
case OPC_CLO:
gen_op_clo();
......@@ -1554,8 +1585,8 @@ static void gen_trap (DisasContext *ctx, uint32_t opc,
case OPC_TNE:
/* Compare two registers */
if (rs != rt) {
GEN_LOAD_REG_TN(T0, rs);
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T0(rs);
GEN_LOAD_REG_T1(rt);
cond = 1;
}
break;
......@@ -1567,7 +1598,7 @@ static void gen_trap (DisasContext *ctx, uint32_t opc,
case OPC_TNEI:
/* Compare register to immediate */
if (rs != 0 || imm != 0) {
GEN_LOAD_REG_TN(T0, rs);
GEN_LOAD_REG_T0(rs);
GEN_LOAD_IMM_TN(T1, (int32_t)imm);
cond = 1;
}
......@@ -1680,8 +1711,8 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
case OPC_BNEL:
/* Compare two registers */
if (rs != rt) {
GEN_LOAD_REG_TN(T0, rs);
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T0(rs);
GEN_LOAD_REG_T1(rt);
bcond = 1;
}
btarget = ctx->pc + 4 + offset;
......@@ -1720,7 +1751,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
generate_exception(ctx, EXCP_RI);
return;
}
GEN_LOAD_REG_TN(T2, rs);
GEN_LOAD_REG_T2(rs);
break;
default:
MIPS_INVAL("branch/jump");
......@@ -1896,7 +1927,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
int rs, int lsb, int msb)
{
GEN_LOAD_REG_TN(T1, rs);
GEN_LOAD_REG_T1(rs);
switch (opc) {
case OPC_EXT:
if (lsb + msb > 31)
......@@ -1923,26 +1954,26 @@ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
case OPC_INS:
if (lsb > msb)
goto fail;
GEN_LOAD_REG_TN(T0, rt);
GEN_LOAD_REG_T0(rt);
gen_op_ins(lsb, msb - lsb + 1);
break;
#if defined(TARGET_MIPS64)
case OPC_DINSM:
if (lsb > msb)
goto fail;
GEN_LOAD_REG_TN(T0, rt);
GEN_LOAD_REG_T0(rt);
gen_op_dins(lsb, msb - lsb + 1 + 32);
break;
case OPC_DINSU:
if (lsb > msb)
goto fail;
GEN_LOAD_REG_TN(T0, rt);
GEN_LOAD_REG_T0(rt);
gen_op_dins(lsb + 32, msb - lsb + 1);
break;
case OPC_DINS:
if (lsb > msb)
goto fail;
GEN_LOAD_REG_TN(T0, rt);
GEN_LOAD_REG_T0(rt);
gen_op_dins(lsb, msb - lsb + 1);
break;
#endif
......@@ -1952,7 +1983,7 @@ fail:
generate_exception(ctx, EXCP_RI);
return;
}
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
}
/* CP0 (MMU and control) */
......@@ -4611,7 +4642,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
opn = "mfc0";
break;
case OPC_MTC0:
GEN_LOAD_REG_TN(T0, rt);
GEN_LOAD_REG_T0(rt);
save_cpu_state(ctx, 1);
gen_mtc0(env, ctx, rd, ctx->opcode & 0x7);
opn = "mtc0";
......@@ -4629,7 +4660,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
break;
case OPC_DMTC0:
check_insn(env, ctx, ISA_MIPS3);
GEN_LOAD_REG_TN(T0, rt);
GEN_LOAD_REG_T0(rt);
save_cpu_state(ctx, 1);
gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7);
opn = "dmtc0";
......@@ -4648,7 +4679,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int
break;
case OPC_MTTR:
check_insn(env, ctx, ASE_MT);
GEN_LOAD_REG_TN(T0, rt);
GEN_LOAD_REG_T0(rt);
gen_mttr(env, ctx, rd, (ctx->opcode >> 5) & 1,
ctx->opcode & 0x7, (ctx->opcode >> 4) & 1);
opn = "mttr";
......@@ -4789,33 +4820,33 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
case OPC_MFC1:
GEN_LOAD_FREG_FTN(WT0, fs);
gen_op_mfc1();
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "mfc1";
break;
case OPC_MTC1:
GEN_LOAD_REG_TN(T0, rt);
GEN_LOAD_REG_T0(rt);
gen_op_mtc1();
GEN_STORE_FTN_FREG(fs, WT0);
opn = "mtc1";
break;
case OPC_CFC1:
gen_op_cfc1(fs);
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "cfc1";
break;
case OPC_CTC1:
GEN_LOAD_REG_TN(T0, rt);
GEN_LOAD_REG_T0(rt);
gen_op_ctc1(fs);
opn = "ctc1";
break;
case OPC_DMFC1:
GEN_LOAD_FREG_FTN(DT0, fs);
gen_op_dmfc1();
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "dmfc1";
break;
case OPC_DMTC1:
GEN_LOAD_REG_TN(T0, rt);
GEN_LOAD_REG_T0(rt);
gen_op_dmtc1();
GEN_STORE_FTN_FREG(fs, DT0);
opn = "dmtc1";
......@@ -4823,11 +4854,11 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
case OPC_MFHC1:
GEN_LOAD_FREG_FTN(WTH0, fs);
gen_op_mfhc1();
GEN_STORE_TN_REG(rt, T0);
GEN_STORE_T0_REG(rt);
opn = "mfhc1";
break;
case OPC_MTHC1:
GEN_LOAD_REG_TN(T0, rt);
GEN_LOAD_REG_T0(rt);
gen_op_mthc1();
GEN_STORE_FTN_FREG(fs, WTH0);
opn = "mthc1";
......@@ -4844,8 +4875,8 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
{
uint32_t ccbit;
GEN_LOAD_REG_TN(T0, rd);
GEN_LOAD_REG_TN(T1, rs);
GEN_LOAD_REG_T0(rd);
GEN_LOAD_REG_T1(rs);
if (cc) {
ccbit = 1 << (24 + cc);
} else
......@@ -4854,7 +4885,7 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
gen_op_movf(ccbit);
else
gen_op_movt(ccbit);
GEN_STORE_TN_REG(rd, T0);
GEN_STORE_T0_REG(rd);
}
#define GEN_MOVCF(fmt) \
......@@ -5029,7 +5060,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "floor.w.s";
break;
case FOP(17, 16):
GEN_LOAD_REG_TN(T0, ft);
GEN_LOAD_REG_T0(ft);
GEN_LOAD_FREG_FTN(WT0, fs);
GEN_LOAD_FREG_FTN(WT2, fd);
gen_movcf_s(ctx, (ft >> 2) & 0x7, ft & 0x1);
......@@ -5037,7 +5068,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "movcf.s";
break;
case FOP(18, 16):
GEN_LOAD_REG_TN(T0, ft);
GEN_LOAD_REG_T0(ft);
GEN_LOAD_FREG_FTN(WT0, fs);
GEN_LOAD_FREG_FTN(WT2, fd);
gen_op_float_movz_s();
......@@ -5045,7 +5076,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "movz.s";
break;
case FOP(19, 16):
GEN_LOAD_REG_TN(T0, ft);
GEN_LOAD_REG_T0(ft);
GEN_LOAD_FREG_FTN(WT0, fs);
GEN_LOAD_FREG_FTN(WT2, fd);
gen_op_float_movn_s();
......@@ -5270,7 +5301,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "floor.w.d";
break;
case FOP(17, 17):
GEN_LOAD_REG_TN(T0, ft);
GEN_LOAD_REG_T0(ft);
GEN_LOAD_FREG_FTN(DT0, fs);
GEN_LOAD_FREG_FTN(DT2, fd);
gen_movcf_d(ctx, (ft >> 2) & 0x7, ft & 0x1);
......@@ -5278,7 +5309,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "movcf.d";
break;
case FOP(18, 17):
GEN_LOAD_REG_TN(T0, ft);
GEN_LOAD_REG_T0(ft);
GEN_LOAD_FREG_FTN(DT0, fs);
GEN_LOAD_FREG_FTN(DT2, fd);
gen_op_float_movz_d();
......@@ -5286,7 +5317,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "movz.d";
break;
case FOP(19, 17):
GEN_LOAD_REG_TN(T0, ft);
GEN_LOAD_REG_T0(ft);
GEN_LOAD_FREG_FTN(DT0, fs);
GEN_LOAD_FREG_FTN(DT2, fd);
gen_op_float_movn_d();
......@@ -5484,7 +5515,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
break;
case FOP(17, 22):
check_cp1_64bitmode(ctx);
GEN_LOAD_REG_TN(T0, ft);
GEN_LOAD_REG_T0(ft);
GEN_LOAD_FREG_FTN(WT0, fs);
GEN_LOAD_FREG_FTN(WTH0, fs);
GEN_LOAD_FREG_FTN(WT2, fd);
......@@ -5496,7 +5527,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
break;
case FOP(18, 22):
check_cp1_64bitmode(ctx);
GEN_LOAD_REG_TN(T0, ft);
GEN_LOAD_REG_T0(ft);
GEN_LOAD_FREG_FTN(WT0, fs);
GEN_LOAD_FREG_FTN(WTH0, fs);
GEN_LOAD_FREG_FTN(WT2, fd);
......@@ -5508,7 +5539,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
break;
case FOP(19, 22):
check_cp1_64bitmode(ctx);
GEN_LOAD_REG_TN(T0, ft);
GEN_LOAD_REG_T0(ft);
GEN_LOAD_FREG_FTN(WT0, fs);
GEN_LOAD_FREG_FTN(WTH0, fs);
GEN_LOAD_FREG_FTN(WT2, fd);
......@@ -5695,12 +5726,12 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
if (index == 0)
gen_op_reset_T0();
else
GEN_LOAD_REG_TN(T0, index);
GEN_LOAD_REG_T0(index);
} else if (index == 0) {
GEN_LOAD_REG_TN(T0, base);
GEN_LOAD_REG_T0(base);
} else {
GEN_LOAD_REG_TN(T0, base);
GEN_LOAD_REG_TN(T1, index);
GEN_LOAD_REG_T0(base);
GEN_LOAD_REG_T1(index);
gen_op_addr_add();
}
/* Don't do NOP if destination is zero: we must perform the actual
......@@ -5757,7 +5788,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
check_cp1_64bitmode(ctx);
switch (opc) {
case OPC_ALNV_PS:
GEN_LOAD_REG_TN(T0, fr);
GEN_LOAD_REG_T0(fr);
GEN_LOAD_FREG_FTN(DT0, fs);
GEN_LOAD_FREG_FTN(DT1, ft);
gen_op_float_alnv_ps();
......@@ -6081,15 +6112,15 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
op2 = MASK_BSHFL(ctx->opcode);
switch (op2) {
case OPC_WSBH:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
gen_op_wsbh();
break;
case OPC_SEB:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
gen_op_seb();
break;
case OPC_SEH:
GEN_LOAD_REG_TN(T1, rt);
GEN_LOAD_REG_T1(rt);
gen_op_seh();
break;
default: /* Inval