From bb07490abba850fd5b1d2d09d76d18b8bdc7d817 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 25 Nov 2020 20:51:26 +0100 Subject: [PATCH] Add EAF_NODIRECTESCAPE flag Main limitation of modref is the fact that it does not track anything in memory. This is intentional - I wanted the initial implementation to be cheap. However it also makes it very limited when it comes to detecting noescape especially because it is paranoid about what memory accesses may be used to copy (bits of) pointers. This patch adds EAF_NODIRECTSCAPE that is weaker vairant of EAF_NOESCAPE where we only know that the pointer itself does not escape, but memory pointed to may. This is a lot more reliable to auto-detect that EAF_NOESCAPE and still enables additional optimization. With patch we get nodirectscape flag for b that enables in practice similar optimization as EAF_NOESCAPE for arrays of integers that points nowhere :) gcc/ChangeLog: * gimple.c (gimple_call_arg_flags): Also imply EAF_NODIRECTESCAPE. * tree-core.h (EAF_NODRECTESCAPE): New flag. * tree-ssa-structalias.c (make_indirect_escape_constraint): New function. (handle_rhs_call): Hanlde EAF_NODIRECTESCAPE. * ipa-modref.c (dump_eaf_flags): Print EAF_NODIRECTESCAPE. (deref_flags): Dereference is always EAF_NODIRECTESCAPE. (modref_lattice::init): Also set EAF_NODIRECTESCAPE. (analyze_ssa_name_flags): Pure functions do not affect EAF_NODIRECTESCAPE. (analyze_params): Likewise. (ipa_merge_modref_summary_after_inlining): Likewise. (modref_merge_call_site_flags): Likewise. --- gcc/gimple.c | 2 +- gcc/ipa-modref.c | 20 ++++++++++++-------- gcc/tree-core.h | 4 ++++ gcc/tree-ssa-structalias.c | 25 +++++++++++++++++++++++-- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/gcc/gimple.c b/gcc/gimple.c index e3e508daf2f..e8246b72cc9 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -1543,7 +1543,7 @@ gimple_call_arg_flags (const gcall *stmt, unsigned arg) if (fnspec.arg_direct_p (arg)) flags |= EAF_DIRECT; if (fnspec.arg_noescape_p (arg)) - flags |= EAF_NOESCAPE; + flags |= EAF_NOESCAPE | EAF_NODIRECTESCAPE; if (fnspec.arg_readonly_p (arg)) flags |= EAF_NOCLOBBER; } diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 0ba1a748257..d1d4ba786a4 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -151,6 +151,8 @@ dump_eaf_flags (FILE *out, int flags, bool newline = true) fprintf (out, " noclobber"); if (flags & EAF_NOESCAPE) fprintf (out, " noescape"); + if (flags & EAF_NODIRECTESCAPE) + fprintf (out, " nodirectescape"); if (flags & EAF_UNUSED) fprintf (out, " unused"); if (newline) @@ -1303,7 +1305,7 @@ memory_access_to (tree op, tree ssa_name) static int deref_flags (int flags, bool ignore_stores) { - int ret = 0; + int ret = EAF_NODIRECTESCAPE; if (flags & EAF_UNUSED) ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE; else @@ -1361,7 +1363,8 @@ public: void modref_lattice::init () { - flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED; + flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED + | EAF_NODIRECTESCAPE; open = true; known = false; } @@ -1653,7 +1656,8 @@ analyze_ssa_name_flags (tree name, vec &lattice, int depth, { int call_flags = gimple_call_arg_flags (call, i); if (ignore_stores) - call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE; + call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE + | EAF_NODIRECTESCAPE; if (!record_ipa) lattice[index].merge (call_flags); @@ -1829,7 +1833,7 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto, /* For pure functions we have implicit NOCLOBBER and NOESCAPE. */ if (ecf_flags & ECF_PURE) - flags &= ~(EAF_NOCLOBBER | EAF_NOESCAPE); + flags &= ~(EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE); if (flags) { @@ -3102,7 +3106,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) if (!ee->direct) flags = deref_flags (flags, ignore_stores); else if (ignore_stores) - flags |= EAF_NOCLOBBER | EAF_NOESCAPE; + flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE; flags |= ee->min_flags; to_info->arg_flags[ee->parm_index] &= flags; if (to_info->arg_flags[ee->parm_index]) @@ -3116,7 +3120,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) if (!ee->direct) flags = deref_flags (flags, ignore_stores); else if (ignore_stores) - flags |= EAF_NOCLOBBER | EAF_NOESCAPE; + flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE; flags |= ee->min_flags; to_info_lto->arg_flags[ee->parm_index] &= flags; if (to_info_lto->arg_flags[ee->parm_index]) @@ -3627,8 +3631,8 @@ modref_merge_call_site_flags (escape_summary *sum, } else if (ignore_stores) { - flags |= EAF_NOESCAPE | EAF_NOCLOBBER; - flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER; + flags |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE; + flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE; } flags |= ee->min_flags; flags_lto |= ee->min_flags; diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 313a6af2253..e457b917b98 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -110,6 +110,10 @@ struct die_struct; /* Nonzero if the argument is not used by the function. */ #define EAF_UNUSED (1 << 3) +/* Nonzero if the argument itself does not escape but memory + referenced by it can escape. */ +#define EAF_NODIRECTESCAPE (1 << 4) + /* Call return flags. */ /* Mask for the argument number that is returned. Lower two bits of the return flags, encodes argument slots zero to three. */ diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index a4832b75436..9f4de96d544 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -3851,6 +3851,23 @@ make_escape_constraint (tree op) make_constraint_to (escaped_id, op); } +/* Make constraint necessary to make all indirect references + from VI escape. */ + +static void +make_indirect_escape_constraint (varinfo_t vi) +{ + struct constraint_expr lhs, rhs; + /* escaped = *(VAR + UNKNOWN); */ + lhs.type = SCALAR; + lhs.var = escaped_id; + lhs.offset = 0; + rhs.type = DEREF; + rhs.var = vi->id; + rhs.offset = UNKNOWN_OFFSET; + process_constraint (new_constraint (lhs, rhs)); +} + /* Add constraints to that the solution of VI is transitively closed. */ static void @@ -4026,7 +4043,7 @@ handle_rhs_call (gcall *stmt, vec *results) set. The argument would still get clobbered through the escape solution. */ if ((flags & EAF_NOCLOBBER) - && (flags & EAF_NOESCAPE)) + && (flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE))) { varinfo_t uses = get_call_use_vi (stmt); varinfo_t tem = new_var_info (NULL_TREE, "callarg", true); @@ -4036,9 +4053,11 @@ handle_rhs_call (gcall *stmt, vec *results) if (!(flags & EAF_DIRECT)) make_transitive_closure_constraints (tem); make_copy_constraint (uses, tem->id); + if (!(flags & (EAF_NOESCAPE | EAF_DIRECT))) + make_indirect_escape_constraint (tem); returns_uses = true; } - else if (flags & EAF_NOESCAPE) + else if (flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE)) { struct constraint_expr lhs, rhs; varinfo_t uses = get_call_use_vi (stmt); @@ -4061,6 +4080,8 @@ handle_rhs_call (gcall *stmt, vec *results) rhs.var = nonlocal_id; rhs.offset = 0; process_constraint (new_constraint (lhs, rhs)); + if (!(flags & (EAF_NOESCAPE | EAF_DIRECT))) + make_indirect_escape_constraint (tem); returns_uses = true; } else -- 2.30.2