From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53137) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YOYRC-0000L2-Af for qemu-devel@nongnu.org; Thu, 19 Feb 2015 16:15:11 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YOYR6-00079e-8P for qemu-devel@nongnu.org; Thu, 19 Feb 2015 16:15:10 -0500 Received: from mail-qg0-x22e.google.com ([2607:f8b0:400d:c04::22e]:45782) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YOYR6-00078q-3j for qemu-devel@nongnu.org; Thu, 19 Feb 2015 16:15:04 -0500 Received: by mail-qg0-f46.google.com with SMTP id z107so9647846qgd.5 for ; Thu, 19 Feb 2015 13:15:03 -0800 (PST) Sender: Richard Henderson From: Richard Henderson Date: Thu, 19 Feb 2015 13:14:19 -0800 Message-Id: <1424380469-20138-2-git-send-email-rth@twiddle.net> In-Reply-To: <1424380469-20138-1-git-send-email-rth@twiddle.net> References: <1424380469-20138-1-git-send-email-rth@twiddle.net> Subject: [Qemu-devel] [PATCH 01/11] target-arm: Introduce DisasCompare List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: peter.maydell@linaro.org Splitting arm_gen_test_cc into 3 functions, so that it can be reused for non-branch TCG comparisons. Note that this is also a bug fix for aarch64. At present, we have branches using the 32-bit (translate.c) versions of cpu_[NZCV]F, but we set the flags using the 64-bit (translate-a64.c) versions of cpu_[NZCV]F. From the view of the TCG code generator, these are unrelated variables. The bug is hard to see because we currently only read these variables from branches, and upon reaching a branch TCG will first spill live variables and then reload the arguments of the branch. Since the 32-bit versions were never live until reaching the branch, we'd re-read the data that had just been spilled from the 64-bit versions. Accept the code duplication for now, as the 64-bit functions will diverge. Signed-off-by: Richard Henderson --- target-arm/translate-a64.c | 102 +++++++++++++++++++++++++++++++++++++++ target-arm/translate.c | 116 +++++++++++++++++++++++++++------------------ target-arm/translate.h | 2 - 3 files changed, 172 insertions(+), 48 deletions(-) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 0b192a1..dbca12a 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -1036,6 +1036,108 @@ static inline void gen_check_sp_alignment(DisasContext *s) */ } +typedef struct DisasCompare { + TCGCond cond; + TCGv_i32 value; + bool value_global; +} DisasCompare; + +/* + * generate a conditional based on ARM condition code cc. + * This is common between ARM and Aarch64 targets. + */ +static void arm_test_cc(DisasCompare *cmp, int cc) +{ + TCGv_i32 value; + TCGCond cond; + bool global = true; + + switch (cc) { + case 0: /* eq: Z */ + case 1: /* ne: !Z */ + cond = TCG_COND_EQ; + value = cpu_ZF; + break; + + case 2: /* cs: C */ + case 3: /* cc: !C */ + cond = TCG_COND_NE; + value = cpu_CF; + break; + + case 4: /* mi: N */ + case 5: /* pl: !N */ + cond = TCG_COND_LT; + value = cpu_NF; + break; + + case 6: /* vs: V */ + case 7: /* vc: !V */ + cond = TCG_COND_LT; + value = cpu_VF; + break; + + case 8: /* hi: C && !Z */ + case 9: /* ls: !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 */ + case 11: /* lt: N != V -> N ^ V != 0 */ + 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 */ + 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); + 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; +} + +static void arm_free_cc(DisasCompare *cmp) +{ + if (!cmp->value_global) { + tcg_temp_free_i32(cmp->value); + } +} + +static void arm_jump_cc(DisasCompare *cmp, TCGLabel *label) +{ + tcg_gen_brcondi_i32(cmp->cond, cmp->value, 0, label); +} + +static 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); +} + /* * This provides a simple table based table lookup decoder. It is * intended to be used when the relevant bits for decode are too diff --git a/target-arm/translate.c b/target-arm/translate.c index 381d896..dd4d80f 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -732,82 +732,106 @@ static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b) } #undef PAS_OP +typedef struct DisasCompare { + TCGCond cond; + TCGv_i32 value; + bool value_global; +} DisasCompare; + /* - * 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) +static 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; +} + +static void arm_free_cc(DisasCompare *cmp) +{ + if (!cmp->value_global) { + tcg_temp_free_i32(cmp->value); + } +} + +static void arm_jump_cc(DisasCompare *cmp, TCGLabel *label) +{ + tcg_gen_brcondi_i32(cmp->cond, cmp->value, 0, label); +} + +static 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 9829576..e6c7048 100644 --- a/target-arm/translate.h +++ b/target-arm/translate.h @@ -119,6 +119,4 @@ static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, } #endif -void arm_gen_test_cc(int cc, TCGLabel *label); - #endif /* TARGET_ARM_TRANSLATE_H */ -- 2.1.0