Add static_chain support to ipa-modref
Commit Message
Hi,
this is patchs teaches 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.
Bootstrapped/regtested x86_64-linux, OK?
Honza
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.
Comments
On Mon, 1 Nov 2021, Jan Hubicka wrote:
> Hi,
> this is patchs teaches 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.
>
> Bootstrapped/regtested x86_64-linux, OK?
OK.
Thanks,
Richard.
> Honza
>
> 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.
>
> diff --git a/gcc/gimple.c b/gcc/gimple.c
> index 22dd6417d19..ef07d9385c5 100644
> --- a/gcc/gimple.c
> +++ b/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
> diff --git a/gcc/gimple.h b/gcc/gimple.h
> index 23a124ec769..3cde3cde7fe 100644
> --- a/gcc/gimple.h
> +++ b/gcc/gimple.h
> @@ -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 *);
> diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
> index d866d9ed6b3..ae8ed53b396 100644
> --- a/gcc/ipa-modref.c
> +++ b/gcc/ipa-modref.c
> @@ -270,7 +270,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)
> {
> }
>
> @@ -325,6 +326,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)
> @@ -367,6 +371,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 ();
> @@ -378,7 +383,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)
> {
> }
>
> @@ -406,6 +412,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)
> @@ -619,6 +628,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. */
> @@ -646,6 +660,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. */
> @@ -1415,7 +1434,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;
> @@ -1776,11 +1796,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);
> @@ -1970,6 +1988,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)
> @@ -1979,12 +1998,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;
> @@ -2058,6 +2079,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 ();
> @@ -2342,6 +2379,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. */
> @@ -2368,6 +2406,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
> @@ -2685,6 +2724,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);
> @@ -2786,6 +2826,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);
> @@ -3871,6 +3918,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)
> {
> @@ -3886,6 +3935,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)
> {
> diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h
> index a4db27471eb..ddc86869069 100644
> --- a/gcc/ipa-modref.h
> +++ b/gcc/ipa-modref.h
> @@ -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 ();
> diff --git a/gcc/testsuite/gcc.dg/ipa/modref-3.c b/gcc/testsuite/gcc.dg/ipa/modref-3.c
> new file mode 100644
> index 00000000000..84013541ce8
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/ipa/modref-3.c
> @@ -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" } } */
> diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
> index 99072df0768..d2a955dafeb 100644
> --- a/gcc/tree-ssa-structalias.c
> +++ b/gcc/tree-ssa-structalias.c
> @@ -4246,7 +4246,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. */
>
@@ -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 *);
@@ -270,7 +270,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)
{
}
@@ -325,6 +326,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)
@@ -367,6 +371,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 ();
@@ -378,7 +383,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)
{
}
@@ -406,6 +412,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)
@@ -619,6 +628,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. */
@@ -646,6 +660,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. */
@@ -1415,7 +1434,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;
@@ -1776,11 +1796,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);
@@ -1970,6 +1988,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)
@@ -1979,12 +1998,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;
@@ -2058,6 +2079,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 ();
@@ -2342,6 +2379,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. */
@@ -2368,6 +2406,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
@@ -2685,6 +2724,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);
@@ -2786,6 +2826,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);
@@ -3871,6 +3918,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)
{
@@ -3886,6 +3935,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 ();
new file mode 100644
@@ -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" } } */
@@ -4246,7 +4246,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. */