On my local branch gcc.dg/torture/pr56349.c fails by sending GCC into an
infinite loop trying to simplify a self-referring statement. ie
something like

x_1 = x_1 + 10;

That, of course, shouldn't be happening in SSA form.  After some digging
I've found the culprit.

Let's say we've got a PHI.

a_1 = PHI (a_0, a_2)

If DOM decides that the edge associated with a_2 is not executable, then
DOM will consider the PHI a degenerate and enter a_1 = a_0 into its
equivalence table.

That in turn will result in propagation of a_0 into uses of a_1.

That, of course, isn't right.  There's nothing that guarantees that the
definition of a_0 dominates the uses of a_1.  In the testcase that bogus
propagation cascades and eventually results in a self-referring node
like I showed above.

The solution here is to note whether or not we ignored any PHI
arguments.  If we do and the equivalence we want to enter is SSA_NAME =
SSA_NAME, then we must reject the equivalence.    Obviously if we wanted
to enter SSA_NAME = CONST, then we can still do so.

Bootstrapped and regression tested on x86_64.  Installing on the trunk.

jeff
commit 2b37e05b327e6b1170f72c51c21681b1dc5b8337
Author: Jeff Law <l...@redhat.com>
Date:   Sun Nov 19 13:14:55 2017 -0700

            * tree-ssa-dom.c (record_equivalences_from_phis): Fix handling
            of degenerates resulting from ignoring an edge.

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ae05dacf791..5ce981d0871 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2017-11-19  Jeff Law  <l...@redhat.com>
+
+       * tree-ssa-dom.c (record_equivalences_from_phis): Fix handling
+       of degenerates resulting from ignoring an edge.
+
 2017-11-19  Jan Hubicka  <hubi...@ucw.cz>
 
        PR ipa/81360
diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
index eb85b4a09ad..916d66134c3 100644
--- a/gcc/tree-ssa-dom.c
+++ b/gcc/tree-ssa-dom.c
@@ -1011,6 +1011,7 @@ record_equivalences_from_phis (basic_block bb)
       tree rhs = NULL;
       size_t i;
 
+      bool ignored_phi_arg = false;
       for (i = 0; i < gimple_phi_num_args (phi); i++)
        {
          tree t = gimple_phi_arg_def (phi, i);
@@ -1021,10 +1022,14 @@ record_equivalences_from_phis (basic_block bb)
          if (lhs == t)
            continue;
 
-         /* If the associated edge is not marked as executable, then it
-            can be ignored.  */
+         /* We want to track if we ignored any PHI arguments because
+            their associated edges were not executable.  This impacts
+            whether or not we can use any equivalence we might discover.  */
          if ((gimple_phi_arg_edge (phi, i)->flags & EDGE_EXECUTABLE) == 0)
-           continue;
+           {
+             ignored_phi_arg = true;
+             continue;
+           }
 
          t = dom_valueize (t);
 
@@ -1049,9 +1054,15 @@ record_equivalences_from_phis (basic_block bb)
         a useful equivalence.  We do not need to record unwind data for
         this, since this is a true assignment and not an equivalence
         inferred from a comparison.  All uses of this ssa name are dominated
-        by this assignment, so unwinding just costs time and space.  */
+        by this assignment, so unwinding just costs time and space.
+
+        Note that if we ignored a PHI argument and the resulting equivalence
+        is SSA_NAME = SSA_NAME.  Then we can not use the equivalence as the
+        uses of the LHS SSA_NAME are not necessarily dominated by the
+        assignment of the RHS SSA_NAME.  */
       if (i == gimple_phi_num_args (phi)
-         && may_propagate_copy (lhs, rhs))
+         && may_propagate_copy (lhs, rhs)
+         && (!ignored_phi_arg || TREE_CODE (rhs) != SSA_NAME))
        set_ssa_name_value (lhs, rhs);
     }
 }

Reply via email to