]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-optimization/123298 - fix backedge detection for VN alias walk
authorRichard Biener <rguenther@suse.de>
Thu, 8 Jan 2026 09:10:25 +0000 (10:10 +0100)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 8 Jan 2026 11:42:54 +0000 (12:42 +0100)
When trying to skip a virtual PHI during an alias walk we have to
direct a possible VN translation hook to not use valueization when
walking a backedge.  But this backedge detection was overly
optimistic, not honoring irreducible regions.  The following hookizes
the backedge detection so VN can properly flag edges that are back
with respect to its particular CFG traversal.

PR tree-optimization/123298
* tree-ssa-alias.h (get_continuation_for_phi): Take a gphi *,
add is_backedge hook argument.
(walk_non_aliased_vuses): Add is_backedge hook argument.
* tree-ssa-alias.cc (maybe_skip_until): Adjust.
(get_continuation_for_phi): Use new hook to classify an
edge into the PHI as backedge.
(walk_non_aliased_vuses): Adjust.
* gimple-lower-bitint.cc (bitint_dom_walker::before_dom_children):
Likewise.
* ipa-prop.cc (determine_known_aggregate_parts): Likewise.
* tree-ssa-scopedtables.cc (avail_exprs_stack::lookup_avail_expr):
Likewise.
* tree-ssa-pre.cc (translate_vuse_through_block): Likewise.
* tree-ssa-sccvn.cc (vn_bb_to_rpo): Make BB to RPO order
mapping accessible from new hook.
(do_rpo_vn_1): Likewise.
(vn_is_backedge): New hook to classify edge.
(vn_reference_lookup_pieces): Adjust.
(vn_reference_lookup): Likewise.

* gcc.dg/torture/pr123298.c: New testcase.

gcc/gimple-lower-bitint.cc
gcc/ipa-prop.cc
gcc/testsuite/gcc.dg/torture/pr123298.c [new file with mode: 0644]
gcc/tree-ssa-alias.cc
gcc/tree-ssa-alias.h
gcc/tree-ssa-pre.cc
gcc/tree-ssa-sccvn.cc
gcc/tree-ssa-scopedtables.cc

index 9ae1954e8ddeb7cc42e5f9cd6fa787558b4d7775..9d027c6a6a1a44c285fabff14195c971b63b71d3 100644 (file)
@@ -6438,7 +6438,7 @@ bitint_dom_walker::before_dom_children (basic_block bb)
            vuse = vop;
          if (vuse != lvop
              && walk_non_aliased_vuses (&ref, vuse, false, vuse_eq,
-                                        NULL, NULL, limit, lvop) == NULL)
+                                        NULL, NULL, NULL, limit, lvop) == NULL)
            bitmap_clear_bit (m_loads, SSA_NAME_VERSION (s));
        }
     }
index c491a4d104f6541535a37aa5fadfad09b5af392c..12e936ba29bfbed23d7bccf81c949b08fa98a063 100644 (file)
@@ -2243,9 +2243,9 @@ determine_known_aggregate_parts (struct ipa_func_body_info *fbi,
     {
       gimple *stmt = SSA_NAME_DEF_STMT (dom_vuse);
 
-      if (gimple_code (stmt) == GIMPLE_PHI)
+      if (gphi *phi = dyn_cast <gphi *> (stmt))
        {
-         dom_vuse = get_continuation_for_phi (stmt, &r, true,
+         dom_vuse = get_continuation_for_phi (phi, &r, true,
                                               fbi->aa_walk_budget,
                                               &visited, false, NULL, NULL);
          continue;
diff --git a/gcc/testsuite/gcc.dg/torture/pr123298.c b/gcc/testsuite/gcc.dg/torture/pr123298.c
new file mode 100644 (file)
index 0000000..ceaa00b
--- /dev/null
@@ -0,0 +1,35 @@
+/* { dg-do run } */
+
+__attribute__((noipa))
+int
+func_1 (int g_258, int func_1_BS_COND_11, int g_64)
+{
+  int BS_VAR_1 = 10;
+  unsigned char BS_VAR_5[2] = { 19, 28 };
+  int LOCAL_CHECKSUM = 0;
+  if (func_1_BS_COND_11)
+    goto BS_LABEL_0;
+  BS_VAR_1 = 0;
+  while (g_64 <= 5)
+    {
+BS_LABEL_0:
+      for (;;)
+       {
+         LOCAL_CHECKSUM = BS_VAR_5[1];
+         if (g_258 != 0) break;
+         goto out;
+       }
+      BS_VAR_5[BS_VAR_1 < 5] = 0;
+      g_258 = 0;
+    }
+out:
+  return LOCAL_CHECKSUM;
+}
+
+int
+main ()
+{
+  if (func_1 (50, 0, 0) != 0)
+    __builtin_abort ();
+  return 0;
+}
index 6658eca4870d56219fa4465d295d220ca3b49872..30c9792fc1a80b7a770492db36de3cd9f112a11a 100644 (file)
@@ -3736,6 +3736,7 @@ maybe_skip_until (gimple *phi, tree &target, basic_block target_bb,
                  ao_ref *ref, tree vuse, bool tbaa_p, unsigned int &limit,
                  bitmap *visited, bool abort_on_visited,
                  void *(*translate)(ao_ref *, tree, void *, translate_flags *),
+                 bool (*is_backedge)(edge, void *),
                  translate_flags disambiguate_only,
                  void *data)
 {
@@ -3767,14 +3768,15 @@ maybe_skip_until (gimple *phi, tree &target, basic_block target_bb,
        }
 
       /* Recurse for PHI nodes.  */
-      if (gimple_code (def_stmt) == GIMPLE_PHI)
+      if (gphi *phi = dyn_cast <gphi *> (def_stmt))
        {
          /* An already visited PHI node ends the walk successfully.  */
-         if (bitmap_bit_p (*visited, SSA_NAME_VERSION (PHI_RESULT (def_stmt))))
+         if (bitmap_bit_p (*visited, SSA_NAME_VERSION (PHI_RESULT (phi))))
            return !abort_on_visited;
-         vuse = get_continuation_for_phi (def_stmt, ref, tbaa_p, limit,
+         vuse = get_continuation_for_phi (phi, ref, tbaa_p, limit,
                                           visited, abort_on_visited,
-                                          translate, data, disambiguate_only);
+                                          translate, data, is_backedge,
+                                          disambiguate_only);
          if (!vuse)
            return false;
          continue;
@@ -3819,12 +3821,13 @@ maybe_skip_until (gimple *phi, tree &target, basic_block target_bb,
    Returns NULL_TREE if no suitable virtual operand can be found.  */
 
 tree
-get_continuation_for_phi (gimple *phi, ao_ref *ref, bool tbaa_p,
+get_continuation_for_phi (gphi *phi, ao_ref *ref, bool tbaa_p,
                          unsigned int &limit, bitmap *visited,
                          bool abort_on_visited,
                          void *(*translate)(ao_ref *, tree, void *,
                                             translate_flags *),
                          void *data,
+                         bool (*is_backedge)(edge, void *),
                          translate_flags disambiguate_only)
 {
   unsigned nargs = gimple_phi_num_args (phi);
@@ -3867,15 +3870,14 @@ get_continuation_for_phi (gimple *phi, ao_ref *ref, bool tbaa_p,
       else if (! maybe_skip_until (phi, arg0, dom, ref, arg1, tbaa_p,
                                   limit, visited,
                                   abort_on_visited,
-                                  translate,
+                                  translate, is_backedge,
                                   /* Do not valueize when walking over
                                      backedges.  */
-                                  dominated_by_p
-                                    (CDI_DOMINATORS,
-                                     gimple_bb (SSA_NAME_DEF_STMT (arg1)),
-                                     phi_bb)
-                                  ? TR_DISAMBIGUATE
-                                  : disambiguate_only, data))
+                                  (is_backedge
+                                   && !is_backedge
+                                         (gimple_phi_arg_edge (phi, i), data))
+                                  ? disambiguate_only : TR_DISAMBIGUATE,
+                                  data))
        return NULL_TREE;
     }
 
@@ -3915,6 +3917,7 @@ walk_non_aliased_vuses (ao_ref *ref, tree vuse, bool tbaa_p,
                        void *(*walker)(ao_ref *, tree, void *),
                        void *(*translate)(ao_ref *, tree, void *,
                                           translate_flags *),
+                       bool (*is_backedge)(edge, void *),
                        tree (*valueize)(tree),
                        unsigned &limit, void *data)
 {
@@ -3952,9 +3955,10 @@ walk_non_aliased_vuses (ao_ref *ref, tree vuse, bool tbaa_p,
       def_stmt = SSA_NAME_DEF_STMT (vuse);
       if (gimple_nop_p (def_stmt))
        break;
-      else if (gimple_code (def_stmt) == GIMPLE_PHI)
-       vuse = get_continuation_for_phi (def_stmt, ref, tbaa_p, limit,
-                                        &visited, translated, translate, data);
+      else if (gphi *phi = dyn_cast <gphi *> (def_stmt))
+       vuse = get_continuation_for_phi (phi, ref, tbaa_p, limit,
+                                        &visited, translated, translate, data,
+                                        is_backedge);
       else
        {
          if ((int)limit <= 0)
index 3f2f7b66e60b20b609093b9e55787ac70ccc632e..e0785c5d4bb9d7f67e7a1142dc4e3b01cbb51257 100644 (file)
@@ -148,16 +148,19 @@ extern bool ref_can_have_store_data_races (tree);
 
 enum translate_flags
   { TR_TRANSLATE, TR_VALUEIZE_AND_DISAMBIGUATE, TR_DISAMBIGUATE };
-extern tree get_continuation_for_phi (gimple *, ao_ref *, bool,
+extern tree get_continuation_for_phi (gphi *, ao_ref *, bool,
                                      unsigned int &, bitmap *, bool,
                                      void *(*)(ao_ref *, tree, void *,
                                                translate_flags *),
-                                     void *, translate_flags
+                                     void *,
+                                     bool (*)(edge, void *) = nullptr,
+                                     translate_flags
                                        = TR_VALUEIZE_AND_DISAMBIGUATE);
 extern void *walk_non_aliased_vuses (ao_ref *, tree, bool,
                                     void *(*)(ao_ref *, tree, void *),
                                     void *(*)(ao_ref *, tree, void *,
                                               translate_flags *),
+                                    bool (*)(edge, void *),
                                     tree (*)(tree), unsigned &, void *);
 extern int walk_aliased_vdefs (ao_ref *, tree,
                               bool (*)(ao_ref *, tree, void *),
index d51341a1950ca1ccb863ac724d95f476b685ee37..9853be167d4a0e1bfdf3a62e96c855849532bb65 100644 (file)
@@ -1199,7 +1199,7 @@ translate_vuse_through_block (vec<vn_reference_op_s> operands,
                              tree type, tree vuse, edge e, bool *same_valid)
 {
   basic_block phiblock = e->dest;
-  gimple *phi = SSA_NAME_DEF_STMT (vuse);
+  gimple *def = SSA_NAME_DEF_STMT (vuse);
   ao_ref ref;
 
   if (same_valid)
@@ -1207,9 +1207,9 @@ translate_vuse_through_block (vec<vn_reference_op_s> operands,
 
   /* If value-numbering provided a memory state for this
      that dominates PHIBLOCK we can just use that.  */
-  if (gimple_nop_p (phi)
-      || (gimple_bb (phi) != phiblock
-         && dominated_by_p (CDI_DOMINATORS, phiblock, gimple_bb (phi))))
+  if (gimple_nop_p (def)
+      || (gimple_bb (def) != phiblock
+         && dominated_by_p (CDI_DOMINATORS, phiblock, gimple_bb (def))))
     return vuse;
 
   /* We have pruned expressions that are killed in PHIBLOCK via
@@ -1217,7 +1217,7 @@ translate_vuse_through_block (vec<vn_reference_op_s> operands,
      live at the start of the block.  If there is no virtual PHI to translate
      through return the VUSE live at entry.  Otherwise the VUSE to translate
      is the def of the virtual PHI node.  */
-  phi = get_virtual_phi (phiblock);
+  gphi *phi = get_virtual_phi (phiblock);
   if (!phi)
     return BB_LIVE_VOP_ON_EXIT
             (get_immediate_dominator (CDI_DOMINATORS, phiblock));
index ec163f20e1a77b219f85b89a4e94cabf9d3e81e3..6fda0ef604407c9ad71cace8a0ddf98183839afa 100644 (file)
@@ -369,6 +369,7 @@ static vn_tables_t valid_info;
 /* Global RPO state for access from hooks.  */
 static class eliminate_dom_walker *rpo_avail;
 basic_block vn_context_bb;
+int *vn_bb_to_rpo;
 
 
 /* Valueization hook for simplify_replace_tree.  Valueize NAME if it is
@@ -4023,6 +4024,16 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
   return (void *)-1;
 }
 
+/* Return true if E is a backedge with respect to our CFG walk order.  */
+
+static bool
+vn_is_backedge (edge e, void *)
+{
+  /* During PRE elimination we no longer have access to this info.  */
+  return (!vn_bb_to_rpo
+         || vn_bb_to_rpo[e->dest->index] <= vn_bb_to_rpo[e->src->index]);
+}
+
 /* Return a reference op vector from OP that can be used for
    vn_reference_lookup_pieces.  The caller is responsible for releasing
    the vector.  */
@@ -4104,8 +4115,8 @@ vn_reference_lookup_pieces (tree vuse, alias_set_type set,
        *vnresult
          = ((vn_reference_t)
             walk_non_aliased_vuses (&r, vr1.vuse, true, vn_reference_lookup_2,
-                                    vn_reference_lookup_3, vuse_valueize,
-                                    limit, &data));
+                                    vn_reference_lookup_3, vn_is_backedge,
+                                    vuse_valueize, limit, &data));
       if (ops_for_ref != shared_lookup_references)
        ops_for_ref.release ();
       gcc_checking_assert (vr1.operands == shared_lookup_references);
@@ -4250,8 +4261,8 @@ vn_reference_lookup (tree op, tree vuse, vn_lookup_kind kind,
       wvnresult
        = ((vn_reference_t)
           walk_non_aliased_vuses (&r, vr1.vuse, tbaa_p, vn_reference_lookup_2,
-                                  vn_reference_lookup_3, vuse_valueize, limit,
-                                  &data));
+                                  vn_reference_lookup_3, vn_is_backedge,
+                                  vuse_valueize, limit, &data));
       gcc_checking_assert (vr1.operands == shared_lookup_references);
       if (wvnresult)
        {
@@ -8749,6 +8760,7 @@ do_rpo_vn_1 (function *fn, edge entry, bitmap exit_bbs,
   int *bb_to_rpo = XNEWVEC (int, last_basic_block_for_fn (fn));
   for (int i = 0; i < n; ++i)
     bb_to_rpo[rpo[i]] = i;
+  vn_bb_to_rpo = bb_to_rpo;
 
   unwind_state *rpo_state = XNEWVEC (unwind_state, n);
 
@@ -9106,6 +9118,7 @@ do_rpo_vn_1 (function *fn, edge entry, bitmap exit_bbs,
 
   vn_valueize = NULL;
   rpo_avail = NULL;
+  vn_bb_to_rpo = NULL;
 
   XDELETEVEC (bb_to_rpo);
   XDELETEVEC (rpo);
index 048488ad6e8691d98c59b35f8177fb1c6c5448fb..828f214c7cbe6b5991558a48d27ce642c70f8f35 100644 (file)
@@ -340,7 +340,7 @@ avail_exprs_stack::lookup_avail_expr (gimple *stmt, bool insert, bool tbaa_p,
            && (ao_ref_init (&ref, gimple_assign_rhs1 (stmt)),
                ref.base_alias_set = ref.ref_alias_set = tbaa_p ? -1 : 0, true)
            && walk_non_aliased_vuses (&ref, vuse2, true, vuse_eq, NULL, NULL,
-                                      limit, vuse1) != NULL))
+                                      NULL, limit, vuse1) != NULL))
        {
          if (insert)
            {