target/i386: rewrite flags writeback for ADCX/ADOX
Avoid using set_cc_op() in preparation for implementing APX; treat CC_OP_EFLAGS similar to the case where we have the "opposite" cc_op (CC_OP_ADOX for ADCX and CC_OP_ADCX for ADOX), except the resulting cc_op is not CC_OP_ADCOX. This is written easily as two "if"s, whose conditions are both false for CC_OP_EFLAGS, both true for CC_OP_ADCOX, and one each true for CC_OP_ADCX/ADOX. The new logic also makes it easy to drop usage of tmp0. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
4228eb8cc6
commit
cc155f1971
@ -1260,6 +1260,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
||||
/* Use a clearer name for this. */
|
||||
#define CPU_INTERRUPT_INIT CPU_INTERRUPT_RESET
|
||||
|
||||
#define CC_OP_HAS_EFLAGS(op) ((op) >= CC_OP_EFLAGS && (op) <= CC_OP_ADCOX)
|
||||
|
||||
/* Instead of computing the condition codes after each x86 instruction,
|
||||
* QEMU just stores one operand (called CC_SRC), the result
|
||||
* (called CC_DST) and the type of operation (called CC_OP). When the
|
||||
@ -1270,6 +1272,9 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
||||
typedef enum {
|
||||
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
|
||||
CC_OP_EFLAGS, /* all cc are explicitly computed, CC_SRC = flags */
|
||||
CC_OP_ADCX, /* CC_DST = C, CC_SRC = rest. */
|
||||
CC_OP_ADOX, /* CC_SRC2 = O, CC_SRC = rest. */
|
||||
CC_OP_ADCOX, /* CC_DST = C, CC_SRC2 = O, CC_SRC = rest. */
|
||||
|
||||
CC_OP_MULB, /* modify all flags, C, O = (CC_SRC != 0) */
|
||||
CC_OP_MULW,
|
||||
@ -1326,10 +1331,6 @@ typedef enum {
|
||||
CC_OP_BMILGL,
|
||||
CC_OP_BMILGQ,
|
||||
|
||||
CC_OP_ADCX, /* CC_DST = C, CC_SRC = rest. */
|
||||
CC_OP_ADOX, /* CC_DST = O, CC_SRC = rest. */
|
||||
CC_OP_ADCOX, /* CC_DST = C, CC_SRC2 = O, CC_SRC = rest. */
|
||||
|
||||
CC_OP_CLR, /* Z set, all other flags clear. */
|
||||
CC_OP_POPCNT, /* Z via CC_SRC, all other flags clear. */
|
||||
|
||||
|
@ -1122,24 +1122,41 @@ static void gen_ADC(DisasContext *s, X86DecodedInsn *decode)
|
||||
prepare_update3_cc(decode, s, CC_OP_ADCB + ot, c_in);
|
||||
}
|
||||
|
||||
/* ADCX/ADOX do not have memory operands and can use set_cc_op. */
|
||||
static void gen_ADCOX(DisasContext *s, MemOp ot, int cc_op)
|
||||
static void gen_ADCOX(DisasContext *s, X86DecodedInsn *decode, int cc_op)
|
||||
{
|
||||
int opposite_cc_op;
|
||||
MemOp ot = decode->op[0].ot;
|
||||
TCGv carry_in = NULL;
|
||||
TCGv carry_out = (cc_op == CC_OP_ADCX ? cpu_cc_dst : cpu_cc_src2);
|
||||
TCGv *carry_out = (cc_op == CC_OP_ADCX ? &decode->cc_dst : &decode->cc_src2);
|
||||
TCGv zero;
|
||||
|
||||
if (cc_op == s->cc_op || s->cc_op == CC_OP_ADCOX) {
|
||||
/* Re-use the carry-out from a previous round. */
|
||||
carry_in = carry_out;
|
||||
} else {
|
||||
/* We don't have a carry-in, get it out of EFLAGS. */
|
||||
if (s->cc_op != CC_OP_ADCX && s->cc_op != CC_OP_ADOX) {
|
||||
gen_compute_eflags(s);
|
||||
decode->cc_op = cc_op;
|
||||
*carry_out = tcg_temp_new();
|
||||
if (CC_OP_HAS_EFLAGS(s->cc_op)) {
|
||||
decode->cc_src = cpu_cc_src;
|
||||
|
||||
/* Re-use the carry-out from a previous round? */
|
||||
if (s->cc_op == cc_op || s->cc_op == CC_OP_ADCOX) {
|
||||
carry_in = (cc_op == CC_OP_ADCX ? cpu_cc_dst : cpu_cc_src2);
|
||||
}
|
||||
carry_in = s->tmp0;
|
||||
tcg_gen_extract_tl(carry_in, cpu_cc_src,
|
||||
|
||||
/* Preserve the opposite carry from previous rounds? */
|
||||
if (s->cc_op != cc_op && s->cc_op != CC_OP_EFLAGS) {
|
||||
decode->cc_op = CC_OP_ADCOX;
|
||||
if (carry_out == &decode->cc_dst) {
|
||||
decode->cc_src2 = cpu_cc_src2;
|
||||
} else {
|
||||
decode->cc_dst = cpu_cc_dst;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
decode->cc_src = tcg_temp_new();
|
||||
gen_mov_eflags(s, decode->cc_src);
|
||||
}
|
||||
|
||||
if (!carry_in) {
|
||||
/* Get carry_in out of EFLAGS. */
|
||||
carry_in = tcg_temp_new();
|
||||
tcg_gen_extract_tl(carry_in, decode->cc_src,
|
||||
ctz32(cc_op == CC_OP_ADCX ? CC_C : CC_O), 1);
|
||||
}
|
||||
|
||||
@ -1151,28 +1168,20 @@ static void gen_ADCOX(DisasContext *s, MemOp ot, int cc_op)
|
||||
tcg_gen_ext32u_tl(s->T1, s->T1);
|
||||
tcg_gen_add_i64(s->T0, s->T0, s->T1);
|
||||
tcg_gen_add_i64(s->T0, s->T0, carry_in);
|
||||
tcg_gen_shri_i64(carry_out, s->T0, 32);
|
||||
tcg_gen_shri_i64(*carry_out, s->T0, 32);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
zero = tcg_constant_tl(0);
|
||||
tcg_gen_add2_tl(s->T0, carry_out, s->T0, zero, carry_in, zero);
|
||||
tcg_gen_add2_tl(s->T0, carry_out, s->T0, carry_out, s->T1, zero);
|
||||
tcg_gen_add2_tl(s->T0, *carry_out, s->T0, zero, carry_in, zero);
|
||||
tcg_gen_add2_tl(s->T0, *carry_out, s->T0, *carry_out, s->T1, zero);
|
||||
break;
|
||||
}
|
||||
|
||||
opposite_cc_op = cc_op == CC_OP_ADCX ? CC_OP_ADOX : CC_OP_ADCX;
|
||||
if (s->cc_op == CC_OP_ADCOX || s->cc_op == opposite_cc_op) {
|
||||
/* Merge with the carry-out from the opposite instruction. */
|
||||
set_cc_op(s, CC_OP_ADCOX);
|
||||
} else {
|
||||
set_cc_op(s, cc_op);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_ADCX(DisasContext *s, X86DecodedInsn *decode)
|
||||
{
|
||||
gen_ADCOX(s, decode->op[0].ot, CC_OP_ADCX);
|
||||
gen_ADCOX(s, decode, CC_OP_ADCX);
|
||||
}
|
||||
|
||||
static void gen_ADD(DisasContext *s, X86DecodedInsn *decode)
|
||||
@ -1190,7 +1199,7 @@ static void gen_ADD(DisasContext *s, X86DecodedInsn *decode)
|
||||
|
||||
static void gen_ADOX(DisasContext *s, X86DecodedInsn *decode)
|
||||
{
|
||||
gen_ADCOX(s, decode->op[0].ot, CC_OP_ADOX);
|
||||
gen_ADCOX(s, decode, CC_OP_ADOX);
|
||||
}
|
||||
|
||||
static void gen_AND(DisasContext *s, X86DecodedInsn *decode)
|
||||
|
Loading…
Reference in New Issue
Block a user