This patch adds logic for internal callback edge redirection and
modification of their call statements.

Internal callback edges need to be redirected in a different manner
compared to their regular counterparts.  Because we have their call
statements under complete control, we can implement call statement
modifications beyond simple address replacement.  Functions for call
modification need to be adjusted to accommodate for this.

modify_call_stmt creates a summary describing what changes were done so
far.  This summary contains indices of arguments which need to be remapped.

modify_call also needed to have its indices remapped, as the summaries
describing changes to be made follow the indexing of the assume
function, not the call statement.

Both functions now include a branch for the creation of an internal
IFN_ASSUME call statement.

gcc/ChangeLog:

        * cgraph.cc (cgraph_edge::redirect_call_stmt_to_callee): Add
        redirection logic for internal edges.
        * ipa-param-manipulation.cc (ipa_param_adjustments::modify_call):
        Adjust argument modifications for callback edges.
        (ipa_param_body_adjustments::modify_call_stmt): Likewise.

Signed-off-by: Josef Melcr <[email protected]>
---
 gcc/cgraph.cc                 | 21 ++++++++++++++
 gcc/ipa-param-manipulation.cc | 54 ++++++++++++++++++++++++++++++-----
 2 files changed, 68 insertions(+), 7 deletions(-)

diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
index 6dab18cf298..76b8f70878d 100644
--- a/gcc/cgraph.cc
+++ b/gcc/cgraph.cc
@@ -1903,6 +1903,27 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge 
*e,
       callback_redirect_edge (e);
       return e->call_stmt;
     }
+  /* Callback calls to .ASSUME bodies might need to have their statement
+     rebuilt.  */
+  else if (e->callback && e->callee->assume_function)
+    {
+      ipa_param_adjustments *padjs
+       = callee_info ? callee_info->param_adjustments : NULL;
+
+      /* If there are no param adjustments, replace the address in the call
+        statement.  */
+      if (!padjs)
+       callback_redirect_edge (e);
+      else
+       {
+         new_stmt = padjs->modify_call (e, false, killed_ssas);
+         gcc_checking_assert (callback_ifn_assume_call_p (new_stmt));
+         e->caller->set_call_stmt_including_clones (e->call_stmt, new_stmt,
+                                                    false);
+       }
+      return e->call_stmt;
+    }
+  gcc_checking_assert (!e->callback);
 
   if (decl && ipa_saved_clone_sources)
     {
diff --git a/gcc/ipa-param-manipulation.cc b/gcc/ipa-param-manipulation.cc
index 0f384848ce5..571f87583b2 100644
--- a/gcc/ipa-param-manipulation.cc
+++ b/gcc/ipa-param-manipulation.cc
@@ -50,7 +50,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "sreal.h"
 #include "ipa-cp.h"
 #include "ipa-prop.h"
+#include "data-streamer.h"
 #include "attr-callback.h"
+#include "callback-info.h"
 
 /* Actual prefixes of different newly synthesized parameters.  Keep in sync
    with IPA_PARAM_PREFIX_* defines.  */
@@ -719,7 +721,17 @@ ipa_param_adjustments::modify_call (cgraph_edge *cs,
 
   unsigned len = vec_safe_length (m_adj_params);
   auto_vec<tree, 16> vargs (len);
-  unsigned old_nargs = gimple_call_num_args (stmt);
+  /* Argument remapping has to be used in this function, because it builds the
+     new call statement from the parameter descriptors, rather than the actual
+     arguments, as in ipa_param_adjustments::modify_call_stmt.  */
+  callback_info *ci = callback_info_sum->get (cs);
+
+  /* Callback edges should be here only if they are pointing towards .ASSUME
+     bodies, which always have a complete argument mapping.  */
+  if (ci)
+    gcc_assert (cs->callee->assume_function);
+
+  unsigned old_nargs = callback_call_num_args_summary (stmt, ci);
   unsigned orig_nargs = mod_info ? mod_info->index_map.length () : old_nargs;
   auto_vec<bool, 16> kept (old_nargs);
   kept.quick_grow_cleared (old_nargs);
@@ -728,6 +740,9 @@ ipa_param_adjustments::modify_call (cgraph_edge *cs,
   if (update_references)
     current_node->remove_stmt_references (stmt);
 
+  if (cs->callback && cs->callee->assume_function)
+    vargs.safe_push (build_fold_addr_expr (callee_decl));
+
   gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
   gimple_stmt_iterator prev_gsi = gsi;
   gsi_prev (&prev_gsi);
@@ -747,7 +762,7 @@ ipa_param_adjustments::modify_call (cgraph_edge *cs,
              gcc_assert (index >= 0);
            }
 
-         tree arg = gimple_call_arg (stmt, index);
+         tree arg = callback_call_arg_summary (stmt, index, ci);
 
          vargs.quick_push (arg);
          kept[index] = true;
@@ -797,7 +812,7 @@ ipa_param_adjustments::modify_call (cgraph_edge *cs,
          index = mod_info->index_map[apm->base_index];
          gcc_assert (index >= 0);
        }
-      tree base = gimple_call_arg (stmt, index);
+      tree base = callback_call_arg_summary (stmt, index, ci);
 
       /* We create a new parameter out of the value of the old one, we can
         do the following kind of transformations:
@@ -920,7 +935,7 @@ ipa_param_adjustments::modify_call (cgraph_edge *cs,
          gcc_assert (always_copy_start >= 0);
        }
       for (unsigned i = always_copy_start; i < old_nargs; i++)
-       vargs.safe_push (gimple_call_arg (stmt, i));
+       vargs.safe_push (callback_call_arg_summary (stmt, i, ci));
     }
 
   /* For optimized away parameters, add on the caller side
@@ -1005,7 +1020,11 @@ ipa_param_adjustments::modify_call (cgraph_edge *cs,
       print_gimple_stmt (dump_file, gsi_stmt (gsi), 0);
     }
 
-  gcall *new_stmt = gimple_build_call_vec (callee_decl, vargs);
+  gcall *new_stmt;
+  if (cs->callback && cs->callee->assume_function)
+    new_stmt = gimple_build_call_internal_vec (IFN_ASSUME, vargs);
+  else
+    new_stmt = gimple_build_call_vec (callee_decl, vargs);
 
   hash_set <tree> *ssas_to_remove = NULL;
   if (tree lhs = gimple_call_lhs (stmt))
@@ -2224,6 +2243,18 @@ ipa_param_body_adjustments::modify_call_stmt (gcall 
**stmt_p,
   bool recreate = false;
   gcc_assert (m_sorted_replacements_p);
 
+  callback_info *ci = NULL;
+  if (callback_ifn_assume_call_p (orig_stmt))
+    {
+      cgraph_edge *cbei = cgraph_node::get (m_fndecl)->get_edge (orig_stmt);
+      if (cbei)
+       {
+         gcc_checking_assert (cbei->callback);
+         ci = callback_info_sum->get (cbei);
+         gcc_checking_assert (ci);
+       }
+    }
+
   for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
     {
       tree t = gimple_call_arg (stmt, i);
@@ -2349,7 +2380,12 @@ ipa_param_body_adjustments::modify_call_stmt (gcall 
**stmt_p,
              if (m_replacements[j].unit_offset < agg_arg_offset)
                continue;
              pass_through_split_map pt_map;
-             pt_map.base_index = i;
+             /* The base index wouldn't match for callback calls, as the
+                analysis is done on their remapped indices.  */
+             if (ci)
+               pt_map.base_index = ci->inverted_mapping[i];
+             else
+               pt_map.base_index = i;
              pt_map.unit_offset
                = m_replacements[j].unit_offset - agg_arg_offset;
              pt_map.new_index = new_arg_idx;
@@ -2379,7 +2415,11 @@ ipa_param_body_adjustments::modify_call_stmt (gcall 
**stmt_p,
        }
     }
 
-  gcall *new_stmt = gimple_build_call_vec (gimple_call_fn (stmt), vargs);
+  gcall *new_stmt;
+  if (callback_ifn_assume_call_p (orig_stmt))
+    new_stmt = gimple_build_call_internal_vec (IFN_ASSUME, vargs);
+  else
+    new_stmt = gimple_build_call_vec (gimple_call_fn (stmt), vargs);
   if (gimple_has_location (stmt))
     gimple_set_location (new_stmt, gimple_location (stmt));
   gimple_call_set_chain (new_stmt, gimple_call_chain (stmt));
-- 
2.55.0

Reply via email to