Hi,

when reviewing various IPA bits and pieces I have discovered two
embarrassing problems with jump function duplication.

First, aggregate jump function vector copying contained a pasto where
the source is the (empty) destination vector and so no aggregate jump
functions ever got copied to jump functions of clones.

Second, the code did not copy value range information stored in the
jump functions, again not making them available for the inliner when
examining calls going out of IPA clones.

This patch fixes both issues and on top of that moves copying of
individual jump functions out of the duplication hook to a special
function because we expect it to be useful in creating jump functions
for planned call-graph edges that model transfer of control to OpenMP
outlined regions through calls to gomp functions.

Bootstrapped and tested on x86_64-linux, the whole patch series has
additionally passed LTO and profiled-LTO bootstrap on the same platform
and a bootstrap and testsuite on ppc64-linux.  Aarch64-linux bootstrap
and testing is in progress.  Because we have agreed with Honza this is
necessary last week, I consider the patch pre-approved and will commit
it later today.

Thanks,

Martin


gcc/ChangeLog:

2024-11-01  Martin Jambor  <mjam...@suse.cz>

        * ipa-prop.cc (ipa_duplicate_jump_function): New function.
        (ipa_edge_args_sum_t::duplicate): Move individual jump function
        copying to ipa_duplicate_jump_function.
---
 gcc/ipa-prop.cc | 187 ++++++++++++++++++++++++++----------------------
 1 file changed, 100 insertions(+), 87 deletions(-)

diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index add3a12b584..db8eda8c361 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -4497,6 +4497,105 @@ ipa_edge_args_sum_t::remove (cgraph_edge *cs, 
ipa_edge_args *args)
     }
 }
 
+/* Copy information from SRC_JF to DST_JF which correstpond to call graph edges
+   SRC and DST.  */
+
+static void
+ipa_duplicate_jump_function (cgraph_edge *src, cgraph_edge *dst,
+                            ipa_jump_func *src_jf, ipa_jump_func *dst_jf)
+{
+  dst_jf->agg.items = vec_safe_copy (src_jf->agg.items);
+
+  if (src_jf->type == IPA_JF_CONST)
+    {
+      struct ipa_cst_ref_desc *src_rdesc = jfunc_rdesc_usable (src_jf);
+
+      if (!src_rdesc)
+       dst_jf->value.constant.rdesc = NULL;
+      else if (src->caller == dst->caller)
+       {
+         /* Creation of a speculative edge.  If the source edge is the one
+            grabbing a reference, we must create a new (duplicate)
+            reference description.  Otherwise they refer to the same
+            description corresponding to a reference taken in a function
+            src->caller is inlined to.  In that case we just must
+            increment the refcount.  */
+         if (src_rdesc->cs == src)
+           {
+             symtab_node *n = symtab_node_for_jfunc (src_jf);
+             gcc_checking_assert (n);
+             ipa_ref *ref
+               = src->caller->find_reference (n, src->call_stmt,
+                                              src->lto_stmt_uid,
+                                              IPA_REF_ADDR);
+             gcc_checking_assert (ref);
+             dst->caller->clone_reference (ref, ref->stmt);
+
+             ipa_cst_ref_desc *dst_rdesc = ipa_refdesc_pool.allocate ();
+             dst_rdesc->cs = dst;
+             dst_rdesc->refcount = src_rdesc->refcount;
+             dst_rdesc->next_duplicate = NULL;
+             dst_jf->value.constant.rdesc = dst_rdesc;
+           }
+         else
+           {
+             src_rdesc->refcount++;
+             dst_jf->value.constant.rdesc = src_rdesc;
+           }
+       }
+      else if (src_rdesc->cs == src)
+       {
+         struct ipa_cst_ref_desc *dst_rdesc = ipa_refdesc_pool.allocate ();
+         dst_rdesc->cs = dst;
+         dst_rdesc->refcount = src_rdesc->refcount;
+         dst_rdesc->next_duplicate = src_rdesc->next_duplicate;
+         src_rdesc->next_duplicate = dst_rdesc;
+         dst_jf->value.constant.rdesc = dst_rdesc;
+       }
+      else
+       {
+         struct ipa_cst_ref_desc *dst_rdesc;
+         /* This can happen during inlining, when a JFUNC can refer to a
+            reference taken in a function up in the tree of inline clones.
+            We need to find the duplicate that refers to our tree of
+            inline clones.  */
+
+         gcc_assert (dst->caller->inlined_to);
+         for (dst_rdesc = src_rdesc->next_duplicate;
+              dst_rdesc;
+              dst_rdesc = dst_rdesc->next_duplicate)
+           {
+             struct cgraph_node *top;
+             top = dst_rdesc->cs->caller->inlined_to
+               ? dst_rdesc->cs->caller->inlined_to
+               : dst_rdesc->cs->caller;
+             if (dst->caller->inlined_to == top)
+               break;
+           }
+         gcc_assert (dst_rdesc);
+         dst_jf->value.constant.rdesc = dst_rdesc;
+       }
+    }
+  else if (dst_jf->type == IPA_JF_PASS_THROUGH
+          && src->caller == dst->caller)
+    {
+      struct cgraph_node *inline_root = dst->caller->inlined_to
+       ? dst->caller->inlined_to : dst->caller;
+      ipa_node_params *root_info = ipa_node_params_sum->get (inline_root);
+      int idx = ipa_get_jf_pass_through_formal_id (dst_jf);
+
+      int c = ipa_get_controlled_uses (root_info, idx);
+      if (c != IPA_UNDESCRIBED_USE)
+       {
+         c++;
+         ipa_set_controlled_uses (root_info, idx, c);
+       }
+    }
+
+  if (src_jf->m_vr && src_jf->m_vr->known_p ())
+    ipa_set_jfunc_vr (dst_jf, *src_jf->m_vr);
+}
+
 /* Method invoked when an edge is duplicated.  Copy ipa_edge_args and adjust
    reference count data strucutres accordingly.  */
 
@@ -4516,93 +4615,7 @@ ipa_edge_args_sum_t::duplicate (cgraph_edge *src, 
cgraph_edge *dst,
       struct ipa_jump_func *src_jf = ipa_get_ith_jump_func (old_args, i);
       struct ipa_jump_func *dst_jf = ipa_get_ith_jump_func (new_args, i);
 
-      dst_jf->agg.items = vec_safe_copy (dst_jf->agg.items);
-
-      if (src_jf->type == IPA_JF_CONST)
-       {
-         struct ipa_cst_ref_desc *src_rdesc = jfunc_rdesc_usable (src_jf);
-
-         if (!src_rdesc)
-           dst_jf->value.constant.rdesc = NULL;
-         else if (src->caller == dst->caller)
-           {
-             /* Creation of a speculative edge.  If the source edge is the one
-                grabbing a reference, we must create a new (duplicate)
-                reference description.  Otherwise they refer to the same
-                description corresponding to a reference taken in a function
-                src->caller is inlined to.  In that case we just must
-                increment the refcount.  */
-             if (src_rdesc->cs == src)
-               {
-                  symtab_node *n = symtab_node_for_jfunc (src_jf);
-                  gcc_checking_assert (n);
-                  ipa_ref *ref
-                    = src->caller->find_reference (n, src->call_stmt,
-                                                   src->lto_stmt_uid,
-                                                   IPA_REF_ADDR);
-                  gcc_checking_assert (ref);
-                  dst->caller->clone_reference (ref, ref->stmt);
-
-                  ipa_cst_ref_desc *dst_rdesc = ipa_refdesc_pool.allocate ();
-                  dst_rdesc->cs = dst;
-                  dst_rdesc->refcount = src_rdesc->refcount;
-                  dst_rdesc->next_duplicate = NULL;
-                  dst_jf->value.constant.rdesc = dst_rdesc;
-               }
-             else
-               {
-                 src_rdesc->refcount++;
-                 dst_jf->value.constant.rdesc = src_rdesc;
-               }
-           }
-         else if (src_rdesc->cs == src)
-           {
-             struct ipa_cst_ref_desc *dst_rdesc = ipa_refdesc_pool.allocate ();
-             dst_rdesc->cs = dst;
-             dst_rdesc->refcount = src_rdesc->refcount;
-             dst_rdesc->next_duplicate = src_rdesc->next_duplicate;
-             src_rdesc->next_duplicate = dst_rdesc;
-             dst_jf->value.constant.rdesc = dst_rdesc;
-           }
-         else
-           {
-             struct ipa_cst_ref_desc *dst_rdesc;
-             /* This can happen during inlining, when a JFUNC can refer to a
-                reference taken in a function up in the tree of inline clones.
-                We need to find the duplicate that refers to our tree of
-                inline clones.  */
-
-             gcc_assert (dst->caller->inlined_to);
-             for (dst_rdesc = src_rdesc->next_duplicate;
-                  dst_rdesc;
-                  dst_rdesc = dst_rdesc->next_duplicate)
-               {
-                 struct cgraph_node *top;
-                 top = dst_rdesc->cs->caller->inlined_to
-                   ? dst_rdesc->cs->caller->inlined_to
-                   : dst_rdesc->cs->caller;
-                 if (dst->caller->inlined_to == top)
-                   break;
-               }
-             gcc_assert (dst_rdesc);
-             dst_jf->value.constant.rdesc = dst_rdesc;
-           }
-       }
-      else if (dst_jf->type == IPA_JF_PASS_THROUGH
-              && src->caller == dst->caller)
-       {
-         struct cgraph_node *inline_root = dst->caller->inlined_to
-           ? dst->caller->inlined_to : dst->caller;
-         ipa_node_params *root_info = ipa_node_params_sum->get (inline_root);
-         int idx = ipa_get_jf_pass_through_formal_id (dst_jf);
-
-         int c = ipa_get_controlled_uses (root_info, idx);
-         if (c != IPA_UNDESCRIBED_USE)
-           {
-             c++;
-             ipa_set_controlled_uses (root_info, idx, c);
-           }
-       }
+      ipa_duplicate_jump_function (src, dst, src_jf, dst_jf);
     }
 }
 
-- 
2.47.0

Reply via email to