On Tue, Apr 27, 2021 at 5:25 PM Martin Jambor <mjam...@suse.cz> wrote:
>
> Hi,
>
> PR 93385 reveals that if the user explicitely disables DCE, IPA-SRA
> can leave behind statements which are useless because their results
> are eventually not used but can have problematic side effects,
> especially since their inputs are now bogus that useless parameters
> were removed.
>
> This patch fixes the problem by doing a def-use walk when
> materializing clones, marking which statements should not be copied
> and which SSA_NAMEs do not need to be computed because eventually they
> would be DCEd.
>
> When an argument of a call within such a function is removed,
> however, that change needs to be communicated to call redirection code.
> This is call specific information and therefore cannot be reasonably
> encoded in clone node summary and has to be put in call summaries.
> Combining these with stuff in performed_splits in clone_info would be
> very cumbersome and therefore this patch removes performed_splits and
> moves all information it into call summaries too.  This has also the
> advantage that the code is hopefully a bit easier to understand and we
> do not need any special dummy variables.
>
> The new edge summaries are private to ipa-param-manipulation.c and
> hopefully will never be needed elsewhere.  It simply contains 1) a
> mapping from the original argument indices to the actual indices in the
> call statement as it is now, 2) information needed to identify
> arguments representing pass-through IPA-SRA splits with which have
> been added to the call arguments in place of an original
> argument/reference and 3) a delta to the index where va_args may
> start.
>
> Bootstrapped and tested on x86_64-linux, i686-linux and aarch64-linux.
> Also LTO-bootstrapped and LTO-profiledbootstrapped on x86_64-linux.
>
> OK for trunk?

I've tried to have a look at this patch but it does a lot of IPA specific
refactoring(?), so the actual DCE bits are hard to find.  Is it possible
to split the patch up or is it too entangled?

Thanks,
Richard.

> Thanks,
>
> Martin
>
>
> gcc/ChangeLog:
>
> 2021-03-24  Martin Jambor  <mjam...@suse.cz>
>
>         PR ipa/93385
>         * symtab-clones.h (clone_info): Removed member param_adjustments.
>         * ipa-param-manipulation.h: Adjust initial comment to reflect how we
>         deal with pass-through splits now.
>         (ipa_param_performed_split): Removed.
>         (ipa_param_adjustments::modify_call): Adjusted parameters.
>         (class ipa_param_body_adjustments): New members m_dead_stmts,
>         m_dead_ssas, mark_dead_statements, modify_call_argument and
>         m_new_call_arg_modification_info.  Adjusted parameters of
>         register_replacement, modify_gimple_stmt and modify_call_stmt.
>         (ipa_verify_edge_has_no_modifications): Declare.
>         * ipa-param-manipulation.c (struct pass_through_split_map): New type.
>         (ipa_edge_modification_info): Likewise.
>         (ipa_edge_modification_sum): Likewise.
>         (ipa_edge_modifications): New edge summary.
>         (ipa_verify_edge_has_no_modifications): New function.
>         (transitive_split_p): Removed.
>         (transitive_split_map): Likewise.
>         (init_transitive_splits): Likewise.
>         (ipa_param_adjustments::modify_call): Adjusted to use the new edge
>         summary instead of performed_splits.
>         (ipa_param_body_adjustments::register_replacement): Drop dummy
>         parameter, set base_index of the created ipa_param_body_replacement.
>         (phi_arg_will_live_p): New function.
>         (ipa_param_body_adjustments::mark_dead_statements): New method.
>         (ipa_param_body_adjustments::common_initialization): Call it.  Do not
>         create IPA_SRA dummy decls.
>         (ipa_param_body_adjustments::ipa_param_body_adjustments): Initialize
>         new mwmbers.
>         (simple_tree_swap_info): Removed.
>         (remap_split_decl_to_dummy): Likewise.
>         (record_argument_state_1): New function.
>         (record_argument_state): Likewise.
>         (ipa_param_body_adjustments::modify_call_stmt): New parameter
>         orig_stmt.  Do not work with dummy decls, save necessary info about
>         changes to ipa_edge_modifications.
>         (ipa_param_body_adjustments::modify_gimple_stmt): New parameter
>         orig_stmt, pass it to modify_call_stmt.
>         (ipa_param_body_adjustments::modify_cfun_body): Adjust call to
>         modify_gimple_stmt.
>         * tree-inline.c (remap_gimple_stmt): Do not copy dead statements,
>         reset dead debug statements, pass original statement to
>         modify_gimple_stmt.
>         (copy_phis_for_bb): Do not copy dead PHI nodes.
>         (expand_call_inline): Do not remap performed_splits.
>         (update_clone_info): Likewise.
>
> gcc/testsuite/ChangeLog:
>
> 2021-03-22  Martin Jambor  <mjam...@suse.cz>
>
>         PR ipa/93385
>         * gcc.dg/ipa/pr93385.c: New test.
>         * gcc.dg/ipa/ipa-sra-23.c: Likewise.
>         * gcc.dg/ipa/ipa-sra-24.c: Likewise.
>         * g++.dg/ipa/ipa-sra-4.C: Likewise.
> ---
>  gcc/cgraph.c                          |  22 +-
>  gcc/cgraphclones.c                    |   3 -
>  gcc/ipa-param-manipulation.c          | 916 ++++++++++++++++----------
>  gcc/ipa-param-manipulation.h          |  92 ++-
>  gcc/symtab-clones.h                   |  15 +-
>  gcc/testsuite/g++.dg/ipa/ipa-sra-4.C  |  37 ++
>  gcc/testsuite/gcc.dg/ipa/ipa-sra-23.c |  24 +
>  gcc/testsuite/gcc.dg/ipa/ipa-sra-24.c |  20 +
>  gcc/testsuite/gcc.dg/ipa/pr93385.c    |  27 +
>  gcc/tree-inline.c                     | 121 +---
>  10 files changed, 721 insertions(+), 556 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/ipa/ipa-sra-4.C
>  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-23.c
>  create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-24.c
>  create mode 100644 gcc/testsuite/gcc.dg/ipa/pr93385.c
>
> diff --git a/gcc/cgraph.c b/gcc/cgraph.c
> index d7c78d518bc..d473da5a325 100644
> --- a/gcc/cgraph.c
> +++ b/gcc/cgraph.c
> @@ -1506,8 +1506,6 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge 
> *e)
>      }
>
>    clone_info *callee_info = clone_info::get (e->callee);
> -  clone_info *caller_info = clone_info::get (e->caller);
> -
>    if (symtab->dump_file)
>      {
>        fprintf (symtab->dump_file, "updating call of %s -> %s: ",
> @@ -1515,18 +1513,6 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge 
> *e)
>        print_gimple_stmt (symtab->dump_file, e->call_stmt, 0, dump_flags);
>        if (callee_info && callee_info->param_adjustments)
>         callee_info->param_adjustments->dump (symtab->dump_file);
> -      unsigned performed_len
> -       = caller_info ? vec_safe_length (caller_info->performed_splits) : 0;
> -      if (performed_len > 0)
> -       fprintf (symtab->dump_file, "Performed splits records:\n");
> -      for (unsigned i = 0; i < performed_len; i++)
> -       {
> -         ipa_param_performed_split *sm
> -           = &(*caller_info->performed_splits)[i];
> -         print_node_brief (symtab->dump_file, "  dummy_decl: ", 
> sm->dummy_decl,
> -                           TDF_UID);
> -         fprintf (symtab->dump_file, ", unit_offset: %u\n", sm->unit_offset);
> -       }
>      }
>
>    if (ipa_param_adjustments *padjs
> @@ -1541,10 +1527,7 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge 
> *e)
>         remove_stmt_from_eh_lp (e->call_stmt);
>
>        tree old_fntype = gimple_call_fntype (e->call_stmt);
> -      new_stmt = padjs->modify_call (e->call_stmt,
> -                                    caller_info
> -                                    ? caller_info->performed_splits : NULL,
> -                                    e->callee->decl, false);
> +      new_stmt = padjs->modify_call (e, false);
>        cgraph_node *origin = e->callee;
>        while (origin->clone_of)
>         origin = origin->clone_of;
> @@ -1564,6 +1547,9 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge 
> *e)
>      }
>    else
>      {
> +      if (flag_checking
> +         && !fndecl_built_in_p (e->callee->decl, BUILT_IN_UNREACHABLE))
> +       ipa_verify_edge_has_no_modifications (e);
>        new_stmt = e->call_stmt;
>        gimple_call_set_fndecl (new_stmt, e->callee->decl);
>        update_stmt_fn (DECL_STRUCT_FUNCTION (e->caller->decl), new_stmt);
> diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c
> index 9f86463b42d..7e463acab91 100644
> --- a/gcc/cgraphclones.c
> +++ b/gcc/cgraphclones.c
> @@ -414,9 +414,6 @@ cgraph_node::create_clone (tree new_decl, profile_count 
> prof_count,
>    else if (info && info->param_adjustments)
>      clone_info::get_create (new_node)->param_adjustments
>          = info->param_adjustments;
> -  if (info && info->performed_splits)
> -    clone_info::get_create (new_node)->performed_splits
> -        = vec_safe_copy (info->performed_splits);
>    new_node->split_part = split_part;
>
>    FOR_EACH_VEC_ELT (redirect_callers, i, e)
> diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c
> index 132bb24f76a..3e07fd72fe2 100644
> --- a/gcc/ipa-param-manipulation.c
> +++ b/gcc/ipa-param-manipulation.c
> @@ -62,6 +62,80 @@ static const char 
> *ipa_param_op_names[IPA_PARAM_PREFIX_COUNT]
>       "IPA_PARAM_OP_NEW",
>       "IPA_PARAM_OP_SPLIT"};
>
> +/* Structure to hold declarations representing pass-through IPA-SRA splits.  
> In
> +   essence, it tells new index for a combination of original index and
> +   offset.  */
> +
> +struct pass_through_split_map
> +{
> +  /* Original argument index.  */
> +  unsigned base_index;
> +  /* Offset of the split part in the original argument.  */
> +  unsigned unit_offset;
> +  /* Index of the split part in the call statement - where clone
> +     materialization put it.  */
> +  int new_index;
> +};
> +
> +/* Information about some call statements that needs to be conveyed from 
> clone
> +   materialization to edge redirection. */
> +
> +class ipa_edge_modification_info
> +{
> + public:
> +  ipa_edge_modification_info ()
> +    {}
> +
> +  /* Mapping of original argument indices to where those arguments sit in the
> +     call statement now or to a negative index if they were removed.  */
> +  auto_vec<int> index_map;
> +  /* Information about ISRA replacements put into the call statement at the
> +     clone materialization stages.  */
> +  auto_vec<pass_through_split_map> pass_through_map;
> +  /* Necessary adjustment to ipa_param_adjustments::m_always_copy_start when
> +     redirecting the call.  */
> +  int always_copy_delta = 0;
> +};
> +
> +/* Class for storing and retrieving summaries about cal statement
> +   modifications.  */
> +
> +class ipa_edge_modification_sum
> +  : public call_summary <ipa_edge_modification_info *>
> +{
> + public:
> +  ipa_edge_modification_sum (symbol_table *table)
> +    : call_summary<ipa_edge_modification_info *> (table)
> +  {
> +  }
> +
> +  /* Hook that is called by summary when an edge is duplicated.  */
> +
> +  virtual void duplicate (cgraph_edge *,
> +                         cgraph_edge *,
> +                         ipa_edge_modification_info *old_info,
> +                         ipa_edge_modification_info *new_info)
> +  {
> +    new_info->index_map.safe_splice (old_info->index_map);
> +    new_info->pass_through_map.safe_splice (old_info->pass_through_map);
> +    new_info->always_copy_delta = old_info->always_copy_delta;
> +  }
> +};
> +
> +/* Call summary to store information about edges which have had their 
> arguments
> +   partially modified already.  */
> +
> +static ipa_edge_modification_sum *ipa_edge_modifications;
> +
> +/* Fail compilation if CS has any summary associated with it in
> +   ipa_edge_modifications.  */
> +
> +DEBUG_FUNCTION void
> +ipa_verify_edge_has_no_modifications (cgraph_edge *cs)
> +{
> +  gcc_assert (!ipa_edge_modifications || !ipa_edge_modifications->get (cs));
> +}
> +
>  /* Fill an empty vector ARGS with PARM_DECLs representing formal parameters 
> of
>     FNDECL.  The function should not be called during LTO WPA phase except for
>     thunks (or functions with bodies streamed in). */
> @@ -459,147 +533,46 @@ isra_get_ref_base_and_offset (tree expr, tree *base_p, 
> unsigned *unit_offset_p)
>    return true;
>  }
>
> -/* Return true if EXPR describes a transitive split (i.e. one that happened 
> for
> -   both the caller and the callee) as recorded in PERFORMED_SPLITS.  In that
> -   case, store index of the respective record in PERFORMED_SPLITS into
> -   *SM_IDX_P and the unit offset from all handled components in EXPR into
> -   *UNIT_OFFSET_P.  */
> -
> -static bool
> -transitive_split_p (vec<ipa_param_performed_split, va_gc> *performed_splits,
> -                   tree expr, unsigned *sm_idx_p, unsigned *unit_offset_p)
> -{
> -  tree base;
> -  if (!isra_get_ref_base_and_offset (expr, &base, unit_offset_p))
> -    return false;
> -
> -  if (TREE_CODE (base) == SSA_NAME)
> -    {
> -      base = SSA_NAME_VAR (base);
> -      if (!base)
> -       return false;
> -    }
> -
> -  unsigned len = vec_safe_length (performed_splits);
> -  for (unsigned i = 0 ; i < len; i++)
> -    {
> -      ipa_param_performed_split *sm = &(*performed_splits)[i];
> -      if (sm->dummy_decl == base)
> -       {
> -         *sm_idx_p = i;
> -         return true;
> -       }
> -    }
> -  return false;
> -}
> -
> -/* Structure to hold declarations representing transitive IPA-SRA splits.  In
> -   essence, if we need to pass UNIT_OFFSET of a parameter which originally 
> has
> -   number BASE_INDEX, we should pass down REPL.  */
> -
> -struct transitive_split_map
> -{
> -  tree repl;
> -  unsigned base_index;
> -  unsigned unit_offset;
> -};
> -
> -/* If call STMT contains any parameters representing transitive splits as
> -   described by PERFORMED_SPLITS, return the number of extra parameters that
> -   were addded during clone materialization and fill in INDEX_MAP with 
> adjusted
> -   indices of corresponding original parameters and TRANS_MAP with 
> description
> -   of all transitive replacement descriptions.  Otherwise return zero. */
> -
> -static unsigned
> -init_transitive_splits (vec<ipa_param_performed_split, va_gc> 
> *performed_splits,
> -                       gcall *stmt, vec <unsigned> *index_map,
> -                       auto_vec <transitive_split_map> *trans_map)
> -{
> -  unsigned phony_arguments = 0;
> -  unsigned stmt_idx = 0, base_index = 0;
> -  unsigned nargs = gimple_call_num_args (stmt);
> -  while (stmt_idx < nargs)
> -    {
> -      unsigned unit_offset_delta;
> -      tree base_arg = gimple_call_arg (stmt, stmt_idx);
> -
> -      if (phony_arguments > 0)
> -       index_map->safe_push (stmt_idx);
> -
> -      unsigned sm_idx;
> -      stmt_idx++;
> -      if (transitive_split_p (performed_splits, base_arg, &sm_idx,
> -                             &unit_offset_delta))
> -       {
> -         if (phony_arguments == 0)
> -           /* We have optimistically avoided constructing index_map do far 
> but
> -              now it is clear it will be necessary, so let's create the easy
> -              bit we skipped until now.  */
> -           for (unsigned k = 0; k < stmt_idx; k++)
> -             index_map->safe_push (k);
> -
> -         tree dummy = (*performed_splits)[sm_idx].dummy_decl;
> -         for (unsigned j = sm_idx; j < performed_splits->length (); j++)
> -           {
> -             ipa_param_performed_split *caller_split
> -               = &(*performed_splits)[j];
> -             if (caller_split->dummy_decl != dummy)
> -               break;
> -
> -             tree arg = gimple_call_arg (stmt, stmt_idx);
> -             struct transitive_split_map tsm;
> -             tsm.repl = arg;
> -             tsm.base_index = base_index;
> -             if (caller_split->unit_offset >= unit_offset_delta)
> -               {
> -                 tsm.unit_offset
> -                   = (caller_split->unit_offset - unit_offset_delta);
> -                 trans_map->safe_push (tsm);
> -               }
> -
> -             phony_arguments++;
> -             stmt_idx++;
> -           }
> -       }
> -      base_index++;
> -    }
> -  return phony_arguments;
> -}
> -
> -/* Modify actual arguments of a function call in statement STMT, assuming it
> -   calls CALLEE_DECL.  CALLER_ADJ must be the description of parameter
> -   adjustments of the caller or NULL if there are none.  Return the new
> -   statement that replaced the old one.  When invoked, cfun and
> -   current_function_decl have to be set to the caller.  */
> +/* Modify actual arguments of a function call in statement currently 
> belonging
> +   to CS, and make it call CS->callee->decl.  Return the new statement that
> +   replaced the old one.  When invoked, cfun and current_function_decl have 
> to
> +   be set to the caller.  */
>
>  gcall *
> -ipa_param_adjustments::modify_call (gcall *stmt,
> -                                   vec<ipa_param_performed_split,
> -                                       va_gc> *performed_splits,
> -                                   tree callee_decl, bool update_references)
> +ipa_param_adjustments::modify_call (cgraph_edge *cs,
> +                                   bool update_references)
>  {
> +  gcall *stmt = cs->call_stmt;
> +  tree callee_decl = cs->callee->decl;
> +
> +  ipa_edge_modification_info *mod_info
> +    = ipa_edge_modifications ? ipa_edge_modifications->get (cs) : NULL;
> +  if (mod_info && symtab->dump_file)
> +    {
> +      fprintf (symtab->dump_file, "Information about pre-exiting "
> +              "modifications.\n  Index map:");
> +      unsigned idx_len = mod_info->index_map.length ();
> +      for (unsigned i = 0; i < idx_len; i++)
> +       fprintf (symtab->dump_file, " %i", mod_info->index_map[i]);
> +      fprintf (symtab->dump_file, "\n  Pass-through split map: ");
> +      unsigned ptm_len = mod_info->pass_through_map.length ();
> +      for (unsigned i = 0; i < ptm_len; i++)
> +       fprintf (symtab->dump_file,
> +                " (base_index: %u, offset: %u, new_index: %i)",
> +                mod_info->pass_through_map[i].base_index,
> +                mod_info->pass_through_map[i].unit_offset,
> +                mod_info->pass_through_map[i].new_index);
> +      fprintf (symtab->dump_file, "\n  Always-copy delta: %i\n",
> +              mod_info->always_copy_delta);
> +    }
> +
>    unsigned len = vec_safe_length (m_adj_params);
>    auto_vec<tree, 16> vargs (len);
> -  tree old_decl = gimple_call_fndecl (stmt);
>    unsigned old_nargs = gimple_call_num_args (stmt);
> +  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);
>
> -  auto_vec <unsigned, 16> index_map;
> -  auto_vec <transitive_split_map> trans_map;
> -  bool transitive_remapping = false;
> -
> -  if (performed_splits)
> -    {
> -      unsigned removed = init_transitive_splits (performed_splits,
> -                                                stmt, &index_map, 
> &trans_map);
> -      if (removed > 0)
> -       {
> -         transitive_remapping = true;
> -         old_nargs -= removed;
> -       }
> -    }
> -
>    cgraph_node *current_node = cgraph_node::get (current_function_decl);
>    if (update_references)
>      current_node->remove_stmt_references (stmt);
> @@ -612,13 +585,16 @@ ipa_param_adjustments::modify_call (gcall *stmt,
>        ipa_adjusted_param *apm = &(*m_adj_params)[i];
>        if (apm->op == IPA_PARAM_OP_COPY)
>         {
> -         unsigned index = apm->base_index;
> -         if (index >= old_nargs)
> +         int index = apm->base_index;
> +         if ((unsigned) index >= orig_nargs)
>             /* Can happen if the original call has argument mismatch,
>                ignore.  */
>             continue;
> -         if (transitive_remapping)
> -           index = index_map[apm->base_index];
> +         if (mod_info)
> +           {
> +             index = mod_info->index_map[apm->base_index];
> +             gcc_assert (index >= 0);
> +           }
>
>           tree arg = gimple_call_arg (stmt, index);
>
> @@ -636,14 +612,17 @@ ipa_param_adjustments::modify_call (gcall *stmt,
>          materialization.  */
>        gcc_assert (apm->op == IPA_PARAM_OP_SPLIT);
>
> -      /* We have to handle transitive changes differently using the maps we
> -        have created before.  So look into them first.  */
> +      /* We have to handle pass-through changes differently using the map
> +        clone materialziation might have left behind.  */
>        tree repl = NULL_TREE;
> -      for (unsigned j = 0; j < trans_map.length (); j++)
> -       if (trans_map[j].base_index == apm->base_index
> -           && trans_map[j].unit_offset == apm->unit_offset)
> +      unsigned ptm_len = mod_info ? mod_info->pass_through_map.length () : 0;
> +      for (unsigned j = 0; j < ptm_len; j++)
> +       if (mod_info->pass_through_map[j].base_index == apm->base_index
> +           && mod_info->pass_through_map[j].unit_offset == apm->unit_offset)
>           {
> -           repl = trans_map[j].repl;
> +           int repl_idx = mod_info->pass_through_map[j].new_index;
> +           gcc_assert (repl_idx >= 0);
> +           repl = gimple_call_arg (stmt, repl_idx);
>             break;
>           }
>        if (repl)
> @@ -652,12 +631,15 @@ ipa_param_adjustments::modify_call (gcall *stmt,
>           continue;
>         }
>
> -      unsigned index = apm->base_index;
> -      if (index >= old_nargs)
> +      int index = apm->base_index;
> +      if ((unsigned) index >= orig_nargs)
>         /* Can happen if the original call has argument mismatch, ignore.  */
>         continue;
> -      if (transitive_remapping)
> -       index = index_map[apm->base_index];
> +      if (mod_info)
> +       {
> +         index = mod_info->index_map[apm->base_index];
> +         gcc_assert (index >= 0);
> +       }
>        tree base = gimple_call_arg (stmt, index);
>
>        /* We create a new parameter out of the value of the old one, we can
> @@ -773,8 +755,16 @@ ipa_param_adjustments::modify_call (gcall *stmt,
>      }
>
>    if (m_always_copy_start >= 0)
> -    for (unsigned i = m_always_copy_start; i < old_nargs; i++)
> -      vargs.safe_push (gimple_call_arg (stmt, i));
> +    {
> +      int always_copy_start = m_always_copy_start;
> +      if (mod_info)
> +       {
> +         always_copy_start += mod_info->always_copy_delta;
> +         gcc_assert (always_copy_start >= 0);
> +       }
> +      for (unsigned i = always_copy_start; i < old_nargs; i++)
> +       vargs.safe_push (gimple_call_arg (stmt, i));
> +    }
>
>    /* For optimized away parameters, add on the caller side
>       before the call
> @@ -782,6 +772,7 @@ ipa_param_adjustments::modify_call (gcall *stmt,
>       stmts and associate D#X with parm in decl_debug_args_lookup
>       vector to say for debug info that if parameter parm had been passed,
>       it would have value parm_Y(D).  */
> +  tree old_decl = gimple_call_fndecl (stmt);
>    if (MAY_HAVE_DEBUG_BIND_STMTS && old_decl && callee_decl)
>      {
>        vec<tree, va_gc> **debug_args = NULL;
> @@ -799,13 +790,17 @@ ipa_param_adjustments::modify_call (gcall *stmt,
>         {
>           if (!is_gimple_reg (old_parm) || kept[i])
>             continue;
> -         tree origin = DECL_ORIGIN (old_parm);
>           tree arg;
> -         if (transitive_remapping)
> -           arg = gimple_call_arg (stmt, index_map[i]);
> +         if (mod_info)
> +           {
> +             if (mod_info->index_map[i] < 0)
> +               continue;
> +             arg = gimple_call_arg (stmt, mod_info->index_map[i]);
> +           }
>           else
>             arg = gimple_call_arg (stmt, i);
>
> +         tree origin = DECL_ORIGIN (old_parm);
>           if (!useless_type_conversion_p (TREE_TYPE (origin), TREE_TYPE 
> (arg)))
>             {
>               if (!fold_convertible_p (TREE_TYPE (origin), arg))
> @@ -905,6 +900,9 @@ ipa_param_adjustments::modify_call (gcall *stmt,
>         gsi_prev (&gsi);
>        }
>      while (gsi_stmt (gsi) != gsi_stmt (prev_gsi));
> +
> +  if (mod_info)
> +    ipa_edge_modifications->remove (cs);
>    return new_stmt;
>  }
>
> @@ -927,13 +925,11 @@ ipa_param_adjustments::debug ()
>    dump (stderr);
>  }
>
> -/* Register that REPLACEMENT should replace parameter described in APM and
> -   optionally as DUMMY to mark transitive splits across calls.  */
> +/* Register that REPLACEMENT should replace parameter described in APM.  */
>
>  void
>  ipa_param_body_adjustments::register_replacement (ipa_adjusted_param *apm,
> -                                                 tree replacement,
> -                                                 tree dummy)
> +                                                 tree replacement)
>  {
>    gcc_checking_assert (apm->op == IPA_PARAM_OP_SPLIT
>                        || apm->op == IPA_PARAM_OP_NEW);
> @@ -941,7 +937,6 @@ ipa_param_body_adjustments::register_replacement 
> (ipa_adjusted_param *apm,
>    ipa_param_body_replacement psr;
>    psr.base = m_oparms[apm->prev_clone_index];
>    psr.repl = replacement;
> -  psr.dummy = dummy;
>    psr.unit_offset = apm->unit_offset;
>    m_replacements.safe_push (psr);
>  }
> @@ -970,6 +965,97 @@ ipa_param_body_adjustments::carry_over_param (tree t)
>    return new_parm;
>  }
>
> +/* Return true if BLOCKS_TO_COPY is NULL or if PHI has an argument ARG in
> +   position that corresponds to an edge that is coming from a block that has
> +   the corresponding bit set in BLOCKS_TO_COPY.  */
> +
> +static bool
> +phi_arg_will_live_p (gphi *phi, bitmap blocks_to_copy, tree arg)
> +{
> +  bool arg_will_survive = false;
> +  if (!blocks_to_copy)
> +    arg_will_survive = true;
> +  else
> +    for (unsigned i = 0; i < gimple_phi_num_args (phi); i++)
> +      if (gimple_phi_arg_def (phi, i) == arg
> +         && bitmap_bit_p (blocks_to_copy,
> +                          gimple_phi_arg_edge (phi, i)->src->index))
> +       {
> +         arg_will_survive = true;
> +         break;
> +       }
> +  return arg_will_survive;
> +}
> +
> +/* Populate m_dead_stmts given that DEAD_PARAM is going to be removed without
> +   any replacement or splitting.  REPL is the replacement VAR_SECL to base 
> any
> +   remaining uses of a removed parameter on.  */
> +
> +void
> +ipa_param_body_adjustments::mark_dead_statements (tree dead_param)
> +{
> +  /* Current IPA analyses which remove unused parameters never remove a
> +     non-gimple register ones which have any use except as parameters in 
> other
> +     calls, so we can safely leve them as they are.  */
> +  if (!is_gimple_reg (dead_param))
> +    return;
> +  tree parm_ddef = ssa_default_def (m_id->src_cfun, dead_param);
> +  if (!parm_ddef || has_zero_uses (parm_ddef))
> +    return;
> +
> +  auto_vec<tree, 4> stack;
> +  m_dead_ssas.add (parm_ddef);
> +  stack.safe_push (parm_ddef);
> +  while (!stack.is_empty ())
> +    {
> +      tree t = stack.pop ();
> +
> +      imm_use_iterator imm_iter;
> +      gimple *stmt;
> +
> +      insert_decl_map (m_id, t, error_mark_node);
> +      FOR_EACH_IMM_USE_STMT (stmt, imm_iter, t)
> +       {
> +         if (is_gimple_call (stmt)
> +             || (m_id->blocks_to_copy
> +                 && !bitmap_bit_p (m_id->blocks_to_copy,
> +                                   gimple_bb (stmt)->index)))
> +           continue;
> +
> +         if (is_gimple_debug (stmt))
> +           {
> +             m_dead_stmts.add (stmt);
> +             gcc_assert (gimple_debug_bind_p (stmt));
> +           }
> +         else if (gimple_code (stmt) == GIMPLE_PHI)
> +           {
> +             gphi *phi = as_a <gphi *> (stmt);
> +             if (phi_arg_will_live_p (phi, m_id->blocks_to_copy, t))
> +               {
> +                 m_dead_stmts.add (phi);
> +                 tree res = gimple_phi_result (phi);
> +                 if (!m_dead_ssas.add (res))
> +                   stack.safe_push (res);
> +               }
> +           }
> +         else if (is_gimple_assign (stmt))
> +           {
> +             m_dead_stmts.add (stmt);
> +             if (!gimple_clobber_p (stmt))
> +               {
> +                 tree lhs = gimple_assign_lhs (stmt);
> +                 gcc_assert (TREE_CODE (lhs) == SSA_NAME);
> +                 if (!m_dead_ssas.add (lhs))
> +                   stack.safe_push (lhs);
> +               }
> +           }
> +         else
> +           /* IPA-SRA does not analyze other types of statements.  */
> +           gcc_unreachable ();
> +       }
> +    }
> +}
> +
>  /* Common initialization performed by all ipa_param_body_adjustments
>     constructors.  OLD_FNDECL is the declaration we take original arguments
>     from, (it may be the same as M_FNDECL).  VARS, if non-NULL, is a pointer 
> to
> @@ -1003,9 +1089,9 @@ ipa_param_body_adjustments::common_initialization (tree 
> old_fndecl,
>    auto_vec<bool, 16> kept;
>    kept.reserve_exact (m_oparms.length ());
>    kept.quick_grow_cleared (m_oparms.length ());
> -  auto_vec<tree, 16> isra_dummy_decls;
> -  isra_dummy_decls.reserve_exact (m_oparms.length ());
> -  isra_dummy_decls.quick_grow_cleared (m_oparms.length ());
> +  auto_vec<bool, 16> split;
> +  split.reserve_exact (m_oparms.length ());
> +  split.quick_grow_cleared (m_oparms.length ());
>
>    unsigned adj_len = vec_safe_length (m_adj_params);
>    m_method2func = ((TREE_CODE (TREE_TYPE (m_fndecl)) == METHOD_TYPE)
> @@ -1051,35 +1137,8 @@ ipa_param_body_adjustments::common_initialization 
> (tree old_fndecl,
>           if (apm->op == IPA_PARAM_OP_SPLIT)
>             {
>               m_split_modifications_p = true;
> -
> -             if (m_id)
> -               {
> -                 tree dummy_decl;
> -                 if (!isra_dummy_decls[prev_index])
> -                   {
> -                     dummy_decl = copy_decl_to_var (m_oparms[prev_index],
> -                                                    m_id);
> -                     /* Any attempt to remap this dummy in this particular
> -                        instance of clone materialization should yield
> -                        itself.  */
> -                     insert_decl_map (m_id, dummy_decl, dummy_decl);
> -
> -                     DECL_CHAIN (dummy_decl) = *vars;
> -                     *vars = dummy_decl;
> -                     isra_dummy_decls[prev_index] = dummy_decl;
> -                   }
> -                 else
> -                   dummy_decl = isra_dummy_decls[prev_index];
> -
> -                 register_replacement (apm, new_parm, dummy_decl);
> -                 ipa_param_performed_split ps;
> -                 ps.dummy_decl = dummy_decl;
> -                 ps.unit_offset = apm->unit_offset;
> -                 vec_safe_push (clone_info::get_create
> -                                  (m_id->dst_node)->performed_splits, ps);
> -               }
> -             else
> -               register_replacement (apm, new_parm);
> +             split[prev_index] = true;
> +             register_replacement (apm, new_parm);
>             }
>          }
>        else
> @@ -1106,13 +1165,16 @@ ipa_param_body_adjustments::common_initialization 
> (tree old_fndecl,
>           {
>             if (!m_id->decl_map->get (m_oparms[i]))
>               {
> -               /* TODO: Perhaps at least aggregate-type params could re-use
> -                  their isra_dummy_decl here?  */
>                 tree var = copy_decl_to_var (m_oparms[i], m_id);
>                 insert_decl_map (m_id, m_oparms[i], var);
>                 /* Declare this new variable.  */
>                 DECL_CHAIN (var) = *vars;
>                 *vars = var;
> +
> +               /* If this is not a split but a real removal, init hash sets
> +                  that will guide what not to copy to the new body.  */
> +               if (!split[i])
> +                 mark_dead_statements (m_oparms[i]);
>               }
>           }
>         else
> @@ -1169,9 +1231,10 @@ ipa_param_body_adjustments
>  ::ipa_param_body_adjustments (vec<ipa_adjusted_param, va_gc> *adj_params,
>                               tree fndecl)
>    : m_adj_params (adj_params), m_adjustments (NULL), m_reset_debug_decls (),
> -    m_split_modifications_p (false), m_fndecl (fndecl), m_id (NULL),
> -    m_oparms (), m_new_decls (), m_new_types (), m_replacements (),
> -    m_removed_decls (), m_removed_map (), m_method2func (false)
> +    m_split_modifications_p (false), m_dead_stmts (), m_dead_ssas (),
> +    m_fndecl (fndecl), m_id (NULL), m_oparms (), m_new_decls (),
> +    m_new_types (), m_replacements (), m_removed_decls (), m_removed_map (),
> +    m_method2func (false), m_new_call_arg_modification_info (false)
>  {
>    common_initialization (fndecl, NULL, NULL);
>  }
> @@ -1185,10 +1248,10 @@ ipa_param_body_adjustments
>  ::ipa_param_body_adjustments (ipa_param_adjustments *adjustments,
>                               tree fndecl)
>    : m_adj_params (adjustments->m_adj_params), m_adjustments (adjustments),
> -    m_reset_debug_decls (), m_split_modifications_p (false), m_fndecl 
> (fndecl),
> -    m_id (NULL), m_oparms (), m_new_decls (), m_new_types (),
> -    m_replacements (), m_removed_decls (), m_removed_map (),
> -    m_method2func (false)
> +    m_reset_debug_decls (), m_split_modifications_p (false), m_dead_stmts (),
> +    m_dead_ssas (), m_fndecl (fndecl), m_id (NULL), m_oparms (), m_new_decls 
> (),
> +    m_new_types (), m_replacements (), m_removed_decls (), m_removed_map (),
> +    m_method2func (false), m_new_call_arg_modification_info (false)
>  {
>    common_initialization (fndecl, NULL, NULL);
>  }
> @@ -1208,9 +1271,10 @@ ipa_param_body_adjustments
>                               copy_body_data *id, tree *vars,
>                               vec<ipa_replace_map *, va_gc> *tree_map)
>    : m_adj_params (adjustments->m_adj_params), m_adjustments (adjustments),
> -    m_reset_debug_decls (), m_split_modifications_p (false), m_fndecl 
> (fndecl),
> -    m_id (id), m_oparms (), m_new_decls (), m_new_types (), m_replacements 
> (),
> -    m_removed_decls (), m_removed_map (), m_method2func (false)
> +    m_reset_debug_decls (), m_split_modifications_p (false), m_dead_stmts (),
> +    m_dead_ssas (),m_fndecl (fndecl), m_id (id), m_oparms (), m_new_decls (),
> +    m_new_types (), m_replacements (), m_removed_decls (), m_removed_map (),
> +    m_method2func (false), m_new_call_arg_modification_info (false)
>  {
>    common_initialization (old_fndecl, vars, tree_map);
>  }
> @@ -1498,218 +1562,338 @@ ipa_param_body_adjustments::modify_assignment 
> (gimple *stmt,
>    return any;
>  }
>
> -/* Data passed to remap_split_decl_to_dummy through walk_tree.  */
> +/* Record information about what modifications to call arguments have already
> +   been done by clone materialization into a summary describing CS.  The
> +   information is stored in NEW_INDEX_MAP, NEW_PT_MAP and 
> NEW_ALWAYS_COPY_DELTA
> +   and correspond to equivalent fields in ipa_edge_modification_info.  Return
> +   the edge summary.  */
> +
> +static ipa_edge_modification_info *
> +record_argument_state_1 (cgraph_edge *cs, const vec<int> &new_index_map,
> +                        const vec<pass_through_split_map> &new_pt_map,
> +                        int new_always_copy_delta)
>
> -struct simple_tree_swap_info
>  {
> -  /* Change FROM to TO.  */
> -  tree from, to;
> -  /* And set DONE to true when doing so.  */
> -  bool done;
> -};
> +  ipa_edge_modification_info *sum = ipa_edge_modifications->get_create (cs);
>
> -/* Simple remapper to remap a split parameter to the same expression based 
> on a
> -   special dummy decl so that edge redirections can detect transitive 
> splitting
> -   and finish them.  */
> -
> -static tree
> -remap_split_decl_to_dummy (tree *tp, int *walk_subtrees, void *data)
> -{
> -  tree t = *tp;
> -
> -  if (DECL_P (t) || TREE_CODE (t) == SSA_NAME)
> +  unsigned len = sum->pass_through_map.length ();
> +  for (unsigned i = 0; i < len; i++)
>      {
> -      struct simple_tree_swap_info *swapinfo
> -       = (struct simple_tree_swap_info *) data;
> -      if (t == swapinfo->from
> -         || (TREE_CODE (t) == SSA_NAME
> -             && SSA_NAME_VAR (t) == swapinfo->from))
> -       {
> -         *tp = swapinfo->to;
> -         swapinfo->done = true;
> -       }
> -      *walk_subtrees = 0;
> +      unsigned oldnew = sum->pass_through_map[i].new_index;
> +      sum->pass_through_map[i].new_index = new_index_map[oldnew];
> +    }
> +
> +  len = sum->index_map.length ();
> +  if (len > 0)
> +    {
> +      unsigned nptlen = new_pt_map.length ();
> +      for (unsigned j = 0; j < nptlen; j++)
> +       {
> +         int inverse = -1;
> +         for (unsigned i = 0; i < len ; i++)
> +           if ((unsigned) sum->index_map[i] == new_pt_map[j].base_index)
> +           {
> +             inverse = i;
> +             break;
> +           }
> +         gcc_assert (inverse >= 0);
> +         pass_through_split_map ptm_item;
> +
> +         ptm_item.base_index = inverse;
> +         ptm_item.unit_offset = new_pt_map[j].unit_offset;
> +         ptm_item.new_index = new_pt_map[j].new_index;
> +         sum->pass_through_map.safe_push (ptm_item);
> +       }
> +
> +      for (unsigned i = 0; i < len; i++)
> +       {
> +         int idx = sum->index_map[i];
> +         if (idx < 0)
> +           continue;
> +         sum->index_map[i] = new_index_map[idx];
> +       }
>      }
> -  else if (TYPE_P (t))
> -      *walk_subtrees = 0;
>    else
> -    *walk_subtrees = 1;
> -  return NULL_TREE;
> +    {
> +      sum->pass_through_map.safe_splice (new_pt_map);
> +      sum->index_map.safe_splice (new_index_map);
> +    }
> +  sum->always_copy_delta += new_always_copy_delta;
> +  return sum;
>  }
>
> +/* Record information about what modifications to call arguments have already
> +   been done by clone materialization into a summary of an edge describing 
> the
> +   call in this clone and all its clones.  NEW_INDEX_MAP, NEW_PT_MAP and
> +   NEW_ALWAYS_COPY_DELTA have the same meaning as record_argument_state_1.
> +
> +   In order to associate the info with the right edge summaries, we need
> +   address of the ORIG_STMT in the function from which we are cloning 
> (because
> +   the edges have not yet been re-assigned to the new statement that has just
> +   been created) and ID, the structure governing function body copying.  */
> +
> +static void
> +record_argument_state (copy_body_data *id, gimple *orig_stmt,
> +                      const vec<int> &new_index_map,
> +                      const vec<pass_through_split_map> &new_pt_map,
> +                      int new_always_copy_delta)
> +{
> +  if (!ipa_edge_modifications)
> +    ipa_edge_modifications = new ipa_edge_modification_sum (symtab);
> +
> +  struct cgraph_node *this_node = id->dst_node;
> +  ipa_edge_modification_info *first_sum = NULL;
> +  cgraph_edge *cs = this_node->get_edge (orig_stmt);
> +  if (cs)
> +    first_sum = record_argument_state_1 (cs, new_index_map, new_pt_map,
> +                                        new_always_copy_delta);
> +  else
> +    gcc_assert (this_node->clones);
> +
> +  if (!this_node->clones)
> +    return;
> +  for (cgraph_node *subclone = this_node->clones; subclone != this_node;)
> +    {
> +      cs = subclone->get_edge (orig_stmt);
> +      if (cs)
> +       {
> +         if (!first_sum)
> +           first_sum = record_argument_state_1 (cs, new_index_map, 
> new_pt_map,
> +                                                new_always_copy_delta);
> +         else
> +           {
> +             ipa_edge_modification_info *s2
> +               = ipa_edge_modifications->get_create (cs);
> +             s2->index_map.truncate (0);
> +             s2->index_map.safe_splice (first_sum->index_map);
> +             s2->pass_through_map.truncate (0);
> +             s2->pass_through_map.safe_splice (first_sum->pass_through_map);
> +             s2->always_copy_delta = first_sum->always_copy_delta;
> +           }
> +       }
> +      else
> +       gcc_assert (subclone->clones);
> +
> +      if (subclone->clones)
> +       subclone = subclone->clones;
> +      else if (subclone->next_sibling_clone)
> +       subclone = subclone->next_sibling_clone;
> +      else
> +       {
> +         while (subclone != this_node && !subclone->next_sibling_clone)
> +           subclone = subclone->clone_of;
> +         if (subclone != this_node)
> +           subclone = subclone->next_sibling_clone;
> +       }
> +    }
> +}
>
>  /* If the call statement pointed at by STMT_P contains any expressions that
>     need to replaced with a different one as noted by ADJUSTMENTS, do so.  f 
> the
>     statement needs to be rebuilt, do so.  Return true if any modifications 
> have
> -   been performed.
> +   been performed.  ORIG_STMT, if not NULL, is the original statement in the
> +   function that is being cloned from, which at this point can be used to 
> look
> +   up call_graph edges.
>
>     If the method is invoked as a part of IPA clone materialization and if any
> -   parameter split is transitive, i.e. it applies to the functin that is 
> being
> -   modified and also to the callee of the statement, replace the parameter
> -   passed to old callee with an equivalent expression based on a dummy decl
> -   followed by PARM_DECLs representing the actual replacements.  The actual
> -   replacements will be then converted into SSA_NAMEs and then
> -   ipa_param_adjustments::modify_call will find the appropriate ones and 
> leave
> -   only those in the call.  */
> +   parameter split is pass-through, i.e. it applies to the functin that is
> +   being modified and also to the callee of the statement, replace the
> +   parameter passed to old callee with all of the replacement a callee might
> +   possibly want and record the performed argument modifications in
> +   ipa_edge_modifications.  Likewise if any argument has already been left 
> out
> +   because it is not necessary.  */
>
>  bool
> -ipa_param_body_adjustments::modify_call_stmt (gcall **stmt_p)
> +ipa_param_body_adjustments::modify_call_stmt (gcall **stmt_p,
> +                                             gimple *orig_stmt)
>  {
> -  gcall *stmt = *stmt_p;
>    auto_vec <unsigned, 4> pass_through_args;
>    auto_vec <unsigned, 4> pass_through_pbr_indices;
> +  auto_vec <HOST_WIDE_INT, 4> pass_through_offsets;
> +  gcall *stmt = *stmt_p;
> +  unsigned nargs = gimple_call_num_args (stmt);
> +  bool recreate = false;
>
> -  if (m_split_modifications_p && m_id)
> +  for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
>      {
> -      for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
> +      tree t = gimple_call_arg (stmt, i);
> +      gcc_assert (TREE_CODE (t) != BIT_FIELD_REF
> +                 && TREE_CODE (t) != IMAGPART_EXPR
> +                 && TREE_CODE (t) != REALPART_EXPR);
> +
> +      if (TREE_CODE (t) == SSA_NAME
> +         && m_dead_ssas.contains (t))
> +       recreate = true;
> +
> +      if (!m_split_modifications_p)
> +       continue;
> +
> +      tree base;
> +      unsigned agg_arg_offset;
> +      if (!isra_get_ref_base_and_offset (t, &base, &agg_arg_offset))
> +       continue;
> +
> +      bool by_ref = false;
> +      if (TREE_CODE (base) == SSA_NAME)
>         {
> -         tree t = gimple_call_arg (stmt, i);
> -         gcc_assert (TREE_CODE (t) != BIT_FIELD_REF
> -                     && TREE_CODE (t) != IMAGPART_EXPR
> -                     && TREE_CODE (t) != REALPART_EXPR);
> -
> -         tree base;
> -         unsigned unit_offset;
> -         if (!isra_get_ref_base_and_offset (t, &base, &unit_offset))
> +         if (!SSA_NAME_IS_DEFAULT_DEF (base))
>             continue;
> +         base = SSA_NAME_VAR (base);
> +         gcc_checking_assert (base);
> +         by_ref = true;
> +       }
> +      if (TREE_CODE (base) != PARM_DECL)
> +       continue;
>
> -         bool by_ref = false;
> -         if (TREE_CODE (base) == SSA_NAME)
> +      bool base_among_replacements = false;
> +      unsigned j, repl_list_len = m_replacements.length ();
> +      for (j = 0; j < repl_list_len; j++)
> +       {
> +         ipa_param_body_replacement *pbr = &m_replacements[j];
> +         if (pbr->base == base)
>             {
> -             if (!SSA_NAME_IS_DEFAULT_DEF (base))
> -               continue;
> -             base = SSA_NAME_VAR (base);
> -             gcc_checking_assert (base);
> -             by_ref = true;
> +             base_among_replacements = true;
> +             break;
>             }
> -         if (TREE_CODE (base) != PARM_DECL)
> -           continue;
> +       }
> +      if (!base_among_replacements)
> +       continue;
>
> -         bool base_among_replacements = false;
> -         unsigned j, repl_list_len = m_replacements.length ();
> -         for (j = 0; j < repl_list_len; j++)
> +      /* We still have to distinguish between an end-use that we have to
> +        transform now and a pass-through, which happens in the following
> +        two cases.  */
> +
> +      /* TODO: After we adjust ptr_parm_has_nonarg_uses to also consider
> +        &MEM_REF[ssa_name + offset], we will also have to detect that case
> +        here.    */
> +
> +      if (TREE_CODE (t) == SSA_NAME
> +         && SSA_NAME_IS_DEFAULT_DEF (t)
> +         && SSA_NAME_VAR (t)
> +         && TREE_CODE (SSA_NAME_VAR (t)) == PARM_DECL)
> +       {
> +         /* This must be a by_reference pass-through.  */
> +         recreate = true;
> +         gcc_assert (POINTER_TYPE_P (TREE_TYPE (t)));
> +         pass_through_args.safe_push (i);
> +         pass_through_pbr_indices.safe_push (j);
> +         pass_through_offsets.safe_push (agg_arg_offset);
> +       }
> +      else if (!by_ref && AGGREGATE_TYPE_P (TREE_TYPE (t)))
> +       {
> +         /* Currently IPA-SRA guarantees the aggregate access type
> +            exactly matches in this case.  So if it does not match, it is
> +            a pass-through argument that will be sorted out at edge
> +            redirection time.  */
> +         ipa_param_body_replacement *pbr
> +           = lookup_replacement_1 (base, agg_arg_offset);
> +
> +         if (!pbr
> +             || (TYPE_MAIN_VARIANT (TREE_TYPE (t))
> +                 != TYPE_MAIN_VARIANT (TREE_TYPE (pbr->repl))))
>             {
> -             ipa_param_body_replacement *pbr = &m_replacements[j];
> -             if (pbr->base == base)
> -               {
> -                 base_among_replacements = true;
> -                 break;
> -               }
> -           }
> -         if (!base_among_replacements)
> -           continue;
> -
> -         /* We still have to distinguish between an end-use that we have to
> -            transform now and a pass-through, which happens in the following
> -            two cases.  */
> -
> -         /* TODO: After we adjust ptr_parm_has_nonarg_uses to also consider
> -            &MEM_REF[ssa_name + offset], we will also have to detect that 
> case
> -            here.    */
> -
> -         if (TREE_CODE (t) == SSA_NAME
> -             && SSA_NAME_IS_DEFAULT_DEF (t)
> -             && SSA_NAME_VAR (t)
> -             && TREE_CODE (SSA_NAME_VAR (t)) == PARM_DECL)
> -           {
> -             /* This must be a by_reference pass-through.  */
> -             gcc_assert (POINTER_TYPE_P (TREE_TYPE (t)));
> +             recreate = true;
>               pass_through_args.safe_push (i);
>               pass_through_pbr_indices.safe_push (j);
> -           }
> -         else if (!by_ref && AGGREGATE_TYPE_P (TREE_TYPE (t)))
> -           {
> -             /* Currently IPA-SRA guarantees the aggregate access type
> -                exactly matches in this case.  So if it does not match, it is
> -                a pass-through argument that will be sorted out at edge
> -                redirection time.  */
> -             ipa_param_body_replacement *pbr
> -               = lookup_replacement_1 (base, unit_offset);
> -
> -             if (!pbr
> -                 || (TYPE_MAIN_VARIANT (TREE_TYPE (t))
> -                     != TYPE_MAIN_VARIANT (TREE_TYPE (pbr->repl))))
> -               {
> -                 pass_through_args.safe_push (i);
> -                 pass_through_pbr_indices.safe_push (j);
> -               }
> +             pass_through_offsets.safe_push (agg_arg_offset);
>             }
>         }
>      }
>
> -  unsigned nargs = gimple_call_num_args (stmt);
> -  if (!pass_through_args.is_empty ())
> +  if (!recreate)
>      {
> -      auto_vec<tree, 16> vargs;
> -      unsigned pt_idx = 0;
> +      /* No need to rebuild the statement, let's just modify arguments
> +        and the LHS if/as appropriate.  */
> +      bool modified = false;
>        for (unsigned i = 0; i < nargs; i++)
>         {
> -         if (pt_idx < pass_through_args.length ()
> -             && i == pass_through_args[pt_idx])
> -           {
> -             unsigned j = pass_through_pbr_indices[pt_idx];
> -             pt_idx++;
> -             tree base = m_replacements[j].base;
> +         tree *t = gimple_call_arg_ptr (stmt, i);
> +         modified |= modify_expression (t, true);
> +       }
> +      if (gimple_call_lhs (stmt))
> +       {
> +         tree *t = gimple_call_lhs_ptr (stmt);
> +         modified |= modify_expression (t, false);
> +       }
> +      return modified;
> +    }
>
> -             /* Map base will get mapped to the special transitive-isra 
> marker
> -                dummy decl. */
> -             struct simple_tree_swap_info swapinfo;
> -             swapinfo.from = base;
> -             swapinfo.to = m_replacements[j].dummy;
> -             swapinfo.done = false;
> -             tree arg = gimple_call_arg (stmt, i);
> -             walk_tree (&arg, remap_split_decl_to_dummy, &swapinfo, NULL);
> -             gcc_assert (swapinfo.done);
> -             vargs.safe_push (arg);
> -             /* Now let's push all replacements pertaining to this parameter
> -                so that all gimple register ones get correct SSA_NAMES.  Edge
> -                redirection will weed out the dummy argument as well as all
> -                unused replacements later.  */
> -             unsigned int repl_list_len = m_replacements.length ();
> -             for (; j < repl_list_len; j++)
> -               {
> -                 if (m_replacements[j].base != base)
> -                   break;
> -                 vargs.safe_push (m_replacements[j].repl);
> -               }
> +  auto_vec<int, 16> index_map;
> +  auto_vec<pass_through_split_map, 4> pass_through_map;
> +  auto_vec<tree, 16> vargs;
> +  int always_copy_delta = 0;
> +  unsigned pt_idx = 0;
> +  int new_arg_idx = 0;
> +  for (unsigned i = 0; i < nargs; i++)
> +    {
> +      if (pt_idx < pass_through_args.length ()
> +         && i == pass_through_args[pt_idx])
> +       {
> +         unsigned j = pass_through_pbr_indices[pt_idx];
> +         unsigned agg_arg_offset = pass_through_offsets[pt_idx];
> +         pt_idx++;
> +         always_copy_delta--;
> +         tree base = m_replacements[j].base;
> +
> +         /* In order to be put into SSA form, we have to push all 
> replacements
> +            pertaining to this parameter as parameters to the call statement.
> +            Edge redirection will need to use edge summary to weed out the
> +            unnecessary ones.  */
> +         unsigned repl_list_len = m_replacements.length ();
> +         for (; j < repl_list_len; j++)
> +           {
> +             if (m_replacements[j].base != base)
> +               break;
> +             if (m_replacements[j].unit_offset < agg_arg_offset)
> +               continue;
> +             pass_through_split_map pt_map;
> +             pt_map.base_index = i;
> +             pt_map.unit_offset
> +               = m_replacements[j].unit_offset - agg_arg_offset;
> +             pt_map.new_index = new_arg_idx;
> +             pass_through_map.safe_push (pt_map);
> +             vargs.safe_push (m_replacements[j].repl);
> +             new_arg_idx++;
> +             always_copy_delta++;
> +           }
> +         index_map.safe_push (-1);
> +       }
> +      else
> +       {
> +         tree t = gimple_call_arg (stmt, i);
> +         if (TREE_CODE (t) == SSA_NAME
> +             && m_dead_ssas.contains (t))
> +           {
> +             always_copy_delta--;
> +             index_map.safe_push (-1);
>             }
>           else
>             {
> -             tree t = gimple_call_arg (stmt, i);
>               modify_expression (&t, true);
>               vargs.safe_push (t);
> +             index_map.safe_push (new_arg_idx);
> +             new_arg_idx++;
>             }
>         }
> -      gcall *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));
> -      gimple_call_copy_flags (new_stmt, stmt);
> -      if (tree lhs = gimple_call_lhs (stmt))
> -       {
> -         modify_expression (&lhs, false);
> -         gimple_call_set_lhs (new_stmt, lhs);
> -       }
> -      *stmt_p = new_stmt;
> -      return true;
>      }
>
> -  /* Otherwise, no need to rebuild the statement, let's just modify arguments
> -     and the LHS if/as appropriate.  */
> -  bool modified = false;
> -  for (unsigned i = 0; i < nargs; i++)
> +  gcall *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));
> +  gimple_call_copy_flags (new_stmt, stmt);
> +  if (tree lhs = gimple_call_lhs (stmt))
>      {
> -      tree *t = gimple_call_arg_ptr (stmt, i);
> -      modified |= modify_expression (t, true);
> +      modify_expression (&lhs, false);
> +      gimple_call_set_lhs (new_stmt, lhs);
>      }
> +  *stmt_p = new_stmt;
>
> -  if (gimple_call_lhs (stmt))
> -    {
> -      tree *t = gimple_call_lhs_ptr (stmt);
> -      modified |= modify_expression (t, false);
> -    }
> -
> -  return modified;
> +  m_new_call_arg_modification_info = true;
> +  if (orig_stmt)
> +    record_argument_state (m_id, orig_stmt, index_map, pass_through_map,
> +                          always_copy_delta);
> +  return true;
>  }
>
>  /* If the statement STMT contains any expressions that need to replaced with 
> a
> @@ -1720,7 +1904,8 @@ ipa_param_body_adjustments::modify_call_stmt (gcall 
> **stmt_p)
>
>  bool
>  ipa_param_body_adjustments::modify_gimple_stmt (gimple **stmt,
> -                                               gimple_seq *extra_stmts)
> +                                               gimple_seq *extra_stmts,
> +                                               gimple *orig_stmt)
>  {
>    bool modified = false;
>    tree *t;
> @@ -1740,7 +1925,7 @@ ipa_param_body_adjustments::modify_gimple_stmt (gimple 
> **stmt,
>        break;
>
>      case GIMPLE_CALL:
> -      modified |= modify_call_stmt ((gcall **) stmt);
> +      modified |= modify_call_stmt ((gcall **) stmt, orig_stmt);
>        break;
>
>      case GIMPLE_ASM:
> @@ -1797,7 +1982,7 @@ ipa_param_body_adjustments::modify_cfun_body ()
>           gimple *stmt = gsi_stmt (gsi);
>           gimple *stmt_copy = stmt;
>           gimple_seq extra_stmts = NULL;
> -         bool modified = modify_gimple_stmt (&stmt, &extra_stmts);
> +         bool modified = modify_gimple_stmt (&stmt, &extra_stmts, NULL);
>           if (stmt != stmt_copy)
>             {
>               gcc_checking_assert (modified);
> @@ -1945,4 +2130,3 @@ 
> ipa_param_body_adjustments::perform_cfun_body_modifications ()
>
>    return cfg_changed;
>  }
> -
> diff --git a/gcc/ipa-param-manipulation.h b/gcc/ipa-param-manipulation.h
> index c80e1bc5d6b..f59d17717ee 100644
> --- a/gcc/ipa-param-manipulation.h
> +++ b/gcc/ipa-param-manipulation.h
> @@ -54,7 +54,7 @@ or only a vector of ipa_adjusted_params.
>  When these classes are used in the context of call graph clone 
> materialization
>  and subsequent call statement redirection - which is the point at which we
>  modify arguments in call statements - they need to cooperate with each other 
> in
> -order to handle what we refer to as transitive (IPA-SRA) splits.  These are
> +order to handle what we refer to as pass-through (IPA-SRA) splits.  These are
>  situations when a formal parameter of one function is split into several
>  smaller ones and some of them are then passed on in a call to another 
> function
>  because the formal parameter of this callee has also been split.
> @@ -83,7 +83,7 @@ baz ()
>  Both bar and foo would have their parameter split.  Foo would receive one
>  replacement representing s.b.  Function bar would see its parameter split 
> into
>  one replacement representing z.s.a and another representing z.s.b which would
> -be passed on to foo.  It would be a so called transitive split IPA-SRA
> +be passed on to foo.  It would be a so called pass-through split IPA-SRA
>  replacement, one which is passed in a call as an actual argument to another
>  IPA-SRA replacement in another function.
>
> @@ -95,30 +95,25 @@ all of the above.
>
>  Call redirection has to be able to find the right decl or SSA_NAME that
>  corresponds to the transitive split in the caller.  The SSA names are 
> assigned
> -right after clone materialization/ modification and cannot be "added"
> -afterwards.  Moreover, if the caller has been inlined the SSA_NAMEs in 
> question
> -no longer belong to PARM_DECLs but to VAR_DECLs, indistinguishable from any
> -others.
> +right after clone materialization/ modification and cannot be "added" to call
> +arguments at any later point.  Moreover, if the caller has been inlined the
> +SSA_NAMEs in question no longer belong to PARM_DECLs but to VAR_DECLs,
> +indistinguishable from any others.
>
>  Therefore, when clone materialization finds a call statement which it knows 
> is
> -a part of a transitive split, it will modify it into:
> +a part of a transitive split, it will simply add as arguments all new "split"
> +replacements (that have grater or equal offset than the original call
> +argument):
>
> -  foo (DUMMY_Z_VAR.s, repl_for_a, repl_for_b, <rest of original arguments>);
> +  foo (repl_for_a, repl_for_b, <rest of original arguments>);
>
> -It will also store {DUMMY_S_VAR, 32} and {DUMMY_S_VAR, 64} representing 
> offsets
> -of z.s.a and z.s.b (assuming a 32-bit int) into foo's cgraph node
> -clone->performed_splits vector (which is storing structures of type
> -ipa_param_performed_split also defined in this header file).
> -
> -Call redirection will identify that expression DUMMY_Z_VAR.s is based on a
> -variable stored in performed_splits vector and learn that the following
> -arguments, already in SSA form, represent offsets 32 and 64 in a split 
> original
> -parameter.  It subtracts offset of DUMMY_Z_VAR.s from 32 and 64 and arrives 
> at
> -offsets 0 and 32 within callee's original parameter.  At this point it also
> -knows from the call graph that only the bit with offset 32 is needed and so
> -changes the call statement into final:
> -
> -bar (repl_for_b, <rest of original arguments>);  */
> +It will also store into ipa_edge_modification_info (which is internal to
> +ipa-param-modification.c) information about which replacement is which and
> +where original arguments are.  Call redirection will then invoke
> +ipa_param_adjustments::modify_call which will access this information and
> +eliminate all replacements which the callee does not expect (repl_for_a in 
> our
> +example above).  In between these two steps, however, a call statement might
> +have extraneous arguments.  */
>
>  #ifndef IPA_PARAM_MANIPULATION_H
>  #define IPA_PARAM_MANIPULATION_H
> @@ -207,21 +202,6 @@ struct GTY(()) ipa_adjusted_param
>  void ipa_dump_adjusted_parameters (FILE *f,
>                                    vec<ipa_adjusted_param, va_gc> 
> *adj_params);
>
> -/* Structure to remember the split performed on a node so that edge 
> redirection
> -   (i.e. splitting arguments of call statements) know how split formal
> -   parameters of the caller are represented.  */
> -
> -struct GTY(()) ipa_param_performed_split
> -{
> -  /* The dummy VAR_DECL that was created instead of the split parameter that
> -     sits in the call in the meantime between clone materialization and call
> -     redirection.  All entries in a vector of performed splits that 
> correspond
> -     to the same dumy decl must be grouped together.  */
> -  tree dummy_decl;
> -  /* Offset into the original parameter.  */
> -  unsigned unit_offset;
> -};
> -
>  /* Class used to record planned modifications to parameters of a function and
>     also to perform necessary modifications at the caller side at the gimple
>     level.  Used to describe all cgraph node clones that have their parameters
> @@ -244,9 +224,7 @@ public:
>
>    /* Modify a call statement arguments (and possibly remove the return value)
>       as described in the data fields of this class.  */
> -  gcall *modify_call (gcall *stmt,
> -                     vec<ipa_param_performed_split, va_gc> *performed_splits,
> -                     tree callee_decl, bool update_references);
> +  gcall *modify_call (cgraph_edge *cs, bool update_references);
>    /* Return if the first parameter is left intact.  */
>    bool first_param_intact_p ();
>    /* Build a function type corresponding to the modified call.  */
> @@ -293,15 +271,9 @@ struct ipa_param_body_replacement
>    tree base;
>    /* The new decl it should be replaced with.  */
>    tree repl;
> -  /* When modifying clones during IPA clone materialization, this is a dummy
> -     decl used to mark calls in which we need to apply transitive splitting,
> -     these dummy delcls are inserted as arguments to such calls and then
> -     followed by all the replacements with offset info stored in
> -     ipa_param_performed_split.
> -
> -     Users of ipa_param_body_adjustments that modify standalone functions
> -     outside of IPA clone materialization can use this field for their 
> internal
> -     purposes.  */
> +  /* Users of ipa_param_body_adjustments that modify standalone functions
> +     outside of IPA clone materialization can use the following field for 
> their
> +     internal purposes.  */
>    tree dummy;
>    /* The offset within BASE that REPL represents.  */
>    unsigned unit_offset;
> @@ -342,8 +314,7 @@ public:
>    /* Change the PARM_DECLs.  */
>    void modify_formal_parameters ();
>    /* Register a replacement decl for the transformation done in APM.  */
> -  void register_replacement (ipa_adjusted_param *apm, tree replacement,
> -                            tree dummy = NULL_TREE);
> +  void register_replacement (ipa_adjusted_param *apm, tree replacement);
>    /* Lookup a replacement for a given offset within a given parameter.  */
>    tree lookup_replacement (tree base, unsigned unit_offset);
>    /* Lookup a replacement for an expression, if there is one.  */
> @@ -353,7 +324,8 @@ public:
>       parameter. */
>    tree get_replacement_ssa_base (tree old_decl);
>    /* Modify a statement.  */
> -  bool modify_gimple_stmt (gimple **stmt, gimple_seq *extra_stmts);
> +  bool modify_gimple_stmt (gimple **stmt, gimple_seq *extra_stmts,
> +                          gimple *orig_stmt);
>    /* Return the new chain of parameters.  */
>    tree get_new_param_chain ();
>
> @@ -370,6 +342,12 @@ public:
>    /* Set to true if there are any IPA_PARAM_OP_SPLIT adjustments among stored
>       adjustments.  */
>    bool m_split_modifications_p;
> +
> +  /* Sets of statements and SSA_NAMEs that only manipulate data from 
> parameters
> +     removed because they are not necessary.  */
> +  hash_set<gimple *> m_dead_stmts;
> +  hash_set<tree> m_dead_ssas;
> +
>  private:
>    void common_initialization (tree old_fndecl, tree *vars,
>                               vec<ipa_replace_map *, va_gc> *tree_map);
> @@ -380,9 +358,10 @@ private:
>    tree replace_removed_params_ssa_names (tree old_name, gimple *stmt);
>    bool modify_expression (tree *expr_p, bool convert);
>    bool modify_assignment (gimple *stmt, gimple_seq *extra_stmts);
> -  bool modify_call_stmt (gcall **stmt_p);
> +  bool modify_call_stmt (gcall **stmt_p, gimple *orig_stmt);
>    bool modify_cfun_body ();
>    void reset_debug_stmts ();
> +  void mark_dead_statements (tree dead_param);
>
>    /* Declaration of the function that is being transformed.  */
>
> @@ -427,9 +406,16 @@ private:
>       its this pointer and must be converted to a normal function.  */
>
>    bool m_method2func;
> +
> +  /* Set to true if any new information has been stored to
> +     ipa_edge_modifications as part of this body transformation.  */
> +
> +  bool m_new_call_arg_modification_info;
>  };
>
>  void push_function_arg_decls (vec<tree> *args, tree fndecl);
>  void push_function_arg_types (vec<tree> *types, tree fntype);
> +void ipa_verify_edge_has_no_modifications (cgraph_edge *cs);
> +
>
>  #endif /* IPA_PARAM_MANIPULATION_H */
> diff --git a/gcc/symtab-clones.h b/gcc/symtab-clones.h
> index 5695a434f6a..a6ad4a6e27f 100644
> --- a/gcc/symtab-clones.h
> +++ b/gcc/symtab-clones.h
> @@ -26,8 +26,7 @@ struct GTY(()) clone_info
>    /* Constructor.  */
>    clone_info ()
>      : tree_map (NULL),
> -      param_adjustments (NULL),
> -      performed_splits (NULL)
> +      param_adjustments (NULL)
>    {
>    }
>    /* Constants discovered by IPA-CP, i.e. which parameter should be replaced
> @@ -35,18 +34,6 @@ struct GTY(()) clone_info
>    vec<ipa_replace_map *, va_gc> *tree_map;
>    /* Parameter modification that IPA-SRA decided to perform.  */
>    ipa_param_adjustments *param_adjustments;
> -  /* Lists of dummy-decl and offset pairs representing split formal 
> parameters
> -     in the caller.  Offsets of all new replacements are enumerated, those
> -     coming from the same original parameter have the same dummy decl stored
> -     along with them.
> -
> -     Dummy decls sit in call statement arguments followed by new parameter
> -     decls (or their SSA names) in between (caller) clone materialization and
> -     call redirection.  Redirection then recognizes the dummy variable and
> -     together with the stored offsets can reconstruct what exactly the new
> -     parameter decls represent and can leave in place only those that the
> -     callee expects.  */
> -  vec<ipa_param_performed_split, va_gc> *performed_splits;
>
>    /* Return clone_info, if available.  */
>    static clone_info *get (cgraph_node *node);
> diff --git a/gcc/testsuite/g++.dg/ipa/ipa-sra-4.C 
> b/gcc/testsuite/g++.dg/ipa/ipa-sra-4.C
> new file mode 100644
> index 00000000000..56d59f9fd9a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ipa/ipa-sra-4.C
> @@ -0,0 +1,37 @@
> +/* { dg-do compile { target c++11 } } */
> +/* { dg-options "-O2 -fipa-sra"  } */
> +
> +void __throw_bad_alloc() __attribute__((__noreturn__));
> +void __throw_bad_array_new_length();
> +template <typename> class allocator {};
> +template <typename> struct allocator_traits;
> +int *allocate___trans_tmp_2;
> +template <typename _Tp> struct allocator_traits<allocator<_Tp>> {
> +  using allocator_type = allocator<_Tp>;
> +  using pointer = _Tp *;
> +  using size_type = long;
> +  static pointer allocate(allocator_type &, size_type __n) {
> +    long __trans_tmp_3 = __n;
> +    if (__builtin_expect(__trans_tmp_3, false))
> +      if (__trans_tmp_3)
> +        __throw_bad_array_new_length();
> +    operator new(sizeof(int));
> +    return allocate___trans_tmp_2;
> +  }
> +};
> +class throw_allocator_base {
> +  allocator<int> _M_allocator;
> +public:
> +  int *allocate(long __n) {
> +    if (__n)
> +      __throw_bad_alloc();
> +    int *a = allocator_traits<allocator<int>>::allocate(_M_allocator, __n);
> +    return a;
> +  }
> +};
> +template <typename Alloc> void check_allocate_max_size() {
> +  Alloc a;
> +  long __trans_tmp_1 = 0;
> +  a.allocate(__trans_tmp_1 + 1);
> +}
> +int main() { check_allocate_max_size<throw_allocator_base>(); }
> diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-23.c 
> b/gcc/testsuite/gcc.dg/ipa/ipa-sra-23.c
> new file mode 100644
> index 00000000000..f438b509614
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-23.c
> @@ -0,0 +1,24 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2"  } */
> +
> +extern int g;
> +
> +static int __attribute__((noinline))
> +bar (int i, int j)
> +{
> +  return 2*g + i;
> +}
> +
> +static int __attribute__((noinline))
> +foo (int i, int j)
> +{
> +  if (i > 5)
> +    j = 22;
> +  return bar (i, j) + 1;
> +}
> +
> +int
> +entry (int l, int k)
> +{
> +  return foo (l, k);
> +}
> diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-24.c 
> b/gcc/testsuite/gcc.dg/ipa/ipa-sra-24.c
> new file mode 100644
> index 00000000000..7b5bf0825fc
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-24.c
> @@ -0,0 +1,20 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -Wmaybe-uninitialized -Werror"  } */
> +
> +int *ttmp_1;
> +_Bool pt_ins_tipdo, pq_ins_apd, pq_ins_tt2;
> +int gtrphdt;
> +
> +void pl_ins(int, _Bool, _Bool);
> +inline void pt_ins(int *, _Bool apdo) {
> +  int list = *ttmp_1;
> +  pl_ins(list, apdo, pt_ins_tipdo);
> +}
> +void pq_ins(int *t) {
> +  if (pq_ins_tt2)
> +    pt_ins(t, pq_ins_apd);
> +}
> +int gtr_post_hd() {
> +  pq_ins(&gtrphdt);
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/ipa/pr93385.c 
> b/gcc/testsuite/gcc.dg/ipa/pr93385.c
> new file mode 100644
> index 00000000000..6d1d0d7cd27
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/ipa/pr93385.c
> @@ -0,0 +1,27 @@
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fno-dce -fno-ipa-cp -fno-tree-dce" } */
> +
> +char a, b;
> +
> +#ifdef __SIZEOF_INT128__
> +#define T unsigned __int128
> +#else
> +#define T unsigned
> +#endif
> +
> +static inline int
> +c (T d)
> +{
> +  char e = 0;
> +  d %= (unsigned) d;
> +  e -= 0;
> +  __builtin_strncpy (&a, &e, 1);
> +  return e + b;
> +}
> +
> +int
> +main (void)
> +{
> +  c (~0);
> +  return 0;
> +}
> diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
> index 1dcb31c0267..165c4ad7c72 100644
> --- a/gcc/tree-inline.c
> +++ b/gcc/tree-inline.c
> @@ -1528,6 +1528,11 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
>           : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))
>      return NULL;
>
> +  if (!is_gimple_debug (stmt)
> +      && id->param_body_adjs
> +      && id->param_body_adjs->m_dead_stmts.contains (stmt))
> +    return NULL;
> +
>    /* Begin by recognizing trees that we'll completely rewrite for the
>       inlining context.  Our output for these trees is completely
>       different from our input (e.g. RETURN_EXPR is deleted and morphs
> @@ -1792,10 +1797,15 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
>
>        if (gimple_debug_bind_p (stmt))
>         {
> +         tree value;
> +         if (id->param_body_adjs
> +             && id->param_body_adjs->m_dead_stmts.contains (stmt))
> +           value = NULL_TREE;
> +         else
> +           value = gimple_debug_bind_get_value (stmt);
>           gdebug *copy
>             = gimple_build_debug_bind (gimple_debug_bind_get_var (stmt),
> -                                      gimple_debug_bind_get_value (stmt),
> -                                      stmt);
> +                                      value, stmt);
>           if (id->reset_location)
>             gimple_set_location (copy, input_location);
>           id->debug_stmts.safe_push (copy);
> @@ -1924,7 +1934,7 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
>    if (id->param_body_adjs)
>      {
>        gimple_seq extra_stmts = NULL;
> -      id->param_body_adjs->modify_gimple_stmt (&copy, &extra_stmts);
> +      id->param_body_adjs->modify_gimple_stmt (&copy, &extra_stmts, stmt);
>        if (!gimple_seq_empty_p (extra_stmts))
>         {
>           memset (&wi, 0, sizeof (wi));
> @@ -2674,7 +2684,9 @@ copy_phis_for_bb (basic_block bb, copy_body_data *id)
>        phi = si.phi ();
>        res = PHI_RESULT (phi);
>        new_res = res;
> -      if (!virtual_operand_p (res))
> +      if (!virtual_operand_p (res)
> +         && (!id->param_body_adjs
> +             || !id->param_body_adjs->m_dead_stmts.contains (phi)))
>         {
>           walk_tree (&new_res, copy_tree_body_r, id, NULL);
>           if (EDGE_COUNT (new_bb->preds) == 0)
> @@ -4740,7 +4752,6 @@ expand_call_inline (basic_block bb, gimple *stmt, 
> copy_body_data *id,
>    use_operand_p use;
>    gimple *simtenter_stmt = NULL;
>    vec<tree> *simtvars_save;
> -  clone_info *info;
>
>    /* The gimplifier uses input_location in too many places, such as
>       internal_get_tmp_var ().  */
> @@ -5065,40 +5076,6 @@ expand_call_inline (basic_block bb, gimple *stmt, 
> copy_body_data *id,
>    /* Add local vars in this inlined callee to caller.  */
>    add_local_variables (id->src_cfun, cfun, id);
>
> -  info = clone_info::get (id->src_node);
> -  if (info && info->performed_splits)
> -    {
> -      clone_info *dst_info = clone_info::get_create (id->dst_node);
> -      /* Any calls from the inlined function will be turned into calls from 
> the
> -        function we inline into.  We must preserve notes about how to split
> -        parameters such calls should be redirected/updated.  */
> -      unsigned len = vec_safe_length (info->performed_splits);
> -      for (unsigned i = 0; i < len; i++)
> -       {
> -         ipa_param_performed_split ps
> -           = (*info->performed_splits)[i];
> -         ps.dummy_decl = remap_decl (ps.dummy_decl, id);
> -         vec_safe_push (dst_info->performed_splits, ps);
> -       }
> -
> -      if (flag_checking)
> -       {
> -         len = vec_safe_length (dst_info->performed_splits);
> -         for (unsigned i = 0; i < len; i++)
> -           {
> -             ipa_param_performed_split *ps1
> -               = &(*dst_info->performed_splits)[i];
> -             for (unsigned j = i + 1; j < len; j++)
> -               {
> -                 ipa_param_performed_split *ps2
> -                   = &(*dst_info->performed_splits)[j];
> -                 gcc_assert (ps1->dummy_decl != ps2->dummy_decl
> -                             || ps1->unit_offset != ps2->unit_offset);
> -               }
> -           }
> -       }
> -    }
> -
>    if (dump_enabled_p ())
>      {
>        char buf[128];
> @@ -6117,23 +6094,10 @@ tree_versionable_function_p (tree fndecl)
>  static void
>  update_clone_info (copy_body_data * id)
>  {
> -  clone_info *dst_info = clone_info::get (id->dst_node);
> -  vec<ipa_param_performed_split, va_gc> *cur_performed_splits
> -    = dst_info ? dst_info->performed_splits : NULL;
> -  if (cur_performed_splits)
> -    {
> -      unsigned len = cur_performed_splits->length ();
> -      for (unsigned i = 0; i < len; i++)
> -       {
> -         ipa_param_performed_split *ps = &(*cur_performed_splits)[i];
> -         ps->dummy_decl = remap_decl (ps->dummy_decl, id);
> -       }
> -    }
> -
> -  struct cgraph_node *node;
> -  if (!id->dst_node->clones)
> +  struct cgraph_node *this_node = id->dst_node;
> +  if (!this_node->clones)
>      return;
> -  for (node = id->dst_node->clones; node != id->dst_node;)
> +  for (cgraph_node *node = this_node->clones; node != this_node;)
>      {
>        /* First update replace maps to match the new body.  */
>        clone_info *info = clone_info::get (node);
> @@ -6147,53 +6111,6 @@ update_clone_info (copy_body_data * id)
>               walk_tree (&replace_info->new_tree, copy_tree_body_r, id, NULL);
>             }
>         }
> -      if (info && info->performed_splits)
> -       {
> -         unsigned len = vec_safe_length (info->performed_splits);
> -         for (unsigned i = 0; i < len; i++)
> -           {
> -             ipa_param_performed_split *ps
> -               = &(*info->performed_splits)[i];
> -             ps->dummy_decl = remap_decl (ps->dummy_decl, id);
> -           }
> -       }
> -      if (unsigned len = vec_safe_length (cur_performed_splits))
> -       {
> -         /* We do not want to add current performed splits when we are saving
> -            a copy of function body for later during inlining, that would 
> just
> -            duplicate all entries.  So let's have a look whether anything
> -            referring to the first dummy_decl is present.  */
> -         if (!info)
> -           info = clone_info::get_create (node);
> -         unsigned dst_len = vec_safe_length (info->performed_splits);
> -         ipa_param_performed_split *first = &(*cur_performed_splits)[0];
> -         for (unsigned i = 0; i < dst_len; i++)
> -           if ((*info->performed_splits)[i].dummy_decl
> -               == first->dummy_decl)
> -             {
> -               len = 0;
> -               break;
> -             }
> -
> -         for (unsigned i = 0; i < len; i++)
> -           vec_safe_push (info->performed_splits,
> -                          (*cur_performed_splits)[i]);
> -         if (flag_checking)
> -           {
> -             for (unsigned i = 0; i < dst_len; i++)
> -               {
> -                 ipa_param_performed_split *ps1
> -                   = &(*info->performed_splits)[i];
> -                 for (unsigned j = i + 1; j < dst_len; j++)
> -                   {
> -                     ipa_param_performed_split *ps2
> -                       = &(*info->performed_splits)[j];
> -                     gcc_assert (ps1->dummy_decl != ps2->dummy_decl
> -                                 || ps1->unit_offset != ps2->unit_offset);
> -                   }
> -               }
> -           }
> -       }
>
>        if (node->clones)
>         node = node->clones;
> --
> 2.31.1
>

Reply via email to