Skip to content

Commit

Permalink
target/sparc: Move ADDC to decodetree
Browse files Browse the repository at this point in the history
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
  • Loading branch information
rth7680 committed Oct 25, 2023
1 parent 428881d commit 420a187
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 55 deletions.
1 change: 1 addition & 0 deletions target/sparc/insns.decode
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ SUB 10 ..... 0.0100 ..... . ............. @r_r_ri_cc
ANDN 10 ..... 0.0101 ..... . ............. @r_r_ri_cc
ORN 10 ..... 0.0110 ..... . ............. @r_r_ri_cc
XORN 10 ..... 0.0111 ..... . ............. @r_r_ri_cc
ADDC 10 ..... 0.1000 ..... . ............. @r_r_ri_cc

Tcc_r 10 0 cond:4 111010 rs1:5 0 cc:1 0000000 rs2:5
{
Expand Down
148 changes: 93 additions & 55 deletions target/sparc/translate.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,71 +447,89 @@ static TCGv_i32 gen_sub32_carry32(void)
return carry_32;
}

static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1,
TCGv src2, int update_cc)
static void gen_op_addc_int(TCGv dst, TCGv src1, TCGv src2,
TCGv_i32 carry_32, bool update_cc)
{
TCGv_i32 carry_32;
TCGv carry;
tcg_gen_add_tl(dst, src1, src2);

switch (dc->cc_op) {
case CC_OP_DIV:
case CC_OP_LOGIC:
/* Carry is known to be zero. Fall back to plain ADD. */
if (update_cc) {
gen_op_add_cc(dst, src1, src2);
} else {
tcg_gen_add_tl(dst, src1, src2);
}
return;
#ifdef TARGET_SPARC64
TCGv carry = tcg_temp_new();
tcg_gen_extu_i32_tl(carry, carry_32);
tcg_gen_add_tl(dst, dst, carry);
#else
tcg_gen_add_i32(dst, dst, carry_32);
#endif

case CC_OP_ADD:
case CC_OP_TADD:
case CC_OP_TADDTV:
if (TARGET_LONG_BITS == 32) {
/* We can re-use the host's hardware carry generation by using
an ADD2 opcode. We discard the low part of the output.
Ideally we'd combine this operation with the add that
generated the carry in the first place. */
carry = tcg_temp_new();
tcg_gen_add2_tl(carry, dst, cpu_cc_src, src1, cpu_cc_src2, src2);
goto add_done;
}
carry_32 = gen_add32_carry32();
break;
if (update_cc) {
tcg_debug_assert(dst == cpu_cc_dst);
tcg_gen_mov_tl(cpu_cc_src, src1);
tcg_gen_mov_tl(cpu_cc_src2, src2);
}
}

case CC_OP_SUB:
case CC_OP_TSUB:
case CC_OP_TSUBTV:
carry_32 = gen_sub32_carry32();
break;
static void gen_op_addc_int_add(TCGv dst, TCGv src1, TCGv src2, bool update_cc)
{
TCGv discard;

default:
/* We need external help to produce the carry. */
carry_32 = tcg_temp_new_i32();
gen_helper_compute_C_icc(carry_32, tcg_env);
break;
if (TARGET_LONG_BITS == 64) {
gen_op_addc_int(dst, src1, src2, gen_add32_carry32(), update_cc);
return;
}

#if TARGET_LONG_BITS == 64
carry = tcg_temp_new();
tcg_gen_extu_i32_i64(carry, carry_32);
#else
carry = carry_32;
#endif

tcg_gen_add_tl(dst, src1, src2);
tcg_gen_add_tl(dst, dst, carry);
/*
* We can re-use the host's hardware carry generation by using
* an ADD2 opcode. We discard the low part of the output.
* Ideally we'd combine this operation with the add that
* generated the carry in the first place.
*/
discard = tcg_temp_new();
tcg_gen_add2_tl(discard, dst, cpu_cc_src, src1, cpu_cc_src2, src2);

add_done:
if (update_cc) {
tcg_debug_assert(dst == cpu_cc_dst);
tcg_gen_mov_tl(cpu_cc_src, src1);
tcg_gen_mov_tl(cpu_cc_src2, src2);
tcg_gen_mov_tl(cpu_cc_dst, dst);
tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADDX);
dc->cc_op = CC_OP_ADDX;
}
}

static void gen_op_addc_add(TCGv dst, TCGv src1, TCGv src2)
{
gen_op_addc_int_add(dst, src1, src2, false);
}

static void gen_op_addccc_add(TCGv dst, TCGv src1, TCGv src2)
{
gen_op_addc_int_add(dst, src1, src2, true);
}

static void gen_op_addc_sub(TCGv dst, TCGv src1, TCGv src2)
{
gen_op_addc_int(dst, src1, src2, gen_sub32_carry32(), false);
}

static void gen_op_addccc_sub(TCGv dst, TCGv src1, TCGv src2)
{
gen_op_addc_int(dst, src1, src2, gen_sub32_carry32(), true);
}

static void gen_op_addc_int_generic(TCGv dst, TCGv src1, TCGv src2,
bool update_cc)
{
TCGv_i32 carry_32 = tcg_temp_new_i32();
gen_helper_compute_C_icc(carry_32, tcg_env);
gen_op_addc_int(dst, src1, src2, carry_32, update_cc);
}

static void gen_op_addc_generic(TCGv dst, TCGv src1, TCGv src2)
{
gen_op_addc_int_generic(dst, src1, src2, false);
}

static void gen_op_addccc_generic(TCGv dst, TCGv src1, TCGv src2)
{
gen_op_addc_int_generic(dst, src1, src2, true);
}

static void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
{
tcg_gen_mov_tl(cpu_cc_src, src1);
Expand Down Expand Up @@ -4095,6 +4113,30 @@ static bool trans_OR(DisasContext *dc, arg_r_r_ri_cc *a)
return do_logic(dc, a, tcg_gen_or_tl, tcg_gen_ori_tl);
}

static bool trans_ADDC(DisasContext *dc, arg_r_r_ri_cc *a)
{
switch (dc->cc_op) {
case CC_OP_DIV:
case CC_OP_LOGIC:
/* Carry is known to be zero. Fall back to plain ADD. */
return do_arith(dc, a, CC_OP_ADD,
tcg_gen_add_tl, tcg_gen_addi_tl, gen_op_add_cc);
case CC_OP_ADD:
case CC_OP_TADD:
case CC_OP_TADDTV:
return do_arith(dc, a, CC_OP_ADDX,
gen_op_addc_add, NULL, gen_op_addccc_add);
case CC_OP_SUB:
case CC_OP_TSUB:
case CC_OP_TSUBTV:
return do_arith(dc, a, CC_OP_ADDX,
gen_op_addc_sub, NULL, gen_op_addccc_sub);
default:
return do_arith(dc, a, CC_OP_ADDX,
gen_op_addc_generic, NULL, gen_op_addccc_generic);
}
}

#define CHECK_IU_FEATURE(dc, FEATURE) \
if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE)) \
goto illegal_insn;
Expand Down Expand Up @@ -4519,10 +4561,6 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
cpu_src1 = get_src1(dc, insn);
cpu_src2 = get_src2(dc, insn);
switch (xop & ~0x10) {
case 0x8: /* addx, V9 addc */
gen_op_addx_int(dc, cpu_dst, cpu_src1, cpu_src2,
(xop & 0x10));
break;
#ifdef TARGET_SPARC64
case 0x9: /* V9 mulx */
tcg_gen_mul_i64(cpu_dst, cpu_src1, cpu_src2);
Expand Down

0 comments on commit 420a187

Please sign in to comment.