aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/gimple.c9
-rw-r--r--gcc/ipa-modref.c204
-rw-r--r--gcc/ipa-modref.h42
-rw-r--r--gcc/testsuite/g++.dg/ipa/modref-1.C2
-rw-r--r--gcc/testsuite/gcc.dg/ipa/modref-3.c2
-rw-r--r--gcc/testsuite/gcc.dg/lto/modref-3_0.c2
-rw-r--r--gcc/testsuite/gcc.dg/lto/modref-4_0.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/modref-10.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/modref-11.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/modref-13.c21
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/modref-5.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/modref-6.c6
-rw-r--r--gcc/tree-core.h31
-rw-r--r--gcc/tree-ssa-alias.c2
-rw-r--r--gcc/tree-ssa-structalias.c142
-rw-r--r--gcc/tree-ssa-uninit.c3
16 files changed, 302 insertions, 172 deletions
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 9e65fa6..1e0fad9 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -1575,11 +1575,12 @@ gimple_call_arg_flags (const gcall *stmt, unsigned arg)
else
{
if (fnspec.arg_direct_p (arg))
- flags |= EAF_DIRECT;
+ flags |= EAF_NO_INDIRECT_READ | EAF_NO_INDIRECT_ESCAPE
+ | EAF_NOT_RETURNED_INDIRECTLY | EAF_NO_INDIRECT_CLOBBER;
if (fnspec.arg_noescape_p (arg))
- flags |= EAF_NOESCAPE | EAF_NODIRECTESCAPE;
+ flags |= EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE;
if (fnspec.arg_readonly_p (arg))
- flags |= EAF_NOCLOBBER;
+ flags |= EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER;
}
}
tree callee = gimple_call_fndecl (stmt);
@@ -1608,7 +1609,7 @@ gimple_call_arg_flags (const gcall *stmt, unsigned arg)
int
gimple_call_retslot_flags (const gcall *stmt)
{
- int flags = EAF_DIRECT | EAF_NOREAD;
+ int flags = implicit_retslot_eaf_flags;
tree callee = gimple_call_fndecl (stmt);
if (callee)
diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
index e3cad3e..14c3894 100644
--- a/gcc/ipa-modref.c
+++ b/gcc/ipa-modref.c
@@ -148,22 +148,24 @@ struct escape_entry
static void
dump_eaf_flags (FILE *out, int flags, bool newline = true)
{
- if (flags & EAF_DIRECT)
- fprintf (out, " direct");
- if (flags & EAF_NOCLOBBER)
- 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 (flags & EAF_NOT_RETURNED)
- fprintf (out, " not_returned");
+ if (flags & EAF_NO_DIRECT_CLOBBER)
+ fprintf (out, " no_direct_clobber");
+ if (flags & EAF_NO_INDIRECT_CLOBBER)
+ fprintf (out, " no_indirect_clobber");
+ if (flags & EAF_NO_DIRECT_ESCAPE)
+ fprintf (out, " no_direct_escape");
+ if (flags & EAF_NO_INDIRECT_ESCAPE)
+ fprintf (out, " no_indirect_escape");
if (flags & EAF_NOT_RETURNED_DIRECTLY)
fprintf (out, " not_returned_directly");
- if (flags & EAF_NOREAD)
- fprintf (out, " noread");
+ if (flags & EAF_NOT_RETURNED_INDIRECTLY)
+ fprintf (out, " not_returned_indirectly");
+ if (flags & EAF_NO_DIRECT_READ)
+ fprintf (out, " no_direct_read");
+ if (flags & EAF_NO_INDIRECT_READ)
+ fprintf (out, " no_indirect_read");
if (newline)
fprintf (out, "\n");
}
@@ -296,7 +298,7 @@ remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
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 | EAF_NOT_RETURNED_DIRECTLY);
+ eaf_flags &= ~(EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY);
return eaf_flags;
}
@@ -1412,35 +1414,32 @@ memory_access_to (tree op, tree ssa_name)
static int
deref_flags (int flags, bool ignore_stores)
{
- int ret = EAF_NODIRECTESCAPE | EAF_NOT_RETURNED_DIRECTLY;
+ /* Dereference is also a direct read but dereferenced value does not
+ yield any other direct use. */
+ int ret = EAF_NO_DIRECT_CLOBBER | EAF_NO_DIRECT_ESCAPE
+ | EAF_NOT_RETURNED_DIRECTLY;
/* If argument is unused just account for
the read involved in dereference. */
if (flags & EAF_UNUSED)
- ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOT_RETURNED;
+ ret |= EAF_NO_INDIRECT_READ | EAF_NO_INDIRECT_CLOBBER
+ | EAF_NO_INDIRECT_ESCAPE;
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;
+ /* Direct or indirect accesses leads to indirect accesses. */
+ if (((flags & EAF_NO_DIRECT_CLOBBER)
+ && (flags & EAF_NO_INDIRECT_CLOBBER))
+ || ignore_stores)
+ ret |= EAF_NO_INDIRECT_CLOBBER;
+ if (((flags & EAF_NO_DIRECT_ESCAPE)
+ && (flags & EAF_NO_INDIRECT_ESCAPE))
+ || ignore_stores)
+ ret |= EAF_NO_INDIRECT_ESCAPE;
+ if ((flags & EAF_NO_DIRECT_READ)
+ && (flags & EAF_NO_INDIRECT_READ))
+ ret |= EAF_NO_INDIRECT_READ;
+ if ((flags & EAF_NOT_RETURNED_DIRECTLY)
+ && (flags & EAF_NOT_RETURNED_INDIRECTLY))
+ ret |= EAF_NOT_RETURNED_INDIRECTLY;
}
return ret;
}
@@ -1508,9 +1507,11 @@ void
modref_lattice::init ()
{
/* All flags we track. */
- int f = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED
- | EAF_NODIRECTESCAPE | EAF_NOT_RETURNED |
- EAF_NOT_RETURNED_DIRECTLY | EAF_NOREAD;
+ int f = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
+ | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE
+ | EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ
+ | EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY
+ | EAF_UNUSED;
flags = f;
/* Check that eaf_flags_t is wide enough to hold all flags. */
gcc_checking_assert (f == flags);
@@ -1589,12 +1590,6 @@ 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 (f & EAF_NOT_RETURNED)
- f |= EAF_NOT_RETURNED_DIRECTLY;
if ((flags & f) != flags)
{
flags &= f;
@@ -1664,7 +1659,7 @@ modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
bool
modref_lattice::merge_direct_load ()
{
- return merge (~(EAF_UNUSED | EAF_NOREAD));
+ return merge (~(EAF_UNUSED | EAF_NO_DIRECT_READ));
}
/* Merge in flags for direct store. */
@@ -1672,7 +1667,7 @@ modref_lattice::merge_direct_load ()
bool
modref_lattice::merge_direct_store ()
{
- return merge (~(EAF_UNUSED | EAF_NOCLOBBER));
+ return merge (~(EAF_UNUSED | EAF_NO_DIRECT_CLOBBER));
}
/* Analyzer of EAF flags.
@@ -1729,22 +1724,30 @@ private:
auto_vec<int> m_names_to_propagate;
void merge_with_ssa_name (tree dest, tree src, bool deref);
- void merge_call_lhs_flags (gcall *call, int arg, tree name, bool deref);
+ void merge_call_lhs_flags (gcall *call, int arg, tree name, bool direct,
+ bool deref);
};
-/* Call statements may return their parameters. Consider argument number
+/* Call statements may return tgeir parameters. Consider argument number
ARG of USE_STMT and determine flags that can needs to be cleared
in case pointer possibly indirectly references from ARG I is returned.
+ If DIRECT is true consider direct returns and if INDIRECT consider
+ indirect returns.
LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
ARG is set to -1 for static chain. */
void
modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg,
- tree name, bool deref)
+ tree name, bool direct,
+ bool indirect)
{
int index = SSA_NAME_VERSION (name);
+ /* If value is not returned at all, do nothing. */
+ if (!direct && !indirect)
+ return;
+
/* If there is no return value, no flags are affected. */
if (!gimple_call_lhs (call))
return;
@@ -1763,10 +1766,13 @@ modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg,
if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
{
tree lhs = gimple_call_lhs (call);
- merge_with_ssa_name (name, lhs, deref);
+ if (direct)
+ merge_with_ssa_name (name, lhs, false);
+ if (indirect)
+ merge_with_ssa_name (name, lhs, true);
}
/* In the case of memory store we can do nothing. */
- else if (deref)
+ else if (!direct)
m_lattice[index].merge (deref_flags (0, false));
else
m_lattice[index].merge (0);
@@ -1782,18 +1788,19 @@ callee_to_caller_flags (int call_flags, bool ignore_stores,
{
/* call_flags is about callee returning a value
that is not the same as caller returning it. */
- call_flags |= EAF_NOT_RETURNED
- | EAF_NOT_RETURNED_DIRECTLY;
+ call_flags |= EAF_NOT_RETURNED_DIRECTLY
+ | EAF_NOT_RETURNED_INDIRECTLY;
/* TODO: We miss return value propagation.
Be conservative and if value escapes to memory
also mark it as escaping. */
if (!ignore_stores && !(call_flags & EAF_UNUSED))
{
- if (!(call_flags & EAF_NOESCAPE))
- lattice.merge (~(EAF_NOT_RETURNED | EAF_UNUSED));
- if (!(call_flags & (EAF_NODIRECTESCAPE | EAF_NOESCAPE)))
+ if (!(call_flags & EAF_NO_DIRECT_ESCAPE))
lattice.merge (~(EAF_NOT_RETURNED_DIRECTLY
- | EAF_NOT_RETURNED
+ | EAF_NOT_RETURNED_INDIRECTLY
+ | EAF_UNUSED));
+ if (!(call_flags & EAF_NO_INDIRECT_ESCAPE))
+ lattice.merge (~(EAF_NOT_RETURNED_INDIRECTLY
| EAF_UNUSED));
}
else
@@ -1869,13 +1876,13 @@ modref_eaf_analysis::analyze_ssa_name (tree name)
&& DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
;
else if (gimple_return_retval (ret) == name)
- m_lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED
+ m_lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED_DIRECTLY
| EAF_NOT_RETURNED_DIRECTLY));
else if (memory_access_to (gimple_return_retval (ret), name))
{
m_lattice[index].merge_direct_load ();
- m_lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED
- | EAF_NOT_RETURNED_DIRECTLY));
+ m_lattice[index].merge (~(EAF_UNUSED
+ | EAF_NOT_RETURNED_INDIRECTLY));
}
}
/* Account for LHS store, arg loads and flags from callee function. */
@@ -1889,7 +1896,7 @@ modref_eaf_analysis::analyze_ssa_name (tree name)
is on since that would allow propagation of this from -fno-ipa-pta
to -fipa-pta functions. */
if (gimple_call_fn (use_stmt) == name)
- m_lattice[index].merge (~(EAF_NOCLOBBER | EAF_UNUSED));
+ m_lattice[index].merge (~(EAF_NO_DIRECT_CLOBBER | EAF_UNUSED));
/* Recursion would require bit of propagation; give up for now. */
if (callee && !m_ipa && recursive_call_p (current_function_decl,
@@ -1932,14 +1939,14 @@ modref_eaf_analysis::analyze_ssa_name (tree name)
arg is written to itself which is an escape. */
if (!isretslot)
{
- if (!(call_flags & (EAF_NOT_RETURNED | EAF_UNUSED)))
- m_lattice[index].merge (~(EAF_NOESCAPE
- | EAF_UNUSED));
if (!(call_flags & (EAF_NOT_RETURNED_DIRECTLY
- | EAF_UNUSED
- | EAF_NOT_RETURNED)))
- m_lattice[index].merge (~(EAF_NODIRECTESCAPE
- | EAF_NOESCAPE
+ | EAF_UNUSED)))
+ m_lattice[index].merge (~(EAF_NO_DIRECT_ESCAPE
+ | EAF_NO_INDIRECT_ESCAPE
+ | EAF_UNUSED));
+ if (!(call_flags & (EAF_NOT_RETURNED_INDIRECTLY
+ | EAF_UNUSED)))
+ m_lattice[index].merge (~(EAF_NO_INDIRECT_ESCAPE
| EAF_UNUSED));
call_flags = callee_to_caller_flags
(call_flags, false,
@@ -1953,9 +1960,11 @@ modref_eaf_analysis::analyze_ssa_name (tree name)
&& (gimple_call_chain (call) == name))
{
int call_flags = gimple_call_static_chain_flags (call);
- if (!ignore_retval
- && !(call_flags & (EAF_NOT_RETURNED | EAF_UNUSED)))
- merge_call_lhs_flags (call, -1, name, false);
+ if (!ignore_retval && !(call_flags & EAF_UNUSED))
+ merge_call_lhs_flags
+ (call, -1, name,
+ !(call_flags & EAF_NOT_RETURNED_DIRECTLY),
+ !(call_flags & EAF_NOT_RETURNED_INDIRECTLY));
call_flags = callee_to_caller_flags
(call_flags, ignore_stores,
m_lattice[index]);
@@ -1974,11 +1983,11 @@ modref_eaf_analysis::analyze_ssa_name (tree name)
if (gimple_call_arg (call, i) == name)
{
int call_flags = gimple_call_arg_flags (call, i);
- if (!ignore_retval && !(call_flags
- & (EAF_NOT_RETURNED | EAF_UNUSED)))
+ if (!ignore_retval && !(call_flags & EAF_UNUSED))
merge_call_lhs_flags
(call, i, name,
- call_flags & EAF_NOT_RETURNED_DIRECTLY);
+ !(call_flags & EAF_NOT_RETURNED_DIRECTLY),
+ !(call_flags & EAF_NOT_RETURNED_INDIRECTLY));
if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
{
call_flags = callee_to_caller_flags
@@ -1996,9 +2005,10 @@ modref_eaf_analysis::analyze_ssa_name (tree name)
{
int call_flags = deref_flags
(gimple_call_arg_flags (call, i), ignore_stores);
- if (!ignore_retval
- && !(call_flags & (EAF_NOT_RETURNED | EAF_UNUSED)))
- merge_call_lhs_flags (call, i, name, true);
+ if (!ignore_retval && !(call_flags & EAF_UNUSED)
+ && !(call_flags & EAF_NOT_RETURNED_DIRECTLY)
+ && !(call_flags & EAF_NOT_RETURNED_INDIRECTLY))
+ merge_call_lhs_flags (call, i, name, false, true);
if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
m_lattice[index].merge_direct_load ();
else
@@ -2281,8 +2291,7 @@ modref_eaf_analysis::propagate ()
fprintf (dump_file, " New lattice: ");
m_lattice[target].dump (dump_file);
}
- if (target <= (int)i)
- changed = true;
+ changed = true;
m_lattice[target].changed = true;
}
}
@@ -2820,6 +2829,14 @@ modref_generate (void)
} /* ANON namespace. */
+/* Debugging helper. */
+
+void
+debug_eaf_flags (int flags)
+{
+ dump_eaf_flags (stderr, flags, true);
+}
+
/* Called when a new function is inserted to callgraph late. */
void
@@ -4232,7 +4249,8 @@ modref_merge_call_site_flags (escape_summary *sum,
int flags = 0;
int flags_lto = 0;
/* Returning the value is already accounted to at local propagation. */
- int implicit_flags = EAF_NOT_RETURNED | EAF_NOT_RETURNED_DIRECTLY;
+ int implicit_flags = EAF_NOT_RETURNED_DIRECTLY
+ | EAF_NOT_RETURNED_INDIRECTLY;
if (summary && ee->arg < summary->arg_flags.length ())
flags = summary->arg_flags[ee->arg];
@@ -4263,11 +4281,15 @@ modref_merge_call_site_flags (escape_summary *sum,
else
{
if (fnspec.arg_direct_p (ee->arg))
- fnspec_flags |= EAF_DIRECT;
+ fnspec_flags |= EAF_NO_INDIRECT_READ
+ | EAF_NO_INDIRECT_ESCAPE
+ | EAF_NOT_RETURNED_INDIRECTLY
+ | EAF_NO_INDIRECT_CLOBBER;
if (fnspec.arg_noescape_p (ee->arg))
- fnspec_flags |= EAF_NOESCAPE | EAF_NODIRECTESCAPE;
+ fnspec_flags |= EAF_NO_DIRECT_ESCAPE
+ | EAF_NO_INDIRECT_ESCAPE;
if (fnspec.arg_readonly_p (ee->arg))
- fnspec_flags |= EAF_NOCLOBBER;
+ flags |= EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER;
}
}
implicit_flags |= fnspec_flags;
@@ -4281,16 +4303,6 @@ modref_merge_call_site_flags (escape_summary *sum,
flags = interposable_eaf_flags (flags, implicit_flags);
flags_lto = interposable_eaf_flags (flags_lto, implicit_flags);
}
- /* 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_NOT_RETURNED)
- flags |= EAF_NOT_RETURNED_DIRECTLY;
- if (flags_lto & EAF_NOT_RETURNED)
- flags_lto |= EAF_NOT_RETURNED_DIRECTLY;
if (!(flags & EAF_UNUSED)
&& cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ())
{
@@ -4695,8 +4707,6 @@ ipa_modref_c_finalize ()
if (optimization_summaries)
ggc_delete (optimization_summaries);
optimization_summaries = NULL;
- gcc_checking_assert (!summaries
- || flag_incremental_link == INCREMENTAL_LINK_LTO);
if (summaries_lto)
ggc_delete (summaries_lto);
summaries_lto = NULL;
diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h
index 20170a6..482c4e4 100644
--- a/gcc/ipa-modref.h
+++ b/gcc/ipa-modref.h
@@ -21,7 +21,7 @@ along with GCC; see the file COPYING3. If not see
#define IPA_MODREF_H
typedef modref_tree <alias_set_type> modref_records;
-typedef unsigned char eaf_flags_t;
+typedef unsigned short eaf_flags_t;
/* Single function summary. */
@@ -48,15 +48,28 @@ void ipa_modref_c_finalize ();
void ipa_merge_modref_summary_after_inlining (cgraph_edge *e);
/* All flags that are implied by the ECF_CONST functions. */
-static const int implicit_const_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
- | EAF_NODIRECTESCAPE | EAF_NOREAD;
+static const int implicit_const_eaf_flags
+ = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
+ | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE
+ | EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ
+ | EAF_NOT_RETURNED_INDIRECTLY;
+
/* All flags that are implied by the ECF_PURE function. */
-static const int implicit_pure_eaf_flags = EAF_NOCLOBBER | EAF_NOESCAPE
- | EAF_NODIRECTESCAPE;
+static const int implicit_pure_eaf_flags
+ = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
+ | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE;
+
/* All flags implied when we know we can ignore stores (i.e. when handling
call to noreturn). */
-static const int ignore_stores_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
- | EAF_NODIRECTESCAPE;
+static const int ignore_stores_eaf_flags
+ = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
+ | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE;
+
+/* Return slot is write-only. */
+static const int implicit_retslot_eaf_flags
+ = EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ
+ | EAF_NO_INDIRECT_ESCAPE | EAF_NO_INDIRECT_CLOBBER
+ | EAF_NOT_RETURNED_INDIRECTLY;
/* If function does not bind to current def (i.e. it is inline in comdat
section), the modref analysis may not match the behaviour of function
@@ -74,16 +87,15 @@ interposable_eaf_flags (int modref_flags, int flags)
if ((modref_flags & EAF_UNUSED) && !(flags & EAF_UNUSED))
{
modref_flags &= ~EAF_UNUSED;
- modref_flags |= EAF_NOESCAPE | EAF_NOT_RETURNED
- | EAF_NOT_RETURNED_DIRECTLY | EAF_NOCLOBBER;
+ modref_flags |= EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE
+ | EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY
+ | EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER;
}
/* We can not deterine that value is not read at all. */
- if ((modref_flags & EAF_NOREAD) && !(flags & EAF_NOREAD))
- modref_flags &= ~EAF_NOREAD;
- /* Clear direct flags so we also know that value is possibly read
- indirectly. */
- if ((modref_flags & EAF_DIRECT) && !(flags & EAF_DIRECT))
- modref_flags &= ~EAF_DIRECT;
+ if ((modref_flags & EAF_NO_DIRECT_READ) && !(flags & EAF_NO_DIRECT_READ))
+ modref_flags &= ~EAF_NO_DIRECT_READ;
+ if ((modref_flags & EAF_NO_INDIRECT_READ) && !(flags & EAF_NO_INDIRECT_READ))
+ modref_flags &= ~EAF_NO_INDIRECT_READ;
return modref_flags;
}
diff --git a/gcc/testsuite/g++.dg/ipa/modref-1.C b/gcc/testsuite/g++.dg/ipa/modref-1.C
index eaa14ea..c57aaca 100644
--- a/gcc/testsuite/g++.dg/ipa/modref-1.C
+++ b/gcc/testsuite/g++.dg/ipa/modref-1.C
@@ -31,5 +31,5 @@ int main()
return 0;
}
/* { dg-final { scan-tree-dump "Function found to be const: {anonymous}::B::genB" "local-pure-const1" } } */
-/* { dg-final { scan-tree-dump "Retslot flags: direct noescape nodirectescape not_returned not_returned_directly noread" "modref1" } } */
+/* { dg-final { scan-tree-dump "Retslot flags: no_indirect_clobber no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly no_direct_read no_indirect_read" "modref1" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/modref-3.c b/gcc/testsuite/gcc.dg/ipa/modref-3.c
index 8401354..9a20e01 100644
--- a/gcc/testsuite/gcc.dg/ipa/modref-3.c
+++ b/gcc/testsuite/gcc.dg/ipa/modref-3.c
@@ -17,4 +17,4 @@ main ()
linker_error ();
return 0;
}
-/* { dg-final { scan-ipa-dump "Static chain flags: noclobber noescape nodirectescape" "modref" } } */
+/* { dg-final { scan-ipa-dump "Static chain flags: no_direct_clobber no_indirect_clobber no_direct_escape no_indirect_escape not_returned_directly no_indirect_read" "modref" } } */
diff --git a/gcc/testsuite/gcc.dg/lto/modref-3_0.c b/gcc/testsuite/gcc.dg/lto/modref-3_0.c
index bd8f96f..0210d11 100644
--- a/gcc/testsuite/gcc.dg/lto/modref-3_0.c
+++ b/gcc/testsuite/gcc.dg/lto/modref-3_0.c
@@ -14,4 +14,4 @@ main()
__builtin_abort ();
return 0;
}
-/* { dg-final { scan-wpa-ipa-dump "parm 1 flags: nodirectescape" "modref" } } */
+/* { dg-final { scan-wpa-ipa-dump "parm 1 flags: no_direct_clobber no_direct_escape" "modref" } } */
diff --git a/gcc/testsuite/gcc.dg/lto/modref-4_0.c b/gcc/testsuite/gcc.dg/lto/modref-4_0.c
index db90b4f..9437585 100644
--- a/gcc/testsuite/gcc.dg/lto/modref-4_0.c
+++ b/gcc/testsuite/gcc.dg/lto/modref-4_0.c
@@ -14,4 +14,4 @@ main()
__builtin_abort ();
return 0;
}
-/* { dg-final { scan-wpa-ipa-dump "parm 1 flags: nodirectescape" "modref" } } */
+/* { dg-final { scan-wpa-ipa-dump "parm 1 flags: no_direct_clobber no_direct_escape" "modref" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-10.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-10.c
index c608408..4a6d9e5 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/modref-10.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-10.c
@@ -17,4 +17,4 @@ main()
linker_error ();
return 0;
}
-/* { dg-final { scan-tree-dump "parm 0 flags: noclobber noescape nodirectescape not_returned_directly" "modref1"} } */
+/* { dg-final { scan-tree-dump "no_direct_clobber no_indirect_clobber no_direct_escape no_indirect_escape not_returned_directly no_indirect_read" "modref1"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-11.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-11.c
index de9ad16..cafb4f3 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/modref-11.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-11.c
@@ -10,4 +10,4 @@ find_last (struct linkedlist *l)
l = l->next;
return l;
}
-/* { dg-final { scan-tree-dump "noclobber noescape nodirectescape" "modref1"} } */
+/* { dg-final { scan-tree-dump "parm 0 flags: no_direct_clobber no_indirect_clobber no_direct_escape no_indirect_escape" "modref1"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-13.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-13.c
new file mode 100644
index 0000000..5a57504
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-13.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-release_ssa" } */
+struct wrap {
+ void **array;
+};
+__attribute__ ((noinline))
+void
+write_array (struct wrap *ptr)
+{
+ ptr->array[0]=0;
+}
+int
+test ()
+{
+ void *arrayval;
+ struct wrap w = {&arrayval};
+ write_array (&w);
+ return w.array == &arrayval;
+}
+/* We should deterine that write_array writes to PTR only indirectly. */
+/* { dg-final { scan-tree-dump "return 1" "releae_ssa" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-5.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-5.c
index fde3177..0bee79d 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/modref-5.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-5.c
@@ -24,4 +24,4 @@ main()
__builtin_abort ();
return 0;
}
-/* { dg-final { scan-tree-dump "parm 1 flags: nodirectescape" "modref1" } } */
+/* { dg-final { scan-tree-dump "parm 1 flags: no_direct_clobber no_direct_escape" "modref1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-6.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-6.c
index 2d97a49..7146389 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/modref-6.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-6.c
@@ -28,10 +28,10 @@ int test2()
return a;
}
/* Flags for normal call. */
-/* { dg-final { scan-tree-dump "parm 0 flags: direct noclobber noescape nodirectescape not_returned" "modref1" } } */
+/* { dg-final { scan-tree-dump "parm 0 flags: no_direct_clobber no_indirect_clobber no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly no_indirect_read" "modref1" } } */
/* Flags for pure call. */
-/* { dg-final { scan-tree-dump "parm 0 flags: direct not_returned" "modref1" } } */
+/* { dg-final { scan-tree-dump "parm 0 flags: not_returned_directly not_returned_indirectly no_indirect_read" "modref1" } } */
/* Flags for const call. */
-/* { dg-final { scan-tree-dump "parm 0 flags: not_returned" "modref1" } } */
+/* { dg-final { scan-tree-dump "parm 0 flags: not_returned_directly" "modref1" } } */
/* Overall we want to make "int a" non escaping. */
/* { dg-final { scan-tree-dump "return 42" "optimized" } } */
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index f0c65a2..8ab119d 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -97,32 +97,29 @@ struct die_struct;
#define ECF_COLD (1 << 15)
/* Call argument flags. */
-/* Nonzero if the argument is not dereferenced recursively, thus only
- directly reachable memory is read or written. */
-#define EAF_DIRECT (1 << 0)
-/* Nonzero if memory reached by the argument is not clobbered. */
-#define EAF_NOCLOBBER (1 << 1)
+/* Nonzero if the argument is not used by the function. */
+#define EAF_UNUSED (1 << 1)
-/* Nonzero if the argument does not escape. */
-#define EAF_NOESCAPE (1 << 2)
+/* Following flags come in pairs. First one is about direct dereferences
+ from the parameter, while the second is about memory reachable by
+ recursive dereferences. */
-/* Nonzero if the argument is not used by the function. */
-#define EAF_UNUSED (1 << 3)
+/* Nonzero if memory reached by the argument is not clobbered. */
+#define EAF_NO_DIRECT_CLOBBER (1 << 2)
+#define EAF_NO_INDIRECT_CLOBBER (1 << 3)
-/* Nonzero if the argument itself does not escape but memory
- referenced by it can escape. */
-#define EAF_NODIRECTESCAPE (1 << 4)
+/* Nonzero if the argument does not escape. */
+#define EAF_NO_DIRECT_ESCAPE (1 << 4)
+#define EAF_NO_INDIRECT_ESCAPE (1 << 5)
/* Nonzero if the argument does not escape to return value. */
-#define EAF_NOT_RETURNED (1 << 5)
-
-/* Nonzero if the argument itself does not escape
- to return value but memory referenced by it may escape. */
#define EAF_NOT_RETURNED_DIRECTLY (1 << 6)
+#define EAF_NOT_RETURNED_INDIRECTLY (1 << 7)
/* Nonzero if the argument is not read. */
-#define EAF_NOREAD (1 << 7)
+#define EAF_NO_DIRECT_READ (1 << 8)
+#define EAF_NO_INDIRECT_READ (1 << 9)
/* Call return flags. */
/* Mask for the argument number that is returned. Lower two bits of
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index eabf680..17ff6bb 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -2874,7 +2874,7 @@ process_args:
tree op = gimple_call_arg (call, i);
int flags = gimple_call_arg_flags (call, i);
- if (flags & (EAF_UNUSED | EAF_NOREAD))
+ if (flags & (EAF_UNUSED | EAF_NO_DIRECT_READ))
continue;
if (TREE_CODE (op) == WITH_SIZE_EXPR)
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index c70f5af..153ddf5 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -4060,48 +4060,117 @@ static void
handle_call_arg (gcall *stmt, tree arg, vec<ce_s> *results, int flags,
int callescape_id, bool writes_global_memory)
{
+ int relevant_indirect_flags = EAF_NO_INDIRECT_CLOBBER | EAF_NO_INDIRECT_READ
+ | EAF_NO_INDIRECT_ESCAPE;
+ int relevant_flags = relevant_indirect_flags
+ | EAF_NO_DIRECT_CLOBBER
+ | EAF_NO_DIRECT_READ
+ | EAF_NO_DIRECT_ESCAPE;
+ if (gimple_call_lhs (stmt))
+ {
+ relevant_flags |= EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY;
+ relevant_indirect_flags |= EAF_NOT_RETURNED_INDIRECTLY;
+
+ /* If value is never read from it can not be returned indirectly
+ (except through the escape solution).
+ For all flags we get these implications right except for
+ not_returned because we miss return functions in ipa-prop. */
+
+ if (flags & EAF_NO_DIRECT_READ)
+ flags |= EAF_NOT_RETURNED_INDIRECTLY;
+ }
+
/* If the argument is not used we can ignore it.
Similarly argument is invisile for us if it not clobbered, does not
escape, is not read and can not be returned. */
- if ((flags & EAF_UNUSED)
- || ((flags & (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD
- | EAF_NOT_RETURNED))
- == (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD
- | EAF_NOT_RETURNED)))
+ if ((flags & EAF_UNUSED) || ((flags & relevant_flags) == relevant_flags))
return;
+ /* Produce varinfo for direct accesses to ARG. */
varinfo_t tem = new_var_info (NULL_TREE, "callarg", true);
tem->is_reg_var = true;
make_constraint_to (tem->id, arg);
make_any_offset_constraints (tem);
- if (!(flags & EAF_DIRECT))
- make_transitive_closure_constraints (tem);
+ bool callarg_transitive = false;
+
+ /* As an compile time optimization if we make no difference between
+ direct and indirect accesses make arg transitively closed.
+ This avoids the need to build indir arg and do everything twice. */
+ if (((flags & EAF_NO_INDIRECT_CLOBBER) != 0)
+ == ((flags & EAF_NO_DIRECT_CLOBBER) != 0)
+ && (((flags & EAF_NO_INDIRECT_READ) != 0)
+ == ((flags & EAF_NO_DIRECT_READ) != 0))
+ && (((flags & EAF_NO_INDIRECT_ESCAPE) != 0)
+ == ((flags & EAF_NO_DIRECT_ESCAPE) != 0))
+ && (((flags & EAF_NOT_RETURNED_INDIRECTLY) != 0)
+ == ((flags & EAF_NOT_RETURNED_DIRECTLY) != 0)))
+ {
+ make_transitive_closure_constraints (tem);
+ callarg_transitive = true;
+ gcc_checking_assert (!(flags & EAF_NO_DIRECT_READ));
+ }
+
+ /* If necessary, produce varinfo for indirect accesses to ARG. */
+ varinfo_t indir_tem = NULL;
+ if (!callarg_transitive
+ && (flags & relevant_indirect_flags) != relevant_indirect_flags)
+ {
+ struct constraint_expr lhs, rhs;
+ indir_tem = new_var_info (NULL_TREE, "indircallarg", true);
+ indir_tem->is_reg_var = true;
+
+ /* indir_term = *tem. */
+ lhs.type = SCALAR;
+ lhs.var = indir_tem->id;
+ lhs.offset = 0;
+
+ rhs.type = DEREF;
+ rhs.var = tem->id;
+ rhs.offset = UNKNOWN_OFFSET;
+ process_constraint (new_constraint (lhs, rhs));
+
+ make_any_offset_constraints (indir_tem);
- if (!(flags & EAF_NOT_RETURNED))
+ /* If we do not read indirectly there is no need for transitive closure.
+ We know there is only one level of indirection. */
+ if (!(flags & EAF_NO_INDIRECT_READ))
+ make_transitive_closure_constraints (indir_tem);
+ gcc_checking_assert (!(flags & EAF_NO_DIRECT_READ));
+ }
+
+ if (gimple_call_lhs (stmt))
{
- struct constraint_expr cexpr;
- cexpr.var = tem->id;
- if (flags & EAF_NOT_RETURNED_DIRECTLY)
+ if (!(flags & EAF_NOT_RETURNED_DIRECTLY))
{
- cexpr.type = DEREF;
- cexpr.offset = UNKNOWN_OFFSET;
+ struct constraint_expr cexpr;
+ cexpr.var = tem->id;
+ cexpr.type = SCALAR;
+ cexpr.offset = 0;
+ results->safe_push (cexpr);
}
- else
+ if (!callarg_transitive & !(flags & EAF_NOT_RETURNED_INDIRECTLY))
{
+ struct constraint_expr cexpr;
+ cexpr.var = indir_tem->id;
cexpr.type = SCALAR;
cexpr.offset = 0;
+ results->safe_push (cexpr);
}
- results->safe_push (cexpr);
}
- if (!(flags & EAF_NOREAD))
+ if (!(flags & EAF_NO_DIRECT_READ))
{
varinfo_t uses = get_call_use_vi (stmt);
make_copy_constraint (uses, tem->id);
+ if (!callarg_transitive & !(flags & EAF_NO_INDIRECT_READ))
+ make_copy_constraint (uses, indir_tem->id);
}
+ else
+ /* To read indirectly we need to read directly. */
+ gcc_checking_assert (flags & EAF_NO_INDIRECT_READ);
- if (!(flags & EAF_NOCLOBBER))
+ if (!(flags & EAF_NO_DIRECT_CLOBBER))
{
struct constraint_expr lhs, rhs;
@@ -4118,8 +4187,25 @@ handle_call_arg (gcall *stmt, tree arg, vec<ce_s> *results, int flags,
/* callclobbered = arg. */
make_copy_constraint (get_call_clobber_vi (stmt), tem->id);
}
+ if (!callarg_transitive & !(flags & EAF_NO_INDIRECT_CLOBBER))
+ {
+ struct constraint_expr lhs, rhs;
- if (!(flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE)))
+ /* *indir_arg = callescape. */
+ lhs.type = DEREF;
+ lhs.var = indir_tem->id;
+ lhs.offset = 0;
+
+ rhs.type = SCALAR;
+ rhs.var = callescape_id;
+ rhs.offset = 0;
+ process_constraint (new_constraint (lhs, rhs));
+
+ /* callclobbered = indir_arg. */
+ make_copy_constraint (get_call_clobber_vi (stmt), indir_tem->id);
+ }
+
+ if (!(flags & (EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE)))
{
struct constraint_expr lhs, rhs;
@@ -4136,18 +4222,18 @@ handle_call_arg (gcall *stmt, tree arg, vec<ce_s> *results, int flags,
if (writes_global_memory)
make_escape_constraint (arg);
}
- else if (!(flags & EAF_NOESCAPE))
+ else if (!callarg_transitive & !(flags & EAF_NO_INDIRECT_ESCAPE))
{
struct constraint_expr lhs, rhs;
- /* callescape = *(arg + UNKNOWN); */
+ /* callescape = *(indir_arg + UNKNOWN); */
lhs.var = callescape_id;
lhs.offset = 0;
lhs.type = SCALAR;
- rhs.var = tem->id;
- rhs.offset = UNKNOWN_OFFSET;
- rhs.type = DEREF;
+ rhs.var = indir_tem->id;
+ rhs.offset = 0;
+ rhs.type = SCALAR;
process_constraint (new_constraint (lhs, rhs));
if (writes_global_memory)
@@ -4264,20 +4350,22 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results,
&& TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt))))
{
int flags = gimple_call_retslot_flags (stmt);
- if ((flags & (EAF_NOESCAPE | EAF_NOT_RETURNED))
- != (EAF_NOESCAPE | EAF_NOT_RETURNED))
+ const int relevant_flags = EAF_NO_DIRECT_ESCAPE
+ | EAF_NOT_RETURNED_DIRECTLY;
+
+ if (!(flags & EAF_UNUSED) && (flags & relevant_flags) != relevant_flags)
{
auto_vec<ce_s> tmpc;
get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc);
- if (!(flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE)))
+ if (!(flags & EAF_NO_DIRECT_ESCAPE))
{
make_constraints_to (callescape->id, tmpc);
if (writes_global_memory)
make_constraints_to (escaped_id, tmpc);
}
- if (!(flags & EAF_NOT_RETURNED))
+ if (!(flags & EAF_NOT_RETURNED_DIRECTLY))
{
struct constraint_expr *c;
unsigned i;
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index d67534f..1df0bcc 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -744,7 +744,8 @@ maybe_warn_pass_by_reference (gcall *stmt, wlimits &wlims)
wlims.always_executed = false;
/* Ignore args we are not going to read from. */
- if (gimple_call_arg_flags (stmt, argno - 1) & (EAF_UNUSED | EAF_NOREAD))
+ if (gimple_call_arg_flags (stmt, argno - 1)
+ & (EAF_UNUSED | EAF_NO_DIRECT_READ))
continue;
tree arg = gimple_call_arg (stmt, argno - 1);