diff --git a/qemu/tcg/s390/tcg-target.inc.c b/qemu/tcg/s390/tcg-target.inc.c index 0eadc9eb..4b75849c 100644 --- a/qemu/tcg/s390/tcg-target.inc.c +++ b/qemu/tcg/s390/tcg-target.inc.c @@ -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]; }