From: Richard Biener <rguenther@suse.de>
To: Jan Hubicka <hubicka@kam.mff.cuni.cz>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: Make EAF flags more regular (and expressive)
Date: Wed, 10 Nov 2021 08:25:51 +0100 (CET) [thread overview]
Message-ID: <1r846n15-684-50p9-qs99-q7o24981n8po@fhfr.qr> (raw)
In-Reply-To: <20211109204548.GA97553@kam.mff.cuni.cz>
On Tue, 9 Nov 2021, Jan Hubicka wrote:
> Hi,
> I hoped that I am done with EAF flags related changes, but while looking into
> the Fortran testcases I noticed that I have designed them in unnecesarily
> restricted way. I followed the scheme of NOESCAPE and NODIRECTESCAPE which is
> however the only property tht is naturally transitive.
>
> This patch replaces the existing flags by 9 flags:
>
> EAF_UNUSED
> EAF_NO_DIRECT_CLOBBER and EAF_NO_INDIRECT_CLOBBER
> EAF_NO_DIRECT_READ and EAF_NO_INDIRECT_READ
> EAF_NO_DIRECT_ESCAPE and EAF_NO_INDIRECT_ESCAPE
> EAF_NO_DIRECT_READ and EAF_NO_INDIRECT_READ
>
> So I have removed the unified EAF_DIRECT flag and made each of the flags to come
> in direct and indirect variant. Newly the indirect variant is not implied by direct
> (well except for escape but it is not special cased in the code)
> Consequently we can analyse i.e. the case where function reads directly and clobber
> indirectly as in the following testcase:
>
> 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;
> }
>
> This is pretty common in array descriptors and also C++ pointer wrappers or structures
> containing pointers to arrays.
>
> Other advantage is that !binds_to_current_def_p functions we can still track the fact
> that the value is not clobbered indirectly while previously we implied EAF_DIRECT
> for all three cases.
>
> We can now also, in some cases, make difference between single and
> multiple indirection becaue from EAF_READ_INDIRECTLY we know when
> function can not produce deeper indirections.
>
> Finally the propagation becomes more regular and I hope easier to understand
> because the flags are handled in a symmetric way.
>
> In tree-ssa-structalias I now produce "callarg" var_info as before and if necessary
> also "indircallarg" for the indirect accesses. I added some logic to optimize the
> common case where we can not make difference between direct and indirect.
>
> The patch changes cc1plus build stats from:
>
> Alias oracle query stats:
> refs_may_alias_p: 76837664 disambiguations, 101409766 queries
> ref_maybe_used_by_call_p: 653271 disambiguations, 77840575 queries
> call_may_clobber_ref_p: 390312 disambiguations, 393172 queries
> nonoverlapping_component_refs_p: 0 disambiguations, 26140 queries
> nonoverlapping_refs_since_match_p: 30203 disambiguations, 65079 must overlaps, 96241 queries
> aliasing_component_refs_p: 57089 disambiguations, 15404304 queries
> TBAA oracle: 28153258 disambiguations 104252784 queries
> 14994692 are in alias set 0
> 8948831 queries asked about the same object
> 98 queries asked about the same alias set
> 0 access volatile
> 50240521 are dependent in the DAG
> 1915384 are aritificially in conflict with void *
>
> Modref stats:
> modref use: 25340 disambiguations, 712706 queries
> modref clobber: 2341693 disambiguations, 22800331 queries
> 5368354 tbaa queries (0.235451 per modref query)
> 765195 base compares (0.033561 per modref query)
>
> PTA query stats:
> pt_solution_includes: 13551618 disambiguations, 40800084 queries
> pt_solutions_intersect: 1698854 disambiguations, 13763853 queries
>
> to:
>
> Alias oracle query stats:
> refs_may_alias_p: 76925524 disambiguations, 101500189 queries
> ref_maybe_used_by_call_p: 653442 disambiguations, 77928881 queries
> call_may_clobber_ref_p: 390427 disambiguations, 393209 queries
> nonoverlapping_component_refs_p: 0 disambiguations, 26158 queries
> nonoverlapping_refs_since_match_p: 30370 disambiguations, 65145 must overlaps, 96477 queries
> aliasing_component_refs_p: 57095 disambiguations, 15404308 queries
> TBAA oracle: 28166182 disambiguations 104266578 queries
> 15000259 are in alias set 0
> 8961963 queries asked about the same object
> 98 queries asked about the same alias set
> 0 access volatile
> 50218808 are dependent in the DAG
> 1919268 are aritificially in conflict with void *
>
> Modref stats:
> modref use: 25381 disambiguations, 712966 queries
> modref clobber: 2331197 disambiguations, 22827861 queries
> 5350923 tbaa queries (0.234403 per modref query)
> 765444 base compares (0.033531 per modref query)
>
> PTA query stats:
> pt_solution_includes: 13593046 disambiguations, 40826434 queries
> pt_solutions_intersect: 1726400 disambiguations, 13796247 queries
>
> So only by about 1%. However for tramp3d the difference is more noticeable. From
>
> Alias oracle query stats:
> refs_may_alias_p: 5462729 disambiguations, 5799042 queries
> ref_maybe_used_by_call_p: 23575 disambiguations, 5511000 queries
> call_may_clobber_ref_p: 2188 disambiguations, 2188 queries
> nonoverlapping_component_refs_p: 0 disambiguations, 6216 queries
> nonoverlapping_refs_since_match_p: 270 disambiguations, 4803 must overlaps, 5164 queries
> aliasing_component_refs_p: 2242 disambiguations, 41884 queries
> TBAA oracle: 2287136 disambiguations 3598543 queries
> 166373 are in alias set 0
> 769743 queries asked about the same object
> 0 queries asked about the same alias set
> 0 access volatile
> 375144 are dependent in the DAG
> 147 are aritificially in conflict with void *
>
> Modref stats:
> modref use: 6124 disambiguations, 55063 queries
> modref clobber: 43317 disambiguations, 581346 queries
> 121869 tbaa queries (0.209632 per modref query)
> 32045 base compares (0.055122 per modref query)
>
> PTA query stats:
> pt_solution_includes: 872055 disambiguations, 1119697 queries
> pt_solutions_intersect: 106431 disambiguations, 536171 queries
>
> to:
>
> Alias oracle query stats:
> refs_may_alias_p: 5759154 disambiguations, 6095629 queries
> ref_maybe_used_by_call_p: 24364 disambiguations, 5806584 queries
> call_may_clobber_ref_p: 2484 disambiguations, 2484 queries
> nonoverlapping_component_refs_p: 0 disambiguations, 6204 queries
> nonoverlapping_refs_since_match_p: 283 disambiguations, 4823 must overlaps, 5197 queries
> aliasing_component_refs_p: 2217 disambiguations, 40633 queries
> TBAA oracle: 2314375 disambiguations 3649316 queries
> 166981 are in alias set 0
> 785650 queries asked about the same object
> 0 queries asked about the same alias set
> 0 access volatile
> 382163 are dependent in the DAG
> 147 are aritificially in conflict with void *
>
> Modref stats:
> modref use: 6132 disambiguations, 55004 queries
> modref clobber: 45192 disambiguations, 634478 queries
> 126552 tbaa queries (0.199458 per modref query)
> 32340 base compares (0.050971 per modref query)
>
> PTA query stats:
> pt_solution_includes: 972939 disambiguations, 1205610 queries
> pt_solutions_intersect: 103741 disambiguations, 533181 queries
>
> This is 11% improvement on PTA query stats and 5% overall that is quite nice.
>
> Bootstrapped/regtested x86_64-linux, OK?
OK.
Thanks,
Richard.
> gcc/ChangeLog:
>
> 2021-11-09 Jan Hubicka <hubicka@ucw.cz>
>
> * tree-core.h (EAF_DIRECT): Remove.
> (EAF_NOCLOBBER): Remove.
> (EAF_UNUSED): Remove.
> (EAF_NOESCAPE): Remove.
> (EAF_NO_DIRECT_CLOBBER): New.
> (EAF_NO_INDIRECT_CLOBBER): New.
> (EAF_NODIRECTESCAPE): Remove.
> (EAF_NO_DIRECT_ESCAPE): New.
> (EAF_NO_INDIRECT_ESCAPE): New.
> (EAF_NOT_RETURNED): Remove.
> (EAF_NOT_RETURNED_INDIRECTLY): New.
> (EAF_NOREAD): Remove.
> (EAF_NO_DIRECT_READ): New.
> (EAF_NO_INDIRECT_READ): New.
> * gimple.c (gimple_call_arg_flags): Update for new flags.
> (gimple_call_retslot_flags): Update for new flags.
> * ipa-modref.c (dump_eaf_flags): Likewise.
> (remove_useless_eaf_flags): Likewise.
> (deref_flags): Likewise.
> (modref_lattice::init): Likewise.
> (modref_lattice::merge): Likewise.
> (modref_lattice::merge_direct_load): Likewise.
> (modref_lattice::merge_direct_store): Likewise.
> (modref_eaf_analysis::merge_call_lhs_flags): Likewise.
> (callee_to_caller_flags): Likewise.
> (modref_eaf_analysis::analyze_ssa_name): Likewise.
> (modref_eaf_analysis::propagate): Likewise.
> (modref_merge_call_site_flags): Likewise.
> * ipa-modref.h (interposable_eaf_flags): Likewise.
> * tree-ssa-alias.c: (ref_maybe_used_by_call_p_1) Likewise.
> * tree-ssa-structalias.c (handle_call_arg): Likewise.
> (handle_rhs_call): Likewise.
> * tree-ssa-uninit.c (maybe_warn_pass_by_reference): Likewise.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/ipa/modref-1.C: Update template.
> * gcc.dg/ipa/modref-3.c: Update template.
> * gcc.dg/lto/modref-3_0.c: Update template.
> * gcc.dg/lto/modref-4_0.c: Update template.
> * gcc.dg/tree-ssa/modref-10.c: Update template.
> * gcc.dg/tree-ssa/modref-11.c: Update template.
> * gcc.dg/tree-ssa/modref-5.c: Update template.
> * gcc.dg/tree-ssa/modref-6.c: Update template.
> * gcc.dg/tree-ssa/modref-13.c: New test.
>
> diff --git a/gcc/gimple.c b/gcc/gimple.c
> index 9e65fa61c73..1e0fad92e15 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 22efc06c583..f6b0bf3212b 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
> @@ -2819,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
> @@ -4231,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];
> @@ -4262,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;
> @@ -4280,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 ())
> {
> diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h
> index 20170a65ded..482c4e4633e 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 eaa14ea5c7f..c57aaca0230 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 84013541ce8..9a20e018ae1 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 bd8f96f6ec4..0210d115111 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 db90b4f1f3d..94375851146 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 c608408809d..4a6d9e54c23 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 de9ad16879f..cafb4f34894 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 00000000000..5a5750425d2
> --- /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 fde31772862..0bee79d769d 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 2d97a4903ff..7146389a5b4 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 f0c65a25f07..8ab119dc9a2 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 eabf6805f2b..17ff6bb582c 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 c70f5af8949..153ddf57a61 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 d67534f22a8..1df0bcc42c0 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);
>
>
--
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Ivo Totev; HRB 36809 (AG Nuernberg)
prev parent reply other threads:[~2021-11-10 7:25 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-11-09 20:45 Jan Hubicka
2021-11-10 7:25 ` Richard Biener [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1r846n15-684-50p9-qs99-q7o24981n8po@fhfr.qr \
--to=rguenther@suse.de \
--cc=gcc-patches@gcc.gnu.org \
--cc=hubicka@kam.mff.cuni.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).