aboutsummaryrefslogtreecommitdiff
path: root/gcc/ipa-modref.c
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2021-09-13 10:37:49 -0700
committerIan Lance Taylor <iant@golang.org>2021-09-13 10:37:49 -0700
commite252b51ccde010cbd2a146485d8045103cd99533 (patch)
treee060f101cdc32bf5e520de8e5275db9d4236b74c /gcc/ipa-modref.c
parentf10c7c4596dda99d2ee872c995ae4aeda65adbdf (diff)
parent104c05c5284b7822d770ee51a7d91946c7e56d50 (diff)
downloadgcc-e252b51ccde010cbd2a146485d8045103cd99533.zip
gcc-e252b51ccde010cbd2a146485d8045103cd99533.tar.gz
gcc-e252b51ccde010cbd2a146485d8045103cd99533.tar.bz2
Merge from trunk revision 104c05c5284b7822d770ee51a7d91946c7e56d50.
Diffstat (limited to 'gcc/ipa-modref.c')
-rw-r--r--gcc/ipa-modref.c388
1 files changed, 257 insertions, 131 deletions
diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
index 7aaf53b..6d49cc1 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"
+
namespace {
/* We record fnspec specifiers for call edges since they depends on actual
@@ -135,7 +136,7 @@ struct escape_entry
/* Argument it escapes to. */
unsigned int arg;
/* Minimal flags known about the argument. */
- char min_flags;
+ eaf_flags_t min_flags;
/* Does it escape directly or indirectly? */
bool direct;
};
@@ -155,6 +156,10 @@ dump_eaf_flags (FILE *out, int flags, bool newline = true)
fprintf (out, " nodirectescape");
if (flags & EAF_UNUSED)
fprintf (out, " unused");
+ if (flags & EAF_NOT_RETURNED)
+ fprintf (out, " not_returned");
+ if (flags & EAF_NOREAD)
+ fprintf (out, " noread");
if (newline)
fprintf (out, "\n");
}
@@ -275,22 +280,46 @@ modref_summary::~modref_summary ()
ggc_delete (stores);
}
+/* All flags that are implied by the ECF_CONST functions. */
+const int implicit_const_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
+ | EAF_NODIRECTESCAPE | EAF_NOREAD;
+/* All flags that are implied by the ECF_PURE function. */
+const int implicit_pure_eaf_flags = EAF_NOCLOBBER | EAF_NOESCAPE
+ | EAF_NODIRECTESCAPE;
+/* All flags implied when we know we can ignore stores (i.e. when handling
+ call to noreturn). */
+const int ignore_stores_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
+ | EAF_NODIRECTESCAPE;
+
+/* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
+ useful to track. If returns_void is true moreover clear
+ EAF_NOT_RETURNED. */
+static int
+remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
+{
+ if (ecf_flags & ECF_NOVOPS)
+ return 0;
+ if (ecf_flags & ECF_CONST)
+ eaf_flags &= ~implicit_const_eaf_flags;
+ else if (ecf_flags & ECF_PURE)
+ eaf_flags &= ~implicit_pure_eaf_flags;
+ else if ((ecf_flags & ECF_NORETURN) || returns_void)
+ eaf_flags &= ~EAF_NOT_RETURNED;
+ /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
+ in tree-ssa-alias.c). Give up earlier. */
+ if ((eaf_flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
+ return 0;
+ return eaf_flags;
+}
+
/* Return true if FLAGS holds some useful information. */
static bool
-eaf_flags_useful_p (vec <unsigned char> &flags, int ecf_flags)
+eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags)
{
for (unsigned i = 0; i < flags.length (); i++)
- if (ecf_flags & ECF_PURE)
- {
- if (flags[i] & (EAF_UNUSED | EAF_DIRECT))
- return true;
- }
- else
- {
- if (flags[i])
- return true;
- }
+ if (remove_useless_eaf_flags (flags[i], ecf_flags, false))
+ return true;
return false;
}
@@ -300,13 +329,15 @@ eaf_flags_useful_p (vec <unsigned char> &flags, int ecf_flags)
bool
modref_summary::useful_p (int ecf_flags, bool check_flags)
{
- if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
+ if (ecf_flags & ECF_NOVOPS)
return false;
if (arg_flags.length () && !check_flags)
return true;
if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
return true;
arg_flags.release ();
+ if (ecf_flags & ECF_CONST)
+ return false;
if (loads && !loads->every_base)
return true;
if (ecf_flags & ECF_PURE)
@@ -325,7 +356,7 @@ struct GTY(()) modref_summary_lto
more verbose and thus more likely to hit the limits. */
modref_records_lto *loads;
modref_records_lto *stores;
- auto_vec<unsigned char> GTY((skip)) arg_flags;
+ auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
bool writes_errno;
modref_summary_lto ();
@@ -356,13 +387,15 @@ modref_summary_lto::~modref_summary_lto ()
bool
modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
{
- if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
+ if (ecf_flags & ECF_NOVOPS)
return false;
if (arg_flags.length () && !check_flags)
return true;
if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
return true;
arg_flags.release ();
+ if (ecf_flags & ECF_CONST)
+ return false;
if (loads && !loads->every_base)
return true;
if (ecf_flags & ECF_PURE)
@@ -393,6 +426,8 @@ dump_access (modref_access_node *a, FILE *out)
print_dec ((poly_int64_pod)a->size, out, SIGNED);
fprintf (out, " max_size:");
print_dec ((poly_int64_pod)a->max_size, out, SIGNED);
+ if (a->adjustments)
+ fprintf (out, " adjusted %i times", a->adjustments);
}
fprintf (out, "\n");
}
@@ -623,7 +658,7 @@ get_access (ao_ref *ref)
base = ao_ref_base (ref);
modref_access_node a = {ref->offset, ref->size, ref->max_size,
- 0, -1, false};
+ 0, -1, false, 0};
if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
{
tree memref = base;
@@ -675,7 +710,7 @@ record_access (modref_records *tt, ao_ref *ref)
fprintf (dump_file, " - Recording base_set=%i ref_set=%i parm=%i\n",
base_set, ref_set, a.parm_index);
}
- tt->insert (base_set, ref_set, a);
+ tt->insert (base_set, ref_set, a, false);
}
/* IPA version of record_access_tree. */
@@ -741,7 +776,7 @@ record_access_lto (modref_records_lto *tt, ao_ref *ref)
a.parm_index);
}
- tt->insert (base_type, ref_type, a);
+ tt->insert (base_type, ref_type, a, false);
}
/* Returns true if and only if we should store the access to EXPR.
@@ -825,12 +860,15 @@ parm_map_for_arg (gimple *stmt, int i)
/* Merge side effects of call STMT to function with CALLEE_SUMMARY
int CUR_SUMMARY. Return true if something changed.
- If IGNORE_STORES is true, do not merge stores. */
+ If IGNORE_STORES is true, do not merge stores.
+ If RECORD_ADJUSTMENTS is true cap number of adjustments to
+ a given access to make dataflow finite. */
bool
merge_call_side_effects (modref_summary *cur_summary,
gimple *stmt, modref_summary *callee_summary,
- bool ignore_stores, cgraph_node *callee_node)
+ bool ignore_stores, cgraph_node *callee_node,
+ bool record_adjustments)
{
auto_vec <modref_parm_map, 32> parm_map;
bool changed = false;
@@ -869,11 +907,13 @@ merge_call_side_effects (modref_summary *cur_summary,
fprintf (dump_file, "\n");
/* Merge with callee's summary. */
- changed |= cur_summary->loads->merge (callee_summary->loads, &parm_map);
+ changed |= cur_summary->loads->merge (callee_summary->loads, &parm_map,
+ record_adjustments);
if (!ignore_stores)
{
changed |= cur_summary->stores->merge (callee_summary->stores,
- &parm_map);
+ &parm_map,
+ record_adjustments);
if (!cur_summary->writes_errno
&& callee_summary->writes_errno)
{
@@ -908,7 +948,7 @@ get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
}
modref_access_node a = {0, -1, -1,
map.parm_offset, map.parm_index,
- map.parm_offset_known};
+ map.parm_offset_known, 0};
poly_int64 size_hwi;
if (size
&& poly_int_tree_p (size, &size_hwi)
@@ -1011,12 +1051,14 @@ process_fnspec (modref_summary *cur_summary,
cur_summary->loads->insert (0, 0,
get_access_for_fnspec (call,
fnspec, i,
- map));
+ map),
+ false);
if (cur_summary_lto)
cur_summary_lto->loads->insert (0, 0,
get_access_for_fnspec (call,
fnspec, i,
- map));
+ map),
+ false);
}
}
if (ignore_stores)
@@ -1044,12 +1086,14 @@ process_fnspec (modref_summary *cur_summary,
cur_summary->stores->insert (0, 0,
get_access_for_fnspec (call,
fnspec, i,
- map));
+ map),
+ false);
if (cur_summary_lto)
cur_summary_lto->stores->insert (0, 0,
get_access_for_fnspec (call,
fnspec, i,
- map));
+ map),
+ false);
}
if (fnspec.errno_maybe_written_p () && flag_errno_math)
{
@@ -1135,7 +1179,7 @@ analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto,
}
merge_call_side_effects (cur_summary, stmt, callee_summary, ignore_stores,
- callee_node);
+ callee_node, false);
return true;
}
@@ -1308,14 +1352,34 @@ static int
deref_flags (int flags, bool ignore_stores)
{
int ret = EAF_NODIRECTESCAPE;
+ /* If argument is unused just account for
+ the read involved in dereference. */
if (flags & EAF_UNUSED)
- ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE;
+ ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOT_RETURNED;
else
{
if ((flags & EAF_NOCLOBBER) || ignore_stores)
ret |= EAF_NOCLOBBER;
if ((flags & EAF_NOESCAPE) || ignore_stores)
ret |= EAF_NOESCAPE;
+ /* If the value dereferenced is not used for another load or store
+ we can still consider ARG as used only directly.
+
+ Consider
+
+ int
+ test (int *a)
+ {
+ return *a!=0;
+ }
+
+ */
+ if ((flags & (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT))
+ == (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT)
+ && ((flags & EAF_NOCLOBBER) || ignore_stores))
+ ret |= EAF_DIRECT;
+ if (flags & EAF_NOT_RETURNED)
+ ret |= EAF_NOT_RETURNED;
}
return ret;
}
@@ -1332,7 +1396,7 @@ struct escape_point
int arg;
/* Flags already known about the argument (this can save us from recording
esape points if local analysis did good job already). */
- char min_flags;
+ eaf_flags_t min_flags;
/* Does value escape directly or indiretly? */
bool direct;
};
@@ -1341,7 +1405,7 @@ class modref_lattice
{
public:
/* EAF flags of the SSA name. */
- int flags;
+ eaf_flags_t flags;
/* DFS bookkkeeping: we don't do real dataflow yet. */
bool known;
bool open;
@@ -1365,8 +1429,12 @@ public:
void
modref_lattice::init ()
{
- flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED
- | EAF_NODIRECTESCAPE;
+ /* All flags we track. */
+ int f = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED
+ | EAF_NODIRECTESCAPE | EAF_NOT_RETURNED | EAF_NOREAD;
+ flags = f;
+ /* Check that eaf_flags_t is wide enough to hold all flags. */
+ gcc_checking_assert (f == flags);
open = true;
known = false;
}
@@ -1392,7 +1460,7 @@ modref_lattice::dump (FILE *out, int indent) const
fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
escape_points[i].arg,
escape_points[i].direct ? "direct" : "indirect");
- dump_eaf_flags (out, flags, false);
+ dump_eaf_flags (out, escape_points[i].min_flags, false);
fprintf (out, " in call ");
print_gimple_stmt (out, escape_points[i].call, 0);
}
@@ -1410,8 +1478,8 @@ modref_lattice::add_escape_point (gcall *call, int arg, int min_flags,
unsigned int i;
/* If we already determined flags to be bad enough,
- * we do not need to record. */
- if ((flags & min_flags) == flags)
+ we do not need to record. */
+ if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
return false;
FOR_EACH_VEC_ELT (escape_points, i, ep)
@@ -1441,13 +1509,18 @@ modref_lattice::merge (int f)
{
if (f & EAF_UNUSED)
return false;
+ /* Noescape implies that value also does not escape directly.
+ Fnspec machinery does set both so compensate for this. */
+ if (f & EAF_NOESCAPE)
+ f |= EAF_NODIRECTESCAPE;
if ((flags & f) != flags)
{
flags &= f;
- /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
- in tree-ssa-alias.c). Give up earlier. */
- if ((flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
- flags = 0;
+ /* Prune obvoiusly useless flags;
+ We do not have ECF_FLAGS handy which is not big problem since
+ we will do final flags cleanup before producing summary.
+ Merging should be fast so it can work well with dataflow. */
+ flags = remove_useless_eaf_flags (flags, 0, false);
if (!flags)
escape_points.release ();
return true;
@@ -1489,10 +1562,18 @@ modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
if (!flags)
return changed;
for (unsigned int i = 0; i < with.escape_points.length (); i++)
- changed |= add_escape_point (with.escape_points[i].call,
- with.escape_points[i].arg,
- with.escape_points[i].min_flags,
- false);
+ {
+ int min_flags = with.escape_points[i].min_flags;
+
+ if (with.escape_points[i].direct)
+ min_flags = deref_flags (min_flags, ignore_stores);
+ else if (ignore_stores)
+ min_flags |= ignore_stores_eaf_flags;
+ changed |= add_escape_point (with.escape_points[i].call,
+ with.escape_points[i].arg,
+ min_flags,
+ false);
+ }
return changed;
}
@@ -1501,7 +1582,7 @@ modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
bool
modref_lattice::merge_direct_load ()
{
- return merge (~EAF_UNUSED);
+ return merge (~(EAF_UNUSED | EAF_NOREAD));
}
/* Merge in flags for direct store. */
@@ -1539,15 +1620,18 @@ merge_call_lhs_flags (gcall *call, int arg, int index, bool deref,
&& (flags & ERF_RETURN_ARG_MASK) != arg)
return;
+ if (gimple_call_arg_flags (call, arg) & (EAF_NOT_RETURNED | EAF_UNUSED))
+ return;
+
/* If return value is SSA name determine its flags. */
if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
{
tree lhs = gimple_call_lhs (call);
analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
if (deref)
- lattice[index].merge (lattice[SSA_NAME_VERSION (lhs)]);
- else
lattice[index].merge_deref (lattice[SSA_NAME_VERSION (lhs)], false);
+ else
+ lattice[index].merge (lattice[SSA_NAME_VERSION (lhs)]);
}
/* In the case of memory store we can do nothing. */
else
@@ -1607,33 +1691,37 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
fprintf (dump_file, "%*s Analyzing stmt: ", depth * 4, "");
print_gimple_stmt (dump_file, use_stmt, 0);
}
+ /* If we see a direct non-debug use, clear unused bit.
+ All dereferneces should be accounted below using deref_flags. */
+ lattice[index].merge (~EAF_UNUSED);
/* Gimple return may load the return value.
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)
- lattice[index].merge (~EAF_UNUSED);
+ lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED));
else if (memory_access_to (gimple_return_retval (ret), name))
- lattice[index].merge_direct_load ();
+ {
+ lattice[index].merge_direct_load ();
+ lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED));
+ }
}
/* Account for LHS store, arg loads and flags from callee function. */
else if (gcall *call = dyn_cast <gcall *> (use_stmt))
{
tree callee = gimple_call_fndecl (call);
- /* Return slot optiomization would require bit of propagation;
- give up for now. */
- if (gimple_call_return_slot_opt_p (call)
- && gimple_call_lhs (call) != NULL_TREE
- && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
- {
- if (dump_file)
- fprintf (dump_file, "%*s Unhandled return slot opt\n",
- depth * 4, "");
- lattice[index].merge (0);
- }
+
+ /* IPA PTA internally it treats calling a function as "writing" to
+ the argument space of all functions the function pointer points to
+ (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
+ is on since that would allow propagation of this from -fno-ipa-pta
+ to -fipa-pta functions. */
+ if (gimple_call_fn (use_stmt) == name)
+ lattice[index].merge (~(EAF_NOCLOBBER | EAF_UNUSED));
+
/* Recursion would require bit of propagation; give up for now. */
- else if (callee && !ipa && recursive_call_p (current_function_decl,
+ if (callee && !ipa && recursive_call_p (current_function_decl,
callee))
lattice[index].merge (0);
else
@@ -1647,7 +1735,15 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
/* Handle *name = func (...). */
if (gimple_call_lhs (call)
&& memory_access_to (gimple_call_lhs (call), name))
- lattice[index].merge_direct_store ();
+ {
+ lattice[index].merge_direct_store ();
+ /* Return slot optimization passes address of
+ LHS to callee via hidden parameter and this
+ 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);
+ }
/* We do not track accesses to the static chain (we could)
so give up. */
@@ -1666,14 +1762,14 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
{
if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
{
- int call_flags = gimple_call_arg_flags (call, i);
+ int call_flags = gimple_call_arg_flags (call, i)
+ | EAF_NOT_RETURNED;
if (ignore_stores)
- call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE
- | EAF_NODIRECTESCAPE;
+ call_flags |= ignore_stores_eaf_flags;
if (!record_ipa)
lattice[index].merge (call_flags);
- if (record_ipa)
+ else
lattice[index].add_escape_point (call, i,
call_flags, true);
}
@@ -1689,10 +1785,11 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
else
{
int call_flags = deref_flags
- (gimple_call_arg_flags (call, i), ignore_stores);
+ (gimple_call_arg_flags (call, i)
+ | EAF_NOT_RETURNED, ignore_stores);
if (!record_ipa)
- lattice[index].merge (call_flags);
- if (record_ipa)
+ lattice[index].merge (call_flags);
+ else
lattice[index].add_escape_point (call, i,
call_flags, false);
}
@@ -1819,8 +1916,8 @@ 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);
- /* For const functions we have nothing to gain by EAF flags. */
- if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
+ /* For novops functions we have nothing to gain by EAF flags. */
+ if (ecf_flags & ECF_NOVOPS)
return;
for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
@@ -1860,10 +1957,12 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
analyze_ssa_name_flags (name, lattice, 0, ipa);
int flags = lattice[SSA_NAME_VERSION (name)].flags;
- /* For pure functions we have implicit NOCLOBBER
- and NOESCAPE. */
- if (ecf_flags & ECF_PURE)
- flags &= ~(EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE);
+ /* Eliminate useless flags so we do not end up storing unnecessary
+ summaries. */
+
+ flags = remove_useless_eaf_flags
+ (flags, ecf_flags,
+ VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
if (flags)
{
@@ -2026,7 +2125,8 @@ analyze_function (function *f, bool ipa)
FOR_EACH_BB_FN (bb, f)
{
gimple_stmt_iterator si;
- for (si = gsi_after_labels (bb); !gsi_end_p (si); gsi_next (&si))
+ for (si = gsi_start_nondebug_after_labels_bb (bb);
+ !gsi_end_p (si); gsi_next_nondebug (&si))
{
if (!analyze_stmt (summary, summary_lto,
gsi_stmt (si), ipa, &recursive_calls)
@@ -2046,6 +2146,7 @@ analyze_function (function *f, bool ipa)
if (!ipa)
{
bool changed = true;
+ bool first = true;
while (changed)
{
changed = false;
@@ -2056,13 +2157,14 @@ analyze_function (function *f, bool ipa)
ignore_stores_p (current_function_decl,
gimple_call_flags
(recursive_calls[i])),
- fnode);
+ fnode, !first);
if (!summary->useful_p (ecf_flags, false))
{
remove_summary (lto, nolto, ipa);
return;
}
}
+ first = false;
}
}
if (summary && !summary->useful_p (ecf_flags))
@@ -2344,9 +2446,9 @@ read_modref_records (lto_input_block *ib, struct data_in *data_in,
if (nolto_ret)
nolto_base_node = (*nolto_ret)->insert_base (base_tree
? get_alias_set (base_tree)
- : 0);
+ : 0, 0);
if (lto_ret)
- lto_base_node = (*lto_ret)->insert_base (base_tree);
+ lto_base_node = (*lto_ret)->insert_base (base_tree, 0);
size_t every_ref = streamer_read_uhwi (ib);
size_t nref = streamer_read_uhwi (ib);
@@ -2413,11 +2515,11 @@ read_modref_records (lto_input_block *ib, struct data_in *data_in,
}
}
modref_access_node a = {offset, size, max_size, parm_offset,
- parm_index, parm_offset_known};
+ parm_index, parm_offset_known, false};
if (nolto_ref_node)
- nolto_ref_node->insert_access (a, max_accesses);
+ nolto_ref_node->insert_access (a, max_accesses, false);
if (lto_ref_node)
- lto_ref_node->insert_access (a, max_accesses);
+ lto_ref_node->insert_access (a, max_accesses, false);
}
}
}
@@ -2518,7 +2620,7 @@ modref_write ()
streamer_write_uhwi (ob, r->arg_flags.length ());
for (unsigned int i = 0; i < r->arg_flags.length (); i++)
- streamer_write_char_stream (ob->main_stream, r->arg_flags[i]);
+ streamer_write_uhwi (ob, r->arg_flags[i]);
write_modref_records (r->loads, ob);
write_modref_records (r->stores, ob);
@@ -2609,7 +2711,7 @@ read_section (struct lto_file_decl_data *file_data, const char *data,
modref_sum_lto->arg_flags.reserve_exact (args);
for (unsigned int i = 0; i < args; i++)
{
- unsigned char flags = streamer_read_uchar (&ib);
+ eaf_flags_t flags = streamer_read_uhwi (&ib);
if (modref_sum)
modref_sum->arg_flags.quick_push (flags);
if (modref_sum_lto)
@@ -2713,9 +2815,9 @@ modref_read (void)
/* Recompute arg_flags for param adjustments in INFO. */
static void
-remap_arg_flags (auto_vec <unsigned char> &arg_flags, clone_info *info)
+remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
{
- auto_vec<unsigned char> old = arg_flags.copy ();
+ auto_vec<eaf_flags_t> old = arg_flags.copy ();
int max = -1;
size_t i;
ipa_adjusted_param *p;
@@ -2899,7 +3001,7 @@ compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
class ipa_edge_args *args;
if (ipa_node_params_sum
&& !callee_edge->call_stmt_cannot_inline_p
- && (args = IPA_EDGE_REF (callee_edge)) != NULL)
+ && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
{
int i, count = ipa_get_cs_argument_count (args);
class ipa_node_params *caller_parms_info, *callee_pi;
@@ -2909,10 +3011,11 @@ compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
= callee_edge->callee->function_or_virtual_thunk_symbol
(NULL, callee_edge->caller);
- caller_parms_info = IPA_NODE_REF (callee_edge->caller->inlined_to
- ? callee_edge->caller->inlined_to
- : callee_edge->caller);
- callee_pi = IPA_NODE_REF (callee);
+ caller_parms_info
+ = ipa_node_params_sum->get (callee_edge->caller->inlined_to
+ ? callee_edge->caller->inlined_to
+ : callee_edge->caller);
+ callee_pi = ipa_node_params_sum->get (callee);
(*parm_map).safe_grow_cleared (count, true);
@@ -2992,7 +3095,8 @@ struct escape_map
static void
update_escape_summary_1 (cgraph_edge *e,
- vec <vec <escape_map>> &map)
+ vec <vec <escape_map>> &map,
+ bool ignore_stores)
{
escape_summary *sum = escape_summaries->get (e);
if (!sum)
@@ -3010,6 +3114,9 @@ update_escape_summary_1 (cgraph_edge *e,
continue;
FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
{
+ int min_flags = ee->min_flags;
+ 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->direct & em->direct};
@@ -3024,18 +3131,19 @@ update_escape_summary_1 (cgraph_edge *e,
static void
update_escape_summary (cgraph_node *node,
- vec <vec <escape_map>> &map)
+ vec <vec <escape_map>> &map,
+ bool ignore_stores)
{
if (!escape_summaries)
return;
for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
- update_escape_summary_1 (e, map);
+ update_escape_summary_1 (e, map, ignore_stores);
for (cgraph_edge *e = node->callees; e; e = e->next_callee)
{
if (!e->inline_failed)
- update_escape_summary (e->callee, map);
+ update_escape_summary (e->callee, map, ignore_stores);
else
- update_escape_summary_1 (e, map);
+ update_escape_summary_1 (e, map, ignore_stores);
}
}
@@ -3093,16 +3201,18 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
if (!ignore_stores)
{
if (to_info && callee_info)
- to_info->stores->merge (callee_info->stores, &parm_map);
+ to_info->stores->merge (callee_info->stores, &parm_map, false);
if (to_info_lto && callee_info_lto)
- to_info_lto->stores->merge (callee_info_lto->stores, &parm_map);
+ to_info_lto->stores->merge (callee_info_lto->stores, &parm_map,
+ false);
}
if (!(flags & (ECF_CONST | ECF_NOVOPS)))
{
if (to_info && callee_info)
- to_info->loads->merge (callee_info->loads, &parm_map);
+ to_info->loads->merge (callee_info->loads, &parm_map, false);
if (to_info_lto && callee_info_lto)
- to_info_lto->loads->merge (callee_info_lto->loads, &parm_map);
+ to_info_lto->loads->merge (callee_info_lto->loads, &parm_map,
+ false);
}
}
@@ -3136,7 +3246,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 | EAF_NODIRECTESCAPE;
+ flags |= ignore_stores_eaf_flags;
flags |= ee->min_flags;
to_info->arg_flags[ee->parm_index] &= flags;
if (to_info->arg_flags[ee->parm_index])
@@ -3150,7 +3260,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 | EAF_NODIRECTESCAPE;
+ flags |= ignore_stores_eaf_flags;
flags |= ee->min_flags;
to_info_lto->arg_flags[ee->parm_index] &= flags;
if (to_info_lto->arg_flags[ee->parm_index])
@@ -3160,7 +3270,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
if (needed)
emap[ee->arg].safe_push (entry);
}
- update_escape_summary (edge->callee, emap);
+ update_escape_summary (edge->callee, emap, ignore_stores);
for (i = 0; (int)i < max_escape + 1; i++)
emap[i].release ();
if (sum)
@@ -3240,8 +3350,8 @@ get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
{
cgraph_node *node = e->caller->inlined_to
? e->caller->inlined_to : e->caller;
- class ipa_node_params *caller_parms_info = IPA_NODE_REF (node);
- class ipa_edge_args *args = IPA_EDGE_REF (e);
+ ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
+ ipa_edge_args *args = ipa_edge_args_sum->get (e);
struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
if (jf)
@@ -3252,7 +3362,7 @@ get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
modref_access_node a = {0, -1, -1,
map.parm_offset, map.parm_index,
- map.parm_offset_known};
+ map.parm_offset_known, 0};
poly_int64 size_hwi;
if (size
&& poly_int_tree_p (size, &size_hwi)
@@ -3305,10 +3415,10 @@ propagate_unknown_call (cgraph_node *node,
}
if (cur_summary)
changed |= cur_summary->loads->insert
- (0, 0, get_access_for_fnspec (e, fnspec, i, map));
+ (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
if (cur_summary_lto)
changed |= cur_summary_lto->loads->insert
- (0, 0, get_access_for_fnspec (e, fnspec, i, map));
+ (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
}
}
if (ignore_stores_p (node->decl, ecf_flags))
@@ -3335,10 +3445,10 @@ propagate_unknown_call (cgraph_node *node,
}
if (cur_summary)
changed |= cur_summary->stores->insert
- (0, 0, get_access_for_fnspec (e, fnspec, i, map));
+ (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
if (cur_summary_lto)
changed |= cur_summary_lto->stores->insert
- (0, 0, get_access_for_fnspec (e, fnspec, i, map));
+ (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
}
}
if (fnspec.errno_maybe_written_p () && flag_errno_math)
@@ -3397,6 +3507,7 @@ static void
modref_propagate_in_scc (cgraph_node *component_node)
{
bool changed = true;
+ bool first = true;
int iteration = 0;
while (changed)
@@ -3534,11 +3645,12 @@ modref_propagate_in_scc (cgraph_node *component_node)
if (callee_summary)
{
changed |= cur_summary->loads->merge
- (callee_summary->loads, &parm_map);
+ (callee_summary->loads, &parm_map, !first);
if (!ignore_stores)
{
changed |= cur_summary->stores->merge
- (callee_summary->stores, &parm_map);
+ (callee_summary->stores, &parm_map,
+ !first);
if (!cur_summary->writes_errno
&& callee_summary->writes_errno)
{
@@ -3550,11 +3662,13 @@ modref_propagate_in_scc (cgraph_node *component_node)
if (callee_summary_lto)
{
changed |= cur_summary_lto->loads->merge
- (callee_summary_lto->loads, &parm_map);
+ (callee_summary_lto->loads, &parm_map,
+ !first);
if (!ignore_stores)
{
changed |= cur_summary_lto->stores->merge
- (callee_summary_lto->stores, &parm_map);
+ (callee_summary_lto->stores, &parm_map,
+ !first);
if (!cur_summary_lto->writes_errno
&& callee_summary_lto->writes_errno)
{
@@ -3580,6 +3694,7 @@ modref_propagate_in_scc (cgraph_node *component_node)
}
}
iteration++;
+ first = false;
}
if (dump_file)
fprintf (dump_file,
@@ -3633,11 +3748,13 @@ modref_merge_call_site_flags (escape_summary *sum,
modref_summary_lto *cur_summary_lto,
modref_summary *summary,
modref_summary_lto *summary_lto,
- bool ignore_stores)
+ tree caller,
+ int ecf_flags)
{
escape_entry *ee;
unsigned int i;
bool changed = false;
+ bool ignore_stores = ignore_stores_p (caller, ecf_flags);
/* If we have no useful info to propagate. */
if ((!cur_summary || !cur_summary->arg_flags.length ())
@@ -3661,20 +3778,27 @@ modref_merge_call_site_flags (escape_summary *sum,
}
else if (ignore_stores)
{
- flags |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE;
- flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE;
+ flags |= ignore_stores_eaf_flags;
+ flags_lto |= ignore_stores_eaf_flags;
}
- flags |= ee->min_flags;
- flags_lto |= ee->min_flags;
+ /* Returning the value is already accounted to at local propagation. */
+ flags |= ee->min_flags | EAF_NOT_RETURNED;
+ flags_lto |= ee->min_flags | EAF_NOT_RETURNED;
+ /* Noescape implies that value also does not escape directly.
+ Fnspec machinery does set both so compensate for this. */
+ if (flags & EAF_NOESCAPE)
+ flags |= EAF_NODIRECTESCAPE;
+ if (flags_lto & EAF_NOESCAPE)
+ flags_lto |= EAF_NODIRECTESCAPE;
if (!(flags & EAF_UNUSED)
&& cur_summary && ee->parm_index < cur_summary->arg_flags.length ())
{
int f = cur_summary->arg_flags[ee->parm_index];
if ((f & flags) != f)
{
- f = f & flags;
- if ((f & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
- f = 0;
+ 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;
}
@@ -3686,9 +3810,9 @@ modref_merge_call_site_flags (escape_summary *sum,
int f = cur_summary_lto->arg_flags[ee->parm_index];
if ((f & flags_lto) != f)
{
- f = f & flags;
- if ((f & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
- f = 0;
+ 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;
}
@@ -3739,8 +3863,8 @@ modref_propagate_flags_in_scc (cgraph_node *component_node)
changed |= modref_merge_call_site_flags
(sum, cur_summary, cur_summary_lto,
- NULL, NULL, ignore_stores_p (node->decl,
- e->indirect_info->ecf_flags));
+ NULL, NULL,
+ node->decl, e->indirect_info->ecf_flags);
}
if (!cur_summary && !cur_summary_lto)
@@ -3749,12 +3873,13 @@ modref_propagate_flags_in_scc (cgraph_node *component_node)
for (cgraph_edge *callee_edge = cur->callees; callee_edge;
callee_edge = callee_edge->next_callee)
{
- int flags = flags_from_decl_or_type (callee_edge->callee->decl);
+ int ecf_flags = flags_from_decl_or_type
+ (callee_edge->callee->decl);
modref_summary *callee_summary = NULL;
modref_summary_lto *callee_summary_lto = NULL;
struct cgraph_node *callee;
- if (flags & (ECF_CONST | ECF_NOVOPS)
+ if (ecf_flags & (ECF_CONST | ECF_NOVOPS)
|| !callee_edge->inline_failed)
continue;
/* Get the callee and its summary. */
@@ -3791,7 +3916,7 @@ modref_propagate_flags_in_scc (cgraph_node *component_node)
changed |= modref_merge_call_site_flags
(sum, cur_summary, cur_summary_lto,
callee_summary, callee_summary_lto,
- ignore_stores_p (node->decl, flags));
+ node->decl, ecf_flags);
if (dump_file && changed)
{
if (cur_summary)
@@ -3867,7 +3992,8 @@ ipa_modref_c_finalize ()
if (optimization_summaries)
ggc_delete (optimization_summaries);
optimization_summaries = NULL;
- gcc_checking_assert (!summaries);
+ gcc_checking_assert (!summaries
+ || flag_incremental_link == INCREMENTAL_LINK_LTO);
if (summaries_lto)
ggc_delete (summaries_lto);
summaries_lto = NULL;