aboutsummaryrefslogtreecommitdiff
path: root/tcg/ppc/tcg-target.c.inc
diff options
context:
space:
mode:
Diffstat (limited to 'tcg/ppc/tcg-target.c.inc')
-rw-r--r--tcg/ppc/tcg-target.c.inc254
1 files changed, 165 insertions, 89 deletions
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
index 3553a47ba9..3f413ce3c1 100644
--- a/tcg/ppc/tcg-target.c.inc
+++ b/tcg/ppc/tcg-target.c.inc
@@ -3567,12 +3567,14 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
case INDEX_op_usadd_vec:
case INDEX_op_ussub_vec:
return vece <= MO_32;
- case INDEX_op_cmp_vec:
case INDEX_op_shli_vec:
case INDEX_op_shri_vec:
case INDEX_op_sari_vec:
case INDEX_op_rotli_vec:
return vece <= MO_32 || have_isa_2_07 ? -1 : 0;
+ case INDEX_op_cmp_vec:
+ case INDEX_op_cmpsel_vec:
+ return vece <= MO_32 || have_isa_2_07 ? 1 : 0;
case INDEX_op_neg_vec:
return vece >= MO_32 && have_isa_3_00;
case INDEX_op_mul_vec:
@@ -3713,6 +3715,149 @@ static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
return true;
}
+static void tcg_out_not_vec(TCGContext *s, TCGReg a0, TCGReg a1)
+{
+ tcg_out32(s, VNOR | VRT(a0) | VRA(a1) | VRB(a1));
+}
+
+static void tcg_out_or_vec(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, VOR | VRT(a0) | VRA(a1) | VRB(a2));
+}
+
+static void tcg_out_orc_vec(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, VORC | VRT(a0) | VRA(a1) | VRB(a2));
+}
+
+static void tcg_out_and_vec(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, VAND | VRT(a0) | VRA(a1) | VRB(a2));
+}
+
+static void tcg_out_andc_vec(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, VANDC | VRT(a0) | VRA(a1) | VRB(a2));
+}
+
+static void tcg_out_bitsel_vec(TCGContext *s, TCGReg d,
+ TCGReg c, TCGReg t, TCGReg f)
+{
+ if (TCG_TARGET_HAS_bitsel_vec) {
+ tcg_out32(s, XXSEL | VRT(d) | VRC(c) | VRB(t) | VRA(f));
+ } else {
+ tcg_out_and_vec(s, TCG_VEC_TMP2, t, c);
+ tcg_out_andc_vec(s, d, f, c);
+ tcg_out_or_vec(s, d, d, TCG_VEC_TMP2);
+ }
+}
+
+static bool tcg_out_cmp_vec_noinv(TCGContext *s, unsigned vece, TCGReg a0,
+ TCGReg a1, TCGReg a2, TCGCond cond)
+{
+ static const uint32_t
+ eq_op[4] = { VCMPEQUB, VCMPEQUH, VCMPEQUW, VCMPEQUD },
+ ne_op[4] = { VCMPNEB, VCMPNEH, VCMPNEW, 0 },
+ gts_op[4] = { VCMPGTSB, VCMPGTSH, VCMPGTSW, VCMPGTSD },
+ gtu_op[4] = { VCMPGTUB, VCMPGTUH, VCMPGTUW, VCMPGTUD };
+ uint32_t insn;
+
+ bool need_swap = false, need_inv = false;
+
+ tcg_debug_assert(vece <= MO_32 || have_isa_2_07);
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ case TCG_COND_GT:
+ case TCG_COND_GTU:
+ break;
+ case TCG_COND_NE:
+ if (have_isa_3_00 && vece <= MO_32) {
+ break;
+ }
+ /* fall through */
+ case TCG_COND_LE:
+ case TCG_COND_LEU:
+ need_inv = true;
+ break;
+ case TCG_COND_LT:
+ case TCG_COND_LTU:
+ need_swap = true;
+ break;
+ case TCG_COND_GE:
+ case TCG_COND_GEU:
+ need_swap = need_inv = true;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (need_inv) {
+ cond = tcg_invert_cond(cond);
+ }
+ if (need_swap) {
+ TCGReg swap = a1;
+ a1 = a2;
+ a2 = swap;
+ cond = tcg_swap_cond(cond);
+ }
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ insn = eq_op[vece];
+ break;
+ case TCG_COND_NE:
+ insn = ne_op[vece];
+ break;
+ case TCG_COND_GT:
+ insn = gts_op[vece];
+ break;
+ case TCG_COND_GTU:
+ insn = gtu_op[vece];
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ tcg_out32(s, insn | VRT(a0) | VRA(a1) | VRB(a2));
+
+ return need_inv;
+}
+
+static void tcg_out_cmp_vec(TCGContext *s, unsigned vece, TCGReg a0,
+ TCGReg a1, TCGReg a2, TCGCond cond)
+{
+ if (tcg_out_cmp_vec_noinv(s, vece, a0, a1, a2, cond)) {
+ tcg_out_not_vec(s, a0, a0);
+ }
+}
+
+static void tcg_out_cmpsel_vec(TCGContext *s, unsigned vece, TCGReg a0,
+ TCGReg c1, TCGReg c2, TCGArg v3, int const_v3,
+ TCGReg v4, TCGCond cond)
+{
+ bool inv = tcg_out_cmp_vec_noinv(s, vece, TCG_VEC_TMP1, c1, c2, cond);
+
+ if (!const_v3) {
+ if (inv) {
+ tcg_out_bitsel_vec(s, a0, TCG_VEC_TMP1, v4, v3);
+ } else {
+ tcg_out_bitsel_vec(s, a0, TCG_VEC_TMP1, v3, v4);
+ }
+ } else if (v3) {
+ if (inv) {
+ tcg_out_orc_vec(s, a0, v4, TCG_VEC_TMP1);
+ } else {
+ tcg_out_or_vec(s, a0, v4, TCG_VEC_TMP1);
+ }
+ } else {
+ if (inv) {
+ tcg_out_and_vec(s, a0, v4, TCG_VEC_TMP1);
+ } else {
+ tcg_out_andc_vec(s, a0, v4, TCG_VEC_TMP1);
+ }
+ }
+}
+
static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
unsigned vecl, unsigned vece,
const TCGArg args[TCG_MAX_OP_ARGS],
@@ -3723,10 +3868,6 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
sub_op[4] = { VSUBUBM, VSUBUHM, VSUBUWM, VSUBUDM },
mul_op[4] = { 0, 0, VMULUWM, VMULLD },
neg_op[4] = { 0, 0, VNEGW, VNEGD },
- eq_op[4] = { VCMPEQUB, VCMPEQUH, VCMPEQUW, VCMPEQUD },
- ne_op[4] = { VCMPNEB, VCMPNEH, VCMPNEW, 0 },
- gts_op[4] = { VCMPGTSB, VCMPGTSH, VCMPGTSW, VCMPGTSD },
- gtu_op[4] = { VCMPGTUB, VCMPGTUH, VCMPGTUW, VCMPGTUD },
ssadd_op[4] = { VADDSBS, VADDSHS, VADDSWS, 0 },
usadd_op[4] = { VADDUBS, VADDUHS, VADDUWS, 0 },
sssub_op[4] = { VSUBSBS, VSUBSHS, VSUBSWS, 0 },
@@ -3808,24 +3949,23 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
insn = sarv_op[vece];
break;
case INDEX_op_and_vec:
- insn = VAND;
- break;
+ tcg_out_and_vec(s, a0, a1, a2);
+ return;
case INDEX_op_or_vec:
- insn = VOR;
- break;
+ tcg_out_or_vec(s, a0, a1, a2);
+ return;
case INDEX_op_xor_vec:
insn = VXOR;
break;
case INDEX_op_andc_vec:
- insn = VANDC;
- break;
+ tcg_out_andc_vec(s, a0, a1, a2);
+ return;
case INDEX_op_not_vec:
- insn = VNOR;
- a2 = a1;
- break;
+ tcg_out_not_vec(s, a0, a1);
+ return;
case INDEX_op_orc_vec:
- insn = VORC;
- break;
+ tcg_out_orc_vec(s, a0, a1, a2);
+ return;
case INDEX_op_nand_vec:
insn = VNAND;
break;
@@ -3837,26 +3977,14 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
break;
case INDEX_op_cmp_vec:
- switch (args[3]) {
- case TCG_COND_EQ:
- insn = eq_op[vece];
- break;
- case TCG_COND_NE:
- insn = ne_op[vece];
- break;
- case TCG_COND_GT:
- insn = gts_op[vece];
- break;
- case TCG_COND_GTU:
- insn = gtu_op[vece];
- break;
- default:
- g_assert_not_reached();
- }
- break;
-
+ tcg_out_cmp_vec(s, vece, a0, a1, a2, args[3]);
+ return;
+ case INDEX_op_cmpsel_vec:
+ tcg_out_cmpsel_vec(s, vece, a0, a1, a2,
+ args[3], const_args[3], args[4], args[5]);
+ return;
case INDEX_op_bitsel_vec:
- tcg_out32(s, XXSEL | VRT(a0) | VRC(a1) | VRB(a2) | VRA(args[3]));
+ tcg_out_bitsel_vec(s, a0, a1, a2, args[3]);
return;
case INDEX_op_dup2_vec:
@@ -3921,56 +4049,6 @@ static void expand_vec_shi(TCGType type, unsigned vece, TCGv_vec v0,
tcgv_vec_arg(v1), tcgv_vec_arg(t1));
}
-static void expand_vec_cmp(TCGType type, unsigned vece, TCGv_vec v0,
- TCGv_vec v1, TCGv_vec v2, TCGCond cond)
-{
- bool need_swap = false, need_inv = false;
-
- tcg_debug_assert(vece <= MO_32 || have_isa_2_07);
-
- switch (cond) {
- case TCG_COND_EQ:
- case TCG_COND_GT:
- case TCG_COND_GTU:
- break;
- case TCG_COND_NE:
- if (have_isa_3_00 && vece <= MO_32) {
- break;
- }
- /* fall through */
- case TCG_COND_LE:
- case TCG_COND_LEU:
- need_inv = true;
- break;
- case TCG_COND_LT:
- case TCG_COND_LTU:
- need_swap = true;
- break;
- case TCG_COND_GE:
- case TCG_COND_GEU:
- need_swap = need_inv = true;
- break;
- default:
- g_assert_not_reached();
- }
-
- if (need_inv) {
- cond = tcg_invert_cond(cond);
- }
- if (need_swap) {
- TCGv_vec t1;
- t1 = v1, v1 = v2, v2 = t1;
- cond = tcg_swap_cond(cond);
- }
-
- vec_gen_4(INDEX_op_cmp_vec, type, vece, tcgv_vec_arg(v0),
- tcgv_vec_arg(v1), tcgv_vec_arg(v2), cond);
-
- if (need_inv) {
- tcg_gen_not_vec(vece, v0, v0);
- }
-}
-
static void expand_vec_mul(TCGType type, unsigned vece, TCGv_vec v0,
TCGv_vec v1, TCGv_vec v2)
{
@@ -4045,10 +4123,6 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
case INDEX_op_rotli_vec:
expand_vec_shi(type, vece, v0, v1, a2, INDEX_op_rotlv_vec);
break;
- case INDEX_op_cmp_vec:
- v2 = temp_tcgv_vec(arg_temp(a2));
- expand_vec_cmp(type, vece, v0, v1, v2, va_arg(va, TCGArg));
- break;
case INDEX_op_mul_vec:
v2 = temp_tcgv_vec(arg_temp(a2));
expand_vec_mul(type, vece, v0, v1, v2);
@@ -4276,6 +4350,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_bitsel_vec:
case INDEX_op_ppc_msum_vec:
return C_O1_I3(v, v, v, v);
+ case INDEX_op_cmpsel_vec:
+ return C_O1_I4(v, v, v, vZM, v);
default:
g_assert_not_reached();