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