https://gcc.gnu.org/g:f035e26ef7eee00fd0028531b087e4d2b72c6695

commit r17-5462-gf035e26ef7eee00fd0028531b087e4d2b72c6695
Author: Richard Biener <[email protected]>
Date:   Wed Oct 21 15:40:53 2026 +0200

    tree-optimization/128054 - isolate path issue with multiple UBs
    
    The isolate path iteration scheme attempts to isolate a path exactly
    once, applying all transforms so the earliest will survive.  But it
    fails to associate later UBs to the correctly isolated path due to
    the way it iterates over PHIs and arguments.  The following changes
    the NULL dereference discovery to iterate over incoming edges
    (paths) so we clearly deal with UBs on the same path.
    
            PR tree-optimization/128054
            * gimple-ssa-isolate-paths.cc (find_implicit_erroneous_behavior):
            Iterate over edges and then PHIs for NULL dereference discovery.
            Duplicate each path exactly once and apply all transforms for
            UB on that edge to that duplicate.
    
            * gcc.dg/torture/pr128054.c: New testcase.

Diff:
---
 gcc/gimple-ssa-isolate-paths.cc         | 68 ++++++++++++++-------------------
 gcc/testsuite/gcc.dg/torture/pr128054.c | 29 ++++++++++++++
 2 files changed, 58 insertions(+), 39 deletions(-)

diff --git a/gcc/gimple-ssa-isolate-paths.cc b/gcc/gimple-ssa-isolate-paths.cc
index ceef422495c7..6068418ce3b7 100644
--- a/gcc/gimple-ssa-isolate-paths.cc
+++ b/gcc/gimple-ssa-isolate-paths.cc
@@ -710,7 +710,6 @@ find_implicit_erroneous_behavior (void)
       if (has_abnormal_or_eh_outgoing_edge_p (bb))
        continue;
 
-
       /* If BB has an edge to itself, then duplication of BB below
         could result in reallocation of BB's PHI nodes.   If that happens
         then the loop below over the PHIs would use the old PHI and
@@ -724,74 +723,65 @@ find_implicit_erroneous_behavior (void)
         is then dereferenced within BB.  This is somewhat overly
         conservative, but probably catches most of the interesting
         cases.   */
-      basic_block duplicate = NULL;
-      for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
+      edge e;
+      for (edge_iterator ei = ei_start (bb->preds); (e = ei_safe_edge (ei));)
        {
-         gphi *phi = si.phi ();
-         tree lhs = gimple_phi_result (phi);
-
-         /* PHI produces a pointer result.  See if any of the PHI's
-            arguments are NULL.
-
-            When we remove an edge, we want to reprocess the current
-            index since the argument at that index will have been
-            removed, hence the ugly way we update I for each iteration.  */
-         for (unsigned i = 0, next_i = 0;
-              i < gimple_phi_num_args (phi); i = next_i)
+         auto_vec <std::pair<gimple *, tree>, 4> uses_in_bb;
+         for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
            {
-             tree arg = gimple_phi_arg_def (phi, i);
-             edge e = gimple_phi_arg_edge (phi, i);
-
-             /* Advance the argument index unless a path involving
-                the current argument has been isolated.  */
-             next_i = i + 1;
+             gphi *phi = si.phi ();
+             tree lhs = gimple_phi_result (phi);
+             tree arg = gimple_phi_arg_def_from_edge (phi, e);
 
+             /* PHI produces a pointer result.  See if any of the PHI's
+                arguments are NULL.  */
              if (!integer_zerop (arg))
                continue;
 
-             location_t phi_arg_loc = gimple_phi_arg_location (phi, i);
+             location_t phi_arg_loc
+               = gimple_phi_arg_location_from_edge (phi, e);
 
              imm_use_iterator iter;
              gimple *use_stmt;
 
              /* We've got a NULL PHI argument.  Now see if the
-                PHI's result is dereferenced within BB.  */
-             auto_vec <gimple *, 4> uses_in_bb;
+                PHI's result is dereferenced within BB.  */
              FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
-               {
-                 /* We only care about uses in BB.  Catching cases in
+               {
+                 /* We only care about uses in BB.  Catching cases in
                     in other blocks would require more complex path
                     isolation code.   */
                  if (gimple_bb (use_stmt) != bb)
                    continue;
 
-                 location_t loc = gimple_location (use_stmt)
-                   ? gimple_location (use_stmt)
-                   : phi_arg_loc;
+                 location_t loc = (gimple_location (use_stmt)
+                                   ? gimple_location (use_stmt)
+                                   : phi_arg_loc);
 
                  if (stmt_uses_name_in_undefined_way (use_stmt, lhs, loc))
                    {
                      if (!can_duplicate_block_p (bb))
                        break;
-                     uses_in_bb.safe_push (use_stmt);
+                     uses_in_bb.safe_push (std::make_pair (use_stmt, lhs));
                    }
                }
-             for (gimple *use_stmt : uses_in_bb)
-               {
-                 duplicate = isolate_path (bb, duplicate, e,
-                                           use_stmt, lhs, false);
+           }
+         basic_block duplicate = NULL;
+         for (auto use : uses_in_bb)
+           {
+             duplicate = isolate_path (bb, duplicate, e,
+                                       use.first, use.second, false);
 
-                 /* When we remove an incoming edge, we need to
-                    reprocess the Ith element.  */
-                 next_i = i;
-                 cfg_altered = true;
-               }
+             cfg_altered = true;
            }
+
+         if (!duplicate)
+           ei_next (&ei);
        }
 
       /* Then look for a PHI which have addresses of locals that
         are then returned.  */
-      duplicate = NULL;
+      basic_block duplicate = NULL;
       for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
        {
          gphi *phi = si.phi ();
diff --git a/gcc/testsuite/gcc.dg/torture/pr128054.c 
b/gcc/testsuite/gcc.dg/torture/pr128054.c
new file mode 100644
index 000000000000..0570f33eabc0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr128054.c
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+
+volatile int sel = 1;
+int x = 5, y = 42;
+
+__attribute__((noipa)) void
+maybe_exit (int c)
+{
+  if (c == 42)
+    __builtin_exit (0);
+}
+
+int main ()
+{
+  int *p1, *p2;
+  if (sel)
+    {
+      p1 = 0;
+      p2 = &y;
+    }
+  else
+    {
+      p1 = &x;
+      p2 = 0;
+    }
+  int v = *p2;
+  maybe_exit (v);
+  return *p1;
+}

Reply via email to