Static chain support in ipa-modref

Teach ipa-modref about the static chain that is, like
retslot, a hiden argument.  The patch is pretty much symemtric to what
was done for retslot handling and I verified it does the intended job
for Ada LTO bootstrap.

gcc/ChangeLog:

	* gimple.c (gimple_call_static_chain_flags): New function.
	* gimple.h (gimple_call_static_chain_flags): Declare
	* ipa-modref.c (modref_summary::modref_summary): Initialize
	static_chain_flags.
	(modref_summary_lto::modref_summary_lto): Likewise.
	(modref_summary::useful_p): Test static_chain_flags.
	(modref_summary_lto::useful_p): Likewise.
	(struct modref_summary_lto): Add static_chain_flags.
	(modref_summary::dump): Dump static_chain_flags.
	(modref_summary_lto::dump): Likewise.
	(struct escape_point): Add static_cahin_arg.
	(analyze_ssa_name_flags): Use gimple_call_static_chain_flags.
	(analyze_parms): Handle static chains.
	(modref_summaries::duplicate): Duplicate static_chain_flags.
	(modref_summaries_lto::duplicate): Likewise.
	(modref_write): Stream static_chain_flags.
	(read_section): Likewise.
	(modref_merge_call_site_flags): Handle static_chain_flags.
	* ipa-modref.h (struct modref_summary): Add static_chain_flags.
	* tree-ssa-structalias.c (handle_rhs_call): Use
	gimple_static_chain_flags.

gcc/testsuite/ChangeLog:

	* gcc.dg/ipa/modref-3.c: New test.
This commit is contained in:
Jan Hubicka 2021-11-02 18:57:51 +01:00
parent 164bbf701f
commit a70c05120a
6 changed files with 109 additions and 8 deletions

View File

@ -1647,6 +1647,33 @@ gimple_call_retslot_flags (const gcall *stmt)
return flags;
}
/* Detects argument flags for static chain on call STMT. */
int
gimple_call_static_chain_flags (const gcall *stmt)
{
int flags = 0;
tree callee = gimple_call_fndecl (stmt);
if (callee)
{
cgraph_node *node = cgraph_node::get (callee);
modref_summary *summary = node ? get_modref_function_summary (node)
: NULL;
if (summary)
{
int modref_flags = summary->static_chain_flags;
/* We have possibly optimized out load. Be conservative here. */
gcc_checking_assert (node->binds_to_current_def_p ());
if (dbg_cnt (ipa_mod_ref_pta))
flags |= modref_flags;
}
}
return flags;
}
/* Detects return flags for the call STMT. */
int

View File

@ -1590,6 +1590,7 @@ bool gimple_call_same_target_p (const gimple *, const gimple *);
int gimple_call_flags (const gimple *);
int gimple_call_arg_flags (const gcall *, unsigned);
int gimple_call_retslot_flags (const gcall *);
int gimple_call_static_chain_flags (const gcall *);
int gimple_call_return_flags (const gcall *);
bool gimple_call_nonnull_result_p (gcall *);
tree gimple_call_nonnull_arg (gcall *);

View File

@ -272,7 +272,8 @@ static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
/* Summary for a single function which this pass produces. */
modref_summary::modref_summary ()
: loads (NULL), stores (NULL), retslot_flags (0), writes_errno (false)
: loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
writes_errno (false)
{
}
@ -327,6 +328,9 @@ modref_summary::useful_p (int ecf_flags, bool check_flags)
arg_flags.release ();
if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
return true;
if (check_flags
&& remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
return true;
if (ecf_flags & ECF_CONST)
return false;
if (loads && !loads->every_base)
@ -369,6 +373,7 @@ struct GTY(()) modref_summary_lto
modref_records_lto *stores;
auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
eaf_flags_t retslot_flags;
eaf_flags_t static_chain_flags;
bool writes_errno;
modref_summary_lto ();
@ -380,7 +385,8 @@ struct GTY(()) modref_summary_lto
/* Summary for a single function which this pass produces. */
modref_summary_lto::modref_summary_lto ()
: loads (NULL), stores (NULL), retslot_flags (0), writes_errno (false)
: loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
writes_errno (false)
{
}
@ -408,6 +414,9 @@ modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
arg_flags.release ();
if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
return true;
if (check_flags
&& remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
return true;
if (ecf_flags & ECF_CONST)
return false;
if (loads && !loads->every_base)
@ -621,6 +630,11 @@ modref_summary::dump (FILE *out)
fprintf (out, " Retslot flags:");
dump_eaf_flags (out, retslot_flags);
}
if (static_chain_flags)
{
fprintf (out, " Static chain flags:");
dump_eaf_flags (out, static_chain_flags);
}
}
/* Dump summary. */
@ -648,6 +662,11 @@ modref_summary_lto::dump (FILE *out)
fprintf (out, " Retslot flags:");
dump_eaf_flags (out, retslot_flags);
}
if (static_chain_flags)
{
fprintf (out, " Static chain flags:");
dump_eaf_flags (out, static_chain_flags);
}
}
/* Get function summary for FUNC if it exists, return NULL otherwise. */
@ -1417,7 +1436,8 @@ struct escape_point
/* Extra hidden args we keep track of. */
enum hidden_args
{
retslot_arg = -1
retslot_arg = -1,
static_chain_arg = -2
};
/* Value escapes to this call. */
gcall *call;
@ -1787,11 +1807,9 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
lattice[index].merge (gimple_call_retslot_flags (call));
}
/* We do not track accesses to the static chain (we could)
so give up. */
if (gimple_call_chain (call)
&& (gimple_call_chain (call) == name))
lattice[index].merge (0);
lattice[index].merge (gimple_call_static_chain_flags (call));
/* Process internal functions and right away. */
bool record_ipa = ipa && !gimple_call_internal_p (call);
@ -1983,6 +2001,7 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
unsigned int count = 0;
int ecf_flags = flags_from_decl_or_type (current_function_decl);
tree retslot = NULL;
tree static_chain = NULL;
/* For novops functions we have nothing to gain by EAF flags. */
if (ecf_flags & ECF_NOVOPS)
@ -1992,12 +2011,14 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
if (DECL_RESULT (current_function_decl)
&& DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
if (cfun->static_chain_decl)
static_chain = ssa_default_def (cfun, cfun->static_chain_decl);
for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
parm = TREE_CHAIN (parm))
count++;
if (!count && !retslot)
if (!count && !retslot && !static_chain)
return;
auto_vec<modref_lattice> lattice;
@ -2071,6 +2092,22 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
escape_point::retslot_arg, flags);
}
}
if (static_chain)
{
analyze_ssa_name_flags (static_chain, lattice, 0, ipa);
int flags = lattice[SSA_NAME_VERSION (static_chain)].flags;
flags = remove_useless_eaf_flags (flags, ecf_flags, false);
if (flags)
{
if (summary)
summary->static_chain_flags = flags;
if (summary_lto)
summary_lto->static_chain_flags = flags;
record_escape_points (lattice[SSA_NAME_VERSION (static_chain)],
escape_point::static_chain_arg, flags);
}
}
if (ipa)
for (unsigned int i = 0; i < num_ssa_names; i++)
lattice[i].release ();
@ -2355,6 +2392,7 @@ modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
if (src_data->arg_flags.length ())
dst_data->arg_flags = src_data->arg_flags.copy ();
dst_data->retslot_flags = src_data->retslot_flags;
dst_data->static_chain_flags = src_data->static_chain_flags;
}
/* Called when new clone is inserted to callgraph late. */
@ -2381,6 +2419,7 @@ modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
if (src_data->arg_flags.length ())
dst_data->arg_flags = src_data->arg_flags.copy ();
dst_data->retslot_flags = src_data->retslot_flags;
dst_data->static_chain_flags = src_data->static_chain_flags;
}
namespace
@ -2698,6 +2737,7 @@ modref_write ()
for (unsigned int i = 0; i < r->arg_flags.length (); i++)
streamer_write_uhwi (ob, r->arg_flags[i]);
streamer_write_uhwi (ob, r->retslot_flags);
streamer_write_uhwi (ob, r->static_chain_flags);
write_modref_records (r->loads, ob);
write_modref_records (r->stores, ob);
@ -2799,6 +2839,13 @@ read_section (struct lto_file_decl_data *file_data, const char *data,
modref_sum->retslot_flags = flags;
if (modref_sum_lto)
modref_sum_lto->retslot_flags = flags;
flags = streamer_read_uhwi (&ib);
if (modref_sum)
modref_sum->static_chain_flags = flags;
if (modref_sum_lto)
modref_sum_lto->static_chain_flags = flags;
read_modref_records (&ib, data_in,
modref_sum ? &modref_sum->loads : NULL,
modref_sum_lto ? &modref_sum_lto->loads : NULL);
@ -3888,6 +3935,8 @@ modref_merge_call_site_flags (escape_summary *sum,
{
eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg
? cur_summary->retslot_flags
: ee->parm_index == escape_point::static_chain_arg
? cur_summary->static_chain_flags
: cur_summary->arg_flags[ee->parm_index];
if ((f & flags) != f)
{
@ -3903,6 +3952,8 @@ modref_merge_call_site_flags (escape_summary *sum,
{
eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg
? cur_summary_lto->retslot_flags
: ee->parm_index == escape_point::static_chain_arg
? cur_summary_lto->static_chain_flags
: cur_summary_lto->arg_flags[ee->parm_index];
if ((f & flags_lto) != f)
{

View File

@ -32,6 +32,7 @@ struct GTY(()) modref_summary
modref_records *stores;
auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
eaf_flags_t retslot_flags;
eaf_flags_t static_chain_flags;
bool writes_errno;
modref_summary ();

View File

@ -0,0 +1,20 @@
/* { dg-options "-O2 -fdump-ipa-modref" } */
/* { dg-do link } */
int *ptr;
void linker_error ();
int
main ()
{
int a;
__attribute__((noinline)) int test2 ()
{
ptr = 0;
return a;
}
a = 1;
test2 ();
if (a != 1)
linker_error ();
return 0;
}
/* { dg-final { scan-ipa-dump "Static chain flags: noclobber noescape nodirectescape" "modref" } } */

View File

@ -4254,7 +4254,8 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results,
/* The static chain escapes as well. */
if (gimple_call_chain (stmt))
handle_call_arg (stmt, gimple_call_chain (stmt), results,
implicit_eaf_flags,
implicit_eaf_flags
| gimple_call_static_chain_flags (stmt),
callescape->id, writes_global_memory);
/* And if we applied NRV the address of the return slot escapes as well. */