diff options
Diffstat (limited to 'tcg/s390/tcg-target.inc.c')
-rw-r--r-- | tcg/s390/tcg-target.inc.c | 700 |
1 files changed, 378 insertions, 322 deletions
diff --git a/tcg/s390/tcg-target.inc.c b/tcg/s390/tcg-target.inc.c index 5d7083e90c..38b9e791ee 100644 --- a/tcg/s390/tcg-target.inc.c +++ b/tcg/s390/tcg-target.inc.c @@ -38,12 +38,13 @@ a 32-bit displacement here Just In Case. */ #define USE_LONG_BRANCHES 0 -#define TCG_CT_CONST_MULI 0x100 -#define TCG_CT_CONST_ORI 0x200 -#define TCG_CT_CONST_XORI 0x400 -#define TCG_CT_CONST_CMPI 0x800 -#define TCG_CT_CONST_ADLI 0x1000 -#define TCG_CT_CONST_ZERO 0x2000 +#define TCG_CT_CONST_S16 0x100 +#define TCG_CT_CONST_S32 0x200 +#define TCG_CT_CONST_NN16 0x400 +#define TCG_CT_CONST_NN32 0x800 +#define TCG_CT_CONST_U31 0x1000 +#define TCG_CT_CONST_S33 0x2000 +#define TCG_CT_CONST_ZERO 0x4000 /* Several places within the instruction set 0 means "no register" rather than TCG_REG_R0. */ @@ -121,6 +122,7 @@ typedef enum S390Opcode { RIE_CLGIJ = 0xec7d, RIE_CLRJ = 0xec77, RIE_CRJ = 0xec76, + RIE_LOCGHI = 0xec46, RIE_RISBG = 0xec55, RRE_AGR = 0xb908, @@ -158,6 +160,16 @@ typedef enum S390Opcode { RRF_LOCR = 0xb9f2, RRF_LOCGR = 0xb9e2, + RRF_NRK = 0xb9f4, + RRF_NGRK = 0xb9e4, + RRF_ORK = 0xb9f6, + RRF_OGRK = 0xb9e6, + RRF_SRK = 0xb9f9, + RRF_SGRK = 0xb9e9, + RRF_SLRK = 0xb9fb, + RRF_SLGRK = 0xb9eb, + RRF_XRK = 0xb9f7, + RRF_XGRK = 0xb9e7, RR_AR = 0x1a, RR_ALR = 0x1e, @@ -178,8 +190,11 @@ typedef enum S390Opcode { RSY_RLL = 0xeb1d, RSY_RLLG = 0xeb1c, RSY_SLLG = 0xeb0d, + RSY_SLLK = 0xebdf, RSY_SRAG = 0xeb0a, + RSY_SRAK = 0xebdc, RSY_SRLG = 0xeb0c, + RSY_SRLK = 0xebde, RS_SLL = 0x89, RS_SRA = 0x8a, @@ -386,19 +401,33 @@ static const char *target_parse_constraint(TCGArgConstraint *ct, tcg_regset_set_reg(ct->u.regs, TCG_REG_R3); break; case 'A': - ct->ct |= TCG_CT_CONST_ADLI; + ct->ct |= TCG_CT_CONST_S33; break; - case 'K': - ct->ct |= TCG_CT_CONST_MULI; + case 'I': + ct->ct |= TCG_CT_CONST_S16; break; - case 'O': - ct->ct |= TCG_CT_CONST_ORI; + case 'J': + ct->ct |= TCG_CT_CONST_S32; break; - case 'X': - ct->ct |= TCG_CT_CONST_XORI; + case 'N': + ct->ct |= TCG_CT_CONST_NN16; + break; + case 'M': + ct->ct |= TCG_CT_CONST_NN32; break; case 'C': - ct->ct |= TCG_CT_CONST_CMPI; + /* ??? 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; @@ -409,103 +438,6 @@ static const char *target_parse_constraint(TCGArgConstraint *ct, return ct_str; } -/* Immediates to be used with logical OR. This is an optimization only, - since a full 64-bit immediate OR can always be performed with 4 sequential - OI[LH][LH] instructions. What we're looking for is immediates that we - can load efficiently, and the immediate load plus the reg-reg OR is - smaller than the sequential OI's. */ - -static int tcg_match_ori(TCGType type, tcg_target_long val) -{ - if (s390_facilities & FACILITY_EXT_IMM) { - if (type == TCG_TYPE_I32) { - /* All 32-bit ORs can be performed with 1 48-bit insn. */ - return 1; - } - } - - /* Look for negative values. These are best to load with LGHI. */ - if (val < 0) { - if (val == (int16_t)val) { - return 0; - } - if (s390_facilities & FACILITY_EXT_IMM) { - if (val == (int32_t)val) { - return 0; - } - } - } - - return 1; -} - -/* Immediates to be used with logical XOR. This is almost, but not quite, - only an optimization. XOR with immediate is only supported with the - extended-immediate facility. That said, there are a few patterns for - which it is better to load the value into a register first. */ - -static int tcg_match_xori(TCGType type, tcg_target_long val) -{ - if ((s390_facilities & FACILITY_EXT_IMM) == 0) { - return 0; - } - - if (type == TCG_TYPE_I32) { - /* All 32-bit XORs can be performed with 1 48-bit insn. */ - return 1; - } - - /* Look for negative values. These are best to load with LGHI. */ - if (val < 0 && val == (int32_t)val) { - return 0; - } - - return 1; -} - -/* Imediates to be used with comparisons. */ - -static int tcg_match_cmpi(TCGType type, tcg_target_long val) -{ - if (s390_facilities & FACILITY_EXT_IMM) { - /* The COMPARE IMMEDIATE instruction is available. */ - if (type == TCG_TYPE_I32) { - /* We have a 32-bit immediate and can compare against anything. */ - return 1; - } else { - /* ??? 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. */ - return val >= 0 && val <= 0x7fffffff; - } - } else { - /* Only the LOAD AND TEST instruction is available. */ - return val == 0; - } -} - -/* Immediates to be used with add2/sub2. */ - -static int tcg_match_add2i(TCGType type, tcg_target_long val) -{ - if (s390_facilities & FACILITY_EXT_IMM) { - if (type == TCG_TYPE_I32) { - return 1; - } else if (val >= -0xffffffffll && val <= 0xffffffffll) { - return 1; - } - } - return 0; -} - /* Test if a constant matches the constraint. */ static int tcg_target_const_match(tcg_target_long val, TCGType type, const TCGArgConstraint *arg_ct) @@ -521,24 +453,18 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type, } /* The following are mutually exclusive. */ - if (ct & TCG_CT_CONST_MULI) { - /* Immediates that may be used with multiply. If we have the - general-instruction-extensions, then we have MULTIPLY SINGLE - IMMEDIATE with a signed 32-bit, otherwise we have only - MULTIPLY HALFWORD IMMEDIATE, with a signed 16-bit. */ - if (s390_facilities & FACILITY_GEN_INST_EXT) { - return val == (int32_t)val; - } else { - return val == (int16_t)val; - } - } else if (ct & TCG_CT_CONST_ADLI) { - return tcg_match_add2i(type, val); - } else if (ct & TCG_CT_CONST_ORI) { - return tcg_match_ori(type, val); - } else if (ct & TCG_CT_CONST_XORI) { - return tcg_match_xori(type, val); - } else if (ct & TCG_CT_CONST_CMPI) { - return tcg_match_cmpi(type, val); + if (ct & TCG_CT_CONST_S16) { + return val == (int16_t)val; + } else if (ct & TCG_CT_CONST_S32) { + return val == (int32_t)val; + } else if (ct & TCG_CT_CONST_S33) { + return val >= -0xffffffffll && val <= 0xffffffffll; + } else if (ct & TCG_CT_CONST_NN16) { + return !(val < 0 && val == (int16_t)val); + } else if (ct & TCG_CT_CONST_NN32) { + return !(val < 0 && val == (int32_t)val); + } else if (ct & TCG_CT_CONST_U31) { + return val >= 0 && val <= 0x7fffffff; } else if (ct & TCG_CT_CONST_ZERO) { return val == 0; } @@ -570,6 +496,13 @@ static void tcg_out_insn_RI(TCGContext *s, S390Opcode op, TCGReg r1, int i2) tcg_out32(s, (op << 16) | (r1 << 20) | (i2 & 0xffff)); } +static void tcg_out_insn_RIE(TCGContext *s, S390Opcode op, TCGReg r1, + int i2, int m3) +{ + tcg_out16(s, (op & 0xff00) | (r1 << 4) | m3); + tcg_out32(s, (i2 << 16) | (op & 0xff)); +} + static void tcg_out_insn_RIL(TCGContext *s, S390Opcode op, TCGReg r1, int i2) { tcg_out16(s, op | (r1 << 4)); @@ -1138,11 +1071,33 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, TCGReg dest, TCGReg c1, TCGArg c2, int c2const) { int cc; + bool have_loc; + + /* With LOC2, we can always emit the minimum 3 insns. */ + if (s390_facilities & FACILITY_LOAD_ON_COND2) { + /* Emit: d = 0, d = (cc ? 1 : d). */ + cc = tgen_cmp(s, type, cond, c1, c2, c2const, false); + tcg_out_movi(s, TCG_TYPE_I64, dest, 0); + tcg_out_insn(s, RIE, LOCGHI, dest, 1, cc); + return; + } + have_loc = (s390_facilities & FACILITY_LOAD_ON_COND) != 0; + + /* For HAVE_LOC, only the paths through GTU/GT/LEU/LE are smaller. */ + restart: switch (cond) { + case TCG_COND_NE: + /* X != 0 is X > 0. */ + if (c2const && c2 == 0) { + cond = TCG_COND_GTU; + } else { + break; + } + /* fallthru */ + case TCG_COND_GTU: case TCG_COND_GT: - do_greater: /* The result of a compare has CC=2 for GT and CC=3 unused. ADD LOGICAL WITH CARRY considers (CC & 2) the carry bit. */ tgen_cmp(s, type, cond, c1, c2, c2const, true); @@ -1150,34 +1105,34 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, tcg_out_insn(s, RRE, ALCGR, dest, dest); return; - case TCG_COND_GEU: - do_geu: - /* We need "real" carry semantics, so use SUBTRACT LOGICAL - instead of COMPARE LOGICAL. This needs an extra move. */ - tcg_out_mov(s, type, TCG_TMP0, c1); - if (c2const) { - tcg_out_movi(s, TCG_TYPE_I64, dest, 0); - if (type == TCG_TYPE_I32) { - tcg_out_insn(s, RIL, SLFI, TCG_TMP0, c2); - } else { - tcg_out_insn(s, RIL, SLGFI, TCG_TMP0, c2); - } + case TCG_COND_EQ: + /* X == 0 is X <= 0. */ + if (c2const && c2 == 0) { + cond = TCG_COND_LEU; } else { - if (type == TCG_TYPE_I32) { - tcg_out_insn(s, RR, SLR, TCG_TMP0, c2); - } else { - tcg_out_insn(s, RRE, SLGR, TCG_TMP0, c2); - } - tcg_out_movi(s, TCG_TYPE_I64, dest, 0); + break; } - tcg_out_insn(s, RRE, ALCGR, dest, dest); - return; + /* fallthru */ case TCG_COND_LEU: + case TCG_COND_LE: + /* As above, but we're looking for borrow, or !carry. + The second insn computes d - d - borrow, or -1 for true + and 0 for false. So we must mask to 1 bit afterward. */ + tgen_cmp(s, type, cond, c1, c2, c2const, true); + tcg_out_insn(s, RRE, SLBGR, dest, dest); + tgen_andi(s, type, dest, 1); + return; + + case TCG_COND_GEU: case TCG_COND_LTU: case TCG_COND_LT: - /* Swap operands so that we can use GEU/GTU/GT. */ + case TCG_COND_GE: + /* Swap operands so that we can use LEU/GTU/GT/LE. */ if (c2const) { + if (have_loc) { + break; + } tcg_out_movi(s, type, TCG_TMP0, c2); c2 = c1; c2const = 0; @@ -1187,37 +1142,15 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, c1 = c2; c2 = t; } - if (cond == TCG_COND_LEU) { - goto do_geu; - } cond = tcg_swap_cond(cond); - goto do_greater; - - case TCG_COND_NE: - /* X != 0 is X > 0. */ - if (c2const && c2 == 0) { - cond = TCG_COND_GTU; - goto do_greater; - } - break; - - case TCG_COND_EQ: - /* X == 0 is X <= 0 is 0 >= X. */ - if (c2const && c2 == 0) { - tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 0); - c2 = c1; - c2const = 0; - c1 = TCG_TMP0; - goto do_geu; - } - break; + goto restart; default: - break; + g_assert_not_reached(); } cc = tgen_cmp(s, type, cond, c1, c2, c2const, false); - if (s390_facilities & FACILITY_LOAD_ON_COND) { + if (have_loc) { /* Emit: d = 0, t = 1, d = (cc ? t : d). */ tcg_out_movi(s, TCG_TYPE_I64, dest, 0); tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 1); @@ -1231,19 +1164,24 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, } static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest, - TCGReg c1, TCGArg c2, int c2const, TCGReg r3) + TCGReg c1, TCGArg c2, int c2const, + TCGArg v3, int v3const) { int cc; if (s390_facilities & FACILITY_LOAD_ON_COND) { cc = tgen_cmp(s, type, c, c1, c2, c2const, false); - tcg_out_insn(s, RRF, LOCGR, dest, r3, cc); + if (v3const) { + tcg_out_insn(s, RIE, LOCGHI, dest, v3, cc); + } else { + tcg_out_insn(s, RRF, LOCGR, dest, v3, cc); + } } else { c = tcg_invert_cond(c); cc = tgen_cmp(s, type, c, c1, c2, c2const, false); /* Emit: if (cc) goto over; dest = r3; over: */ tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1); - tcg_out_insn(s, RRE, LGR, dest, r3); + tcg_out_insn(s, RRE, LGR, dest, v3); } } @@ -1736,7 +1674,7 @@ static void tcg_out_qemu_st(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, const int *const_args) { - S390Opcode op; + S390Opcode op, op2; TCGArg a0, a1, a2; switch (opc) { @@ -1841,29 +1779,44 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, if (const_args[2]) { a2 = -a2; goto do_addi_32; + } else if (a0 == a1) { + tcg_out_insn(s, RR, SR, a0, a2); + } else { + tcg_out_insn(s, RRF, SRK, a0, a1, a2); } - tcg_out_insn(s, RR, SR, args[0], args[2]); break; case INDEX_op_and_i32: + a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; if (const_args[2]) { - tgen_andi(s, TCG_TYPE_I32, args[0], args[2]); + tcg_out_mov(s, TCG_TYPE_I32, a0, a1); + tgen_andi(s, TCG_TYPE_I32, a0, a2); + } else if (a0 == a1) { + tcg_out_insn(s, RR, NR, a0, a2); } else { - tcg_out_insn(s, RR, NR, args[0], args[2]); + tcg_out_insn(s, RRF, NRK, a0, a1, a2); } break; case INDEX_op_or_i32: + a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; if (const_args[2]) { - tgen64_ori(s, args[0], args[2] & 0xffffffff); + tcg_out_mov(s, TCG_TYPE_I32, a0, a1); + tgen64_ori(s, a0, a2); + } else if (a0 == a1) { + tcg_out_insn(s, RR, OR, a0, a2); } else { - tcg_out_insn(s, RR, OR, args[0], args[2]); + tcg_out_insn(s, RRF, ORK, a0, a1, a2); } break; case INDEX_op_xor_i32: + a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; if (const_args[2]) { - tgen64_xori(s, args[0], args[2] & 0xffffffff); - } else { + tcg_out_mov(s, TCG_TYPE_I32, a0, a1); + tgen64_xori(s, a0, a2); + } else if (a0 == a1) { tcg_out_insn(s, RR, XR, args[0], args[2]); + } else { + tcg_out_insn(s, RRF, XRK, a0, a1, a2); } break; @@ -1892,18 +1845,31 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_shl_i32: op = RS_SLL; + op2 = RSY_SLLK; do_shift32: - if (const_args[2]) { - tcg_out_sh32(s, op, args[0], TCG_REG_NONE, args[2]); + a0 = args[0], a1 = args[1], a2 = (int32_t)args[2]; + if (a0 == a1) { + if (const_args[2]) { + tcg_out_sh32(s, op, a0, TCG_REG_NONE, a2); + } else { + tcg_out_sh32(s, op, a0, a2, 0); + } } else { - tcg_out_sh32(s, op, args[0], args[2], 0); + /* Using tcg_out_sh64 here for the format; it is a 32-bit shift. */ + if (const_args[2]) { + tcg_out_sh64(s, op2, a0, a1, TCG_REG_NONE, a2); + } else { + tcg_out_sh64(s, op2, a0, a1, a2, 0); + } } break; case INDEX_op_shr_i32: op = RS_SRL; + op2 = RSY_SRLK; goto do_shift32; case INDEX_op_sar_i32: op = RS_SRA; + op2 = RSY_SRAK; goto do_shift32; case INDEX_op_rotl_i32: @@ -1978,7 +1944,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_movcond_i32: tgen_movcond(s, TCG_TYPE_I32, args[5], args[0], args[1], - args[2], const_args[2], args[3]); + args[2], const_args[2], args[3], const_args[3]); break; case INDEX_op_qemu_ld_i32: @@ -2045,30 +2011,44 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, if (const_args[2]) { a2 = -a2; goto do_addi_64; + } else if (a0 == a1) { + tcg_out_insn(s, RRE, SGR, a0, a2); } else { - tcg_out_insn(s, RRE, SGR, args[0], args[2]); + tcg_out_insn(s, RRF, SGRK, a0, a1, a2); } break; case INDEX_op_and_i64: + a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[2]) { + tcg_out_mov(s, TCG_TYPE_I64, a0, a1); tgen_andi(s, TCG_TYPE_I64, args[0], args[2]); - } else { + } else if (a0 == a1) { tcg_out_insn(s, RRE, NGR, args[0], args[2]); + } else { + tcg_out_insn(s, RRF, NGRK, a0, a1, a2); } break; case INDEX_op_or_i64: + a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[2]) { - tgen64_ori(s, args[0], args[2]); + tcg_out_mov(s, TCG_TYPE_I64, a0, a1); + tgen64_ori(s, a0, a2); + } else if (a0 == a1) { + tcg_out_insn(s, RRE, OGR, a0, a2); } else { - tcg_out_insn(s, RRE, OGR, args[0], args[2]); + tcg_out_insn(s, RRF, OGRK, a0, a1, a2); } break; case INDEX_op_xor_i64: + a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[2]) { - tgen64_xori(s, args[0], args[2]); + tcg_out_mov(s, TCG_TYPE_I64, a0, a1); + tgen64_xori(s, a0, a2); + } else if (a0 == a1) { + tcg_out_insn(s, RRE, XGR, a0, a2); } else { - tcg_out_insn(s, RRE, XGR, args[0], args[2]); + tcg_out_insn(s, RRF, XGRK, a0, a1, a2); } break; @@ -2197,7 +2177,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_movcond_i64: tgen_movcond(s, TCG_TYPE_I64, args[5], args[0], args[1], - args[2], const_args[2], args[3]); + args[2], const_args[2], args[3], const_args[3]); break; OP_32_64(deposit): @@ -2246,134 +2226,210 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, } } -static const TCGTargetOpDef s390_op_defs[] = { - { INDEX_op_exit_tb, { } }, - { INDEX_op_goto_tb, { } }, - { INDEX_op_br, { } }, - { INDEX_op_goto_ptr, { "r" } }, - - { INDEX_op_ld8u_i32, { "r", "r" } }, - { INDEX_op_ld8s_i32, { "r", "r" } }, - { INDEX_op_ld16u_i32, { "r", "r" } }, - { INDEX_op_ld16s_i32, { "r", "r" } }, - { INDEX_op_ld_i32, { "r", "r" } }, - { INDEX_op_st8_i32, { "r", "r" } }, - { INDEX_op_st16_i32, { "r", "r" } }, - { INDEX_op_st_i32, { "r", "r" } }, - - { INDEX_op_add_i32, { "r", "r", "ri" } }, - { INDEX_op_sub_i32, { "r", "0", "ri" } }, - { INDEX_op_mul_i32, { "r", "0", "rK" } }, - - { INDEX_op_div2_i32, { "b", "a", "0", "1", "r" } }, - { INDEX_op_divu2_i32, { "b", "a", "0", "1", "r" } }, - - { INDEX_op_and_i32, { "r", "0", "ri" } }, - { INDEX_op_or_i32, { "r", "0", "rO" } }, - { INDEX_op_xor_i32, { "r", "0", "rX" } }, - - { INDEX_op_neg_i32, { "r", "r" } }, - - { INDEX_op_shl_i32, { "r", "0", "ri" } }, - { INDEX_op_shr_i32, { "r", "0", "ri" } }, - { INDEX_op_sar_i32, { "r", "0", "ri" } }, - - { INDEX_op_rotl_i32, { "r", "r", "ri" } }, - { INDEX_op_rotr_i32, { "r", "r", "ri" } }, - - { INDEX_op_ext8s_i32, { "r", "r" } }, - { INDEX_op_ext8u_i32, { "r", "r" } }, - { INDEX_op_ext16s_i32, { "r", "r" } }, - { INDEX_op_ext16u_i32, { "r", "r" } }, - - { INDEX_op_bswap16_i32, { "r", "r" } }, - { INDEX_op_bswap32_i32, { "r", "r" } }, - - { INDEX_op_add2_i32, { "r", "r", "0", "1", "rA", "r" } }, - { INDEX_op_sub2_i32, { "r", "r", "0", "1", "rA", "r" } }, - - { INDEX_op_brcond_i32, { "r", "rC" } }, - { INDEX_op_setcond_i32, { "r", "r", "rC" } }, - { INDEX_op_movcond_i32, { "r", "r", "rC", "r", "0" } }, - { INDEX_op_deposit_i32, { "r", "rZ", "r" } }, - { INDEX_op_extract_i32, { "r", "r" } }, - - { INDEX_op_qemu_ld_i32, { "r", "L" } }, - { INDEX_op_qemu_ld_i64, { "r", "L" } }, - { INDEX_op_qemu_st_i32, { "L", "L" } }, - { INDEX_op_qemu_st_i64, { "L", "L" } }, - - { INDEX_op_ld8u_i64, { "r", "r" } }, - { INDEX_op_ld8s_i64, { "r", "r" } }, - { INDEX_op_ld16u_i64, { "r", "r" } }, - { INDEX_op_ld16s_i64, { "r", "r" } }, - { INDEX_op_ld32u_i64, { "r", "r" } }, - { INDEX_op_ld32s_i64, { "r", "r" } }, - { INDEX_op_ld_i64, { "r", "r" } }, - - { INDEX_op_st8_i64, { "r", "r" } }, - { INDEX_op_st16_i64, { "r", "r" } }, - { INDEX_op_st32_i64, { "r", "r" } }, - { INDEX_op_st_i64, { "r", "r" } }, - - { INDEX_op_add_i64, { "r", "r", "ri" } }, - { INDEX_op_sub_i64, { "r", "0", "ri" } }, - { INDEX_op_mul_i64, { "r", "0", "rK" } }, - - { INDEX_op_div2_i64, { "b", "a", "0", "1", "r" } }, - { INDEX_op_divu2_i64, { "b", "a", "0", "1", "r" } }, - { INDEX_op_mulu2_i64, { "b", "a", "0", "r" } }, - - { INDEX_op_and_i64, { "r", "0", "ri" } }, - { INDEX_op_or_i64, { "r", "0", "rO" } }, - { INDEX_op_xor_i64, { "r", "0", "rX" } }, - - { INDEX_op_neg_i64, { "r", "r" } }, - - { INDEX_op_shl_i64, { "r", "r", "ri" } }, - { INDEX_op_shr_i64, { "r", "r", "ri" } }, - { INDEX_op_sar_i64, { "r", "r", "ri" } }, - - { INDEX_op_rotl_i64, { "r", "r", "ri" } }, - { INDEX_op_rotr_i64, { "r", "r", "ri" } }, - - { INDEX_op_ext8s_i64, { "r", "r" } }, - { INDEX_op_ext8u_i64, { "r", "r" } }, - { INDEX_op_ext16s_i64, { "r", "r" } }, - { INDEX_op_ext16u_i64, { "r", "r" } }, - { INDEX_op_ext32s_i64, { "r", "r" } }, - { INDEX_op_ext32u_i64, { "r", "r" } }, - - { INDEX_op_ext_i32_i64, { "r", "r" } }, - { INDEX_op_extu_i32_i64, { "r", "r" } }, - - { INDEX_op_bswap16_i64, { "r", "r" } }, - { INDEX_op_bswap32_i64, { "r", "r" } }, - { INDEX_op_bswap64_i64, { "r", "r" } }, - - { INDEX_op_clz_i64, { "r", "r", "ri" } }, - - { INDEX_op_add2_i64, { "r", "r", "0", "1", "rA", "r" } }, - { INDEX_op_sub2_i64, { "r", "r", "0", "1", "rA", "r" } }, - - { INDEX_op_brcond_i64, { "r", "rC" } }, - { INDEX_op_setcond_i64, { "r", "r", "rC" } }, - { INDEX_op_movcond_i64, { "r", "r", "rC", "r", "0" } }, - { INDEX_op_deposit_i64, { "r", "0", "r" } }, - { INDEX_op_extract_i64, { "r", "r" } }, - - { INDEX_op_mb, { } }, - { -1 }, -}; - static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) { - int i, n = ARRAY_SIZE(s390_op_defs); + static const TCGTargetOpDef r = { .args_ct_str = { "r" } }; + static const TCGTargetOpDef r_r = { .args_ct_str = { "r", "r" } }; + 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_r_rM = { .args_ct_str = { "r", "r", "rM" } }; + static const TCGTargetOpDef r_0_r = { .args_ct_str = { "r", "0", "r" } }; + 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_rJ = { .args_ct_str = { "r", "0", "rJ" } }; + static const TCGTargetOpDef r_0_rN = { .args_ct_str = { "r", "0", "rN" } }; + static const TCGTargetOpDef r_0_rM = { .args_ct_str = { "r", "0", "rM" } }; + static const TCGTargetOpDef a2_r + = { .args_ct_str = { "r", "r", "0", "1", "r", "r" } }; + static const TCGTargetOpDef a2_ri + = { .args_ct_str = { "r", "r", "0", "1", "ri", "r" } }; + static const TCGTargetOpDef a2_rA + = { .args_ct_str = { "r", "r", "0", "1", "rA", "r" } }; + + switch (op) { + case INDEX_op_goto_ptr: + return &r; + + case INDEX_op_ld8u_i32: + case INDEX_op_ld8u_i64: + case INDEX_op_ld8s_i32: + case INDEX_op_ld8s_i64: + case INDEX_op_ld16u_i32: + case INDEX_op_ld16u_i64: + case INDEX_op_ld16s_i32: + case INDEX_op_ld16s_i64: + case INDEX_op_ld_i32: + case INDEX_op_ld32u_i64: + case INDEX_op_ld32s_i64: + case INDEX_op_ld_i64: + case INDEX_op_st8_i32: + case INDEX_op_st8_i64: + case INDEX_op_st16_i32: + case INDEX_op_st16_i64: + case INDEX_op_st_i32: + case INDEX_op_st32_i64: + case INDEX_op_st_i64: + return &r_r; + + case INDEX_op_add_i32: + case INDEX_op_add_i64: + return &r_r_ri; + case INDEX_op_sub_i32: + case INDEX_op_sub_i64: + return (s390_facilities & FACILITY_DISTINCT_OPS ? &r_r_ri : &r_0_ri); + + case INDEX_op_mul_i32: + /* If we have the general-instruction-extensions, then we have + MULTIPLY SINGLE IMMEDIATE with a signed 32-bit, otherwise we + have only MULTIPLY HALFWORD IMMEDIATE, with a signed 16-bit. */ + return (s390_facilities & FACILITY_GEN_INST_EXT ? &r_0_ri : &r_0_rI); + case INDEX_op_mul_i64: + return (s390_facilities & FACILITY_GEN_INST_EXT ? &r_0_rJ : &r_0_rI); + + case INDEX_op_or_i32: + /* The use of [iNM] constraints are optimization only, since a full + 64-bit immediate OR can always be performed with 4 sequential + OI[LH][LH] instructions. By rejecting certain negative ranges, + the immediate load plus the reg-reg OR is smaller. */ + return (s390_facilities & FACILITY_EXT_IMM + ? (s390_facilities & FACILITY_DISTINCT_OPS ? &r_r_ri : &r_0_ri) + : &r_0_rN); + case INDEX_op_or_i64: + return (s390_facilities & FACILITY_EXT_IMM + ? (s390_facilities & FACILITY_DISTINCT_OPS ? &r_r_rM : &r_0_rM) + : &r_0_rN); + + case INDEX_op_xor_i32: + /* Without EXT_IMM, no immediates are supported. Otherwise, + rejecting certain negative ranges leads to smaller code. */ + return (s390_facilities & FACILITY_EXT_IMM + ? (s390_facilities & FACILITY_DISTINCT_OPS ? &r_r_ri : &r_0_ri) + : &r_0_r); + case INDEX_op_xor_i64: + return (s390_facilities & FACILITY_EXT_IMM + ? (s390_facilities & FACILITY_DISTINCT_OPS ? &r_r_rM : &r_0_rM) + : &r_0_r); + + case INDEX_op_and_i32: + case INDEX_op_and_i64: + return (s390_facilities & FACILITY_DISTINCT_OPS ? &r_r_ri : &r_0_ri); + + case INDEX_op_shl_i32: + case INDEX_op_shr_i32: + case INDEX_op_sar_i32: + return (s390_facilities & FACILITY_DISTINCT_OPS ? &r_r_ri : &r_0_ri); + + case INDEX_op_shl_i64: + case INDEX_op_shr_i64: + case INDEX_op_sar_i64: + return &r_r_ri; + + case INDEX_op_rotl_i32: + case INDEX_op_rotl_i64: + case INDEX_op_rotr_i32: + case INDEX_op_rotr_i64: + 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); + + case INDEX_op_bswap16_i32: + case INDEX_op_bswap16_i64: + case INDEX_op_bswap32_i32: + case INDEX_op_bswap32_i64: + case INDEX_op_bswap64_i64: + case INDEX_op_neg_i32: + case INDEX_op_neg_i64: + case INDEX_op_ext8s_i32: + case INDEX_op_ext8s_i64: + case INDEX_op_ext8u_i32: + case INDEX_op_ext8u_i64: + case INDEX_op_ext16s_i32: + case INDEX_op_ext16s_i64: + case INDEX_op_ext16u_i32: + case INDEX_op_ext16u_i64: + case INDEX_op_ext32s_i64: + case INDEX_op_ext32u_i64: + case INDEX_op_ext_i32_i64: + case INDEX_op_extu_i32_i64: + case INDEX_op_extract_i32: + case INDEX_op_extract_i64: + return &r_r; + + case INDEX_op_clz_i64: + return &r_r_ri; - for (i = 0; i < n; ++i) { - if (s390_op_defs[i].op == op) { - return &s390_op_defs[i]; + case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_ld_i64: + return &r_L; + case INDEX_op_qemu_st_i64: + case INDEX_op_qemu_st_i32: + return &L_L; + + case INDEX_op_deposit_i32: + case INDEX_op_deposit_i64: + { + static const TCGTargetOpDef dep + = { .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_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); + } + case INDEX_op_div2_i32: + case INDEX_op_div2_i64: + case INDEX_op_divu2_i32: + case INDEX_op_divu2_i64: + { + static const TCGTargetOpDef div2 + = { .args_ct_str = { "b", "a", "0", "1", "r" } }; + return &div2; } + case INDEX_op_mulu2_i64: + { + static const TCGTargetOpDef mul2 + = { .args_ct_str = { "b", "a", "0", "r" } }; + return &mul2; + } + + case INDEX_op_add2_i32: + case INDEX_op_sub2_i32: + return (s390_facilities & FACILITY_EXT_IMM ? &a2_ri : &a2_r); + case INDEX_op_add2_i64: + case INDEX_op_sub2_i64: + return (s390_facilities & FACILITY_EXT_IMM ? &a2_rA : &a2_r); + + default: + break; } return NULL; } |