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 <pbonzini@redhat.com>
---
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