Hi,

this patch enhances the equality check for REG_EQUAL notes in the vsetvl
pass.  Currently, we assume that two such notes describe the same value
when they have the same rtx representation.  This is not true when
either of the note's source operands is modified by an insn between the
two notes.

Suppose:

(insn 62 60 63 4 (set (reg:DI 17 a7 [orig:154 loop_len_54 ] [154])
        (umin:DI (reg:DI 15 a5 [orig:174 _100 ] [174])
            (reg:DI 30 t5 [219]))) 442 {umindi3}
     (expr_list:REG_EQUAL (umin:DI (reg:DI 15 a5 [orig:174 _100 ] [174])
            (const_int 8 [0x8]))
        (nil)))
(insn 63 62 65 4 (set (reg:DI 15 a5 [orig:175 _103 ] [175])
        (minus:DI (reg:DI 15 a5 [orig:174 _100 ] [174])
            (reg:DI 17 a7 [orig:154 loop_len_54 ] [154]))) 11 {subdi3}
     (nil))
(insn 65 63 66 4 (set (reg:DI 16 a6 [orig:153 loop_len_53 ] [153])
        (umin:DI (reg:DI 15 a5 [orig:175 _103 ] [175])
            (reg:DI 30 t5 [219]))) 442 {umindi3}
     (expr_list:REG_EQUAL (umin:DI (reg:DI 15 a5 [orig:175 _103 ] [175])
            (const_int 8 [0x8]))
        (nil)))

where insn 63 overwrites a5 and insn 65's REG_EQUAL note that refers to
a5 describes a different value than insn 62's REG_EQUAL note.

In order to catch this situation this patch has source_equal_p check
every instruction between two notes for modification of any
participating register.

Regards
 Robin


gcc/ChangeLog:

        * config/riscv/riscv-vsetvl.cc (modify_reg_between_p): Move.
        (source_equal_p): Check if source registers were modified in
        between.
---
 gcc/config/riscv/riscv-vsetvl.cc | 62 ++++++++++++++++++++++++--------
 1 file changed, 47 insertions(+), 15 deletions(-)

diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc
index 3fa25a6404d..34bf7498103 100644
--- a/gcc/config/riscv/riscv-vsetvl.cc
+++ b/gcc/config/riscv/riscv-vsetvl.cc
@@ -85,6 +85,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "predict.h"
 #include "profile-count.h"
 #include "gcse.h"
+#include "rtl-iter.h"
 
 using namespace rtl_ssa;
 using namespace riscv_vector;
@@ -548,6 +549,21 @@ get_all_sets (set_info *set, bool /* get_real_inst */ 
real_p,
   return hash_set<set_info *> ();
 }
 
+static bool
+modify_reg_between_p (insn_info *prev_insn, insn_info *curr_insn,
+                     unsigned regno)
+{
+  gcc_assert (prev_insn->compare_with (curr_insn) < 0);
+  for (insn_info *i = curr_insn->prev_nondebug_insn (); i != prev_insn;
+       i = i->prev_nondebug_insn ())
+    {
+      // no def of regno
+      if (find_access (i->defs (), regno))
+       return true;
+    }
+  return false;
+}
+
 static bool
 source_equal_p (insn_info *insn1, insn_info *insn2)
 {
@@ -561,7 +577,37 @@ source_equal_p (insn_info *insn1, insn_info *insn2)
   rtx note1 = find_reg_equal_equiv_note (rinsn1);
   rtx note2 = find_reg_equal_equiv_note (rinsn2);
   if (note1 && note2 && rtx_equal_p (note1, note2))
-    return true;
+    {
+      /* REG_EQUIVs are globally.  */
+      if (REG_NOTE_KIND (note2) == REG_EQUIV)
+       return true;
+
+      /* If both insns are the same, the notes are definitely equivalent.  */
+      if (insn2->compare_with (insn1) == 0)
+       return true;
+
+      /* Canonicalize order so insn1 is always before insn2 for the following
+        check.  */
+      if (insn2->compare_with (insn1) < 0)
+       std::swap (insn1, insn2);
+
+      /* If two REG_EQUAL notes are similar the value they calculate can still
+        be different.  The value is only identical if none of the sources have
+        been modified in between.  */
+      subrtx_iterator::array_type array;
+      FOR_EACH_SUBRTX (iter, array, note2, NONCONST)
+       {
+         if (!*iter)
+           continue;
+
+         if (!REG_P (*iter))
+           continue;
+
+         if (modify_reg_between_p (insn1, insn2, REGNO (*iter)))
+           return false;
+       }
+      return true;
+    }
   return false;
 }
 
@@ -1439,20 +1485,6 @@ private:
           && find_access (i->defs (), REGNO (info.get_avl ()));
   }
 
-  inline bool modify_reg_between_p (insn_info *prev_insn, insn_info *curr_insn,
-                                   unsigned regno)
-  {
-    gcc_assert (prev_insn->compare_with (curr_insn) < 0);
-    for (insn_info *i = curr_insn->prev_nondebug_insn (); i != prev_insn;
-        i = i->prev_nondebug_insn ())
-      {
-       // no def of regno
-       if (find_access (i->defs (), regno))
-         return true;
-      }
-    return false;
-  }
-
   inline bool reg_avl_equal_p (const vsetvl_info &prev, const vsetvl_info 
&next)
   {
     if (!prev.has_nonvlmax_reg_avl () || !next.has_nonvlmax_reg_avl ())
-- 
2.41.0

Reply via email to