Message ID | 1441216660-8717-3-git-send-email-rth@twiddle.net |
---|---|
State | New |
Headers | show |
On 2 September 2015 at 18:57, Richard Henderson <rth@twiddle.net> wrote: > Split arm_gen_test_cc into 3 functions, so that it can be reused > for non-branch TCG comparisons. > > Signed-off-by: Richard Henderson <rth@twiddle.net> > --- > target-arm/translate.c | 110 ++++++++++++++++++++++++++++--------------------- > target-arm/translate.h | 9 ++++ > 2 files changed, 73 insertions(+), 46 deletions(-) > > diff --git a/target-arm/translate.c b/target-arm/translate.c > index 3826a02..1f43777 100644 > --- a/target-arm/translate.c > +++ b/target-arm/translate.c > @@ -738,81 +738,99 @@ static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b) > #undef PAS_OP > > /* > - * generate a conditional branch based on ARM condition code cc. > + * Generate a conditional based on ARM condition code cc. > * This is common between ARM and Aarch64 targets. > */ > -void arm_gen_test_cc(int cc, TCGLabel *label) > +void arm_test_cc(DisasCompare *cmp, int cc) > { > - TCGv_i32 tmp; > - TCGLabel *inv; > + TCGv_i32 value; > + TCGCond cond; > + bool global = true; > > switch (cc) { > case 0: /* eq: Z */ > - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label); > - break; > case 1: /* ne: !Z */ > - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ZF, 0, label); > + cond = TCG_COND_EQ; > + value = cpu_ZF; > break; > + > case 2: /* cs: C */ > - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_CF, 0, label); > - break; > case 3: /* cc: !C */ > - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, label); > + cond = TCG_COND_NE; > + value = cpu_CF; > break; > + > case 4: /* mi: N */ > - tcg_gen_brcondi_i32(TCG_COND_LT, cpu_NF, 0, label); > - break; > case 5: /* pl: !N */ > - tcg_gen_brcondi_i32(TCG_COND_GE, cpu_NF, 0, label); > + cond = TCG_COND_LT; > + value = cpu_NF; > break; > + > case 6: /* vs: V */ > - tcg_gen_brcondi_i32(TCG_COND_LT, cpu_VF, 0, label); > - break; > case 7: /* vc: !V */ > - tcg_gen_brcondi_i32(TCG_COND_GE, cpu_VF, 0, label); > + cond = TCG_COND_LT; > + value = cpu_VF; > break; > + > case 8: /* hi: C && !Z */ > - inv = gen_new_label(); > - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, inv); > - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ZF, 0, label); > - gen_set_label(inv); > - break; > - case 9: /* ls: !C || Z */ > - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, label); > - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label); > + case 9: /* ls: !C || Z -> !(C && !Z) */ > + cond = TCG_COND_NE; > + value = tcg_temp_new_i32(); > + global = false; > + tcg_gen_neg_i32(value, cpu_CF); > + tcg_gen_and_i32(value, value, cpu_ZF); > break; The comment says hi is C && !Z, but the code doesn't seem to line up with that. At least part of that is presumably because we store ZF inverted, but why are we negating CF here? > + > case 10: /* ge: N == V -> N ^ V == 0 */ > - tmp = tcg_temp_new_i32(); > - tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); > - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); > - tcg_temp_free_i32(tmp); > - break; > case 11: /* lt: N != V -> N ^ V != 0 */ > - tmp = tcg_temp_new_i32(); > - tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); > - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); > - tcg_temp_free_i32(tmp); > + cond = TCG_COND_GE; > + value = tcg_temp_new_i32(); > + global = false; > + tcg_gen_xor_i32(value, cpu_VF, cpu_NF); > break; > + > case 12: /* gt: !Z && N == V */ > - inv = gen_new_label(); > - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, inv); > - tmp = tcg_temp_new_i32(); > - tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); > - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); > - tcg_temp_free_i32(tmp); > - gen_set_label(inv); > - break; > case 13: /* le: Z || N != V */ > - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label); > - tmp = tcg_temp_new_i32(); > - tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); > - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); > - tcg_temp_free_i32(tmp); > + cond = TCG_COND_NE; > + value = tcg_temp_new_i32(); > + global = false; > + tcg_gen_xor_i32(value, cpu_VF, cpu_NF); > + tcg_gen_sari_i32(value, value, 31); > + tcg_gen_andc_i32(value, cpu_ZF, value); I think this is correct, but it could use some commentary to explain what it's doing. Otherwise looks good. thanks -- PMM
On 09/07/2015 10:09 AM, Peter Maydell wrote: > On 2 September 2015 at 18:57, Richard Henderson <rth@twiddle.net> wrote: >> + case 9: /* ls: !C || Z -> !(C && !Z) */ >> + cond = TCG_COND_NE; >> + value = tcg_temp_new_i32(); >> + global = false; >> + tcg_gen_neg_i32(value, cpu_CF); >> + tcg_gen_and_i32(value, value, cpu_ZF); >> break; > > The comment says hi is C && !Z, but the code > doesn't seem to line up with that. At least part > of that is presumably because we store ZF inverted, > but why are we negating CF here? We're computing CF ? -1 : 0. ANDing that with !Z (aka cpu_ZF) gets us C & !Z. >> case 12: /* gt: !Z && N == V */ >> case 13: /* le: Z || N != V */ >> + cond = TCG_COND_NE; >> + value = tcg_temp_new_i32(); >> + global = false; >> + tcg_gen_xor_i32(value, cpu_VF, cpu_NF); >> + tcg_gen_sari_i32(value, value, 31); >> + tcg_gen_andc_i32(value, cpu_ZF, value); > > I think this is correct, but it could use some commentary > to explain what it's doing. Fair enough. r~
On 8 September 2015 at 06:09, Richard Henderson <rth@twiddle.net> wrote: > On 09/07/2015 10:09 AM, Peter Maydell wrote: >> >> On 2 September 2015 at 18:57, Richard Henderson <rth@twiddle.net> wrote: >>> >>> + case 9: /* ls: !C || Z -> !(C && !Z) */ >>> + cond = TCG_COND_NE; >>> + value = tcg_temp_new_i32(); >>> + global = false; >>> + tcg_gen_neg_i32(value, cpu_CF); >>> + tcg_gen_and_i32(value, value, cpu_ZF); >>> break; >> >> >> The comment says hi is C && !Z, but the code >> doesn't seem to line up with that. At least part >> of that is presumably because we store ZF inverted, >> but why are we negating CF here? > > > We're computing CF ? -1 : 0. ANDing that with !Z (aka cpu_ZF) gets us C & > !Z. Ah yes. As with the case below, a comment would be helpful. thanks -- PMM
diff --git a/target-arm/translate.c b/target-arm/translate.c index 3826a02..1f43777 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -738,81 +738,99 @@ static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b) #undef PAS_OP /* - * generate a conditional branch based on ARM condition code cc. + * Generate a conditional based on ARM condition code cc. * This is common between ARM and Aarch64 targets. */ -void arm_gen_test_cc(int cc, TCGLabel *label) +void arm_test_cc(DisasCompare *cmp, int cc) { - TCGv_i32 tmp; - TCGLabel *inv; + TCGv_i32 value; + TCGCond cond; + bool global = true; switch (cc) { case 0: /* eq: Z */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label); - break; case 1: /* ne: !Z */ - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ZF, 0, label); + cond = TCG_COND_EQ; + value = cpu_ZF; break; + case 2: /* cs: C */ - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_CF, 0, label); - break; case 3: /* cc: !C */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, label); + cond = TCG_COND_NE; + value = cpu_CF; break; + case 4: /* mi: N */ - tcg_gen_brcondi_i32(TCG_COND_LT, cpu_NF, 0, label); - break; case 5: /* pl: !N */ - tcg_gen_brcondi_i32(TCG_COND_GE, cpu_NF, 0, label); + cond = TCG_COND_LT; + value = cpu_NF; break; + case 6: /* vs: V */ - tcg_gen_brcondi_i32(TCG_COND_LT, cpu_VF, 0, label); - break; case 7: /* vc: !V */ - tcg_gen_brcondi_i32(TCG_COND_GE, cpu_VF, 0, label); + cond = TCG_COND_LT; + value = cpu_VF; break; + case 8: /* hi: C && !Z */ - inv = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, inv); - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ZF, 0, label); - gen_set_label(inv); - break; - case 9: /* ls: !C || Z */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, label); - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label); + case 9: /* ls: !C || Z -> !(C && !Z) */ + cond = TCG_COND_NE; + value = tcg_temp_new_i32(); + global = false; + tcg_gen_neg_i32(value, cpu_CF); + tcg_gen_and_i32(value, value, cpu_ZF); break; + case 10: /* ge: N == V -> N ^ V == 0 */ - tmp = tcg_temp_new_i32(); - tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); - tcg_temp_free_i32(tmp); - break; case 11: /* lt: N != V -> N ^ V != 0 */ - tmp = tcg_temp_new_i32(); - tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); - tcg_temp_free_i32(tmp); + cond = TCG_COND_GE; + value = tcg_temp_new_i32(); + global = false; + tcg_gen_xor_i32(value, cpu_VF, cpu_NF); break; + case 12: /* gt: !Z && N == V */ - inv = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, inv); - tmp = tcg_temp_new_i32(); - tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); - tcg_temp_free_i32(tmp); - gen_set_label(inv); - break; case 13: /* le: Z || N != V */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label); - tmp = tcg_temp_new_i32(); - tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); - tcg_temp_free_i32(tmp); + cond = TCG_COND_NE; + value = tcg_temp_new_i32(); + global = false; + tcg_gen_xor_i32(value, cpu_VF, cpu_NF); + tcg_gen_sari_i32(value, value, 31); + tcg_gen_andc_i32(value, cpu_ZF, value); break; + default: fprintf(stderr, "Bad condition code 0x%x\n", cc); abort(); } + + if (cc & 1) { + cond = tcg_invert_cond(cond); + } + + cmp->cond = cond; + cmp->value = value; + cmp->value_global = global; +} + +void arm_free_cc(DisasCompare *cmp) +{ + if (!cmp->value_global) { + tcg_temp_free_i32(cmp->value); + } +} + +void arm_jump_cc(DisasCompare *cmp, TCGLabel *label) +{ + tcg_gen_brcondi_i32(cmp->cond, cmp->value, 0, label); +} + +void arm_gen_test_cc(int cc, TCGLabel *label) +{ + DisasCompare cmp; + arm_test_cc(&cmp, cc); + arm_jump_cc(&cmp, label); + arm_free_cc(&cmp); } static const uint8_t table_logic_cc[16] = { diff --git a/target-arm/translate.h b/target-arm/translate.h index 679bdbc..2f30862 100644 --- a/target-arm/translate.h +++ b/target-arm/translate.h @@ -62,6 +62,12 @@ typedef struct DisasContext { TCGv_i64 tmp_a64[TMP_A64_MAX]; } DisasContext; +typedef struct DisasCompare { + TCGCond cond; + TCGv_i32 value; + bool value_global; +} DisasCompare; + /* Share the TCG temporaries common between 32 and 64 bit modes. */ extern TCGv_ptr cpu_env; extern TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF; @@ -143,6 +149,9 @@ static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, } #endif +void arm_test_cc(DisasCompare *cmp, int cc); +void arm_free_cc(DisasCompare *cmp); +void arm_jump_cc(DisasCompare *cmp, TCGLabel *label); void arm_gen_test_cc(int cc, TCGLabel *label); #endif /* TARGET_ARM_TRANSLATE_H */
Split arm_gen_test_cc into 3 functions, so that it can be reused for non-branch TCG comparisons. Signed-off-by: Richard Henderson <rth@twiddle.net> --- target-arm/translate.c | 110 ++++++++++++++++++++++++++++--------------------- target-arm/translate.h | 9 ++++ 2 files changed, 73 insertions(+), 46 deletions(-)