Hi,

On Mon, Sep 21 2026, Josef Melcr wrote:
> 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));

I wonder whether we should instead add an assert

  gcc_assert (!ci || i >= old_nargs);

before the loop because in case of assumes, we'd better not ever enter
the loop. In that case we really must have the arguments to outlined
assume functions tightly under our control (so no varargs or no
incompatible calls), otherwise we'd simply trigger the checking assert
in callback_call_arg_summary anyway, no?

>      }
>  
>    /* 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);

Please make this a regular gcc_assert.

> +     }
> +    }
> +
>    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];

Perhaps we could add a checking assert the index is not -1 here?

But other than that, the patch is OK.

Thanks,

Martin


> +           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