diff options
Diffstat (limited to 'target-microblaze')
-rw-r--r-- | target-microblaze/translate.c | 28 |
1 files changed, 21 insertions, 7 deletions
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index ca54e2c30e..5d2a0e6dee 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -153,6 +153,14 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) } } +/* True if ALU operand b is a small immediate that may deserve + faster treatment. */ +static inline int dec_alu_op_b_is_small_imm(DisasContext *dc) +{ + /* Immediate insn without the imm prefix ? */ + return dc->type_b && !(dc->tb_flags & IMM_FLAG); +} + static inline TCGv *dec_alu_op_b(DisasContext *dc) { if (dc->type_b) { @@ -984,10 +992,16 @@ static void dec_bcc(DisasContext *dc) cpu_env, offsetof(CPUState, bimm)); } - tcg_gen_movi_tl(env_btarget, dc->pc); - tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc))); - eval_cc(dc, cc, env_btaken, cpu_R[dc->ra], tcg_const_tl(0)); + if (dec_alu_op_b_is_small_imm(dc)) { + int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend. */ + + tcg_gen_movi_tl(env_btarget, dc->pc + offset); + } else { + tcg_gen_movi_tl(env_btarget, dc->pc); + tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc))); + } dc->jmp = JMP_INDIRECT; + eval_cc(dc, cc, env_btaken, cpu_R[dc->ra], tcg_const_tl(0)); } static void dec_br(DisasContext *dc) @@ -1031,13 +1045,13 @@ static void dec_br(DisasContext *dc) } } } else { - if (!dc->type_b || (dc->tb_flags & IMM_FLAG)) { + if (dec_alu_op_b_is_small_imm(dc)) { + dc->jmp = JMP_DIRECT; + dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm); + } else { tcg_gen_movi_tl(env_btaken, 1); tcg_gen_movi_tl(env_btarget, dc->pc); tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc))); - } else { - dc->jmp = JMP_DIRECT; - dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm); } } } |