On 12/15/24 03:06, Paolo Bonzini wrote:
> 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);
The comment in gen_jcc would still seem to apply:
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!
*/
gen_update_cc_op(s);
via any path through gen_prepare_cc that reaches gen_compute_eflags.
However! Because this is JCC_Z, we will never call gen_compute_eflags, we will always go
through the gen_prepare_eflags_z, which doesn't have the same problem.
Or more simply, fn(s, ot) must have left CC_OP_SUBx in cc_op.
This subtlety deserves a comment and maybe an assert. Perhaps
gen_jcc_noeob(...);
assert(!s->cc_op_dirty);
Either that or an assert(s->cc_op != CC_OP_DYNAMIC) before the call to gen_jcc_noeob().
Paolo