diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 141295742a..8bc91c3de3 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -1234,8 +1234,9 @@ static inline void gen_jcc(DisasContext *s, int b, TCGLabel *l1) CCPrepare cc = gen_prepare_cc(s, b, NULL); /* - * Note that this must be _after_ gen_prepare_cc, because it - * can change the cc_op from CC_OP_DYNAMIC to CC_OP_EFLAGS! + * Note that this must be _after_ gen_prepare_cc, because it can change + * the cc_op to CC_OP_EFLAGS (because it's CC_OP_DYNAMIC or because + * it's cheaper to just compute the flags)! */ gen_update_cc_op(s); if (cc.use_reg2) { @@ -1346,14 +1347,31 @@ static void do_gen_rep(DisasContext *s, MemOp ot, */ s->flags &= ~HF_RF_MASK; + /* + * For CMPS/SCAS, the CC_OP after a memory fault could come from either + * the previous instruction or the string instruction; but because we + * arrange to keep CC_OP up to date all the time, just mark the whole + * insn as CC_OP_DYNAMIC. + * + * It's not a problem to do this even for instructions that do not + * modify the flags, so do it unconditionally. + */ gen_update_cc_op(s); + tcg_set_insn_start_param(s->base.insn_start, 1, CC_OP_DYNAMIC); + + /* Any iteration at all? */ gen_op_jz_ecx(s, done); fn(s, ot); gen_op_add_reg_im(s, s->aflag, R_ECX, -1); + gen_update_cc_op(s); + + /* Leave if REP condition fails. */ if (is_repz_nz) { int nz = (s->prefix & PREFIX_REPNZ) ? 1 : 0; - gen_jcc(s, (JCC_Z << 1) | (nz ^ 1), done); + gen_jcc_noeob(s, (JCC_Z << 1) | (nz ^ 1), done); + /* gen_prepare_eflags_z never changes cc_op. */ + assert(!s->cc_op_dirty); } /*