https://gcc.gnu.org/g:660de7e0a3cd8f1ddf6719d3cfe0a6b452557f9c

commit 660de7e0a3cd8f1ddf6719d3cfe0a6b452557f9c
Author: Josef Melcr <melcr...@fit.cvut.cz>
Date:   Sun Mar 30 19:37:22 2025 +0200

    omp-cp: multiple callbacks in progress
    
    gcc/ChangeLog:
    
            * attr-callback.h (callback_edge_useful_p): New function.
            * cgraph.cc (cgraph_edge::purge_callback_children): New
            function.
            (cgraph_edge::redirect_call_stmt_to_callee): Add redirection
            skipping for callback edges.
            * cgraph.h: Declarations.
            * ipa-cp.cc (purge_useless_callback_edges): New function.
            (ipcp_decision_stage): Integrate the above function.
            * ipa-param-manipulation.cc 
(drop_decl_attribute_if_params_changed_p): New predicate.
            (ipa_param_adjustments::build_new_function_type): Add output
            parameter.
            (ipa_param_adjustments::adjust_decl): Add attribute dropping.
            * ipa-param-manipulation.h: Change signature.
            * tree-core.h (ECF_CB_1_0): New constant for callback attribute.
            (ECF_CB_1_2): Likewise.
            (ECF_CB_2_4): Likewise.
            (ECF_CB_3_0_2): Likewise.
            * tree.cc (set_call_expr_flags): Integrate the above flags.
    
    gcc/fortran/ChangeLog:
    
            * f95-lang.cc (ATTR_CALLBACK_GOMP_LIST): Add constant for list,
            see builtin-attrs.def.
            (ATTR_CALLBACK_GOMP_TASK_LIST): Likewise.
            (ATTR_CALLBACK_OACC_LIST): Likewise.
    
    Signed-off-by: Josef Melcr <melcr...@fit.cvut.cz>

Diff:
---
 gcc/attr-callback.h           | 11 ++++++++++
 gcc/cgraph.cc                 | 20 ++++++++++++++++++
 gcc/cgraph.h                  |  3 +++
 gcc/fortran/f95-lang.cc       |  4 ++++
 gcc/ipa-cp.cc                 | 47 ++++++++++++++++++++++++++++++++++++++++++-
 gcc/ipa-param-manipulation.cc | 28 ++++++++++++++++++++++++--
 gcc/ipa-param-manipulation.h  |  2 +-
 gcc/tree-core.h               | 14 +++++++++++++
 gcc/tree.cc                   | 43 +++++++++++++++++++++++++++++++++++++++
 9 files changed, 168 insertions(+), 4 deletions(-)

diff --git a/gcc/attr-callback.h b/gcc/attr-callback.h
index ea9c9cbbc780..b6a1a0c4106c 100644
--- a/gcc/attr-callback.h
+++ b/gcc/attr-callback.h
@@ -270,4 +270,15 @@ handle_callback_attribute (tree *node, tree name, tree 
args,
   return NULL_TREE;
 }
 
+inline bool
+callback_edge_useful_p (cgraph_edge *e)
+{
+  gcc_checking_assert (e->callback);
+  /* If the edge is not pointing towards a clone, it is no longer useful as its
+     entire purpose is to produce clones of callbacks. */
+  if (!e->callee->clone_of)
+    return false;
+  return true;
+}
+
 #endif /* ATTR_CALLBACK_H  */
diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
index e032cc0b4864..3bcfe1f2da12 100644
--- a/gcc/cgraph.cc
+++ b/gcc/cgraph.cc
@@ -1248,6 +1248,19 @@ cgraph_edge::next_callback_target ()
   return e;
 }
 
+void
+cgraph_edge::purge_callback_children ()
+{
+  gcc_checking_assert (has_callback);
+  cgraph_edge *e, *next;
+  for (e = first_callback_target (); e; e = next)
+    {
+      next = e->next_callback_target ();
+      cgraph_edge::remove (e);
+    }
+  has_callback = false;
+}
+
 /* Speculative call consists of an indirect edge and one or more
    direct edge+ref pairs.
 
@@ -1610,6 +1623,13 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge 
*e,
      redirecting to. */
   if (e->callback)
     {
+      cgraph_edge *parent = e->get_callback_parent_edge ();
+      if (!lookup_attribute ("callback",
+                            DECL_ATTRIBUTES (parent->callee->decl)))
+       /* Callback attribute is removed if the offloading function changes
+          signature, as the indices would be correct anymore. These edges will
+          get cleaned up later, ignore their redirection for now. */
+       return e->call_stmt;
       int fn_idx
        = callback_fetch_fn_position (e->call_stmt, DECL_ATTRIBUTES (decl),
                                      e->callee->decl);
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 044639793486..18756cf9f4f8 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -1753,6 +1753,9 @@ public:
   /* TODO DOCS */
   cgraph_edge *next_callback_target ();
 
+  /* TODO DOCS */
+  void purge_callback_children ();
+
   /* Speculative call consists of an indirect edge and one or more
      direct edge+ref pairs.  Speculative will expand to the following sequence:
 
diff --git a/gcc/fortran/f95-lang.cc b/gcc/fortran/f95-lang.cc
index aed19a9822ee..1c4b4b0de3d8 100644
--- a/gcc/fortran/f95-lang.cc
+++ b/gcc/fortran/f95-lang.cc
@@ -574,6 +574,10 @@ gfc_builtin_function (tree decl)
 #define ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST \
                                        (ECF_COLD | ECF_NORETURN | \
                                         ECF_NOTHROW | ECF_LEAF)
+#define ATTR_CALLBACK_GOMP_LIST (ECF_CB_1_2 | ATTR_NOTHROW_LIST)
+#define ATTR_CALLBACK_GOMP_TASK_LIST \
+  (ECF_CB_3_0_2 | ECF_CB_1_0 | ATTR_NOTHROW_LIST)
+#define ATTR_CALLBACK_OACC_LIST (ECF_CB_2_4 | ATTR_NOTHROW_LIST)
 
 static void
 gfc_define_builtin (const char *name, tree type, enum built_in_function code,
diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index e6d707c286db..b259e51d8e74 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -131,7 +131,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "symtab-clones.h"
 #include "gimple-range.h"
-
+#include "attr-callback.h"
 
 /* Allocation pools for values and their sources in ipa-cp.  */
 
@@ -6208,6 +6208,49 @@ identify_dead_nodes (struct cgraph_node *node)
     }
 }
 
+static void
+purge_useless_callback_edges ()
+{
+  if (dump_file)
+    fprintf (dump_file, "\nPurging useless callback edges:\n");
+
+  cgraph_edge *e;
+  cgraph_node *node;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+    {
+      for (e = node->callees; e; e = e->next_callee)
+       {
+         if (e->has_callback)
+           {
+             if (dump_file)
+               fprintf (dump_file, "\tExamining children of edge %s -> %s:\n",
+                        e->caller->name (), e->callee->name ());
+             if (!lookup_attribute ("callback",
+                                    DECL_ATTRIBUTES (e->callee->decl)))
+               {
+                 if (dump_file)
+                   fprintf (dump_file,
+                            "\t\tPurging children, because the offloading "
+                            "function no longer has any callback 
attributes.\n");
+                 e->purge_callback_children ();
+                 continue;
+               }
+                   cgraph_edge *cbe, *next;
+                   for (cbe = e->first_callback_target(); cbe; cbe = next) {
+          next = cbe->next_callback_target();
+          if (!callback_edge_useful_p(cbe)) {
+            if (dump_file)
+              fprintf(dump_file, "\t\tCallback edge %s -> %s not deemed 
useful, removing.\n", cbe->caller->name(), cbe->callee->name());
+            cgraph_edge::remove(cbe);
+          }
+                   }
+           }
+       }
+    }
+  if (dump_file)
+    fprintf(dump_file, "\n");
+}
+
 /* The decision stage.  Iterate over the topological order of call graph nodes
    TOPO and make specialized clones if deemed beneficial.  */
 
@@ -6238,6 +6281,8 @@ ipcp_decision_stage (class ipa_topo_info *topo)
       if (change)
        identify_dead_nodes (node);
     }
+  if (0)
+  purge_useless_callback_edges();
 }
 
 /* Look up all VR and bits information that we have discovered and copy it
diff --git a/gcc/ipa-param-manipulation.cc b/gcc/ipa-param-manipulation.cc
index ad36b8389c00..13abedf100a4 100644
--- a/gcc/ipa-param-manipulation.cc
+++ b/gcc/ipa-param-manipulation.cc
@@ -308,6 +308,14 @@ drop_type_attribute_if_params_changed_p (tree name)
   return false;
 }
 
+static bool
+drop_decl_attribute_if_params_changed_p (tree name)
+{
+  if (is_attribute_p ("callback", name))
+    return true;
+  return false;
+}
+
 /* Build and return a function type just like ORIG_TYPE but with parameter
    types given in NEW_PARAM_TYPES - which can be NULL if, but only if,
    ORIG_TYPE itself has NULL TREE_ARG_TYPEs.  If METHOD2FUNC is true, also make
@@ -492,7 +500,7 @@ ipa_param_adjustments::method2func_p (tree orig_type)
 
 tree
 ipa_param_adjustments::build_new_function_type (tree old_type,
-                                               bool type_original_p)
+                                               bool type_original_p, bool 
*args_modified /* = NULL */)
 {
   auto_vec<tree,16> new_param_types, *new_param_types_p;
   if (prototype_p (old_type))
@@ -518,6 +526,8 @@ ipa_param_adjustments::build_new_function_type (tree 
old_type,
          || get_original_index (index) != (int)index)
        modified = true;
 
+  if (args_modified)
+    *args_modified = modified;
 
   return build_adjusted_function_type (old_type, new_param_types_p,
                                       method2func_p (old_type), m_skip_return,
@@ -536,10 +546,11 @@ ipa_param_adjustments::adjust_decl (tree orig_decl)
 {
   tree new_decl = copy_node (orig_decl);
   tree orig_type = TREE_TYPE (orig_decl);
+  bool args_modified = false;
   if (prototype_p (orig_type)
       || (m_skip_return && !VOID_TYPE_P (TREE_TYPE (orig_type))))
     {
-      tree new_type = build_new_function_type (orig_type, false);
+      tree new_type = build_new_function_type (orig_type, false, 
&args_modified);
       TREE_TYPE (new_decl) = new_type;
     }
   if (method2func_p (orig_type))
@@ -556,6 +567,19 @@ ipa_param_adjustments::adjust_decl (tree orig_decl)
   if (m_skip_return)
     DECL_IS_MALLOC (new_decl) = 0;
 
+  if (args_modified && DECL_ATTRIBUTES (new_decl))
+    {
+      tree t = DECL_ATTRIBUTES (new_decl);
+      tree *last = &DECL_ATTRIBUTES (new_decl);
+      DECL_ATTRIBUTES (new_decl) = NULL;
+      for (; t; t = TREE_CHAIN (t))
+       if (!drop_decl_attribute_if_params_changed_p (get_attribute_name (t)))
+         {
+           *last = copy_node (t);
+           TREE_CHAIN (*last) = NULL;
+           last = &TREE_CHAIN (*last);
+         }
+    }
   return new_decl;
 }
 
diff --git a/gcc/ipa-param-manipulation.h b/gcc/ipa-param-manipulation.h
index 8dd5e5bdeaee..adf4321a10d4 100644
--- a/gcc/ipa-param-manipulation.h
+++ b/gcc/ipa-param-manipulation.h
@@ -229,7 +229,7 @@ public:
   /* Return if the first parameter is left intact.  */
   bool first_param_intact_p ();
   /* Build a function type corresponding to the modified call.  */
-  tree build_new_function_type (tree old_type, bool type_is_original_p);
+  tree build_new_function_type (tree old_type, bool type_is_original_p, bool 
*args_modified = NULL);
   /* Build a declaration corresponding to the target of the modified call.  */
   tree adjust_decl (tree orig_decl);
   /* Fill a vector marking which parameters are intact by the described
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 1776c154d94e..7d9c2154415d 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -98,6 +98,20 @@ struct die_struct;
 /* Nonzero if this is a function expected to end with an exception.  */
 #define ECF_XTHROW               (1 << 16)
 
+/* Flags for various callback attribute combinations. */
+
+/* callback(1, 0) */
+#define ECF_CB_1_0      (1 << 17)
+
+/* callback(1, 2) */
+#define ECF_CB_1_2      (1 << 18)
+
+/* callback(2, 4) */
+#define ECF_CB_2_4      (1 << 19)
+
+/* callback(3, 0, 2) */
+#define ECF_CB_3_0_2    (1 << 20)
+
 /* Call argument flags.  */
 
 /* Nonzero if the argument is not used by the function.  */
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 83a03374a325..5d0bf03281a4 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -9817,6 +9817,7 @@ build_common_tree_nodes (bool signed_char)
 void
 set_call_expr_flags (tree decl, int flags)
 {
+  // ahoj
   if (flags & ECF_NOTHROW)
     TREE_NOTHROW (decl) = 1;
   if (flags & ECF_CONST)
@@ -9850,6 +9851,48 @@ set_call_expr_flags (tree decl, int flags)
     DECL_ATTRIBUTES (decl)
       = tree_cons (get_identifier ("expected_throw"),
                   NULL, DECL_ATTRIBUTES (decl));
+
+  if (flags & ECF_CB_1_0)
+    {
+      tree args
+       = tree_cons (NULL_TREE, build_int_cst (integer_type_node, 1),
+                    build_tree_list (NULL_TREE,
+                                     build_int_cst (integer_type_node, 0)));
+      DECL_ATTRIBUTES (decl)
+       = tree_cons (get_identifier ("callback"), args, DECL_ATTRIBUTES (decl));
+    }
+
+  if (flags & ECF_CB_1_2)
+    {
+      tree args
+       = tree_cons (NULL_TREE, build_int_cst (integer_type_node, 1),
+                    build_tree_list (NULL_TREE,
+                                     build_int_cst (integer_type_node, 2)));
+      DECL_ATTRIBUTES (decl)
+       = tree_cons (get_identifier ("callback"), args, DECL_ATTRIBUTES (decl));
+    }
+
+  if (flags & ECF_CB_2_4)
+    {
+      tree args
+       = tree_cons (NULL_TREE, build_int_cst (integer_type_node, 2),
+                    build_tree_list (NULL_TREE,
+                                     build_int_cst (integer_type_node, 4)));
+      DECL_ATTRIBUTES (decl)
+       = tree_cons (get_identifier ("callback"), args, DECL_ATTRIBUTES (decl));
+    }
+
+  if (flags & ECF_CB_3_0_2)
+    {
+      tree args = tree_cons (
+       NULL_TREE, build_int_cst (integer_type_node, 3),
+       tree_cons (NULL_TREE, build_int_cst (integer_type_node, 0),
+                  build_tree_list (NULL_TREE,
+                                   build_int_cst (integer_type_node, 2))));
+      DECL_ATTRIBUTES (decl)
+       = tree_cons (get_identifier ("callback"), args, DECL_ATTRIBUTES (decl));
+    }
+
   /* Looping const or pure is implied by noreturn.
      There is currently no way to declare looping const or looping pure alone. 
 */
   gcc_assert (!(flags & ECF_LOOPING_CONST_OR_PURE)

Reply via email to