analyzer: handle self-referential phis
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 15 Jul 2021 19:01:57 +0000 (15:01 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Thu, 15 Jul 2021 19:01:57 +0000 (15:01 -0400)
gcc/analyzer/ChangeLog:
* state-purge.cc (self_referential_phi_p): New.
(state_purge_per_ssa_name::process_point): Don't purge an SSA name
at its def-stmt if the def-stmt is self-referential.

gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/phi-1.c: New test.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
gcc/analyzer/state-purge.cc
gcc/testsuite/gcc.dg/analyzer/phi-1.c [new file with mode: 0644]

index 70a09ed..e82ea87 100644 (file)
@@ -288,6 +288,20 @@ state_purge_per_ssa_name::add_to_worklist (const function_point &point,
     }
 }
 
+/* Does this phi depend on itself?
+   e.g. in:
+     added_2 = PHI <added_6(2), added_2(3), added_11(4)>
+   the middle defn (from edge 3) requires added_2 itself.  */
+
+static bool
+self_referential_phi_p (const gphi *phi)
+{
+  for (unsigned i = 0; i < gimple_phi_num_args (phi); i++)
+    if (gimple_phi_arg_def (phi, i) == gimple_phi_result (phi))
+      return true;
+  return false;
+}
+
 /* Process POINT, popped from WORKLIST.
    Iterate over predecessors of POINT, adding to WORKLIST.  */
 
@@ -326,11 +340,28 @@ state_purge_per_ssa_name::process_point (const function_point &point,
             !gsi_end_p (gpi); gsi_next (&gpi))
          {
            gphi *phi = gpi.phi ();
+           /* Are we at the def-stmt for m_name?  */
            if (phi == def_stmt)
              {
-               if (logger)
-                 logger->log ("def stmt within phis; terminating");
-               return;
+               /* Does this phi depend on itself?
+                  e.g. in:
+                    added_2 = PHI <added_6(2), added_2(3), added_11(4)>
+                  the middle defn (from edge 3) requires added_2 itself
+                  so we can't purge it here.  */
+               if (self_referential_phi_p (phi))
+                 {
+                   if (logger)
+                     logger->log ("self-referential def stmt within phis;"
+                                  " continuing");
+                 }
+               else
+                 {
+                   /* Otherwise, we can stop here, so that m_name
+                      can be purged.  */
+                   if (logger)
+                     logger->log ("def stmt within phis; terminating");
+                   return;
+                 }
              }
          }
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/phi-1.c b/gcc/testsuite/gcc.dg/analyzer/phi-1.c
new file mode 100644 (file)
index 0000000..0926003
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do "compile" } */
+
+typedef __SIZE_TYPE__ size_t;
+#define NULL ((void *) 0)
+
+extern const char *foo (void);
+extern size_t bar (void);
+
+void
+_nl_expand_alias (const char *locale_alias_path)
+{
+  size_t added;
+  do
+    {
+      added = 0;
+      while (added == 0 && locale_alias_path[0] != '\0')
+       {
+         const char *start = foo ();
+         if (start < locale_alias_path)
+           added = bar ();
+       }
+    }
+  while (added != 0);
+}