tcg/s390: Use constant pool for cmpi
Also use CHI/CGHI for 16-bit signed constants. Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
parent
5bf67a9217
commit
a534bb15f3
@ -39,9 +39,8 @@
|
|||||||
|
|
||||||
#define TCG_CT_CONST_S16 0x100
|
#define TCG_CT_CONST_S16 0x100
|
||||||
#define TCG_CT_CONST_S32 0x200
|
#define TCG_CT_CONST_S32 0x200
|
||||||
#define TCG_CT_CONST_U31 0x400
|
#define TCG_CT_CONST_S33 0x400
|
||||||
#define TCG_CT_CONST_S33 0x800
|
#define TCG_CT_CONST_ZERO 0x800
|
||||||
#define TCG_CT_CONST_ZERO 0x1000
|
|
||||||
|
|
||||||
/* Several places within the instruction set 0 means "no register"
|
/* Several places within the instruction set 0 means "no register"
|
||||||
rather than TCG_REG_R0. */
|
rather than TCG_REG_R0. */
|
||||||
@ -75,6 +74,10 @@ typedef enum S390Opcode {
|
|||||||
RIL_CGFI = 0xc20c,
|
RIL_CGFI = 0xc20c,
|
||||||
RIL_CLFI = 0xc20f,
|
RIL_CLFI = 0xc20f,
|
||||||
RIL_CLGFI = 0xc20e,
|
RIL_CLGFI = 0xc20e,
|
||||||
|
RIL_CLRL = 0xc60f,
|
||||||
|
RIL_CLGRL = 0xc60a,
|
||||||
|
RIL_CRL = 0xc60d,
|
||||||
|
RIL_CGRL = 0xc608,
|
||||||
RIL_IIHF = 0xc008,
|
RIL_IIHF = 0xc008,
|
||||||
RIL_IILF = 0xc009,
|
RIL_IILF = 0xc009,
|
||||||
RIL_LARL = 0xc000,
|
RIL_LARL = 0xc000,
|
||||||
@ -97,6 +100,8 @@ typedef enum S390Opcode {
|
|||||||
RI_AGHI = 0xa70b,
|
RI_AGHI = 0xa70b,
|
||||||
RI_AHI = 0xa70a,
|
RI_AHI = 0xa70a,
|
||||||
RI_BRC = 0xa704,
|
RI_BRC = 0xa704,
|
||||||
|
RI_CHI = 0xa70e,
|
||||||
|
RI_CGHI = 0xa70f,
|
||||||
RI_IIHH = 0xa500,
|
RI_IIHH = 0xa500,
|
||||||
RI_IIHL = 0xa501,
|
RI_IIHL = 0xa501,
|
||||||
RI_IILH = 0xa502,
|
RI_IILH = 0xa502,
|
||||||
@ -206,6 +211,8 @@ typedef enum S390Opcode {
|
|||||||
RXY_AG = 0xe308,
|
RXY_AG = 0xe308,
|
||||||
RXY_AY = 0xe35a,
|
RXY_AY = 0xe35a,
|
||||||
RXY_CG = 0xe320,
|
RXY_CG = 0xe320,
|
||||||
|
RXY_CLG = 0xe321,
|
||||||
|
RXY_CLY = 0xe355,
|
||||||
RXY_CY = 0xe359,
|
RXY_CY = 0xe359,
|
||||||
RXY_LAY = 0xe371,
|
RXY_LAY = 0xe371,
|
||||||
RXY_LB = 0xe376,
|
RXY_LB = 0xe376,
|
||||||
@ -423,20 +430,6 @@ static const char *target_parse_constraint(TCGArgConstraint *ct,
|
|||||||
case 'J':
|
case 'J':
|
||||||
ct->ct |= TCG_CT_CONST_S32;
|
ct->ct |= TCG_CT_CONST_S32;
|
||||||
break;
|
break;
|
||||||
case 'C':
|
|
||||||
/* ??? We have no insight here into whether the comparison is
|
|
||||||
signed or unsigned. The COMPARE IMMEDIATE insn uses a 32-bit
|
|
||||||
signed immediate, and the COMPARE LOGICAL IMMEDIATE insn uses
|
|
||||||
a 32-bit unsigned immediate. If we were to use the (semi)
|
|
||||||
obvious "val == (int32_t)val" we would be enabling unsigned
|
|
||||||
comparisons vs very large numbers. The only solution is to
|
|
||||||
take the intersection of the ranges. */
|
|
||||||
/* ??? Another possible solution is to simply lie and allow all
|
|
||||||
constants here and force the out-of-range values into a temp
|
|
||||||
register in tgen_cmp when we have knowledge of the actual
|
|
||||||
comparison code in use. */
|
|
||||||
ct->ct |= TCG_CT_CONST_U31;
|
|
||||||
break;
|
|
||||||
case 'Z':
|
case 'Z':
|
||||||
ct->ct |= TCG_CT_CONST_ZERO;
|
ct->ct |= TCG_CT_CONST_ZERO;
|
||||||
break;
|
break;
|
||||||
@ -467,8 +460,6 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type,
|
|||||||
return val == (int32_t)val;
|
return val == (int32_t)val;
|
||||||
} else if (ct & TCG_CT_CONST_S33) {
|
} else if (ct & TCG_CT_CONST_S33) {
|
||||||
return val >= -0xffffffffll && val <= 0xffffffffll;
|
return val >= -0xffffffffll && val <= 0xffffffffll;
|
||||||
} else if (ct & TCG_CT_CONST_U31) {
|
|
||||||
return val >= 0 && val <= 0x7fffffff;
|
|
||||||
} else if (ct & TCG_CT_CONST_ZERO) {
|
} else if (ct & TCG_CT_CONST_ZERO) {
|
||||||
return val == 0;
|
return val == 0;
|
||||||
}
|
}
|
||||||
@ -1092,6 +1083,8 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
|
|||||||
TCGArg c2, bool c2const, bool need_carry)
|
TCGArg c2, bool c2const, bool need_carry)
|
||||||
{
|
{
|
||||||
bool is_unsigned = is_unsigned_cond(c);
|
bool is_unsigned = is_unsigned_cond(c);
|
||||||
|
S390Opcode op;
|
||||||
|
|
||||||
if (c2const) {
|
if (c2const) {
|
||||||
if (c2 == 0) {
|
if (c2 == 0) {
|
||||||
if (!(is_unsigned && need_carry)) {
|
if (!(is_unsigned && need_carry)) {
|
||||||
@ -1102,44 +1095,67 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
|
|||||||
}
|
}
|
||||||
return tcg_cond_to_ltr_cond[c];
|
return tcg_cond_to_ltr_cond[c];
|
||||||
}
|
}
|
||||||
/* If we only got here because of load-and-test,
|
}
|
||||||
and we couldn't use that, then we need to load
|
|
||||||
the constant into a register. */
|
if (!is_unsigned && c2 == (int16_t)c2) {
|
||||||
if (!(s390_facilities & FACILITY_EXT_IMM)) {
|
op = (type == TCG_TYPE_I32 ? RI_CHI : RI_CGHI);
|
||||||
c2 = TCG_TMP0;
|
tcg_out_insn_RI(s, op, r1, c2);
|
||||||
tcg_out_movi(s, type, c2, 0);
|
goto exit;
|
||||||
goto do_reg;
|
}
|
||||||
|
|
||||||
|
if (s390_facilities & FACILITY_EXT_IMM) {
|
||||||
|
if (type == TCG_TYPE_I32) {
|
||||||
|
op = (is_unsigned ? RIL_CLFI : RIL_CFI);
|
||||||
|
tcg_out_insn_RIL(s, op, r1, c2);
|
||||||
|
goto exit;
|
||||||
|
} else if (c2 == (is_unsigned ? (uint32_t)c2 : (int32_t)c2)) {
|
||||||
|
op = (is_unsigned ? RIL_CLGFI : RIL_CGFI);
|
||||||
|
tcg_out_insn_RIL(s, op, r1, c2);
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_unsigned) {
|
|
||||||
|
/* Use the constant pool, but not for small constants. */
|
||||||
|
if (maybe_out_small_movi(s, type, TCG_TMP0, c2)) {
|
||||||
|
c2 = TCG_TMP0;
|
||||||
|
/* fall through to reg-reg */
|
||||||
|
} else if (USE_REG_TB) {
|
||||||
if (type == TCG_TYPE_I32) {
|
if (type == TCG_TYPE_I32) {
|
||||||
tcg_out_insn(s, RIL, CLFI, r1, c2);
|
op = (is_unsigned ? RXY_CLY : RXY_CY);
|
||||||
|
tcg_out_insn_RXY(s, op, r1, TCG_REG_TB, TCG_REG_NONE, 0);
|
||||||
|
new_pool_label(s, (uint32_t)c2, R_390_20, s->code_ptr - 2,
|
||||||
|
4 - (intptr_t)s->code_gen_ptr);
|
||||||
} else {
|
} else {
|
||||||
tcg_out_insn(s, RIL, CLGFI, r1, c2);
|
op = (is_unsigned ? RXY_CLG : RXY_CG);
|
||||||
|
tcg_out_insn_RXY(s, op, r1, TCG_REG_TB, TCG_REG_NONE, 0);
|
||||||
|
new_pool_label(s, c2, R_390_20, s->code_ptr - 2,
|
||||||
|
-(intptr_t)s->code_gen_ptr);
|
||||||
}
|
}
|
||||||
|
goto exit;
|
||||||
} else {
|
} else {
|
||||||
if (type == TCG_TYPE_I32) {
|
if (type == TCG_TYPE_I32) {
|
||||||
tcg_out_insn(s, RIL, CFI, r1, c2);
|
op = (is_unsigned ? RIL_CLRL : RIL_CRL);
|
||||||
|
tcg_out_insn_RIL(s, op, r1, 0);
|
||||||
|
new_pool_label(s, (uint32_t)c2, R_390_PC32DBL,
|
||||||
|
s->code_ptr - 2, 2 + 4);
|
||||||
} else {
|
} else {
|
||||||
tcg_out_insn(s, RIL, CGFI, r1, c2);
|
op = (is_unsigned ? RIL_CLGRL : RIL_CGRL);
|
||||||
}
|
tcg_out_insn_RIL(s, op, r1, 0);
|
||||||
}
|
new_pool_label(s, c2, R_390_PC32DBL, s->code_ptr - 2, 2);
|
||||||
} else {
|
|
||||||
do_reg:
|
|
||||||
if (is_unsigned) {
|
|
||||||
if (type == TCG_TYPE_I32) {
|
|
||||||
tcg_out_insn(s, RR, CLR, r1, c2);
|
|
||||||
} else {
|
|
||||||
tcg_out_insn(s, RRE, CLGR, r1, c2);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (type == TCG_TYPE_I32) {
|
|
||||||
tcg_out_insn(s, RR, CR, r1, c2);
|
|
||||||
} else {
|
|
||||||
tcg_out_insn(s, RRE, CGR, r1, c2);
|
|
||||||
}
|
}
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == TCG_TYPE_I32) {
|
||||||
|
op = (is_unsigned ? RR_CLR : RR_CR);
|
||||||
|
tcg_out_insn_RR(s, op, r1, c2);
|
||||||
|
} else {
|
||||||
|
op = (is_unsigned ? RRE_CLGR : RRE_CGR);
|
||||||
|
tcg_out_insn_RRE(s, op, r1, c2);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
return tcg_cond_to_s390_cond[c];
|
return tcg_cond_to_s390_cond[c];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2325,8 +2341,6 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
|||||||
static const TCGTargetOpDef r_L = { .args_ct_str = { "r", "L" } };
|
static const TCGTargetOpDef r_L = { .args_ct_str = { "r", "L" } };
|
||||||
static const TCGTargetOpDef L_L = { .args_ct_str = { "L", "L" } };
|
static const TCGTargetOpDef L_L = { .args_ct_str = { "L", "L" } };
|
||||||
static const TCGTargetOpDef r_ri = { .args_ct_str = { "r", "ri" } };
|
static const TCGTargetOpDef r_ri = { .args_ct_str = { "r", "ri" } };
|
||||||
static const TCGTargetOpDef r_rC = { .args_ct_str = { "r", "rC" } };
|
|
||||||
static const TCGTargetOpDef r_rZ = { .args_ct_str = { "r", "rZ" } };
|
|
||||||
static const TCGTargetOpDef r_r_ri = { .args_ct_str = { "r", "r", "ri" } };
|
static const TCGTargetOpDef r_r_ri = { .args_ct_str = { "r", "r", "ri" } };
|
||||||
static const TCGTargetOpDef r_0_ri = { .args_ct_str = { "r", "0", "ri" } };
|
static const TCGTargetOpDef r_0_ri = { .args_ct_str = { "r", "0", "ri" } };
|
||||||
static const TCGTargetOpDef r_0_rI = { .args_ct_str = { "r", "0", "rI" } };
|
static const TCGTargetOpDef r_0_rI = { .args_ct_str = { "r", "0", "rI" } };
|
||||||
@ -2401,10 +2415,8 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
|||||||
return &r_r_ri;
|
return &r_r_ri;
|
||||||
|
|
||||||
case INDEX_op_brcond_i32:
|
case INDEX_op_brcond_i32:
|
||||||
/* Without EXT_IMM, only the LOAD AND TEST insn is available. */
|
|
||||||
return (s390_facilities & FACILITY_EXT_IMM ? &r_ri : &r_rZ);
|
|
||||||
case INDEX_op_brcond_i64:
|
case INDEX_op_brcond_i64:
|
||||||
return (s390_facilities & FACILITY_EXT_IMM ? &r_rC : &r_rZ);
|
return &r_ri;
|
||||||
|
|
||||||
case INDEX_op_bswap16_i32:
|
case INDEX_op_bswap16_i32:
|
||||||
case INDEX_op_bswap16_i64:
|
case INDEX_op_bswap16_i64:
|
||||||
@ -2430,6 +2442,8 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
|||||||
return &r_r;
|
return &r_r;
|
||||||
|
|
||||||
case INDEX_op_clz_i64:
|
case INDEX_op_clz_i64:
|
||||||
|
case INDEX_op_setcond_i32:
|
||||||
|
case INDEX_op_setcond_i64:
|
||||||
return &r_r_ri;
|
return &r_r_ri;
|
||||||
|
|
||||||
case INDEX_op_qemu_ld_i32:
|
case INDEX_op_qemu_ld_i32:
|
||||||
@ -2446,30 +2460,14 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
|||||||
= { .args_ct_str = { "r", "rZ", "r" } };
|
= { .args_ct_str = { "r", "rZ", "r" } };
|
||||||
return &dep;
|
return &dep;
|
||||||
}
|
}
|
||||||
case INDEX_op_setcond_i32:
|
|
||||||
case INDEX_op_setcond_i64:
|
|
||||||
{
|
|
||||||
/* Without EXT_IMM, only the LOAD AND TEST insn is available. */
|
|
||||||
static const TCGTargetOpDef setc_z
|
|
||||||
= { .args_ct_str = { "r", "r", "rZ" } };
|
|
||||||
static const TCGTargetOpDef setc_c
|
|
||||||
= { .args_ct_str = { "r", "r", "rC" } };
|
|
||||||
return (s390_facilities & FACILITY_EXT_IMM ? &setc_c : &setc_z);
|
|
||||||
}
|
|
||||||
case INDEX_op_movcond_i32:
|
case INDEX_op_movcond_i32:
|
||||||
case INDEX_op_movcond_i64:
|
case INDEX_op_movcond_i64:
|
||||||
{
|
{
|
||||||
/* Without EXT_IMM, only the LOAD AND TEST insn is available. */
|
static const TCGTargetOpDef movc
|
||||||
static const TCGTargetOpDef movc_z
|
= { .args_ct_str = { "r", "r", "ri", "r", "0" } };
|
||||||
= { .args_ct_str = { "r", "r", "rZ", "r", "0" } };
|
|
||||||
static const TCGTargetOpDef movc_c
|
|
||||||
= { .args_ct_str = { "r", "r", "rC", "r", "0" } };
|
|
||||||
static const TCGTargetOpDef movc_l
|
static const TCGTargetOpDef movc_l
|
||||||
= { .args_ct_str = { "r", "r", "rC", "rI", "0" } };
|
= { .args_ct_str = { "r", "r", "ri", "rI", "0" } };
|
||||||
return (s390_facilities & FACILITY_EXT_IMM
|
return (s390_facilities & FACILITY_LOAD_ON_COND2 ? &movc_l : &movc);
|
||||||
? (s390_facilities & FACILITY_LOAD_ON_COND2
|
|
||||||
? &movc_l : &movc_c)
|
|
||||||
: &movc_z);
|
|
||||||
}
|
}
|
||||||
case INDEX_op_div2_i32:
|
case INDEX_op_div2_i32:
|
||||||
case INDEX_op_div2_i64:
|
case INDEX_op_div2_i64:
|
||||||
|
Loading…
Reference in New Issue
Block a user