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:
parent
164bbf701f
commit
a70c05120a
27
gcc/gimple.c
27
gcc/gimple.c
|
@ -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
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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" } } */
|
|
@ -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. */
|
||||
|
|
Loading…
Reference in New Issue