]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: Do not delete fused vsetvl if it has uses [PR119115].
authorRobin Dapp <rdapp@ventanamicro.com>
Wed, 5 Mar 2025 17:16:57 +0000 (18:16 +0100)
committerRobin Dapp <rdapp@ventanamicro.com>
Thu, 13 Mar 2025 09:40:40 +0000 (10:40 +0100)
In PR119115 we end up with an orphaned
vsetvli zero,t1,e16,m1,ta,ma.
t1 originally came from another vsetvl that was fused from
vsetvli a4,a3,e8,mf2,ta,ma
vsetvli t1,a3,e8,mf2,ta,ma   (1)
to
vsetvli zero,a3,e16,m1,ta,ma.

This patch checks if t1, the VL operand of (1), has AVL uses and does
not delete the vsetvl if so.  While doing so, it also wraps the search
for VL uses into two new functions reg_used and reg_single_use_in_avl.

PR target/119115

gcc/ChangeLog:

* config/riscv/riscv-vsetvl.cc (reg_used): New function.
(reg_single_use_in_avl): Ditto.
(pre_vsetvl::fuse_local_vsetvl_info): Use reg_single_use_in_avl
when checking if vsetvl can be deleted.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/rvv/base/pr119115.c: New test.

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

index f0165f7b8c8ca25f25060b2718d9eb6f3774a215..0ac2538f596f4985572caa78960b25f3481f4ab3 100644 (file)
@@ -780,6 +780,36 @@ enum class avl_demand_type : unsigned
   ignore_avl = demand_flags::DEMAND_EMPTY_P,
 };
 
+/* Go through all uses of INSN looking for a single use of register REG.
+   Return true if we find
+    - Uses in a non-RVV insn
+    - More than one use in an RVV insn
+    - A single use in the VL operand of an RVV insn
+   and false otherwise.
+   A single use in the AVL operand does not count as use as we take care of
+   those separately in the pass.  */
+
+static bool
+reg_used (insn_info *insn, rtx reg)
+{
+  unsigned int regno = REGNO (reg);
+  const hash_set<use_info *> vl_uses = get_all_real_uses (insn, regno);
+  for (use_info *use : vl_uses)
+    {
+      gcc_assert (use->insn ()->is_real ());
+      rtx_insn *rinsn = use->insn ()->rtl ();
+      if (!has_vl_op (rinsn)
+         || count_regno_occurrences (rinsn, regno) != 1)
+       return true;
+
+      rtx avl = ::get_avl (rinsn);
+      if (!avl || !REG_P (avl) || regno != REGNO (avl))
+       return true;
+    }
+  return false;
+}
+
+
 class vsetvl_info
 {
 private:
@@ -1142,27 +1172,7 @@ public:
 
     /* Determine if dest operand(vl) has been used by non-RVV instructions.  */
     if (dest_vl)
-      {
-       const hash_set<use_info *> vl_uses
-         = get_all_real_uses (get_insn (), REGNO (dest_vl));
-       for (use_info *use : vl_uses)
-         {
-           gcc_assert (use->insn ()->is_real ());
-           rtx_insn *rinsn = use->insn ()->rtl ();
-           if (!has_vl_op (rinsn)
-               || count_regno_occurrences (rinsn, REGNO (dest_vl)) != 1)
-             {
-               m_vl_used_by_non_rvv_insn = true;
-               break;
-             }
-           rtx avl = ::get_avl (rinsn);
-           if (!avl || !REG_P (avl) || REGNO (dest_vl) != REGNO (avl))
-             {
-               m_vl_used_by_non_rvv_insn = true;
-               break;
-             }
-         }
-      }
+      m_vl_used_by_non_rvv_insn = reg_used (get_insn (), dest_vl);
 
     /* Collect the read vl insn for the fault-only-first rvv loads.  */
     if (fault_first_load_p (insn->rtl ()))
@@ -1369,6 +1379,35 @@ public:
   void set_empty_info () { global_info.set_empty (); }
 };
 
+/* Same as REG_USED () but looks for a single use in an RVV insn's AVL
+   operand.  */
+static bool
+reg_single_use_in_avl (insn_info *insn, rtx reg)
+{
+  if (!reg)
+    return false;
+  unsigned int regno = REGNO (reg);
+  const hash_set<use_info *> vl_uses = get_all_real_uses (insn, regno);
+  for (use_info *use : vl_uses)
+    {
+      gcc_assert (use->insn ()->is_real ());
+      rtx_insn *rinsn = use->insn ()->rtl ();
+      if (!has_vl_op (rinsn)
+         || count_regno_occurrences (rinsn, regno) != 1)
+       return false;
+
+      vsetvl_info info = vsetvl_info (use->insn ());
+
+      if (!info.has_nonvlmax_reg_avl ())
+       return false;
+
+      rtx avl = info.get_avl ();
+      if (avl && REG_P (avl) && regno == REGNO (avl))
+       return true;
+    }
+  return false;
+}
+
 /* Demand system is the RVV-based VSETVL info analysis tools wrapper.
    It defines compatible rules for SEW/LMUL, POLICY and AVL.
    Also, it provides 3 interfaces available_p, compatible_p and
@@ -2797,8 +2836,18 @@ pre_vsetvl::fuse_local_vsetvl_info ()
                     64 into 32.  */
                  prev_info.set_max_sew (
                    MIN (prev_info.get_max_sew (), curr_info.get_max_sew ()));
-                 if (!curr_info.vl_used_by_non_rvv_insn_p ()
-                     && vsetvl_insn_p (curr_info.get_insn ()->rtl ()))
+
+                 /* If we fuse and the current, to be deleted vsetvl has uses
+                    of its VL as AVL operand in other vsetvls those will be
+                    orphaned.  Therefore only delete if that's not the case.
+                    */
+                 rtx cur_dest = curr_info.has_vl ()
+                   ? curr_info.get_vl ()
+                   : NULL_RTX;
+
+                 if (vsetvl_insn_p (curr_info.get_insn ()->rtl ())
+                     && !reg_single_use_in_avl (curr_info.get_insn (),
+                                                cur_dest))
                    m_delete_list.safe_push (curr_info);
 
                  if (curr_info.get_read_vl_insn ())
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr119115.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr119115.c
new file mode 100644 (file)
index 0000000..ac8a70e
--- /dev/null
@@ -0,0 +1,59 @@
+/* { dg-do run } */
+/* { dg-require-effective-target rv64 } */
+/* { dg-require-effective-target rvv_zvl256b_ok } */
+/* { dg-additional-options "-march=rv64gcv_zvl256b -mabi=lp64d -O3 -fsigned-char -fwrapv -mrvv-vector-bits=zvl" } */
+
+short a[4][14][14];
+void
+b (short d, short e, _Bool f, short g, int h, int i, char j, int k, int l,
+   short m[][14], char n[], unsigned short o[][14][14], short p[])
+{
+  for (unsigned q = 0; q < (char) i; q++)
+    for (unsigned char r = 0; r < (char) (-1748723647U * m[q][q]) - 20; r++)
+      a[q][q][r] = p[q] || o[q][q][r];
+}
+
+__attribute__ ((noipa))
+void
+check (long long val)
+{
+  if (val != 0)
+    __builtin_abort ();
+}
+
+long long seed;
+short d;
+short e;
+_Bool f;
+short g;
+int h;
+int i = 15963650;
+char j;
+int k;
+int l;
+short m[4][14];
+char n[4];
+unsigned short o[4][14][14];
+short p[4];
+
+int
+main ()
+{
+  for (int q = 0; q < 4; ++q)
+    {
+      p[q] = 4084;
+      for (int r = 0; r < 4; ++r)
+       {
+         m[q][r] = 24482;
+         for (int u = 0; u < 4; ++u)
+           a[q][r][u] = 81;
+       }
+    }
+  b (d, e, f, g, h, i, j, k, l, m, n, o, p);
+  for (int q = 0; q < 4; ++q)
+    for (int r = 0; r < 4; ++r)
+      for (int u = 0; u < 14; ++u)
+       seed ^= a[q][r][u] + (seed >> 2);
+
+  check (seed);
+}