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: Tue, 19 Sep 2023 13:36:59 +0200	[thread overview]
Message-ID: <ri6y1h2bdic.fsf@suse.cz> (raw)
In-Reply-To: <ri634zy58a1.fsf@suse.cz>

Hello,

and ping.

Thanks,

Martin


On Fri, Sep 01 2023, Martin Jambor wrote:
> 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

  reply	other threads:[~2023-09-19 11:37 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
2023-09-19 11:36   ` Martin Jambor [this message]
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=ri6y1h2bdic.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).