target-arm: Introduce DisasCompare
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> Message-id: 1441909103-24666-3-git-send-email-rth@twiddle.net Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
78bcaa3e37
commit
6c2c63d3a0
@ -738,81 +738,104 @@ 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;
|
||||
/* CF is 1 for C, so -CF is an all-bits-set mask for C;
|
||||
ZF is non-zero for !Z; so AND the two subexpressions. */
|
||||
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);
|
||||
/* Since we're only interested in the sign bit, == 0 is >= 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 */
|
||||
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;
|
||||
/* (N == V) is equal to the sign bit of ~(NF ^ VF). Propagate
|
||||
* the sign bit then AND with ZF to yield the result. */
|
||||
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] = {
|
||||
|
@ -63,6 +63,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;
|
||||
@ -144,6 +150,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 */
|
||||
|
Loading…
Reference in New Issue
Block a user