From a70c05120ae6f15f204a04a7df7d19941ab33ef1 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Tue, 2 Nov 2021 18:57:51 +0100 Subject: [PATCH] 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. --- gcc/gimple.c | 27 +++++++++++++++ gcc/gimple.h | 1 + gcc/ipa-modref.c | 65 +++++++++++++++++++++++++++++++++---- gcc/ipa-modref.h | 1 + gcc/testsuite/gcc.dg/ipa/modref-3.c | 20 ++++++++++++ gcc/tree-ssa-structalias.c | 3 +- 6 files changed, 109 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/ipa/modref-3.c diff --git a/gcc/gimple.c b/gcc/gimple.c index 22dd641..76768c1 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 23a124e..3cde3cd 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 c0aae08..bb51312 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -272,7 +272,8 @@ static GTY(()) fast_function_summary /* 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 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 &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 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) { diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h index a4db274..ddc8686 100644 --- a/gcc/ipa-modref.h +++ b/gcc/ipa-modref.h @@ -32,6 +32,7 @@ struct GTY(()) modref_summary modref_records *stores; auto_vec 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 0000000..8401354 --- /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 5f24c01..c70f5af 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -4254,7 +4254,8 @@ handle_rhs_call (gcall *stmt, vec *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. */ -- 2.7.4