public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Martin Jambor <mjambor@suse.cz>
To: GCC Patches <gcc-patches@gcc.gnu.org>
Cc: Jan Hubicka <hubicka@ucw.cz>
Subject: Re: [PATCH] ipa: Self-DCE of uses of removed call LHSs (PR 108007)
Date: Fri, 01 Sep 2023 15:32:06 +0200	[thread overview]
Message-ID: <ri634zy58a1.fsf@suse.cz> (raw)
In-Reply-To: <ri6sfc1g1lx.fsf@suse.cz>

Hello

and ping.

Thanks,

Martin


On Fri, May 12 2023, Martin Jambor wrote:
> Hi,
>
> PR 108007 is another manifestation where we rely on DCE to clean-up
> after IPA-SRA and if the user explicitely switches DCE off, IPA-SRA
> can leave behind statements which are fed uninitialized values and
> trap, even though their results are themselves never used.
>
> I have already fixed this for unused parameters in callees, this bug
> shows that almost the same thing can happen for removed returns, on
> the side of callers.  This means that the issue has to be fixed
> elsewhere, in call redirection.  This patch adds a function which
> recursivewly looks for uses of operations fed specific SSA names and
> removes them all.
>
> That would have been easy if it wasn't for debug statements during
> tree-inline (from which call redirection is also invoked).  Debug
> statements are decoupled from the rest at this point and iterating
> over uses of SSAs does not bring them up.  During tree-inline they are
> handled especially at the end, I assume in order to make sure that
> relative ordering of UIDs are the same with and without debug info.
>
> This means that during tree-inline we need to make a hash of killed
> SSAs, that we already have in copy_body_data, available to the
> function making the purging.  So the patch duly does also that, making
> the interface slightly ugly.
>
> Bootstrapped and tested on x86_64-linux.  OK for master?  (I am not sure
> the problem is grave enough to warrant backporting to release branches
> but can do that as well if people think I should.)
>
> Thanks,
>
> Martin
>
>
> gcc/ChangeLog:
>
> 2023-05-11  Martin Jambor  <mjambor@suse.cz>
>
> 	PR ipa/108007
> 	* cgraph.h (cgraph_edge): Add a parameter to
> 	redirect_call_stmt_to_callee.
> 	* ipa-param-manipulation.h (ipa_param_adjustments): Added a
> 	parameter to modify_call.
> 	* cgraph.cc (cgraph_edge::redirect_call_stmt_to_callee): New
> 	parameter killed_ssas, pass it to padjs->modify_call.
> 	* ipa-param-manipulation.cc (purge_transitive_uses): New function.
> 	(ipa_param_adjustments::modify_call): New parameter killed_ssas.
> 	Instead of substitutin uses, invoke purge_transitive_uses.  If
> 	hash of killed SSAs has not been provided, create a temporary one
> 	and release SSAs that have been added to it.
> 	* tree-inline.cc (redirect_all_calls): Create
> 	id->killed_new_ssa_names earlier, pass it to edge redirection,
> 	adjust a comment.
> 	(copy_body): Release SSAs in id->killed_new_ssa_names.
>
> gcc/testsuite/ChangeLog:
>
> 2023-05-11  Martin Jambor  <mjambor@suse.cz>
>
> 	PR ipa/108007
> 	* gcc.dg/ipa/pr108007.c: New test.
> ---
>  gcc/cgraph.cc                       | 10 +++-
>  gcc/cgraph.h                        |  9 ++-
>  gcc/ipa-param-manipulation.cc       | 85 +++++++++++++++++++++--------
>  gcc/ipa-param-manipulation.h        |  3 +-
>  gcc/testsuite/gcc.dg/ipa/pr108007.c | 32 +++++++++++
>  gcc/tree-inline.cc                  | 28 ++++++----
>  6 files changed, 129 insertions(+), 38 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/ipa/pr108007.c
>
> diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
> index e8f9bec8227..5e923bf0557 100644
> --- a/gcc/cgraph.cc
> +++ b/gcc/cgraph.cc
> @@ -1403,11 +1403,17 @@ cgraph_edge::redirect_callee (cgraph_node *n)
>     speculative indirect call, remove "speculative" of the indirect call and
>     also redirect stmt to it's final direct target.
>  
> +   When called from within tree-inline, KILLED_SSAs has to contain the pointer
> +   to killed_new_ssa_names within the copy_body_data structure and SSAs
> +   discovered to be useless (if LHS is removed) will be added to it, otherwise
> +   it needs to be NULL.
> +
>     It is up to caller to iteratively transform each "speculative"
>     direct call as appropriate.  */
>  
>  gimple *
> -cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge *e)
> +cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge *e,
> +					   hash_set <tree> *killed_ssas)
>  {
>    tree decl = gimple_call_fndecl (e->call_stmt);
>    gcall *new_stmt;
> @@ -1527,7 +1533,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, false);
> +      new_stmt = padjs->modify_call (e, false, killed_ssas);
>        cgraph_node *origin = e->callee;
>        while (origin->clone_of)
>  	origin = origin->clone_of;
> diff --git a/gcc/cgraph.h b/gcc/cgraph.h
> index f5f54769eda..c1a3691b6f5 100644
> --- a/gcc/cgraph.h
> +++ b/gcc/cgraph.h
> @@ -1833,9 +1833,16 @@ public:
>       speculative indirect call, remove "speculative" of the indirect call and
>       also redirect stmt to it's final direct target.
>  
> +     When called from within tree-inline, KILLED_SSAs has to contain the
> +     pointer to killed_new_ssa_names within the copy_body_data structure and
> +     SSAs discovered to be useless (if LHS is removed) will be added to it,
> +     otherwise it needs to be NULL.
> +
>       It is up to caller to iteratively transform each "speculative"
>       direct call as appropriate.  */
> -  static gimple *redirect_call_stmt_to_callee (cgraph_edge *e);
> +  static gimple *redirect_call_stmt_to_callee (cgraph_edge *e,
> +					       hash_set <tree>
> +					       *killed_ssas = nullptr);
>  
>    /* Create clone of edge in the node N represented
>       by CALL_EXPR the callgraph.  */
> diff --git a/gcc/ipa-param-manipulation.cc b/gcc/ipa-param-manipulation.cc
> index a286af7f5d9..bf2adeb4bd6 100644
> --- a/gcc/ipa-param-manipulation.cc
> +++ b/gcc/ipa-param-manipulation.cc
> @@ -593,14 +593,63 @@ isra_get_ref_base_and_offset (tree expr, tree *base_p, unsigned *unit_offset_p)
>    return true;
>  }
>  
> +/* Remove all statements that use NAME and transitively those that use the
> +   result of such statements.  KILLED_SSAS contains the SSA_NAMEs that are
> +   already being or have been processed and new ones need to be added to it.
> +   The funtction only has to process situations handled by
> +   ssa_name_only_returned_p in ipa-sra.cc with the exception that it can assume
> +   it must never reach a use in a return statement.  */
> +
> +static void
> +purge_transitive_uses (tree name, hash_set <tree> *killed_ssas)
> +{
> +  imm_use_iterator imm_iter;
> +  gimple *stmt;
> +
> +  FOR_EACH_IMM_USE_STMT (stmt, imm_iter, name)
> +    {
> +      if (gimple_debug_bind_p (stmt))
> +	{
> +	  /* When runing within tree-inline, we will never end up here but
> +	     adding the SSAs to killed_ssas will do the trick in this case and
> +	     the respective debug statements will get reset. */
> +
> +	  gimple_debug_bind_reset_value (stmt);
> +	  update_stmt (stmt);
> +	  continue;
> +	}
> +
> +      tree lhs = NULL_TREE;
> +      if (is_gimple_assign (stmt))
> +	lhs = gimple_assign_lhs (stmt);
> +      else if (gimple_code (stmt) == GIMPLE_PHI)
> +	lhs = gimple_phi_result (stmt);
> +      gcc_assert (lhs
> +		  && (TREE_CODE (lhs) == SSA_NAME)
> +		  && !gimple_vdef (stmt));
> +
> +      if (!killed_ssas->contains (lhs))
> +	{
> +	  killed_ssas->add (lhs);
> +	  purge_transitive_uses (lhs, killed_ssas);
> +	  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
> +	  gsi_remove (&gsi, true);
> +	}
> +    }
> +}
> +
>  /* 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.  */
> +   be set to the caller.  When called from within tree-inline, KILLED_SSAs has
> +   to contain the pointer to killed_new_ssa_names within the copy_body_data
> +   structure and SSAs discovered to be useless (if LHS is removed) will be
> +   added to it, otherwise it needs to be NULL.  */
>  
>  gcall *
>  ipa_param_adjustments::modify_call (cgraph_edge *cs,
> -				    bool update_references)
> +				    bool update_references,
> +				    hash_set <tree> *killed_ssas)
>  {
>    gcall *stmt = cs->call_stmt;
>    tree callee_decl = cs->callee->decl;
> @@ -910,32 +959,20 @@ ipa_param_adjustments::modify_call (cgraph_edge *cs,
>  
>    gcall *new_stmt = gimple_build_call_vec (callee_decl, vargs);
>  
> -  tree ssa_to_remove = NULL;
> +  hash_set <tree> *ssas_to_remove = NULL;
>    if (tree lhs = gimple_call_lhs (stmt))
>      {
>        if (!m_skip_return)
>  	gimple_call_set_lhs (new_stmt, lhs);
>        else if (TREE_CODE (lhs) == SSA_NAME)
>  	{
> -	  /* LHS should now by a default-def SSA.  Unfortunately default-def
> -	     SSA_NAMEs need a backing variable (or at least some code examining
> -	     SSAs assumes it is non-NULL).  So we either have to re-use the
> -	     decl we have at hand or introdice a new one.  */
> -	  tree repl = create_tmp_var (TREE_TYPE (lhs), "removed_return");
> -	  repl = get_or_create_ssa_default_def (cfun, repl);
> -	  SSA_NAME_IS_DEFAULT_DEF (repl) = true;
> -	  imm_use_iterator ui;
> -	  use_operand_p use_p;
> -	  gimple *using_stmt;
> -	  FOR_EACH_IMM_USE_STMT (using_stmt, ui, lhs)
> +	  if (!killed_ssas)
>  	    {
> -	      FOR_EACH_IMM_USE_ON_STMT (use_p, ui)
> -		{
> -		  SET_USE (use_p, repl);
> -		}
> -	      update_stmt (using_stmt);
> +	      ssas_to_remove = new hash_set<tree> (8);
> +	      killed_ssas = ssas_to_remove;
>  	    }
> -	  ssa_to_remove = lhs;
> +	  killed_ssas->add (lhs);
> +	  purge_transitive_uses (lhs, killed_ssas);
>  	}
>      }
>  
> @@ -954,8 +991,12 @@ ipa_param_adjustments::modify_call (cgraph_edge *cs,
>        fprintf (dump_file, "\n");
>      }
>    gsi_replace (&gsi, new_stmt, true);
> -  if (ssa_to_remove)
> -    release_ssa_name (ssa_to_remove);
> +  if (ssas_to_remove)
> +    {
> +      for (tree sn : *ssas_to_remove)
> +	release_ssa_name (sn);
> +      delete ssas_to_remove;
> +    }
>    if (update_references)
>      do
>        {
> diff --git a/gcc/ipa-param-manipulation.h b/gcc/ipa-param-manipulation.h
> index 9798eedf0b6..5b2f90f8307 100644
> --- a/gcc/ipa-param-manipulation.h
> +++ b/gcc/ipa-param-manipulation.h
> @@ -224,7 +224,8 @@ public:
>  
>    /* Modify a call statement arguments (and possibly remove the return value)
>       as described in the data fields of this class.  */
> -  gcall *modify_call (cgraph_edge *cs, bool update_references);
> +  gcall *modify_call (cgraph_edge *cs, bool update_references,
> +		      hash_set <tree> *killed_ssas);
>    /* Return if the first parameter is left intact.  */
>    bool first_param_intact_p ();
>    /* Build a function type corresponding to the modified call.  */
> diff --git a/gcc/testsuite/gcc.dg/ipa/pr108007.c b/gcc/testsuite/gcc.dg/ipa/pr108007.c
> new file mode 100644
> index 00000000000..77fc95975cf
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/ipa/pr108007.c
> @@ -0,0 +1,32 @@
> +/* { dg-do run } */
> +/* { dg-options "-Os -fno-dce -fno-tree-dce -g" } */
> +
> +/* This tests that when IPA-SRA removes a LHS of a call statement which, in the
> +   original source, is fed into a useless operation which however can trap when
> +   given nonsensical input, that we remove it even when the user has turned off
> +   normal DCE.  */
> +
> +int a, b, d, e, f = 10000000, h;
> +short c, g;
> +static int *i() {
> +  g = f;
> + L:
> +  h = e = ~g;
> +  g = ~f % g & e;
> +  if (!g)
> +    goto L;
> +  c++;
> +  while (g < 1)
> +    ;
> +  return &a;
> +}
> +static void k() {
> +  int *l, m = 2;
> +  l = i();
> +  for (; d < 1; d++)
> +    m |= *l >= b;
> +}
> +int main() {
> +  k();
> +  return 0;
> +}
> diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc
> index 63a19f8d1d8..1c20e9545d1 100644
> --- a/gcc/tree-inline.cc
> +++ b/gcc/tree-inline.cc
> @@ -2982,20 +2982,19 @@ redirect_all_calls (copy_body_data * id, basic_block bb)
>  	  struct cgraph_edge *edge = id->dst_node->get_edge (stmt);
>  	  if (edge)
>  	    {
> +	      if (!id->killed_new_ssa_names)
> +		id->killed_new_ssa_names = new hash_set<tree> (16);
>  	      gimple *new_stmt
> -		= cgraph_edge::redirect_call_stmt_to_callee (edge);
> -	      /* If IPA-SRA transformation, run as part of edge redirection,
> -		 removed the LHS because it is unused, save it to
> -		 killed_new_ssa_names so that we can prune it from debug
> -		 statements.  */
> +		= cgraph_edge::redirect_call_stmt_to_callee (edge,
> +		    id->killed_new_ssa_names);
>  	      if (old_lhs
>  		  && TREE_CODE (old_lhs) == SSA_NAME
>  		  && !gimple_call_lhs (new_stmt))
> -		{
> -		  if (!id->killed_new_ssa_names)
> -		    id->killed_new_ssa_names = new hash_set<tree> (16);
> -		  id->killed_new_ssa_names->add (old_lhs);
> -		}
> +		/* In case of IPA-SRA removing the LHS, the name should have
> +		   been already added to the hash.  But in case of redirecting
> +		   to builtin_unreachable it was not and the name still should
> +		   be pruned from debug statements.  */
> +		id->killed_new_ssa_names->add (old_lhs);
>  
>  	      if (stmt == last && id->call_stmt && maybe_clean_eh_stmt (stmt))
>  		gimple_purge_dead_eh_edges (bb);
> @@ -3322,8 +3321,13 @@ copy_body (copy_body_data *id,
>    body = copy_cfg_body (id, entry_block_map, exit_block_map,
>  			new_entry);
>    copy_debug_stmts (id);
> -  delete id->killed_new_ssa_names;
> -  id->killed_new_ssa_names = NULL;
> +  if (id->killed_new_ssa_names)
> +    {
> +      for (tree sn : *id->killed_new_ssa_names)
> +	release_ssa_name (sn);
> +      delete id->killed_new_ssa_names;
> +      id->killed_new_ssa_names = NULL;
> +    }
>  
>    return body;
>  }
> -- 
> 2.40.0

  parent reply	other threads:[~2023-09-01 13:32 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-12 12:45 Martin Jambor
2023-05-12 19:21 ` Bernhard Reutner-Fischer
2023-06-13 15:11 ` Martin Jambor
2023-06-15  9:20   ` Bernhard Reutner-Fischer
2023-09-01 13:32 ` Martin Jambor [this message]
2023-09-19 11:36   ` Martin Jambor
2023-09-25  8:52     ` Jan Hubicka
2023-10-03 17:07       ` Martin Jambor
2023-10-05  0:08         ` Maciej W. Rozycki
2023-10-05  0:09           ` Andrew Pinski
2024-01-16 12:39 Martin Jambor
2024-01-22 17:21 ` Jan Hubicka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ri634zy58a1.fsf@suse.cz \
    --to=mjambor@suse.cz \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=hubicka@ucw.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).