@@ -643,6 +643,42 @@
FAIL;
})
+(define_expand "vec_unpacks_lo_<mode>"
+ [(match_operand:<V_stretch_half> 0 "register_operand" "")
+ (match_operand:VHB 1 "register_operand" "")]
+ "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
+{
+ mips_expand_vec_unpack (operands, false, false);
+ DONE;
+})
+
+(define_expand "vec_unpacks_hi_<mode>"
+ [(match_operand:<V_stretch_half> 0 "register_operand" "")
+ (match_operand:VHB 1 "register_operand" "")]
+ "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
+{
+ mips_expand_vec_unpack (operands, false, true);
+ DONE;
+})
+
+(define_expand "vec_unpacku_lo_<mode>"
+ [(match_operand:<V_stretch_half> 0 "register_operand" "")
+ (match_operand:VHB 1 "register_operand" "")]
+ "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
+{
+ mips_expand_vec_unpack (operands, true, false);
+ DONE;
+})
+
+(define_expand "vec_unpacku_hi_<mode>"
+ [(match_operand:<V_stretch_half> 0 "register_operand" "")
+ (match_operand:VHB 1 "register_operand" "")]
+ "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
+{
+ mips_expand_vec_unpack (operands, true, true);
+ DONE;
+})
+
;; Integer division and modulus. For integer multiplication, see mips.md.
(define_insn "<u>div<mode>3"
@@ -329,6 +329,7 @@ extern void mips_expand_atomic_qihi (union mips_gen_fn_ptrs,
extern void mips_expand_vector_init (rtx, rtx);
extern bool mips_expand_vec_perm_const (rtx op[4]);
+extern void mips_expand_vec_unpack (rtx op[2], bool, bool);
extern bool mips_eh_uses (unsigned int);
extern bool mips_epilogue_uses (unsigned int);
@@ -16611,6 +16611,51 @@ mips_vectorize_vec_perm_const_ok (enum machine_mode vmode,
return ret;
}
+
+/* Expand an integral vector unpack operation. */
+
+void
+mips_expand_vec_unpack (rtx operands[2], bool unsigned_p, bool high_p)
+{
+ enum machine_mode imode = GET_MODE (operands[1]);
+ rtx (*unpack) (rtx, rtx, rtx);
+ rtx (*cmpgt) (rtx, rtx, rtx);
+ rtx tmp, dest, zero;
+
+ switch (imode)
+ {
+ case V8QImode:
+ if (high_p)
+ unpack = gen_loongson_punpckhbh;
+ else
+ unpack = gen_loongson_punpcklbh;
+ cmpgt = gen_loongson_pcmpgtb;
+ break;
+ case V4HImode:
+ if (high_p)
+ unpack = gen_loongson_punpckhhw;
+ else
+ unpack = gen_loongson_punpcklhw;
+ cmpgt = gen_loongson_pcmpgth;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ zero = force_reg (imode, CONST0_RTX (imode));
+ if (unsigned_p)
+ tmp = zero;
+ else
+ {
+ tmp = gen_reg_rtx (imode);
+ emit_insn (cmpgt (tmp, zero, operands[1]));
+ }
+
+ dest = gen_reg_rtx (imode);
+ emit_insn (unpack (dest, operands[1], tmp));
+
+ emit_move_insn (operands[0], gen_lowpart (GET_MODE (operands[0]), dest));
+}
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP