From 240ce26a0533a6e5ee472789fbfbd9f7f939197e Mon Sep 17 00:00:00 2001 From: James Hogan Date: Mon, 24 Jun 2013 17:45:39 +0100 Subject: target-mips: fix branch in likely delay slot tcg assert When a branch delay slot contains another branch instruction, the code generated raises an exception, however since is_branch==1, handle_delay_slot() doesn't get called immediately. This means ctx->bstate isn't set to BS_BRANCH, and the decoder continues decoding until a non-branch instruction is found. If the first branch was a branch likely instruction then each instruction after it generates code for the unlikely case, to go to the next tb starting after the delay slot. This results in multiple goto_tb tcg ops being generated with the same exit number. When debug is enabled this hits: tcg-op.h:2589: tcg_gen_goto_tb: Assertion `(tcg_ctx.goto_tb_issue_mask & (1 << idx)) == 0' failed. This is fixed by removing is_branch entirely, and calling handle_delay_slot() if (ctx.hflags & MIPS_HFLAG_BMASK) was set prior to the current instruction being decoded. This still prevents handle_delay_slot() being called immediately after a branch but allows it to still be called after a branch within a delay slot. Signed-off-by: James Hogan Signed-off-by: Yongbok Kim Signed-off-by: Aurelien Jarno --- target-mips/translate.c | 62 ++++++++++++++----------------------------------- 1 file changed, 17 insertions(+), 45 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 877f8df..c1d57a7 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -9571,8 +9571,7 @@ static void decode_i64_mips16 (DisasContext *ctx, } #endif -static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx, - int *is_branch) +static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) { int extend = cpu_lduw_code(env, ctx->pc + 2); int op, rx, ry, funct, sa; @@ -9763,8 +9762,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx, return 4; } -static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, - int *is_branch) +static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) { int rx, ry; int sa; @@ -9807,7 +9805,6 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALXS : OPC_JALS; gen_compute_branch(ctx, op, 4, rx, ry, offset); n_bytes = 4; - *is_branch = 1; break; case M16_OPC_BEQZ: gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << 1); @@ -10046,9 +10043,6 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, } gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0); - if (!nd) { - *is_branch = 1; - } } break; case RR_SDBBP: @@ -10193,7 +10187,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, } break; case M16_OPC_EXTEND: - decode_extended_mips16_opc(env, ctx, is_branch); + decode_extended_mips16_opc(env, ctx); n_bytes = 4; break; #if defined(TARGET_MIPS64) @@ -10802,7 +10796,7 @@ static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist, } -static void gen_pool16c_insn(DisasContext *ctx, int *is_branch) +static void gen_pool16c_insn(DisasContext *ctx) { int rd = mmreg((ctx->opcode >> 3) & 0x7); int rs = mmreg(ctx->opcode & 0x7); @@ -10864,7 +10858,6 @@ static void gen_pool16c_insn(DisasContext *ctx, int *is_branch) gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0); } - *is_branch = 1; break; case JRC16 + 0: case JRC16 + 1: @@ -10889,7 +10882,6 @@ static void gen_pool16c_insn(DisasContext *ctx, int *is_branch) gen_compute_branch(ctx, opc, 2, reg, 31, 0); } - *is_branch = 1; break; case MFHI16 + 0: case MFHI16 + 1: @@ -11020,8 +11012,7 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd, tcg_temp_free(t1); } -static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, - int *is_branch) +static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) { int extension = (ctx->opcode >> 6) & 0x3f; int minor = (ctx->opcode >> 12) & 0xf; @@ -11147,12 +11138,10 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, case JALR: case JALR_HB: gen_compute_branch (ctx, OPC_JALR, 4, rs, rt, 0); - *is_branch = 1; break; case JALRS: case JALRS_HB: gen_compute_branch (ctx, OPC_JALRS, 4, rs, rt, 0); - *is_branch = 1; break; default: goto pool32axf_invalid; @@ -11551,7 +11540,7 @@ static void gen_pool32fxf(DisasContext *ctx, int rt, int rs) } static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, - uint16_t insn_hw1, int *is_branch) + uint16_t insn_hw1) { int32_t offset; uint16_t insn; @@ -11685,7 +11674,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd); return; case POOL32AXF: - gen_pool32axf(env, ctx, rt, rs, is_branch); + gen_pool32axf(env, ctx, rt, rs); break; case 0x07: generate_exception(ctx, EXCP_BREAK); @@ -12048,7 +12037,6 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, mips32_op = OPC_BGTZ; do_branch: gen_compute_branch(ctx, mips32_op, 4, rs, -1, imm << 1); - *is_branch = 1; break; /* Traps */ @@ -12109,7 +12097,6 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, do_cp1branch: gen_compute_branch1(ctx, mips32_op, (ctx->opcode >> 18) & 0x7, imm << 1); - *is_branch = 1; break; case BPOSGE64: case BPOSGE32: @@ -12216,30 +12203,24 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case JALX32: offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset); - *is_branch = 1; break; case JALS32: offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1; gen_compute_branch(ctx, OPC_JALS, 4, rt, rs, offset); - *is_branch = 1; break; case BEQ32: gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1); - *is_branch = 1; break; case BNE32: gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1); - *is_branch = 1; break; case J32: gen_compute_branch(ctx, OPC_J, 4, rt, rs, (int32_t)(ctx->opcode & 0x3FFFFFF) << 1); - *is_branch = 1; break; case JAL32: gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, (int32_t)(ctx->opcode & 0x3FFFFFF) << 1); - *is_branch = 1; break; /* Floating point (COP1) */ case LWC132: @@ -12309,7 +12290,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, } } -static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) +static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) { uint32_t op; @@ -12442,7 +12423,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b } break; case POOL16C: - gen_pool16c_insn(ctx, is_branch); + gen_pool16c_insn(ctx); break; case LWGP16: { @@ -12582,14 +12563,12 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b case B16: gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, SIMM(ctx->opcode, 0, 10) << 1); - *is_branch = 1; break; case BNEZ16: case BEQZ16: gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2, mmreg(uMIPS_RD(ctx->opcode)), 0, SIMM(ctx->opcode, 0, 7) << 1); - *is_branch = 1; break; case LI16: { @@ -12610,7 +12589,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b generate_exception(ctx, EXCP_RI); break; default: - decode_micromips32_opc (env, ctx, op, is_branch); + decode_micromips32_opc (env, ctx, op); return 4; } @@ -14346,7 +14325,7 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2, /* End MIPSDSP functions. */ -static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) +static void decode_opc (CPUMIPSState *env, DisasContext *ctx) { int32_t offset; int rs, rt, rd, sa; @@ -14460,7 +14439,6 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) break; case OPC_JR ... OPC_JALR: gen_compute_branch(ctx, op1, 4, rs, rd, sa); - *is_branch = 1; break; case OPC_TGE ... OPC_TEQ: /* Traps */ case OPC_TNE: @@ -15227,7 +15205,6 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */ case OPC_BLTZAL ... OPC_BGEZALL: gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2); - *is_branch = 1; break; case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */ case OPC_TNEI: @@ -15243,7 +15220,6 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) #endif check_dsp(ctx); gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2); - *is_branch = 1; break; default: /* Invalid */ MIPS_INVAL("regimm"); @@ -15355,12 +15331,10 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_J ... OPC_JAL: /* Jump */ offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; gen_compute_branch(ctx, op, 4, rs, rt, offset); - *is_branch = 1; break; case OPC_BEQ ... OPC_BGTZ: /* Branch */ case OPC_BEQL ... OPC_BGTZL: gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); - *is_branch = 1; break; case OPC_LB ... OPC_LWR: /* Load and stores */ case OPC_LL: @@ -15420,7 +15394,6 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_BC1: gen_compute_branch1(ctx, MASK_BC1(ctx->opcode), (rt >> 2) & 0x7, imm << 2); - *is_branch = 1; break; case OPC_S_FMT: case OPC_D_FMT: @@ -15527,7 +15500,6 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; gen_compute_branch(ctx, op, 4, rs, rt, offset); - *is_branch = 1; break; case OPC_MDMX: check_insn(ctx, ASE_MDMX); @@ -15553,7 +15525,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, int num_insns; int max_insns; int insn_bytes; - int is_branch; + int is_delay; if (search_pc) qemu_log("search pc %d\n", search_pc); @@ -15611,23 +15583,23 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); - is_branch = 0; + is_delay = ctx.hflags & MIPS_HFLAG_BMASK; if (!(ctx.hflags & MIPS_HFLAG_M16)) { ctx.opcode = cpu_ldl_code(env, ctx.pc); insn_bytes = 4; - decode_opc(env, &ctx, &is_branch); + decode_opc(env, &ctx); } else if (ctx.insn_flags & ASE_MICROMIPS) { ctx.opcode = cpu_lduw_code(env, ctx.pc); - insn_bytes = decode_micromips_opc(env, &ctx, &is_branch); + insn_bytes = decode_micromips_opc(env, &ctx); } else if (ctx.insn_flags & ASE_MIPS16) { ctx.opcode = cpu_lduw_code(env, ctx.pc); - insn_bytes = decode_mips16_opc(env, &ctx, &is_branch); + insn_bytes = decode_mips16_opc(env, &ctx); } else { generate_exception(&ctx, EXCP_RI); ctx.bstate = BS_STOP; break; } - if (!is_branch) { + if (is_delay) { handle_delay_slot(&ctx, insn_bytes); } ctx.pc += insn_bytes; -- cgit v1.1