tcg/s390: Use constant pool for cmpi

Also use CHI/CGHI for 16-bit signed constants.

Backports commit a534bb15f30ff7e420434b3e5746bcad595c5429 from qemu
This commit is contained in:
Richard Henderson 2018-03-04 22:44:23 -05:00 committed by Lioncash
parent c08620b984
commit 5150970625
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -39,9 +39,8 @@
#define TCG_CT_CONST_S16 0x100
#define TCG_CT_CONST_S32 0x200
#define TCG_CT_CONST_U31 0x400
#define TCG_CT_CONST_S33 0x800
#define TCG_CT_CONST_ZERO 0x1000
#define TCG_CT_CONST_S33 0x400
#define TCG_CT_CONST_ZERO 0x800
/* Several places within the instruction set 0 means "no register"
rather than TCG_REG_R0. */
@ -80,6 +79,10 @@ typedef enum S390Opcode {
RIL_CGFI = 0xc20c,
RIL_CLFI = 0xc20f,
RIL_CLGFI = 0xc20e,
RIL_CLRL = 0xc60f,
RIL_CLGRL = 0xc60a,
RIL_CRL = 0xc60d,
RIL_CGRL = 0xc608,
RIL_IIHF = 0xc008,
RIL_IILF = 0xc009,
RIL_LARL = 0xc000,
@ -102,6 +105,8 @@ typedef enum S390Opcode {
RI_AGHI = 0xa70b,
RI_AHI = 0xa70a,
RI_BRC = 0xa704,
RI_CHI = 0xa70e,
RI_CGHI = 0xa70f,
RI_IIHH = 0xa500,
RI_IIHL = 0xa501,
RI_IILH = 0xa502,
@ -211,6 +216,8 @@ typedef enum S390Opcode {
RXY_AG = 0xe308,
RXY_AY = 0xe35a,
RXY_CG = 0xe320,
RXY_CLG = 0xe321,
RXY_CLY = 0xe355,
RXY_CY = 0xe359,
RXY_LAY = 0xe371,
RXY_LB = 0xe376,
@ -429,20 +436,6 @@ static const char *target_parse_constraint(TCGArgConstraint *ct,
case 'J':
ct->ct |= TCG_CT_CONST_S32;
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':
ct->ct |= TCG_CT_CONST_ZERO;
break;
@ -473,8 +466,6 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type,
return val == (int32_t)val;
} else if (ct & TCG_CT_CONST_S33) {
return val >= -0xffffffffll && val <= 0xffffffffll;
} else if (ct & TCG_CT_CONST_U31) {
return val >= 0 && val <= 0x7fffffff;
} else if (ct & TCG_CT_CONST_ZERO) {
return val == 0;
}
@ -1097,6 +1088,8 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
TCGArg c2, bool c2const, bool need_carry)
{
bool is_unsigned = is_unsigned_cond(c);
S390Opcode op;
if (c2const) {
if (c2 == 0) {
if (!(is_unsigned && need_carry)) {
@ -1107,44 +1100,67 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
}
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 (!(s390_facilities & FACILITY_EXT_IMM)) {
c2 = TCG_TMP0;
tcg_out_movi(s, type, c2, 0);
goto do_reg;
}
if (!is_unsigned && c2 == (int16_t)c2) {
op = (type == TCG_TYPE_I32 ? RI_CHI : RI_CGHI);
tcg_out_insn_RI(s, op, r1, c2);
goto exit;
}
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) {
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 {
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 {
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 {
tcg_out_insn(s, RIL, CGFI, r1, c2);
}
}
} 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);
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);
}
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];
}