public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-4447] RISC-V: Add duplicate vector support.
@ 2022-12-01 16:14 Kito Cheng
  0 siblings, 0 replies; only message in thread
From: Kito Cheng @ 2022-12-01 16:14 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:fa144175c9ccaa10d7021d00f97aaa9eac59afec

commit r13-4447-gfa144175c9ccaa10d7021d00f97aaa9eac59afec
Author: Ju-Zhe Zhong <juzhe.zhong@rivai.ai>
Date:   Sat Nov 26 00:06:39 2022 +0800

    RISC-V: Add duplicate vector support.
    
    gcc/ChangeLog:
    
            * config/riscv/constraints.md (Wdm): New constraint.
            * config/riscv/predicates.md (direct_broadcast_operand): New predicate.
            * config/riscv/riscv-protos.h (RVV_VLMAX): New macro.
            (emit_pred_op): Refine function.
            * config/riscv/riscv-selftests.cc (run_const_vector_selftests): New function.
            (run_broadcast_selftests): Ditto.
            (BROADCAST_TEST): New tests.
            (riscv_run_selftests): More tests.
            * config/riscv/riscv-v.cc (emit_pred_move): Refine function.
            (emit_vlmax_vsetvl): Ditto.
            (emit_pred_op): Ditto.
            (expand_const_vector): New function.
            (legitimize_move): Add constant vector support.
            * config/riscv/riscv.cc (riscv_print_operand): New asm print rule for const vector.
            * config/riscv/riscv.h (X0_REGNUM): New macro.
            * config/riscv/vector-iterators.md: New attribute.
            * config/riscv/vector.md (vec_duplicate<mode>): New pattern.
            (@pred_broadcast<mode>): New pattern.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/riscv/rvv/base/dup-1.c: New test.
            * gcc.target/riscv/rvv/base/dup-2.c: New test.

Diff:
---
 gcc/config/riscv/constraints.md                 |   5 +
 gcc/config/riscv/predicates.md                  |   5 +
 gcc/config/riscv/riscv-protos.h                 |   2 +
 gcc/config/riscv/riscv-selftests.cc             | 127 ++++++
 gcc/config/riscv/riscv-v.cc                     |  86 +++-
 gcc/config/riscv/riscv.cc                       |  13 +
 gcc/config/riscv/riscv.h                        |   3 +
 gcc/config/riscv/vector-iterators.md            |   9 +
 gcc/config/riscv/vector.md                      |  53 ++-
 gcc/testsuite/gcc.target/riscv/rvv/base/dup-1.c | 521 ++++++++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/rvv/base/dup-2.c |  75 ++++
 11 files changed, 881 insertions(+), 18 deletions(-)

diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index 4088c48150a..51cffb2bcb6 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -151,3 +151,8 @@
  A constraint that matches a vector of immediate all ones."
  (and (match_code "const_vector")
       (match_test "op == CONSTM1_RTX (GET_MODE (op))")))
+
+(define_constraint "Wdm"
+  "Vector duplicate memory operand"
+  (and (match_operand 0 "memory_operand")
+       (match_code "reg" "0")))
diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index dfd98761b8b..5a5a49bf7c0 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -286,6 +286,11 @@
 	    (match_test "GET_CODE (op) == UNSPEC
 			 && (XINT (op, 1) == UNSPEC_VUNDEF)"))))
 
+;; The scalar operand can be directly broadcast by RVV instructions.
+(define_predicate "direct_broadcast_operand"
+  (ior (match_operand 0 "register_operand")
+       (match_test "satisfies_constraint_Wdm (op)")))
+
 ;; A CONST_INT operand that has exactly two bits cleared.
 (define_predicate "const_nottwobits_operand"
   (and (match_code "const_int")
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 2ec3af05aa4..27692ffb210 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -119,6 +119,7 @@ extern void riscv_run_selftests (void);
 #endif
 
 namespace riscv_vector {
+#define RVV_VLMAX gen_rtx_REG (Pmode, X0_REGNUM)
 /* Routines implemented in riscv-vector-builtins.cc.  */
 extern void init_builtins (void);
 extern const char *mangle_builtin_type (const_tree);
@@ -130,6 +131,7 @@ extern tree builtin_decl (unsigned, bool);
 extern rtx expand_builtin (unsigned int, tree, rtx);
 extern bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
 extern bool legitimize_move (rtx, rtx, machine_mode);
+extern void emit_pred_op (unsigned, rtx, rtx, machine_mode);
 enum tail_policy
 {
   TAIL_UNDISTURBED = 0,
diff --git a/gcc/config/riscv/riscv-selftests.cc b/gcc/config/riscv/riscv-selftests.cc
index 636874ebc0f..1bf1a648fa1 100644
--- a/gcc/config/riscv/riscv-selftests.cc
+++ b/gcc/config/riscv/riscv-selftests.cc
@@ -33,6 +33,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "expr.h"
 #include "selftest.h"
 #include "selftest-rtl.h"
+#include "insn-attr.h"
+#include "target.h"
+#include "optabs.h"
 
 #if CHECKING_P
 using namespace selftest;
@@ -230,12 +233,136 @@ run_poly_int_selftests (void)
   run_poly_int_selftest ("rv32imafd_zve32x1p0", ABI_ILP32D, POLY_TEST_DIMODE,
 			 worklist);
 }
+
+static void
+run_const_vector_selftests (void)
+{
+  /* We dont't need to do the redundant tests in different march && mabi.
+     Just pick up the march && mabi which fully support all RVV modes.  */
+  riscv_selftest_arch_abi_setter rv ("rv64imafdcv", ABI_LP64D);
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl"));
+  set_new_first_and_last_insn (NULL, NULL);
+
+  machine_mode mode;
+  std::vector<HOST_WIDE_INT> worklist = {-111, -17, -16, 7, 15, 16, 111};
+
+  FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_INT)
+    {
+      if (riscv_v_ext_vector_mode_p (mode))
+	{
+	  for (const HOST_WIDE_INT &val : worklist)
+	    {
+	      start_sequence ();
+	      rtx dest = gen_reg_rtx (mode);
+	      rtx dup = gen_const_vec_duplicate (mode, GEN_INT (val));
+	      emit_move_insn (dest, dup);
+	      rtx_insn *insn = get_last_insn ();
+	      rtx src = XEXP (SET_SRC (PATTERN (insn)), 1);
+	      /* 1. Should be vmv.v.i for in rang of -16 ~ 15.
+		 2. Should be vmv.v.x for exceed -16 ~ 15.  */
+	      if (IN_RANGE (val, -16, 15))
+		ASSERT_TRUE (rtx_equal_p (src, dup));
+	      else
+		ASSERT_TRUE (
+		  rtx_equal_p (src,
+			       gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0))));
+	      end_sequence ();
+	    }
+	}
+    }
+
+  FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_FLOAT)
+    {
+      if (riscv_v_ext_vector_mode_p (mode))
+	{
+	  scalar_mode inner_mode = GET_MODE_INNER (mode);
+	  REAL_VALUE_TYPE f = REAL_VALUE_ATOF ("0.2928932", inner_mode);
+	  rtx ele = const_double_from_real_value (f, inner_mode);
+
+	  start_sequence ();
+	  rtx dest = gen_reg_rtx (mode);
+	  rtx dup = gen_const_vec_duplicate (mode, ele);
+	  emit_move_insn (dest, dup);
+	  rtx_insn *insn = get_last_insn ();
+	  rtx src = XEXP (SET_SRC (PATTERN (insn)), 1);
+	  /* Should always be vfmv.v.f.  */
+	  ASSERT_TRUE (
+	    rtx_equal_p (src, gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0))));
+	  end_sequence ();
+	}
+    }
+
+  FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_BOOL)
+    {
+      /* Test vmset.m.  */
+      if (riscv_v_ext_vector_mode_p (mode))
+	{
+	  start_sequence ();
+	  rtx dest = gen_reg_rtx (mode);
+	  emit_move_insn (dest, CONSTM1_RTX (mode));
+	  rtx_insn *insn = get_last_insn ();
+	  rtx src = XEXP (SET_SRC (PATTERN (insn)), 1);
+	  ASSERT_TRUE (rtx_equal_p (src, CONSTM1_RTX (mode)));
+	  end_sequence ();
+	}
+    }
+}
+
+static void
+run_broadcast_selftests (void)
+{
+  /* We dont't need to do the redundant tests in different march && mabi.
+     Just pick up the march && mabi which fully support all RVV modes.  */
+  riscv_selftest_arch_abi_setter rv ("rv64imafdcv", ABI_LP64D);
+  rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl"));
+  set_new_first_and_last_insn (NULL, NULL);
+
+  machine_mode mode;
+
+#define BROADCAST_TEST(MODE_CLASS)                                             \
+  FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_INT)                               \
+    {                                                                          \
+      if (riscv_v_ext_vector_mode_p (mode))                                    \
+	{                                                                      \
+	  rtx_insn *insn;                                                      \
+	  rtx src;                                                             \
+	  scalar_mode inner_mode = GET_MODE_INNER (mode);                      \
+	  /* Test vlse.v with zero stride.  */                                 \
+	  start_sequence ();                                                   \
+	  rtx addr = gen_reg_rtx (Pmode);                                      \
+	  rtx mem = gen_rtx_MEM (inner_mode, addr);                            \
+	  expand_vector_broadcast (mode, mem);                                 \
+	  insn = get_last_insn ();                                             \
+	  src = XEXP (SET_SRC (PATTERN (insn)), 1);                            \
+	  ASSERT_TRUE (MEM_P (XEXP (src, 0)));                                 \
+	  ASSERT_TRUE (                                                        \
+	    rtx_equal_p (src, gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0))));   \
+	  end_sequence ();                                                     \
+	  /* Test vmv.v.x or vfmv.v.f.  */                                     \
+	  start_sequence ();                                                   \
+	  rtx reg = gen_reg_rtx (inner_mode);                                  \
+	  expand_vector_broadcast (mode, reg);                                 \
+	  insn = get_last_insn ();                                             \
+	  src = XEXP (SET_SRC (PATTERN (insn)), 1);                            \
+	  ASSERT_TRUE (REG_P (XEXP (src, 0)));                                 \
+	  ASSERT_TRUE (                                                        \
+	    rtx_equal_p (src, gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0))));   \
+	  end_sequence ();                                                     \
+	}                                                                      \
+    }
+
+  BROADCAST_TEST (MODE_VECTOR_INT)
+  BROADCAST_TEST (MODE_VECTOR_FLOAT)
+}
+
 namespace selftest {
 /* Run all target-specific selftests.  */
 void
 riscv_run_selftests (void)
 {
   run_poly_int_selftests ();
+  run_const_vector_selftests ();
+  run_broadcast_selftests ();
 }
 } // namespace selftest
 #endif /* #if CHECKING_P */
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index e0459e3f610..fbd8bbfe254 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -40,6 +40,7 @@
 #include "target.h"
 #include "expr.h"
 #include "optabs.h"
+#include "tm-constrs.h"
 
 using namespace riscv_vector;
 
@@ -104,34 +105,80 @@ const_vec_all_same_in_range_p (rtx x, HOST_WIDE_INT minval,
 	  && IN_RANGE (INTVAL (elt), minval, maxval));
 }
 
-/* Emit an RVV unmask && vl mov from SRC to DEST.  */
-static void
-emit_pred_move (rtx dest, rtx src, machine_mode mask_mode)
+static rtx
+emit_vlmax_vsetvl (machine_mode vmode)
 {
-  insn_expander<7> e;
-  machine_mode mode = GET_MODE (dest);
   rtx vl = gen_reg_rtx (Pmode);
-  unsigned int sew = GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL
+  unsigned int sew = GET_MODE_CLASS (vmode) == MODE_VECTOR_BOOL
 		       ? 8
-		       : GET_MODE_BITSIZE (GET_MODE_INNER (mode));
+		       : GET_MODE_BITSIZE (GET_MODE_INNER (vmode));
 
-  emit_insn (gen_vsetvl_no_side_effects (
-    Pmode, vl, gen_rtx_REG (Pmode, 0), gen_int_mode (sew, Pmode),
-    gen_int_mode ((unsigned int) mode, Pmode), const1_rtx, const1_rtx));
+  emit_insn (
+    gen_vsetvl_no_side_effects (Pmode, vl, RVV_VLMAX, gen_int_mode (sew, Pmode),
+				gen_int_mode ((unsigned int) vmode, Pmode),
+				const1_rtx, const1_rtx));
+  return vl;
+}
+
+/* Emit an RVV unmask && vl mov from SRC to DEST.  */
+void
+emit_pred_op (unsigned icode, rtx dest, rtx src, machine_mode mask_mode)
+{
+  insn_expander<7> e;
+  machine_mode mode = GET_MODE (dest);
 
   e.add_output_operand (dest, mode);
   e.add_all_one_mask_operand (mask_mode);
   e.add_vundef_operand (mode);
 
-  e.add_input_operand (src, mode);
+  e.add_input_operand (src, GET_MODE (src));
 
-  e.add_input_operand (vl, Pmode);
+  rtx vlmax = emit_vlmax_vsetvl (mode);
+  e.add_input_operand (vlmax, Pmode);
 
   e.add_policy_operand (TAIL_AGNOSTIC, MASK_AGNOSTIC);
 
-  enum insn_code icode;
-  icode = code_for_pred_mov (mode);
-  e.expand (icode, true);
+  e.expand ((enum insn_code) icode, MEM_P (dest) || MEM_P (src));
+}
+
+static void
+expand_const_vector (rtx target, rtx src, machine_mode mask_mode)
+{
+  machine_mode mode = GET_MODE (target);
+  scalar_mode elt_mode = GET_MODE_INNER (mode);
+  if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL)
+    {
+      rtx elt;
+      gcc_assert (
+	const_vec_duplicate_p (src, &elt)
+	&& (rtx_equal_p (elt, const0_rtx) || rtx_equal_p (elt, const1_rtx)));
+      emit_pred_op (code_for_pred_mov (mode), target, src, mode);
+      return;
+    }
+
+  rtx elt;
+  if (const_vec_duplicate_p (src, &elt))
+    {
+      rtx tmp = register_operand (target, mode) ? target : gen_reg_rtx (mode);
+      /* Element in range -16 ~ 15 integer or 0.0 floating-point,
+	 we use vmv.v.i instruction.  */
+      if (satisfies_constraint_vi (src) || satisfies_constraint_Wc0 (src))
+	emit_pred_op (code_for_pred_mov (mode), tmp, src, mask_mode);
+      else
+	emit_pred_op (code_for_pred_broadcast (mode), tmp,
+		      force_reg (elt_mode, elt), mask_mode);
+
+      if (tmp != target)
+	emit_move_insn (target, tmp);
+      return;
+    }
+
+  /* TODO: We only support const duplicate vector for now. More cases
+     will be supported when we support auto-vectorization:
+
+       1. series vector.
+       2. multiple elts duplicate vector.
+       3. multiple patterns with multiple elts.  */
 }
 
 /* Expand a pre-RA RVV data move from SRC to DEST.
@@ -140,6 +187,11 @@ bool
 legitimize_move (rtx dest, rtx src, machine_mode mask_mode)
 {
   machine_mode mode = GET_MODE (dest);
+  if (CONST_VECTOR_P (src))
+    {
+      expand_const_vector (dest, src, mask_mode);
+      return true;
+    }
   if (known_ge (GET_MODE_SIZE (mode), BYTES_PER_RISCV_VECTOR)
       && GET_MODE_CLASS (mode) != MODE_VECTOR_BOOL)
     {
@@ -153,12 +205,12 @@ legitimize_move (rtx dest, rtx src, machine_mode mask_mode)
     {
       rtx tmp = gen_reg_rtx (mode);
       if (MEM_P (src))
-	emit_pred_move (tmp, src, mask_mode);
+	emit_pred_op (code_for_pred_mov (mode), tmp, src, mask_mode);
       else
 	emit_move_insn (tmp, src);
       src = tmp;
     }
-  emit_pred_move (dest, src, mask_mode);
+  emit_pred_op (code_for_pred_mov (mode), dest, src, mask_mode);
   return true;
 }
 
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 05bdba5ab4d..bc0411ea862 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -4229,6 +4229,19 @@ riscv_print_operand (FILE *file, rtx op, int letter)
 
   switch (letter)
     {
+      case 'v': {
+	rtx elt;
+
+	if (!const_vec_duplicate_p (op, &elt))
+	  output_operand_lossage ("invalid vector constant");
+	else if (satisfies_constraint_Wc0 (op))
+	  asm_fprintf (file, "0");
+	else if (satisfies_constraint_vi (op))
+	  asm_fprintf (file, "%wd", INTVAL (elt));
+	else
+	  output_operand_lossage ("invalid vector constant");
+	break;
+      }
       case 'm': {
 	if (riscv_v_ext_vector_mode_p (mode))
 	  {
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index b05c3c1545c..defb475f948 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -651,6 +651,9 @@ enum reg_class
 #define FP_ARG_FIRST (FP_REG_FIRST + 10)
 #define FP_ARG_LAST  (FP_ARG_FIRST + MAX_ARGS_IN_REGISTERS - 1)
 
+/* Helper macro for RVV vsetvl instruction generation.  */
+#define X0_REGNUM GP_REG_FIRST
+
 #define CALLEE_SAVED_REG_NUMBER(REGNO)			\
   ((REGNO) >= 8 && (REGNO) <= 9 ? (REGNO) - 8 :		\
    (REGNO) >= 18 && (REGNO) <= 27 ? (REGNO) - 16 : -1)
diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
index 9d4a9dc8a0e..92c4bd0a6a3 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -71,6 +71,15 @@
   (VNx1DF "VNx1BI") (VNx2DF "VNx2BI") (VNx4DF "VNx4BI") (VNx8DF "VNx8BI")
 ])
 
+(define_mode_attr VEL [
+  (VNx1QI "QI") (VNx2QI "QI") (VNx4QI "QI") (VNx8QI "QI") (VNx16QI "QI") (VNx32QI "QI") (VNx64QI "QI")
+  (VNx1HI "HI") (VNx2HI "HI") (VNx4HI "HI") (VNx8HI "HI") (VNx16HI "HI") (VNx32HI "HI")
+  (VNx1SI "SI") (VNx2SI "SI") (VNx4SI "SI") (VNx8SI "SI") (VNx16SI "SI")
+  (VNx1DI "DI") (VNx2DI "DI") (VNx4DI "DI") (VNx8DI "DI")
+  (VNx1SF "SF") (VNx2SF "SF") (VNx4SF "SF") (VNx8SF "SF") (VNx16SF "SF")
+  (VNx1DF "DF") (VNx2DF "DF") (VNx4DF "DF") (VNx8DF "DF")
+])
+
 (define_mode_attr sew [
   (VNx1QI "8") (VNx2QI "8") (VNx4QI "8") (VNx8QI "8") (VNx16QI "8") (VNx32QI "8") (VNx64QI "8")
   (VNx1HI "16") (VNx2HI "16") (VNx4HI "16") (VNx8HI "16") (VNx16HI "16") (VNx32HI "16")
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 01418ac5fcf..611cc862ca8 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -151,6 +151,26 @@
   [(set_attr "type" "vmov")
    (set_attr "mode" "<MODE>")])
 
+;; -----------------------------------------------------------------
+;; ---- Duplicate Operations
+;; -----------------------------------------------------------------
+
+;; According to GCC internal:
+;; This pattern only handles duplicates of non-constant inputs.
+;; Constant vectors go through the movm pattern instead.
+;; So "direct_broadcast_operand" can only be mem or reg, no CONSTANT.
+(define_expand "vec_duplicate<mode>"
+  [(set (match_operand:V 0 "register_operand")
+	(vec_duplicate:V
+	  (match_operand:<VEL> 1 "direct_broadcast_operand")))]
+  "TARGET_VECTOR"
+  {
+    riscv_vector::emit_pred_op (
+      code_for_pred_broadcast (<MODE>mode), operands[0], operands[1], <VM>mode);
+    DONE;
+  }
+)
+
 ;; -----------------------------------------------------------------
 ;; ---- 6. Configuration-Setting Instructions
 ;; -----------------------------------------------------------------
@@ -368,7 +388,7 @@
    vle<sew>.v\t%0,%3%p1
    vse<sew>.v\t%3,%0%p1
    vmv.v.v\t%0,%3
-   vmv.v.i\t%0,v%3"
+   vmv.v.i\t%0,%v3"
   "&& register_operand (operands[0], <MODE>mode)
    && register_operand (operands[3], <MODE>mode)
    && satisfies_constraint_vu (operands[2])"
@@ -407,3 +427,34 @@
   ""
   [(set_attr "type" "vldm,vstm,vimov,vmalu,vmalu")
    (set_attr "mode" "<MODE>")])
+
+;; -------------------------------------------------------------------------------
+;; ---- Predicated Broadcast
+;; -------------------------------------------------------------------------------
+;; Includes:
+;; - 7.5. Vector Strided Instructions (zero stride)
+;; - 11.16 Vector Integer Move Instructions (vmv.v.x)
+;; - 13.16 Vector Floating-Point Move Instruction (vfmv.v.f)
+;; -------------------------------------------------------------------------------
+
+(define_insn "@pred_broadcast<mode>"
+  [(set (match_operand:V 0 "register_operand"                 "=vr,  vr,  vr,  vr")
+	(if_then_else:V
+	  (unspec:<VM>
+	    [(match_operand:<VM> 1 "vector_mask_operand"      " Wc1, Wc1, vm, Wc1")
+	     (match_operand 4 "vector_length_operand"         " rK,  rK,  rK,  rK")
+	     (match_operand 5 "const_int_operand"             "  i,   i,   i,   i")
+	     (match_operand 6 "const_int_operand"             "  i,   i,   i,   i")
+	     (reg:SI VL_REGNUM)
+	     (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
+	  (vec_duplicate:V
+	    (match_operand:<VEL> 3 "direct_broadcast_operand" "  r,   f, Wdm, Wdm"))
+	  (match_operand:V 2 "vector_merge_operand"           "vu0, vu0, vu0, vu0")))]
+  "TARGET_VECTOR"
+  "@
+   vmv.v.x\t%0,%3
+   vfmv.v.f\t%0,%3
+   vlse<sew>.v\t%0,%3,zero,%1.t
+   vlse<sew>.v\t%0,%3,zero"
+  [(set_attr "type" "vimov,vfmov,vlds,vlds")
+   (set_attr "mode" "<MODE>")])
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/dup-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/dup-1.c
new file mode 100644
index 00000000000..2a83afae056
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/dup-1.c
@@ -0,0 +1,521 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -O3 -fgimple" } */
+
+#include "riscv_vector.h"
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f1 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint8mf8_t> ((vint8mf8_t *)out_2(D)) = _Literal (vint8mf8_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f2 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint8mf4_t> ((vint8mf4_t *)out_2(D)) = _Literal (vint8mf4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f3 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint8mf2_t> ((vint8mf2_t *)out_2(D)) = _Literal (vint8mf2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f4 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint8m1_t> ((vint8m1_t *)out_2(D)) = _Literal (vint8m1_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f5 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint8m2_t> ((vint8m2_t *)out_2(D)) = _Literal (vint8m2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f6 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint8m4_t> ((vint8m4_t *)out_2(D)) = _Literal (vint8m4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f7 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint8m8_t> ((vint8m8_t *)out_2(D)) = _Literal (vint8m8_t) 0;
+  return;
+
+}
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f8 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint8mf8_t> ((vuint8mf8_t *)out_2(D)) = _Literal (vuint8mf8_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f9 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint8mf4_t> ((vuint8mf4_t *)out_2(D)) = _Literal (vuint8mf4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f10 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint8mf2_t> ((vuint8mf2_t *)out_2(D)) = _Literal (vuint8mf2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f11 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint8m1_t> ((vuint8m1_t *)out_2(D)) = _Literal (vuint8m1_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f12 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint8m2_t> ((vuint8m2_t *)out_2(D)) = _Literal (vuint8m2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f13 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint8m4_t> ((vuint8m4_t *)out_2(D)) = _Literal (vuint8m4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f14 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint8m8_t> ((vuint8m8_t *)out_2(D)) = _Literal (vuint8m8_t) 0;
+  return;
+
+}
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f15 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint16mf4_t> ((vint16mf4_t *)out_2(D)) = _Literal (vint16mf4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f16 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint16mf2_t> ((vint16mf2_t *)out_2(D)) = _Literal (vint16mf2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f17 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint16m1_t> ((vint16m1_t *)out_2(D)) = _Literal (vint16m1_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f18 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint16m2_t> ((vint16m2_t *)out_2(D)) = _Literal (vint16m2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f19 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint16m4_t> ((vint16m4_t *)out_2(D)) = _Literal (vint16m4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f20 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint16m8_t> ((vint16m8_t *)out_2(D)) = _Literal (vint16m8_t) 0;
+  return;
+
+}
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f21 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint16mf4_t> ((vuint16mf4_t *)out_2(D)) = _Literal (vuint16mf4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f22 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint16mf2_t> ((vuint16mf2_t *)out_2(D)) = _Literal (vuint16mf2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f23 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint16m1_t> ((vuint16m1_t *)out_2(D)) = _Literal (vuint16m1_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f24 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint16m2_t> ((vuint16m2_t *)out_2(D)) = _Literal (vuint16m2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f25 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint16m4_t> ((vuint16m4_t *)out_2(D)) = _Literal (vuint16m4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f26 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint16m8_t> ((vuint16m8_t *)out_2(D)) = _Literal (vuint16m8_t) 0;
+  return;
+
+}
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f27 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint32mf2_t> ((vint32mf2_t *)out_2(D)) = _Literal (vint32mf2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f28 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint32m1_t> ((vint32m1_t *)out_2(D)) = _Literal (vint32m1_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f29 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint32m2_t> ((vint32m2_t *)out_2(D)) = _Literal (vint32m2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f30 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint32m4_t> ((vint32m4_t *)out_2(D)) = _Literal (vint32m4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f31 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint32m8_t> ((vint32m8_t *)out_2(D)) = _Literal (vint32m8_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f32 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint32mf2_t> ((vuint32mf2_t *)out_2(D)) = _Literal (vuint32mf2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f33 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint32m1_t> ((vuint32m1_t *)out_2(D)) = _Literal (vuint32m1_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f34 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint32m2_t> ((vuint32m2_t *)out_2(D)) = _Literal (vuint32m2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f35 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint32m4_t> ((vuint32m4_t *)out_2(D)) = _Literal (vuint32m4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f36 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint32m8_t> ((vuint32m8_t *)out_2(D)) = _Literal (vuint32m8_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f37 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint64m1_t> ((vint64m1_t *)out_2(D)) = _Literal (vint64m1_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f38 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint64m2_t> ((vint64m2_t *)out_2(D)) = _Literal (vint64m2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f39 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint64m4_t> ((vint64m4_t *)out_2(D)) = _Literal (vint64m4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f40 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vint64m8_t> ((vint64m8_t *)out_2(D)) = _Literal (vint64m8_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f41 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint64m1_t> ((vuint64m1_t *)out_2(D)) = _Literal (vuint64m1_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f42 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint64m2_t> ((vuint64m2_t *)out_2(D)) = _Literal (vuint64m2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f43 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint64m4_t> ((vuint64m4_t *)out_2(D)) = _Literal (vuint64m4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f44 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vuint64m8_t> ((vuint64m8_t *)out_2(D)) = _Literal (vuint64m8_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f45 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vfloat32m1_t> ((vfloat32m1_t *)out_2(D)) = _Literal (vfloat32m1_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f46 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vfloat32m2_t> ((vfloat32m2_t *)out_2(D)) = _Literal (vfloat32m2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f47 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vfloat32m4_t> ((vfloat32m4_t *)out_2(D)) = _Literal (vfloat32m4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f48 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vfloat32m8_t> ((vfloat32m8_t *)out_2(D)) = _Literal (vfloat32m8_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f49 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vfloat64m1_t> ((vfloat64m1_t *)out_2(D)) = _Literal (vfloat64m1_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f50 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vfloat64m2_t> ((vfloat64m2_t *)out_2(D)) = _Literal (vfloat64m2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f51 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vfloat64m4_t> ((vfloat64m4_t *)out_2(D)) = _Literal (vfloat64m4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f52 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vfloat64m8_t> ((vfloat64m8_t *)out_2(D)) = _Literal (vfloat64m8_t) 0;
+  return;
+
+}
+
+/* { dg-final { scan-assembler-times {vmv\.v\.i\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),\s*0} 52 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/dup-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/dup-2.c
new file mode 100644
index 00000000000..c6903039c2a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/dup-2.c
@@ -0,0 +1,75 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -O3 -fgimple" } */
+
+#include "riscv_vector.h"
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f1 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vbool1_t> ((vbool1_t *)out_2(D)) = _Literal (vbool1_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f2 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vbool2_t> ((vbool2_t *)out_2(D)) = _Literal (vbool2_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f3 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vbool4_t> ((vbool4_t *)out_2(D)) = _Literal (vbool4_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f4 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vbool8_t> ((vbool8_t *)out_2(D)) = _Literal (vbool8_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f5 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vbool16_t> ((vbool16_t *)out_2(D)) = _Literal (vbool16_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f6 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vbool32_t> ((vbool32_t *)out_2(D)) = _Literal (vbool32_t) 0;
+  return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f7 (void * out)
+{
+  __BB(2,guessed_local(1073741824)):
+  __MEM <vbool64_t> ((vbool64_t *)out_2(D)) = _Literal (vbool64_t) 0;
+  return;
+
+}
+
+/* { dg-final { scan-assembler-times {vmclr\.m\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1])} 7 } } */

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-12-01 16:14 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-01 16:14 [gcc r13-4447] RISC-V: Add duplicate vector support Kito Cheng

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).