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 <hubi...@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 <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany; GF: Ivo Totev; HRB 36809 (AG Nuernberg)