Since the cost of gen_update_cc_op() must be paid anyway, it's easier to place them manually and not rely on spilling that is buried under multiple levels of function calls.
And since cc_op will have been spilled at the point of a fault, just make the whole insn CC_OP_DYNAMIC. Once repz_opt is reintroduced, a fault could happen either before or after the first execution of CMPS/SCAS, and CC_OP_DYNAMIC sidesteps the complicated matter of what x86_restore_state_to_opc would do. Signed-off-by: Paolo Bonzini <[email protected]> --- target/i386/tcg/translate.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 4ff0ccf71cb..4b53a47000e 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -1345,14 +1345,29 @@ 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); } /* -- 2.47.1
