LCOV - code coverage report
Current view: top level - gcc - ipa-modref.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 94.7 % 2887 2734
Test Date: 2026-02-28 14:20:25 Functions: 98.2 % 114 112
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Search for references that a functions loads or stores.
       2              :    Copyright (C) 2020-2026 Free Software Foundation, Inc.
       3              :    Contributed by David Cepelik and Jan Hubicka
       4              : 
       5              : This file is part of GCC.
       6              : 
       7              : GCC is free software; you can redistribute it and/or modify it under
       8              : the terms of the GNU General Public License as published by the Free
       9              : Software Foundation; either version 3, or (at your option) any later
      10              : version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15              : for more details.
      16              : 
      17              : You should have received a copy of the GNU General Public License
      18              : along with GCC; see the file COPYING3.  If not see
      19              : <http://www.gnu.org/licenses/>.  */
      20              : 
      21              : /* Mod/ref pass records summary about loads and stores performed by the
      22              :    function.  This is later used by alias analysis to disambiguate memory
      23              :    accesses across function calls.
      24              : 
      25              :    This file contains a tree pass and an IPA pass.  Both performs the same
      26              :    analysis however tree pass is executed during early and late optimization
      27              :    passes to propagate info downwards in the compilation order.  IPA pass
      28              :    propagates across the callgraph and is able to handle recursion and works on
      29              :    whole program during link-time analysis.
      30              : 
      31              :    LTO mode differs from the local mode by not recording alias sets but types
      32              :    that are translated to alias sets later.  This is necessary in order stream
      33              :    the information because the alias sets are rebuild at stream-in time and may
      34              :    not correspond to ones seen during analysis.  For this reason part of
      35              :    analysis is duplicated.
      36              : 
      37              :    The following information is computed
      38              :      1) load/store access tree described in ipa-modref-tree.h
      39              :         This is used by tree-ssa-alias to disambiguate load/stores
      40              :      2) EAF flags used by points-to analysis (in tree-ssa-structalias).
      41              :         and defined in tree-core.h.
      42              :    and stored to optimization_summaries.
      43              : 
      44              :    There are multiple summaries computed and used during the propagation:
      45              :      - summaries holds summaries from analysis to IPA propagation
      46              :        time.
      47              :      - summaries_lto is same as summaries but holds them in a format
      48              :        that can be streamed (as described above).
      49              :      - fnspec_summary holds fnspec strings for call.  This is
      50              :        necessary because gimple_call_fnspec performs additional
      51              :        analysis except for looking callee fndecl.
      52              :      - escape_summary holds escape points for given call edge.
      53              :        That is a vector recording what function parameters
      54              :        may escape to a function call (and with what parameter index).  */
      55              : 
      56              : #include "config.h"
      57              : #include "system.h"
      58              : #include "coretypes.h"
      59              : #include "backend.h"
      60              : #include "tree.h"
      61              : #include "gimple.h"
      62              : #include "alloc-pool.h"
      63              : #include "tree-pass.h"
      64              : #include "gimple-iterator.h"
      65              : #include "tree-dfa.h"
      66              : #include "cgraph.h"
      67              : #include "ipa-utils.h"
      68              : #include "symbol-summary.h"
      69              : #include "gimple-pretty-print.h"
      70              : #include "gimple-walk.h"
      71              : #include "print-tree.h"
      72              : #include "tree-streamer.h"
      73              : #include "alias.h"
      74              : #include "calls.h"
      75              : #include "ipa-modref-tree.h"
      76              : #include "ipa-modref.h"
      77              : #include "value-range.h"
      78              : #include "sreal.h"
      79              : #include "ipa-cp.h"
      80              : #include "ipa-prop.h"
      81              : #include "ipa-fnsummary.h"
      82              : #include "attr-fnspec.h"
      83              : #include "symtab-clones.h"
      84              : #include "gimple-ssa.h"
      85              : #include "tree-phinodes.h"
      86              : #include "tree-ssa-operands.h"
      87              : #include "ssa-iterators.h"
      88              : #include "stringpool.h"
      89              : #include "tree-ssanames.h"
      90              : #include "attribs.h"
      91              : #include "tree-cfg.h"
      92              : #include "tree-eh.h"
      93              : 
      94              : 
      95              : namespace {
      96              : 
      97              : /* We record fnspec specifiers for call edges since they depends on actual
      98              :    gimple statements.  */
      99              : 
     100              : class fnspec_summary
     101              : {
     102              : public:
     103              :   char *fnspec;
     104              : 
     105      1081716 :   fnspec_summary ()
     106      1081716 :   : fnspec (NULL)
     107              :   {
     108              :   }
     109              : 
     110      1081716 :   ~fnspec_summary ()
     111              :   {
     112      1081716 :     free (fnspec);
     113      1081716 :   }
     114              : };
     115              : 
     116              : /* Summary holding fnspec string for a given call.  */
     117              : 
     118              : class fnspec_summaries_t : public call_summary <fnspec_summary *>
     119              : {
     120              : public:
     121       154150 :   fnspec_summaries_t (symbol_table *symtab)
     122       308300 :       : call_summary <fnspec_summary *> (symtab) {}
     123              :   /* Hook that is called by summary when an edge is duplicated.  */
     124       495886 :   void duplicate (cgraph_edge *,
     125              :                   cgraph_edge *,
     126              :                   fnspec_summary *src,
     127              :                   fnspec_summary *dst) final override
     128              :   {
     129       495886 :     dst->fnspec = xstrdup (src->fnspec);
     130       495886 :   }
     131              : };
     132              : 
     133              : static fnspec_summaries_t *fnspec_summaries = NULL;
     134              : 
     135              : /* Escape summary holds a vector of param indexes that escape to
     136              :    a given call.  */
     137              : struct escape_entry
     138              : {
     139              :   /* Parameter that escapes at a given call.  */
     140              :   int parm_index;
     141              :   /* Argument it escapes to.  */
     142              :   unsigned int arg;
     143              :   /* Minimal flags known about the argument.  */
     144              :   eaf_flags_t min_flags;
     145              :   /* Does it escape directly or indirectly?  */
     146              :   bool direct;
     147              : };
     148              : 
     149              : /* Dump EAF flags.  */
     150              : 
     151              : static void
     152         3547 : dump_eaf_flags (FILE *out, int flags, bool newline = true)
     153              : {
     154         3547 :   if (flags & EAF_UNUSED)
     155          238 :     fprintf (out, " unused");
     156         3547 :   if (flags & EAF_NO_DIRECT_CLOBBER)
     157         2275 :     fprintf (out, " no_direct_clobber");
     158         3547 :   if (flags & EAF_NO_INDIRECT_CLOBBER)
     159         2177 :     fprintf (out, " no_indirect_clobber");
     160         3547 :   if (flags & EAF_NO_DIRECT_ESCAPE)
     161         2800 :     fprintf (out, " no_direct_escape");
     162         3547 :   if (flags & EAF_NO_INDIRECT_ESCAPE)
     163         2436 :     fprintf (out, " no_indirect_escape");
     164         3547 :   if (flags & EAF_NOT_RETURNED_DIRECTLY)
     165         2499 :     fprintf (out, " not_returned_directly");
     166         3547 :   if (flags & EAF_NOT_RETURNED_INDIRECTLY)
     167         2375 :     fprintf (out, " not_returned_indirectly");
     168         3547 :   if (flags & EAF_NO_DIRECT_READ)
     169         2096 :     fprintf (out, " no_direct_read");
     170         3547 :   if (flags & EAF_NO_INDIRECT_READ)
     171         2242 :     fprintf (out, " no_indirect_read");
     172         3547 :   if (newline)
     173         3471 :   fprintf (out, "\n");
     174         3547 : }
     175              : 
     176       785194 : struct escape_summary
     177              : {
     178              :   auto_vec <escape_entry> esc;
     179           11 :   void dump (FILE *out)
     180              :   {
     181           24 :     for (unsigned int i = 0; i < esc.length (); i++)
     182              :       {
     183           39 :         fprintf (out, "   parm %i arg %i %s min:",
     184           13 :                  esc[i].parm_index,
     185           13 :                  esc[i].arg,
     186           13 :                  esc[i].direct ? "(direct)" : "(indirect)");
     187           13 :         dump_eaf_flags (out, esc[i].min_flags, false);
     188              :       }
     189           11 :     fprintf (out, "\n");
     190           11 :   }
     191              : };
     192              : 
     193              : class escape_summaries_t : public call_summary <escape_summary *>
     194              : {
     195              : public:
     196       154150 :   escape_summaries_t (symbol_table *symtab)
     197       308300 :       : call_summary <escape_summary *> (symtab) {}
     198              :   /* Hook that is called by summary when an edge is duplicated.  */
     199       159714 :   void duplicate (cgraph_edge *,
     200              :                   cgraph_edge *,
     201              :                   escape_summary *src,
     202              :                   escape_summary *dst) final override
     203              :   {
     204       159714 :     dst->esc = src->esc.copy ();
     205       159714 :   }
     206              : };
     207              : 
     208              : static escape_summaries_t *escape_summaries = NULL;
     209              : 
     210              : }  /* ANON namespace: GTY annotated summaries can not be anonymous.  */
     211              : 
     212              : 
     213              : /* Class (from which there is one global instance) that holds modref summaries
     214              :    for all analyzed functions.  */
     215              : 
     216              : class GTY((user)) modref_summaries
     217              :   : public fast_function_summary <modref_summary *, va_gc>
     218              : {
     219              : public:
     220       287652 :   modref_summaries (symbol_table *symtab)
     221       575304 :       : fast_function_summary <modref_summary *, va_gc> (symtab) {}
     222              :   void insert (cgraph_node *, modref_summary *state) final override;
     223              :   void duplicate (cgraph_node *src_node,
     224              :                   cgraph_node *dst_node,
     225              :                   modref_summary *src_data,
     226              :                   modref_summary *dst_data) final override;
     227       287652 :   static modref_summaries *create_ggc (symbol_table *symtab)
     228              :   {
     229       287652 :     return new (ggc_alloc_no_dtor<modref_summaries> ())
     230       287652 :              modref_summaries (symtab);
     231              :   }
     232              : };
     233              : 
     234              : class modref_summary_lto;
     235              : 
     236              : /* Class (from which there is one global instance) that holds modref summaries
     237              :    for all analyzed functions.  */
     238              : 
     239              : class GTY((user)) modref_summaries_lto
     240              :   : public fast_function_summary <modref_summary_lto *, va_gc>
     241              : {
     242              : public:
     243        27378 :   modref_summaries_lto (symbol_table *symtab)
     244        27378 :       : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
     245        54756 :         propagated (false) {}
     246              :   void insert (cgraph_node *, modref_summary_lto *state) final override;
     247              :   void duplicate (cgraph_node *src_node,
     248              :                   cgraph_node *dst_node,
     249              :                   modref_summary_lto *src_data,
     250              :                   modref_summary_lto *dst_data) final override;
     251        27378 :   static modref_summaries_lto *create_ggc (symbol_table *symtab)
     252              :   {
     253        27378 :     return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
     254        27378 :              modref_summaries_lto (symtab);
     255              :   }
     256              :   bool propagated;
     257              : };
     258              : 
     259              : /* Global variable holding all modref summaries
     260              :    (from analysis to IPA propagation time).  */
     261              : 
     262              : static GTY(()) fast_function_summary <modref_summary *, va_gc>
     263              :          *summaries;
     264              : 
     265              : /* Global variable holding all modref optimization summaries
     266              :    (from IPA propagation time or used by local optimization pass).  */
     267              : 
     268              : static GTY(()) fast_function_summary <modref_summary *, va_gc>
     269              :          *optimization_summaries;
     270              : 
     271              : /* LTO summaries hold info from analysis to LTO streaming or from LTO
     272              :    stream-in through propagation to LTO stream-out.  */
     273              : 
     274              : static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
     275              :          *summaries_lto;
     276              : 
     277              : /* Summary for a single function which this pass produces.  */
     278              : 
     279      7676468 : modref_summary::modref_summary ()
     280      7676468 :   : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
     281      7676468 :     writes_errno (false), side_effects (false), nondeterministic (false),
     282      7676468 :     calls_interposable (false), global_memory_read (false),
     283      7676468 :     global_memory_written (false), try_dse (false)
     284              : {
     285      7676468 : }
     286              : 
     287      7675788 : modref_summary::~modref_summary ()
     288              : {
     289      7675788 :   if (loads)
     290      5447993 :     ggc_delete (loads);
     291      7675788 :   if (stores)
     292      5447993 :     ggc_delete (stores);
     293      7675788 : }
     294              : 
     295              : /* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
     296              :    useful to track.  If returns_void is true moreover clear
     297              :    EAF_NOT_RETURNED.  */
     298              : static int
     299     16614304 : remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
     300              : {
     301     16614304 :   if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
     302      1472428 :     eaf_flags &= ~implicit_const_eaf_flags;
     303     15141876 :   else if (ecf_flags & ECF_PURE)
     304      2374376 :     eaf_flags &= ~implicit_pure_eaf_flags;
     305     12767500 :   else if ((ecf_flags & ECF_NORETURN) || returns_void)
     306      3021831 :     eaf_flags &= ~(EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY);
     307     16614304 :   return eaf_flags;
     308              : }
     309              : 
     310              : /* Return true if FLAGS holds some useful information.  */
     311              : 
     312              : static bool
     313      5804865 : eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags)
     314              : {
     315      6507015 :   for (unsigned i = 0; i < flags.length (); i++)
     316      4054049 :     if (remove_useless_eaf_flags (flags[i], ecf_flags, false))
     317              :       return true;
     318              :   return false;
     319              : }
     320              : 
     321              : /* Return true if summary is potentially useful for optimization.
     322              :    If CHECK_FLAGS is false assume that arg_flags are useful.  */
     323              : 
     324              : bool
     325     75776862 : modref_summary::useful_p (int ecf_flags, bool check_flags)
     326              : {
     327     75776862 :   if (arg_flags.length () && !check_flags)
     328              :     return true;
     329     29530506 :   if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
     330              :     return true;
     331     26385854 :   arg_flags.release ();
     332     26385854 :   if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
     333              :     return true;
     334     26371112 :   if (check_flags
     335     26371112 :       && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
     336              :     return true;
     337     26328900 :   if (ecf_flags & ECF_CONST)
     338      1154285 :     return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
     339     25740906 :   if (loads && !loads->every_base)
     340              :     return true;
     341              :   else
     342      5611947 :     kills.release ();
     343      5611947 :   if (ecf_flags & ECF_PURE)
     344       168005 :     return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
     345      5495121 :   return stores && !stores->every_base;
     346              : }
     347              : 
     348              : /* Single function summary used for LTO.  */
     349              : 
     350              : typedef modref_tree <tree> modref_records_lto;
     351              : struct GTY(()) modref_summary_lto
     352              : {
     353              :   /* Load and stores in functions using types rather then alias sets.
     354              : 
     355              :      This is necessary to make the information streamable for LTO but is also
     356              :      more verbose and thus more likely to hit the limits.  */
     357              :   modref_records_lto *loads;
     358              :   modref_records_lto *stores;
     359              :   auto_vec<modref_access_node> GTY((skip)) kills;
     360              :   auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
     361              :   eaf_flags_t retslot_flags;
     362              :   eaf_flags_t static_chain_flags;
     363              :   unsigned writes_errno : 1;
     364              :   unsigned side_effects : 1;
     365              :   unsigned nondeterministic : 1;
     366              :   unsigned calls_interposable : 1;
     367              : 
     368              :   modref_summary_lto ();
     369              :   ~modref_summary_lto ();
     370              :   void dump (FILE *);
     371              :   bool useful_p (int ecf_flags, bool check_flags = true);
     372              : };
     373              : 
     374              : /* Summary for a single function which this pass produces.  */
     375              : 
     376       171231 : modref_summary_lto::modref_summary_lto ()
     377       171231 :   : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
     378       171231 :     writes_errno (false), side_effects (false), nondeterministic (false),
     379       171231 :     calls_interposable (false)
     380              : {
     381       171231 : }
     382              : 
     383       171225 : modref_summary_lto::~modref_summary_lto ()
     384              : {
     385       171225 :   if (loads)
     386       170568 :     ggc_delete (loads);
     387       171225 :   if (stores)
     388       170568 :     ggc_delete (stores);
     389       171225 : }
     390              : 
     391              : 
     392              : /* Return true if lto summary is potentially useful for optimization.
     393              :    If CHECK_FLAGS is false assume that arg_flags are useful.  */
     394              : 
     395              : bool
     396       927726 : modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
     397              : {
     398       927726 :   if (arg_flags.length () && !check_flags)
     399              :     return true;
     400       617931 :   if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
     401              :     return true;
     402       410684 :   arg_flags.release ();
     403       410684 :   if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
     404              :     return true;
     405       409988 :   if (check_flags
     406       409988 :       && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
     407              :     return true;
     408       409596 :   if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
     409        34242 :     return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
     410       392144 :   if (loads && !loads->every_base)
     411              :     return true;
     412              :   else
     413        75648 :     kills.release ();
     414        75648 :   if (ecf_flags & ECF_PURE)
     415         8317 :     return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
     416        70941 :   return stores && !stores->every_base;
     417              : }
     418              : 
     419              : /* Dump records TT to OUT.  */
     420              : 
     421              : static void
     422         1282 : dump_records (modref_records *tt, FILE *out)
     423              : {
     424         1282 :   if (tt->every_base)
     425              :     {
     426          209 :       fprintf (out, "    Every base\n");
     427          209 :       return;
     428              :     }
     429              :   size_t i;
     430              :   modref_base_node <alias_set_type> *n;
     431         1795 :   FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
     432              :     {
     433          722 :       fprintf (out, "      Base %i: alias set %i\n", (int)i, n->base);
     434          722 :       if (n->every_ref)
     435              :         {
     436            0 :           fprintf (out, "      Every ref\n");
     437            0 :           continue;
     438              :         }
     439              :       size_t j;
     440              :       modref_ref_node <alias_set_type> *r;
     441         2236 :       FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
     442              :         {
     443          792 :           fprintf (out, "        Ref %i: alias set %i\n", (int)j, r->ref);
     444          792 :           if (r->every_access)
     445              :             {
     446          539 :               fprintf (out, "          Every access\n");
     447          539 :               continue;
     448              :             }
     449              :           size_t k;
     450              :           modref_access_node *a;
     451         1320 :           FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
     452              :             {
     453          275 :               fprintf (out, "          access:");
     454          275 :               a->dump (out);
     455              :             }
     456              :         }
     457              :     }
     458              : }
     459              : 
     460              : /* Dump records TT to OUT.  */
     461              : 
     462              : static void
     463           74 : dump_lto_records (modref_records_lto *tt, FILE *out)
     464              : {
     465           74 :   if (tt->every_base)
     466              :     {
     467           10 :       fprintf (out, "    Every base\n");
     468           10 :       return;
     469              :     }
     470              :   size_t i;
     471              :   modref_base_node <tree> *n;
     472          124 :   FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
     473              :     {
     474           60 :       fprintf (out, "      Base %i:", (int)i);
     475           60 :       print_generic_expr (out, n->base);
     476           60 :       fprintf (out, " (alias set %i)\n",
     477           60 :                n->base ? get_alias_set (n->base) : 0);
     478           60 :       if (n->every_ref)
     479              :         {
     480            0 :           fprintf (out, "      Every ref\n");
     481            0 :           continue;
     482              :         }
     483              :       size_t j;
     484              :       modref_ref_node <tree> *r;
     485          180 :       FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
     486              :         {
     487           60 :           fprintf (out, "        Ref %i:", (int)j);
     488           60 :           print_generic_expr (out, r->ref);
     489           60 :           fprintf (out, " (alias set %i)\n",
     490           60 :                    r->ref ? get_alias_set (r->ref) : 0);
     491           60 :           if (r->every_access)
     492              :             {
     493           36 :               fprintf (out, "          Every access\n");
     494           36 :               continue;
     495              :             }
     496              :           size_t k;
     497              :           modref_access_node *a;
     498          108 :           FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
     499              :             {
     500           24 :               fprintf (out, "          access:");
     501           24 :               a->dump (out);
     502              :             }
     503              :         }
     504              :     }
     505              : }
     506              : 
     507              : /* Dump all escape points of NODE to OUT.  */
     508              : 
     509              : static void
     510          180 : dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
     511              : {
     512          180 :   int i = 0;
     513          180 :   if (!escape_summaries)
     514              :     return;
     515          121 :   for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
     516              :     {
     517           26 :       class escape_summary *sum = escape_summaries->get (e);
     518           26 :       if (sum)
     519              :         {
     520            0 :           fprintf (out, "%*sIndirect call %i in %s escapes:",
     521              :                    depth, "", i, node->dump_name ());
     522            0 :           sum->dump (out);
     523              :         }
     524           26 :       i++;
     525              :     }
     526          196 :   for (cgraph_edge *e = node->callees; e; e = e->next_callee)
     527              :     {
     528          101 :       if (!e->inline_failed)
     529            0 :         dump_modref_edge_summaries (out, e->callee, depth + 1);
     530          101 :       class escape_summary *sum = escape_summaries->get (e);
     531          101 :       if (sum)
     532              :         {
     533           11 :           fprintf (out, "%*sCall %s->%s escapes:", depth, "",
     534           11 :                    node->dump_name (), e->callee->dump_name ());
     535           11 :           sum->dump (out);
     536              :         }
     537          101 :       class fnspec_summary *fsum = fnspec_summaries->get (e);
     538          101 :       if (fsum)
     539              :         {
     540            2 :           fprintf (out, "%*sCall %s->%s fnspec: %s\n", depth, "",
     541            2 :                    node->dump_name (), e->callee->dump_name (),
     542              :                    fsum->fnspec);
     543              :         }
     544              :     }
     545              : }
     546              : 
     547              : /* Remove all call edge summaries associated with NODE.  */
     548              : 
     549              : static void
     550       486408 : remove_modref_edge_summaries (cgraph_node *node)
     551              : {
     552       486408 :   if (!escape_summaries)
     553              :     return;
     554       530342 :   for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
     555        43934 :     escape_summaries->remove (e);
     556      2491202 :   for (cgraph_edge *e = node->callees; e; e = e->next_callee)
     557              :     {
     558      2004794 :       if (!e->inline_failed)
     559       194513 :         remove_modref_edge_summaries (e->callee);
     560      2004794 :       escape_summaries->remove (e);
     561      2004794 :       fnspec_summaries->remove (e);
     562              :     }
     563              : }
     564              : 
     565              : /* Dump summary.  */
     566              : 
     567              : void
     568          641 : modref_summary::dump (FILE *out) const
     569              : {
     570          641 :   if (loads)
     571              :     {
     572          641 :       fprintf (out, "  loads:\n");
     573          641 :       dump_records (loads, out);
     574              :     }
     575          641 :   if (stores)
     576              :     {
     577          641 :       fprintf (out, "  stores:\n");
     578          641 :       dump_records (stores, out);
     579              :     }
     580          641 :   if (kills.length ())
     581              :     {
     582           26 :       fprintf (out, "  kills:\n");
     583          115 :       for (auto kill : kills)
     584              :         {
     585           37 :           fprintf (out, "    ");
     586           37 :           kill.dump (out);
     587              :         }
     588              :     }
     589          641 :   if (writes_errno)
     590            0 :     fprintf (out, "  Writes errno\n");
     591          641 :   if (side_effects)
     592          135 :     fprintf (out, "  Side effects\n");
     593          641 :   if (nondeterministic)
     594          445 :     fprintf (out, "  Nondeterministic\n");
     595          641 :   if (calls_interposable)
     596            0 :     fprintf (out, "  Calls interposable\n");
     597          641 :   if (global_memory_read)
     598          183 :     fprintf (out, "  Global memory read\n");
     599          641 :   if (global_memory_written)
     600          113 :     fprintf (out, "  Global memory written\n");
     601          641 :   if (try_dse)
     602          449 :     fprintf (out, "  Try dse\n");
     603          641 :   if (arg_flags.length ())
     604              :     {
     605         1234 :       for (unsigned int i = 0; i < arg_flags.length (); i++)
     606          876 :         if (arg_flags[i])
     607              :           {
     608          768 :             fprintf (out, "  parm %i flags:", i);
     609          768 :             dump_eaf_flags (out, arg_flags[i]);
     610              :           }
     611              :     }
     612          641 :   if (retslot_flags)
     613              :     {
     614            4 :       fprintf (out, "  Retslot flags:");
     615            4 :       dump_eaf_flags (out, retslot_flags);
     616              :     }
     617          641 :   if (static_chain_flags)
     618              :     {
     619            4 :       fprintf (out, "  Static chain flags:");
     620            4 :       dump_eaf_flags (out, static_chain_flags);
     621              :     }
     622          641 : }
     623              : 
     624              : /* Dump summary.  */
     625              : 
     626              : void
     627           37 : modref_summary_lto::dump (FILE *out)
     628              : {
     629           37 :   fprintf (out, "  loads:\n");
     630           37 :   dump_lto_records (loads, out);
     631           37 :   fprintf (out, "  stores:\n");
     632           37 :   dump_lto_records (stores, out);
     633           37 :   if (kills.length ())
     634              :     {
     635            6 :       fprintf (out, "  kills:\n");
     636           24 :       for (auto kill : kills)
     637              :         {
     638            6 :           fprintf (out, "    ");
     639            6 :           kill.dump (out);
     640              :         }
     641              :     }
     642           37 :   if (writes_errno)
     643            0 :     fprintf (out, "  Writes errno\n");
     644           37 :   if (side_effects)
     645            8 :     fprintf (out, "  Side effects\n");
     646           37 :   if (nondeterministic)
     647            2 :     fprintf (out, "  Nondeterministic\n");
     648           37 :   if (calls_interposable)
     649            0 :     fprintf (out, "  Calls interposable\n");
     650           37 :   if (arg_flags.length ())
     651              :     {
     652           72 :       for (unsigned int i = 0; i < arg_flags.length (); i++)
     653           54 :         if (arg_flags[i])
     654              :           {
     655           48 :             fprintf (out, "  parm %i flags:", i);
     656           48 :             dump_eaf_flags (out, arg_flags[i]);
     657              :           }
     658              :     }
     659           37 :   if (retslot_flags)
     660              :     {
     661            0 :       fprintf (out, "  Retslot flags:");
     662            0 :       dump_eaf_flags (out, retslot_flags);
     663              :     }
     664           37 :   if (static_chain_flags)
     665              :     {
     666            0 :       fprintf (out, "  Static chain flags:");
     667            0 :       dump_eaf_flags (out, static_chain_flags);
     668              :     }
     669           37 : }
     670              : 
     671              : /* Called after summary is produced and before it is used by local analysis.
     672              :    Can be called multiple times in case summary needs to update signature.
     673              :    FUN is decl of function summary is attached to.  */
     674              : void
     675      4333648 : modref_summary::finalize (tree fun)
     676              : {
     677      4333648 :   global_memory_read = !loads || loads->global_access_p ();
     678      4333648 :   global_memory_written = !stores || stores->global_access_p ();
     679              : 
     680              :   /* We can do DSE if we know function has no side effects and
     681              :      we can analyze all stores.  Disable dse if there are too many
     682              :      stores to try.  */
     683      4333648 :   if (side_effects || global_memory_written || writes_errno)
     684      2239099 :     try_dse = false;
     685              :   else
     686              :     {
     687      2094549 :       try_dse = true;
     688      2094549 :       size_t i, j, k;
     689      2094549 :       int num_tests = 0, max_tests
     690      2094549 :         = opt_for_fn (fun, param_modref_max_tests);
     691      2094549 :       modref_base_node <alias_set_type> *base_node;
     692      2094549 :       modref_ref_node <alias_set_type> *ref_node;
     693      2094549 :       modref_access_node *access_node;
     694      2680334 :       FOR_EACH_VEC_SAFE_ELT (stores->bases, i, base_node)
     695              :         {
     696       630280 :           if (base_node->every_ref)
     697              :             {
     698            0 :               try_dse = false;
     699            0 :               break;
     700              :             }
     701      1365256 :           FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
     702              :             {
     703       779471 :               if (base_node->every_ref)
     704              :                 {
     705              :                   try_dse = false;
     706              :                   break;
     707              :                 }
     708      1591221 :               FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
     709       856245 :                 if (num_tests++ > max_tests
     710       856245 :                     || !access_node->parm_offset_known)
     711              :                   {
     712        44495 :                     try_dse = false;
     713        44495 :                     break;
     714              :                   }
     715       779471 :               if (!try_dse)
     716              :                 break;
     717              :             }
     718       630280 :           if (!try_dse)
     719              :             break;
     720              :         }
     721              :     }
     722      4333648 :   if (loads->every_base)
     723      1253728 :     load_accesses = 1;
     724              :   else
     725              :     {
     726      3079920 :       load_accesses = 0;
     727      8872821 :       for (auto base_node : loads->bases)
     728              :         {
     729      2389353 :           if (base_node->every_ref)
     730         5086 :             load_accesses++;
     731              :           else
     732      9852175 :             for (auto ref_node : base_node->refs)
     733      2699374 :               if (ref_node->every_access)
     734       946653 :                 load_accesses++;
     735              :               else
     736      1752721 :                 load_accesses += ref_node->accesses->length ();
     737              :         }
     738              :     }
     739      4333648 : }
     740              : 
     741              : /* Get function summary for FUNC if it exists, return NULL otherwise.  */
     742              : 
     743              : modref_summary *
     744    506500050 : get_modref_function_summary (cgraph_node *func)
     745              : {
     746              :   /* Avoid creation of the summary too early (e.g. when front-end calls us).  */
     747    506500050 :   if (!optimization_summaries)
     748              :     return NULL;
     749              : 
     750              :   /* A single function body may be represented by multiple symbols with
     751              :      different visibility.  For example, if FUNC is an interposable alias,
     752              :      we don't want to return anything, even if we have summary for the target
     753              :      function.  */
     754    493440416 :   enum availability avail;
     755    493440416 :   func = func->ultimate_alias_target
     756    986667909 :                  (&avail, current_function_decl ?
     757    493227493 :                           cgraph_node::get (current_function_decl) : NULL);
     758    493440416 :   if (avail <= AVAIL_INTERPOSABLE)
     759              :     return NULL;
     760              : 
     761    130463643 :   modref_summary *r = optimization_summaries->get (func);
     762    130463643 :   return r;
     763              : }
     764              : 
     765              : /* Get function summary for CALL if it exists, return NULL otherwise.
     766              :    If non-null set interposed to indicate whether function may not
     767              :    bind to current def.  In this case sometimes loads from function
     768              :    needs to be ignored.  */
     769              : 
     770              : modref_summary *
     771     38087201 : get_modref_function_summary (gcall *call, bool *interposed)
     772              : {
     773     38087201 :   tree callee = gimple_call_fndecl (call);
     774     38087201 :   if (!callee)
     775              :     return NULL;
     776     36281507 :   struct cgraph_node *node = cgraph_node::get (callee);
     777     36281507 :   if (!node)
     778              :     return NULL;
     779     36210974 :   modref_summary *r = get_modref_function_summary (node);
     780     36210974 :   if (interposed && r)
     781      6921960 :     *interposed = r->calls_interposable
     782      6921960 :                   || !node->binds_to_current_def_p ();
     783              :   return r;
     784              : }
     785              : 
     786              : 
     787              : namespace {
     788              : 
     789              : /* Return true if ECF flags says that nondeterminism can be ignored.  */
     790              : 
     791              : static bool
     792      8147301 : ignore_nondeterminism_p (tree caller, int flags, tree callee_fntype)
     793              : {
     794      8147301 :   int caller_flags = flags_from_decl_or_type (caller);
     795      8147301 :   if ((flags | caller_flags) & (ECF_CONST | ECF_PURE))
     796              :     return true;
     797      7829931 :   if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
     798      7829931 :       || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
     799              :     return true;
     800              :   /* C language defines unsequenced and reproducible functions
     801              :      to be deterministic.  */
     802      7218572 :   if (lookup_attribute ("unsequenced", TYPE_ATTRIBUTES (TREE_TYPE (caller)))
     803     14437144 :       || lookup_attribute ("reproducible",
     804      7218572 :                            TYPE_ATTRIBUTES (TREE_TYPE (caller))))
     805            0 :     return true;
     806      7218572 :   if (callee_fntype
     807      7218572 :       && (lookup_attribute ("unsequenced", TYPE_ATTRIBUTES (callee_fntype))
     808      5902767 :           || lookup_attribute ("reproducible",
     809      5902767 :                                TYPE_ATTRIBUTES (callee_fntype))))
     810            0 :     return true;
     811              :   return false;
     812              : }
     813              : 
     814              : /* Return true if ECF flags says that return value can be ignored.  */
     815              : 
     816              : static bool
     817      5861902 : ignore_retval_p (tree caller, int flags)
     818              : {
     819      5861902 :   if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
     820      5861902 :       || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
     821        42779 :     return true;
     822              :   return false;
     823              : }
     824              : 
     825              : /* Return true if ECF flags says that stores can be ignored.  */
     826              : 
     827              : static bool
     828     27291502 : ignore_stores_p (tree caller, int flags)
     829              : {
     830     27291502 :   if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
     831              :     return true;
     832     24119288 :   if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
     833     24119288 :       || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
     834      1645013 :     return true;
     835              :   return false;
     836              : }
     837              : 
     838              : /* Determine parm_map for PTR which is supposed to be a pointer.  */
     839              : 
     840              : modref_parm_map
     841     15664404 : parm_map_for_ptr (tree op)
     842              : {
     843     15664404 :   bool offset_known;
     844     15664404 :   poly_int64 offset;
     845     15664404 :   struct modref_parm_map parm_map;
     846     15664404 :   gcall *call;
     847              : 
     848     15664404 :   parm_map.parm_offset_known = false;
     849     15664404 :   parm_map.parm_offset = 0;
     850              : 
     851     15664404 :   offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
     852     15664404 :   if (TREE_CODE (op) == SSA_NAME
     853     10362580 :       && SSA_NAME_IS_DEFAULT_DEF (op)
     854     23909273 :       && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
     855              :     {
     856      8228309 :       int index = 0;
     857              : 
     858      8228309 :       if (cfun->static_chain_decl
     859      8228309 :           && op == ssa_default_def (cfun, cfun->static_chain_decl))
     860              :         index = MODREF_STATIC_CHAIN_PARM;
     861              :       else
     862      8150504 :         for (tree t = DECL_ARGUMENTS (current_function_decl);
     863     13392579 :              t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
     864      5242075 :           index++;
     865      8228309 :       parm_map.parm_index = index;
     866      8228309 :       parm_map.parm_offset_known = offset_known;
     867      8228309 :       parm_map.parm_offset = offset;
     868              :     }
     869      7436095 :   else if (points_to_local_or_readonly_memory_p (op))
     870              :     parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM;
     871              :   /* Memory allocated in the function is not visible to caller before the
     872              :      call and thus we do not need to record it as load/stores/kills.  */
     873      6634005 :   else if (TREE_CODE (op) == SSA_NAME
     874      2039853 :            && (call = dyn_cast<gcall *>(SSA_NAME_DEF_STMT (op))) != NULL
     875      7401909 :            && gimple_call_flags (call) & ECF_MALLOC)
     876              :     parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM;
     877              :   else
     878              :     parm_map.parm_index = MODREF_UNKNOWN_PARM;
     879     15664404 :   return parm_map;
     880              : }
     881              : 
     882              : /* Return true if ARG with EAF flags FLAGS can not make any caller's parameter
     883              :    used (if LOAD is true we check loads, otherwise stores).  */
     884              : 
     885              : static bool
     886     10911123 : verify_arg (tree arg, int flags, bool load)
     887              : {
     888     10911123 :   if (flags & EAF_UNUSED)
     889              :     return true;
     890     10668740 :   if (load && (flags & EAF_NO_DIRECT_READ))
     891              :     return true;
     892              :   if (!load
     893      4614493 :       && (flags & (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER))
     894              :           == (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER))
     895              :     return true;
     896      9750723 :   if (is_gimple_constant (arg))
     897              :     return true;
     898      7569395 :   if (DECL_P (arg) && TREE_READONLY (arg))
     899              :     return true;
     900      7569148 :   if (TREE_CODE (arg) == ADDR_EXPR)
     901              :     {
     902      3195026 :       tree t = get_base_address (TREE_OPERAND (arg, 0));
     903      7131573 :       if (is_gimple_constant (t))
     904              :         return true;
     905      2258460 :       if (DECL_P (t)
     906      2258460 :           && (TREE_READONLY (t) || TREE_CODE (t) == FUNCTION_DECL))
     907              :         return true;
     908              :     }
     909              :   return false;
     910              : }
     911              : 
     912              : /* Return true if STMT may access memory that is pointed to by parameters
     913              :    of caller and which is not seen as an escape by PTA.
     914              :    CALLEE_ECF_FLAGS are ECF flags of callee.  If LOAD is true then by access
     915              :    we mean load, otherwise we mean store.  */
     916              : 
     917              : static bool
     918      8936108 : may_access_nonescaping_parm_p (gcall *call, int callee_ecf_flags, bool load)
     919              : {
     920      8936108 :   int implicit_flags = 0;
     921              : 
     922      8936108 :   if (ignore_stores_p (current_function_decl, callee_ecf_flags))
     923       678982 :     implicit_flags |= ignore_stores_eaf_flags;
     924      8936108 :   if (callee_ecf_flags & ECF_PURE)
     925       263759 :     implicit_flags |= implicit_pure_eaf_flags;
     926      8936108 :   if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
     927            0 :     implicit_flags |= implicit_const_eaf_flags;
     928      8936108 :   if (gimple_call_chain (call)
     929      8975304 :       && !verify_arg (gimple_call_chain (call),
     930        39196 :                       gimple_call_static_chain_flags (call) | implicit_flags,
     931              :                       load))
     932              :     return true;
     933     13770025 :   for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
     934     10871927 :     if (!verify_arg (gimple_call_arg (call, i),
     935     10871927 :                      gimple_call_arg_flags (call, i) | implicit_flags,
     936              :                      load))
     937              :       return true;
     938              :   return false;
     939              : }
     940              : 
     941              : 
     942              : /* Analyze memory accesses (loads, stores and kills) performed
     943              :    by the function.  Set also side_effects, calls_interposable
     944              :    and nondeterminism flags.  */
     945              : 
     946      9499270 : class modref_access_analysis
     947              : {
     948              : public:
     949      4749635 :   modref_access_analysis (bool ipa, modref_summary *summary,
     950              :                           modref_summary_lto *summary_lto)
     951      4749635 :   : m_summary (summary), m_summary_lto (summary_lto), m_ipa (ipa)
     952              :   {
     953              :   }
     954              :   void analyze ();
     955              : private:
     956              :   bool set_side_effects ();
     957              :   bool set_nondeterministic ();
     958              :   static modref_access_node get_access (ao_ref *ref);
     959              :   static void record_access (modref_records *, ao_ref *, modref_access_node &);
     960              :   static void record_access_lto (modref_records_lto *, ao_ref *,
     961              :                                  modref_access_node &a);
     962              :   bool record_access_p (tree);
     963              :   bool record_unknown_load ();
     964              :   bool record_unknown_store ();
     965              :   bool record_global_memory_load ();
     966              :   bool record_global_memory_store ();
     967              :   bool merge_call_side_effects (gimple *, modref_summary *,
     968              :                                 cgraph_node *, bool);
     969              :   modref_access_node get_access_for_fnspec (gcall *, attr_fnspec &,
     970              :                                             unsigned int, modref_parm_map &);
     971              :   void process_fnspec (gcall *);
     972              :   void analyze_call (gcall *);
     973              :   static bool analyze_load (gimple *, tree, tree, void *);
     974              :   static bool analyze_store (gimple *, tree, tree, void *);
     975              :   void analyze_stmt (gimple *, bool);
     976              :   void propagate ();
     977              : 
     978              :   /* Summary being computed.
     979              :      We work either with m_summary or m_summary_lto.  Never on both.  */
     980              :   modref_summary *m_summary;
     981              :   modref_summary_lto *m_summary_lto;
     982              :   /* Recursive calls needs simplistic dataflow after analysis finished.
     983              :      Collect all calls into this vector during analysis and later process
     984              :      them in propagate.  */
     985              :   auto_vec <gimple *, 32> m_recursive_calls;
     986              :   /* ECF flags of function being analyzed.  */
     987              :   int m_ecf_flags;
     988              :   /* True if IPA propagation will be done later.  */
     989              :   bool m_ipa;
     990              :   /* Set true if statement currently analyze is known to be
     991              :      executed each time function is called.  */
     992              :   bool m_always_executed;
     993              : };
     994              : 
     995              : /* Set side_effects flag and return if something changed.  */
     996              : 
     997              : bool
     998      6813154 : modref_access_analysis::set_side_effects ()
     999              : {
    1000      6813154 :   bool changed = false;
    1001              : 
    1002      6813154 :   if (m_summary && !m_summary->side_effects)
    1003              :     {
    1004      1573747 :       m_summary->side_effects = true;
    1005      1573747 :       changed = true;
    1006              :     }
    1007      6813154 :   if (m_summary_lto && !m_summary_lto->side_effects)
    1008              :     {
    1009         1538 :       m_summary_lto->side_effects = true;
    1010         1538 :       changed = true;
    1011              :     }
    1012      6813154 :   return changed;
    1013              : }
    1014              : 
    1015              : /* Set nondeterministic flag and return if something changed.  */
    1016              : 
    1017              : bool
    1018      4218548 : modref_access_analysis::set_nondeterministic ()
    1019              : {
    1020      4218548 :   bool changed = false;
    1021              : 
    1022      4218548 :   if (m_summary && !m_summary->nondeterministic)
    1023              :     {
    1024      1376313 :       m_summary->side_effects = m_summary->nondeterministic = true;
    1025      1376313 :       changed = true;
    1026              :     }
    1027      4218548 :   if (m_summary_lto && !m_summary_lto->nondeterministic)
    1028              :     {
    1029         6114 :       m_summary_lto->side_effects = m_summary_lto->nondeterministic = true;
    1030         6114 :       changed = true;
    1031              :     }
    1032      4218548 :   return changed;
    1033              : }
    1034              : 
    1035              : /* Construct modref_access_node from REF.  */
    1036              : 
    1037              : modref_access_node
    1038     13444842 : modref_access_analysis::get_access (ao_ref *ref)
    1039              : {
    1040     13444842 :   tree base;
    1041              : 
    1042     13444842 :   base = ao_ref_base (ref);
    1043     13444842 :   modref_access_node a = {ref->offset, ref->size, ref->max_size,
    1044     13444842 :                           0, MODREF_UNKNOWN_PARM, false, 0};
    1045     13444842 :   if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
    1046              :     {
    1047     10896936 :       tree memref = base;
    1048     10896936 :       modref_parm_map m = parm_map_for_ptr (TREE_OPERAND (base, 0));
    1049              : 
    1050     10896936 :       a.parm_index = m.parm_index;
    1051     10896936 :       if (a.parm_index != MODREF_UNKNOWN_PARM && TREE_CODE (memref) == MEM_REF)
    1052              :         {
    1053      7144755 :           a.parm_offset_known
    1054      7144755 :              = wi::to_poly_wide (TREE_OPERAND
    1055      7144755 :                                      (memref, 1)).to_shwi (&a.parm_offset);
    1056      7144755 :           if (a.parm_offset_known && m.parm_offset_known)
    1057     10896936 :             a.parm_offset += m.parm_offset;
    1058              :           else
    1059       570315 :             a.parm_offset_known = false;
    1060              :         }
    1061              :     }
    1062              :   else
    1063              :     a.parm_index = MODREF_UNKNOWN_PARM;
    1064     13444842 :   return a;
    1065              : }
    1066              : 
    1067              : /* Record access into the modref_records data structure.  */
    1068              : 
    1069              : void
    1070     13086427 : modref_access_analysis::record_access (modref_records *tt,
    1071              :                                        ao_ref *ref,
    1072              :                                        modref_access_node &a)
    1073              : {
    1074     13086427 :   alias_set_type base_set = !flag_strict_aliasing
    1075     13086427 :                             || !flag_ipa_strict_aliasing ? 0
    1076     10477478 :                             : ao_ref_base_alias_set (ref);
    1077     13086427 :   alias_set_type ref_set = !flag_strict_aliasing
    1078     13086427 :                            || !flag_ipa_strict_aliasing ? 0
    1079     10477478 :                             : (ao_ref_alias_set (ref));
    1080     13086427 :   if (dump_file)
    1081              :     {
    1082          246 :        fprintf (dump_file, "   - Recording base_set=%i ref_set=%i ",
    1083              :                 base_set, ref_set);
    1084          246 :        a.dump (dump_file);
    1085              :     }
    1086     13086427 :   tt->insert (current_function_decl, base_set, ref_set, a, false);
    1087     13086427 : }
    1088              : 
    1089              : /* IPA version of record_access_tree.  */
    1090              : 
    1091              : void
    1092       169884 : modref_access_analysis::record_access_lto (modref_records_lto *tt, ao_ref *ref,
    1093              :                                            modref_access_node &a)
    1094              : {
    1095              :   /* get_alias_set sometimes use different type to compute the alias set
    1096              :      than TREE_TYPE (base).  Do same adjustments.  */
    1097       169884 :   tree base_type = NULL_TREE, ref_type = NULL_TREE;
    1098       169884 :   if (flag_strict_aliasing && flag_ipa_strict_aliasing)
    1099              :     {
    1100       169353 :       tree base;
    1101              : 
    1102       169353 :       base = ref->ref;
    1103       229177 :       while (handled_component_p (base))
    1104        59824 :         base = TREE_OPERAND (base, 0);
    1105              : 
    1106       169353 :       base_type = reference_alias_ptr_type_1 (&base);
    1107              : 
    1108       169353 :       if (!base_type)
    1109       167571 :         base_type = TREE_TYPE (base);
    1110              :       else
    1111         2914 :         base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
    1112         1782 :                     ? NULL_TREE : TREE_TYPE (base_type);
    1113              : 
    1114       169353 :       tree ref_expr = ref->ref;
    1115       169353 :       ref_type = reference_alias_ptr_type_1 (&ref_expr);
    1116              : 
    1117       169353 :       if (!ref_type)
    1118       167665 :         ref_type = TREE_TYPE (ref_expr);
    1119              :       else
    1120         2726 :         ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
    1121         1688 :                    ? NULL_TREE : TREE_TYPE (ref_type);
    1122              : 
    1123              :       /* Sanity check that we are in sync with what get_alias_set does.  */
    1124       169353 :       gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
    1125              :                            || get_alias_set (base_type)
    1126              :                               == ao_ref_base_alias_set (ref));
    1127       169353 :       gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
    1128              :                            || get_alias_set (ref_type)
    1129              :                               == ao_ref_alias_set (ref));
    1130              : 
    1131              :       /* Do not bother to record types that have no meaningful alias set.
    1132              :          Also skip variably modified types since these go to local streams.  */
    1133       169353 :       if (base_type && (!get_alias_set (base_type)
    1134       157581 :                         || variably_modified_type_p (base_type, NULL_TREE)))
    1135              :         base_type = NULL_TREE;
    1136       169353 :       if (ref_type && (!get_alias_set (ref_type)
    1137       160025 :                        || variably_modified_type_p (ref_type, NULL_TREE)))
    1138              :         ref_type = NULL_TREE;
    1139              :     }
    1140       169884 :   if (dump_file)
    1141              :     {
    1142           28 :       fprintf (dump_file, "   - Recording base type:");
    1143           28 :       print_generic_expr (dump_file, base_type);
    1144           56 :       fprintf (dump_file, " (alias set %i) ref type:",
    1145           28 :                base_type ? get_alias_set (base_type) : 0);
    1146           28 :       print_generic_expr (dump_file, ref_type);
    1147           56 :       fprintf (dump_file, " (alias set %i) ",
    1148           28 :                ref_type ? get_alias_set (ref_type) : 0);
    1149           28 :        a.dump (dump_file);
    1150              :     }
    1151              : 
    1152       169884 :   tt->insert (current_function_decl, base_type, ref_type, a, false);
    1153       169884 : }
    1154              : 
    1155              : /* Returns true if and only if we should store the access to EXPR.
    1156              :    Some accesses, e.g. loads from automatic variables, are not interesting.  */
    1157              : 
    1158              : bool
    1159     26772384 : modref_access_analysis::record_access_p (tree expr)
    1160              : {
    1161     26772384 :   if (TREE_THIS_VOLATILE (expr)
    1162     26772384 :       && !ignore_nondeterminism_p (current_function_decl, 0, NULL))
    1163              :     {
    1164       903335 :       if (dump_file)
    1165            0 :         fprintf (dump_file, " (volatile; marking nondeterministic) ");
    1166       903335 :       set_nondeterministic ();
    1167              :     }
    1168     26772384 :   if (cfun->can_throw_non_call_exceptions
    1169     26772384 :       && tree_could_throw_p (expr))
    1170              :     {
    1171      1597426 :       if (dump_file)
    1172            0 :         fprintf (dump_file, " (can throw; marking side effects) ");
    1173      1597426 :       set_side_effects ();
    1174              :     }
    1175              : 
    1176     26772384 :   if (refs_local_or_readonly_memory_p (expr))
    1177              :     {
    1178     13327542 :       if (dump_file)
    1179           57 :         fprintf (dump_file, "   - Read-only or local, ignoring.\n");
    1180     13327542 :       return false;
    1181              :     }
    1182              :   return true;
    1183              : }
    1184              : 
    1185              : /* Collapse loads and return true if something changed.  */
    1186              : 
    1187              : bool
    1188      2367309 : modref_access_analysis::record_unknown_load ()
    1189              : {
    1190      2367309 :   bool changed = false;
    1191              : 
    1192      2367309 :   if (m_summary && !m_summary->loads->every_base)
    1193              :     {
    1194       946491 :       m_summary->loads->collapse ();
    1195       946491 :       changed = true;
    1196              :     }
    1197      2367309 :   if (m_summary_lto && !m_summary_lto->loads->every_base)
    1198              :     {
    1199         1829 :       m_summary_lto->loads->collapse ();
    1200         1829 :       changed = true;
    1201              :     }
    1202      2367309 :   return changed;
    1203              : }
    1204              : 
    1205              : /* Collapse loads and return true if something changed.  */
    1206              : 
    1207              : bool
    1208      2100636 : modref_access_analysis::record_unknown_store ()
    1209              : {
    1210      2100636 :   bool changed = false;
    1211              : 
    1212      2100636 :   if (m_summary && !m_summary->stores->every_base)
    1213              :     {
    1214       998341 :       m_summary->stores->collapse ();
    1215       998341 :       changed = true;
    1216              :     }
    1217      2100636 :   if (m_summary_lto && !m_summary_lto->stores->every_base)
    1218              :     {
    1219         1733 :       m_summary_lto->stores->collapse ();
    1220         1733 :       changed = true;
    1221              :     }
    1222      2100636 :   return changed;
    1223              : }
    1224              : 
    1225              : /* Record unknown load from global memory.  */
    1226              : 
    1227              : bool
    1228      1188764 : modref_access_analysis::record_global_memory_load ()
    1229              : {
    1230      1188764 :   bool changed = false;
    1231      1188764 :   modref_access_node a = {0, -1, -1,
    1232              :                           0, MODREF_GLOBAL_MEMORY_PARM, false, 0};
    1233              : 
    1234      1188764 :   if (m_summary && !m_summary->loads->every_base)
    1235       830806 :     changed |= m_summary->loads->insert (current_function_decl, 0, 0, a, false);
    1236      1188764 :   if (m_summary_lto && !m_summary_lto->loads->every_base)
    1237          475 :     changed |= m_summary_lto->loads->insert (current_function_decl,
    1238              :                                              0, 0, a, false);
    1239      1188764 :   return changed;
    1240              : }
    1241              : 
    1242              : /* Record unknown store from global memory.  */
    1243              : 
    1244              : bool
    1245       792467 : modref_access_analysis::record_global_memory_store ()
    1246              : {
    1247       792467 :   bool changed = false;
    1248       792467 :   modref_access_node a = {0, -1, -1,
    1249              :                           0, MODREF_GLOBAL_MEMORY_PARM, false, 0};
    1250              : 
    1251       792467 :   if (m_summary && !m_summary->stores->every_base)
    1252       598726 :     changed |= m_summary->stores->insert (current_function_decl,
    1253              :                                           0, 0, a, false);
    1254       792467 :   if (m_summary_lto && !m_summary_lto->stores->every_base)
    1255          352 :     changed |= m_summary_lto->stores->insert (current_function_decl,
    1256              :                                              0, 0, a, false);
    1257       792467 :   return changed;
    1258              : }
    1259              : 
    1260              : /* Merge side effects of call STMT to function with CALLEE_SUMMARY.
    1261              :    Return true if something changed.
    1262              :    If IGNORE_STORES is true, do not merge stores.
    1263              :    If RECORD_ADJUSTMENTS is true cap number of adjustments to
    1264              :    a given access to make dataflow finite.  */
    1265              : 
    1266              : bool
    1267      1565881 : modref_access_analysis::merge_call_side_effects
    1268              :          (gimple *stmt, modref_summary *callee_summary,
    1269              :           cgraph_node *callee_node, bool record_adjustments)
    1270              : {
    1271      1565881 :   gcall *call = as_a <gcall *> (stmt);
    1272      1565881 :   int flags = gimple_call_flags (call);
    1273              : 
    1274              :   /* Nothing to do for non-looping cont functions.  */
    1275      1565881 :   if ((flags & ECF_CONST)
    1276          456 :       && !(flags & ECF_LOOPING_CONST_OR_PURE))
    1277              :     return false;
    1278              : 
    1279      1565881 :   bool changed = false;
    1280              : 
    1281      1565881 :   if (dump_file)
    1282           13 :     fprintf (dump_file, " - Merging side effects of %s\n",
    1283              :              callee_node->dump_name ());
    1284              : 
    1285              :   /* Merge side effects and non-determinism.
    1286              :      PURE/CONST flags makes functions deterministic and if there is
    1287              :      no LOOPING_CONST_OR_PURE they also have no side effects.  */
    1288      1565881 :   if (!(flags & (ECF_CONST | ECF_PURE))
    1289       146633 :       || (flags & ECF_LOOPING_CONST_OR_PURE))
    1290              :     {
    1291      1464060 :       if (!m_summary->side_effects && callee_summary->side_effects)
    1292              :         {
    1293       396081 :           if (dump_file)
    1294            0 :             fprintf (dump_file, " - merging side effects.\n");
    1295       396081 :           m_summary->side_effects = true;
    1296       396081 :           changed = true;
    1297              :         }
    1298       938641 :       if (!m_summary->nondeterministic && callee_summary->nondeterministic
    1299      1850762 :           && !ignore_nondeterminism_p (current_function_decl, flags,
    1300              :                                        gimple_call_fntype (call)))
    1301              :         {
    1302       385121 :           if (dump_file)
    1303            0 :             fprintf (dump_file, " - merging nondeterministic.\n");
    1304       385121 :           m_summary->nondeterministic = true;
    1305       385121 :           changed = true;
    1306              :         }
    1307              :      }
    1308              : 
    1309              :   /* For const functions we are done.  */
    1310      1565881 :   if (flags & (ECF_CONST | ECF_NOVOPS))
    1311              :     return changed;
    1312              : 
    1313              :   /* Merge calls_interposable flags.  */
    1314      1565425 :   if (!m_summary->calls_interposable && callee_summary->calls_interposable)
    1315              :     {
    1316       197619 :       if (dump_file)
    1317            0 :         fprintf (dump_file, " - merging calls interposable.\n");
    1318       197619 :       m_summary->calls_interposable = true;
    1319       197619 :       changed = true;
    1320              :     }
    1321              : 
    1322      1565425 :   if (!callee_node->binds_to_current_def_p () && !m_summary->calls_interposable)
    1323              :     {
    1324       162577 :       if (dump_file)
    1325            0 :         fprintf (dump_file, " - May be interposed.\n");
    1326       162577 :       m_summary->calls_interposable = true;
    1327       162577 :       changed = true;
    1328              :     }
    1329              : 
    1330              :   /* Now merge the actual load, store and kill vectors.  For this we need
    1331              :      to compute map translating new parameters to old.  */
    1332      1565425 :   if (dump_file)
    1333           13 :     fprintf (dump_file, "   Parm map:");
    1334              : 
    1335      1565425 :   auto_vec <modref_parm_map, 32> parm_map;
    1336      1565425 :   parm_map.safe_grow_cleared (gimple_call_num_args (call), true);
    1337      5429143 :   for (unsigned i = 0; i < gimple_call_num_args (call); i++)
    1338              :     {
    1339      3863718 :       parm_map[i] = parm_map_for_ptr (gimple_call_arg (call, i));
    1340      3863718 :       if (dump_file)
    1341              :         {
    1342           23 :           fprintf (dump_file, " %i", parm_map[i].parm_index);
    1343           23 :           if (parm_map[i].parm_offset_known)
    1344              :             {
    1345           12 :               fprintf (dump_file, " offset:");
    1346           12 :               print_dec ((poly_int64)parm_map[i].parm_offset,
    1347              :                          dump_file, SIGNED);
    1348              :             }
    1349              :         }
    1350              :     }
    1351              : 
    1352      1565425 :   modref_parm_map chain_map;
    1353      1565425 :   if (gimple_call_chain (call))
    1354              :     {
    1355         2429 :       chain_map = parm_map_for_ptr (gimple_call_chain (call));
    1356         2429 :       if (dump_file)
    1357              :         {
    1358            0 :           fprintf (dump_file, "static chain %i", chain_map.parm_index);
    1359            0 :           if (chain_map.parm_offset_known)
    1360              :             {
    1361            0 :               fprintf (dump_file, " offset:");
    1362            0 :               print_dec ((poly_int64)chain_map.parm_offset,
    1363              :                          dump_file, SIGNED);
    1364              :             }
    1365              :         }
    1366              :     }
    1367      1565425 :   if (dump_file)
    1368           13 :     fprintf (dump_file, "\n");
    1369              : 
    1370              :   /* Kills can me merged in only if we know the function is going to be
    1371              :      always executed.  */
    1372      1565425 :   if (m_always_executed
    1373       633389 :       && callee_summary->kills.length ()
    1374      1642408 :       && (!cfun->can_throw_non_call_exceptions
    1375           48 :           || !stmt_could_throw_p (cfun, call)))
    1376              :     {
    1377              :       /* Watch for self recursive updates.  */
    1378        76976 :       auto_vec<modref_access_node, 32> saved_kills;
    1379              : 
    1380       153952 :       saved_kills.reserve_exact (callee_summary->kills.length ());
    1381        76976 :       saved_kills.splice (callee_summary->kills);
    1382       329096 :       for (auto kill : saved_kills)
    1383              :         {
    1384       196336 :           if (kill.parm_index >= (int)parm_map.length ())
    1385        43278 :             continue;
    1386        98168 :           modref_parm_map &m
    1387              :                   = kill.parm_index == MODREF_STATIC_CHAIN_PARM
    1388        98168 :                     ? chain_map
    1389        97782 :                     : parm_map[kill.parm_index];
    1390       141446 :           if (m.parm_index == MODREF_LOCAL_MEMORY_PARM
    1391        98168 :               || m.parm_index == MODREF_UNKNOWN_PARM
    1392              :               || m.parm_index == MODREF_RETSLOT_PARM
    1393        54979 :               || !m.parm_offset_known)
    1394        43278 :             continue;
    1395        54890 :           modref_access_node n = kill;
    1396        54890 :           n.parm_index = m.parm_index;
    1397        54890 :           n.parm_offset += m.parm_offset;
    1398        54890 :           if (modref_access_node::insert_kill (m_summary->kills, n,
    1399              :                                                record_adjustments))
    1400        45226 :             changed = true;
    1401              :         }
    1402        76976 :     }
    1403              : 
    1404              :   /* Merge in loads.  */
    1405      4696275 :   changed |= m_summary->loads->merge (current_function_decl,
    1406      1565425 :                                       callee_summary->loads,
    1407              :                                       &parm_map, &chain_map,
    1408              :                                       record_adjustments,
    1409      1565425 :                                       !may_access_nonescaping_parm_p
    1410      1565425 :                                          (call, flags, true));
    1411              :   /* Merge in stores.  */
    1412      1565425 :   if (!ignore_stores_p (current_function_decl, flags))
    1413              :     {
    1414      4256352 :       changed |= m_summary->stores->merge (current_function_decl,
    1415      1418784 :                                            callee_summary->stores,
    1416              :                                            &parm_map, &chain_map,
    1417              :                                            record_adjustments,
    1418      1418784 :                                            !may_access_nonescaping_parm_p
    1419      1418784 :                                                (call, flags, false));
    1420      1418784 :       if (!m_summary->writes_errno
    1421      1177380 :           && callee_summary->writes_errno)
    1422              :         {
    1423       155503 :           m_summary->writes_errno = true;
    1424       155503 :           changed = true;
    1425              :         }
    1426              :     }
    1427      1565425 :   return changed;
    1428      1565425 : }
    1429              : 
    1430              : /* Return access mode for argument I of call STMT with FNSPEC.  */
    1431              : 
    1432              : modref_access_node
    1433       300694 : modref_access_analysis::get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
    1434              :                                                unsigned int i,
    1435              :                                                modref_parm_map &map)
    1436              : {
    1437       300694 :   tree size = NULL_TREE;
    1438       300694 :   unsigned int size_arg;
    1439              : 
    1440       300694 :   if (!fnspec.arg_specified_p (i))
    1441              :     ;
    1442       300694 :   else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
    1443        67625 :     size = gimple_call_arg (call, size_arg);
    1444       233069 :   else if (fnspec.arg_access_size_given_by_type_p (i))
    1445              :     {
    1446           34 :       tree callee = gimple_call_fndecl (call);
    1447           34 :       tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
    1448              : 
    1449           84 :       for (unsigned int p = 0; p < i; p++)
    1450           50 :         t = TREE_CHAIN (t);
    1451           34 :       size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
    1452              :     }
    1453       300694 :   modref_access_node a = {0, -1, -1,
    1454       300694 :                           map.parm_offset, map.parm_index,
    1455       300694 :                           map.parm_offset_known, 0};
    1456       300694 :   poly_int64 size_hwi;
    1457       300694 :   if (size
    1458        67659 :       && poly_int_tree_p (size, &size_hwi)
    1459       317783 :       && coeffs_in_range_p (size_hwi, 0,
    1460              :                             HOST_WIDE_INT_MAX / BITS_PER_UNIT))
    1461              :     {
    1462        16867 :       a.size = -1;
    1463        16867 :       a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
    1464              :     }
    1465       300694 :   return a;
    1466              : }
    1467              : 
    1468              : /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
    1469              :    If IGNORE_STORES is true ignore them.
    1470              :    Return false if no useful summary can be produced.   */
    1471              : 
    1472              : void
    1473      4001193 : modref_access_analysis::process_fnspec (gcall *call)
    1474              : {
    1475      4001193 :   int flags = gimple_call_flags (call);
    1476              : 
    1477              :   /* PURE/CONST flags makes functions deterministic and if there is
    1478              :      no LOOPING_CONST_OR_PURE they also have no side effects.  */
    1479      4001193 :   if (!(flags & (ECF_CONST | ECF_PURE))
    1480       380777 :       || (flags & ECF_LOOPING_CONST_OR_PURE)
    1481      4369665 :       || (cfun->can_throw_non_call_exceptions
    1482        35718 :           && stmt_could_throw_p (cfun, call)))
    1483              :     {
    1484      3633303 :       set_side_effects ();
    1485      7094846 :       if (!ignore_nondeterminism_p (current_function_decl, flags,
    1486              :                                     gimple_call_fntype (call)))
    1487      3194044 :         set_nondeterministic ();
    1488              :     }
    1489              : 
    1490              :   /* For const functions we are done.  */
    1491      4001193 :   if (flags & (ECF_CONST | ECF_NOVOPS))
    1492      3411914 :     return;
    1493              : 
    1494      3994394 :   attr_fnspec fnspec = gimple_call_fnspec (call);
    1495              :   /* If there is no fnpec we know nothing about loads & stores.  */
    1496      3994394 :   if (!fnspec.known_p ())
    1497              :     {
    1498      3066813 :       if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
    1499            0 :         fprintf (dump_file, "      Builtin with no fnspec: %s\n",
    1500            0 :                  IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
    1501      3066813 :       if (!ignore_stores_p (current_function_decl, flags))
    1502              :         {
    1503      2611027 :           if (!may_access_nonescaping_parm_p (call, flags, false))
    1504       760223 :             record_global_memory_store ();
    1505              :           else
    1506      1850804 :             record_unknown_store ();
    1507      2611027 :           if (!may_access_nonescaping_parm_p (call, flags, true))
    1508       760223 :             record_global_memory_load ();
    1509              :           else
    1510      1850804 :             record_unknown_load ();
    1511              :         }
    1512              :       else
    1513              :         {
    1514       455786 :           if (!may_access_nonescaping_parm_p (call, flags, true))
    1515       372414 :             record_global_memory_load ();
    1516              :           else
    1517        83372 :             record_unknown_load ();
    1518              :         }
    1519      3066813 :       return;
    1520              :     }
    1521              :   /* Process fnspec.  */
    1522       927581 :   if (fnspec.global_memory_read_p ())
    1523              :     {
    1524       175307 :       if (may_access_nonescaping_parm_p (call, flags, true))
    1525       119180 :         record_unknown_load ();
    1526              :       else
    1527        56127 :         record_global_memory_load ();
    1528              :     }
    1529              :   else
    1530              :     {
    1531      1766833 :       for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
    1532      1316681 :         if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
    1533              :           ;
    1534       896231 :         else if (!fnspec.arg_specified_p (i)
    1535       896231 :                  || fnspec.arg_maybe_read_p (i))
    1536              :           {
    1537       554854 :             modref_parm_map map = parm_map_for_ptr
    1538       554854 :                                         (gimple_call_arg (call, i));
    1539              : 
    1540       554854 :             if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
    1541        35476 :               continue;
    1542       519378 :             if (map.parm_index == MODREF_UNKNOWN_PARM)
    1543              :               {
    1544       302122 :                 record_unknown_load ();
    1545       302122 :                 break;
    1546              :               }
    1547       217256 :             modref_access_node a = get_access_for_fnspec (call, fnspec, i, map);
    1548       217256 :             if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
    1549            0 :               continue;
    1550       217256 :             if (m_summary)
    1551       217256 :               m_summary->loads->insert (current_function_decl, 0, 0, a, false);
    1552       217256 :             if (m_summary_lto)
    1553            0 :               m_summary_lto->loads->insert (current_function_decl, 0, 0, a,
    1554              :                                             false);
    1555              :           }
    1556              :     }
    1557       927581 :   if (ignore_stores_p (current_function_decl, flags))
    1558              :     return;
    1559       589279 :   if (fnspec.global_memory_written_p ())
    1560              :     {
    1561        98752 :       if (may_access_nonescaping_parm_p (call, flags, false))
    1562        66508 :         record_unknown_store ();
    1563              :       else
    1564        32244 :         record_global_memory_store ();
    1565              :     }
    1566              :   else
    1567              :     {
    1568      1050674 :       for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
    1569       731640 :         if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
    1570              :           ;
    1571       414484 :         else if (!fnspec.arg_specified_p (i)
    1572       414484 :                  || fnspec.arg_maybe_written_p (i))
    1573              :           {
    1574       346467 :             modref_parm_map map = parm_map_for_ptr
    1575       346467 :                                          (gimple_call_arg (call, i));
    1576              : 
    1577       346467 :             if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
    1578        91536 :               continue;
    1579       254931 :             if (map.parm_index == MODREF_UNKNOWN_PARM)
    1580              :               {
    1581       171493 :                 record_unknown_store ();
    1582       171493 :                 break;
    1583              :               }
    1584        83438 :             modref_access_node a = get_access_for_fnspec (call, fnspec, i, map);
    1585        83438 :             if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
    1586            0 :               continue;
    1587        83438 :             if (m_summary)
    1588        83438 :               m_summary->stores->insert (current_function_decl, 0, 0, a, false);
    1589        83438 :             if (m_summary_lto)
    1590            0 :               m_summary_lto->stores->insert (current_function_decl,
    1591              :                                              0, 0, a, false);
    1592              :           }
    1593       490527 :       if (fnspec.errno_maybe_written_p () && flag_errno_math)
    1594              :         {
    1595        91064 :           if (m_summary)
    1596        91064 :             m_summary->writes_errno = true;
    1597        91064 :           if (m_summary_lto)
    1598            0 :             m_summary_lto->writes_errno = true;
    1599              :         }
    1600              :     }
    1601              : }
    1602              : 
    1603              : /* Analyze function call STMT in function F.
    1604              :    Remember recursive calls in RECURSIVE_CALLS.  */
    1605              : 
    1606              : void
    1607      6420006 : modref_access_analysis::analyze_call (gcall *stmt)
    1608              : {
    1609              :   /* Check flags on the function call.  In certain cases, analysis can be
    1610              :      simplified.  */
    1611      6420006 :   int flags = gimple_call_flags (stmt);
    1612              : 
    1613      6420006 :   if (dump_file)
    1614              :     {
    1615           33 :       fprintf (dump_file, " - Analyzing call:");
    1616           33 :       print_gimple_stmt (dump_file, stmt, 0);
    1617              :     }
    1618              : 
    1619      6420006 :   if ((flags & ECF_CONST)
    1620       790319 :       && !(flags & ECF_LOOPING_CONST_OR_PURE))
    1621              :     {
    1622       668865 :       if (dump_file)
    1623            0 :         fprintf (dump_file,
    1624              :                  " - ECF_CONST, ignoring all stores and all loads "
    1625              :                  "except for args.\n");
    1626       668865 :       return;
    1627              :     }
    1628              : 
    1629              :   /* Next, we try to get the callee's function declaration.  The goal is to
    1630              :      merge their summary with ours.  */
    1631      5751141 :   tree callee = gimple_call_fndecl (stmt);
    1632              : 
    1633              :   /* Check if this is an indirect call.  */
    1634      5751141 :   if (!callee)
    1635              :     {
    1636       379286 :       if (dump_file)
    1637           52 :         fprintf (dump_file, gimple_call_internal_p (stmt)
    1638              :                  ? " - Internal call" : " - Indirect call.\n");
    1639       379286 :       process_fnspec (stmt);
    1640       379286 :       return;
    1641              :     }
    1642              :   /* We only need to handle internal calls in IPA mode.  */
    1643      5371855 :   gcc_checking_assert (!m_summary_lto && !m_ipa);
    1644              : 
    1645      5371855 :   struct cgraph_node *callee_node = cgraph_node::get_create (callee);
    1646              : 
    1647              :   /* If this is a recursive call, the target summary is the same as ours, so
    1648              :      there's nothing to do.  */
    1649      5371855 :   if (recursive_call_p (current_function_decl, callee))
    1650              :     {
    1651        11031 :       m_recursive_calls.safe_push (stmt);
    1652        11031 :       set_side_effects ();
    1653        11031 :       if (dump_file)
    1654            1 :         fprintf (dump_file, " - Skipping recursive call.\n");
    1655        11031 :       return;
    1656              :     }
    1657              : 
    1658      5360824 :   gcc_assert (callee_node != NULL);
    1659              : 
    1660              :   /* Get the function symbol and its availability.  */
    1661      5360824 :   enum availability avail;
    1662      5360824 :   callee_node = callee_node->function_symbol (&avail);
    1663      5360824 :   bool looping;
    1664      5360824 :   if (builtin_safe_for_const_function_p (&looping, callee))
    1665              :     {
    1666       184242 :       if (looping)
    1667         2779 :         set_side_effects ();
    1668       184242 :       if (dump_file)
    1669            0 :         fprintf (dump_file, " - Builtin is safe for const.\n");
    1670       184242 :       return;
    1671              :     }
    1672      5176582 :   if (avail <= AVAIL_INTERPOSABLE)
    1673              :     {
    1674      3215433 :       if (dump_file)
    1675            3 :         fprintf (dump_file,
    1676              :                  " - Function availability <= AVAIL_INTERPOSABLE.\n");
    1677      3215433 :       process_fnspec (stmt);
    1678      3215433 :       return;
    1679              :     }
    1680              : 
    1681              :   /* Get callee's modref summary.  As above, if there's no summary, we either
    1682              :      have to give up or, if stores are ignored, we can just purge loads.  */
    1683      1961149 :   modref_summary *callee_summary = optimization_summaries->get (callee_node);
    1684      1961149 :   if (!callee_summary)
    1685              :     {
    1686       406474 :       if (dump_file)
    1687            0 :         fprintf (dump_file, " - No modref summary available for callee.\n");
    1688       406474 :       process_fnspec (stmt);
    1689       406474 :       return;
    1690              :     }
    1691              : 
    1692      1554675 :   merge_call_side_effects (stmt, callee_summary, callee_node, false);
    1693              : 
    1694      1554675 :   return;
    1695              : }
    1696              : 
    1697              : /* Helper for analyze_stmt.  */
    1698              : 
    1699              : bool
    1700     13580587 : modref_access_analysis::analyze_load (gimple *, tree, tree op, void *data)
    1701              : {
    1702     13580587 :   modref_access_analysis *t = (modref_access_analysis *)data;
    1703              : 
    1704     13580587 :   if (dump_file)
    1705              :     {
    1706          220 :       fprintf (dump_file, " - Analyzing load: ");
    1707          220 :       print_generic_expr (dump_file, op);
    1708          220 :       fprintf (dump_file, "\n");
    1709              :     }
    1710              : 
    1711     13580587 :   if (!t->record_access_p (op))
    1712              :     return false;
    1713              : 
    1714      8957909 :   ao_ref r;
    1715      8957909 :   ao_ref_init (&r, op);
    1716      8957909 :   modref_access_node a = get_access (&r);
    1717      8957909 :   if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
    1718              :     return false;
    1719              : 
    1720      8926182 :   if (t->m_summary)
    1721      8885829 :     t->record_access (t->m_summary->loads, &r, a);
    1722      8926182 :   if (t->m_summary_lto)
    1723       112577 :     t->record_access_lto (t->m_summary_lto->loads, &r, a);
    1724              :   return false;
    1725              : }
    1726              : 
    1727              : /* Helper for analyze_stmt.  */
    1728              : 
    1729              : bool
    1730     12714797 : modref_access_analysis::analyze_store (gimple *stmt, tree, tree op, void *data)
    1731              : {
    1732     12714797 :   modref_access_analysis *t = (modref_access_analysis *)data;
    1733              : 
    1734     12714797 :   if (dump_file)
    1735              :     {
    1736           99 :       fprintf (dump_file, " - Analyzing store: ");
    1737           99 :       print_generic_expr (dump_file, op);
    1738           99 :       fprintf (dump_file, "\n");
    1739              :     }
    1740              : 
    1741     12714797 :   if (!t->record_access_p (op))
    1742              :     return false;
    1743              : 
    1744      4431735 :   ao_ref r;
    1745      4431735 :   ao_ref_init (&r, op);
    1746      4431735 :   modref_access_node a = get_access (&r);
    1747      4431735 :   if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
    1748              :     return false;
    1749              : 
    1750      4224526 :   if (t->m_summary)
    1751      4200598 :     t->record_access (t->m_summary->stores, &r, a);
    1752      4224526 :   if (t->m_summary_lto)
    1753        57307 :     t->record_access_lto (t->m_summary_lto->stores, &r, a);
    1754      4224526 :   if (t->m_always_executed
    1755      1768980 :       && a.useful_for_kill_p ()
    1756      5398294 :       && !stmt_could_throw_p (cfun, stmt))
    1757              :     {
    1758      1168285 :       if (dump_file)
    1759           20 :         fprintf (dump_file, "   - Recording kill\n");
    1760      1168285 :       if (t->m_summary)
    1761      1165706 :         modref_access_node::insert_kill (t->m_summary->kills, a, false);
    1762      1168285 :       if (t->m_summary_lto)
    1763         5559 :         modref_access_node::insert_kill (t->m_summary_lto->kills, a, false);
    1764              :     }
    1765              :   return false;
    1766              : }
    1767              : 
    1768              : /* Analyze statement STMT of function F.
    1769              :    If IPA is true do not merge in side effects of calls.  */
    1770              : 
    1771              : void
    1772     67764266 : modref_access_analysis::analyze_stmt (gimple *stmt, bool always_executed)
    1773              : {
    1774     67764266 :   m_always_executed = always_executed;
    1775              :   /* In general we can not ignore clobbers because they are barriers for code
    1776              :      motion, however after inlining it is safe to do because local optimization
    1777              :      passes do not consider clobbers from other functions.
    1778              :      Similar logic is in ipa-pure-const.cc.  */
    1779     67764266 :   if ((m_ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
    1780              :     {
    1781      1629974 :       if (always_executed && record_access_p (gimple_assign_lhs (stmt)))
    1782              :         {
    1783        55198 :           ao_ref r;
    1784        55198 :           ao_ref_init (&r, gimple_assign_lhs (stmt));
    1785        55198 :           modref_access_node a = get_access (&r);
    1786        55198 :           if (a.useful_for_kill_p ())
    1787              :             {
    1788        52659 :               if (dump_file)
    1789            0 :                 fprintf (dump_file, "   - Recording kill\n");
    1790        52659 :               if (m_summary)
    1791        52422 :                 modref_access_node::insert_kill (m_summary->kills, a, false);
    1792        52659 :               if (m_summary_lto)
    1793          412 :                 modref_access_node::insert_kill (m_summary_lto->kills,
    1794              :                                                  a, false);
    1795              :             }
    1796              :         }
    1797      1629974 :       return;
    1798              :     }
    1799              : 
    1800              :   /* Analyze all loads and stores in STMT.  */
    1801     66134292 :   walk_stmt_load_store_ops (stmt, this,
    1802              :                             analyze_load, analyze_store);
    1803              : 
    1804     66134292 :   switch (gimple_code (stmt))
    1805              :    {
    1806       140622 :    case GIMPLE_ASM:
    1807       140622 :       if (gimple_asm_volatile_p (as_a <gasm *> (stmt))
    1808       140622 :           && !ignore_nondeterminism_p (current_function_decl, 0, NULL))
    1809       121169 :         set_nondeterministic ();
    1810       140622 :       if (cfun->can_throw_non_call_exceptions
    1811       140622 :           && stmt_could_throw_p (cfun, stmt))
    1812          151 :         set_side_effects ();
    1813              :      /* If the ASM statement does not read nor write memory, there's nothing
    1814              :         to do.  Otherwise just give up.  */
    1815       140622 :      if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
    1816              :        return;
    1817        11831 :      if (dump_file)
    1818            1 :        fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
    1819              :                "which clobbers memory.\n");
    1820        11831 :      record_unknown_load ();
    1821        11831 :      record_unknown_store ();
    1822        11831 :      return;
    1823     11087479 :    case GIMPLE_CALL:
    1824     11087479 :      if (!m_ipa || gimple_call_internal_p (stmt))
    1825      6420006 :        analyze_call (as_a <gcall *> (stmt));
    1826              :      else
    1827              :        {
    1828      4667473 :          attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
    1829              : 
    1830      4667473 :          if (fnspec.known_p ()
    1831      4667473 :              && (!fnspec.global_memory_read_p ()
    1832       302521 :                  || !fnspec.global_memory_written_p ()))
    1833              :            {
    1834       514525 :              cgraph_edge *e = cgraph_node::get
    1835       514525 :                                   (current_function_decl)->get_edge (stmt);
    1836       514525 :              if (e->callee)
    1837              :                {
    1838       514521 :                  fnspec_summaries->get_create (e)->fnspec
    1839       514521 :                           = xstrdup (fnspec.get_str ());
    1840       514521 :                  if (dump_file)
    1841            2 :                    fprintf (dump_file, "  Recorded fnspec %s\n",
    1842              :                             fnspec.get_str ());
    1843              :                }
    1844              :            }
    1845              :        }
    1846              :      return;
    1847     54906191 :    default:
    1848     54906191 :      if (cfun->can_throw_non_call_exceptions
    1849     54906191 :          && stmt_could_throw_p (cfun, stmt))
    1850      1568196 :         set_side_effects ();
    1851              :      return;
    1852              :    }
    1853              : }
    1854              : 
    1855              : /* Propagate load/stores across recursive calls.  */
    1856              : 
    1857              : void
    1858      2398178 : modref_access_analysis::propagate ()
    1859              : {
    1860      2398178 :   if (m_ipa && m_summary)
    1861              :     return;
    1862              : 
    1863      2398178 :   bool changed = true;
    1864      2398178 :   bool first = true;
    1865      2398178 :   cgraph_node *fnode = cgraph_node::get (current_function_decl);
    1866              : 
    1867      2398178 :   m_always_executed = false;
    1868      4797881 :   while (changed && m_summary->useful_p (m_ecf_flags, false))
    1869              :     {
    1870              :       changed = false;
    1871      7208580 :       for (unsigned i = 0; i < m_recursive_calls.length (); i++)
    1872              :         {
    1873        11206 :           changed |= merge_call_side_effects (m_recursive_calls[i], m_summary,
    1874        11206 :                                               fnode, !first);
    1875              :         }
    1876              :       first = false;
    1877              :     }
    1878              : }
    1879              : 
    1880              : /* Analyze function.  */
    1881              : 
    1882              : void
    1883      4749635 : modref_access_analysis::analyze ()
    1884              : {
    1885      4749635 :   m_ecf_flags = flags_from_decl_or_type (current_function_decl);
    1886      4749635 :   bool summary_useful = true;
    1887              : 
    1888              :   /* Analyze each statement in each basic block of the function.  If the
    1889              :      statement cannot be analyzed (for any reason), the entire function cannot
    1890              :      be analyzed by modref.  */
    1891      4749635 :   basic_block bb;
    1892      4749635 :   bitmap always_executed_bbs = find_always_executed_bbs (cfun, true);
    1893     27894329 :   FOR_EACH_BB_FN (bb, cfun)
    1894              :     {
    1895     24313532 :       gimple_stmt_iterator si;
    1896     24313532 :       bool always_executed = bitmap_bit_p (always_executed_bbs, bb->index);
    1897              : 
    1898     24313532 :       for (si = gsi_start_nondebug_after_labels_bb (bb);
    1899     90908960 :            !gsi_end_p (si); gsi_next_nondebug (&si))
    1900              :         {
    1901              :           /* NULL memory accesses terminates BB.  These accesses are known
    1902              :              to trip undefined behavior.  gimple-ssa-isolate-paths turns them
    1903              :              to volatile accesses and adds builtin_trap call which would
    1904              :              confuse us otherwise.  */
    1905     67766080 :           if (infer_nonnull_range_by_dereference (gsi_stmt (si),
    1906              :                                                   null_pointer_node))
    1907              :             {
    1908         1814 :               if (dump_file)
    1909            0 :                 fprintf (dump_file, " - NULL memory access; terminating BB\n");
    1910         1814 :               if (flag_non_call_exceptions)
    1911          268 :                 set_side_effects ();
    1912              :               break;
    1913              :             }
    1914     67764266 :           analyze_stmt (gsi_stmt (si), always_executed);
    1915              : 
    1916              :           /* Avoid doing useless work.  */
    1917     67341334 :           if ((!m_summary || !m_summary->useful_p (m_ecf_flags, false))
    1918     68928727 :               && (!m_summary_lto
    1919       428269 :                   || !m_summary_lto->useful_p (m_ecf_flags, false)))
    1920              :             {
    1921              :               summary_useful = false;
    1922              :               break;
    1923              :             }
    1924     66595428 :           if (always_executed
    1925     66595428 :               && stmt_can_throw_external (cfun, gsi_stmt (si)))
    1926              :             always_executed = false;
    1927              :         }
    1928     24313532 :       if (!summary_useful)
    1929              :         break;
    1930              :     }
    1931              :   /* In non-IPA mode we need to perform iterative dataflow on recursive calls.
    1932              :      This needs to be done after all other side effects are computed.  */
    1933      4749635 :   if (summary_useful)
    1934              :     {
    1935      3580797 :       if (!m_ipa)
    1936      2398178 :         propagate ();
    1937      3580797 :       if (m_summary && !m_summary->side_effects && !finite_function_p ())
    1938        50578 :         m_summary->side_effects = true;
    1939        83082 :       if (m_summary_lto && !m_summary_lto->side_effects
    1940      3658710 :           && !finite_function_p ())
    1941         3073 :         m_summary_lto->side_effects = true;
    1942              :     }
    1943      4749635 :   BITMAP_FREE (always_executed_bbs);
    1944      4749635 : }
    1945              : 
    1946              : /* Return true if OP accesses memory pointed to by SSA_NAME.  */
    1947              : 
    1948              : bool
    1949     22552880 : memory_access_to (tree op, tree ssa_name)
    1950              : {
    1951     22552880 :   tree base = get_base_address (op);
    1952     22552880 :   if (!base)
    1953              :     return false;
    1954     22552880 :   if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
    1955              :     return false;
    1956      8981486 :   return TREE_OPERAND (base, 0) == ssa_name;
    1957              : }
    1958              : 
    1959              : /* Consider statement val = *arg.
    1960              :    return EAF flags of ARG that can be determined from EAF flags of VAL
    1961              :    (which are known to be FLAGS).  If IGNORE_STORES is true we can ignore
    1962              :    all stores to VAL, i.e. when handling noreturn function.  */
    1963              : 
    1964              : static int
    1965      8306170 : deref_flags (int flags, bool ignore_stores)
    1966              : {
    1967              :   /* Dereference is also a direct read but dereferenced value does not
    1968              :      yield any other direct use.  */
    1969      8306170 :   int ret = EAF_NO_DIRECT_CLOBBER | EAF_NO_DIRECT_ESCAPE
    1970              :             | EAF_NOT_RETURNED_DIRECTLY;
    1971              :   /* If argument is unused just account for
    1972              :      the read involved in dereference.  */
    1973      8306170 :   if (flags & EAF_UNUSED)
    1974              :     ret |= EAF_NO_INDIRECT_READ | EAF_NO_INDIRECT_CLOBBER
    1975              :            | EAF_NO_INDIRECT_ESCAPE;
    1976              :   else
    1977              :     {
    1978              :       /* Direct or indirect accesses leads to indirect accesses.  */
    1979      8266992 :       if (((flags & EAF_NO_DIRECT_CLOBBER)
    1980      4672743 :            && (flags & EAF_NO_INDIRECT_CLOBBER))
    1981      4250719 :           || ignore_stores)
    1982      4043938 :         ret |= EAF_NO_INDIRECT_CLOBBER;
    1983      8266992 :       if (((flags & EAF_NO_DIRECT_ESCAPE)
    1984      5183510 :            && (flags & EAF_NO_INDIRECT_ESCAPE))
    1985      3793528 :           || ignore_stores)
    1986      4501125 :         ret |= EAF_NO_INDIRECT_ESCAPE;
    1987      8266992 :       if ((flags & EAF_NO_DIRECT_READ)
    1988      3668183 :            && (flags & EAF_NO_INDIRECT_READ))
    1989      3668183 :         ret |= EAF_NO_INDIRECT_READ;
    1990      8266992 :       if ((flags & EAF_NOT_RETURNED_DIRECTLY)
    1991      3646228 :           && (flags & EAF_NOT_RETURNED_INDIRECTLY))
    1992      2913683 :         ret |= EAF_NOT_RETURNED_INDIRECTLY;
    1993              :     }
    1994      8306170 :   return ret;
    1995              : }
    1996              : 
    1997              : 
    1998              : /* Description of an escape point: a call which affects flags of a given
    1999              :    SSA name.  */
    2000              : 
    2001              : struct escape_point
    2002              : {
    2003              :   /* Value escapes to this call.  */
    2004              :   gcall *call;
    2005              :   /* Argument it escapes to.  */
    2006              :   unsigned int arg;
    2007              :   /* Flags already known about the argument (this can save us from recording
    2008              :      escape points if local analysis did good job already).  */
    2009              :   eaf_flags_t min_flags;
    2010              :   /* Does value escape directly or indirectly?  */
    2011              :   bool direct;
    2012              : };
    2013              : 
    2014              : /* Lattice used during the eaf flags analysis dataflow.  For a given SSA name
    2015              :    we aim to compute its flags and escape points.  We also use the lattice
    2016              :    to dynamically build dataflow graph to propagate on.  */
    2017              : 
    2018              : class modref_lattice
    2019              : {
    2020              : public:
    2021              :   /* EAF flags of the SSA name.  */
    2022              :   eaf_flags_t flags;
    2023              :   /* Used during DFS walk to mark names where final value was determined
    2024              :      without need for dataflow.  */
    2025              :   bool known;
    2026              :   /* Used during DFS walk to mark open vertices (for cycle detection).  */
    2027              :   bool open;
    2028              :   /* Set during DFS walk for names that needs dataflow propagation.  */
    2029              :   bool do_dataflow;
    2030              :   /* Used during the iterative dataflow.  */
    2031              :   bool changed;
    2032              : 
    2033              :   /* When doing IPA analysis we can not merge in callee escape points;
    2034              :      Only remember them and do the merging at IPA propagation time.  */
    2035              :   vec <escape_point, va_heap, vl_ptr> escape_points;
    2036              : 
    2037              :   /* Representation of a graph for dataflow.  This graph is built on-demand
    2038              :      using modref_eaf_analysis::analyze_ssa and later solved by
    2039              :      modref_eaf_analysis::propagate.
    2040              :      Each edge represents the fact that flags of current lattice should be
    2041              :      propagated to lattice of SSA_NAME.  */
    2042              :   struct propagate_edge
    2043              :   {
    2044              :     int ssa_name;
    2045              :     bool deref;
    2046              :   };
    2047              :   vec <propagate_edge, va_heap, vl_ptr> propagate_to;
    2048              : 
    2049              :   void init ();
    2050              :   void release ();
    2051              :   bool merge (const modref_lattice &with);
    2052              :   bool merge (int flags);
    2053              :   bool merge_deref (const modref_lattice &with, bool ignore_stores);
    2054              :   bool merge_direct_load ();
    2055              :   bool merge_direct_store ();
    2056              :   bool add_escape_point (gcall *call, unsigned int arg,
    2057              :                          eaf_flags_t min_flags, bool direct);
    2058              :   void dump (FILE *out, int indent = 0) const;
    2059              : };
    2060              : 
    2061              : /* Lattices are saved to vectors, so keep them PODs.  */
    2062              : void
    2063     23005221 : modref_lattice::init ()
    2064              : {
    2065              :   /* All flags we track.  */
    2066     23005221 :   int f = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
    2067              :           | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE
    2068              :           | EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ
    2069              :           | EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY
    2070              :           | EAF_UNUSED;
    2071     23005221 :   flags = f;
    2072              :   /* Check that eaf_flags_t is wide enough to hold all flags.  */
    2073     23005221 :   gcc_checking_assert (f == flags);
    2074     23005221 :   open = true;
    2075     23005221 :   known = false;
    2076            0 : }
    2077              : 
    2078              : /* Release memory.  */
    2079              : void
    2080     42867805 : modref_lattice::release ()
    2081              : {
    2082            0 :   escape_points.release ();
    2083     42867805 :   propagate_to.release ();
    2084            0 : }
    2085              : 
    2086              : /* Dump lattice to OUT; indent with INDENT spaces.  */
    2087              : 
    2088              : void
    2089         2623 : modref_lattice::dump (FILE *out, int indent) const
    2090              : {
    2091         2623 :   dump_eaf_flags (out, flags);
    2092         2623 :   if (escape_points.length ())
    2093              :     {
    2094           37 :       fprintf (out, "%*sEscapes:\n", indent, "");
    2095           76 :       for (unsigned int i = 0; i < escape_points.length (); i++)
    2096              :         {
    2097          117 :           fprintf (out, "%*s  Arg %i (%s) min flags", indent, "",
    2098           39 :                    escape_points[i].arg,
    2099           39 :                    escape_points[i].direct ? "direct" : "indirect");
    2100           39 :           dump_eaf_flags (out, escape_points[i].min_flags, false);
    2101           39 :           fprintf (out, " in call ");
    2102           39 :           print_gimple_stmt (out, escape_points[i].call, 0);
    2103              :         }
    2104              :     }
    2105         2623 : }
    2106              : 
    2107              : /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT.  Return false if such escape
    2108              :    point exists.  */
    2109              : 
    2110              : bool
    2111      2054814 : modref_lattice::add_escape_point (gcall *call, unsigned arg,
    2112              :                                   eaf_flags_t min_flags, bool direct)
    2113              : {
    2114      2054814 :   escape_point *ep;
    2115      2054814 :   unsigned int i;
    2116              : 
    2117              :   /* If we already determined flags to be bad enough,
    2118              :      we do not need to record.  */
    2119      2054814 :   if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
    2120              :     return false;
    2121              : 
    2122      4140785 :   FOR_EACH_VEC_ELT (escape_points, i, ep)
    2123      3452021 :     if (ep->call == call && ep->arg == arg && ep->direct == direct)
    2124              :       {
    2125        65299 :         if ((ep->min_flags & min_flags) == min_flags)
    2126              :           return false;
    2127            0 :         ep->min_flags &= min_flags;
    2128            0 :         return true;
    2129              :       }
    2130              :   /* Give up if max escape points is met.  */
    2131       858121 :   if ((int)escape_points.length () > param_modref_max_escape_points)
    2132              :     {
    2133            0 :       if (dump_file)
    2134            0 :         fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
    2135            0 :       merge (0);
    2136            0 :       return true;
    2137              :     }
    2138       688764 :   escape_point new_ep = {call, arg, min_flags, direct};
    2139       688764 :   escape_points.safe_push (new_ep);
    2140       688764 :   return true;
    2141              : }
    2142              : 
    2143              : /* Merge in flags from F.  */
    2144              : bool
    2145     70702651 : modref_lattice::merge (int f)
    2146              : {
    2147     70702651 :   if (f & EAF_UNUSED)
    2148              :     return false;
    2149              :   /* Check that flags seems sane: if function does not read the parameter
    2150              :      it can not access it indirectly.  */
    2151     70693694 :   gcc_checking_assert (!(f & EAF_NO_DIRECT_READ)
    2152              :                        || ((f & EAF_NO_INDIRECT_READ)
    2153              :                            && (f & EAF_NO_INDIRECT_CLOBBER)
    2154              :                            && (f & EAF_NO_INDIRECT_ESCAPE)
    2155              :                            && (f & EAF_NOT_RETURNED_INDIRECTLY)));
    2156     70693694 :   if ((flags & f) != flags)
    2157              :     {
    2158     44421197 :       flags &= f;
    2159              :       /* Prune obviously useless flags;
    2160              :          We do not have ECF_FLAGS handy which is not big problem since
    2161              :          we will do final flags cleanup before producing summary.
    2162              :          Merging should be fast so it can work well with dataflow.  */
    2163     44421197 :       flags = remove_useless_eaf_flags (flags, 0, false);
    2164     44421197 :       if (!flags)
    2165      8451684 :         escape_points.release ();
    2166     44421197 :       return true;
    2167              :     }
    2168              :   return false;
    2169              : }
    2170              : 
    2171              : /* Merge in WITH.  Return true if anything changed.  */
    2172              : 
    2173              : bool
    2174     15378602 : modref_lattice::merge (const modref_lattice &with)
    2175              : {
    2176     15378602 :   if (!with.known)
    2177      2385791 :     do_dataflow = true;
    2178              : 
    2179     15378602 :   bool changed = merge (with.flags);
    2180              : 
    2181     15378602 :   if (!flags)
    2182              :     return changed;
    2183     11722591 :   for (unsigned int i = 0; i < with.escape_points.length (); i++)
    2184       278810 :     changed |= add_escape_point (with.escape_points[i].call,
    2185       278810 :                                  with.escape_points[i].arg,
    2186       278810 :                                  with.escape_points[i].min_flags,
    2187       278810 :                                  with.escape_points[i].direct);
    2188              :   return changed;
    2189              : }
    2190              : 
    2191              : /* Merge in deref of WITH.  If IGNORE_STORES is true do not consider
    2192              :    stores.  Return true if anything changed.  */
    2193              : 
    2194              : bool
    2195      7986659 : modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
    2196              : {
    2197      7986659 :   if (!with.known)
    2198       377807 :     do_dataflow = true;
    2199              : 
    2200      7986659 :   bool changed = merge (deref_flags (with.flags, ignore_stores));
    2201              : 
    2202      7986659 :   if (!flags)
    2203              :     return changed;
    2204      7749621 :   for (unsigned int i = 0; i < with.escape_points.length (); i++)
    2205              :     {
    2206       157056 :       int min_flags = with.escape_points[i].min_flags;
    2207              : 
    2208       157056 :       if (with.escape_points[i].direct)
    2209       130482 :         min_flags = deref_flags (min_flags, ignore_stores);
    2210        26574 :       else if (ignore_stores)
    2211            0 :         min_flags |= ignore_stores_eaf_flags;
    2212       157056 :       changed |= add_escape_point (with.escape_points[i].call,
    2213       157056 :                                    with.escape_points[i].arg,
    2214              :                                    min_flags,
    2215              :                                    false);
    2216              :     }
    2217              :   return changed;
    2218              : }
    2219              : 
    2220              : /* Merge in flags for direct load.  */
    2221              : 
    2222              : bool
    2223          157 : modref_lattice::merge_direct_load ()
    2224              : {
    2225            0 :   return merge (~(EAF_UNUSED | EAF_NO_DIRECT_READ));
    2226              : }
    2227              : 
    2228              : /* Merge in flags for direct store.  */
    2229              : 
    2230              : bool
    2231      2730456 : modref_lattice::merge_direct_store ()
    2232              : {
    2233            0 :   return merge (~(EAF_UNUSED | EAF_NO_DIRECT_CLOBBER));
    2234              : }
    2235              : 
    2236              : /* Analyzer of EAF flags.
    2237              :    This is generally dataflow problem over the SSA graph, however we only
    2238              :    care about flags of few selected ssa names (arguments, return slot and
    2239              :    static chain).  So we first call analyze_ssa_name on all relevant names
    2240              :    and perform a DFS walk to discover SSA names where flags needs to be
    2241              :    determined.  For acyclic graphs we try to determine final flags during
    2242              :    this walk.  Once cycles or recursion depth is met we enlist SSA names
    2243              :    for dataflow which is done by propagate call.
    2244              : 
    2245              :    After propagation the flags can be obtained using get_ssa_name_flags.  */
    2246              : 
    2247              : class modref_eaf_analysis
    2248              : {
    2249              : public:
    2250              :   /* Mark NAME as relevant for analysis.  */
    2251              :   void analyze_ssa_name (tree name, bool deferred = false);
    2252              :   /* Dataflow solver.  */
    2253              :   void propagate ();
    2254              :   /* Return flags computed earlier for NAME.  */
    2255      6823202 :   int get_ssa_name_flags (tree name)
    2256              :   {
    2257      6823202 :     int version = SSA_NAME_VERSION (name);
    2258      6823202 :     gcc_checking_assert (m_lattice[version].known);
    2259      6823202 :     return m_lattice[version].flags;
    2260              :   }
    2261              :   /* In IPA mode this will record all escape points
    2262              :      determined for NAME to PARM_IDNEX.  Flags are minimal
    2263              :      flags known.  */
    2264              :   void record_escape_points (tree name, int parm_index, int flags);
    2265      4039755 :   modref_eaf_analysis (bool ipa)
    2266      4039755 :   {
    2267      4039755 :     m_ipa = ipa;
    2268      4039755 :     m_depth = 0;
    2269      8079510 :     m_lattice.safe_grow_cleared (num_ssa_names, true);
    2270      4039755 :   }
    2271      4039755 :   ~modref_eaf_analysis ()
    2272              :   {
    2273      4039755 :     gcc_checking_assert (!m_depth);
    2274      4039755 :     if (m_ipa || m_names_to_propagate.length ())
    2275     44092726 :       for (unsigned int i = 0; i < num_ssa_names; i++)
    2276     85735610 :         m_lattice[i].release ();
    2277      4039755 :   }
    2278              : private:
    2279              :   /* If true, we produce analysis for IPA mode.  In this case escape points are
    2280              :      collected.  */
    2281              :   bool m_ipa;
    2282              :   /* Depth of recursion of analyze_ssa_name.  */
    2283              :   int m_depth;
    2284              :   /* Propagation lattice for individual ssa names.  */
    2285              :   auto_vec<modref_lattice> m_lattice;
    2286              :   auto_vec<tree> m_deferred_names;
    2287              :   auto_vec<int> m_names_to_propagate;
    2288              : 
    2289              :   void merge_with_ssa_name (tree dest, tree src, bool deref);
    2290              :   void merge_call_lhs_flags (gcall *call, int arg, tree name, bool direct,
    2291              :                              bool deref);
    2292              : };
    2293              : 
    2294              : 
    2295              : /* Call statements may return their parameters.  Consider argument number
    2296              :    ARG of USE_STMT and determine flags that can needs to be cleared
    2297              :    in case pointer possibly indirectly references from ARG I is returned.
    2298              :    If DIRECT is true consider direct returns and if INDIRECT consider
    2299              :    indirect returns.
    2300              :    LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
    2301              :    ARG is set to -1 for static chain.  */
    2302              : 
    2303              : void
    2304      5742181 : modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg,
    2305              :                                            tree name, bool direct,
    2306              :                                            bool indirect)
    2307              : {
    2308      5742181 :   int index = SSA_NAME_VERSION (name);
    2309      5742181 :   bool returned_directly = false;
    2310              : 
    2311              :   /* If there is no return value, no flags are affected.  */
    2312      5742181 :   if (!gimple_call_lhs (call))
    2313              :     return;
    2314              : 
    2315              :   /* If we know that function returns given argument and it is not ARG
    2316              :      we can still be happy.  */
    2317      3068491 :   if (arg >= 0)
    2318              :     {
    2319      3061118 :       int flags = gimple_call_return_flags (call);
    2320      3061118 :       if (flags & ERF_RETURNS_ARG)
    2321              :         {
    2322        23900 :           if ((flags & ERF_RETURN_ARG_MASK) == arg)
    2323              :             returned_directly = true;
    2324              :           else
    2325              :            return;
    2326              :         }
    2327              :     }
    2328              :   /* Make ERF_RETURNS_ARG overwrite EAF_UNUSED.  */
    2329              :   if (returned_directly)
    2330              :     {
    2331              :       direct = true;
    2332              :       indirect = false;
    2333              :     }
    2334              :   /* If value is not returned at all, do nothing.  */
    2335      3044591 :   else if (!direct && !indirect)
    2336              :     return;
    2337              : 
    2338              :   /* If return value is SSA name determine its flags.  */
    2339      2825777 :   if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
    2340              :     {
    2341      2470402 :       tree lhs = gimple_call_lhs (call);
    2342      2470402 :       if (direct)
    2343      2312308 :         merge_with_ssa_name (name, lhs, false);
    2344      2470402 :       if (indirect)
    2345      2013092 :         merge_with_ssa_name (name, lhs, true);
    2346              :     }
    2347              :   /* In the case of memory store we can do nothing.  */
    2348       355375 :   else if (!direct)
    2349       111683 :     m_lattice[index].merge (deref_flags (0, false));
    2350              :   else
    2351       243692 :     m_lattice[index].merge (0);
    2352              : }
    2353              : 
    2354              : /* CALL_FLAGS are EAF_FLAGS of the argument.  Turn them
    2355              :    into flags for caller, update LATTICE of corresponding
    2356              :    argument if needed.  */
    2357              : 
    2358              : static int
    2359      5132596 : callee_to_caller_flags (int call_flags, bool ignore_stores,
    2360              :                         modref_lattice &lattice)
    2361              : {
    2362              :   /* call_flags is about callee returning a value
    2363              :      that is not the same as caller returning it.  */
    2364      5132596 :   call_flags |= EAF_NOT_RETURNED_DIRECTLY
    2365              :                 | EAF_NOT_RETURNED_INDIRECTLY;
    2366      5132596 :   if (!ignore_stores && !(call_flags & EAF_UNUSED))
    2367              :     {
    2368              :       /* If value escapes we are no longer able to track what happens
    2369              :          with it because we can read it from the escaped location
    2370              :          anytime.  */
    2371      4406190 :       if (!(call_flags & EAF_NO_DIRECT_ESCAPE))
    2372      3248438 :         lattice.merge (0);
    2373      1157752 :       else if (!(call_flags & EAF_NO_INDIRECT_ESCAPE))
    2374       549370 :         lattice.merge (~(EAF_NOT_RETURNED_INDIRECTLY
    2375              :                          | EAF_NO_DIRECT_READ
    2376              :                          | EAF_NO_INDIRECT_READ
    2377              :                          | EAF_NO_INDIRECT_CLOBBER
    2378              :                          | EAF_UNUSED));
    2379              :     }
    2380              :   else
    2381       726406 :     call_flags |= ignore_stores_eaf_flags;
    2382      5132596 :   return call_flags;
    2383              : }
    2384              : 
    2385              : /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
    2386              :    LATTICE is an array of modref_lattices.
    2387              :    DEPTH is a recursion depth used to make debug output prettier.
    2388              :    If IPA is true we analyze for IPA propagation (and thus call escape points
    2389              :    are processed later)  */
    2390              : 
    2391              : void
    2392     27661500 : modref_eaf_analysis::analyze_ssa_name (tree name, bool deferred)
    2393              : {
    2394     27661500 :   imm_use_iterator ui;
    2395     27661500 :   gimple *use_stmt;
    2396     27661500 :   int index = SSA_NAME_VERSION (name);
    2397              : 
    2398     27661500 :   if (!deferred)
    2399              :     {
    2400              :       /* See if value is already computed.  */
    2401     27658799 :       if (m_lattice[index].known || m_lattice[index].do_dataflow)
    2402      4656279 :        return;
    2403     23402971 :       if (m_lattice[index].open)
    2404              :         {
    2405       397750 :           if (dump_file)
    2406           41 :             fprintf (dump_file,
    2407              :                      "%*sCycle in SSA graph\n",
    2408           41 :                      m_depth * 4, "");
    2409       397750 :           return;
    2410              :         }
    2411              :       /* Recursion guard.  */
    2412     23005221 :       m_lattice[index].init ();
    2413     23005221 :       if (m_depth == param_modref_max_depth)
    2414              :         {
    2415         2701 :           if (dump_file)
    2416            0 :             fprintf (dump_file,
    2417              :                      "%*sMax recursion depth reached; postponing\n",
    2418              :                      m_depth * 4, "");
    2419         2701 :           m_deferred_names.safe_push (name);
    2420         2701 :           return;
    2421              :         }
    2422              :     }
    2423              : 
    2424     23005221 :   if (dump_file)
    2425              :     {
    2426         1139 :       fprintf (dump_file,
    2427         1139 :                "%*sAnalyzing flags of ssa name: ", m_depth * 4, "");
    2428         1139 :       print_generic_expr (dump_file, name);
    2429         1139 :       fprintf (dump_file, "\n");
    2430              :     }
    2431              : 
    2432     86667013 :   FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
    2433              :     {
    2434     43822946 :       if (m_lattice[index].flags == 0)
    2435              :         break;
    2436     40656571 :       if (is_gimple_debug (use_stmt))
    2437      7189340 :         continue;
    2438     33467231 :       if (dump_file)
    2439              :         {
    2440         1480 :           fprintf (dump_file, "%*s  Analyzing stmt: ", m_depth * 4, "");
    2441         1480 :           print_gimple_stmt (dump_file, use_stmt, 0);
    2442              :         }
    2443              :       /* If we see a direct non-debug use, clear unused bit.
    2444              :          All dereferences should be accounted below using deref_flags.  */
    2445     33467231 :       m_lattice[index].merge (~EAF_UNUSED);
    2446              : 
    2447              :       /* Gimple return may load the return value.
    2448              :          Returning name counts as an use by tree-ssa-structalias.cc  */
    2449     33467231 :       if (greturn *ret = dyn_cast <greturn *> (use_stmt))
    2450              :         {
    2451              :           /* Returning through return slot is seen as memory write earlier.  */
    2452      1319097 :           if (DECL_RESULT (current_function_decl)
    2453      1319097 :               && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
    2454              :             ;
    2455      1266790 :           else if (gimple_return_retval (ret) == name)
    2456      1266790 :             m_lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED_DIRECTLY
    2457              :                                       | EAF_NOT_RETURNED_DIRECTLY));
    2458            0 :           else if (memory_access_to (gimple_return_retval (ret), name))
    2459              :             {
    2460            0 :               m_lattice[index].merge_direct_load ();
    2461            0 :               m_lattice[index].merge (~(EAF_UNUSED
    2462              :                                         | EAF_NOT_RETURNED_INDIRECTLY));
    2463              :             }
    2464              :         }
    2465              :       /* Account for LHS store, arg loads and flags from callee function.  */
    2466     32148134 :       else if (gcall *call = dyn_cast <gcall *> (use_stmt))
    2467              :         {
    2468      5876722 :           tree callee = gimple_call_fndecl (call);
    2469              : 
    2470              :           /* IPA PTA internally it treats calling a function as "writing" to
    2471              :              the argument space of all functions the function pointer points to
    2472              :              (PR101949).  We can not drop EAF_NOCLOBBER only when ipa-pta
    2473              :              is on since that would allow propagation of this from -fno-ipa-pta
    2474              :              to -fipa-pta functions.  */
    2475      5876722 :           if (gimple_call_fn (use_stmt) == name)
    2476        55493 :             m_lattice[index].merge (~(EAF_NO_DIRECT_CLOBBER | EAF_UNUSED));
    2477              : 
    2478              :           /* Recursion would require bit of propagation; give up for now.  */
    2479      5876722 :           if (callee && !m_ipa && recursive_call_p (current_function_decl,
    2480              :                                                   callee))
    2481        14820 :             m_lattice[index].merge (0);
    2482              :           else
    2483              :             {
    2484      5861902 :               int ecf_flags = gimple_call_flags (call);
    2485      5861902 :               bool ignore_stores = ignore_stores_p (current_function_decl,
    2486              :                                                     ecf_flags);
    2487      5861902 :               bool ignore_retval = ignore_retval_p (current_function_decl,
    2488              :                                                     ecf_flags);
    2489              : 
    2490              :               /* Handle *name = func (...).  */
    2491      5861902 :               if (gimple_call_lhs (call)
    2492      5861902 :                   && memory_access_to (gimple_call_lhs (call), name))
    2493              :                 {
    2494        16562 :                   m_lattice[index].merge_direct_store ();
    2495              :                   /* Return slot optimization passes address of
    2496              :                      LHS to callee via hidden parameter and this
    2497              :                      may make LHS to escape.  See PR 98499.  */
    2498        16562 :                   if (gimple_call_return_slot_opt_p (call)
    2499        16562 :                       && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
    2500              :                     {
    2501        13264 :                       int call_flags = gimple_call_retslot_flags (call);
    2502        13264 :                       bool isretslot = false;
    2503              : 
    2504        13264 :                       if (DECL_RESULT (current_function_decl)
    2505        13264 :                           && DECL_BY_REFERENCE
    2506              :                                 (DECL_RESULT (current_function_decl)))
    2507        25120 :                         isretslot = ssa_default_def
    2508        12560 :                                          (cfun,
    2509        12560 :                                           DECL_RESULT (current_function_decl))
    2510              :                                          == name;
    2511              : 
    2512              :                       /* Passing returnslot to return slot is special because
    2513              :                          not_returned and escape has same meaning.
    2514              :                          However passing arg to return slot is different.  If
    2515              :                          the callee's return slot is returned it means that
    2516              :                          arg is written to itself which is an escape.
    2517              :                          Since we do not track the memory it is written to we
    2518              :                          need to give up on analyzing it.  */
    2519        12560 :                       if (!isretslot)
    2520              :                         {
    2521          704 :                           if (!(call_flags & (EAF_NOT_RETURNED_DIRECTLY
    2522              :                                               | EAF_UNUSED)))
    2523          506 :                             m_lattice[index].merge (0);
    2524          198 :                           else gcc_checking_assert
    2525              :                                 (call_flags & (EAF_NOT_RETURNED_INDIRECTLY
    2526              :                                                | EAF_UNUSED));
    2527          704 :                           call_flags = callee_to_caller_flags
    2528          704 :                                            (call_flags, false,
    2529              :                                             m_lattice[index]);
    2530              :                         }
    2531        13264 :                       m_lattice[index].merge (call_flags);
    2532              :                     }
    2533              :                 }
    2534              : 
    2535      5861902 :               if (gimple_call_chain (call)
    2536      5861902 :                   && (gimple_call_chain (call) == name))
    2537              :                 {
    2538        27729 :                   int call_flags = gimple_call_static_chain_flags (call);
    2539        27729 :                   if (!ignore_retval && !(call_flags & EAF_UNUSED))
    2540        27729 :                     merge_call_lhs_flags
    2541        27729 :                          (call, -1, name,
    2542        27729 :                           !(call_flags & EAF_NOT_RETURNED_DIRECTLY),
    2543        27729 :                           !(call_flags & EAF_NOT_RETURNED_INDIRECTLY));
    2544        27729 :                   call_flags = callee_to_caller_flags
    2545        27729 :                                    (call_flags, ignore_stores,
    2546              :                                     m_lattice[index]);
    2547        27729 :                   if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
    2548        27729 :                     m_lattice[index].merge (call_flags);
    2549              :                 }
    2550              : 
    2551              :               /* Process internal functions and right away.  */
    2552      5861902 :               bool record_ipa = m_ipa && !gimple_call_internal_p (call);
    2553              : 
    2554              :               /* Handle all function parameters.  */
    2555     21902115 :               for (unsigned i = 0;
    2556     21902115 :                    i < gimple_call_num_args (call)
    2557     21902115 :                    && m_lattice[index].flags; i++)
    2558              :                 /* Name is directly passed to the callee.  */
    2559     16040213 :                 if (gimple_call_arg (call, i) == name)
    2560              :                   {
    2561      5688211 :                     int call_flags = gimple_call_arg_flags (call, i);
    2562      5688211 :                     if (!ignore_retval)
    2563      5645431 :                       merge_call_lhs_flags
    2564      5645431 :                               (call, i, name,
    2565      5645431 :                                !(call_flags & (EAF_NOT_RETURNED_DIRECTLY
    2566              :                                                | EAF_UNUSED)),
    2567      5645431 :                                !(call_flags & (EAF_NOT_RETURNED_INDIRECTLY
    2568              :                                                | EAF_UNUSED)));
    2569      5688211 :                     if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
    2570              :                       {
    2571      5035277 :                         call_flags = callee_to_caller_flags
    2572      5035277 :                                          (call_flags, ignore_stores,
    2573              :                                           m_lattice[index]);
    2574      5035277 :                         if (!record_ipa)
    2575      3440657 :                           m_lattice[index].merge (call_flags);
    2576              :                         else
    2577      1594620 :                           m_lattice[index].add_escape_point (call, i,
    2578              :                                                            call_flags, true);
    2579              :                       }
    2580              :                   }
    2581              :                 /* Name is dereferenced and passed to a callee.  */
    2582     10352002 :                 else if (memory_access_to (gimple_call_arg (call, i), name))
    2583              :                   {
    2584        69043 :                     int call_flags = deref_flags
    2585        69043 :                             (gimple_call_arg_flags (call, i), ignore_stores);
    2586        69043 :                     if (!ignore_retval && !(call_flags & EAF_UNUSED)
    2587        69021 :                         && (call_flags & (EAF_NOT_RETURNED_DIRECTLY
    2588              :                                           | EAF_NOT_RETURNED_INDIRECTLY))
    2589              :                             != (EAF_NOT_RETURNED_DIRECTLY
    2590              :                                 | EAF_NOT_RETURNED_INDIRECTLY))
    2591        69021 :                       merge_call_lhs_flags (call, i, name, false, true);
    2592        69043 :                     if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
    2593          157 :                       m_lattice[index].merge_direct_load ();
    2594              :                     else
    2595              :                       {
    2596        68886 :                         call_flags = callee_to_caller_flags
    2597        68886 :                                          (call_flags, ignore_stores,
    2598              :                                           m_lattice[index]);
    2599        68886 :                         if (!record_ipa)
    2600        44558 :                           m_lattice[index].merge (call_flags);
    2601              :                         else
    2602        24328 :                           m_lattice[index].add_escape_point (call, i,
    2603              :                                                              call_flags, false);
    2604              :                       }
    2605              :                   }
    2606              :             }
    2607              :         }
    2608     26271412 :       else if (gimple_assign_load_p (use_stmt))
    2609              :         {
    2610      6051499 :           gassign *assign = as_a <gassign *> (use_stmt);
    2611              :           /* Memory to memory copy.  */
    2612      6051499 :           if (gimple_store_p (assign))
    2613              :             {
    2614              :               /* Handle *lhs = *name.
    2615              : 
    2616              :                  We do not track memory locations, so assume that value
    2617              :                  is used arbitrarily.  */
    2618       325538 :               if (memory_access_to (gimple_assign_rhs1 (assign), name))
    2619       218256 :                 m_lattice[index].merge (deref_flags (0, false));
    2620              : 
    2621              :               /* Handle *name = *exp.  */
    2622       325538 :               if (memory_access_to (gimple_assign_lhs (assign), name))
    2623       106913 :                 m_lattice[index].merge_direct_store ();
    2624              :             }
    2625              :           /* Handle lhs = *name.  */
    2626      5725961 :           else if (memory_access_to (gimple_assign_rhs1 (assign), name))
    2627              :             {
    2628      5584136 :               tree lhs = gimple_assign_lhs (assign);
    2629      5584136 :               merge_with_ssa_name (name, lhs, true);
    2630              :             }
    2631              :         }
    2632     20219913 :       else if (gimple_store_p (use_stmt))
    2633              :         {
    2634      4548447 :           gassign *assign = dyn_cast <gassign *> (use_stmt);
    2635              : 
    2636              :           /* Handle *lhs = name.  */
    2637      4548447 :           if (assign && gimple_assign_rhs1 (assign) == name)
    2638              :             {
    2639      1830791 :               if (dump_file)
    2640           63 :                 fprintf (dump_file, "%*s  ssa name saved to memory\n",
    2641           63 :                          m_depth * 4, "");
    2642      1830791 :               m_lattice[index].merge (0);
    2643              :             }
    2644              :           /* Handle *name = exp.  */
    2645      2717656 :           else if (assign
    2646      2717656 :                    && memory_access_to (gimple_assign_lhs (assign), name))
    2647              :             {
    2648              :               /* In general we can not ignore clobbers because they are
    2649              :                  barriers for code motion, however after inlining it is safe to
    2650              :                  do because local optimization passes do not consider clobbers
    2651              :                  from other functions.
    2652              :                  Similar logic is in ipa-pure-const.cc.  */
    2653      2651622 :               if (!cfun->after_inlining || !gimple_clobber_p (assign))
    2654      2606981 :                 m_lattice[index].merge_direct_store ();
    2655              :             }
    2656              :           /* ASM statements etc.  */
    2657        66034 :           else if (!assign)
    2658              :             {
    2659            0 :               if (dump_file)
    2660            0 :                 fprintf (dump_file, "%*s  Unhandled store\n", m_depth * 4, "");
    2661            0 :               m_lattice[index].merge (0);
    2662              :             }
    2663              :         }
    2664     15671466 :       else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
    2665              :         {
    2666      9810137 :           enum tree_code code = gimple_assign_rhs_code (assign);
    2667              : 
    2668              :           /* See if operation is a merge as considered by
    2669              :              tree-ssa-structalias.cc:find_func_aliases.  */
    2670      9810137 :           if (!truth_value_p (code)
    2671      9253381 :               && code != POINTER_DIFF_EXPR
    2672     18841492 :               && (code != POINTER_PLUS_EXPR
    2673      1354975 :                   || gimple_assign_rhs1 (assign) == name))
    2674              :             {
    2675      8575641 :               tree lhs = gimple_assign_lhs (assign);
    2676      8575641 :               merge_with_ssa_name (name, lhs, false);
    2677              :             }
    2678              :         }
    2679      5861329 :       else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
    2680              :         {
    2681      2073918 :           tree result = gimple_phi_result (phi);
    2682      2073918 :           merge_with_ssa_name (name, result, false);
    2683              :         }
    2684              :       /* Conditions are not considered escape points
    2685              :          by tree-ssa-structalias.  */
    2686      3787411 :       else if (gimple_code (use_stmt) == GIMPLE_COND)
    2687              :         ;
    2688              :       else
    2689              :         {
    2690        73499 :           if (dump_file)
    2691            6 :             fprintf (dump_file, "%*s  Unhandled stmt\n", m_depth * 4, "");
    2692        73499 :           m_lattice[index].merge (0);
    2693              :         }
    2694              : 
    2695     33467231 :       if (dump_file)
    2696              :         {
    2697         1480 :           fprintf (dump_file, "%*s  current flags of ", m_depth * 4, "");
    2698         1480 :           print_generic_expr (dump_file, name);
    2699         1480 :           m_lattice[index].dump (dump_file, m_depth * 4 + 4);
    2700              :         }
    2701     23005221 :     }
    2702     23005221 :   if (dump_file)
    2703              :     {
    2704         1139 :       fprintf (dump_file, "%*sflags of ssa name ", m_depth * 4, "");
    2705         1139 :       print_generic_expr (dump_file, name);
    2706         1139 :       m_lattice[index].dump (dump_file, m_depth * 4 + 2);
    2707              :     }
    2708     23005221 :   m_lattice[index].open = false;
    2709     23005221 :   if (!m_lattice[index].do_dataflow)
    2710     20772801 :     m_lattice[index].known = true;
    2711              : }
    2712              : 
    2713              : /* Propagate info from SRC to DEST.  If DEREF it true, assume that SRC
    2714              :    is dereferenced.  */
    2715              : 
    2716              : void
    2717     20559095 : modref_eaf_analysis::merge_with_ssa_name (tree dest, tree src, bool deref)
    2718              : {
    2719     20559095 :   int index = SSA_NAME_VERSION (dest);
    2720     20559095 :   int src_index = SSA_NAME_VERSION (src);
    2721              : 
    2722              :   /* Merging lattice with itself is a no-op.  */
    2723     20559095 :   if (!deref && src == dest)
    2724           38 :     return;
    2725              : 
    2726     20559057 :   m_depth++;
    2727     20559057 :   analyze_ssa_name (src);
    2728     20559057 :   m_depth--;
    2729     20559057 :   if (deref)
    2730      7597228 :     m_lattice[index].merge_deref (m_lattice[src_index], false);
    2731              :   else
    2732     12961829 :     m_lattice[index].merge (m_lattice[src_index]);
    2733              : 
    2734              :   /* If we failed to produce final solution add an edge to the dataflow
    2735              :      graph.  */
    2736     20559057 :   if (!m_lattice[src_index].known)
    2737              :     {
    2738      2763598 :       modref_lattice::propagate_edge e = {index, deref};
    2739              : 
    2740      2763598 :       if (!m_lattice[src_index].propagate_to.length ())
    2741      1983264 :         m_names_to_propagate.safe_push (src_index);
    2742      2763598 :       m_lattice[src_index].propagate_to.safe_push (e);
    2743      2763598 :       m_lattice[src_index].changed = true;
    2744      2763598 :       m_lattice[src_index].do_dataflow = true;
    2745      2763598 :       if (dump_file)
    2746          135 :         fprintf (dump_file,
    2747              :                  "%*sWill propgate from ssa_name %i to %i%s\n",
    2748          135 :                  m_depth * 4 + 4,
    2749              :                  "", src_index, index, deref ? " (deref)" : "");
    2750              :     }
    2751              : }
    2752              : 
    2753              : /* In the case we deferred some SSA names, reprocess them.  In the case some
    2754              :    dataflow edges were introduced, do the actual iterative dataflow.  */
    2755              : 
    2756              : void
    2757      4039755 : modref_eaf_analysis::propagate ()
    2758              : {
    2759      4039755 :   int iterations = 0;
    2760      4039755 :   size_t i;
    2761      4039755 :   int index;
    2762      4039755 :   bool changed = true;
    2763              : 
    2764      4042456 :   while (m_deferred_names.length ())
    2765              :     {
    2766         2701 :       tree name = m_deferred_names.pop ();
    2767         2701 :       if (dump_file)
    2768            0 :         fprintf (dump_file, "Analyzing deferred SSA name\n");
    2769         2701 :       analyze_ssa_name (name, true);
    2770              :     }
    2771              : 
    2772      4039755 :   if (!m_names_to_propagate.length ())
    2773      3857154 :     return;
    2774       182601 :   if (dump_file)
    2775           41 :     fprintf (dump_file, "Propagating EAF flags\n");
    2776              : 
    2777              :   /* Compute reverse postorder.  */
    2778       182601 :   auto_vec <int> rpo;
    2779       182601 :   struct stack_entry
    2780              :   {
    2781              :     int name;
    2782              :     unsigned pos;
    2783              :   };
    2784       182601 :   auto_vec <struct stack_entry> stack;
    2785       182601 :   int pos = m_names_to_propagate.length () - 1;
    2786              : 
    2787       182601 :   rpo.safe_grow (m_names_to_propagate.length (), true);
    2788       365202 :   stack.reserve_exact (m_names_to_propagate.length ());
    2789              : 
    2790              :   /* We reuse known flag for RPO DFS walk bookkeeping.  */
    2791       182601 :   if (flag_checking)
    2792      2165775 :     FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
    2793      1983189 :       gcc_assert (!m_lattice[index].known && m_lattice[index].changed);
    2794              : 
    2795      2165865 :   FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
    2796              :     {
    2797      1983264 :       if (!m_lattice[index].known)
    2798              :         {
    2799       352479 :           stack_entry e = {index, 0};
    2800              : 
    2801       352479 :           stack.quick_push (e);
    2802       352479 :           m_lattice[index].known = true;
    2803              :         }
    2804      5597313 :       while (stack.length ())
    2805              :         {
    2806      3614049 :           bool found = false;
    2807      3614049 :           int index1 = stack.last ().name;
    2808              : 
    2809      4746862 :           while (stack.last ().pos < m_lattice[index1].propagate_to.length ())
    2810              :             {
    2811      2763598 :               int index2 = m_lattice[index1]
    2812      2763598 :                       .propagate_to[stack.last ().pos].ssa_name;
    2813              : 
    2814      2763598 :               stack.last ().pos++;
    2815      2763598 :               if (!m_lattice[index2].known
    2816      3896411 :                   && m_lattice[index2].propagate_to.length ())
    2817              :                 {
    2818      1630785 :                   stack_entry e = {index2, 0};
    2819              : 
    2820      1630785 :                   stack.quick_push (e);
    2821      1630785 :                   m_lattice[index2].known = true;
    2822      1630785 :                   found = true;
    2823      1630785 :                   break;
    2824              :                 }
    2825              :             }
    2826      1630785 :           if (!found
    2827      3966528 :               && stack.last ().pos == m_lattice[index1].propagate_to.length ())
    2828              :             {
    2829      1983264 :               rpo[pos--] = index1;
    2830      1983264 :               stack.pop ();
    2831              :             }
    2832              :         }
    2833              :     }
    2834              : 
    2835              :   /* Perform iterative dataflow.  */
    2836       463000 :   while (changed)
    2837              :     {
    2838       280399 :       changed = false;
    2839       280399 :       iterations++;
    2840       280399 :       if (dump_file)
    2841           43 :         fprintf (dump_file, " iteration %i\n", iterations);
    2842      4097806 :       FOR_EACH_VEC_ELT (rpo, i, index)
    2843              :         {
    2844      3354407 :           if (m_lattice[index].changed)
    2845              :             {
    2846      2011277 :               size_t j;
    2847              : 
    2848      2011277 :               m_lattice[index].changed = false;
    2849      2011277 :               if (dump_file)
    2850           96 :                 fprintf (dump_file, "  Visiting ssa name %i\n", index);
    2851      6160611 :               for (j = 0; j < m_lattice[index].propagate_to.length (); j++)
    2852              :                 {
    2853      2806204 :                   bool ch;
    2854      2806204 :                   int target = m_lattice[index].propagate_to[j].ssa_name;
    2855      2806204 :                   bool deref = m_lattice[index].propagate_to[j].deref;
    2856              : 
    2857      2806204 :                   if (dump_file)
    2858          274 :                     fprintf (dump_file, "   Propagating flags of ssa name"
    2859              :                              " %i to %i%s\n",
    2860              :                              index, target, deref ? " (deref)" : "");
    2861      2806204 :                   m_lattice[target].known = true;
    2862      2806204 :                   if (!m_lattice[index].propagate_to[j].deref)
    2863      2416773 :                     ch = m_lattice[target].merge (m_lattice[index]);
    2864              :                   else
    2865       389431 :                     ch = m_lattice[target].merge_deref (m_lattice[index],
    2866              :                                                         false);
    2867      2806204 :                   if (!ch)
    2868      2492255 :                     continue;
    2869       313949 :                   if (dump_file)
    2870              :                     {
    2871            4 :                       fprintf (dump_file, "   New lattice: ");
    2872            4 :                       m_lattice[target].dump (dump_file);
    2873              :                     }
    2874       313949 :                   changed = true;
    2875       313949 :                   m_lattice[target].changed = true;
    2876              :                 }
    2877              :             }
    2878              :         }
    2879              :     }
    2880       182601 :   if (dump_file)
    2881           41 :     fprintf (dump_file, "EAF flags propagated in %i iterations\n", iterations);
    2882       182601 : }
    2883              : 
    2884              : /* Record escape points of PARM_INDEX according to LATTICE.  */
    2885              : 
    2886              : void
    2887      3402381 : modref_eaf_analysis::record_escape_points (tree name, int parm_index, int flags)
    2888              : {
    2889      3402381 :   modref_lattice &lattice = m_lattice[SSA_NAME_VERSION (name)];
    2890              : 
    2891      3402381 :   if (lattice.escape_points.length ())
    2892              :     {
    2893       192585 :       escape_point *ep;
    2894       192585 :       unsigned int ip;
    2895       192585 :       cgraph_node *node = cgraph_node::get (current_function_decl);
    2896              : 
    2897       192585 :       gcc_assert (m_ipa);
    2898       490493 :       FOR_EACH_VEC_ELT (lattice.escape_points, ip, ep)
    2899       297908 :         if ((ep->min_flags & flags) != flags)
    2900              :           {
    2901       250119 :             cgraph_edge *e = node->get_edge (ep->call);
    2902       250119 :             struct escape_entry ee = {parm_index, ep->arg,
    2903       250119 :                                       ep->min_flags, ep->direct};
    2904              : 
    2905       250119 :             escape_summaries->get_create (e)->esc.safe_push (ee);
    2906              :           }
    2907              :     }
    2908      3402381 : }
    2909              : 
    2910              : /* Determine EAF flags for function parameters
    2911              :    and fill in SUMMARY/SUMMARY_LTO.  If IPA is true work in IPA mode
    2912              :    where we also collect escape points.
    2913              :    PAST_FLAGS, PAST_RETSLOT_FLAGS, PAST_STATIC_CHAIN_FLAGS can be
    2914              :    used to preserve flags from previous (IPA) run for cases where
    2915              :    late optimizations changed code in a way we can no longer analyze
    2916              :    it easily.  */
    2917              : 
    2918              : static void
    2919      4749635 : analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
    2920              :                bool ipa, vec<eaf_flags_t> &past_flags,
    2921              :                int past_retslot_flags, int past_static_chain_flags)
    2922              : {
    2923      4749635 :   unsigned int parm_index = 0;
    2924      4749635 :   unsigned int count = 0;
    2925      4749635 :   int ecf_flags = flags_from_decl_or_type (current_function_decl);
    2926      4749635 :   tree retslot = NULL;
    2927      4749635 :   tree static_chain = NULL;
    2928              : 
    2929              :   /* If there is return slot, look up its SSA name.  */
    2930      4749635 :   if (DECL_RESULT (current_function_decl)
    2931      4749635 :       && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
    2932        64248 :     retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
    2933      4749635 :   if (cfun->static_chain_decl)
    2934        48726 :     static_chain = ssa_default_def (cfun, cfun->static_chain_decl);
    2935              : 
    2936     14982128 :   for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
    2937     10232493 :        parm = TREE_CHAIN (parm))
    2938     10232493 :     count++;
    2939              : 
    2940      4749635 :   if (!count && !retslot && !static_chain)
    2941       709880 :     return;
    2942              : 
    2943      4039755 :   modref_eaf_analysis eaf_analysis (ipa);
    2944              : 
    2945              :   /* Determine all SSA names we need to know flags for.  */
    2946     14272248 :   for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
    2947     10232493 :        parm = TREE_CHAIN (parm))
    2948              :     {
    2949     10232493 :       tree name = ssa_default_def (cfun, parm);
    2950     10232493 :       if (name)
    2951      6987157 :         eaf_analysis.analyze_ssa_name (name);
    2952              :     }
    2953      4039755 :   if (retslot)
    2954        64061 :     eaf_analysis.analyze_ssa_name (retslot);
    2955      4039755 :   if (static_chain)
    2956        48524 :     eaf_analysis.analyze_ssa_name (static_chain);
    2957              : 
    2958              :   /* Do the dataflow.  */
    2959      4039755 :   eaf_analysis.propagate ();
    2960              : 
    2961      4039755 :   tree attr = lookup_attribute ("fn spec",
    2962      4039755 :                                 TYPE_ATTRIBUTES
    2963              :                                   (TREE_TYPE (current_function_decl)));
    2964      4039755 :   attr_fnspec fnspec (attr
    2965       107813 :                       ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)))
    2966      4147568 :                       : "");
    2967              : 
    2968              : 
    2969              :   /* Store results to summaries.  */
    2970     14272248 :   for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
    2971     10232493 :        parm = TREE_CHAIN (parm))
    2972              :     {
    2973     10232493 :       tree name = ssa_default_def (cfun, parm);
    2974     10232493 :       if (!name || has_zero_uses (name))
    2975              :         {
    2976              :           /* We do not track non-SSA parameters,
    2977              :              but we want to track unused gimple_regs.  */
    2978      3521876 :           if (!is_gimple_reg (parm))
    2979       680039 :             continue;
    2980      2841837 :           if (summary)
    2981              :             {
    2982      2733419 :               if (parm_index >= summary->arg_flags.length ())
    2983       652670 :                 summary->arg_flags.safe_grow_cleared (count, true);
    2984      2733419 :               summary->arg_flags[parm_index] = EAF_UNUSED;
    2985              :             }
    2986      2841837 :           if (summary_lto)
    2987              :             {
    2988       218143 :               if (parm_index >= summary_lto->arg_flags.length ())
    2989         9902 :                 summary_lto->arg_flags.safe_grow_cleared (count, true);
    2990       218143 :               summary_lto->arg_flags[parm_index] = EAF_UNUSED;
    2991              :             }
    2992      2841837 :           continue;
    2993              :         }
    2994      6710617 :       int flags = eaf_analysis.get_ssa_name_flags (name);
    2995      6710617 :       int attr_flags = fnspec.arg_eaf_flags (parm_index);
    2996              : 
    2997      6710617 :       if (dump_file && (flags | attr_flags) != flags && !(flags & EAF_UNUSED))
    2998              :         {
    2999            0 :           fprintf (dump_file,
    3000              :                    "  Flags for param %i combined with fnspec flags:",
    3001              :                    (int)parm_index);
    3002            0 :           dump_eaf_flags (dump_file, attr_flags, false);
    3003            0 :           fprintf (dump_file, " determined: ");
    3004            0 :           dump_eaf_flags (dump_file, flags, true);
    3005              :         }
    3006      6710617 :       flags |= attr_flags;
    3007              : 
    3008              :       /* Eliminate useless flags so we do not end up storing unnecessary
    3009              :          summaries.  */
    3010              : 
    3011      6710617 :       flags = remove_useless_eaf_flags
    3012      6710617 :                  (flags, ecf_flags,
    3013      6710617 :                   VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
    3014      6710617 :       if (past_flags.length () > parm_index)
    3015              :         {
    3016       682337 :           int past = past_flags[parm_index];
    3017       682337 :           past = remove_useless_eaf_flags
    3018       682337 :                      (past, ecf_flags,
    3019       682337 :                       VOID_TYPE_P (TREE_TYPE
    3020              :                           (TREE_TYPE (current_function_decl))));
    3021              :           /* Store merging can produce reads when combining together multiple
    3022              :              bitfields.  See PR111613.  */
    3023       682337 :           past &= ~(EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ);
    3024       682337 :           if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
    3025              :             {
    3026           24 :               fprintf (dump_file,
    3027              :                        "  Flags for param %i combined with IPA pass:",
    3028              :                        (int)parm_index);
    3029           24 :               dump_eaf_flags (dump_file, past, false);
    3030           24 :               fprintf (dump_file, " determined: ");
    3031           24 :               dump_eaf_flags (dump_file, flags, true);
    3032              :             }
    3033       682337 :           if (!(flags & EAF_UNUSED))
    3034       682337 :             flags |= past;
    3035              :         }
    3036              : 
    3037      6710617 :       if (flags)
    3038              :         {
    3039      3308566 :           if (summary)
    3040              :             {
    3041      3281279 :               if (parm_index >= summary->arg_flags.length ())
    3042      2062370 :                 summary->arg_flags.safe_grow_cleared (count, true);
    3043      3281279 :               summary->arg_flags[parm_index] = flags;
    3044              :             }
    3045      3308566 :           if (summary_lto)
    3046              :             {
    3047        62205 :               if (parm_index >= summary_lto->arg_flags.length ())
    3048        43972 :                 summary_lto->arg_flags.safe_grow_cleared (count, true);
    3049        62205 :               summary_lto->arg_flags[parm_index] = flags;
    3050              :             }
    3051      3308566 :           eaf_analysis.record_escape_points (name, parm_index, flags);
    3052              :         }
    3053              :     }
    3054      4039755 :   if (retslot)
    3055              :     {
    3056        64061 :       int flags = eaf_analysis.get_ssa_name_flags (retslot);
    3057        64061 :       int past = past_retslot_flags;
    3058              : 
    3059        64061 :       flags = remove_useless_eaf_flags (flags, ecf_flags, false);
    3060        64061 :       past = remove_useless_eaf_flags
    3061        64061 :                  (past, ecf_flags,
    3062        64061 :                   VOID_TYPE_P (TREE_TYPE
    3063              :                       (TREE_TYPE (current_function_decl))));
    3064        64061 :       if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
    3065              :         {
    3066            0 :           fprintf (dump_file,
    3067              :                    "  Retslot flags combined with IPA pass:");
    3068            0 :           dump_eaf_flags (dump_file, past, false);
    3069            0 :           fprintf (dump_file, " determined: ");
    3070            0 :           dump_eaf_flags (dump_file, flags, true);
    3071              :         }
    3072        64061 :       if (!(flags & EAF_UNUSED))
    3073        63974 :         flags |= past;
    3074        63974 :       if (flags)
    3075              :         {
    3076        46906 :           if (summary)
    3077        46762 :             summary->retslot_flags = flags;
    3078        46906 :           if (summary_lto)
    3079          288 :             summary_lto->retslot_flags = flags;
    3080        46906 :           eaf_analysis.record_escape_points (retslot,
    3081              :                                              MODREF_RETSLOT_PARM, flags);
    3082              :         }
    3083              :     }
    3084      4039755 :   if (static_chain)
    3085              :     {
    3086        48524 :       int flags = eaf_analysis.get_ssa_name_flags (static_chain);
    3087        48524 :       int past = past_static_chain_flags;
    3088              : 
    3089        48524 :       flags = remove_useless_eaf_flags (flags, ecf_flags, false);
    3090        48524 :       past = remove_useless_eaf_flags
    3091        48524 :                  (past, ecf_flags,
    3092        48524 :                   VOID_TYPE_P (TREE_TYPE
    3093              :                       (TREE_TYPE (current_function_decl))));
    3094        48524 :       if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
    3095              :         {
    3096            0 :           fprintf (dump_file,
    3097              :                    "  Static chain flags combined with IPA pass:");
    3098            0 :           dump_eaf_flags (dump_file, past, false);
    3099            0 :           fprintf (dump_file, " determined: ");
    3100            0 :           dump_eaf_flags (dump_file, flags, true);
    3101              :         }
    3102        48524 :       if (!(flags & EAF_UNUSED))
    3103        48438 :         flags |= past;
    3104        48438 :       if (flags)
    3105              :         {
    3106        46909 :           if (summary)
    3107        46835 :             summary->static_chain_flags = flags;
    3108        46909 :           if (summary_lto)
    3109          152 :             summary_lto->static_chain_flags = flags;
    3110        46909 :           eaf_analysis.record_escape_points (static_chain,
    3111              :                                              MODREF_STATIC_CHAIN_PARM,
    3112              :                                              flags);
    3113              :         }
    3114              :     }
    3115      4039755 : }
    3116              : 
    3117              : /* Analyze function.  IPA indicates whether we're running in local mode
    3118              :    (false) or the IPA mode (true).
    3119              :    Return true if fixup cfg is needed after the pass.  */
    3120              : 
    3121              : static bool
    3122      5231636 : analyze_function (bool ipa)
    3123              : {
    3124      5231636 :   bool fixup_cfg = false;
    3125      5231636 :   if (dump_file)
    3126          189 :     fprintf (dump_file, "\n\nmodref analyzing '%s' (ipa=%i)%s%s\n",
    3127          189 :              cgraph_node::get (current_function_decl)->dump_name (), ipa,
    3128          189 :              TREE_READONLY (current_function_decl) ? " (const)" : "",
    3129          189 :              DECL_PURE_P (current_function_decl) ? " (pure)" : "");
    3130              : 
    3131              :   /* Don't analyze this function if it's compiled with -fno-strict-aliasing.  */
    3132      5231636 :   if (!flag_ipa_modref
    3133      5231636 :       || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
    3134       482001 :     return false;
    3135              : 
    3136              :   /* Compute no-LTO summaries when local optimization is going to happen.  */
    3137      1335034 :   bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
    3138      4790983 :                 || (in_lto_p && !flag_wpa
    3139          940 :                     && flag_incremental_link != INCREMENTAL_LINK_LTO));
    3140              :   /* Compute LTO when LTO streaming is going to happen.  */
    3141      1335034 :   bool lto = ipa && ((flag_lto && !in_lto_p)
    3142      1242313 :                      || flag_wpa
    3143      1242238 :                      || flag_incremental_link == INCREMENTAL_LINK_LTO);
    3144      4749635 :   cgraph_node *fnode = cgraph_node::get (current_function_decl);
    3145              : 
    3146      4749635 :   modref_summary *summary = NULL;
    3147      4749635 :   modref_summary_lto *summary_lto = NULL;
    3148              : 
    3149      4749635 :   bool past_flags_known = false;
    3150      4749635 :   auto_vec <eaf_flags_t> past_flags;
    3151      4749635 :   int past_retslot_flags = 0;
    3152      4749635 :   int past_static_chain_flags = 0;
    3153              : 
    3154              :   /* Initialize the summary.
    3155              :      If we run in local mode there is possibly pre-existing summary from
    3156              :      IPA pass.  Dump it so it is easy to compare if mod-ref info has
    3157              :      improved.  */
    3158      4749635 :   if (!ipa)
    3159              :     {
    3160      3414601 :       if (!optimization_summaries)
    3161       142055 :         optimization_summaries = modref_summaries::create_ggc (symtab);
    3162              :       else /* Remove existing summary if we are re-running the pass.  */
    3163              :         {
    3164      3272546 :           summary = optimization_summaries->get (fnode);
    3165      3272546 :           if (summary != NULL
    3166       736209 :               && summary->loads)
    3167              :             {
    3168       736209 :               if (dump_file)
    3169              :                 {
    3170           23 :                   fprintf (dump_file, "Past summary:\n");
    3171           23 :                   optimization_summaries->get (fnode)->dump (dump_file);
    3172              :                 }
    3173      1182255 :               past_flags.reserve_exact (summary->arg_flags.length ());
    3174       736209 :               past_flags.splice (summary->arg_flags);
    3175       736209 :               past_retslot_flags = summary->retslot_flags;
    3176       736209 :               past_static_chain_flags = summary->static_chain_flags;
    3177       736209 :               past_flags_known = true;
    3178              :             }
    3179      3272546 :           optimization_summaries->remove (fnode);
    3180              :         }
    3181      3414601 :       summary = optimization_summaries->get_create (fnode);
    3182      3414601 :       gcc_checking_assert (nolto && !lto);
    3183              :     }
    3184              :   /* In IPA mode we analyze every function precisely once.  Assert that.  */
    3185              :   else
    3186              :     {
    3187      1335034 :       if (nolto)
    3188              :         {
    3189      1294626 :           if (!summaries)
    3190       133022 :             summaries = modref_summaries::create_ggc (symtab);
    3191              :           else
    3192      1161604 :             summaries->remove (fnode);
    3193      1294626 :           summary = summaries->get_create (fnode);
    3194              :         }
    3195      1335034 :       if (lto)
    3196              :         {
    3197        92796 :           if (!summaries_lto)
    3198        19528 :             summaries_lto = modref_summaries_lto::create_ggc (symtab);
    3199              :           else
    3200        73268 :             summaries_lto->remove (fnode);
    3201        92796 :           summary_lto = summaries_lto->get_create (fnode);
    3202              :         }
    3203      1335034 :       if (!fnspec_summaries)
    3204       141948 :         fnspec_summaries = new fnspec_summaries_t (symtab);
    3205      1335034 :       if (!escape_summaries)
    3206       141948 :         escape_summaries = new escape_summaries_t (symtab);
    3207              :      }
    3208              : 
    3209              : 
    3210              :   /* Create and initialize summary for F.
    3211              :      Note that summaries may be already allocated from previous
    3212              :      run of the pass.  */
    3213      1335034 :   if (nolto)
    3214              :     {
    3215      4709227 :       gcc_assert (!summary->loads);
    3216      4709227 :       summary->loads = modref_records::create_ggc ();
    3217      4709227 :       gcc_assert (!summary->stores);
    3218      4709227 :       summary->stores = modref_records::create_ggc ();
    3219      4709227 :       summary->writes_errno = false;
    3220      4709227 :       summary->side_effects = false;
    3221      4709227 :       summary->nondeterministic = false;
    3222      4709227 :       summary->calls_interposable = false;
    3223              :     }
    3224      4749635 :   if (lto)
    3225              :     {
    3226        92796 :       gcc_assert (!summary_lto->loads);
    3227        92796 :       summary_lto->loads = modref_records_lto::create_ggc ();
    3228        92796 :       gcc_assert (!summary_lto->stores);
    3229        92796 :       summary_lto->stores = modref_records_lto::create_ggc ();
    3230        92796 :       summary_lto->writes_errno = false;
    3231        92796 :       summary_lto->side_effects = false;
    3232        92796 :       summary_lto->nondeterministic = false;
    3233        92796 :       summary_lto->calls_interposable = false;
    3234              :     }
    3235              : 
    3236      4749635 :   analyze_parms (summary, summary_lto, ipa,
    3237              :                  past_flags, past_retslot_flags, past_static_chain_flags);
    3238              : 
    3239      4749635 :   {
    3240      4749635 :     modref_access_analysis analyzer (ipa, summary, summary_lto);
    3241      4749635 :     analyzer.analyze ();
    3242      4749635 :   }
    3243              : 
    3244      4749635 :   if (!ipa && flag_ipa_pure_const)
    3245              :     {
    3246      3414466 :       if (!summary->stores->every_base && !summary->stores->bases
    3247      1125676 :           && !summary->nondeterministic)
    3248              :         {
    3249      1095600 :           if (!summary->loads->every_base && !summary->loads->bases
    3250       668342 :               && !summary->calls_interposable)
    3251       665322 :             fixup_cfg = ipa_make_function_const (fnode,
    3252              :                                                  summary->side_effects, true);
    3253              :           else
    3254       430278 :             fixup_cfg = ipa_make_function_pure (fnode,
    3255              :                                                 summary->side_effects, true);
    3256              :         }
    3257              :     }
    3258      4749635 :   int ecf_flags = flags_from_decl_or_type (current_function_decl);
    3259      4749635 :   if (summary && !summary->useful_p (ecf_flags))
    3260              :     {
    3261      1132678 :       if (!ipa)
    3262       989564 :         optimization_summaries->remove (fnode);
    3263              :       else
    3264       143114 :         summaries->remove (fnode);
    3265              :       summary = NULL;
    3266              :     }
    3267      3616957 :   if (summary)
    3268      3576549 :     summary->finalize (current_function_decl);
    3269      4749635 :   if (summary_lto && !summary_lto->useful_p (ecf_flags))
    3270              :     {
    3271         9856 :       summaries_lto->remove (fnode);
    3272         9856 :       summary_lto = NULL;
    3273              :     }
    3274              : 
    3275      4749635 :   if (ipa && !summary && !summary_lto)
    3276       147561 :     remove_modref_edge_summaries (fnode);
    3277              : 
    3278      4749635 :   if (dump_file)
    3279              :     {
    3280          154 :       fprintf (dump_file, " - modref done with result: tracked.\n");
    3281          154 :       if (summary)
    3282          128 :         summary->dump (dump_file);
    3283          154 :       if (summary_lto)
    3284           14 :         summary_lto->dump (dump_file);
    3285          154 :       dump_modref_edge_summaries (dump_file, fnode, 2);
    3286              :       /* To simplify debugging, compare IPA and local solutions.  */
    3287          154 :       if (past_flags_known && summary)
    3288              :         {
    3289           23 :           size_t len = summary->arg_flags.length ();
    3290              : 
    3291           23 :           if (past_flags.length () > len)
    3292            0 :             len = past_flags.length ();
    3293          107 :           for (size_t i = 0; i < len; i++)
    3294              :             {
    3295           84 :               int old_flags = i < past_flags.length () ? past_flags[i] : 0;
    3296           84 :               int new_flags = i < summary->arg_flags.length ()
    3297           84 :                               ? summary->arg_flags[i] : 0;
    3298           84 :               old_flags = remove_useless_eaf_flags
    3299          168 :                 (old_flags, flags_from_decl_or_type (current_function_decl),
    3300           84 :                  VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
    3301           84 :               if (old_flags != new_flags)
    3302              :                 {
    3303            0 :                   if ((old_flags & ~new_flags) == 0
    3304            0 :                       || (new_flags & EAF_UNUSED))
    3305            0 :                     fprintf (dump_file, "  Flags for param %i improved:",
    3306              :                              (int)i);
    3307              :                   else
    3308            0 :                     fprintf (dump_file, "  Flags for param %i changed:",
    3309              :                              (int)i);
    3310            0 :                   dump_eaf_flags (dump_file, old_flags, false);
    3311            0 :                   fprintf (dump_file, " -> ");
    3312            0 :                   dump_eaf_flags (dump_file, new_flags, true);
    3313              :                 }
    3314              :             }
    3315           23 :           past_retslot_flags = remove_useless_eaf_flags
    3316           46 :                 (past_retslot_flags,
    3317              :                  flags_from_decl_or_type (current_function_decl),
    3318           23 :                  VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
    3319           23 :           if (past_retslot_flags != summary->retslot_flags)
    3320              :             {
    3321            0 :               if ((past_retslot_flags & ~summary->retslot_flags) == 0
    3322            0 :                   || (summary->retslot_flags & EAF_UNUSED))
    3323            0 :                 fprintf (dump_file, "  Flags for retslot improved:");
    3324              :               else
    3325            0 :                 fprintf (dump_file, "  Flags for retslot changed:");
    3326            0 :               dump_eaf_flags (dump_file, past_retslot_flags, false);
    3327            0 :               fprintf (dump_file, " -> ");
    3328            0 :               dump_eaf_flags (dump_file, summary->retslot_flags, true);
    3329              :             }
    3330           23 :           past_static_chain_flags = remove_useless_eaf_flags
    3331           46 :                 (past_static_chain_flags,
    3332              :                  flags_from_decl_or_type (current_function_decl),
    3333           23 :                  VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
    3334           23 :           if (past_static_chain_flags != summary->static_chain_flags)
    3335              :             {
    3336            0 :               if ((past_static_chain_flags & ~summary->static_chain_flags) == 0
    3337            0 :                   || (summary->static_chain_flags & EAF_UNUSED))
    3338            0 :                 fprintf (dump_file, "  Flags for static chain improved:");
    3339              :               else
    3340            0 :                 fprintf (dump_file, "  Flags for static chain changed:");
    3341            0 :               dump_eaf_flags (dump_file, past_static_chain_flags, false);
    3342            0 :               fprintf (dump_file, " -> ");
    3343            0 :               dump_eaf_flags (dump_file, summary->static_chain_flags, true);
    3344              :             }
    3345              :         }
    3346          131 :       else if (past_flags_known && !summary)
    3347              :         {
    3348            0 :           for (size_t i = 0; i < past_flags.length (); i++)
    3349              :             {
    3350            0 :               int old_flags = past_flags[i];
    3351            0 :               old_flags = remove_useless_eaf_flags
    3352            0 :                 (old_flags, flags_from_decl_or_type (current_function_decl),
    3353            0 :                  VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
    3354            0 :               if (old_flags)
    3355              :                 {
    3356            0 :                   fprintf (dump_file, "  Flags for param %i worsened:",
    3357              :                            (int)i);
    3358            0 :                   dump_eaf_flags (dump_file, old_flags, false);
    3359            0 :                   fprintf (dump_file, " -> \n");
    3360              :                 }
    3361              :             }
    3362            0 :           past_retslot_flags = remove_useless_eaf_flags
    3363            0 :                 (past_retslot_flags,
    3364              :                  flags_from_decl_or_type (current_function_decl),
    3365            0 :                  VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
    3366            0 :           if (past_retslot_flags)
    3367              :             {
    3368            0 :               fprintf (dump_file, "  Flags for retslot worsened:");
    3369            0 :               dump_eaf_flags (dump_file, past_retslot_flags, false);
    3370            0 :               fprintf (dump_file, " ->\n");
    3371              :             }
    3372            0 :           past_static_chain_flags = remove_useless_eaf_flags
    3373            0 :                 (past_static_chain_flags,
    3374              :                  flags_from_decl_or_type (current_function_decl),
    3375            0 :                  VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
    3376            0 :           if (past_static_chain_flags)
    3377              :             {
    3378            0 :               fprintf (dump_file, "  Flags for static chain worsened:");
    3379            0 :               dump_eaf_flags (dump_file, past_static_chain_flags, false);
    3380            0 :               fprintf (dump_file, " ->\n");
    3381              :             }
    3382              :         }
    3383              :     }
    3384      4749635 :   return fixup_cfg;
    3385      4749635 : }
    3386              : 
    3387              : /* Callback for generate_summary.  */
    3388              : 
    3389              : static void
    3390       229806 : modref_generate (void)
    3391              : {
    3392       229806 :   struct cgraph_node *node;
    3393      1990875 :   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
    3394              :     {
    3395      1761069 :       function *f = DECL_STRUCT_FUNCTION (node->decl);
    3396      1761069 :       if (!f)
    3397            0 :         continue;
    3398      1761069 :       push_cfun (f);
    3399      1761069 :       analyze_function (true);
    3400      1761069 :       pop_cfun ();
    3401              :     }
    3402       229806 : }
    3403              : 
    3404              : }  /* ANON namespace.  */
    3405              : 
    3406              : /* Debugging helper.  */
    3407              : 
    3408              : void
    3409            0 : debug_eaf_flags (int flags)
    3410              : {
    3411            0 :    dump_eaf_flags (stderr, flags, true);
    3412            0 : }
    3413              : 
    3414              : /* Called when a new function is inserted to callgraph late.  */
    3415              : 
    3416              : void
    3417        88052 : modref_summaries::insert (struct cgraph_node *node, modref_summary *)
    3418              : {
    3419              :   /* Local passes ought to be executed by the pass manager.  */
    3420        88052 :   if (this == optimization_summaries)
    3421              :     {
    3422        68934 :       optimization_summaries->remove (node);
    3423        68934 :       return;
    3424              :     }
    3425        19118 :   if (!DECL_STRUCT_FUNCTION (node->decl)
    3426        19118 :       || !opt_for_fn (node->decl, flag_ipa_modref))
    3427              :     {
    3428            0 :       summaries->remove (node);
    3429            0 :       return;
    3430              :     }
    3431        19118 :   push_cfun (DECL_STRUCT_FUNCTION (node->decl));
    3432        19118 :   analyze_function (true);
    3433        19118 :   pop_cfun ();
    3434              : }
    3435              : 
    3436              : /* Called when a new function is inserted to callgraph late.  */
    3437              : 
    3438              : void
    3439         1592 : modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
    3440              : {
    3441              :   /* We do not support adding new function when IPA information is already
    3442              :      propagated.  This is done only by SIMD cloning that is not very
    3443              :      critical.  */
    3444         1592 :   if (!DECL_STRUCT_FUNCTION (node->decl)
    3445         1592 :       || !opt_for_fn (node->decl, flag_ipa_modref)
    3446         3183 :       || propagated)
    3447              :     {
    3448          385 :       summaries_lto->remove (node);
    3449          385 :       return;
    3450              :     }
    3451         1207 :   push_cfun (DECL_STRUCT_FUNCTION (node->decl));
    3452         1207 :   analyze_function (true);
    3453         1207 :   pop_cfun ();
    3454              : }
    3455              : 
    3456              : /* Called when new clone is inserted to callgraph late.  */
    3457              : 
    3458              : void
    3459      2834355 : modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
    3460              :                              modref_summary *src_data,
    3461              :                              modref_summary *dst_data)
    3462              : {
    3463              :   /* Do not duplicate optimization summaries; we do not handle parameter
    3464              :      transforms on them.  */
    3465      2834355 :   if (this == optimization_summaries)
    3466              :     {
    3467      2140017 :       optimization_summaries->remove (dst);
    3468      2140017 :       return;
    3469              :     }
    3470       694338 :   dst_data->stores = modref_records::create_ggc ();
    3471       694338 :   dst_data->stores->copy_from (src_data->stores);
    3472       694338 :   dst_data->loads = modref_records::create_ggc ();
    3473       694338 :   dst_data->loads->copy_from (src_data->loads);
    3474       811689 :   dst_data->kills.reserve_exact (src_data->kills.length ());
    3475       694338 :   dst_data->kills.splice (src_data->kills);
    3476       694338 :   dst_data->writes_errno = src_data->writes_errno;
    3477       694338 :   dst_data->side_effects = src_data->side_effects;
    3478       694338 :   dst_data->nondeterministic = src_data->nondeterministic;
    3479       694338 :   dst_data->calls_interposable = src_data->calls_interposable;
    3480       694338 :   if (src_data->arg_flags.length ())
    3481       496375 :     dst_data->arg_flags = src_data->arg_flags.copy ();
    3482       694338 :   dst_data->retslot_flags = src_data->retslot_flags;
    3483       694338 :   dst_data->static_chain_flags = src_data->static_chain_flags;
    3484              : }
    3485              : 
    3486              : /* Called when new clone is inserted to callgraph late.  */
    3487              : 
    3488              : void
    3489        38522 : modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
    3490              :                                  modref_summary_lto *src_data,
    3491              :                                  modref_summary_lto *dst_data)
    3492              : {
    3493              :   /* Be sure that no further cloning happens after ipa-modref.  If it does
    3494              :      we will need to update signatures for possible param changes.  */
    3495        38522 :   gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
    3496        38522 :   dst_data->stores = modref_records_lto::create_ggc ();
    3497        38522 :   dst_data->stores->copy_from (src_data->stores);
    3498        38522 :   dst_data->loads = modref_records_lto::create_ggc ();
    3499        38522 :   dst_data->loads->copy_from (src_data->loads);
    3500        39357 :   dst_data->kills.reserve_exact (src_data->kills.length ());
    3501        38522 :   dst_data->kills.splice (src_data->kills);
    3502        38522 :   dst_data->writes_errno = src_data->writes_errno;
    3503        38522 :   dst_data->side_effects = src_data->side_effects;
    3504        38522 :   dst_data->nondeterministic = src_data->nondeterministic;
    3505        38522 :   dst_data->calls_interposable = src_data->calls_interposable;
    3506        38522 :   if (src_data->arg_flags.length ())
    3507        36149 :     dst_data->arg_flags = src_data->arg_flags.copy ();
    3508        38522 :   dst_data->retslot_flags = src_data->retslot_flags;
    3509        38522 :   dst_data->static_chain_flags = src_data->static_chain_flags;
    3510        38522 : }
    3511              : 
    3512              : namespace
    3513              : {
    3514              : /* Definition of the modref pass on GIMPLE.  */
    3515              : const pass_data pass_data_modref = {
    3516              :   GIMPLE_PASS,
    3517              :   "modref",
    3518              :   OPTGROUP_IPA,
    3519              :   TV_TREE_MODREF,
    3520              :   (PROP_cfg | PROP_ssa),
    3521              :   0,
    3522              :   0,
    3523              :   0,
    3524              :   0,
    3525              : };
    3526              : 
    3527              : class pass_modref : public gimple_opt_pass
    3528              : {
    3529              :   public:
    3530       571444 :     pass_modref (gcc::context *ctxt)
    3531      1142888 :         : gimple_opt_pass (pass_data_modref, ctxt) {}
    3532              : 
    3533              :     /* opt_pass methods: */
    3534       285722 :     opt_pass *clone () final override
    3535              :     {
    3536       285722 :       return new pass_modref (m_ctxt);
    3537              :     }
    3538      3453912 :     bool gate (function *) final override
    3539              :     {
    3540      3453912 :       return flag_ipa_modref;
    3541              :     }
    3542              :     unsigned int execute (function *) final override;
    3543              : };
    3544              : 
    3545              : /* Encode TT to the output block OB using the summary streaming API.  */
    3546              : 
    3547              : static void
    3548       193384 : write_modref_records (modref_records_lto *tt, struct output_block *ob)
    3549              : {
    3550       193384 :   streamer_write_uhwi (ob, tt->every_base);
    3551       256433 :   streamer_write_uhwi (ob, vec_safe_length (tt->bases));
    3552       397883 :   for (auto base_node : tt->bases)
    3553              :     {
    3554        78401 :       stream_write_tree (ob, base_node->base, true);
    3555              : 
    3556        78401 :       streamer_write_uhwi (ob, base_node->every_ref);
    3557       156607 :       streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
    3558              : 
    3559       315761 :       for (auto ref_node : base_node->refs)
    3560              :         {
    3561        80948 :           stream_write_tree (ob, ref_node->ref, true);
    3562        80948 :           streamer_write_uhwi (ob, ref_node->every_access);
    3563       102796 :           streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
    3564              : 
    3565       148174 :           for (auto access_node : ref_node->accesses)
    3566        23530 :             access_node.stream_out (ob);
    3567              :         }
    3568              :     }
    3569       193384 : }
    3570              : 
    3571              : /* Read a modref_tree from the input block IB using the data from DATA_IN.
    3572              :    This assumes that the tree was encoded using write_modref_tree.
    3573              :    Either nolto_ret or lto_ret is initialized by the tree depending whether
    3574              :    LTO streaming is expected or not.  */
    3575              : 
    3576              : static void
    3577       168638 : read_modref_records (tree decl,
    3578              :                      lto_input_block *ib, struct data_in *data_in,
    3579              :                      modref_records **nolto_ret,
    3580              :                      modref_records_lto **lto_ret)
    3581              : {
    3582       168638 :   size_t max_bases = opt_for_fn (decl, param_modref_max_bases);
    3583       168638 :   size_t max_refs = opt_for_fn (decl, param_modref_max_refs);
    3584       168638 :   size_t max_accesses = opt_for_fn (decl, param_modref_max_accesses);
    3585              : 
    3586       168638 :   if (lto_ret)
    3587        78512 :     *lto_ret = modref_records_lto::create_ggc ();
    3588       168638 :   if (nolto_ret)
    3589        90216 :     *nolto_ret = modref_records::create_ggc ();
    3590       168638 :   gcc_checking_assert (lto_ret || nolto_ret);
    3591              : 
    3592       168638 :   size_t every_base = streamer_read_uhwi (ib);
    3593       168638 :   size_t nbase = streamer_read_uhwi (ib);
    3594              : 
    3595       168638 :   gcc_assert (!every_base || nbase == 0);
    3596       168638 :   if (every_base)
    3597              :     {
    3598        11916 :       if (nolto_ret)
    3599        10427 :         (*nolto_ret)->collapse ();
    3600        11916 :       if (lto_ret)
    3601         1489 :         (*lto_ret)->collapse ();
    3602              :     }
    3603       233697 :   for (size_t i = 0; i < nbase; i++)
    3604              :     {
    3605        65059 :       tree base_tree = stream_read_tree (ib, data_in);
    3606        65059 :       modref_base_node <alias_set_type> *nolto_base_node = NULL;
    3607        65059 :       modref_base_node <tree> *lto_base_node = NULL;
    3608              : 
    3609              :       /* At stream in time we have LTO alias info.  Check if we streamed in
    3610              :          something obviously unnecessary.  Do not glob types by alias sets;
    3611              :          it is not 100% clear that ltrans types will get merged same way.
    3612              :          Types may get refined based on ODR type conflicts.  */
    3613        65059 :       if (base_tree && !get_alias_set (base_tree))
    3614              :         {
    3615            9 :           if (dump_file)
    3616              :             {
    3617            0 :               fprintf (dump_file, "Streamed in alias set 0 type ");
    3618            0 :               print_generic_expr (dump_file, base_tree);
    3619            0 :               fprintf (dump_file, "\n");
    3620              :             }
    3621              :           base_tree = NULL;
    3622              :         }
    3623              : 
    3624        65059 :       if (nolto_ret)
    3625        73365 :         nolto_base_node = (*nolto_ret)->insert_base (base_tree
    3626        36032 :                                                      ? get_alias_set (base_tree)
    3627              :                                                      : 0, 0, INT_MAX);
    3628        65059 :       if (lto_ret)
    3629        27758 :         lto_base_node = (*lto_ret)->insert_base (base_tree, 0, max_bases);
    3630        65059 :       size_t every_ref = streamer_read_uhwi (ib);
    3631        65059 :       size_t nref = streamer_read_uhwi (ib);
    3632              : 
    3633        65059 :       gcc_assert (!every_ref || nref == 0);
    3634        65059 :       if (every_ref)
    3635              :         {
    3636           96 :           if (nolto_base_node)
    3637           44 :             nolto_base_node->collapse ();
    3638           96 :           if (lto_base_node)
    3639           52 :             lto_base_node->collapse ();
    3640              :         }
    3641       132070 :       for (size_t j = 0; j < nref; j++)
    3642              :         {
    3643        67011 :           tree ref_tree = stream_read_tree (ib, data_in);
    3644              : 
    3645        67011 :           if (ref_tree && !get_alias_set (ref_tree))
    3646              :             {
    3647           31 :               if (dump_file)
    3648              :                 {
    3649            0 :                   fprintf (dump_file, "Streamed in alias set 0 type ");
    3650            0 :                   print_generic_expr (dump_file, ref_tree);
    3651            0 :                   fprintf (dump_file, "\n");
    3652              :                 }
    3653              :               ref_tree = NULL;
    3654              :             }
    3655              : 
    3656        67011 :           modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
    3657        67011 :           modref_ref_node <tree> *lto_ref_node = NULL;
    3658              : 
    3659        67011 :           if (nolto_base_node)
    3660        38290 :             nolto_ref_node
    3661        75640 :               = nolto_base_node->insert_ref (ref_tree
    3662        37350 :                                              ? get_alias_set (ref_tree) : 0,
    3663              :                                              max_refs);
    3664        67011 :           if (lto_base_node)
    3665        28753 :             lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
    3666              : 
    3667        67011 :           size_t every_access = streamer_read_uhwi (ib);
    3668        67011 :           size_t naccesses = streamer_read_uhwi (ib);
    3669              : 
    3670        67011 :           if (nolto_ref_node && every_access)
    3671        29920 :             nolto_ref_node->collapse ();
    3672        67011 :           if (lto_ref_node && every_access)
    3673        20635 :             lto_ref_node->collapse ();
    3674              : 
    3675        84329 :           for (size_t k = 0; k < naccesses; k++)
    3676              :             {
    3677        17318 :               modref_access_node a = modref_access_node::stream_in (ib);
    3678        17318 :               if (nolto_ref_node)
    3679         8755 :                 nolto_ref_node->insert_access (a, max_accesses, false);
    3680        17318 :               if (lto_ref_node)
    3681         8582 :                 lto_ref_node->insert_access (a, max_accesses, false);
    3682              :             }
    3683              :         }
    3684              :     }
    3685       168638 :   if (lto_ret)
    3686        78512 :     (*lto_ret)->cleanup ();
    3687       168638 :   if (nolto_ret)
    3688        90216 :     (*nolto_ret)->cleanup ();
    3689       168638 : }
    3690              : 
    3691              : /* Write ESUM to BP.  */
    3692              : 
    3693              : static void
    3694       328497 : modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
    3695              : {
    3696       328497 :   if (!esum)
    3697              :     {
    3698       305289 :       bp_pack_var_len_unsigned (bp, 0);
    3699       305289 :       return;
    3700              :     }
    3701        23208 :   bp_pack_var_len_unsigned (bp, esum->esc.length ());
    3702        23208 :   unsigned int i;
    3703        23208 :   escape_entry *ee;
    3704        70086 :   FOR_EACH_VEC_ELT (esum->esc, i, ee)
    3705              :     {
    3706        23670 :       bp_pack_var_len_int (bp, ee->parm_index);
    3707        23670 :       bp_pack_var_len_unsigned (bp, ee->arg);
    3708        23670 :       bp_pack_var_len_unsigned (bp, ee->min_flags);
    3709        23670 :       bp_pack_value (bp, ee->direct, 1);
    3710              :     }
    3711              : }
    3712              : 
    3713              : /* Read escape summary for E from BP.  */
    3714              : 
    3715              : static void
    3716       308811 : modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
    3717              : {
    3718       308811 :   unsigned int n = bp_unpack_var_len_unsigned (bp);
    3719       308811 :   if (!n)
    3720              :     return;
    3721        22723 :   escape_summary *esum = escape_summaries->get_create (e);
    3722        22723 :   esum->esc.reserve_exact (n);
    3723        45855 :   for (unsigned int i = 0; i < n; i++)
    3724              :     {
    3725        23132 :       escape_entry ee;
    3726        23132 :       ee.parm_index = bp_unpack_var_len_int (bp);
    3727        23132 :       ee.arg = bp_unpack_var_len_unsigned (bp);
    3728        23132 :       ee.min_flags = bp_unpack_var_len_unsigned (bp);
    3729        23132 :       ee.direct = bp_unpack_value (bp, 1);
    3730        23132 :       esum->esc.quick_push (ee);
    3731              :     }
    3732              : }
    3733              : 
    3734              : /* Callback for write_summary.  */
    3735              : 
    3736              : static void
    3737        31226 : modref_write ()
    3738              : {
    3739        31226 :   struct output_block *ob = create_output_block (LTO_section_ipa_modref);
    3740        31226 :   lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
    3741        31226 :   unsigned int count = 0;
    3742        31226 :   int i;
    3743              : 
    3744        31226 :   if (!summaries_lto)
    3745              :     {
    3746         3475 :       streamer_write_uhwi (ob, 0);
    3747         3475 :       streamer_write_char_stream (ob->main_stream, 0);
    3748         3475 :       produce_asm (ob);
    3749         3475 :       destroy_output_block (ob);
    3750         3475 :       return;
    3751              :     }
    3752              : 
    3753       631274 :   for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
    3754              :     {
    3755       287890 :       toplevel_node *tnode = lto_symtab_encoder_deref (encoder, i);
    3756       575780 :       cgraph_node *cnode = dyn_cast <cgraph_node *> (tnode);
    3757       206306 :       modref_summary_lto *r;
    3758              : 
    3759       206306 :       if (cnode && cnode->definition && !cnode->alias
    3760       147002 :           && (r = summaries_lto->get (cnode))
    3761       100587 :           && r->useful_p (flags_from_decl_or_type (cnode->decl)))
    3762        96692 :         count++;
    3763              :     }
    3764        27751 :   streamer_write_uhwi (ob, count);
    3765              : 
    3766       631274 :   for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
    3767              :     {
    3768       287890 :       toplevel_node *tnode = lto_symtab_encoder_deref (encoder, i);
    3769       575780 :       cgraph_node *cnode = dyn_cast <cgraph_node *> (tnode);
    3770              : 
    3771       206306 :       if (cnode && cnode->definition && !cnode->alias)
    3772              :         {
    3773       147002 :           modref_summary_lto *r = summaries_lto->get (cnode);
    3774              : 
    3775       147002 :           if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
    3776        50310 :             continue;
    3777              : 
    3778        96692 :           streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
    3779              : 
    3780        96692 :           streamer_write_uhwi (ob, r->arg_flags.length ());
    3781       395915 :           for (unsigned int i = 0; i < r->arg_flags.length (); i++)
    3782       299223 :             streamer_write_uhwi (ob, r->arg_flags[i]);
    3783        96692 :           streamer_write_uhwi (ob, r->retslot_flags);
    3784        96692 :           streamer_write_uhwi (ob, r->static_chain_flags);
    3785              : 
    3786        96692 :           write_modref_records (r->loads, ob);
    3787        96692 :           write_modref_records (r->stores, ob);
    3788       101296 :           streamer_write_uhwi (ob, r->kills.length ());
    3789       111353 :           for (auto kill : r->kills)
    3790         5453 :             kill.stream_out (ob);
    3791              : 
    3792        96692 :           struct bitpack_d bp = bitpack_create (ob->main_stream);
    3793        96692 :           bp_pack_value (&bp, r->writes_errno, 1);
    3794        96692 :           bp_pack_value (&bp, r->side_effects, 1);
    3795        96692 :           bp_pack_value (&bp, r->nondeterministic, 1);
    3796        96692 :           bp_pack_value (&bp, r->calls_interposable, 1);
    3797        96692 :           if (!flag_wpa)
    3798              :             {
    3799        81057 :               for (cgraph_edge *e = cnode->indirect_calls;
    3800        83609 :                    e; e = e->next_callee)
    3801              :                 {
    3802         2552 :                   class fnspec_summary *sum = fnspec_summaries->get (e);
    3803         2552 :                   bp_pack_value (&bp, sum != NULL, 1);
    3804         2552 :                   if (sum)
    3805            0 :                     bp_pack_string (ob, &bp, sum->fnspec, true);
    3806         2552 :                   class escape_summary *esum = escape_summaries->get (e);
    3807         2552 :                   modref_write_escape_summary (&bp,esum);
    3808              :                 }
    3809       407002 :               for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
    3810              :                 {
    3811       325945 :                   class fnspec_summary *sum = fnspec_summaries->get (e);
    3812       325945 :                   bp_pack_value (&bp, sum != NULL, 1);
    3813       325945 :                   if (sum)
    3814        73894 :                     bp_pack_string (ob, &bp, sum->fnspec, true);
    3815       325945 :                   class escape_summary *esum = escape_summaries->get (e);
    3816       325945 :                   modref_write_escape_summary (&bp,esum);
    3817              :                 }
    3818              :             }
    3819        96692 :           streamer_write_bitpack (&bp);
    3820              :         }
    3821              :     }
    3822        27751 :   streamer_write_char_stream (ob->main_stream, 0);
    3823        27751 :   produce_asm (ob);
    3824        27751 :   destroy_output_block (ob);
    3825              : }
    3826              : 
    3827              : static void
    3828        21447 : read_section (struct lto_file_decl_data *file_data, const char *data,
    3829              :               size_t len)
    3830              : {
    3831        21447 :   const struct lto_function_header *header
    3832              :     = (const struct lto_function_header *) data;
    3833        21447 :   const int cfg_offset = sizeof (struct lto_function_header);
    3834        21447 :   const int main_offset = cfg_offset + header->cfg_size;
    3835        21447 :   const int string_offset = main_offset + header->main_size;
    3836        21447 :   struct data_in *data_in;
    3837        21447 :   unsigned int i;
    3838        21447 :   unsigned int f_count;
    3839              : 
    3840        21447 :   lto_input_block ib ((const char *) data + main_offset, header->main_size,
    3841        21447 :                       file_data);
    3842              : 
    3843        21447 :   data_in
    3844        42894 :     = lto_data_in_create (file_data, (const char *) data + string_offset,
    3845        21447 :                           header->string_size, vNULL);
    3846        21447 :   f_count = streamer_read_uhwi (&ib);
    3847       105766 :   for (i = 0; i < f_count; i++)
    3848              :     {
    3849        84319 :       struct cgraph_node *node;
    3850        84319 :       lto_symtab_encoder_t encoder;
    3851              : 
    3852        84319 :       unsigned int index = streamer_read_uhwi (&ib);
    3853        84319 :       encoder = file_data->symtab_node_encoder;
    3854        84319 :       node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
    3855              :                                                                 index));
    3856              : 
    3857        84319 :       modref_summary *modref_sum = summaries
    3858        84319 :                                    ? summaries->get_create (node) : NULL;
    3859        84319 :       modref_summary_lto *modref_sum_lto = summaries_lto
    3860        84319 :                                            ? summaries_lto->get_create (node)
    3861              :                                            : NULL;
    3862        84319 :       if (optimization_summaries)
    3863        15635 :         modref_sum = optimization_summaries->get_create (node);
    3864              : 
    3865        84319 :       if (modref_sum)
    3866              :         {
    3867        45108 :           modref_sum->writes_errno = false;
    3868        45108 :           modref_sum->side_effects = false;
    3869        45108 :           modref_sum->nondeterministic = false;
    3870        45108 :           modref_sum->calls_interposable = false;
    3871              :         }
    3872        84319 :       if (modref_sum_lto)
    3873              :         {
    3874        39256 :           modref_sum_lto->writes_errno = false;
    3875        39256 :           modref_sum_lto->side_effects = false;
    3876        39256 :           modref_sum_lto->nondeterministic = false;
    3877        39256 :           modref_sum_lto->calls_interposable = false;
    3878              :         }
    3879              : 
    3880        84319 :       gcc_assert (!modref_sum || (!modref_sum->loads
    3881              :                                   && !modref_sum->stores));
    3882        84319 :       gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
    3883              :                                       && !modref_sum_lto->stores));
    3884        84319 :       unsigned int args = streamer_read_uhwi (&ib);
    3885        84319 :       if (args && modref_sum)
    3886        30527 :         modref_sum->arg_flags.reserve_exact (args);
    3887        84319 :       if (args && modref_sum_lto)
    3888        24619 :         modref_sum_lto->arg_flags.reserve_exact (args);
    3889       164763 :       for (unsigned int i = 0; i < args; i++)
    3890              :         {
    3891        80444 :           eaf_flags_t flags = streamer_read_uhwi (&ib);
    3892        80444 :           if (modref_sum)
    3893        44258 :             modref_sum->arg_flags.quick_push (flags);
    3894        80444 :           if (modref_sum_lto)
    3895        36236 :             modref_sum_lto->arg_flags.quick_push (flags);
    3896              :         }
    3897        84319 :       eaf_flags_t flags = streamer_read_uhwi (&ib);
    3898        84319 :       if (modref_sum)
    3899        45108 :         modref_sum->retslot_flags = flags;
    3900        84319 :       if (modref_sum_lto)
    3901        39256 :         modref_sum_lto->retslot_flags = flags;
    3902              : 
    3903        84319 :       flags = streamer_read_uhwi (&ib);
    3904        84319 :       if (modref_sum)
    3905        45108 :         modref_sum->static_chain_flags = flags;
    3906        84319 :       if (modref_sum_lto)
    3907        39256 :         modref_sum_lto->static_chain_flags = flags;
    3908              : 
    3909        84319 :       read_modref_records (node->decl, &ib, data_in,
    3910              :                            modref_sum ? &modref_sum->loads : NULL,
    3911              :                            modref_sum_lto ? &modref_sum_lto->loads : NULL);
    3912        84319 :       read_modref_records (node->decl, &ib, data_in,
    3913              :                            modref_sum ? &modref_sum->stores : NULL,
    3914              :                            modref_sum_lto ? &modref_sum_lto->stores : NULL);
    3915        84319 :       int j = streamer_read_uhwi (&ib);
    3916        84319 :       if (j && modref_sum)
    3917         2024 :         modref_sum->kills.reserve_exact (j);
    3918        84319 :       if (j && modref_sum_lto)
    3919         1509 :         modref_sum_lto->kills.reserve_exact (j);
    3920        88604 :       for (int k = 0; k < j; k++)
    3921              :         {
    3922         4285 :           modref_access_node a = modref_access_node::stream_in (&ib);
    3923              : 
    3924         4285 :           if (modref_sum)
    3925         2409 :             modref_sum->kills.quick_push (a);
    3926         4285 :           if (modref_sum_lto)
    3927         1881 :             modref_sum_lto->kills.quick_push (a);
    3928              :         }
    3929        84319 :       struct bitpack_d bp = streamer_read_bitpack (&ib);
    3930        84319 :       if (bp_unpack_value (&bp, 1))
    3931              :         {
    3932          105 :           if (modref_sum)
    3933          105 :             modref_sum->writes_errno = true;
    3934          105 :           if (modref_sum_lto)
    3935            0 :             modref_sum_lto->writes_errno = true;
    3936              :         }
    3937        84319 :       if (bp_unpack_value (&bp, 1))
    3938              :         {
    3939        14372 :           if (modref_sum)
    3940        10711 :             modref_sum->side_effects = true;
    3941        14372 :           if (modref_sum_lto)
    3942         3661 :             modref_sum_lto->side_effects = true;
    3943              :         }
    3944        84319 :       if (bp_unpack_value (&bp, 1))
    3945              :         {
    3946         7588 :           if (modref_sum)
    3947         4813 :             modref_sum->nondeterministic = true;
    3948         7588 :           if (modref_sum_lto)
    3949         2775 :             modref_sum_lto->nondeterministic = true;
    3950              :         }
    3951        84319 :       if (bp_unpack_value (&bp, 1))
    3952              :         {
    3953            0 :           if (modref_sum)
    3954            0 :             modref_sum->calls_interposable = true;
    3955            0 :           if (modref_sum_lto)
    3956            0 :             modref_sum_lto->calls_interposable = true;
    3957              :         }
    3958        84319 :       if (!flag_ltrans)
    3959              :         {
    3960        70043 :           for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
    3961              :             {
    3962         1359 :               if (bp_unpack_value (&bp, 1))
    3963              :                 {
    3964            0 :                   class fnspec_summary *sum = fnspec_summaries->get_create (e);
    3965            0 :                   sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
    3966              :                 }
    3967         1359 :               modref_read_escape_summary (&bp, e);
    3968              :             }
    3969       376136 :           for (cgraph_edge *e = node->callees; e; e = e->next_callee)
    3970              :             {
    3971       307452 :               if (bp_unpack_value (&bp, 1))
    3972              :                 {
    3973        71309 :                   class fnspec_summary *sum = fnspec_summaries->get_create (e);
    3974        71309 :                   sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
    3975              :                 }
    3976       307452 :               modref_read_escape_summary (&bp, e);
    3977              :             }
    3978              :         }
    3979        84319 :       if (flag_ltrans)
    3980        15635 :         modref_sum->finalize (node->decl);
    3981        84319 :       if (dump_file)
    3982              :         {
    3983           16 :           fprintf (dump_file, "Read modref for %s\n",
    3984              :                    node->dump_name ());
    3985           16 :           if (modref_sum)
    3986           10 :             modref_sum->dump (dump_file);
    3987           16 :           if (modref_sum_lto)
    3988            6 :             modref_sum_lto->dump (dump_file);
    3989           16 :           dump_modref_edge_summaries (dump_file, node, 4);
    3990              :         }
    3991              :     }
    3992              : 
    3993        21447 :   lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
    3994              :                          len);
    3995        21447 :   lto_data_in_delete (data_in);
    3996        21447 : }
    3997              : 
    3998              : /* Callback for read_summary.  */
    3999              : 
    4000              : static void
    4001        20392 : modref_read (void)
    4002              : {
    4003        20392 :   struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
    4004        20392 :   struct lto_file_decl_data *file_data;
    4005        20392 :   unsigned int j = 0;
    4006              : 
    4007        20392 :   gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
    4008        20392 :   if (flag_ltrans)
    4009         8190 :     optimization_summaries = modref_summaries::create_ggc (symtab);
    4010              :   else
    4011              :     {
    4012        12202 :       if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
    4013         7850 :         summaries_lto = modref_summaries_lto::create_ggc (symtab);
    4014        12202 :       if (!flag_wpa
    4015         7817 :           || (flag_incremental_link == INCREMENTAL_LINK_LTO
    4016            0 :               && flag_fat_lto_objects))
    4017         4385 :         summaries = modref_summaries::create_ggc (symtab);
    4018        12202 :       if (!fnspec_summaries)
    4019        12202 :         fnspec_summaries = new fnspec_summaries_t (symtab);
    4020        12202 :       if (!escape_summaries)
    4021        12202 :         escape_summaries = new escape_summaries_t (symtab);
    4022              :     }
    4023              : 
    4024        41839 :   while ((file_data = file_data_vec[j++]))
    4025              :     {
    4026        21447 :       size_t len;
    4027        21447 :       const char *data = lto_get_summary_section_data (file_data,
    4028              :                                                        LTO_section_ipa_modref,
    4029              :                                                        &len);
    4030        21447 :       if (data)
    4031        21447 :         read_section (file_data, data, len);
    4032              :       else
    4033              :         /* Fatal error here.  We do not want to support compiling ltrans units
    4034              :            with different version of compiler or different flags than the WPA
    4035              :            unit, so this should never happen.  */
    4036            0 :         fatal_error (input_location,
    4037              :                      "IPA modref summary is missing in input file");
    4038              :     }
    4039        20392 : }
    4040              : 
    4041              : /* Recompute arg_flags for param adjustments in INFO.  */
    4042              : 
    4043              : static void
    4044        22179 : remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
    4045              : {
    4046        22179 :   auto_vec<eaf_flags_t> old = arg_flags.copy ();
    4047        22179 :   int max = -1;
    4048        22179 :   size_t i;
    4049        22179 :   ipa_adjusted_param *p;
    4050              : 
    4051        22179 :   arg_flags.release ();
    4052              : 
    4053        67445 :   FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
    4054              :     {
    4055        45266 :       int o = info->param_adjustments->get_original_index (i);
    4056        79533 :       if (o >= 0 && (int)old.length () > o && old[o])
    4057              :         max = i;
    4058              :     }
    4059        22179 :   if (max >= 0)
    4060        13634 :     arg_flags.safe_grow_cleared (max + 1, true);
    4061        86891 :   FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
    4062              :     {
    4063        45266 :       int o = info->param_adjustments->get_original_index (i);
    4064        34267 :       if (o >= 0 && (int)old.length () > o && old[o])
    4065        18959 :         arg_flags[i] = old[o];
    4066              :     }
    4067        22179 : }
    4068              : 
    4069              : /* Update kills according to the parm map MAP.  */
    4070              : 
    4071              : static void
    4072        24578 : remap_kills (vec <modref_access_node> &kills, const vec <int> &map)
    4073              : {
    4074        26712 :   for (size_t i = 0; i < kills.length ();)
    4075         2134 :     if (kills[i].parm_index >= 0)
    4076              :       {
    4077         2043 :         if (kills[i].parm_index < (int)map.length ()
    4078         2043 :             && map[kills[i].parm_index] != MODREF_UNKNOWN_PARM)
    4079              :           {
    4080         1917 :             kills[i].parm_index = map[kills[i].parm_index];
    4081         1917 :             i++;
    4082              :           }
    4083              :         else
    4084          126 :           kills.unordered_remove (i);
    4085              :       }
    4086              :     else
    4087           91 :       i++;
    4088        24578 : }
    4089              : 
    4090              : /* Return true if the V can overlap with KILL.  */
    4091              : 
    4092              : static bool
    4093         7220 : ipcp_argagg_and_kill_overlap_p (const ipa_argagg_value &v,
    4094              :                                 const modref_access_node &kill)
    4095              : {
    4096         7220 :   if (kill.parm_index == v.index)
    4097              :     {
    4098          667 :       gcc_assert (kill.parm_offset_known);
    4099          667 :       gcc_assert (known_eq (kill.max_size, kill.size));
    4100          667 :       poly_int64 repl_size;
    4101          667 :       bool ok = poly_int_tree_p (TYPE_SIZE (TREE_TYPE (v.value)),
    4102              :                                  &repl_size);
    4103          667 :       gcc_assert (ok);
    4104          667 :       poly_int64 repl_offset (v.unit_offset);
    4105          667 :       repl_offset <<= LOG2_BITS_PER_UNIT;
    4106          667 :       poly_int64 combined_offset
    4107          667 :         = (kill.parm_offset << LOG2_BITS_PER_UNIT) + kill.offset;
    4108          667 :       if (ranges_maybe_overlap_p (repl_offset, repl_size,
    4109          667 :                                   combined_offset, kill.size))
    4110          451 :         return true;
    4111              :     }
    4112              :   return false;
    4113              : }
    4114              : 
    4115              : /* If signature changed, update the summary.  */
    4116              : 
    4117              : static void
    4118      3315392 : update_signature (struct cgraph_node *node)
    4119              : {
    4120      3315392 :   modref_summary *r = optimization_summaries
    4121      3315392 :                       ? optimization_summaries->get (node) : NULL;
    4122      3315392 :   modref_summary_lto *r_lto = summaries_lto
    4123      3315392 :                               ? summaries_lto->get (node) : NULL;
    4124      3315392 :   if (!r && !r_lto)
    4125              :     return;
    4126              : 
    4127              :   /* Propagating constants in killed memory can lead to eliminated stores in
    4128              :      both callees (because they are considered redundant) and callers, leading
    4129              :      to missing them altogether.  */
    4130       865907 :   ipcp_transformation *ipcp_ts = ipcp_get_transformation_summary (node);
    4131       865907 :   if (ipcp_ts)
    4132              :     {
    4133        76183 :     for (auto &v : ipcp_ts->m_agg_values)
    4134              :       {
    4135        23207 :         if (!v.by_ref)
    4136         2550 :           continue;
    4137        20657 :         if (r)
    4138        31599 :           for (const modref_access_node &kill : r->kills)
    4139         7157 :             if (ipcp_argagg_and_kill_overlap_p (v, kill))
    4140              :               {
    4141          433 :                 v.killed = true;
    4142          433 :                 break;
    4143              :               }
    4144        20657 :         if (!v.killed && r_lto)
    4145         1381 :           for (const modref_access_node &kill : r_lto->kills)
    4146           63 :             if (ipcp_argagg_and_kill_overlap_p (v, kill))
    4147              :               {
    4148           18 :                 v.killed = true;
    4149           18 :                 break;
    4150              :               }
    4151              :       }
    4152              :     }
    4153              : 
    4154       865907 :   clone_info *info = clone_info::get (node);
    4155       865907 :   if (!info || !info->param_adjustments)
    4156              :     return;
    4157              : 
    4158        24427 :   if (dump_file)
    4159              :     {
    4160            1 :       fprintf (dump_file, "Updating summary for %s from:\n",
    4161              :                node->dump_name ());
    4162            1 :       if (r)
    4163            1 :         r->dump (dump_file);
    4164            1 :       if (r_lto)
    4165            0 :         r_lto->dump (dump_file);
    4166              :     }
    4167              : 
    4168              :   size_t i, max = 0;
    4169              :   ipa_adjusted_param *p;
    4170              : 
    4171        73923 :   FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
    4172              :     {
    4173        49496 :       int idx = info->param_adjustments->get_original_index (i);
    4174        49496 :       if (idx > (int)max)
    4175        26194 :         max = idx;
    4176              :     }
    4177              : 
    4178        24427 :   auto_vec <int, 32> map;
    4179              : 
    4180        24427 :   map.reserve (max + 1);
    4181       102560 :   for (i = 0; i <= max; i++)
    4182        53706 :     map.quick_push (MODREF_UNKNOWN_PARM);
    4183        73923 :   FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
    4184              :     {
    4185        49496 :       int idx = info->param_adjustments->get_original_index (i);
    4186        49496 :       if (idx >= 0)
    4187        37839 :         map[idx] = i;
    4188              :     }
    4189        24427 :   if (r)
    4190              :     {
    4191        21933 :       r->loads->remap_params (&map);
    4192        21933 :       r->stores->remap_params (&map);
    4193        21933 :       remap_kills (r->kills, map);
    4194        21933 :       if (r->arg_flags.length ())
    4195        19851 :         remap_arg_flags (r->arg_flags, info);
    4196              :     }
    4197        24427 :   if (r_lto)
    4198              :     {
    4199         2645 :       r_lto->loads->remap_params (&map);
    4200         2645 :       r_lto->stores->remap_params (&map);
    4201         2645 :       remap_kills (r_lto->kills, map);
    4202         2645 :       if (r_lto->arg_flags.length ())
    4203         2328 :         remap_arg_flags (r_lto->arg_flags, info);
    4204              :     }
    4205        24427 :   if (dump_file)
    4206              :     {
    4207            1 :       fprintf (dump_file, "to:\n");
    4208            1 :       if (r)
    4209            1 :         r->dump (dump_file);
    4210            1 :       if (r_lto)
    4211            0 :         r_lto->dump (dump_file);
    4212              :     }
    4213        24427 :   if (r)
    4214        21933 :     r->finalize (node->decl);
    4215        24427 :   return;
    4216        24427 : }
    4217              : 
    4218              : /* Definition of the modref IPA pass.  */
    4219              : const pass_data pass_data_ipa_modref =
    4220              : {
    4221              :   IPA_PASS,           /* type */
    4222              :   "modref",       /* name */
    4223              :   OPTGROUP_IPA,       /* optinfo_flags */
    4224              :   TV_IPA_MODREF, /* tv_id */
    4225              :   0, /* properties_required */
    4226              :   0, /* properties_provided */
    4227              :   0, /* properties_destroyed */
    4228              :   0, /* todo_flags_start */
    4229              :   ( TODO_dump_symtab ), /* todo_flags_finish */
    4230              : };
    4231              : 
    4232              : class pass_ipa_modref : public ipa_opt_pass_d
    4233              : {
    4234              : public:
    4235       285722 :   pass_ipa_modref (gcc::context *ctxt)
    4236              :     : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
    4237              :                       modref_generate, /* generate_summary */
    4238              :                       modref_write,    /* write_summary */
    4239              :                       modref_read,     /* read_summary */
    4240              :                       modref_write,    /* write_optimization_summary */
    4241              :                       modref_read,     /* read_optimization_summary */
    4242              :                       NULL,            /* stmt_fixup */
    4243              :                       0,               /* function_transform_todo_flags_start */
    4244              :                       NULL,            /* function_transform */
    4245       285722 :                       NULL)            /* variable_transform */
    4246       285722 :   {}
    4247              : 
    4248              :   /* opt_pass methods: */
    4249            0 :   opt_pass *clone () final override { return new pass_ipa_modref (m_ctxt); }
    4250       594945 :   bool gate (function *) final override
    4251              :   {
    4252       594945 :     return true;
    4253              :   }
    4254              :   unsigned int execute (function *) final override;
    4255              : 
    4256              : };
    4257              : 
    4258              : }
    4259              : 
    4260      3450242 : unsigned int pass_modref::execute (function *)
    4261              : {
    4262      3450242 :   if (analyze_function (false))
    4263         8489 :     return execute_fixup_cfg ();
    4264              :   return 0;
    4265              : }
    4266              : 
    4267              : gimple_opt_pass *
    4268       285722 : make_pass_modref (gcc::context *ctxt)
    4269              : {
    4270       285722 :   return new pass_modref (ctxt);
    4271              : }
    4272              : 
    4273              : ipa_opt_pass_d *
    4274       285722 : make_pass_ipa_modref (gcc::context *ctxt)
    4275              : {
    4276       285722 :   return new pass_ipa_modref (ctxt);
    4277              : }
    4278              : 
    4279              : namespace {
    4280              : 
    4281              : /* Skip edges from and to nodes without ipa_pure_const enabled.
    4282              :    Ignore not available symbols.  */
    4283              : 
    4284              : static bool
    4285      7327573 : ignore_edge (struct cgraph_edge *e)
    4286              : {
    4287              :   /* We merge summaries of inline clones into summaries of functions they
    4288              :      are inlined to.  For that reason the complete function bodies must
    4289              :      act as unit.  */
    4290      7327573 :   if (!e->inline_failed)
    4291              :     return false;
    4292      6002814 :   enum availability avail;
    4293      6002814 :   cgraph_node *callee = e->callee->ultimate_alias_target
    4294      6002814 :                           (&avail, e->caller);
    4295              : 
    4296      6002814 :   return (avail <= AVAIL_INTERPOSABLE
    4297      6002814 :           || ((!optimization_summaries || !optimization_summaries->get (callee))
    4298       217241 :               && (!summaries_lto || !summaries_lto->get (callee))));
    4299              : }
    4300              : 
    4301              : /* Compute parm_map for CALLEE_EDGE.  */
    4302              : 
    4303              : static bool
    4304      2076936 : compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
    4305              : {
    4306      2076936 :   class ipa_edge_args *args;
    4307      2076936 :   if (ipa_node_params_sum
    4308      2076936 :       && !callee_edge->call_stmt_cannot_inline_p
    4309      4153871 :       && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
    4310              :     {
    4311      2041209 :       int i, count = ipa_get_cs_argument_count (args);
    4312      2041209 :       class ipa_node_params *caller_parms_info, *callee_pi;
    4313      2041209 :       class ipa_call_summary *es
    4314      2041209 :              = ipa_call_summaries->get (callee_edge);
    4315      2041209 :       cgraph_node *callee
    4316      2041209 :          = callee_edge->callee->ultimate_alias_target
    4317      2041209 :                               (NULL, callee_edge->caller);
    4318              : 
    4319      2041209 :       caller_parms_info
    4320      2041209 :         = ipa_node_params_sum->get (callee_edge->caller->inlined_to
    4321              :                                     ? callee_edge->caller->inlined_to
    4322              :                                     : callee_edge->caller);
    4323      2041209 :       callee_pi = ipa_node_params_sum->get (callee);
    4324              : 
    4325      2041209 :       (*parm_map).safe_grow_cleared (count, true);
    4326              : 
    4327      6561443 :       for (i = 0; i < count; i++)
    4328              :         {
    4329      4520234 :           if (es && es->param[i].points_to_local_or_readonly_memory)
    4330              :             {
    4331       798468 :               (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
    4332       798468 :               continue;
    4333              :             }
    4334              : 
    4335      3721766 :           struct ipa_jump_func *jf
    4336      3721766 :              = ipa_get_ith_jump_func (args, i);
    4337      3721766 :           if (jf && callee_pi)
    4338              :             {
    4339      2742589 :               tree cst = ipa_value_from_jfunc (caller_parms_info,
    4340              :                                                jf,
    4341              :                                                ipa_get_type
    4342              :                                                  (callee_pi, i));
    4343      2742589 :               if (cst && points_to_local_or_readonly_memory_p (cst))
    4344              :                 {
    4345          960 :                   (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
    4346          960 :                   continue;
    4347              :                 }
    4348              :             }
    4349      3720806 :           if (jf && jf->type == IPA_JF_PASS_THROUGH)
    4350              :             {
    4351       747108 :               (*parm_map)[i].parm_index
    4352       747108 :                 = ipa_get_jf_pass_through_formal_id (jf);
    4353       747108 :               if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
    4354              :                 {
    4355       735866 :                   (*parm_map)[i].parm_offset_known = true;
    4356       735866 :                   (*parm_map)[i].parm_offset = 0;
    4357              :                 }
    4358        11242 :               else if (ipa_get_jf_pass_through_operation (jf)
    4359              :                        == POINTER_PLUS_EXPR
    4360        13321 :                        && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
    4361         2079 :                                           &(*parm_map)[i].parm_offset))
    4362         2079 :                 (*parm_map)[i].parm_offset_known = true;
    4363              :               else
    4364         9163 :                 (*parm_map)[i].parm_offset_known = false;
    4365       747108 :               continue;
    4366              :             }
    4367      2973698 :           if (jf && jf->type == IPA_JF_ANCESTOR)
    4368              :             {
    4369       119956 :               (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
    4370       119956 :               (*parm_map)[i].parm_offset_known = true;
    4371       119956 :               gcc_checking_assert
    4372              :                 (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
    4373       239912 :               (*parm_map)[i].parm_offset
    4374       119956 :                  = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
    4375              :             }
    4376              :           else
    4377      2853742 :             (*parm_map)[i].parm_index = -1;
    4378              :         }
    4379      2041209 :       if (dump_file)
    4380              :         {
    4381          437 :           fprintf (dump_file, "  Parm map: ");
    4382         1433 :           for (i = 0; i < count; i++)
    4383          559 :             fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
    4384          437 :           fprintf (dump_file, "\n");
    4385              :         }
    4386      2041209 :       return true;
    4387              :     }
    4388              :   return false;
    4389              : }
    4390              : 
    4391              : /* Map used to translate escape infos.  */
    4392              : 
    4393              : struct escape_map
    4394              : {
    4395              :   int parm_index;
    4396              :   bool direct;
    4397              : };
    4398              : 
    4399              : /* Update escape map for E.  */
    4400              : 
    4401              : static void
    4402      2226212 : update_escape_summary_1 (cgraph_edge *e,
    4403              :                          vec <vec <escape_map>> &map,
    4404              :                          bool ignore_stores)
    4405              : {
    4406      2226212 :   escape_summary *sum = escape_summaries->get (e);
    4407      2226212 :   if (!sum)
    4408      2097721 :     return;
    4409       128491 :   auto_vec <escape_entry> old = sum->esc.copy ();
    4410       128491 :   sum->esc.release ();
    4411              : 
    4412       128491 :   unsigned int i;
    4413       128491 :   escape_entry *ee;
    4414       285622 :   FOR_EACH_VEC_ELT (old, i, ee)
    4415              :     {
    4416       157131 :       unsigned int j;
    4417       157131 :       struct escape_map *em;
    4418              :       /* TODO: We do not have jump functions for return slots, so we
    4419              :          never propagate them to outer function.  */
    4420       157131 :       if (ee->parm_index >= (int)map.length ()
    4421       157131 :           || ee->parm_index < 0)
    4422       121665 :         continue;
    4423       217648 :       FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
    4424              :         {
    4425        30334 :           eaf_flags_t min_flags = ee->min_flags;
    4426        30334 :           if (ee->direct && !em->direct)
    4427         5095 :             min_flags = deref_flags (min_flags, ignore_stores);
    4428        30334 :           struct escape_entry entry = {em->parm_index, ee->arg,
    4429              :                                        min_flags,
    4430        30334 :                                        ee->direct && em->direct};
    4431        30334 :           sum->esc.safe_push (entry);
    4432              :         }
    4433              :     }
    4434       128491 :   if (!sum->esc.length ())
    4435       103249 :     escape_summaries->remove (e);
    4436       128491 : }
    4437              : 
    4438              : /* Update escape map for NODE.  */
    4439              : 
    4440              : static void
    4441      1368262 : update_escape_summary (cgraph_node *node,
    4442              :                        vec <vec <escape_map>> &map,
    4443              :                        bool ignore_stores)
    4444              : {
    4445      1368262 :   if (!escape_summaries)
    4446              :     return;
    4447      1434995 :   for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
    4448        66733 :     update_escape_summary_1 (e, map, ignore_stores);
    4449      4113854 :   for (cgraph_edge *e = node->callees; e; e = e->next_callee)
    4450              :     {
    4451      2745592 :       if (!e->inline_failed)
    4452       586113 :         update_escape_summary (e->callee, map, ignore_stores);
    4453              :       else
    4454      2159479 :         update_escape_summary_1 (e, map, ignore_stores);
    4455              :     }
    4456              : }
    4457              : 
    4458              : /* Get parameter type from DECL.  This is only safe for special cases
    4459              :    like builtins we create fnspec for because the type match is checked
    4460              :    at fnspec creation time.  */
    4461              : 
    4462              : static tree
    4463        20208 : get_parm_type (tree decl, unsigned int i)
    4464              : {
    4465        20208 :   tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
    4466              : 
    4467        60523 :   for (unsigned int p = 0; p < i; p++)
    4468        40315 :     t = TREE_CHAIN (t);
    4469        20208 :   return TREE_VALUE (t);
    4470              : }
    4471              : 
    4472              : /* Return access mode for argument I of call E with FNSPEC.  */
    4473              : 
    4474              : static modref_access_node
    4475       246403 : get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
    4476              :                        unsigned int i, modref_parm_map &map)
    4477              : {
    4478       246403 :   tree size = NULL_TREE;
    4479       246403 :   unsigned int size_arg;
    4480              : 
    4481       246403 :   if (!fnspec.arg_specified_p (i))
    4482              :     ;
    4483       246403 :   else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
    4484              :     {
    4485        15069 :       cgraph_node *node = e->caller->inlined_to
    4486        20205 :                           ? e->caller->inlined_to : e->caller;
    4487        20205 :       ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
    4488        20205 :       ipa_edge_args *args = ipa_edge_args_sum->get (e);
    4489        20205 :       struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
    4490              : 
    4491        20205 :       if (jf)
    4492        20205 :         size = ipa_value_from_jfunc (caller_parms_info, jf,
    4493        20205 :                                      get_parm_type (e->callee->decl, size_arg));
    4494              :     }
    4495       226198 :   else if (fnspec.arg_access_size_given_by_type_p (i))
    4496            3 :     size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
    4497       246403 :   modref_access_node a = {0, -1, -1,
    4498       246403 :                           map.parm_offset, map.parm_index,
    4499       246403 :                           map.parm_offset_known, 0};
    4500       246403 :   poly_int64 size_hwi;
    4501       246403 :   if (size
    4502         8405 :       && poly_int_tree_p (size, &size_hwi)
    4503       254672 :       && coeffs_in_range_p (size_hwi, 0,
    4504              :                             HOST_WIDE_INT_MAX / BITS_PER_UNIT))
    4505              :     {
    4506         8102 :       a.size = -1;
    4507         8102 :       a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
    4508              :     }
    4509       246403 :   return a;
    4510              : }
    4511              : 
    4512              :  /* Collapse loads and return true if something changed.  */
    4513              : static bool
    4514      2313426 : collapse_loads (modref_summary *cur_summary,
    4515              :                 modref_summary_lto *cur_summary_lto)
    4516              : {
    4517      2313426 :   bool changed = false;
    4518              : 
    4519      2313426 :   if (cur_summary && !cur_summary->loads->every_base)
    4520              :     {
    4521       430935 :       cur_summary->loads->collapse ();
    4522       430935 :       changed = true;
    4523              :     }
    4524      2313426 :   if (cur_summary_lto
    4525       179852 :       && !cur_summary_lto->loads->every_base)
    4526              :     {
    4527        25001 :       cur_summary_lto->loads->collapse ();
    4528        25001 :       changed = true;
    4529              :     }
    4530      2313426 :   return changed;
    4531              : }
    4532              : 
    4533              : /* Collapse loads and return true if something changed.  */
    4534              : 
    4535              : static bool
    4536      1797781 : collapse_stores (modref_summary *cur_summary,
    4537              :                 modref_summary_lto *cur_summary_lto)
    4538              : {
    4539      1797781 :   bool changed = false;
    4540              : 
    4541      1797781 :   if (cur_summary && !cur_summary->stores->every_base)
    4542              :     {
    4543       431593 :       cur_summary->stores->collapse ();
    4544       431593 :       changed = true;
    4545              :     }
    4546      1797781 :   if (cur_summary_lto
    4547        45674 :       && !cur_summary_lto->stores->every_base)
    4548              :     {
    4549        10339 :       cur_summary_lto->stores->collapse ();
    4550        10339 :       changed = true;
    4551              :     }
    4552      1797781 :   return changed;
    4553              : }
    4554              : 
    4555              : /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
    4556              :    CUR_SUMMARY_LTO accordingly.  Return true if something changed.  */
    4557              : 
    4558              : static bool
    4559      2886690 : propagate_unknown_call (cgraph_node *node,
    4560              :                         cgraph_edge *e, int ecf_flags,
    4561              :                         modref_summary *cur_summary,
    4562              :                         modref_summary_lto *cur_summary_lto,
    4563              :                         bool nontrivial_scc)
    4564              : {
    4565      2886690 :   bool changed = false;
    4566      2886690 :   class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
    4567      2886690 :   auto_vec <modref_parm_map, 32> parm_map;
    4568      2886690 :   bool looping;
    4569              : 
    4570      2886690 :   if (e->callee
    4571      2886690 :       && builtin_safe_for_const_function_p (&looping, e->callee->decl))
    4572              :     {
    4573       305769 :       if (looping && cur_summary && !cur_summary->side_effects)
    4574              :         {
    4575          266 :           cur_summary->side_effects = true;
    4576          266 :           changed = true;
    4577              :         }
    4578       305769 :       if (looping && cur_summary_lto && !cur_summary_lto->side_effects)
    4579              :         {
    4580           45 :           cur_summary_lto->side_effects = true;
    4581           45 :           changed = true;
    4582              :         }
    4583       305769 :       return changed;
    4584              :     }
    4585              : 
    4586      2580921 :   if (!(ecf_flags & (ECF_CONST | ECF_PURE))
    4587       268739 :       || (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
    4588       265452 :       || nontrivial_scc)
    4589              :     {
    4590      2315568 :       if (cur_summary && !cur_summary->side_effects)
    4591              :         {
    4592       403996 :           cur_summary->side_effects = true;
    4593       403996 :           changed = true;
    4594              :         }
    4595      2315568 :       if (cur_summary_lto && !cur_summary_lto->side_effects)
    4596              :         {
    4597        20881 :           cur_summary_lto->side_effects = true;
    4598        20881 :           changed = true;
    4599              :         }
    4600      2315568 :       if (!ignore_nondeterminism_p (node->decl, ecf_flags,
    4601      2315568 :                                     e->callee ? TREE_TYPE (e->callee->decl)
    4602              :                                               : NULL_TREE))
    4603              :         {
    4604      1903850 :           if (cur_summary && !cur_summary->nondeterministic)
    4605              :             {
    4606       362827 :               cur_summary->nondeterministic = true;
    4607       362827 :               changed = true;
    4608              :             }
    4609      1903850 :           if (cur_summary_lto && !cur_summary_lto->nondeterministic)
    4610              :             {
    4611         6317 :               cur_summary_lto->nondeterministic = true;
    4612         6317 :               changed = true;
    4613              :             }
    4614              :         }
    4615              :     }
    4616      2580921 :   if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
    4617              :     return changed;
    4618              : 
    4619      2580566 :   if (fnspec_sum
    4620      2580566 :       && compute_parm_map (e, &parm_map))
    4621              :     {
    4622       533989 :       attr_fnspec fnspec (fnspec_sum->fnspec);
    4623              : 
    4624       533989 :       gcc_checking_assert (fnspec.known_p ());
    4625       533989 :       if (fnspec.global_memory_read_p ())
    4626            0 :         collapse_loads (cur_summary, cur_summary_lto);
    4627              :       else
    4628              :         {
    4629       533989 :           tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
    4630      1192825 :           for (unsigned i = 0; i < parm_map.length () && t;
    4631       658836 :                i++, t = TREE_CHAIN (t))
    4632       925685 :             if (!POINTER_TYPE_P (TREE_VALUE (t)))
    4633              :               ;
    4634       684676 :           else if (!fnspec.arg_specified_p (i)
    4635       684676 :                    || fnspec.arg_maybe_read_p (i))
    4636              :             {
    4637       459650 :               modref_parm_map map = parm_map[i];
    4638       459650 :               if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
    4639        25892 :                 continue;
    4640       433758 :               if (map.parm_index == MODREF_UNKNOWN_PARM)
    4641              :                 {
    4642       266849 :                   collapse_loads (cur_summary, cur_summary_lto);
    4643       266849 :                   break;
    4644              :                 }
    4645       166909 :               if (cur_summary)
    4646       279360 :                 changed |= cur_summary->loads->insert
    4647       139680 :                   (node->decl, 0, 0,
    4648       279360 :                    get_access_for_fnspec (e, fnspec, i, map), false);
    4649       166909 :               if (cur_summary_lto)
    4650       179078 :                 changed |= cur_summary_lto->loads->insert
    4651        89539 :                   (node->decl, 0, 0,
    4652       179078 :                    get_access_for_fnspec (e, fnspec, i, map), false);
    4653              :             }
    4654              :         }
    4655       533989 :       if (ignore_stores_p (node->decl, ecf_flags))
    4656              :         ;
    4657       306929 :       else if (fnspec.global_memory_written_p ())
    4658            0 :         collapse_stores (cur_summary, cur_summary_lto);
    4659              :       else
    4660              :         {
    4661       306929 :           tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
    4662       507160 :           for (unsigned i = 0; i < parm_map.length () && t;
    4663       200231 :                i++, t = TREE_CHAIN (t))
    4664       374257 :             if (!POINTER_TYPE_P (TREE_VALUE (t)))
    4665              :               ;
    4666       251053 :           else if (!fnspec.arg_specified_p (i)
    4667       251053 :                    || fnspec.arg_maybe_written_p (i))
    4668              :             {
    4669       229497 :               modref_parm_map map = parm_map[i];
    4670       229497 :               if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
    4671        38624 :                 continue;
    4672       190873 :               if (map.parm_index == MODREF_UNKNOWN_PARM)
    4673              :                 {
    4674       174026 :                   collapse_stores (cur_summary, cur_summary_lto);
    4675       174026 :                   break;
    4676              :                 }
    4677        16847 :               if (cur_summary)
    4678        33570 :                 changed |= cur_summary->stores->insert
    4679        16785 :                   (node->decl, 0, 0,
    4680        33570 :                    get_access_for_fnspec (e, fnspec, i, map), false);
    4681        16847 :               if (cur_summary_lto)
    4682          798 :                 changed |= cur_summary_lto->stores->insert
    4683          399 :                   (node->decl, 0, 0,
    4684          798 :                    get_access_for_fnspec (e, fnspec, i, map), false);
    4685              :             }
    4686              :         }
    4687       533989 :       if (fnspec.errno_maybe_written_p () && flag_errno_math)
    4688              :         {
    4689        48143 :           if (cur_summary && !cur_summary->writes_errno)
    4690              :             {
    4691        23595 :               cur_summary->writes_errno = true;
    4692        23595 :               changed = true;
    4693              :             }
    4694        48143 :           if (cur_summary_lto && !cur_summary_lto->writes_errno)
    4695              :             {
    4696          393 :               cur_summary_lto->writes_errno = true;
    4697          393 :               changed = true;
    4698              :             }
    4699              :         }
    4700       533989 :       return changed;
    4701              :     }
    4702      2046577 :   if (dump_file)
    4703           50 :     fprintf (dump_file, "      collapsing loads\n");
    4704      2046577 :   changed |= collapse_loads (cur_summary, cur_summary_lto);
    4705      2046577 :   if (!ignore_stores_p (node->decl, ecf_flags))
    4706              :     {
    4707      1623755 :       if (dump_file)
    4708           48 :         fprintf (dump_file, "      collapsing stores\n");
    4709      1623755 :       changed |= collapse_stores (cur_summary, cur_summary_lto);
    4710              :     }
    4711              :   return changed;
    4712      2886690 : }
    4713              : 
    4714              : /* Maybe remove summaries of NODE pointed to by CUR_SUMMARY_PTR
    4715              :    and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS.  */
    4716              : 
    4717              : static void
    4718       639549 : remove_useless_summaries (cgraph_node *node,
    4719              :                           modref_summary **cur_summary_ptr,
    4720              :                           modref_summary_lto **cur_summary_lto_ptr,
    4721              :                           int ecf_flags)
    4722              : {
    4723       639549 :   if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
    4724              :     {
    4725       126401 :       optimization_summaries->remove (node);
    4726       126401 :       *cur_summary_ptr = NULL;
    4727              :     }
    4728       639549 :   if (*cur_summary_lto_ptr
    4729       639549 :       && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
    4730              :     {
    4731         4015 :       summaries_lto->remove (node);
    4732         4015 :       *cur_summary_lto_ptr = NULL;
    4733              :     }
    4734       639549 : }
    4735              : 
    4736              : /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
    4737              :    and propagate loads/stores.  */
    4738              : 
    4739              : static bool
    4740      2385204 : modref_propagate_in_scc (cgraph_node *component_node)
    4741              : {
    4742      2385204 :   bool changed = true;
    4743      2385204 :   bool first = true;
    4744      2385204 :   int iteration = 0;
    4745              : 
    4746      5471947 :   while (changed)
    4747              :     {
    4748      3086743 :       bool nontrivial_scc
    4749      3086743 :                  = ((struct ipa_dfs_info *) component_node->aux)->next_cycle;
    4750      3086743 :       changed = false;
    4751      6206072 :       for (struct cgraph_node *cur = component_node; cur;
    4752      3119329 :            cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
    4753              :         {
    4754      3119329 :           cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
    4755      6238658 :           modref_summary *cur_summary = optimization_summaries
    4756      3119329 :                                         ? optimization_summaries->get (node)
    4757              :                                         : NULL;
    4758      6238658 :           modref_summary_lto *cur_summary_lto = summaries_lto
    4759      3119329 :                                                 ? summaries_lto->get (node)
    4760              :                                                 : NULL;
    4761              : 
    4762      3119329 :           if (!cur_summary && !cur_summary_lto)
    4763       843654 :             continue;
    4764              : 
    4765      2302994 :           int cur_ecf_flags = flags_from_decl_or_type (node->decl);
    4766              : 
    4767      2302994 :           if (dump_file)
    4768           74 :             fprintf (dump_file, "  Processing %s%s%s\n",
    4769              :                      cur->dump_name (),
    4770           74 :                      TREE_READONLY (cur->decl) ? " (const)" : "",
    4771           74 :                      DECL_PURE_P (cur->decl) ? " (pure)" : "");
    4772              : 
    4773      2398911 :           for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
    4774              :             {
    4775       123236 :               if (dump_file)
    4776           48 :                 fprintf (dump_file, "    Indirect call\n");
    4777       123236 :               if (propagate_unknown_call
    4778       123236 :                            (node, e, e->indirect_info->ecf_flags,
    4779              :                             cur_summary, cur_summary_lto,
    4780              :                             nontrivial_scc))
    4781              :                 {
    4782        46379 :                   changed = true;
    4783        46379 :                   remove_useless_summaries (node, &cur_summary,
    4784              :                                             &cur_summary_lto,
    4785              :                                             cur_ecf_flags);
    4786        46379 :                   if (!cur_summary && !cur_summary_lto)
    4787              :                     break;
    4788              :                 }
    4789              :             }
    4790              : 
    4791      2302994 :           if (!cur_summary && !cur_summary_lto)
    4792        27319 :             continue;
    4793              : 
    4794      9098731 :           for (cgraph_edge *callee_edge = cur->callees; callee_edge;
    4795      6823056 :                callee_edge = callee_edge->next_callee)
    4796              :             {
    4797      6924050 :               int flags = flags_from_decl_or_type (callee_edge->callee->decl);
    4798      6924050 :               modref_summary *callee_summary = NULL;
    4799      6924050 :               modref_summary_lto *callee_summary_lto = NULL;
    4800      6924050 :               struct cgraph_node *callee;
    4801              : 
    4802      6924050 :               if (!callee_edge->inline_failed
    4803      5969925 :                  || ((flags & ECF_CONST)
    4804       672178 :                      && !(flags & ECF_LOOPING_CONST_OR_PURE)))
    4805      7451413 :                 continue;
    4806              : 
    4807              :               /* Get the callee and its summary.  */
    4808      5625777 :               enum availability avail;
    4809      5625777 :               callee = callee_edge->callee->ultimate_alias_target
    4810      5625777 :                          (&avail, cur);
    4811              : 
    4812              :               /* It is not necessary to re-process calls outside of the
    4813              :                  SCC component.  */
    4814      5625777 :               if (iteration > 0
    4815      2185452 :                   && (!callee->aux
    4816       539325 :                       || ((struct ipa_dfs_info *)cur->aux)->scc_no
    4817       539325 :                           != ((struct ipa_dfs_info *)callee->aux)->scc_no))
    4818      2178195 :                 continue;
    4819              : 
    4820      3447582 :               if (dump_file)
    4821           15 :                 fprintf (dump_file, "    Call to %s\n",
    4822           15 :                          callee_edge->callee->dump_name ());
    4823              : 
    4824      3447582 :               bool ignore_stores = ignore_stores_p (cur->decl, flags);
    4825              : 
    4826      3447582 :               if (avail <= AVAIL_INTERPOSABLE)
    4827              :                 {
    4828      2675060 :                   if (dump_file)
    4829            5 :                     fprintf (dump_file, "      Call target interposable"
    4830              :                              " or not available\n");
    4831      5350120 :                   changed |= propagate_unknown_call
    4832      2675060 :                                (node, callee_edge, flags,
    4833              :                                 cur_summary, cur_summary_lto,
    4834              :                                 nontrivial_scc);
    4835      2675060 :                   if (!cur_summary && !cur_summary_lto)
    4836              :                     break;
    4837      2675060 :                   continue;
    4838              :                 }
    4839              : 
    4840              :               /* We don't know anything about CALLEE, hence we cannot tell
    4841              :                  anything about the entire component.  */
    4842              : 
    4843       772522 :               if (cur_summary
    4844       772522 :                   && !(callee_summary = optimization_summaries->get (callee)))
    4845              :                 {
    4846        87120 :                   if (dump_file)
    4847            0 :                     fprintf (dump_file, "      No call target summary\n");
    4848        87120 :                   changed |= propagate_unknown_call
    4849        87120 :                                (node, callee_edge, flags,
    4850              :                                 cur_summary, NULL,
    4851              :                                 nontrivial_scc);
    4852              :                 }
    4853       772522 :               if (cur_summary_lto
    4854       772522 :                   && !(callee_summary_lto = summaries_lto->get (callee)))
    4855              :                 {
    4856         1274 :                   if (dump_file)
    4857            0 :                     fprintf (dump_file, "      No call target summary\n");
    4858         1274 :                   changed |= propagate_unknown_call
    4859         1274 :                                (node, callee_edge, flags,
    4860              :                                 NULL, cur_summary_lto,
    4861              :                                 nontrivial_scc);
    4862              :                 }
    4863              : 
    4864       600837 :               if (callee_summary && !cur_summary->side_effects
    4865       885518 :                   && (callee_summary->side_effects
    4866        65015 :                       || callee_edge->recursive_p ()))
    4867              :                 {
    4868        49195 :                   cur_summary->side_effects = true;
    4869        49195 :                   changed = true;
    4870              :                 }
    4871       180759 :               if (callee_summary_lto && !cur_summary_lto->side_effects
    4872       795308 :                   && (callee_summary_lto->side_effects
    4873        20860 :                       || callee_edge->recursive_p ()))
    4874              :                 {
    4875         1985 :                   cur_summary_lto->side_effects = true;
    4876         1985 :                   changed = true;
    4877              :                 }
    4878       600837 :               if (callee_summary && !cur_summary->nondeterministic
    4879       180671 :                   && callee_summary->nondeterministic
    4880       813270 :                   && !ignore_nondeterminism_p
    4881        40748 :                           (cur->decl, flags,
    4882        40748 :                            TREE_TYPE (callee_edge->callee->decl)))
    4883              :                 {
    4884        39400 :                   cur_summary->nondeterministic = true;
    4885        39400 :                   changed = true;
    4886              :                 }
    4887       180759 :               if (callee_summary_lto && !cur_summary_lto->nondeterministic
    4888        62233 :                   && callee_summary_lto->nondeterministic
    4889       774905 :                   && !ignore_nondeterminism_p
    4890         2383 :                           (cur->decl, flags,
    4891         2383 :                            TREE_TYPE (callee_edge->callee->decl)))
    4892              :                 {
    4893         2048 :                   cur_summary_lto->nondeterministic = true;
    4894         2048 :                   changed = true;
    4895              :                 }
    4896       772522 :               if (flags & (ECF_CONST | ECF_NOVOPS))
    4897         1612 :                 continue;
    4898              : 
    4899              :               /* We can not safely optimize based on summary of callee if it
    4900              :                  does not always bind to current def: it is possible that
    4901              :                  memory load was optimized out earlier which may not happen in
    4902              :                  the interposed variant.  */
    4903       770910 :               if (!callee_edge->binds_to_current_def_p ())
    4904              :                 {
    4905       142326 :                   if (cur_summary && !cur_summary->calls_interposable)
    4906              :                     {
    4907        43794 :                       cur_summary->calls_interposable = true;
    4908        43794 :                       changed = true;
    4909              :                     }
    4910       142326 :                   if (cur_summary_lto && !cur_summary_lto->calls_interposable)
    4911              :                     {
    4912           54 :                       cur_summary_lto->calls_interposable = true;
    4913           54 :                       changed = true;
    4914              :                     }
    4915       142326 :                   if (dump_file)
    4916            0 :                     fprintf (dump_file, "      May not bind local;"
    4917              :                              " collapsing loads\n");
    4918              :                 }
    4919              : 
    4920              : 
    4921       770910 :               auto_vec <modref_parm_map, 32> parm_map;
    4922       770910 :               modref_parm_map chain_map;
    4923              :               /* TODO: Once we get jump functions for static chains we could
    4924              :                  compute this.  */
    4925       770910 :               chain_map.parm_index = MODREF_UNKNOWN_PARM;
    4926              : 
    4927       770910 :               compute_parm_map (callee_edge, &parm_map);
    4928              : 
    4929              :               /* Merge in callee's information.  */
    4930       770910 :               if (callee_summary)
    4931              :                 {
    4932      1198694 :                   changed |= cur_summary->loads->merge
    4933       599347 :                                   (node->decl, callee_summary->loads,
    4934       599347 :                                    &parm_map, &chain_map, !first);
    4935       599347 :                   if (!ignore_stores)
    4936              :                     {
    4937      1107826 :                       changed |= cur_summary->stores->merge
    4938       553913 :                                       (node->decl, callee_summary->stores,
    4939              :                                        &parm_map, &chain_map, !first);
    4940       553913 :                       if (!cur_summary->writes_errno
    4941       466022 :                           && callee_summary->writes_errno)
    4942              :                         {
    4943        13672 :                           cur_summary->writes_errno = true;
    4944        13672 :                           changed = true;
    4945              :                         }
    4946              :                     }
    4947              :                 }
    4948       770910 :               if (callee_summary_lto)
    4949              :                 {
    4950       361238 :                   changed |= cur_summary_lto->loads->merge
    4951       180619 :                                   (node->decl, callee_summary_lto->loads,
    4952       180619 :                                    &parm_map, &chain_map, !first);
    4953       180619 :                   if (!ignore_stores)
    4954              :                     {
    4955       349170 :                       changed |= cur_summary_lto->stores->merge
    4956       174585 :                                       (node->decl, callee_summary_lto->stores,
    4957              :                                        &parm_map, &chain_map, !first);
    4958       174585 :                       if (!cur_summary_lto->writes_errno
    4959       174520 :                           && callee_summary_lto->writes_errno)
    4960              :                         {
    4961           93 :                           cur_summary_lto->writes_errno = true;
    4962           93 :                           changed = true;
    4963              :                         }
    4964              :                     }
    4965              :                 }
    4966       770910 :               if (changed)
    4967       593170 :                 remove_useless_summaries (node, &cur_summary,
    4968              :                                           &cur_summary_lto,
    4969              :                                           cur_ecf_flags);
    4970       770910 :               if (!cur_summary && !cur_summary_lto)
    4971              :                 break;
    4972       669916 :               if (dump_file && changed)
    4973              :                 {
    4974           10 :                   if (cur_summary)
    4975            6 :                     cur_summary->dump (dump_file);
    4976           10 :                   if (cur_summary_lto)
    4977            4 :                     cur_summary_lto->dump (dump_file);
    4978           10 :                   dump_modref_edge_summaries (dump_file, node, 4);
    4979              :                 }
    4980       770910 :             }
    4981              :         }
    4982      3086743 :       iteration++;
    4983      3086743 :       first = false;
    4984              :     }
    4985      2385204 :   if (dump_file)
    4986           58 :     fprintf (dump_file,
    4987              :              "Propagation finished in %i iterations\n", iteration);
    4988              :   bool pureconst = false;
    4989      4788455 :   for (struct cgraph_node *cur = component_node; cur;
    4990      2403251 :        cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
    4991      2403251 :     if (!cur->inlined_to && opt_for_fn (cur->decl, flag_ipa_pure_const))
    4992              :       {
    4993      1068662 :         modref_summary *summary = optimization_summaries
    4994      1068662 :                                   ? optimization_summaries->get (cur)
    4995              :                                   : NULL;
    4996      1068662 :         modref_summary_lto *summary_lto = summaries_lto
    4997      1068662 :                                           ? summaries_lto->get (cur)
    4998              :                                           : NULL;
    4999      1068662 :         if (summary && !summary->stores->every_base && !summary->stores->bases
    5000       159137 :             && !summary->nondeterministic)
    5001              :           {
    5002       147528 :             if (!summary->loads->every_base && !summary->loads->bases
    5003        67954 :                 && !summary->calls_interposable)
    5004        67440 :               pureconst |= ipa_make_function_const
    5005        67440 :                      (cur, summary->side_effects, false);
    5006              :             else
    5007        80088 :               pureconst |= ipa_make_function_pure
    5008        80088 :                      (cur, summary->side_effects, false);
    5009              :           }
    5010      1068662 :         if (summary_lto && !summary_lto->stores->every_base
    5011        49501 :             && !summary_lto->stores->bases && !summary_lto->nondeterministic)
    5012              :           {
    5013        13437 :             if (!summary_lto->loads->every_base && !summary_lto->loads->bases
    5014         3397 :                 && !summary_lto->calls_interposable)
    5015         3395 :               pureconst |= ipa_make_function_const
    5016         3395 :                      (cur, summary_lto->side_effects, false);
    5017              :             else
    5018        10042 :               pureconst |= ipa_make_function_pure
    5019        10042 :                      (cur, summary_lto->side_effects, false);
    5020              :           }
    5021              :      }
    5022      2385204 :   return pureconst;
    5023              : }
    5024              : 
    5025              : /* Dump results of propagation in SCC rooted in COMPONENT_NODE.  */
    5026              : 
    5027              : static void
    5028           58 : modref_propagate_dump_scc (cgraph_node *component_node)
    5029              : {
    5030          116 :   for (struct cgraph_node *cur = component_node; cur;
    5031           58 :        cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
    5032           58 :     if (!cur->inlined_to)
    5033              :       {
    5034           47 :         modref_summary *cur_summary = optimization_summaries
    5035           47 :                                       ? optimization_summaries->get (cur)
    5036              :                                       : NULL;
    5037           47 :         modref_summary_lto *cur_summary_lto = summaries_lto
    5038           47 :                                               ? summaries_lto->get (cur)
    5039              :                                               : NULL;
    5040              : 
    5041           47 :         fprintf (dump_file, "Propagated modref for %s%s%s\n",
    5042              :                  cur->dump_name (),
    5043           47 :                  TREE_READONLY (cur->decl) ? " (const)" : "",
    5044           47 :                  DECL_PURE_P (cur->decl) ? " (pure)" : "");
    5045           47 :         if (optimization_summaries)
    5046              :           {
    5047           41 :             if (cur_summary)
    5048           35 :               cur_summary->dump (dump_file);
    5049              :             else
    5050            6 :               fprintf (dump_file, "  Not tracked\n");
    5051              :           }
    5052           47 :         if (summaries_lto)
    5053              :           {
    5054           10 :             if (cur_summary_lto)
    5055           10 :               cur_summary_lto->dump (dump_file);
    5056              :             else
    5057            0 :               fprintf (dump_file, "  Not tracked (lto)\n");
    5058              :           }
    5059              :       }
    5060           58 : }
    5061              : 
    5062              : /* Determine EAF flags know for call E with CALLEE_ECF_FLAGS and ARG.  */
    5063              : 
    5064              : int
    5065       228644 : implicit_eaf_flags_for_edge_and_arg (cgraph_edge *e, int callee_ecf_flags,
    5066              :                                      bool ignore_stores, int arg)
    5067              : {
    5068              :   /* Returning the value is already accounted to at local propagation.  */
    5069       228644 :   int implicit_flags = EAF_NOT_RETURNED_DIRECTLY
    5070              :                        | EAF_NOT_RETURNED_INDIRECTLY;
    5071       228644 :   if (ignore_stores)
    5072       102699 :      implicit_flags |= ignore_stores_eaf_flags;
    5073       228644 :   if (callee_ecf_flags & ECF_PURE)
    5074        98004 :     implicit_flags |= implicit_pure_eaf_flags;
    5075       228644 :   if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
    5076          387 :     implicit_flags |= implicit_const_eaf_flags;
    5077       228644 :   class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
    5078       228644 :   if (fnspec_sum)
    5079              :     {
    5080        87616 :       attr_fnspec fnspec (fnspec_sum->fnspec);
    5081        87616 :       implicit_flags |= fnspec.arg_eaf_flags (arg);
    5082              :     }
    5083       228644 :   return implicit_flags;
    5084              : }
    5085              : 
    5086              : /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
    5087              :    and SUMMARY_LTO to CUR_SUMMARY_LTO.
    5088              :    Return true if something changed.  */
    5089              : 
    5090              : static bool
    5091       123376 : modref_merge_call_site_flags (escape_summary *sum,
    5092              :                               modref_summary *cur_summary,
    5093              :                               modref_summary_lto *cur_summary_lto,
    5094              :                               modref_summary *summary,
    5095              :                               modref_summary_lto *summary_lto,
    5096              :                               tree caller,
    5097              :                               cgraph_edge *e,
    5098              :                               int caller_ecf_flags,
    5099              :                               int callee_ecf_flags,
    5100              :                               bool binds_to_current_def)
    5101              : {
    5102       123376 :   escape_entry *ee;
    5103       123376 :   unsigned int i;
    5104       123376 :   bool changed = false;
    5105       123376 :   bool ignore_stores = ignore_stores_p (caller, callee_ecf_flags);
    5106              : 
    5107              :   /* Return early if we have no useful info to propagate.  */
    5108       123376 :   if ((!cur_summary
    5109       101963 :        || (!cur_summary->arg_flags.length ()
    5110          560 :            && !cur_summary->static_chain_flags
    5111           26 :            && !cur_summary->retslot_flags))
    5112       123396 :       && (!cur_summary_lto
    5113        21413 :           || (!cur_summary_lto->arg_flags.length ()
    5114           29 :               && !cur_summary_lto->static_chain_flags
    5115            0 :               && !cur_summary_lto->retslot_flags)))
    5116              :     return false;
    5117              : 
    5118       260351 :   FOR_EACH_VEC_ELT (sum->esc, i, ee)
    5119              :     {
    5120       136995 :       int flags = 0;
    5121       136995 :       int flags_lto = 0;
    5122       136995 :       int implicit_flags = implicit_eaf_flags_for_edge_and_arg
    5123       136995 :                                 (e, callee_ecf_flags, ignore_stores, ee->arg);
    5124              : 
    5125       136995 :       if (summary && ee->arg < summary->arg_flags.length ())
    5126        30585 :         flags = summary->arg_flags[ee->arg];
    5127       136995 :       if (summary_lto
    5128       136995 :           && ee->arg < summary_lto->arg_flags.length ())
    5129          805 :         flags_lto = summary_lto->arg_flags[ee->arg];
    5130       136995 :       if (!ee->direct)
    5131              :         {
    5132        27210 :           flags = deref_flags (flags, ignore_stores);
    5133        27210 :           flags_lto = deref_flags (flags_lto, ignore_stores);
    5134              :         }
    5135       136995 :       if (ignore_stores)
    5136        88157 :          implicit_flags |= ignore_stores_eaf_flags;
    5137       136995 :       if (callee_ecf_flags & ECF_PURE)
    5138        83786 :         implicit_flags |= implicit_pure_eaf_flags;
    5139       136995 :       if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
    5140          387 :         implicit_flags |= implicit_const_eaf_flags;
    5141       136995 :       class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
    5142       136995 :       if (fnspec_sum)
    5143              :         {
    5144        87616 :           attr_fnspec fnspec (fnspec_sum->fnspec);
    5145        87616 :           implicit_flags |= fnspec.arg_eaf_flags (ee->arg);
    5146              :         }
    5147       136995 :       if (!ee->direct)
    5148        27210 :         implicit_flags = deref_flags (implicit_flags, ignore_stores);
    5149       136995 :       flags |= implicit_flags;
    5150       136995 :       flags_lto |= implicit_flags;
    5151       136995 :       if (!binds_to_current_def && (flags || flags_lto))
    5152              :         {
    5153       114339 :           flags = interposable_eaf_flags (flags, implicit_flags);
    5154       114339 :           flags_lto = interposable_eaf_flags (flags_lto, implicit_flags);
    5155              :         }
    5156       136995 :       if (!(flags & EAF_UNUSED)
    5157       250485 :           && cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ())
    5158              :         {
    5159       114037 :           eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
    5160       114037 :                            ? cur_summary->retslot_flags
    5161              :                            : ee->parm_index == MODREF_STATIC_CHAIN_PARM
    5162              :                            ? cur_summary->static_chain_flags
    5163       114037 :                            : cur_summary->arg_flags[ee->parm_index];
    5164       114037 :           if ((f & flags) != f)
    5165              :             {
    5166        99680 :               f = remove_useless_eaf_flags
    5167        49840 :                          (f & flags, caller_ecf_flags,
    5168        49840 :                           VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
    5169        49840 :               changed = true;
    5170              :             }
    5171              :         }
    5172       136995 :       if (!(flags_lto & EAF_UNUSED)
    5173       136995 :           && cur_summary_lto
    5174       223759 :           && ee->parm_index < (int)cur_summary_lto->arg_flags.length ())
    5175              :         {
    5176        43413 :           eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
    5177        43413 :                            ? cur_summary_lto->retslot_flags
    5178              :                            : ee->parm_index == MODREF_STATIC_CHAIN_PARM
    5179              :                            ? cur_summary_lto->static_chain_flags
    5180        43413 :                            : cur_summary_lto->arg_flags[ee->parm_index];
    5181        43413 :           if ((f & flags_lto) != f)
    5182              :             {
    5183         3334 :               f = remove_useless_eaf_flags
    5184         1667 :                          (f & flags_lto, caller_ecf_flags,
    5185         1667 :                           VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
    5186         1667 :               changed = true;
    5187              :             }
    5188              :         }
    5189              :     }
    5190              :   return changed;
    5191              : }
    5192              : 
    5193              : /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
    5194              :    and propagate arg flags.  */
    5195              : 
    5196              : static void
    5197      2385204 : modref_propagate_flags_in_scc (cgraph_node *component_node)
    5198              : {
    5199      2385204 :   bool changed = true;
    5200      2385204 :   int iteration = 0;
    5201              : 
    5202      4809834 :   while (changed)
    5203              :     {
    5204              :       changed = false;
    5205      4867794 :       for (struct cgraph_node *cur = component_node; cur;
    5206      2443164 :            cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
    5207              :         {
    5208      2443164 :           cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
    5209      2443164 :           modref_summary *cur_summary = optimization_summaries
    5210      2443164 :                                         ? optimization_summaries->get (node)
    5211              :                                         : NULL;
    5212      2443164 :           modref_summary_lto *cur_summary_lto = summaries_lto
    5213      2443164 :                                                 ? summaries_lto->get (node)
    5214              :                                                 : NULL;
    5215              : 
    5216      2443164 :           if (!cur_summary && !cur_summary_lto)
    5217       814533 :             continue;
    5218      1628631 :           int caller_ecf_flags = flags_from_decl_or_type (cur->decl);
    5219              : 
    5220      1628631 :           if (dump_file)
    5221           55 :             fprintf (dump_file, "  Processing %s%s%s\n",
    5222              :                      cur->dump_name (),
    5223           55 :                      TREE_READONLY (cur->decl) ? " (const)" : "",
    5224           55 :                      DECL_PURE_P (cur->decl) ? " (pure)" : "");
    5225              : 
    5226      1696742 :           for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
    5227              :             {
    5228        68111 :               escape_summary *sum = escape_summaries->get (e);
    5229              : 
    5230        68111 :               if (!sum || ((e->indirect_info->ecf_flags & ECF_CONST)
    5231            0 :                   && !(e->indirect_info->ecf_flags & ECF_LOOPING_CONST_OR_PURE)))
    5232        67880 :                 continue;
    5233              : 
    5234          231 :               changed |= modref_merge_call_site_flags
    5235          231 :                                 (sum, cur_summary, cur_summary_lto,
    5236              :                                  NULL, NULL,
    5237              :                                  node->decl,
    5238              :                                  e,
    5239              :                                  caller_ecf_flags,
    5240              :                                  e->indirect_info->ecf_flags,
    5241              :                                  false);
    5242              :             }
    5243              : 
    5244      1628631 :           if (!cur_summary && !cur_summary_lto)
    5245              :             continue;
    5246              : 
    5247      6283358 :           for (cgraph_edge *callee_edge = cur->callees; callee_edge;
    5248      4654727 :                callee_edge = callee_edge->next_callee)
    5249              :             {
    5250      4654727 :               int ecf_flags = flags_from_decl_or_type
    5251      4654727 :                                  (callee_edge->callee->decl);
    5252      4654727 :               modref_summary *callee_summary = NULL;
    5253      4654727 :               modref_summary_lto *callee_summary_lto = NULL;
    5254      4654727 :               struct cgraph_node *callee;
    5255              : 
    5256      4654727 :               if ((ecf_flags & ECF_CONST)
    5257       520206 :                   && !(ecf_flags & ECF_LOOPING_CONST_OR_PURE))
    5258      4531582 :                 continue;
    5259              : 
    5260              :               /* Get the callee and its summary.  */
    5261      4416626 :               enum availability avail;
    5262      4416626 :               callee = callee_edge->callee->ultimate_alias_target
    5263      4416626 :                          (&avail, cur);
    5264              : 
    5265              :               /* It is not necessary to re-process calls outside of the
    5266              :                  SCC component.  */
    5267      4416626 :               if (iteration > 0
    5268       378859 :                   && (!callee->aux
    5269       231790 :                       || ((struct ipa_dfs_info *)cur->aux)->scc_no
    5270       231790 :                           != ((struct ipa_dfs_info *)callee->aux)->scc_no))
    5271       377301 :                 continue;
    5272              : 
    5273      4039325 :               escape_summary *sum = escape_summaries->get (callee_edge);
    5274      4039325 :               if (!sum)
    5275      3916180 :                 continue;
    5276              : 
    5277       123145 :               if (dump_file)
    5278            3 :                 fprintf (dump_file, "    Call to %s\n",
    5279            3 :                          callee_edge->callee->dump_name ());
    5280              : 
    5281       123145 :               if (avail <= AVAIL_INTERPOSABLE
    5282        25525 :                   || callee_edge->call_stmt_cannot_inline_p)
    5283              :                 ;
    5284              :               else
    5285              :                 {
    5286        25525 :                   if (cur_summary)
    5287        25255 :                     callee_summary = optimization_summaries->get (callee);
    5288        25525 :                   if (cur_summary_lto)
    5289          593 :                     callee_summary_lto = summaries_lto->get (callee);
    5290              :                 }
    5291       246290 :               changed |= modref_merge_call_site_flags
    5292       123145 :                                 (sum, cur_summary, cur_summary_lto,
    5293              :                                  callee_summary, callee_summary_lto,
    5294              :                                  node->decl,
    5295              :                                  callee_edge,
    5296              :                                  caller_ecf_flags,
    5297              :                                  ecf_flags,
    5298       123145 :                                  callee->binds_to_current_def_p ());
    5299       123145 :               if (dump_file && changed)
    5300              :                 {
    5301            3 :                   if (cur_summary)
    5302            3 :                     cur_summary->dump (dump_file);
    5303            3 :                   if (cur_summary_lto)
    5304            0 :                     cur_summary_lto->dump (dump_file);
    5305              :                 }
    5306              :             }
    5307              :         }
    5308      2424630 :       iteration++;
    5309              :     }
    5310      2385204 :   if (dump_file)
    5311           58 :     fprintf (dump_file,
    5312              :              "Propagation of flags finished in %i iterations\n", iteration);
    5313      2385204 : }
    5314              : 
    5315              : }  /* ANON namespace.  */
    5316              : 
    5317              : /* Call EDGE was inlined; merge summary from callee to the caller.  */
    5318              : 
    5319              : void
    5320      3900094 : ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
    5321              : {
    5322      3900094 :   if (!summaries && !summaries_lto)
    5323              :     return;
    5324              : 
    5325       672940 :   struct cgraph_node *to = (edge->caller->inlined_to
    5326       907934 :                             ? edge->caller->inlined_to : edge->caller);
    5327       907934 :   class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
    5328       907934 :   class modref_summary_lto *to_info_lto = summaries_lto
    5329       907934 :                                           ? summaries_lto->get (to) : NULL;
    5330              : 
    5331       907934 :   if (!to_info && !to_info_lto)
    5332              :     {
    5333       125785 :       if (summaries)
    5334       125008 :         summaries->remove (edge->callee);
    5335       125785 :       if (summaries_lto)
    5336         1829 :         summaries_lto->remove (edge->callee);
    5337       125785 :       remove_modref_edge_summaries (edge->callee);
    5338       125785 :       return;
    5339              :     }
    5340              : 
    5341       782149 :   class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
    5342              :                                       : NULL;
    5343       782149 :   class modref_summary_lto *callee_info_lto
    5344       782149 :                  = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
    5345       782149 :   int flags = flags_from_decl_or_type (edge->callee->decl);
    5346              :   /* Combine in outer flags.  */
    5347       782149 :   cgraph_node *n;
    5348      1199001 :   for (n = edge->caller; n->inlined_to; n = n->callers->caller)
    5349       416852 :     flags |= flags_from_decl_or_type (n->decl);
    5350       782149 :   flags |= flags_from_decl_or_type (n->decl);
    5351       782149 :   bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
    5352              : 
    5353       782149 :   if (!callee_info && to_info)
    5354              :     {
    5355        11450 :       if (!(flags & (ECF_CONST | ECF_NOVOPS)))
    5356         9923 :         to_info->loads->collapse ();
    5357        11450 :       if (!ignore_stores)
    5358         9284 :         to_info->stores->collapse ();
    5359              :     }
    5360       782149 :   if (!callee_info_lto && to_info_lto)
    5361              :     {
    5362          278 :       if (!(flags & (ECF_CONST | ECF_NOVOPS)))
    5363          157 :         to_info_lto->loads->collapse ();
    5364          278 :       if (!ignore_stores)
    5365          125 :         to_info_lto->stores->collapse ();
    5366              :     }
    5367              :   /* Merge side effects and non-determinism.
    5368              :      PURE/CONST flags makes functions deterministic and if there is
    5369              :      no LOOPING_CONST_OR_PURE they also have no side effects.  */
    5370       782149 :   if (!(flags & (ECF_CONST | ECF_PURE))
    5371       105460 :       || (flags & ECF_LOOPING_CONST_OR_PURE))
    5372              :     {
    5373       702059 :       bool set_nondeterministic
    5374              :               = !ignore_nondeterminism_p
    5375       702059 :                       (edge->caller->decl, flags,
    5376       702059 :                        TREE_TYPE (edge->callee->decl));
    5377       702059 :       if (to_info)
    5378              :         {
    5379       686401 :           if (!callee_info || callee_info->side_effects)
    5380        60205 :             to_info->side_effects = true;
    5381       686401 :           if (set_nondeterministic)
    5382       654578 :             to_info->nondeterministic = true;
    5383              :         }
    5384       702059 :       if (to_info_lto)
    5385              :         {
    5386        32670 :           if (!callee_info_lto || callee_info_lto->side_effects)
    5387        24918 :             to_info_lto->side_effects = true;
    5388        32670 :           if (set_nondeterministic)
    5389        31229 :             to_info_lto->nondeterministic = true;
    5390              :         }
    5391              :      }
    5392       782149 :   if (callee_info || callee_info_lto)
    5393              :     {
    5394       770531 :       auto_vec <modref_parm_map, 32> parm_map;
    5395       770531 :       modref_parm_map chain_map;
    5396              :       /* TODO: Once we get jump functions for static chains we could
    5397              :          compute parm_index.  */
    5398              : 
    5399       770531 :       compute_parm_map (edge, &parm_map);
    5400              : 
    5401       770531 :       if (!ignore_stores)
    5402              :         {
    5403       660265 :           if (to_info && callee_info)
    5404       645294 :             to_info->stores->merge (to->decl, callee_info->stores, &parm_map,
    5405              :                                     &chain_map, false);
    5406       660265 :           if (to_info_lto && callee_info_lto)
    5407        31104 :             to_info_lto->stores->merge (to->decl, callee_info_lto->stores,
    5408              :                                         &parm_map, &chain_map, false);
    5409              :         }
    5410       770531 :       if (!(flags & (ECF_CONST | ECF_NOVOPS)))
    5411              :         {
    5412       760566 :           if (to_info && callee_info)
    5413       743904 :             to_info->loads->merge (to->decl, callee_info->loads, &parm_map,
    5414              :                                    &chain_map, false);
    5415       760566 :           if (to_info_lto && callee_info_lto)
    5416        35104 :             to_info_lto->loads->merge (to->decl, callee_info_lto->loads,
    5417              :                                        &parm_map, &chain_map, false);
    5418              :         }
    5419       770531 :     }
    5420              : 
    5421              :   /* Now merge escape summaries.
    5422              :      For every escape to the callee we need to merge callee flags
    5423              :      and remap callee's escapes.  */
    5424       782149 :   class escape_summary *sum = escape_summaries->get (edge);
    5425       782149 :   int max_escape = -1;
    5426       782149 :   escape_entry *ee;
    5427       782149 :   unsigned int i;
    5428              : 
    5429       782149 :   if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
    5430       165332 :     FOR_EACH_VEC_ELT (sum->esc, i, ee)
    5431        91649 :       if ((int)ee->arg > max_escape)
    5432              :         max_escape = ee->arg;
    5433              : 
    5434       782149 :   auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
    5435       782149 :   emap.safe_grow (max_escape + 1, true);
    5436      1696445 :   for (i = 0; (int)i < max_escape + 1; i++)
    5437       132147 :     emap[i] = vNULL;
    5438              : 
    5439       782149 :   if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
    5440       165332 :     FOR_EACH_VEC_ELT (sum->esc, i, ee)
    5441              :       {
    5442        91649 :         bool needed = false;
    5443        91649 :         int implicit_flags = implicit_eaf_flags_for_edge_and_arg
    5444       183298 :                                 (edge, flags, ignore_stores,
    5445        91649 :                                  ee->arg);
    5446        91649 :         if (!ee->direct)
    5447        16614 :           implicit_flags = deref_flags (implicit_flags, ignore_stores);
    5448       182267 :         if (to_info && (int)to_info->arg_flags.length () > ee->parm_index)
    5449              :           {
    5450        90751 :             int flags = callee_info
    5451        90670 :                         && callee_info->arg_flags.length () > ee->arg
    5452       176274 :                         ? callee_info->arg_flags[ee->arg] : 0;
    5453        90751 :             if (!ee->direct)
    5454        16590 :               flags = deref_flags (flags, ignore_stores);
    5455        90751 :             flags |= ee->min_flags | implicit_flags;
    5456        90751 :             eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
    5457        90751 :                              ? to_info->retslot_flags
    5458              :                              : ee->parm_index == MODREF_STATIC_CHAIN_PARM
    5459              :                              ? to_info->static_chain_flags
    5460        90751 :                              : to_info->arg_flags[ee->parm_index];
    5461        90751 :             f &= flags;
    5462        90751 :             if (f)
    5463        91649 :               needed = true;
    5464              :           }
    5465        91649 :         if (to_info_lto
    5466        92773 :             && (int)to_info_lto->arg_flags.length () > ee->parm_index)
    5467              :           {
    5468         1126 :             int flags = callee_info_lto
    5469         1126 :                         && callee_info_lto->arg_flags.length () > ee->arg
    5470         2240 :                         ? callee_info_lto->arg_flags[ee->arg] : 0;
    5471         1126 :             if (!ee->direct)
    5472           57 :               flags = deref_flags (flags, ignore_stores);
    5473         1126 :             flags |= ee->min_flags | implicit_flags;
    5474         1126 :             eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
    5475         1126 :                              ? to_info_lto->retslot_flags
    5476              :                              : ee->parm_index == MODREF_STATIC_CHAIN_PARM
    5477              :                              ? to_info_lto->static_chain_flags
    5478         1126 :                              : to_info_lto->arg_flags[ee->parm_index];
    5479         1126 :             f &= flags;
    5480         1126 :             if (f)
    5481        91649 :               needed = true;
    5482              :           }
    5483        91649 :         struct escape_map entry = {ee->parm_index, ee->direct};
    5484        91649 :         if (needed)
    5485        90908 :           emap[ee->arg].safe_push (entry);
    5486              :       }
    5487       782149 :   update_escape_summary (edge->callee, emap, ignore_stores);
    5488      1696445 :   for (i = 0; (int)i < max_escape + 1; i++)
    5489       132147 :     emap[i].release ();
    5490       782149 :   if (sum)
    5491        73688 :     escape_summaries->remove (edge);
    5492              : 
    5493       782149 :   if (summaries)
    5494              :     {
    5495       765106 :       if (to_info && !to_info->useful_p (flags))
    5496              :         {
    5497        18204 :           if (dump_file)
    5498           38 :             fprintf (dump_file, "Removed mod-ref summary for %s\n",
    5499              :                      to->dump_name ());
    5500        18204 :           summaries->remove (to);
    5501        18204 :           to_info = NULL;
    5502              :         }
    5503       746902 :       else if (to_info && dump_file)
    5504              :         {
    5505          434 :           if (dump_file)
    5506          434 :             fprintf (dump_file, "Updated mod-ref summary for %s\n",
    5507              :                      to->dump_name ());
    5508          434 :           to_info->dump (dump_file);
    5509              :         }
    5510       765106 :       if (callee_info)
    5511       753656 :         summaries->remove (edge->callee);
    5512              :     }
    5513       782149 :   if (summaries_lto)
    5514              :     {
    5515        36562 :       if (to_info_lto && !to_info_lto->useful_p (flags))
    5516              :         {
    5517          603 :           if (dump_file)
    5518            1 :             fprintf (dump_file, "Removed mod-ref summary for %s\n",
    5519              :                      to->dump_name ());
    5520          603 :           summaries_lto->remove (to);
    5521          603 :           to_info_lto = NULL;
    5522              :         }
    5523        35959 :       else if (to_info_lto && dump_file)
    5524              :         {
    5525            3 :           if (dump_file)
    5526            3 :             fprintf (dump_file, "Updated mod-ref summary for %s\n",
    5527              :                      to->dump_name ());
    5528            3 :           to_info_lto->dump (dump_file);
    5529              :         }
    5530        36562 :       if (callee_info_lto)
    5531        36284 :         summaries_lto->remove (edge->callee);
    5532              :     }
    5533       782149 :   if (!to_info && !to_info_lto)
    5534        18549 :     remove_modref_edge_summaries (to);
    5535       782149 :   return;
    5536       782149 : }
    5537              : 
    5538              : /* Run the IPA pass.  This will take a function's summaries and calls and
    5539              :    construct new summaries which represent a transitive closure.  So that
    5540              :    summary of an analyzed function contains information about the loads and
    5541              :    stores that the function or any function that it calls does.  */
    5542              : 
    5543              : unsigned int
    5544       230063 : pass_ipa_modref::execute (function *)
    5545              : {
    5546       230063 :   if (!summaries && !summaries_lto)
    5547              :     return 0;
    5548       145191 :   bool pureconst = false;
    5549              : 
    5550       145191 :   if (optimization_summaries)
    5551       132969 :     ggc_delete (optimization_summaries);
    5552       145191 :   optimization_summaries = summaries;
    5553       145191 :   summaries = NULL;
    5554              : 
    5555       145191 :   struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
    5556              :                                          symtab->cgraph_count);
    5557       145191 :   int order_pos;
    5558       145191 :   order_pos = ipa_reduced_postorder (order, true, ignore_edge);
    5559       145191 :   int i;
    5560              : 
    5561              :   /* Iterate over all strongly connected components in post-order.  */
    5562      2530395 :   for (i = 0; i < order_pos; i++)
    5563              :     {
    5564              :       /* Get the component's representative.  That's just any node in the
    5565              :          component from which we can traverse the entire component.  */
    5566      2385204 :       struct cgraph_node *component_node = order[i];
    5567              : 
    5568      2385204 :       if (dump_file)
    5569           58 :         fprintf (dump_file, "\n\nStart of SCC component\n");
    5570              : 
    5571      2385204 :       pureconst |= modref_propagate_in_scc (component_node);
    5572      2385204 :       modref_propagate_flags_in_scc (component_node);
    5573      2385204 :       if (optimization_summaries)
    5574      4660438 :         for (struct cgraph_node *cur = component_node; cur;
    5575      2339202 :              cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
    5576      2339202 :           if (modref_summary *sum = optimization_summaries->get (cur))
    5577       719531 :             sum->finalize (cur->decl);
    5578      2385204 :       if (dump_file)
    5579           58 :         modref_propagate_dump_scc (component_node);
    5580              :     }
    5581       145191 :   cgraph_node *node;
    5582      3460583 :   FOR_EACH_FUNCTION (node)
    5583      3315392 :     update_signature (node);
    5584       145191 :   if (summaries_lto)
    5585        18419 :     ((modref_summaries_lto *)summaries_lto)->propagated = true;
    5586       145191 :   ipa_free_postorder_info ();
    5587       145191 :   free (order);
    5588       145191 :   delete fnspec_summaries;
    5589       145191 :   fnspec_summaries = NULL;
    5590       145191 :   delete escape_summaries;
    5591       145191 :   escape_summaries = NULL;
    5592              : 
    5593              :   /* If we possibly made constructors const/pure we may need to remove
    5594              :      them.  */
    5595       145191 :   return pureconst ? TODO_remove_functions : 0;
    5596              : }
    5597              : 
    5598              : /* Summaries must stay alive until end of compilation.  */
    5599              : 
    5600              : void
    5601       256621 : ipa_modref_cc_finalize ()
    5602              : {
    5603       256621 :   if (optimization_summaries)
    5604       154414 :     ggc_delete (optimization_summaries);
    5605       256621 :   optimization_summaries = NULL;
    5606       256621 :   if (summaries_lto)
    5607        27368 :     ggc_delete (summaries_lto);
    5608       256621 :   summaries_lto = NULL;
    5609       256621 :   if (fnspec_summaries)
    5610         8958 :     delete fnspec_summaries;
    5611       256621 :   fnspec_summaries = NULL;
    5612       256621 :   if (escape_summaries)
    5613         8958 :     delete escape_summaries;
    5614       256621 :   escape_summaries = NULL;
    5615       256621 : }
    5616              : 
    5617              : /* Return true if call is known to perform no memory reads.  */
    5618              : 
    5619              : bool
    5620     32128405 : ipa_modref_callee_reads_no_memory_p (gcall *call)
    5621              : {
    5622     32128405 :   if (gimple_call_flags (call) & ECF_CONST)
    5623              :     return true;
    5624     32005570 :   attr_fnspec fnspec = gimple_call_fnspec (call);
    5625     32005570 :   if (fnspec.known_p ()
    5626     32005570 :       && !fnspec.global_memory_read_p ())
    5627              :     {
    5628              :       bool found = false;
    5629      7689859 :       for (unsigned int i = 0; i < gimple_call_num_args (call) && !found; i++)
    5630      4400478 :         if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
    5631              :           ;
    5632      3312329 :       else if (!fnspec.arg_specified_p (i)
    5633      3312329 :                || fnspec.arg_maybe_read_p (i))
    5634              :           found = true;
    5635      3289381 :       if (!found)
    5636              :         return true;
    5637              :     }
    5638              : 
    5639              :   /* For interposed calls we can not be sure that the other, semantically
    5640              :      equivalent body, will not perform some redundant load from memory
    5641              :      that may become undefined if we optimize out some stores.  */
    5642     30920114 :   bool interposed;
    5643     30920114 :   modref_summary *sum = get_modref_function_summary (call, &interposed);
    5644     30920114 :   if (sum && !interposed && !sum->global_memory_read && !sum->loads)
    5645              :     return true;
    5646              :   return false;
    5647              : }
    5648              : 
    5649              : #include "gt-ipa-modref.h"
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.