diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/gimple.c | 41 | ||||
-rw-r--r-- | gcc/gimple.h | 1 | ||||
-rw-r--r-- | gcc/ipa-modref.c | 145 | ||||
-rw-r--r-- | gcc/ipa-modref.h | 1 | ||||
-rw-r--r-- | gcc/tree-ssa-structalias.c | 29 |
5 files changed, 170 insertions, 47 deletions
diff --git a/gcc/gimple.c b/gcc/gimple.c index cc7a88e..22dd641 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -1597,7 +1597,12 @@ gimple_call_arg_flags (const gcall *stmt, unsigned arg) if (!node->binds_to_current_def_p ()) { if ((modref_flags & EAF_UNUSED) && !(flags & EAF_UNUSED)) - modref_flags &= ~EAF_UNUSED; + { + modref_flags &= ~EAF_UNUSED; + modref_flags |= EAF_NOESCAPE; + } + if ((modref_flags & EAF_NOREAD) && !(flags & EAF_NOREAD)) + modref_flags &= ~EAF_NOREAD; if ((modref_flags & EAF_DIRECT) && !(flags & EAF_DIRECT)) modref_flags &= ~EAF_DIRECT; } @@ -1608,6 +1613,40 @@ gimple_call_arg_flags (const gcall *stmt, unsigned arg) return flags; } +/* Detects argument flags for return slot on call STMT. */ + +int +gimple_call_retslot_flags (const gcall *stmt) +{ + int flags = EAF_DIRECT | EAF_NOREAD; + + 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->retslot_flags; + + /* We have possibly optimized out load. Be conservative here. */ + if (!node->binds_to_current_def_p ()) + { + if ((modref_flags & EAF_UNUSED) && !(flags & EAF_UNUSED)) + { + modref_flags &= ~EAF_UNUSED; + modref_flags |= EAF_NOESCAPE; + } + } + 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 303623b..23a124e 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -1589,6 +1589,7 @@ gimple_seq gimple_seq_copy (gimple_seq); 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_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 0bbec8d..3539cb4 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -86,6 +86,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "tree-ssanames.h" #include "attribs.h" +#include "tree-cfg.h" namespace { @@ -133,7 +134,7 @@ static fnspec_summaries_t *fnspec_summaries = NULL; struct escape_entry { /* Parameter that escapes at a given call. */ - unsigned int parm_index; + int parm_index; /* Argument it escapes to. */ unsigned int arg; /* Minimal flags known about the argument. */ @@ -269,7 +270,7 @@ 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), writes_errno (NULL) + : loads (NULL), stores (NULL), retslot_flags (0), writes_errno (false) { } @@ -322,6 +323,8 @@ modref_summary::useful_p (int ecf_flags, bool check_flags) if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags)) return true; arg_flags.release (); + if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false)) + return true; if (ecf_flags & ECF_CONST) return false; if (loads && !loads->every_base) @@ -363,6 +366,7 @@ struct GTY(()) modref_summary_lto modref_records_lto *loads; modref_records_lto *stores; auto_vec<eaf_flags_t> GTY((skip)) arg_flags; + eaf_flags_t retslot_flags; bool writes_errno; modref_summary_lto (); @@ -374,7 +378,7 @@ struct GTY(()) modref_summary_lto /* Summary for a single function which this pass produces. */ modref_summary_lto::modref_summary_lto () - : loads (NULL), stores (NULL), writes_errno (NULL) + : loads (NULL), stores (NULL), retslot_flags (0), writes_errno (false) { } @@ -400,6 +404,8 @@ modref_summary_lto::useful_p (int ecf_flags, bool check_flags) if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags)) return true; arg_flags.release (); + if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false)) + return true; if (ecf_flags & ECF_CONST) return false; if (loads && !loads->every_base) @@ -608,6 +614,11 @@ modref_summary::dump (FILE *out) dump_eaf_flags (out, arg_flags[i]); } } + if (retslot_flags) + { + fprintf (out, " Retslot flags:"); + dump_eaf_flags (out, retslot_flags); + } } /* Dump summary. */ @@ -630,6 +641,11 @@ modref_summary_lto::dump (FILE *out) dump_eaf_flags (out, arg_flags[i]); } } + if (retslot_flags) + { + fprintf (out, " Retslot flags:"); + dump_eaf_flags (out, retslot_flags); + } } /* Get function summary for FUNC if it exists, return NULL otherwise. */ @@ -1396,6 +1412,11 @@ namespace { struct escape_point { + /* Extra hidden args we keep track of. */ + enum hidden_args + { + retslot_arg = -1 + }; /* Value escapes to this call. */ gcall *call; /* Argument it escapes to. */ @@ -1705,7 +1726,11 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth, Returning name counts as an use by tree-ssa-structalias.c */ if (greturn *ret = dyn_cast <greturn *> (use_stmt)) { - if (gimple_return_retval (ret) == name) + /* Returning through return slot is seen as memory write earlier. */ + if (DECL_RESULT (current_function_decl) + && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl))) + ; + else if (gimple_return_retval (ret) == name) lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED)); else if (memory_access_to (gimple_return_retval (ret), name)) { @@ -1748,7 +1773,7 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth, may make LHS to escape. See PR 98499. */ if (gimple_call_return_slot_opt_p (call) && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call)))) - lattice[index].merge (EAF_NOREAD | EAF_DIRECT); + lattice[index].merge (gimple_call_retslot_flags (call)); } /* We do not track accesses to the static chain (we could) @@ -1777,7 +1802,7 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth, lattice[index].merge (call_flags); else lattice[index].add_escape_point (call, i, - call_flags, true); + call_flags, true); } if (!ignore_retval) merge_call_lhs_flags (call, i, index, false, @@ -1912,6 +1937,29 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth, lattice[index].known = true; } +/* Record escape points of PARM_INDEX according to LATTICE. */ + +static void +record_escape_points (modref_lattice &lattice, int parm_index, int flags) +{ + if (lattice.escape_points.length ()) + { + escape_point *ep; + unsigned int ip; + cgraph_node *node = cgraph_node::get (current_function_decl); + + FOR_EACH_VEC_ELT (lattice.escape_points, ip, ep) + if ((ep->min_flags & flags) != flags) + { + cgraph_edge *e = node->get_edge (ep->call); + struct escape_entry ee = {parm_index, ep->arg, + ep->min_flags, ep->direct}; + + escape_summaries->get_create (e)->esc.safe_push (ee); + } + } +} + /* Determine EAF flags for function parameters. */ static void @@ -1921,16 +1969,22 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto, unsigned int parm_index = 0; unsigned int count = 0; int ecf_flags = flags_from_decl_or_type (current_function_decl); + tree retslot = NULL; /* For novops functions we have nothing to gain by EAF flags. */ if (ecf_flags & ECF_NOVOPS) return; + /* If there is return slot, look up its SSA name. */ + if (DECL_RESULT (current_function_decl) + && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl))) + retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl)); + for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm = TREE_CHAIN (parm)) count++; - if (!count) + if (!count && !retslot) return; auto_vec<modref_lattice> lattice; @@ -1984,24 +2038,24 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto, summary_lto->arg_flags.safe_grow_cleared (count, true); summary_lto->arg_flags[parm_index] = flags; } - if (lattice[SSA_NAME_VERSION (name)].escape_points.length ()) - { - escape_point *ep; - unsigned int ip; - cgraph_node *node = cgraph_node::get (current_function_decl); - - gcc_checking_assert (ipa); - FOR_EACH_VEC_ELT - (lattice[SSA_NAME_VERSION (name)].escape_points, ip, ep) - if ((ep->min_flags & flags) != flags) - { - cgraph_edge *e = node->get_edge (ep->call); - struct escape_entry ee = {parm_index, ep->arg, - ep->min_flags, ep->direct}; + record_escape_points (lattice[SSA_NAME_VERSION (name)], + parm_index, flags); + } + } + if (retslot) + { + analyze_ssa_name_flags (retslot, lattice, 0, ipa); + int flags = lattice[SSA_NAME_VERSION (retslot)].flags; - escape_summaries->get_create (e)->esc.safe_push (ee); - } - } + flags = remove_useless_eaf_flags (flags, ecf_flags, false); + if (flags) + { + if (summary) + summary->retslot_flags = flags; + if (summary_lto) + summary_lto->retslot_flags = flags; + record_escape_points (lattice[SSA_NAME_VERSION (retslot)], + escape_point::retslot_arg, flags); } } if (ipa) @@ -2287,6 +2341,7 @@ modref_summaries::duplicate (cgraph_node *, cgraph_node *dst, dst_data->writes_errno = src_data->writes_errno; if (src_data->arg_flags.length ()) dst_data->arg_flags = src_data->arg_flags.copy (); + dst_data->retslot_flags = src_data->retslot_flags; } /* Called when new clone is inserted to callgraph late. */ @@ -2312,6 +2367,7 @@ modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *, dst_data->writes_errno = src_data->writes_errno; if (src_data->arg_flags.length ()) dst_data->arg_flags = src_data->arg_flags.copy (); + dst_data->retslot_flags = src_data->retslot_flags; } namespace @@ -2551,7 +2607,7 @@ modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum) escape_entry *ee; FOR_EACH_VEC_ELT (esum->esc, i, ee) { - bp_pack_var_len_unsigned (bp, ee->parm_index); + bp_pack_var_len_int (bp, ee->parm_index); bp_pack_var_len_unsigned (bp, ee->arg); bp_pack_var_len_unsigned (bp, ee->min_flags); bp_pack_value (bp, ee->direct, 1); @@ -2571,7 +2627,7 @@ modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e) for (unsigned int i = 0; i < n; i++) { escape_entry ee; - ee.parm_index = bp_unpack_var_len_unsigned (bp); + ee.parm_index = bp_unpack_var_len_int (bp); ee.arg = bp_unpack_var_len_unsigned (bp); ee.min_flags = bp_unpack_var_len_unsigned (bp); ee.direct = bp_unpack_value (bp, 1); @@ -2628,6 +2684,7 @@ modref_write () streamer_write_uhwi (ob, r->arg_flags.length ()); 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); write_modref_records (r->loads, ob); write_modref_records (r->stores, ob); @@ -2724,6 +2781,11 @@ read_section (struct lto_file_decl_data *file_data, const char *data, if (modref_sum_lto) modref_sum_lto->arg_flags.quick_push (flags); } + eaf_flags_t flags = streamer_read_uhwi (&ib); + if (modref_sum) + modref_sum->retslot_flags = flags; + if (modref_sum_lto) + modref_sum_lto->retslot_flags = flags; read_modref_records (&ib, data_in, modref_sum ? &modref_sum->loads : NULL, modref_sum_lto ? &modref_sum_lto->loads : NULL); @@ -3098,7 +3160,7 @@ struct escape_map bool direct; }; -/* Update escape map fo E. */ +/* Update escape map for E. */ static void update_escape_summary_1 (cgraph_edge *e, @@ -3117,7 +3179,10 @@ update_escape_summary_1 (cgraph_edge *e, { unsigned int j; struct escape_map *em; - if (ee->parm_index >= map.length ()) + /* TODO: We do not have jump functions for return slots, so we + never propagate them to outer function. */ + if (ee->parm_index >= (int)map.length () + || ee->parm_index < 0) continue; FOR_EACH_VEC_ELT (map[ee->parm_index], j, em) { @@ -3125,7 +3190,7 @@ update_escape_summary_1 (cgraph_edge *e, if (ee->direct && !em->direct) min_flags = deref_flags (min_flags, ignore_stores); struct escape_entry entry = {em->parm_index, ee->arg, - ee->min_flags, + ee->min_flags, ee->direct & em->direct}; sum->esc.safe_push (entry); } @@ -3245,7 +3310,11 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) FOR_EACH_VEC_ELT (sum->esc, i, ee) { bool needed = false; - if (to_info && to_info->arg_flags.length () > ee->parm_index) + /* TODO: We do not have jump functions for return slots, so we + never propagate them to outer function. */ + if (ee->parm_index < 0) + continue; + if (to_info && (int)to_info->arg_flags.length () > ee->parm_index) { int flags = callee_info && callee_info->arg_flags.length () > ee->arg @@ -3259,7 +3328,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) if (to_info->arg_flags[ee->parm_index]) needed = true; } - if (to_info_lto && to_info_lto->arg_flags.length () > ee->parm_index) + if (to_info_lto && (int)to_info_lto->arg_flags.length () > ee->parm_index) { int flags = callee_info_lto && callee_info_lto->arg_flags.length () > ee->arg @@ -3798,29 +3867,31 @@ modref_merge_call_site_flags (escape_summary *sum, if (flags_lto & EAF_NOESCAPE) flags_lto |= EAF_NODIRECTESCAPE; if (!(flags & EAF_UNUSED) - && cur_summary && ee->parm_index < cur_summary->arg_flags.length ()) + && cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ()) { - int f = cur_summary->arg_flags[ee->parm_index]; + eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg + ? cur_summary->retslot_flags + : cur_summary->arg_flags[ee->parm_index]; if ((f & flags) != f) { f = remove_useless_eaf_flags (f & flags, ecf_flags, VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller)))); - cur_summary->arg_flags[ee->parm_index] = f; changed = true; } } if (!(flags_lto & EAF_UNUSED) && cur_summary_lto - && ee->parm_index < cur_summary_lto->arg_flags.length ()) + && ee->parm_index < (int)cur_summary_lto->arg_flags.length ()) { - int f = cur_summary_lto->arg_flags[ee->parm_index]; + eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg + ? cur_summary_lto->retslot_flags + : cur_summary_lto->arg_flags[ee->parm_index]; if ((f & flags_lto) != f) { f = remove_useless_eaf_flags (f & flags_lto, ecf_flags, VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller)))); - cur_summary_lto->arg_flags[ee->parm_index] = f; changed = true; } } diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h index 5afa3aa..a4db274 100644 --- a/gcc/ipa-modref.h +++ b/gcc/ipa-modref.h @@ -31,6 +31,7 @@ struct GTY(()) modref_summary modref_records *loads; modref_records *stores; auto_vec<eaf_flags_t> GTY((skip)) arg_flags; + eaf_flags_t retslot_flags; bool writes_errno; modref_summary (); diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index 35971a5..99072df 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -4254,17 +4254,28 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results, && gimple_call_lhs (stmt) != NULL_TREE && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt)))) { - auto_vec<ce_s> tmpc; - struct constraint_expr *c; - unsigned i; + int flags = gimple_call_retslot_flags (stmt); + if ((flags & (EAF_NOESCAPE | EAF_NOT_RETURNED)) + != (EAF_NOESCAPE | EAF_NOT_RETURNED)) + { + auto_vec<ce_s> tmpc; - get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc); + get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc); - make_constraints_to (callescape->id, tmpc); - if (writes_global_memory) - make_constraints_to (escaped_id, tmpc); - FOR_EACH_VEC_ELT (tmpc, i, c) - results->safe_push (*c); + if (!(flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE))) + { + make_constraints_to (callescape->id, tmpc); + if (writes_global_memory) + make_constraints_to (escaped_id, tmpc); + } + if (!(flags & EAF_NOT_RETURNED)) + { + struct constraint_expr *c; + unsigned i; + FOR_EACH_VEC_ELT (tmpc, i, c) + results->safe_push (*c); + } + } } } |