target/s390x: Improve cc computation for SUBTRACT LOGICAL

The resulting cc is only dependent on the result and the carry-out.
Carry-out and borrow-out are inverses, so are trivially converted.
With tcg ops, it is easier to compute borrow-out than carry-out, so
save result and borrow-out rather than the inputs.

Borrow-out for 64-bit inputs is had via tcg_gen_sub2_i64 directly
into cc_src.  Borrow-out for 32-bit inputs is had via extraction
from a normal 64-bit sub (with zero-extended inputs).

Reviewed-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20201214221356.68039-4-richard.henderson@linaro.org>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
This commit is contained in:
Richard Henderson 2020-12-14 16:13:55 -06:00 committed by Cornelia Huck
parent 3bcc3fa799
commit a2db06da7d
5 changed files with 43 additions and 82 deletions

View File

@ -129,6 +129,11 @@ static uint32_t cc_calc_addu(uint64_t carry_out, uint64_t result)
return (result != 0) + 2 * carry_out;
}
static uint32_t cc_calc_subu(uint64_t borrow_out, uint64_t result)
{
return cc_calc_addu(borrow_out + 1, result);
}
static uint32_t cc_calc_add_64(int64_t a1, int64_t a2, int64_t ar)
{
if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
@ -159,19 +164,6 @@ static uint32_t cc_calc_sub_64(int64_t a1, int64_t a2, int64_t ar)
}
}
static uint32_t cc_calc_subu_64(uint64_t a1, uint64_t a2, uint64_t ar)
{
if (ar == 0) {
return 2;
} else {
if (a2 > a1) {
return 1;
} else {
return 3;
}
}
}
static uint32_t cc_calc_subb_64(uint64_t a1, uint64_t a2, uint64_t ar)
{
int borrow_out;
@ -245,19 +237,6 @@ static uint32_t cc_calc_sub_32(int32_t a1, int32_t a2, int32_t ar)
}
}
static uint32_t cc_calc_subu_32(uint32_t a1, uint32_t a2, uint32_t ar)
{
if (ar == 0) {
return 2;
} else {
if (a2 > a1) {
return 1;
} else {
return 3;
}
}
}
static uint32_t cc_calc_subb_32(uint32_t a1, uint32_t a2, uint32_t ar)
{
int borrow_out;
@ -462,15 +441,15 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
case CC_OP_ADDU:
r = cc_calc_addu(src, dst);
break;
case CC_OP_SUBU:
r = cc_calc_subu(src, dst);
break;
case CC_OP_ADD_64:
r = cc_calc_add_64(src, dst, vr);
break;
case CC_OP_SUB_64:
r = cc_calc_sub_64(src, dst, vr);
break;
case CC_OP_SUBU_64:
r = cc_calc_subu_64(src, dst, vr);
break;
case CC_OP_SUBB_64:
r = cc_calc_subb_64(src, dst, vr);
break;
@ -493,9 +472,6 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
case CC_OP_SUB_32:
r = cc_calc_sub_32(src, dst, vr);
break;
case CC_OP_SUBU_32:
r = cc_calc_subu_32(src, dst, vr);
break;
case CC_OP_SUBB_32:
r = cc_calc_subb_32(src, dst, vr);
break;

View File

@ -396,6 +396,7 @@ const char *cc_name(enum cc_op cc_op)
[CC_OP_STATIC] = "CC_OP_STATIC",
[CC_OP_NZ] = "CC_OP_NZ",
[CC_OP_ADDU] = "CC_OP_ADDU",
[CC_OP_SUBU] = "CC_OP_SUBU",
[CC_OP_LTGT_32] = "CC_OP_LTGT_32",
[CC_OP_LTGT_64] = "CC_OP_LTGT_64",
[CC_OP_LTUGTU_32] = "CC_OP_LTUGTU_32",
@ -404,13 +405,11 @@ const char *cc_name(enum cc_op cc_op)
[CC_OP_LTGT0_64] = "CC_OP_LTGT0_64",
[CC_OP_ADD_64] = "CC_OP_ADD_64",
[CC_OP_SUB_64] = "CC_OP_SUB_64",
[CC_OP_SUBU_64] = "CC_OP_SUBU_64",
[CC_OP_SUBB_64] = "CC_OP_SUBB_64",
[CC_OP_ABS_64] = "CC_OP_ABS_64",
[CC_OP_NABS_64] = "CC_OP_NABS_64",
[CC_OP_ADD_32] = "CC_OP_ADD_32",
[CC_OP_SUB_32] = "CC_OP_SUB_32",
[CC_OP_SUBU_32] = "CC_OP_SUBU_32",
[CC_OP_SUBB_32] = "CC_OP_SUBB_32",
[CC_OP_ABS_32] = "CC_OP_ABS_32",
[CC_OP_NABS_32] = "CC_OP_NABS_32",

View File

@ -900,21 +900,21 @@
C(0xb9c9, SHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, sub, subs32)
C(0xb9d9, SHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, sub, subs32)
/* SUBTRACT LOGICAL */
C(0x1f00, SLR, RR_a, Z, r1, r2, new, r1_32, sub, subu32)
C(0xb9fb, SLRK, RRF_a, DO, r2, r3, new, r1_32, sub, subu32)
C(0x5f00, SL, RX_a, Z, r1, m2_32u, new, r1_32, sub, subu32)
C(0xe35f, SLY, RXY_a, LD, r1, m2_32u, new, r1_32, sub, subu32)
C(0xb90b, SLGR, RRE, Z, r1, r2, r1, 0, sub, subu64)
C(0xb91b, SLGFR, RRE, Z, r1, r2_32u, r1, 0, sub, subu64)
C(0xb9eb, SLGRK, RRF_a, DO, r2, r3, r1, 0, sub, subu64)
C(0xe30b, SLG, RXY_a, Z, r1, m2_64, r1, 0, sub, subu64)
C(0xe31b, SLGF, RXY_a, Z, r1, m2_32u, r1, 0, sub, subu64)
C(0x1f00, SLR, RR_a, Z, r1_32u, r2_32u, new, r1_32, sub, subu32)
C(0xb9fb, SLRK, RRF_a, DO, r2_32u, r3_32u, new, r1_32, sub, subu32)
C(0x5f00, SL, RX_a, Z, r1_32u, m2_32u, new, r1_32, sub, subu32)
C(0xe35f, SLY, RXY_a, LD, r1_32u, m2_32u, new, r1_32, sub, subu32)
C(0xb90b, SLGR, RRE, Z, r1, r2, r1, 0, subu64, subu64)
C(0xb91b, SLGFR, RRE, Z, r1, r2_32u, r1, 0, subu64, subu64)
C(0xb9eb, SLGRK, RRF_a, DO, r2, r3, r1, 0, subu64, subu64)
C(0xe30b, SLG, RXY_a, Z, r1, m2_64, r1, 0, subu64, subu64)
C(0xe31b, SLGF, RXY_a, Z, r1, m2_32u, r1, 0, subu64, subu64)
/* SUBTRACT LOCICAL HIGH */
C(0xb9cb, SLHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, sub, subu32)
C(0xb9db, SLHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, sub, subu32)
C(0xb9db, SLHHLR, RRF_a, HW, r2_sr32, r3_32u, new, r1_32h, sub, subu32)
/* SUBTRACT LOGICAL IMMEDIATE */
C(0xc205, SLFI, RIL_a, EI, r1, i2_32u, new, r1_32, sub, subu32)
C(0xc204, SLGFI, RIL_a, EI, r1, i2_32u, r1, 0, sub, subu64)
C(0xc205, SLFI, RIL_a, EI, r1_32u, i2_32u, new, r1_32, sub, subu32)
C(0xc204, SLGFI, RIL_a, EI, r1, i2_32u, r1, 0, subu64, subu64)
/* SUBTRACT LOGICAL WITH BORROW */
C(0xb999, SLBR, RRE, Z, r1, r2, new, r1_32, subb, subb32)
C(0xb989, SLBGR, RRE, Z, r1, r2, r1, 0, subb, subb64)

View File

@ -161,6 +161,7 @@ enum cc_op {
CC_OP_NZ, /* env->cc_dst != 0 */
CC_OP_ADDU, /* dst != 0, src = carry out (0,1) */
CC_OP_SUBU, /* dst != 0, src = borrow out (0,-1) */
CC_OP_LTGT_32, /* signed less/greater than (32bit) */
CC_OP_LTGT_64, /* signed less/greater than (64bit) */
@ -171,7 +172,6 @@ enum cc_op {
CC_OP_ADD_64, /* overflow on add (64bit) */
CC_OP_SUB_64, /* overflow on subtraction (64bit) */
CC_OP_SUBU_64, /* overflow on unsigned subtraction (64bit) */
CC_OP_SUBB_64, /* overflow on unsigned sub-borrow (64bit) */
CC_OP_ABS_64, /* sign eval on abs (64bit) */
CC_OP_NABS_64, /* sign eval on nabs (64bit) */
@ -179,7 +179,6 @@ enum cc_op {
CC_OP_ADD_32, /* overflow on add (32bit) */
CC_OP_SUB_32, /* overflow on subtraction (32bit) */
CC_OP_SUBU_32, /* overflow on unsigned subtraction (32bit) */
CC_OP_SUBB_32, /* overflow on unsigned sub-borrow (32bit) */
CC_OP_ABS_32, /* sign eval on abs (64bit) */
CC_OP_NABS_32, /* sign eval on nabs (64bit) */

View File

@ -601,11 +601,9 @@ static void gen_op_calc_cc(DisasContext *s)
/* FALLTHRU */
case CC_OP_ADD_64:
case CC_OP_SUB_64:
case CC_OP_SUBU_64:
case CC_OP_SUBB_64:
case CC_OP_ADD_32:
case CC_OP_SUB_32:
case CC_OP_SUBU_32:
case CC_OP_SUBB_32:
local_cc_op = tcg_const_i32(s->cc_op);
break;
@ -656,6 +654,7 @@ static void gen_op_calc_cc(DisasContext *s)
case CC_OP_TM_64:
case CC_OP_SLA_32:
case CC_OP_SLA_64:
case CC_OP_SUBU:
case CC_OP_NZ_F128:
case CC_OP_VC:
case CC_OP_MULS_64:
@ -664,11 +663,9 @@ static void gen_op_calc_cc(DisasContext *s)
break;
case CC_OP_ADD_64:
case CC_OP_SUB_64:
case CC_OP_SUBU_64:
case CC_OP_SUBB_64:
case CC_OP_ADD_32:
case CC_OP_SUB_32:
case CC_OP_SUBU_32:
case CC_OP_SUBB_32:
/* 3 arguments */
gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr);
@ -843,6 +840,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
break;
case CC_OP_ADDU:
case CC_OP_SUBU:
switch (mask) {
case 8 | 2: /* result == 0 */
cond = TCG_COND_EQ;
@ -850,33 +848,11 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
case 4 | 1: /* result != 0 */
cond = TCG_COND_NE;
break;
case 8 | 4: /* no carry */
cond = TCG_COND_EQ;
case 8 | 4: /* !carry (borrow) */
cond = old_cc_op == CC_OP_ADDU ? TCG_COND_EQ : TCG_COND_NE;
break;
case 2 | 1: /* carry */
cond = TCG_COND_NE;
break;
default:
goto do_dynamic;
}
account_inline_branch(s, old_cc_op);
break;
case CC_OP_SUBU_32:
case CC_OP_SUBU_64:
/* Note that CC=0 is impossible; treat it as dont-care. */
switch (mask & 7) {
case 2: /* zero -> op1 == op2 */
cond = TCG_COND_EQ;
break;
case 4 | 1: /* !zero -> op1 != op2 */
cond = TCG_COND_NE;
break;
case 4: /* borrow (!carry) -> op1 < op2 */
cond = TCG_COND_LTU;
break;
case 2 | 1: /* !borrow (carry) -> op1 >= op2 */
cond = TCG_COND_GEU;
case 2 | 1: /* carry (!borrow) */
cond = old_cc_op == CC_OP_ADDU ? TCG_COND_NE : TCG_COND_EQ;
break;
default:
goto do_dynamic;
@ -911,7 +887,6 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
break;
case CC_OP_LTGT_32:
case CC_OP_LTUGTU_32:
case CC_OP_SUBU_32:
c->is_64 = false;
c->u.s32.a = tcg_temp_new_i32();
tcg_gen_extrl_i64_i32(c->u.s32.a, cc_src);
@ -928,7 +903,6 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
break;
case CC_OP_LTGT_64:
case CC_OP_LTUGTU_64:
case CC_OP_SUBU_64:
c->u.s64.a = cc_src;
c->u.s64.b = cc_dst;
c->g1 = c->g2 = true;
@ -943,6 +917,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
break;
case CC_OP_ADDU:
case CC_OP_SUBU:
c->is_64 = true;
c->u.s64.b = tcg_const_i64(0);
c->g1 = true;
@ -1446,6 +1421,9 @@ static void compute_carry(DisasContext *s)
case CC_OP_ADDU:
/* The carry value is already in cc_src (1,0). */
break;
case CC_OP_SUBU:
tcg_gen_addi_i64(cc_src, cc_src, 1);
break;
default:
gen_op_calc_cc(s);
/* fall through */
@ -4761,6 +4739,13 @@ static DisasJumpType op_sub(DisasContext *s, DisasOps *o)
return DISAS_NEXT;
}
static DisasJumpType op_subu64(DisasContext *s, DisasOps *o)
{
tcg_gen_movi_i64(cc_src, 0);
tcg_gen_sub2_i64(o->out, cc_src, o->in1, cc_src, o->in2, cc_src);
return DISAS_NEXT;
}
static DisasJumpType op_subb(DisasContext *s, DisasOps *o)
{
DisasCompare cmp;
@ -5312,12 +5297,14 @@ static void cout_subs64(DisasContext *s, DisasOps *o)
static void cout_subu32(DisasContext *s, DisasOps *o)
{
gen_op_update3_cc_i64(s, CC_OP_SUBU_32, o->in1, o->in2, o->out);
tcg_gen_sari_i64(cc_src, o->out, 32);
tcg_gen_ext32u_i64(cc_dst, o->out);
gen_op_update2_cc_i64(s, CC_OP_SUBU, cc_src, cc_dst);
}
static void cout_subu64(DisasContext *s, DisasOps *o)
{
gen_op_update3_cc_i64(s, CC_OP_SUBU_64, o->in1, o->in2, o->out);
gen_op_update2_cc_i64(s, CC_OP_SUBU, cc_src, o->out);
}
static void cout_subb32(DisasContext *s, DisasOps *o)