]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: Add local user vsetvl instruction elimination [PR109547]
authorJuzhe-Zhong <juzhe.zhong@rivai.ai>
Fri, 7 Apr 2023 01:34:13 +0000 (09:34 +0800)
committerKito Cheng <kito.cheng@sifive.com>
Fri, 21 Apr 2023 06:46:03 +0000 (14:46 +0800)
This patch is to enhance optimization for auto-vectorization.

Before this patch:

Loop:
vsetvl a5,a2...
vsetvl zero,a5...
vle

After this patch:

Loop:
vsetvl a5,a2
vle

gcc/ChangeLog:

PR target/109547
* config/riscv/riscv-vsetvl.cc (local_eliminate_vsetvl_insn): New function.
(vector_insn_info::skip_avl_compatible_p): Ditto.
(vector_insn_info::merge): Remove default value.
(pass_vsetvl::compute_local_backward_infos): Ditto.
(pass_vsetvl::cleanup_insns): Add local vsetvl elimination.
* config/riscv/riscv-vsetvl.h: Ditto.

gcc/testsuite/ChangeLog:

PR target/109547
* gcc.target/riscv/rvv/vsetvl/pr109547.c: New.
* gcc.target/riscv/rvv/vsetvl/vsetvl-17.c: Update scan
condition.

gcc/config/riscv/riscv-vsetvl.cc
gcc/config/riscv/riscv-vsetvl.h
gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr109547.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl-17.c

index 9c356ce51579fe7f1565c2ee47b988ff6b5abb9b..2406931dac01b6c2d5d2b6f763847ba0691ea2b4 100644 (file)
@@ -1054,6 +1054,51 @@ change_vsetvl_insn (const insn_info *insn, const vector_insn_info &info)
   change_insn (rinsn, new_pat);
 }
 
+static void
+local_eliminate_vsetvl_insn (const vector_insn_info &dem)
+{
+  const insn_info *insn = dem.get_insn ();
+  if (!insn || insn->is_artificial ())
+    return;
+  rtx_insn *rinsn = insn->rtl ();
+  const bb_info *bb = insn->bb ();
+  if (vsetvl_insn_p (rinsn))
+    {
+      rtx vl = get_vl (rinsn);
+      for (insn_info *i = insn->next_nondebug_insn ();
+          real_insn_and_same_bb_p (i, bb); i = i->next_nondebug_insn ())
+       {
+         if (i->is_call () || i->is_asm ()
+             || find_access (i->defs (), VL_REGNUM)
+             || find_access (i->defs (), VTYPE_REGNUM))
+           return;
+
+         if (has_vtype_op (i->rtl ()))
+           {
+             if (!vsetvl_discard_result_insn_p (PREV_INSN (i->rtl ())))
+               return;
+             rtx avl = get_avl (i->rtl ());
+             if (avl != vl)
+               return;
+             set_info *def = find_access (i->uses (), REGNO (avl))->def ();
+             if (def->insn () != insn)
+               return;
+
+             vector_insn_info new_info;
+             new_info.parse_insn (i);
+             if (!new_info.skip_avl_compatible_p (dem))
+               return;
+
+             new_info.set_avl_info (dem.get_avl_info ());
+             new_info = dem.merge (new_info, LOCAL_MERGE);
+             change_vsetvl_insn (insn, new_info);
+             eliminate_insn (PREV_INSN (i->rtl ()));
+             return;
+           }
+       }
+    }
+}
+
 static bool
 source_equal_p (insn_info *insn1, insn_info *insn2)
 {
@@ -1996,6 +2041,19 @@ vector_insn_info::compatible_p (const vector_insn_info &other) const
   return true;
 }
 
+bool
+vector_insn_info::skip_avl_compatible_p (const vector_insn_info &other) const
+{
+  gcc_assert (valid_or_dirty_p () && other.valid_or_dirty_p ()
+             && "Can't compare invalid demanded infos");
+  unsigned array_size = sizeof (incompatible_conds) / sizeof (demands_cond);
+  /* Bypass AVL incompatible cases.  */
+  for (unsigned i = 1; i < array_size; i++)
+    if (incompatible_conds[i].dual_incompatible_p (*this, other))
+      return false;
+  return true;
+}
+
 bool
 vector_insn_info::compatible_avl_p (const vl_vtype_info &other) const
 {
@@ -2190,7 +2248,7 @@ vector_insn_info::fuse_mask_policy (const vector_insn_info &info1,
 
 vector_insn_info
 vector_insn_info::merge (const vector_insn_info &merge_info,
-                        enum merge_type type = LOCAL_MERGE) const
+                        enum merge_type type) const
 {
   if (!vsetvl_insn_p (get_insn ()->rtl ()))
     gcc_assert (this->compatible_p (merge_info)
@@ -2696,7 +2754,7 @@ pass_vsetvl::compute_local_backward_infos (const bb_info *bb)
                    && !reg_available_p (insn, change))
                  && change.compatible_p (info))
                {
-                 info = change.merge (info);
+                 info = change.merge (info, LOCAL_MERGE);
                  /* Fix PR109399, we should update user vsetvl instruction
                     if there is a change in demand fusion.  */
                  if (vsetvl_insn_p (insn->rtl ()))
@@ -3925,6 +3983,15 @@ pass_vsetvl::cleanup_insns (void) const
       for (insn_info *insn : bb->real_nondebug_insns ())
        {
          rtx_insn *rinsn = insn->rtl ();
+         const auto &dem = m_vector_manager->vector_insn_infos[insn->uid ()];
+         /* Eliminate local vsetvl:
+              bb 0:
+              vsetvl a5,a6,...
+              vsetvl zero,a5.
+
+            Eliminate vsetvl in bb2 when a5 is only coming from
+            bb 0.  */
+         local_eliminate_vsetvl_insn (dem);
 
          if (vlmax_avl_insn_p (rinsn))
            {
index 237381f7026bd1675a1aefaa7ae1a5e03d89377c..4fe08cfc789d059353e916953861f7a91fbb4fec 100644 (file)
@@ -380,6 +380,7 @@ public:
   void fuse_mask_policy (const vector_insn_info &, const vector_insn_info &);
 
   bool compatible_p (const vector_insn_info &) const;
+  bool skip_avl_compatible_p (const vector_insn_info &) const;
   bool compatible_avl_p (const vl_vtype_info &) const;
   bool compatible_avl_p (const avl_info &) const;
   bool compatible_vtype_p (const vl_vtype_info &) const;
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr109547.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/pr109547.c
new file mode 100644 (file)
index 0000000..88dd877
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -fno-schedule-insns -fno-schedule-insns2" } */
+
+#include "riscv_vector.h"
+
+void func(unsigned char *out, unsigned char *in, unsigned long len) {
+  unsigned long i = 0;
+  while (i < len) {
+    unsigned long vl = __riscv_vsetvl_e8m1(len - i);
+    vuint8m1_t r = __riscv_vle8_v_u8m1(in + i, vl);
+    __riscv_vse8_v_u8m1(out + i, r, vl);
+    i += vl;
+  }
+/* { dg-final { scan-assembler-times {vsetvli} 1 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */}
index ee58f9bbdfcf9dc981c16a0194a10a9d05a2d864..8a1bbb40fc8a418876ae4979d6d334c9249a4046 100644 (file)
@@ -11,4 +11,4 @@ void foo(int32_t *in1, int32_t *in2, int32_t *in3, int32_t *out, size_t n, int c
   __riscv_vse32_v_i32m1(out, c, __riscv_vsetvl_e8mf2 (vl));
 }
 
-/* { dg-final { scan-assembler-times {vsetvli} 8 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */
\ No newline at end of file
+/* { dg-final { scan-assembler-times {vsetvli} 7 { target { no-opts "-O0" no-opts "-g" no-opts "-funroll-loops" } } } } */