Commit a534bb15 authored by Richard Henderson's avatar Richard Henderson
Browse files

tcg/s390: Use constant pool for cmpi



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

Signed-off-by: default avatarRichard Henderson <rth@twiddle.net>
parent 5bf67a92
Loading
Loading
Loading
Loading
+67 −69
Original line number Diff line number Diff line
@@ -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.  */
@@ -75,6 +74,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,
@@ -97,6 +100,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,
@@ -206,6 +211,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,
@@ -423,20 +430,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;
@@ -467,8 +460,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;
    }
@@ -1092,6 +1083,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)) {
@@ -1102,44 +1095,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) {
            if (type == TCG_TYPE_I32) {
                tcg_out_insn(s, RIL, CLFI, r1, c2);
            } else {
                tcg_out_insn(s, RIL, CLGFI, r1, c2);

        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;
        }
        } else {

        if (s390_facilities & FACILITY_EXT_IMM) {
            if (type == TCG_TYPE_I32) {
                tcg_out_insn(s, RIL, CFI, r1, c2);
            } else {
                tcg_out_insn(s, RIL, CGFI, r1, c2);
                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;
            }
        }
    } else {
    do_reg:
        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, RR, CLR, r1, c2);
            } else {
                tcg_out_insn(s, RRE, CLGR, 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 {
                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, RR, CR, 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, 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];
}

@@ -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 L_L = { .args_ct_str = { "L", "L" } };
    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_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;

    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:
        return (s390_facilities & FACILITY_EXT_IMM ? &r_rC : &r_rZ);
        return &r_ri;

    case INDEX_op_bswap16_i32:
    case INDEX_op_bswap16_i64:
@@ -2430,6 +2442,8 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
        return &r_r;

    case INDEX_op_clz_i64:
    case INDEX_op_setcond_i32:
    case INDEX_op_setcond_i64:
        return &r_r_ri;

    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" } };
            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_i64:
        {
            /* Without EXT_IMM, only the LOAD AND TEST insn is available.  */
            static const TCGTargetOpDef movc_z
                = { .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
                = { .args_ct_str = { "r", "r", "ri", "r", "0" } };
            static const TCGTargetOpDef movc_l
                = { .args_ct_str = { "r", "r", "rC", "rI", "0" } };
            return (s390_facilities & FACILITY_EXT_IMM
                    ? (s390_facilities & FACILITY_LOAD_ON_COND2
                       ? &movc_l : &movc_c)
                    : &movc_z);
                = { .args_ct_str = { "r", "r", "ri", "rI", "0" } };
            return (s390_facilities & FACILITY_LOAD_ON_COND2 ? &movc_l : &movc);
        }
    case INDEX_op_div2_i32:
    case INDEX_op_div2_i64: