@@ -16391,6 +16391,63 @@ expand_vselect_vconcat (rtx target, rtx op0, rtx op1,
return expand_vselect (target, x, perm, nelt);
}
+/* Recognize patterns for even-odd extraction. */
+
+static bool
+mips_expand_vpc_loongson_even_odd (struct expand_vec_perm_d *d)
+{
+ unsigned i, odd, nelt = d->nelt;
+ rtx t0, t1, t2, t3;
+
+ if (!(TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS))
+ return false;
+ /* Even-odd for V2SI/V2SFmode is matched by interleave directly. */
+ if (nelt < 4)
+ return false;
+
+ odd = d->perm[0];
+ if (odd > 1)
+ return false;
+ for (i = 1; i < nelt; ++i)
+ if (d->perm[i] != i * 2 + odd)
+ return false;
+
+ if (d->testing_p)
+ return true;
+
+ /* We need 2*log2(N)-1 operations to achieve odd/even with interleave. */
+ t0 = gen_reg_rtx (d->vmode);
+ t1 = gen_reg_rtx (d->vmode);
+ switch (d->vmode)
+ {
+ case V4HImode:
+ emit_insn (gen_loongson_punpckhhw (t0, d->op0, d->op1));
+ emit_insn (gen_loongson_punpcklhw (t1, d->op0, d->op1));
+ if (odd)
+ emit_insn (gen_loongson_punpckhhw (d->target, t1, t0));
+ else
+ emit_insn (gen_loongson_punpcklhw (d->target, t1, t0));
+ break;
+
+ case V8QImode:
+ t2 = gen_reg_rtx (d->vmode);
+ t3 = gen_reg_rtx (d->vmode);
+ emit_insn (gen_loongson_punpckhbh (t0, d->op0, d->op1));
+ emit_insn (gen_loongson_punpcklbh (t1, d->op0, d->op1));
+ emit_insn (gen_loongson_punpckhbh (t2, t1, t0));
+ emit_insn (gen_loongson_punpcklbh (t3, t1, t0));
+ if (odd)
+ emit_insn (gen_loongson_punpckhbh (d->target, t3, t2));
+ else
+ emit_insn (gen_loongson_punpcklbh (d->target, t3, t2));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ return true;
+}
+
/* Recognize patterns for the Loongson PSHUFH instruction. */
static bool
@@ -16445,6 +16502,8 @@ mips_expand_vec_perm_const_1 (struct expand_vec_perm_d *d)
return true;
}
+ if (mips_expand_vpc_loongson_even_odd (d))
+ return true;
if (mips_expand_vpc_loongson_pshufh (d))
return true;
return false;