aboutsummaryrefslogtreecommitdiff
path: root/tcg/ppc
diff options
context:
space:
mode:
Diffstat (limited to 'tcg/ppc')
-rw-r--r--tcg/ppc/tcg-target-con-set.h12
-rw-r--r--tcg/ppc/tcg-target-con-str.h1
-rw-r--r--tcg/ppc/tcg-target-has.h59
-rw-r--r--tcg/ppc/tcg-target.c.inc1948
4 files changed, 1078 insertions, 942 deletions
diff --git a/tcg/ppc/tcg-target-con-set.h b/tcg/ppc/tcg-target-con-set.h
index 453abde..da7a383 100644
--- a/tcg/ppc/tcg-target-con-set.h
+++ b/tcg/ppc/tcg-target-con-set.h
@@ -15,29 +15,29 @@ C_O0_I2(r, rC)
C_O0_I2(v, r)
C_O0_I3(r, r, r)
C_O0_I3(o, m, r)
-C_O0_I4(r, r, ri, ri)
+C_O0_I4(r, r, rU, rC)
C_O0_I4(r, r, r, r)
C_O1_I1(r, r)
C_O1_I1(v, r)
C_O1_I1(v, v)
C_O1_I1(v, vr)
C_O1_I2(r, 0, rZ)
-C_O1_I2(r, rI, ri)
-C_O1_I2(r, rI, rT)
+C_O1_I2(r, rI, r)
C_O1_I2(r, r, r)
C_O1_I2(r, r, ri)
C_O1_I2(r, r, rC)
C_O1_I2(r, r, rI)
C_O1_I2(r, r, rT)
C_O1_I2(r, r, rU)
+C_O1_I2(r, r, rZM)
C_O1_I2(r, r, rZW)
+C_O1_I2(r, rI, rN)
+C_O1_I2(r, rZM, rZM)
C_O1_I2(v, v, v)
C_O1_I3(v, v, v, v)
C_O1_I4(v, v, v, vZM, v)
C_O1_I4(r, r, rC, rZ, rZ)
-C_O1_I4(r, r, r, ri, ri)
+C_O1_I4(r, r, r, rU, rC)
C_O2_I1(r, r, r)
C_N1O1_I1(o, m, r)
C_O2_I2(r, r, r, r)
-C_O2_I4(r, r, rI, rZM, r, r)
-C_O2_I4(r, r, r, r, rI, rZM)
diff --git a/tcg/ppc/tcg-target-con-str.h b/tcg/ppc/tcg-target-con-str.h
index 16b6872..faf92da 100644
--- a/tcg/ppc/tcg-target-con-str.h
+++ b/tcg/ppc/tcg-target-con-str.h
@@ -19,6 +19,7 @@ REGS('v', ALL_VECTOR_REGS)
CONST('C', TCG_CT_CONST_CMP)
CONST('I', TCG_CT_CONST_S16)
CONST('M', TCG_CT_CONST_MONE)
+CONST('N', TCG_CT_CONST_N16)
CONST('T', TCG_CT_CONST_S32)
CONST('U', TCG_CT_CONST_U32)
CONST('W', TCG_CT_CONST_WSZ)
diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h
index 6db91f7..81ec5ae 100644
--- a/tcg/ppc/tcg-target-has.h
+++ b/tcg/ppc/tcg-target-has.h
@@ -16,68 +16,9 @@
#define have_altivec (cpuinfo & CPUINFO_ALTIVEC)
#define have_vsx (cpuinfo & CPUINFO_VSX)
-/* optional instructions automatically implemented */
-#define TCG_TARGET_HAS_ext8u_i32 0 /* andi */
-#define TCG_TARGET_HAS_ext16u_i32 0
-
/* optional instructions */
-#define TCG_TARGET_HAS_div_i32 1
-#define TCG_TARGET_HAS_rem_i32 have_isa_3_00
-#define TCG_TARGET_HAS_rot_i32 1
-#define TCG_TARGET_HAS_ext8s_i32 1
-#define TCG_TARGET_HAS_ext16s_i32 1
-#define TCG_TARGET_HAS_bswap16_i32 1
-#define TCG_TARGET_HAS_bswap32_i32 1
-#define TCG_TARGET_HAS_not_i32 1
-#define TCG_TARGET_HAS_andc_i32 1
-#define TCG_TARGET_HAS_orc_i32 1
-#define TCG_TARGET_HAS_eqv_i32 1
-#define TCG_TARGET_HAS_nand_i32 1
-#define TCG_TARGET_HAS_nor_i32 1
-#define TCG_TARGET_HAS_clz_i32 1
-#define TCG_TARGET_HAS_ctz_i32 have_isa_3_00
-#define TCG_TARGET_HAS_ctpop_i32 have_isa_2_06
-#define TCG_TARGET_HAS_extract2_i32 0
-#define TCG_TARGET_HAS_negsetcond_i32 1
-#define TCG_TARGET_HAS_mulu2_i32 0
-#define TCG_TARGET_HAS_muls2_i32 0
-#define TCG_TARGET_HAS_muluh_i32 1
-#define TCG_TARGET_HAS_mulsh_i32 1
-#define TCG_TARGET_HAS_qemu_st8_i32 0
-
#if TCG_TARGET_REG_BITS == 64
-#define TCG_TARGET_HAS_add2_i32 0
-#define TCG_TARGET_HAS_sub2_i32 0
#define TCG_TARGET_HAS_extr_i64_i32 0
-#define TCG_TARGET_HAS_div_i64 1
-#define TCG_TARGET_HAS_rem_i64 have_isa_3_00
-#define TCG_TARGET_HAS_rot_i64 1
-#define TCG_TARGET_HAS_ext8s_i64 1
-#define TCG_TARGET_HAS_ext16s_i64 1
-#define TCG_TARGET_HAS_ext32s_i64 1
-#define TCG_TARGET_HAS_ext8u_i64 0
-#define TCG_TARGET_HAS_ext16u_i64 0
-#define TCG_TARGET_HAS_ext32u_i64 0
-#define TCG_TARGET_HAS_bswap16_i64 1
-#define TCG_TARGET_HAS_bswap32_i64 1
-#define TCG_TARGET_HAS_bswap64_i64 1
-#define TCG_TARGET_HAS_not_i64 1
-#define TCG_TARGET_HAS_andc_i64 1
-#define TCG_TARGET_HAS_orc_i64 1
-#define TCG_TARGET_HAS_eqv_i64 1
-#define TCG_TARGET_HAS_nand_i64 1
-#define TCG_TARGET_HAS_nor_i64 1
-#define TCG_TARGET_HAS_clz_i64 1
-#define TCG_TARGET_HAS_ctz_i64 have_isa_3_00
-#define TCG_TARGET_HAS_ctpop_i64 have_isa_2_06
-#define TCG_TARGET_HAS_extract2_i64 0
-#define TCG_TARGET_HAS_negsetcond_i64 1
-#define TCG_TARGET_HAS_add2_i64 1
-#define TCG_TARGET_HAS_sub2_i64 1
-#define TCG_TARGET_HAS_mulu2_i64 0
-#define TCG_TARGET_HAS_muls2_i64 0
-#define TCG_TARGET_HAS_muluh_i64 1
-#define TCG_TARGET_HAS_mulsh_i64 1
#endif
#define TCG_TARGET_HAS_qemu_ldst_i128 \
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
index 822925a..b8b23d4 100644
--- a/tcg/ppc/tcg-target.c.inc
+++ b/tcg/ppc/tcg-target.c.inc
@@ -89,14 +89,15 @@
/* Shorthand for size of a register. */
#define SZR (TCG_TARGET_REG_BITS / 8)
-#define TCG_CT_CONST_S16 0x100
-#define TCG_CT_CONST_U16 0x200
-#define TCG_CT_CONST_S32 0x400
-#define TCG_CT_CONST_U32 0x800
-#define TCG_CT_CONST_ZERO 0x1000
-#define TCG_CT_CONST_MONE 0x2000
-#define TCG_CT_CONST_WSZ 0x4000
-#define TCG_CT_CONST_CMP 0x8000
+#define TCG_CT_CONST_S16 0x00100
+#define TCG_CT_CONST_U16 0x00200
+#define TCG_CT_CONST_N16 0x00400
+#define TCG_CT_CONST_S32 0x00800
+#define TCG_CT_CONST_U32 0x01000
+#define TCG_CT_CONST_ZERO 0x02000
+#define TCG_CT_CONST_MONE 0x04000
+#define TCG_CT_CONST_WSZ 0x08000
+#define TCG_CT_CONST_CMP 0x10000
#define ALL_GENERAL_REGS 0xffffffffu
#define ALL_VECTOR_REGS 0xffffffff00000000ull
@@ -342,6 +343,9 @@ static bool tcg_target_const_match(int64_t sval, int ct,
if ((ct & TCG_CT_CONST_U16) && uval == (uint16_t)uval) {
return 1;
}
+ if ((ct & TCG_CT_CONST_N16) && -sval == (int16_t)-sval) {
+ return 1;
+ }
if ((ct & TCG_CT_CONST_S32) && sval == (int32_t)sval) {
return 1;
}
@@ -1012,111 +1016,6 @@ static void tcg_out_addpcis(TCGContext *s, TCGReg dst, intptr_t imm)
tcg_out32(s, ADDPCIS | RT(dst) | (d1 << 16) | (d0 << 6) | d2);
}
-static void tcg_out_bswap16(TCGContext *s, TCGReg dst, TCGReg src, int flags)
-{
- TCGReg tmp = dst == src ? TCG_REG_R0 : dst;
-
- if (have_isa_3_10) {
- tcg_out32(s, BRH | RA(dst) | RS(src));
- if (flags & TCG_BSWAP_OS) {
- tcg_out_ext16s(s, TCG_TYPE_REG, dst, dst);
- } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) {
- tcg_out_ext16u(s, dst, dst);
- }
- return;
- }
-
- /*
- * In the following,
- * dep(a, b, m) -> (a & ~m) | (b & m)
- *
- * Begin with: src = xxxxabcd
- */
- /* tmp = rol32(src, 24) & 0x000000ff = 0000000c */
- tcg_out_rlw(s, RLWINM, tmp, src, 24, 24, 31);
- /* tmp = dep(tmp, rol32(src, 8), 0x0000ff00) = 000000dc */
- tcg_out_rlw(s, RLWIMI, tmp, src, 8, 16, 23);
-
- if (flags & TCG_BSWAP_OS) {
- tcg_out_ext16s(s, TCG_TYPE_REG, dst, tmp);
- } else {
- tcg_out_mov(s, TCG_TYPE_REG, dst, tmp);
- }
-}
-
-static void tcg_out_bswap32(TCGContext *s, TCGReg dst, TCGReg src, int flags)
-{
- TCGReg tmp = dst == src ? TCG_REG_R0 : dst;
-
- if (have_isa_3_10) {
- tcg_out32(s, BRW | RA(dst) | RS(src));
- if (flags & TCG_BSWAP_OS) {
- tcg_out_ext32s(s, dst, dst);
- } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) {
- tcg_out_ext32u(s, dst, dst);
- }
- return;
- }
-
- /*
- * Stolen from gcc's builtin_bswap32.
- * In the following,
- * dep(a, b, m) -> (a & ~m) | (b & m)
- *
- * Begin with: src = xxxxabcd
- */
- /* tmp = rol32(src, 8) & 0xffffffff = 0000bcda */
- tcg_out_rlw(s, RLWINM, tmp, src, 8, 0, 31);
- /* tmp = dep(tmp, rol32(src, 24), 0xff000000) = 0000dcda */
- tcg_out_rlw(s, RLWIMI, tmp, src, 24, 0, 7);
- /* tmp = dep(tmp, rol32(src, 24), 0x0000ff00) = 0000dcba */
- tcg_out_rlw(s, RLWIMI, tmp, src, 24, 16, 23);
-
- if (flags & TCG_BSWAP_OS) {
- tcg_out_ext32s(s, dst, tmp);
- } else {
- tcg_out_mov(s, TCG_TYPE_REG, dst, tmp);
- }
-}
-
-static void tcg_out_bswap64(TCGContext *s, TCGReg dst, TCGReg src)
-{
- TCGReg t0 = dst == src ? TCG_REG_R0 : dst;
- TCGReg t1 = dst == src ? dst : TCG_REG_R0;
-
- if (have_isa_3_10) {
- tcg_out32(s, BRD | RA(dst) | RS(src));
- return;
- }
-
- /*
- * In the following,
- * dep(a, b, m) -> (a & ~m) | (b & m)
- *
- * Begin with: src = abcdefgh
- */
- /* t0 = rol32(src, 8) & 0xffffffff = 0000fghe */
- tcg_out_rlw(s, RLWINM, t0, src, 8, 0, 31);
- /* t0 = dep(t0, rol32(src, 24), 0xff000000) = 0000hghe */
- tcg_out_rlw(s, RLWIMI, t0, src, 24, 0, 7);
- /* t0 = dep(t0, rol32(src, 24), 0x0000ff00) = 0000hgfe */
- tcg_out_rlw(s, RLWIMI, t0, src, 24, 16, 23);
-
- /* t0 = rol64(t0, 32) = hgfe0000 */
- tcg_out_rld(s, RLDICL, t0, t0, 32, 0);
- /* t1 = rol64(src, 32) = efghabcd */
- tcg_out_rld(s, RLDICL, t1, src, 32, 0);
-
- /* t0 = dep(t0, rol32(t1, 24), 0xffffffff) = hgfebcda */
- tcg_out_rlw(s, RLWIMI, t0, t1, 8, 0, 31);
- /* t0 = dep(t0, rol32(t1, 24), 0xff000000) = hgfedcda */
- tcg_out_rlw(s, RLWIMI, t0, t1, 24, 0, 7);
- /* t0 = dep(t0, rol32(t1, 24), 0x0000ff00) = hgfedcba */
- tcg_out_rlw(s, RLWIMI, t0, t1, 24, 16, 23);
-
- tcg_out_mov(s, TCG_TYPE_REG, dst, t0);
-}
-
/* Emit a move into ret of arg, if it can be done in one insn. */
static bool tcg_out_movi_one(TCGContext *s, TCGReg ret, tcg_target_long arg)
{
@@ -1777,9 +1676,8 @@ static void tcg_out_test(TCGContext *s, TCGReg dest, TCGReg arg1, TCGArg arg2,
}
static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
- int const_arg2, int cr, TCGType type)
+ bool const_arg2, int cr, TCGType type)
{
- int imm;
uint32_t op;
tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32);
@@ -1796,18 +1694,15 @@ static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
case TCG_COND_EQ:
case TCG_COND_NE:
if (const_arg2) {
- if ((int16_t) arg2 == arg2) {
+ if ((int16_t)arg2 == arg2) {
op = CMPI;
- imm = 1;
- break;
- } else if ((uint16_t) arg2 == arg2) {
- op = CMPLI;
- imm = 1;
break;
}
+ tcg_debug_assert((uint16_t)arg2 == arg2);
+ op = CMPLI;
+ break;
}
op = CMPL;
- imm = 0;
break;
case TCG_COND_TSTEQ:
@@ -1821,14 +1716,11 @@ static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
case TCG_COND_LE:
case TCG_COND_GT:
if (const_arg2) {
- if ((int16_t) arg2 == arg2) {
- op = CMPI;
- imm = 1;
- break;
- }
+ tcg_debug_assert((int16_t)arg2 == arg2);
+ op = CMPI;
+ break;
}
op = CMP;
- imm = 0;
break;
case TCG_COND_LTU:
@@ -1836,30 +1728,20 @@ static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2,
case TCG_COND_LEU:
case TCG_COND_GTU:
if (const_arg2) {
- if ((uint16_t) arg2 == arg2) {
- op = CMPLI;
- imm = 1;
- break;
- }
+ tcg_debug_assert((uint16_t)arg2 == arg2);
+ op = CMPLI;
+ break;
}
op = CMPL;
- imm = 0;
break;
default:
g_assert_not_reached();
}
op |= BF(cr) | ((type == TCG_TYPE_I64) << 21);
-
- if (imm) {
- tcg_out32(s, op | RA(arg1) | (arg2 & 0xffff));
- } else {
- if (const_arg2) {
- tcg_out_movi(s, type, TCG_REG_R0, arg2);
- arg2 = TCG_REG_R0;
- }
- tcg_out32(s, op | RA(arg1) | RB(arg2));
- }
+ op |= RA(arg1);
+ op |= const_arg2 ? arg2 & 0xffff : RB(arg2);
+ tcg_out32(s, op);
}
static void tcg_out_setcond_eq0(TCGContext *s, TCGType type,
@@ -1926,8 +1808,8 @@ static TCGReg tcg_gen_setcond_xor(TCGContext *s, TCGReg arg1, TCGArg arg2,
}
static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond,
- TCGArg arg0, TCGArg arg1, TCGArg arg2,
- int const_arg2, bool neg)
+ TCGReg arg0, TCGReg arg1, TCGArg arg2,
+ bool const_arg2, bool neg)
{
int sh;
bool inv;
@@ -2072,6 +1954,54 @@ static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond,
}
}
+static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg dest, TCGReg arg1, TCGReg arg2)
+{
+ tcg_out_setcond(s, type, cond, dest, arg1, arg2, false, false);
+}
+
+static void tgen_setcondi(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg dest, TCGReg arg1, tcg_target_long arg2)
+{
+ tcg_out_setcond(s, type, cond, dest, arg1, arg2, true, false);
+}
+
+static const TCGOutOpSetcond outop_setcond = {
+ .base.static_constraint = C_O1_I2(r, r, rC),
+ .out_rrr = tgen_setcond,
+ .out_rri = tgen_setcondi,
+};
+
+static void tgen_negsetcond(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg dest, TCGReg arg1, TCGReg arg2)
+{
+ tcg_out_setcond(s, type, cond, dest, arg1, arg2, false, true);
+}
+
+static void tgen_negsetcondi(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg dest, TCGReg arg1, tcg_target_long arg2)
+{
+ tcg_out_setcond(s, type, cond, dest, arg1, arg2, true, true);
+}
+
+static const TCGOutOpSetcond outop_negsetcond = {
+ .base.static_constraint = C_O1_I2(r, r, rC),
+ .out_rrr = tgen_negsetcond,
+ .out_rri = tgen_negsetcondi,
+};
+
+void tcg_out_br(TCGContext *s, TCGLabel *l)
+{
+ uint32_t insn = B;
+
+ if (l->has_value) {
+ insn |= reloc_pc24_val(tcg_splitwx_to_rx(s->code_ptr), l->u.value_ptr);
+ } else {
+ tcg_out_reloc(s, s->code_ptr, R_PPC_REL24, l, 0);
+ }
+ tcg_out32(s, insn);
+}
+
static void tcg_out_bc(TCGContext *s, TCGCond cond, int bd)
{
tcg_out32(s, tcg_to_bc[cond] | bd);
@@ -2088,17 +2018,29 @@ static void tcg_out_bc_lab(TCGContext *s, TCGCond cond, TCGLabel *l)
tcg_out_bc(s, cond, bd);
}
-static void tcg_out_brcond(TCGContext *s, TCGCond cond,
- TCGArg arg1, TCGArg arg2, int const_arg2,
- TCGLabel *l, TCGType type)
+static void tgen_brcond(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg arg1, TCGReg arg2, TCGLabel *l)
+{
+ tcg_out_cmp(s, cond, arg1, arg2, false, 0, type);
+ tcg_out_bc_lab(s, cond, l);
+}
+
+static void tgen_brcondi(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg arg1, tcg_target_long arg2, TCGLabel *l)
{
- tcg_out_cmp(s, cond, arg1, arg2, const_arg2, 0, type);
+ tcg_out_cmp(s, cond, arg1, arg2, true, 0, type);
tcg_out_bc_lab(s, cond, l);
}
-static void tcg_out_movcond(TCGContext *s, TCGType type, TCGCond cond,
- TCGArg dest, TCGArg c1, TCGArg c2, TCGArg v1,
- TCGArg v2, bool const_c2)
+static const TCGOutOpBrcond outop_brcond = {
+ .base.static_constraint = C_O0_I2(r, rC),
+ .out_rr = tgen_brcond,
+ .out_ri = tgen_brcondi,
+};
+
+static void tgen_movcond(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg dest, TCGReg c1, TCGArg c2, bool const_c2,
+ TCGArg v1, bool const_v1, TCGArg v2, bool const_v2)
{
/* If for some reason both inputs are zero, don't produce bad code. */
if (v1 == 0 && v2 == 0) {
@@ -2144,6 +2086,11 @@ static void tcg_out_movcond(TCGContext *s, TCGType type, TCGCond cond,
}
}
+static const TCGOutOpMovcond outop_movcond = {
+ .base.static_constraint = C_O1_I4(r, r, rC, rZ, rZ),
+ .out = tgen_movcond,
+};
+
static void tcg_out_cntxz(TCGContext *s, TCGType type, uint32_t opc,
TCGArg a0, TCGArg a1, TCGArg a2, bool const_a2)
{
@@ -2170,8 +2117,8 @@ static void tcg_out_cntxz(TCGContext *s, TCGType type, uint32_t opc,
}
}
-static void tcg_out_cmp2(TCGContext *s, const TCGArg *args,
- const int *const_args)
+static void tcg_out_cmp2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah,
+ TCGArg bl, bool blconst, TCGArg bh, bool bhconst)
{
static const struct { uint8_t bit1, bit2; } bits[] = {
[TCG_COND_LT ] = { CR_LT, CR_LT },
@@ -2184,18 +2131,9 @@ static void tcg_out_cmp2(TCGContext *s, const TCGArg *args,
[TCG_COND_GEU] = { CR_GT, CR_LT },
};
- TCGCond cond = args[4], cond2;
- TCGArg al, ah, bl, bh;
- int blconst, bhconst;
+ TCGCond cond2;
int op, bit1, bit2;
- al = args[0];
- ah = args[1];
- bl = args[2];
- bh = args[3];
- blconst = const_args[2];
- bhconst = const_args[3];
-
switch (cond) {
case TCG_COND_EQ:
op = CRAND;
@@ -2247,22 +2185,42 @@ static void tcg_out_cmp2(TCGContext *s, const TCGArg *args,
}
}
-static void tcg_out_setcond2(TCGContext *s, const TCGArg *args,
- const int *const_args)
+static void tgen_setcond2(TCGContext *s, TCGCond cond, TCGReg ret,
+ TCGReg al, TCGReg ah,
+ TCGArg bl, bool const_bl,
+ TCGArg bh, bool const_bh)
{
- tcg_out_cmp2(s, args + 1, const_args + 1);
+ tcg_out_cmp2(s, cond, al, ah, bl, const_bl, bh, const_bh);
tcg_out32(s, MFOCRF | RT(TCG_REG_R0) | FXM(0));
- tcg_out_rlw(s, RLWINM, args[0], TCG_REG_R0, CR_EQ + 0*4 + 1, 31, 31);
+ tcg_out_rlw(s, RLWINM, ret, TCG_REG_R0, CR_EQ + 0*4 + 1, 31, 31);
}
-static void tcg_out_brcond2(TCGContext *s, const TCGArg *args,
- const int *const_args)
+#if TCG_TARGET_REG_BITS != 32
+__attribute__((unused))
+#endif
+static const TCGOutOpSetcond2 outop_setcond2 = {
+ .base.static_constraint = C_O1_I4(r, r, r, rU, rC),
+ .out = tgen_setcond2,
+};
+
+static void tgen_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah,
+ TCGArg bl, bool const_bl,
+ TCGArg bh, bool const_bh, TCGLabel *l)
{
- tcg_out_cmp2(s, args, const_args);
- tcg_out_bc_lab(s, TCG_COND_EQ, arg_label(args[5]));
+ assert(TCG_TARGET_REG_BITS == 32);
+ tcg_out_cmp2(s, cond, al, ah, bl, const_bl, bh, const_bh);
+ tcg_out_bc_lab(s, TCG_COND_EQ, l);
}
-static void tcg_out_mb(TCGContext *s, TCGArg a0)
+#if TCG_TARGET_REG_BITS != 32
+__attribute__((unused))
+#endif
+static const TCGOutOpBrcond2 outop_brcond2 = {
+ .base.static_constraint = C_O0_I4(r, r, rU, rC),
+ .out = tgen_brcond2,
+};
+
+static void tcg_out_mb(TCGContext *s, unsigned a0)
{
uint32_t insn;
@@ -2482,10 +2440,10 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
/* Extract the page index, shifted into place for tlb index. */
if (TCG_TARGET_REG_BITS == 32) {
tcg_out_shri32(s, TCG_REG_R0, addr,
- s->page_bits - CPU_TLB_ENTRY_BITS);
+ TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
} else {
tcg_out_shri64(s, TCG_REG_R0, addr,
- s->page_bits - CPU_TLB_ENTRY_BITS);
+ TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
}
tcg_out32(s, AND | SAB(TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_R0));
@@ -2522,7 +2480,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
a_bits = s_bits;
}
tcg_out_rlw(s, RLWINM, TCG_REG_R0, addr, 0,
- (32 - a_bits) & 31, 31 - s->page_bits);
+ (32 - a_bits) & 31, 31 - TARGET_PAGE_BITS);
} else {
TCGReg t = addr;
@@ -2543,13 +2501,13 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
/* Mask the address for the requested alignment. */
if (addr_type == TCG_TYPE_I32) {
tcg_out_rlw(s, RLWINM, TCG_REG_R0, t, 0,
- (32 - a_bits) & 31, 31 - s->page_bits);
+ (32 - a_bits) & 31, 31 - TARGET_PAGE_BITS);
} else if (a_bits == 0) {
- tcg_out_rld(s, RLDICR, TCG_REG_R0, t, 0, 63 - s->page_bits);
+ tcg_out_rld(s, RLDICR, TCG_REG_R0, t, 0, 63 - TARGET_PAGE_BITS);
} else {
tcg_out_rld(s, RLDICL, TCG_REG_R0, t,
- 64 - s->page_bits, s->page_bits - a_bits);
- tcg_out_rld(s, RLDICL, TCG_REG_R0, TCG_REG_R0, s->page_bits, 0);
+ 64 - TARGET_PAGE_BITS, TARGET_PAGE_BITS - a_bits);
+ tcg_out_rld(s, RLDICL, TCG_REG_R0, TCG_REG_R0, TARGET_PAGE_BITS, 0);
}
}
@@ -2737,6 +2695,60 @@ static void tcg_out_qemu_ldst_i128(TCGContext *s, TCGReg datalo, TCGReg datahi,
}
}
+static void tgen_qemu_ld(TCGContext *s, TCGType type, TCGReg data,
+ TCGReg addr, MemOpIdx oi)
+{
+ tcg_out_qemu_ld(s, data, -1, addr, oi, type);
+}
+
+static const TCGOutOpQemuLdSt outop_qemu_ld = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_qemu_ld,
+};
+
+static void tgen_qemu_ld2(TCGContext *s, TCGType type, TCGReg datalo,
+ TCGReg datahi, TCGReg addr, MemOpIdx oi)
+{
+ if (TCG_TARGET_REG_BITS == 32) {
+ tcg_out_qemu_ld(s, datalo, datahi, addr, oi, type);
+ } else {
+ tcg_out_qemu_ldst_i128(s, datalo, datahi, addr, oi, true);
+ }
+}
+
+static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = {
+ .base.static_constraint =
+ TCG_TARGET_REG_BITS == 64 ? C_N1O1_I1(o, m, r) : C_O2_I1(r, r, r),
+ .out = tgen_qemu_ld2,
+};
+
+static void tgen_qemu_st(TCGContext *s, TCGType type, TCGReg data,
+ TCGReg addr, MemOpIdx oi)
+{
+ tcg_out_qemu_st(s, data, -1, addr, oi, type);
+}
+
+static const TCGOutOpQemuLdSt outop_qemu_st = {
+ .base.static_constraint = C_O0_I2(r, r),
+ .out = tgen_qemu_st,
+};
+
+static void tgen_qemu_st2(TCGContext *s, TCGType type, TCGReg datalo,
+ TCGReg datahi, TCGReg addr, MemOpIdx oi)
+{
+ if (TCG_TARGET_REG_BITS == 32) {
+ tcg_out_qemu_st(s, datalo, datahi, addr, oi, type);
+ } else {
+ tcg_out_qemu_ldst_i128(s, datalo, datahi, addr, oi, false);
+ }
+}
+
+static const TCGOutOpQemuLdSt2 outop_qemu_st2 = {
+ .base.static_constraint =
+ TCG_TARGET_REG_BITS == 64 ? C_O0_I3(o, m, r) : C_O0_I3(r, r, r),
+ .out = tgen_qemu_st2,
+};
+
static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
{
int i;
@@ -2885,6 +2897,13 @@ static void tcg_out_goto_tb(TCGContext *s, int which)
set_jmp_reset_offset(s, which);
}
+static void tcg_out_goto_ptr(TCGContext *s, TCGReg a0)
+{
+ tcg_out32(s, MTSPR | RS(a0) | CTR);
+ tcg_out32(s, ADDI | TAI(TCG_REG_R3, 0, 0));
+ tcg_out32(s, BCCTR | BO_ALWAYS);
+}
+
void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
uintptr_t jmp_rx, uintptr_t jmp_rw)
{
@@ -2902,595 +2921,913 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
flush_idcache_range(jmp_rx, jmp_rw, 4);
}
-static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
- const TCGArg args[TCG_MAX_OP_ARGS],
- const int const_args[TCG_MAX_OP_ARGS])
+
+static void tgen_add(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
{
- TCGArg a0, a1, a2;
+ tcg_out32(s, ADD | TAB(a0, a1, a2));
+}
- switch (opc) {
- case INDEX_op_goto_ptr:
- tcg_out32(s, MTSPR | RS(args[0]) | CTR);
- tcg_out32(s, ADDI | TAI(TCG_REG_R3, 0, 0));
- tcg_out32(s, BCCTR | BO_ALWAYS);
- break;
- case INDEX_op_br:
- {
- TCGLabel *l = arg_label(args[0]);
- uint32_t insn = B;
-
- if (l->has_value) {
- insn |= reloc_pc24_val(tcg_splitwx_to_rx(s->code_ptr),
- l->u.value_ptr);
- } else {
- tcg_out_reloc(s, s->code_ptr, R_PPC_REL24, l, 0);
- }
- tcg_out32(s, insn);
- }
- break;
- case INDEX_op_ld8u_i32:
- case INDEX_op_ld8u_i64:
- tcg_out_mem_long(s, LBZ, LBZX, args[0], args[1], args[2]);
- break;
- case INDEX_op_ld8s_i32:
- case INDEX_op_ld8s_i64:
- tcg_out_mem_long(s, LBZ, LBZX, args[0], args[1], args[2]);
- tcg_out_ext8s(s, TCG_TYPE_REG, args[0], args[0]);
- break;
- case INDEX_op_ld16u_i32:
- case INDEX_op_ld16u_i64:
- tcg_out_mem_long(s, LHZ, LHZX, args[0], args[1], args[2]);
- break;
- case INDEX_op_ld16s_i32:
- case INDEX_op_ld16s_i64:
- tcg_out_mem_long(s, LHA, LHAX, args[0], args[1], args[2]);
- break;
- case INDEX_op_ld_i32:
- case INDEX_op_ld32u_i64:
- tcg_out_mem_long(s, LWZ, LWZX, args[0], args[1], args[2]);
- break;
- case INDEX_op_ld32s_i64:
- tcg_out_mem_long(s, LWA, LWAX, args[0], args[1], args[2]);
- break;
- case INDEX_op_ld_i64:
- tcg_out_mem_long(s, LD, LDX, args[0], args[1], args[2]);
- break;
- case INDEX_op_st8_i32:
- case INDEX_op_st8_i64:
- tcg_out_mem_long(s, STB, STBX, args[0], args[1], args[2]);
- break;
- case INDEX_op_st16_i32:
- case INDEX_op_st16_i64:
- tcg_out_mem_long(s, STH, STHX, args[0], args[1], args[2]);
- break;
- case INDEX_op_st_i32:
- case INDEX_op_st32_i64:
- tcg_out_mem_long(s, STW, STWX, args[0], args[1], args[2]);
- break;
- case INDEX_op_st_i64:
- tcg_out_mem_long(s, STD, STDX, args[0], args[1], args[2]);
- break;
+static void tgen_addi(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tcg_out_mem_long(s, ADDI, ADD, a0, a1, a2);
+}
- case INDEX_op_add_i32:
- a0 = args[0], a1 = args[1], a2 = args[2];
- if (const_args[2]) {
- do_addi_32:
- tcg_out_mem_long(s, ADDI, ADD, a0, a1, (int32_t)a2);
- } else {
- tcg_out32(s, ADD | TAB(a0, a1, a2));
- }
- break;
- case INDEX_op_sub_i32:
- a0 = args[0], a1 = args[1], a2 = args[2];
- if (const_args[1]) {
- if (const_args[2]) {
- tcg_out_movi(s, TCG_TYPE_I32, a0, a1 - a2);
- } else {
- tcg_out32(s, SUBFIC | TAI(a0, a2, a1));
- }
- } else if (const_args[2]) {
- a2 = -a2;
- goto do_addi_32;
- } else {
- tcg_out32(s, SUBF | TAB(a0, a2, a1));
- }
- break;
+static const TCGOutOpBinary outop_add = {
+ .base.static_constraint = C_O1_I2(r, r, rT),
+ .out_rrr = tgen_add,
+ .out_rri = tgen_addi,
+};
- case INDEX_op_and_i32:
- a0 = args[0], a1 = args[1], a2 = args[2];
- if (const_args[2]) {
- tcg_out_andi32(s, a0, a1, a2);
- } else {
- tcg_out32(s, AND | SAB(a1, a0, a2));
- }
- break;
- case INDEX_op_and_i64:
- a0 = args[0], a1 = args[1], a2 = args[2];
- if (const_args[2]) {
- tcg_out_andi64(s, a0, a1, a2);
- } else {
- tcg_out32(s, AND | SAB(a1, a0, a2));
- }
- break;
- case INDEX_op_or_i64:
- case INDEX_op_or_i32:
- a0 = args[0], a1 = args[1], a2 = args[2];
- if (const_args[2]) {
- tcg_out_ori32(s, a0, a1, a2);
- } else {
- tcg_out32(s, OR | SAB(a1, a0, a2));
- }
- break;
- case INDEX_op_xor_i64:
- case INDEX_op_xor_i32:
- a0 = args[0], a1 = args[1], a2 = args[2];
- if (const_args[2]) {
- tcg_out_xori32(s, a0, a1, a2);
- } else {
- tcg_out32(s, XOR | SAB(a1, a0, a2));
- }
- break;
- case INDEX_op_andc_i32:
- a0 = args[0], a1 = args[1], a2 = args[2];
- if (const_args[2]) {
- tcg_out_andi32(s, a0, a1, ~a2);
- } else {
- tcg_out32(s, ANDC | SAB(a1, a0, a2));
- }
- break;
- case INDEX_op_andc_i64:
- a0 = args[0], a1 = args[1], a2 = args[2];
- if (const_args[2]) {
- tcg_out_andi64(s, a0, a1, ~a2);
- } else {
- tcg_out32(s, ANDC | SAB(a1, a0, a2));
- }
- break;
- case INDEX_op_orc_i32:
- if (const_args[2]) {
- tcg_out_ori32(s, args[0], args[1], ~args[2]);
- break;
- }
- /* FALLTHRU */
- case INDEX_op_orc_i64:
- tcg_out32(s, ORC | SAB(args[1], args[0], args[2]));
- break;
- case INDEX_op_eqv_i32:
- if (const_args[2]) {
- tcg_out_xori32(s, args[0], args[1], ~args[2]);
- break;
- }
- /* FALLTHRU */
- case INDEX_op_eqv_i64:
- tcg_out32(s, EQV | SAB(args[1], args[0], args[2]));
- break;
- case INDEX_op_nand_i32:
- case INDEX_op_nand_i64:
- tcg_out32(s, NAND | SAB(args[1], args[0], args[2]));
- break;
- case INDEX_op_nor_i32:
- case INDEX_op_nor_i64:
- tcg_out32(s, NOR | SAB(args[1], args[0], args[2]));
- break;
+static void tgen_addco_rrr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, ADDC | TAB(a0, a1, a2));
+}
- case INDEX_op_clz_i32:
- tcg_out_cntxz(s, TCG_TYPE_I32, CNTLZW, args[0], args[1],
- args[2], const_args[2]);
- break;
- case INDEX_op_ctz_i32:
- tcg_out_cntxz(s, TCG_TYPE_I32, CNTTZW, args[0], args[1],
- args[2], const_args[2]);
- break;
- case INDEX_op_ctpop_i32:
- tcg_out32(s, CNTPOPW | SAB(args[1], args[0], 0));
- break;
+static void tgen_addco_rri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tcg_out32(s, ADDIC | TAI(a0, a1, a2));
+}
- case INDEX_op_clz_i64:
- tcg_out_cntxz(s, TCG_TYPE_I64, CNTLZD, args[0], args[1],
- args[2], const_args[2]);
- break;
- case INDEX_op_ctz_i64:
- tcg_out_cntxz(s, TCG_TYPE_I64, CNTTZD, args[0], args[1],
- args[2], const_args[2]);
- break;
- case INDEX_op_ctpop_i64:
- tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0));
- break;
+static TCGConstraintSetIndex cset_addco(TCGType type, unsigned flags)
+{
+ /*
+ * Note that the CA bit is defined based on the word size of the
+ * environment. So in 64-bit mode it's always carry-out of bit 63.
+ * The fallback code using deposit works just as well for TCG_TYPE_I32.
+ */
+ return type == TCG_TYPE_REG ? C_O1_I2(r, r, rI) : C_NotImplemented;
+}
- case INDEX_op_mul_i32:
- a0 = args[0], a1 = args[1], a2 = args[2];
- if (const_args[2]) {
- tcg_out32(s, MULLI | TAI(a0, a1, a2));
- } else {
- tcg_out32(s, MULLW | TAB(a0, a1, a2));
- }
- break;
+static const TCGOutOpBinary outop_addco = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_addco,
+ .out_rrr = tgen_addco_rrr,
+ .out_rri = tgen_addco_rri,
+};
- case INDEX_op_div_i32:
- tcg_out32(s, DIVW | TAB(args[0], args[1], args[2]));
- break;
+static void tgen_addcio_rrr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, ADDE | TAB(a0, a1, a2));
+}
- case INDEX_op_divu_i32:
- tcg_out32(s, DIVWU | TAB(args[0], args[1], args[2]));
- break;
+static void tgen_addcio_rri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tcg_out32(s, (a2 ? ADDME : ADDZE) | RT(a0) | RA(a1));
+}
- case INDEX_op_rem_i32:
- tcg_out32(s, MODSW | TAB(args[0], args[1], args[2]));
- break;
+static TCGConstraintSetIndex cset_addcio(TCGType type, unsigned flags)
+{
+ return type == TCG_TYPE_REG ? C_O1_I2(r, r, rZM) : C_NotImplemented;
+}
- case INDEX_op_remu_i32:
- tcg_out32(s, MODUW | TAB(args[0], args[1], args[2]));
- break;
+static const TCGOutOpBinary outop_addcio = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_addcio,
+ .out_rrr = tgen_addcio_rrr,
+ .out_rri = tgen_addcio_rri,
+};
- case INDEX_op_shl_i32:
- if (const_args[2]) {
- /* Limit immediate shift count lest we create an illegal insn. */
- tcg_out_shli32(s, args[0], args[1], args[2] & 31);
- } else {
- tcg_out32(s, SLW | SAB(args[1], args[0], args[2]));
- }
- break;
- case INDEX_op_shr_i32:
- if (const_args[2]) {
- /* Limit immediate shift count lest we create an illegal insn. */
- tcg_out_shri32(s, args[0], args[1], args[2] & 31);
- } else {
- tcg_out32(s, SRW | SAB(args[1], args[0], args[2]));
- }
- break;
- case INDEX_op_sar_i32:
- if (const_args[2]) {
- tcg_out_sari32(s, args[0], args[1], args[2]);
- } else {
- tcg_out32(s, SRAW | SAB(args[1], args[0], args[2]));
- }
- break;
- case INDEX_op_rotl_i32:
- if (const_args[2]) {
- tcg_out_rlw(s, RLWINM, args[0], args[1], args[2], 0, 31);
- } else {
- tcg_out32(s, RLWNM | SAB(args[1], args[0], args[2])
- | MB(0) | ME(31));
- }
- break;
- case INDEX_op_rotr_i32:
- if (const_args[2]) {
- tcg_out_rlw(s, RLWINM, args[0], args[1], 32 - args[2], 0, 31);
- } else {
- tcg_out32(s, SUBFIC | TAI(TCG_REG_R0, args[2], 32));
- tcg_out32(s, RLWNM | SAB(args[1], args[0], TCG_REG_R0)
- | MB(0) | ME(31));
- }
- break;
+static const TCGOutOpAddSubCarry outop_addci = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_addcio,
+ .out_rrr = tgen_addcio_rrr,
+ .out_rri = tgen_addcio_rri,
+};
- case INDEX_op_brcond_i32:
- tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
- arg_label(args[3]), TCG_TYPE_I32);
- break;
- case INDEX_op_brcond_i64:
- tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
- arg_label(args[3]), TCG_TYPE_I64);
- break;
- case INDEX_op_brcond2_i32:
- tcg_out_brcond2(s, args, const_args);
- break;
+static void tcg_out_set_carry(TCGContext *s)
+{
+ tcg_out32(s, SUBFC | TAB(TCG_REG_R0, TCG_REG_R0, TCG_REG_R0));
+}
- case INDEX_op_neg_i32:
- case INDEX_op_neg_i64:
- tcg_out32(s, NEG | RT(args[0]) | RA(args[1]));
- break;
+static void tgen_and(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, AND | SAB(a1, a0, a2));
+}
- case INDEX_op_not_i32:
- case INDEX_op_not_i64:
- tcg_out32(s, NOR | SAB(args[1], args[0], args[1]));
- break;
+static void tgen_andi(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ if (type == TCG_TYPE_I32) {
+ tcg_out_andi32(s, a0, a1, a2);
+ } else {
+ tcg_out_andi64(s, a0, a1, a2);
+ }
+}
- case INDEX_op_add_i64:
- a0 = args[0], a1 = args[1], a2 = args[2];
- if (const_args[2]) {
- do_addi_64:
- tcg_out_mem_long(s, ADDI, ADD, a0, a1, a2);
- } else {
- tcg_out32(s, ADD | TAB(a0, a1, a2));
- }
- break;
- case INDEX_op_sub_i64:
- a0 = args[0], a1 = args[1], a2 = args[2];
- if (const_args[1]) {
- if (const_args[2]) {
- tcg_out_movi(s, TCG_TYPE_I64, a0, a1 - a2);
- } else {
- tcg_out32(s, SUBFIC | TAI(a0, a2, a1));
- }
- } else if (const_args[2]) {
- a2 = -a2;
- goto do_addi_64;
- } else {
- tcg_out32(s, SUBF | TAB(a0, a2, a1));
- }
- break;
+static const TCGOutOpBinary outop_and = {
+ .base.static_constraint = C_O1_I2(r, r, ri),
+ .out_rrr = tgen_and,
+ .out_rri = tgen_andi,
+};
- case INDEX_op_shl_i64:
- if (const_args[2]) {
- /* Limit immediate shift count lest we create an illegal insn. */
- tcg_out_shli64(s, args[0], args[1], args[2] & 63);
- } else {
- tcg_out32(s, SLD | SAB(args[1], args[0], args[2]));
- }
- break;
- case INDEX_op_shr_i64:
- if (const_args[2]) {
- /* Limit immediate shift count lest we create an illegal insn. */
- tcg_out_shri64(s, args[0], args[1], args[2] & 63);
- } else {
- tcg_out32(s, SRD | SAB(args[1], args[0], args[2]));
- }
- break;
- case INDEX_op_sar_i64:
- if (const_args[2]) {
- tcg_out_sari64(s, args[0], args[1], args[2]);
- } else {
- tcg_out32(s, SRAD | SAB(args[1], args[0], args[2]));
- }
- break;
- case INDEX_op_rotl_i64:
- if (const_args[2]) {
- tcg_out_rld(s, RLDICL, args[0], args[1], args[2], 0);
- } else {
- tcg_out32(s, RLDCL | SAB(args[1], args[0], args[2]) | MB64(0));
- }
- break;
- case INDEX_op_rotr_i64:
- if (const_args[2]) {
- tcg_out_rld(s, RLDICL, args[0], args[1], 64 - args[2], 0);
- } else {
- tcg_out32(s, SUBFIC | TAI(TCG_REG_R0, args[2], 64));
- tcg_out32(s, RLDCL | SAB(args[1], args[0], TCG_REG_R0) | MB64(0));
- }
- break;
+static void tgen_andc(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, ANDC | SAB(a1, a0, a2));
+}
- case INDEX_op_mul_i64:
- a0 = args[0], a1 = args[1], a2 = args[2];
- if (const_args[2]) {
- tcg_out32(s, MULLI | TAI(a0, a1, a2));
- } else {
- tcg_out32(s, MULLD | TAB(a0, a1, a2));
- }
- break;
- case INDEX_op_div_i64:
- tcg_out32(s, DIVD | TAB(args[0], args[1], args[2]));
- break;
- case INDEX_op_divu_i64:
- tcg_out32(s, DIVDU | TAB(args[0], args[1], args[2]));
- break;
- case INDEX_op_rem_i64:
- tcg_out32(s, MODSD | TAB(args[0], args[1], args[2]));
- break;
- case INDEX_op_remu_i64:
- tcg_out32(s, MODUD | TAB(args[0], args[1], args[2]));
- break;
+static const TCGOutOpBinary outop_andc = {
+ .base.static_constraint = C_O1_I2(r, r, r),
+ .out_rrr = tgen_andc,
+};
- case INDEX_op_qemu_ld_i32:
- tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I32);
- break;
- case INDEX_op_qemu_ld_i64:
- if (TCG_TARGET_REG_BITS == 64) {
- tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I64);
- } else {
- tcg_out_qemu_ld(s, args[0], args[1], args[2],
- args[3], TCG_TYPE_I64);
- }
- break;
- case INDEX_op_qemu_ld_i128:
- tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
- tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], true);
- break;
+static void tgen_clz(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? CNTLZW : CNTLZD;
+ tcg_out_cntxz(s, type, insn, a0, a1, a2, false);
+}
- case INDEX_op_qemu_st_i32:
- tcg_out_qemu_st(s, args[0], -1, args[1], args[2], TCG_TYPE_I32);
- break;
- case INDEX_op_qemu_st_i64:
- if (TCG_TARGET_REG_BITS == 64) {
- tcg_out_qemu_st(s, args[0], -1, args[1], args[2], TCG_TYPE_I64);
- } else {
- tcg_out_qemu_st(s, args[0], args[1], args[2],
- args[3], TCG_TYPE_I64);
- }
- break;
- case INDEX_op_qemu_st_i128:
- tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
- tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false);
- break;
+static void tgen_clzi(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? CNTLZW : CNTLZD;
+ tcg_out_cntxz(s, type, insn, a0, a1, a2, true);
+}
- case INDEX_op_setcond_i32:
- tcg_out_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], args[2],
- const_args[2], false);
- break;
- case INDEX_op_setcond_i64:
- tcg_out_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], args[2],
- const_args[2], false);
- break;
- case INDEX_op_negsetcond_i32:
- tcg_out_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], args[2],
- const_args[2], true);
- break;
- case INDEX_op_negsetcond_i64:
- tcg_out_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], args[2],
- const_args[2], true);
- break;
- case INDEX_op_setcond2_i32:
- tcg_out_setcond2(s, args, const_args);
- break;
+static const TCGOutOpBinary outop_clz = {
+ .base.static_constraint = C_O1_I2(r, r, rZW),
+ .out_rrr = tgen_clz,
+ .out_rri = tgen_clzi,
+};
- case INDEX_op_bswap16_i32:
- case INDEX_op_bswap16_i64:
- tcg_out_bswap16(s, args[0], args[1], args[2]);
- break;
- case INDEX_op_bswap32_i32:
- tcg_out_bswap32(s, args[0], args[1], 0);
- break;
- case INDEX_op_bswap32_i64:
- tcg_out_bswap32(s, args[0], args[1], args[2]);
- break;
- case INDEX_op_bswap64_i64:
- tcg_out_bswap64(s, args[0], args[1]);
- break;
+static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? CNTPOPW : CNTPOPD;
+ tcg_out32(s, insn | SAB(a1, a0, 0));
+}
- case INDEX_op_deposit_i32:
- if (const_args[2]) {
- uint32_t mask = ((2u << (args[4] - 1)) - 1) << args[3];
- tcg_out_andi32(s, args[0], args[0], ~mask);
- } else {
- tcg_out_rlw(s, RLWIMI, args[0], args[2], args[3],
- 32 - args[3] - args[4], 31 - args[3]);
- }
- break;
- case INDEX_op_deposit_i64:
- if (const_args[2]) {
- uint64_t mask = ((2ull << (args[4] - 1)) - 1) << args[3];
- tcg_out_andi64(s, args[0], args[0], ~mask);
- } else {
- tcg_out_rld(s, RLDIMI, args[0], args[2], args[3],
- 64 - args[3] - args[4]);
- }
- break;
+static TCGConstraintSetIndex cset_ctpop(TCGType type, unsigned flags)
+{
+ return have_isa_2_06 ? C_O1_I1(r, r) : C_NotImplemented;
+}
- case INDEX_op_extract_i32:
- if (args[2] == 0 && args[3] <= 16) {
- tcg_out32(s, ANDI | SAI(args[1], args[0], (1 << args[3]) - 1));
- break;
- }
- tcg_out_rlw(s, RLWINM, args[0], args[1],
- 32 - args[2], 32 - args[3], 31);
- break;
- case INDEX_op_extract_i64:
- if (args[2] == 0 && args[3] <= 16) {
- tcg_out32(s, ANDI | SAI(args[1], args[0], (1 << args[3]) - 1));
- break;
- }
- tcg_out_rld(s, RLDICL, args[0], args[1], 64 - args[2], 64 - args[3]);
- break;
+static const TCGOutOpUnary outop_ctpop = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_ctpop,
+ .out_rr = tgen_ctpop,
+};
- case INDEX_op_sextract_i64:
- if (args[2] + args[3] == 32) {
- if (args[2] == 0) {
- tcg_out_ext32s(s, args[0], args[1]);
- } else {
- tcg_out_sari32(s, args[0], args[1], args[2]);
- }
- break;
- }
- /* FALLTHRU */
- case INDEX_op_sextract_i32:
- if (args[2] == 0 && args[3] == 8) {
- tcg_out_ext8s(s, TCG_TYPE_I32, args[0], args[1]);
- } else if (args[2] == 0 && args[3] == 16) {
- tcg_out_ext16s(s, TCG_TYPE_I32, args[0], args[1]);
- } else {
- g_assert_not_reached();
- }
- break;
+static void tgen_ctz(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? CNTTZW : CNTTZD;
+ tcg_out_cntxz(s, type, insn, a0, a1, a2, false);
+}
- case INDEX_op_movcond_i32:
- tcg_out_movcond(s, TCG_TYPE_I32, args[5], args[0], args[1], args[2],
- args[3], args[4], const_args[2]);
- break;
- case INDEX_op_movcond_i64:
- tcg_out_movcond(s, TCG_TYPE_I64, args[5], args[0], args[1], args[2],
- args[3], args[4], const_args[2]);
- break;
+static void tgen_ctzi(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? CNTTZW : CNTTZD;
+ tcg_out_cntxz(s, type, insn, a0, a1, a2, true);
+}
+
+static TCGConstraintSetIndex cset_ctz(TCGType type, unsigned flags)
+{
+ return have_isa_3_00 ? C_O1_I2(r, r, rZW) : C_NotImplemented;
+}
+
+static const TCGOutOpBinary outop_ctz = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_ctz,
+ .out_rrr = tgen_ctz,
+ .out_rri = tgen_ctzi,
+};
+
+static void tgen_eqv(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, EQV | SAB(a1, a0, a2));
+}
#if TCG_TARGET_REG_BITS == 64
- case INDEX_op_add2_i64:
-#else
- case INDEX_op_add2_i32:
+static void tgen_extrh_i64_i32(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1)
+{
+ tcg_out_shri64(s, a0, a1, 32);
+}
+
+static const TCGOutOpUnary outop_extrh_i64_i32 = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out_rr = tgen_extrh_i64_i32,
+};
#endif
- /* Note that the CA bit is defined based on the word size of the
- environment. So in 64-bit mode it's always carry-out of bit 63.
- The fallback code using deposit works just as well for 32-bit. */
- a0 = args[0], a1 = args[1];
- if (a0 == args[3] || (!const_args[5] && a0 == args[5])) {
- a0 = TCG_REG_R0;
- }
- if (const_args[4]) {
- tcg_out32(s, ADDIC | TAI(a0, args[2], args[4]));
- } else {
- tcg_out32(s, ADDC | TAB(a0, args[2], args[4]));
+
+static void tgen_divs(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? DIVW : DIVD;
+ tcg_out32(s, insn | TAB(a0, a1, a2));
+}
+
+static const TCGOutOpBinary outop_divs = {
+ .base.static_constraint = C_O1_I2(r, r, r),
+ .out_rrr = tgen_divs,
+};
+
+static const TCGOutOpDivRem outop_divs2 = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static void tgen_divu(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? DIVWU : DIVDU;
+ tcg_out32(s, insn | TAB(a0, a1, a2));
+}
+
+static const TCGOutOpBinary outop_divu = {
+ .base.static_constraint = C_O1_I2(r, r, r),
+ .out_rrr = tgen_divu,
+};
+
+static const TCGOutOpDivRem outop_divu2 = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static const TCGOutOpBinary outop_eqv = {
+ .base.static_constraint = C_O1_I2(r, r, r),
+ .out_rrr = tgen_eqv,
+};
+
+static void tgen_mul(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? MULLW : MULLD;
+ tcg_out32(s, insn | TAB(a0, a1, a2));
+}
+
+static void tgen_muli(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tcg_out32(s, MULLI | TAI(a0, a1, a2));
+}
+
+static const TCGOutOpBinary outop_mul = {
+ .base.static_constraint = C_O1_I2(r, r, rI),
+ .out_rrr = tgen_mul,
+ .out_rri = tgen_muli,
+};
+
+static const TCGOutOpMul2 outop_muls2 = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static void tgen_mulsh(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? MULHW : MULHD;
+ tcg_out32(s, insn | TAB(a0, a1, a2));
+}
+
+static const TCGOutOpBinary outop_mulsh = {
+ .base.static_constraint = C_O1_I2(r, r, r),
+ .out_rrr = tgen_mulsh,
+};
+
+static const TCGOutOpMul2 outop_mulu2 = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static void tgen_muluh(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? MULHWU : MULHDU;
+ tcg_out32(s, insn | TAB(a0, a1, a2));
+}
+
+static const TCGOutOpBinary outop_muluh = {
+ .base.static_constraint = C_O1_I2(r, r, r),
+ .out_rrr = tgen_muluh,
+};
+
+static void tgen_nand(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, NAND | SAB(a1, a0, a2));
+}
+
+static const TCGOutOpBinary outop_nand = {
+ .base.static_constraint = C_O1_I2(r, r, r),
+ .out_rrr = tgen_nand,
+};
+
+static void tgen_nor(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, NOR | SAB(a1, a0, a2));
+}
+
+static const TCGOutOpBinary outop_nor = {
+ .base.static_constraint = C_O1_I2(r, r, r),
+ .out_rrr = tgen_nor,
+};
+
+static void tgen_or(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, OR | SAB(a1, a0, a2));
+}
+
+static void tgen_ori(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tcg_out_ori32(s, a0, a1, a2);
+}
+
+static const TCGOutOpBinary outop_or = {
+ .base.static_constraint = C_O1_I2(r, r, rU),
+ .out_rrr = tgen_or,
+ .out_rri = tgen_ori,
+};
+
+static void tgen_orc(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, ORC | SAB(a1, a0, a2));
+}
+
+static const TCGOutOpBinary outop_orc = {
+ .base.static_constraint = C_O1_I2(r, r, r),
+ .out_rrr = tgen_orc,
+};
+
+static TCGConstraintSetIndex cset_mod(TCGType type, unsigned flags)
+{
+ return have_isa_3_00 ? C_O1_I2(r, r, r) : C_NotImplemented;
+}
+
+static void tgen_rems(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? MODSW : MODSD;
+ tcg_out32(s, insn | TAB(a0, a1, a2));
+}
+
+static const TCGOutOpBinary outop_rems = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_mod,
+ .out_rrr = tgen_rems,
+};
+
+static void tgen_remu(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? MODUW : MODUD;
+ tcg_out32(s, insn | TAB(a0, a1, a2));
+}
+
+static const TCGOutOpBinary outop_remu = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_mod,
+ .out_rrr = tgen_remu,
+};
+
+static void tgen_rotl(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ if (type == TCG_TYPE_I32) {
+ tcg_out32(s, RLWNM | SAB(a1, a0, a2) | MB(0) | ME(31));
+ } else {
+ tcg_out32(s, RLDCL | SAB(a1, a0, a2) | MB64(0));
+ }
+}
+
+static void tgen_rotli(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ if (type == TCG_TYPE_I32) {
+ tcg_out_rlw(s, RLWINM, a0, a1, a2, 0, 31);
+ } else {
+ tcg_out_rld(s, RLDICL, a0, a1, a2, 0);
+ }
+}
+
+static const TCGOutOpBinary outop_rotl = {
+ .base.static_constraint = C_O1_I2(r, r, ri),
+ .out_rrr = tgen_rotl,
+ .out_rri = tgen_rotli,
+};
+
+static const TCGOutOpBinary outop_rotr = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static void tgen_sar(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? SRAW : SRAD;
+ tcg_out32(s, insn | SAB(a1, a0, a2));
+}
+
+static void tgen_sari(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ /* Limit immediate shift count lest we create an illegal insn. */
+ if (type == TCG_TYPE_I32) {
+ tcg_out_sari32(s, a0, a1, a2 & 31);
+ } else {
+ tcg_out_sari64(s, a0, a1, a2 & 63);
+ }
+}
+
+static const TCGOutOpBinary outop_sar = {
+ .base.static_constraint = C_O1_I2(r, r, ri),
+ .out_rrr = tgen_sar,
+ .out_rri = tgen_sari,
+};
+
+static void tgen_shl(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? SLW : SLD;
+ tcg_out32(s, insn | SAB(a1, a0, a2));
+}
+
+static void tgen_shli(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ /* Limit immediate shift count lest we create an illegal insn. */
+ if (type == TCG_TYPE_I32) {
+ tcg_out_shli32(s, a0, a1, a2 & 31);
+ } else {
+ tcg_out_shli64(s, a0, a1, a2 & 63);
+ }
+}
+
+static const TCGOutOpBinary outop_shl = {
+ .base.static_constraint = C_O1_I2(r, r, ri),
+ .out_rrr = tgen_shl,
+ .out_rri = tgen_shli,
+};
+
+static void tgen_shr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ uint32_t insn = type == TCG_TYPE_I32 ? SRW : SRD;
+ tcg_out32(s, insn | SAB(a1, a0, a2));
+}
+
+static void tgen_shri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ /* Limit immediate shift count lest we create an illegal insn. */
+ if (type == TCG_TYPE_I32) {
+ tcg_out_shri32(s, a0, a1, a2 & 31);
+ } else {
+ tcg_out_shri64(s, a0, a1, a2 & 63);
+ }
+}
+
+static const TCGOutOpBinary outop_shr = {
+ .base.static_constraint = C_O1_I2(r, r, ri),
+ .out_rrr = tgen_shr,
+ .out_rri = tgen_shri,
+};
+
+static void tgen_sub(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, SUBF | TAB(a0, a2, a1));
+}
+
+static void tgen_subfi(TCGContext *s, TCGType type,
+ TCGReg a0, tcg_target_long a1, TCGReg a2)
+{
+ tcg_out32(s, SUBFIC | TAI(a0, a2, a1));
+}
+
+static const TCGOutOpSubtract outop_sub = {
+ .base.static_constraint = C_O1_I2(r, rI, r),
+ .out_rrr = tgen_sub,
+ .out_rir = tgen_subfi,
+};
+
+static void tgen_subbo_rrr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, SUBFC | TAB(a0, a2, a1));
+}
+
+static void tgen_subbo_rri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ if (a2 == 0) {
+ tcg_out_movi(s, type, TCG_REG_R0, 0);
+ tgen_subbo_rrr(s, type, a0, a1, TCG_REG_R0);
+ } else {
+ tgen_addco_rri(s, type, a0, a1, -a2);
+ }
+}
+
+/* The underlying insn for subfi is subfic. */
+#define tgen_subbo_rir tgen_subfi
+
+static void tgen_subbo_rii(TCGContext *s, TCGType type,
+ TCGReg a0, tcg_target_long a1, tcg_target_long a2)
+{
+ tcg_out_movi(s, type, TCG_REG_R0, a2);
+ tgen_subbo_rir(s, type, a0, a1, TCG_REG_R0);
+}
+
+static TCGConstraintSetIndex cset_subbo(TCGType type, unsigned flags)
+{
+ /* Recall that the CA bit is defined based on the host word size. */
+ return type == TCG_TYPE_REG ? C_O1_I2(r, rI, rN) : C_NotImplemented;
+}
+
+static const TCGOutOpAddSubCarry outop_subbo = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_subbo,
+ .out_rrr = tgen_subbo_rrr,
+ .out_rri = tgen_subbo_rri,
+ .out_rir = tgen_subbo_rir,
+ .out_rii = tgen_subbo_rii,
+};
+
+static void tgen_subbio_rrr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, SUBFE | TAB(a0, a2, a1));
+}
+
+static void tgen_subbio_rri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tgen_addcio_rri(s, type, a0, a1, ~a2);
+}
+
+static void tgen_subbio_rir(TCGContext *s, TCGType type,
+ TCGReg a0, tcg_target_long a1, TCGReg a2)
+{
+ tcg_debug_assert(a1 == 0 || a1 == -1);
+ tcg_out32(s, (a1 ? SUBFME : SUBFZE) | RT(a0) | RA(a2));
+}
+
+static void tgen_subbio_rii(TCGContext *s, TCGType type,
+ TCGReg a0, tcg_target_long a1, tcg_target_long a2)
+{
+ tcg_out_movi(s, type, TCG_REG_R0, a2);
+ tgen_subbio_rir(s, type, a0, a1, TCG_REG_R0);
+}
+
+static TCGConstraintSetIndex cset_subbio(TCGType type, unsigned flags)
+{
+ return type == TCG_TYPE_REG ? C_O1_I2(r, rZM, rZM) : C_NotImplemented;
+}
+
+static const TCGOutOpAddSubCarry outop_subbio = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_subbio,
+ .out_rrr = tgen_subbio_rrr,
+ .out_rri = tgen_subbio_rri,
+ .out_rir = tgen_subbio_rir,
+ .out_rii = tgen_subbio_rii,
+};
+
+#define outop_subbi outop_subbio
+
+static void tcg_out_set_borrow(TCGContext *s)
+{
+ /* borrow = !carry */
+ tcg_out32(s, ADDIC | TAI(TCG_REG_R0, TCG_REG_R0, 0));
+}
+
+static void tgen_xor(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, XOR | SAB(a1, a0, a2));
+}
+
+static void tgen_xori(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tcg_out_xori32(s, a0, a1, a2);
+}
+
+static const TCGOutOpBinary outop_xor = {
+ .base.static_constraint = C_O1_I2(r, r, rU),
+ .out_rrr = tgen_xor,
+ .out_rri = tgen_xori,
+};
+
+static void tgen_bswap16(TCGContext *s, TCGType type,
+ TCGReg dst, TCGReg src, unsigned flags)
+{
+ TCGReg tmp = dst == src ? TCG_REG_R0 : dst;
+
+ if (have_isa_3_10) {
+ tcg_out32(s, BRH | RA(dst) | RS(src));
+ if (flags & TCG_BSWAP_OS) {
+ tcg_out_ext16s(s, TCG_TYPE_REG, dst, dst);
+ } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) {
+ tcg_out_ext16u(s, dst, dst);
}
- if (const_args[5]) {
- tcg_out32(s, (args[5] ? ADDME : ADDZE) | RT(a1) | RA(args[3]));
- } else {
- tcg_out32(s, ADDE | TAB(a1, args[3], args[5]));
+ return;
+ }
+
+ /*
+ * In the following,
+ * dep(a, b, m) -> (a & ~m) | (b & m)
+ *
+ * Begin with: src = xxxxabcd
+ */
+ /* tmp = rol32(src, 24) & 0x000000ff = 0000000c */
+ tcg_out_rlw(s, RLWINM, tmp, src, 24, 24, 31);
+ /* tmp = dep(tmp, rol32(src, 8), 0x0000ff00) = 000000dc */
+ tcg_out_rlw(s, RLWIMI, tmp, src, 8, 16, 23);
+
+ if (flags & TCG_BSWAP_OS) {
+ tcg_out_ext16s(s, TCG_TYPE_REG, dst, tmp);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_REG, dst, tmp);
+ }
+}
+
+static const TCGOutOpBswap outop_bswap16 = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out_rr = tgen_bswap16,
+};
+
+static void tgen_bswap32(TCGContext *s, TCGType type,
+ TCGReg dst, TCGReg src, unsigned flags)
+{
+ TCGReg tmp = dst == src ? TCG_REG_R0 : dst;
+
+ if (have_isa_3_10) {
+ tcg_out32(s, BRW | RA(dst) | RS(src));
+ if (flags & TCG_BSWAP_OS) {
+ tcg_out_ext32s(s, dst, dst);
+ } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) {
+ tcg_out_ext32u(s, dst, dst);
}
- if (a0 != args[0]) {
- tcg_out_mov(s, TCG_TYPE_REG, args[0], a0);
+ return;
+ }
+
+ /*
+ * Stolen from gcc's builtin_bswap32.
+ * In the following,
+ * dep(a, b, m) -> (a & ~m) | (b & m)
+ *
+ * Begin with: src = xxxxabcd
+ */
+ /* tmp = rol32(src, 8) & 0xffffffff = 0000bcda */
+ tcg_out_rlw(s, RLWINM, tmp, src, 8, 0, 31);
+ /* tmp = dep(tmp, rol32(src, 24), 0xff000000) = 0000dcda */
+ tcg_out_rlw(s, RLWIMI, tmp, src, 24, 0, 7);
+ /* tmp = dep(tmp, rol32(src, 24), 0x0000ff00) = 0000dcba */
+ tcg_out_rlw(s, RLWIMI, tmp, src, 24, 16, 23);
+
+ if (flags & TCG_BSWAP_OS) {
+ tcg_out_ext32s(s, dst, tmp);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_REG, dst, tmp);
+ }
+}
+
+static const TCGOutOpBswap outop_bswap32 = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out_rr = tgen_bswap32,
+};
+
+#if TCG_TARGET_REG_BITS == 64
+static void tgen_bswap64(TCGContext *s, TCGType type, TCGReg dst, TCGReg src)
+{
+ TCGReg t0 = dst == src ? TCG_REG_R0 : dst;
+ TCGReg t1 = dst == src ? dst : TCG_REG_R0;
+
+ if (have_isa_3_10) {
+ tcg_out32(s, BRD | RA(dst) | RS(src));
+ return;
+ }
+
+ /*
+ * In the following,
+ * dep(a, b, m) -> (a & ~m) | (b & m)
+ *
+ * Begin with: src = abcdefgh
+ */
+ /* t0 = rol32(src, 8) & 0xffffffff = 0000fghe */
+ tcg_out_rlw(s, RLWINM, t0, src, 8, 0, 31);
+ /* t0 = dep(t0, rol32(src, 24), 0xff000000) = 0000hghe */
+ tcg_out_rlw(s, RLWIMI, t0, src, 24, 0, 7);
+ /* t0 = dep(t0, rol32(src, 24), 0x0000ff00) = 0000hgfe */
+ tcg_out_rlw(s, RLWIMI, t0, src, 24, 16, 23);
+
+ /* t0 = rol64(t0, 32) = hgfe0000 */
+ tcg_out_rld(s, RLDICL, t0, t0, 32, 0);
+ /* t1 = rol64(src, 32) = efghabcd */
+ tcg_out_rld(s, RLDICL, t1, src, 32, 0);
+
+ /* t0 = dep(t0, rol32(t1, 24), 0xffffffff) = hgfebcda */
+ tcg_out_rlw(s, RLWIMI, t0, t1, 8, 0, 31);
+ /* t0 = dep(t0, rol32(t1, 24), 0xff000000) = hgfedcda */
+ tcg_out_rlw(s, RLWIMI, t0, t1, 24, 0, 7);
+ /* t0 = dep(t0, rol32(t1, 24), 0x0000ff00) = hgfedcba */
+ tcg_out_rlw(s, RLWIMI, t0, t1, 24, 16, 23);
+
+ tcg_out_mov(s, TCG_TYPE_REG, dst, t0);
+}
+
+static const TCGOutOpUnary outop_bswap64 = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out_rr = tgen_bswap64,
+};
+#endif /* TCG_TARGET_REG_BITS == 64 */
+
+static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
+{
+ tcg_out32(s, NEG | RT(a0) | RA(a1));
+}
+
+static const TCGOutOpUnary outop_neg = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out_rr = tgen_neg,
+};
+
+static void tgen_not(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
+{
+ tgen_nor(s, type, a0, a1, a1);
+}
+
+static const TCGOutOpUnary outop_not = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out_rr = tgen_not,
+};
+
+static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
+ TCGReg a2, unsigned ofs, unsigned len)
+{
+ if (type == TCG_TYPE_I32) {
+ tcg_out_rlw(s, RLWIMI, a0, a2, ofs, 32 - ofs - len, 31 - ofs);
+ } else {
+ tcg_out_rld(s, RLDIMI, a0, a2, ofs, 64 - ofs - len);
+ }
+}
+
+static void tgen_depositi(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
+ tcg_target_long a2, unsigned ofs, unsigned len)
+{
+ tgen_andi(s, type, a0, a1, ~MAKE_64BIT_MASK(ofs, len));
+}
+
+static const TCGOutOpDeposit outop_deposit = {
+ .base.static_constraint = C_O1_I2(r, 0, rZ),
+ .out_rrr = tgen_deposit,
+ .out_rri = tgen_depositi,
+};
+
+static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
+ unsigned ofs, unsigned len)
+{
+ if (ofs == 0 && len <= 16) {
+ tgen_andi(s, TCG_TYPE_I32, a0, a1, (1 << len) - 1);
+ } else if (type == TCG_TYPE_I32) {
+ tcg_out_rlw(s, RLWINM, a0, a1, 32 - ofs, 32 - len, 31);
+ } else {
+ tcg_out_rld(s, RLDICL, a0, a1, 64 - ofs, 64 - len);
+ }
+}
+
+static const TCGOutOpExtract outop_extract = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out_rr = tgen_extract,
+};
+
+static void tgen_sextract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
+ unsigned ofs, unsigned len)
+{
+ if (ofs == 0) {
+ switch (len) {
+ case 8:
+ tcg_out_ext8s(s, type, a0, a1);
+ return;
+ case 16:
+ tcg_out_ext16s(s, type, a0, a1);
+ return;
+ case 32:
+ tcg_out_ext32s(s, a0, a1);
+ return;
}
- break;
+ } else if (ofs + len == 32) {
+ tcg_out_sari32(s, a0, a1, ofs);
+ return;
+ }
+ g_assert_not_reached();
+}
+
+static const TCGOutOpExtract outop_sextract = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out_rr = tgen_sextract,
+};
+
+static const TCGOutOpExtract2 outop_extract2 = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static void tgen_ld8u(TCGContext *s, TCGType type, TCGReg dest,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_mem_long(s, LBZ, LBZX, dest, base, offset);
+}
+
+static const TCGOutOpLoad outop_ld8u = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_ld8u,
+};
+
+static void tgen_ld8s(TCGContext *s, TCGType type, TCGReg dest,
+ TCGReg base, ptrdiff_t offset)
+{
+ tgen_ld8u(s, type, dest, base, offset);
+ tcg_out_ext8s(s, type, dest, dest);
+}
+
+static const TCGOutOpLoad outop_ld8s = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_ld8s,
+};
+
+static void tgen_ld16u(TCGContext *s, TCGType type, TCGReg dest,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_mem_long(s, LHZ, LHZX, dest, base, offset);
+}
+
+static const TCGOutOpLoad outop_ld16u = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_ld16u,
+};
+
+static void tgen_ld16s(TCGContext *s, TCGType type, TCGReg dest,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_mem_long(s, LHA, LHAX, dest, base, offset);
+}
+
+static const TCGOutOpLoad outop_ld16s = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_ld16s,
+};
#if TCG_TARGET_REG_BITS == 64
- case INDEX_op_sub2_i64:
-#else
- case INDEX_op_sub2_i32:
+static void tgen_ld32u(TCGContext *s, TCGType type, TCGReg dest,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_mem_long(s, LWZ, LWZX, dest, base, offset);
+}
+
+static const TCGOutOpLoad outop_ld32u = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_ld32u,
+};
+
+static void tgen_ld32s(TCGContext *s, TCGType type, TCGReg dest,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_mem_long(s, LWA, LWAX, dest, base, offset);
+}
+
+static const TCGOutOpLoad outop_ld32s = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_ld32s,
+};
#endif
- a0 = args[0], a1 = args[1];
- if (a0 == args[5] || (!const_args[3] && a0 == args[3])) {
- a0 = TCG_REG_R0;
- }
- if (const_args[2]) {
- tcg_out32(s, SUBFIC | TAI(a0, args[4], args[2]));
- } else {
- tcg_out32(s, SUBFC | TAB(a0, args[4], args[2]));
- }
- if (const_args[3]) {
- tcg_out32(s, (args[3] ? SUBFME : SUBFZE) | RT(a1) | RA(args[5]));
- } else {
- tcg_out32(s, SUBFE | TAB(a1, args[5], args[3]));
- }
- if (a0 != args[0]) {
- tcg_out_mov(s, TCG_TYPE_REG, args[0], a0);
- }
- break;
- case INDEX_op_muluh_i32:
- tcg_out32(s, MULHWU | TAB(args[0], args[1], args[2]));
- break;
- case INDEX_op_mulsh_i32:
- tcg_out32(s, MULHW | TAB(args[0], args[1], args[2]));
- break;
- case INDEX_op_muluh_i64:
- tcg_out32(s, MULHDU | TAB(args[0], args[1], args[2]));
- break;
- case INDEX_op_mulsh_i64:
- tcg_out32(s, MULHD | TAB(args[0], args[1], args[2]));
- break;
+static void tgen_st8(TCGContext *s, TCGType type, TCGReg data,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_mem_long(s, STB, STBX, data, base, offset);
+}
- case INDEX_op_mb:
- tcg_out_mb(s, args[0]);
- break;
+static const TCGOutOpStore outop_st8 = {
+ .base.static_constraint = C_O0_I2(r, r),
+ .out_r = tgen_st8,
+};
- case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
- case INDEX_op_mov_i64:
- case INDEX_op_call: /* Always emitted via tcg_out_call. */
- case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
- case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */
- case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */
- 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_extrl_i64_i32:
- default:
- g_assert_not_reached();
- }
+static void tgen_st16(TCGContext *s, TCGType type, TCGReg data,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_mem_long(s, STH, STHX, data, base, offset);
}
+static const TCGOutOpStore outop_st16 = {
+ .base.static_constraint = C_O0_I2(r, r),
+ .out_r = tgen_st16,
+};
+
+static const TCGOutOpStore outop_st = {
+ .base.static_constraint = C_O0_I2(r, r),
+ .out_r = tcg_out_st,
+};
+
+
int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
{
switch (opc) {
@@ -4098,154 +4435,11 @@ static TCGConstraintSetIndex
tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
{
switch (op) {
- case INDEX_op_goto_ptr:
- return C_O0_I1(r);
-
- case INDEX_op_ld8u_i32:
- case INDEX_op_ld8s_i32:
- case INDEX_op_ld16u_i32:
- case INDEX_op_ld16s_i32:
- case INDEX_op_ld_i32:
- case INDEX_op_ctpop_i32:
- case INDEX_op_neg_i32:
- case INDEX_op_not_i32:
- case INDEX_op_ext8s_i32:
- case INDEX_op_ext16s_i32:
- case INDEX_op_bswap16_i32:
- case INDEX_op_bswap32_i32:
- case INDEX_op_extract_i32:
- case INDEX_op_sextract_i32:
- case INDEX_op_ld8u_i64:
- case INDEX_op_ld8s_i64:
- case INDEX_op_ld16u_i64:
- case INDEX_op_ld16s_i64:
- case INDEX_op_ld32u_i64:
- case INDEX_op_ld32s_i64:
- case INDEX_op_ld_i64:
- case INDEX_op_ctpop_i64:
- case INDEX_op_neg_i64:
- case INDEX_op_not_i64:
- case INDEX_op_ext8s_i64:
- case INDEX_op_ext16s_i64:
- case INDEX_op_ext32s_i64:
- case INDEX_op_ext_i32_i64:
- case INDEX_op_extu_i32_i64:
- case INDEX_op_bswap16_i64:
- case INDEX_op_bswap32_i64:
- case INDEX_op_bswap64_i64:
- case INDEX_op_extract_i64:
- case INDEX_op_sextract_i64:
- return C_O1_I1(r, r);
-
- case INDEX_op_st8_i32:
- case INDEX_op_st16_i32:
- case INDEX_op_st_i32:
- case INDEX_op_st8_i64:
- case INDEX_op_st16_i64:
- case INDEX_op_st32_i64:
- case INDEX_op_st_i64:
+ case INDEX_op_qemu_st:
return C_O0_I2(r, r);
-
- case INDEX_op_add_i32:
- case INDEX_op_and_i32:
- case INDEX_op_or_i32:
- case INDEX_op_xor_i32:
- case INDEX_op_andc_i32:
- case INDEX_op_orc_i32:
- case INDEX_op_eqv_i32:
- case INDEX_op_shl_i32:
- case INDEX_op_shr_i32:
- case INDEX_op_sar_i32:
- case INDEX_op_rotl_i32:
- case INDEX_op_rotr_i32:
- case INDEX_op_and_i64:
- case INDEX_op_andc_i64:
- case INDEX_op_shl_i64:
- case INDEX_op_shr_i64:
- case INDEX_op_sar_i64:
- case INDEX_op_rotl_i64:
- case INDEX_op_rotr_i64:
- return C_O1_I2(r, r, ri);
-
- case INDEX_op_mul_i32:
- case INDEX_op_mul_i64:
- return C_O1_I2(r, r, rI);
-
- case INDEX_op_div_i32:
- case INDEX_op_divu_i32:
- case INDEX_op_rem_i32:
- case INDEX_op_remu_i32:
- case INDEX_op_nand_i32:
- case INDEX_op_nor_i32:
- case INDEX_op_muluh_i32:
- case INDEX_op_mulsh_i32:
- case INDEX_op_orc_i64:
- case INDEX_op_eqv_i64:
- case INDEX_op_nand_i64:
- case INDEX_op_nor_i64:
- case INDEX_op_div_i64:
- case INDEX_op_divu_i64:
- case INDEX_op_rem_i64:
- case INDEX_op_remu_i64:
- case INDEX_op_mulsh_i64:
- case INDEX_op_muluh_i64:
- return C_O1_I2(r, r, r);
-
- case INDEX_op_sub_i32:
- return C_O1_I2(r, rI, ri);
- case INDEX_op_add_i64:
- return C_O1_I2(r, r, rT);
- case INDEX_op_or_i64:
- case INDEX_op_xor_i64:
- return C_O1_I2(r, r, rU);
- case INDEX_op_sub_i64:
- return C_O1_I2(r, rI, rT);
- case INDEX_op_clz_i32:
- case INDEX_op_ctz_i32:
- case INDEX_op_clz_i64:
- case INDEX_op_ctz_i64:
- return C_O1_I2(r, r, rZW);
-
- case INDEX_op_brcond_i32:
- case INDEX_op_brcond_i64:
- return C_O0_I2(r, rC);
- case INDEX_op_setcond_i32:
- case INDEX_op_setcond_i64:
- case INDEX_op_negsetcond_i32:
- case INDEX_op_negsetcond_i64:
- return C_O1_I2(r, r, rC);
- case INDEX_op_movcond_i32:
- case INDEX_op_movcond_i64:
- return C_O1_I4(r, r, rC, rZ, rZ);
-
- case INDEX_op_deposit_i32:
- case INDEX_op_deposit_i64:
- return C_O1_I2(r, 0, rZ);
- case INDEX_op_brcond2_i32:
- return C_O0_I4(r, r, ri, ri);
- case INDEX_op_setcond2_i32:
- return C_O1_I4(r, r, r, ri, ri);
- case INDEX_op_add2_i64:
- case INDEX_op_add2_i32:
- return C_O2_I4(r, r, r, r, rI, rZM);
- case INDEX_op_sub2_i64:
- case INDEX_op_sub2_i32:
- return C_O2_I4(r, r, rI, rZM, r, r);
-
- case INDEX_op_qemu_ld_i32:
- return C_O1_I1(r, r);
- case INDEX_op_qemu_ld_i64:
- return TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, r) : C_O2_I1(r, r, r);
-
- case INDEX_op_qemu_st_i32:
- return C_O0_I2(r, r);
- case INDEX_op_qemu_st_i64:
- return TCG_TARGET_REG_BITS == 64 ? C_O0_I2(r, r) : C_O0_I3(r, r, r);
-
- case INDEX_op_qemu_ld_i128:
- return C_N1O1_I1(o, m, r);
- case INDEX_op_qemu_st_i128:
- return C_O0_I3(o, m, r);
+ case INDEX_op_qemu_st2:
+ return TCG_TARGET_REG_BITS == 64
+ ? C_O0_I3(o, m, r) : C_O0_I3(r, r, r);
case INDEX_op_add_vec:
case INDEX_op_sub_vec: