ipa-sra: Don't consider CLOBBERS as writes preventing splitting

When IPA-SRA detects whether a parameter passed by reference is
written to, it does not special case CLOBBERs which means it often
bails out unnecessarily, especially when dealing with C++ destructors.
Fixed by the obvious continue in the two relevant loops and by adding
a simple function that marks the clobbers in the transformation code
as statements to be removed.

gcc/ChangeLog:

2023-08-04  Martin Jambor  <mjambor@suse.cz>

	PR ipa/110378
	* ipa-param-manipulation.h (class ipa_param_body_adjustments): New
	members get_ddef_if_exists_and_is_used and mark_clobbers_dead.
	* ipa-sra.cc (isra_track_scalar_value_uses): Ignore clobbers.
	(ptr_parm_has_nonarg_uses): Likewise.
	* ipa-param-manipulation.cc
	(ipa_param_body_adjustments::get_ddef_if_exists_and_is_used): New.
	(ipa_param_body_adjustments::mark_dead_statements): Move initial
	checks to get_ddef_if_exists_and_is_used.
	(ipa_param_body_adjustments::mark_clobbers_dead): New.
	(ipa_param_body_adjustments::common_initialization): Call
	mark_clobbers_dead when splitting.

gcc/testsuite/ChangeLog:

2023-07-31  Martin Jambor  <mjambor@suse.cz>

	PR ipa/110378
	* g++.dg/ipa/pr110378-1.C: New test.
This commit is contained in:
Martin Jambor 2023-08-07 19:13:41 +02:00
parent 8ae83274d8
commit da1a888b52
No known key found for this signature in database
GPG key ID: BF63C1BC3FA43540
4 changed files with 94 additions and 6 deletions

View file

@ -1072,6 +1072,20 @@ ipa_param_body_adjustments::carry_over_param (tree t)
return new_parm;
}
/* If DECL is a gimple register that has a default definition SSA name and that
has some uses, return the default definition, otherwise return NULL_TREE. */
tree
ipa_param_body_adjustments::get_ddef_if_exists_and_is_used (tree decl)
{
if (!is_gimple_reg (decl))
return NULL_TREE;
tree ddef = ssa_default_def (m_id->src_cfun, decl);
if (!ddef || has_zero_uses (ddef))
return NULL_TREE;
return ddef;
}
/* 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. Push all removed SSA names that
@ -1084,10 +1098,8 @@ 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))
tree parm_ddef = get_ddef_if_exists_and_is_used (dead_param);
if (!parm_ddef)
return;
auto_vec<tree, 4> stack;
@ -1169,6 +1181,28 @@ ipa_param_body_adjustments::mark_dead_statements (tree dead_param,
m_dead_ssa_debug_equiv.put (parm_ddef, dp_ddecl);
}
/* Put all clobbers of of dereference of default definition of PARAM into
m_dead_stmts. */
void
ipa_param_body_adjustments::mark_clobbers_dead (tree param)
{
if (!is_gimple_reg (param))
return;
tree ddef = get_ddef_if_exists_and_is_used (param);
if (!ddef)
return;
imm_use_iterator imm_iter;
use_operand_p use_p;
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, ddef)
{
gimple *stmt = USE_STMT (use_p);
if (gimple_clobber_p (stmt))
m_dead_stmts.add (stmt);
}
}
/* Callback to walk_tree. If REMAP is an SSA_NAME that is present in hash_map
passed in DATA, replace it with unshared version of what it was mapped to.
If an SSA argument would be remapped to NULL, the whole operation needs to
@ -1504,6 +1538,8 @@ ipa_param_body_adjustments::common_initialization (tree old_fndecl,
that will guide what not to copy to the new body. */
if (!split[i])
mark_dead_statements (m_oparms[i], &ssas_to_process_debug);
else
mark_clobbers_dead (m_oparms[i]);
if (MAY_HAVE_DEBUG_STMTS
&& is_gimple_reg (m_oparms[i]))
m_reset_debug_decls.safe_push (m_oparms[i]);

View file

@ -378,7 +378,9 @@ private:
bool modify_call_stmt (gcall **stmt_p, gimple *orig_stmt);
bool modify_cfun_body ();
void reset_debug_stmts ();
tree get_ddef_if_exists_and_is_used (tree decl);
void mark_dead_statements (tree dead_param, vec<tree> *debugstack);
void mark_clobbers_dead (tree dead_param);
bool prepare_debug_expressions (tree dead_ssa);
/* Declaration of the function that is being transformed. */

View file

@ -898,7 +898,8 @@ isra_track_scalar_value_uses (function *fun, cgraph_node *node, tree name,
FOR_EACH_IMM_USE_STMT (stmt, imm_iter, name)
{
if (is_gimple_debug (stmt))
if (is_gimple_debug (stmt)
|| gimple_clobber_p (stmt))
continue;
/* TODO: We could handle at least const builtin functions like arithmetic
@ -1056,7 +1057,8 @@ ptr_parm_has_nonarg_uses (cgraph_node *node, function *fun, tree parm,
unsigned uses_ok = 0;
use_operand_p use_p;
if (is_gimple_debug (stmt))
if (is_gimple_debug (stmt)
|| gimple_clobber_p (stmt))
continue;
if (gimple_assign_single_p (stmt))

View file

@ -0,0 +1,48 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-ipa-sra -fdump-tree-optimized-slim" } */
/* Test that even though destructors end with clobbering all of *this, it
should not prevent IPA-SRA. */
namespace {
class foo
{
public:
short move_offset_of_a;
int *a;
foo(int c)
{
a = new int[c];
a[0] = 4;
}
__attribute__((noinline)) ~foo();
int f ()
{
return a[0] + 1;
}
};
volatile int v1 = 4;
__attribute__((noinline)) foo::~foo()
{
delete[] a;
return;
}
}
volatile int v2 = 20;
int test (void)
{
foo shouldnotexist(v2);
v2 = shouldnotexist.f();
return 0;
}
/* { dg-final { scan-ipa-dump "Will split parameter 0" "sra" } } */
/* { dg-final { scan-tree-dump-not "shouldnotexist" "optimized" } } */