0411f660df747503a3946fea4686b6a396d02fdf
[platform/upstream/gcc.git] / gcc / ipa-modref.c
1 /* Search for references that a functions loads or stores.
2    Copyright (C) 2020 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.  The summary has a form of decision tree and
24    contains:
25
26     - base alias set
27       and for each:
28       - ref alias set
29
30    In future more information will be tracked.
31
32    This file contains a tree pass and an IPA pass.  Both performs the same
33    analys however tree pass is executed during early and late optimization
34    passes to propagate info downwards in the compilation order.  IPA pass
35    propagates across the callgraph and is able to handle recursion and works on
36    whole program during link-time analysis.
37
38    LTO mode differs from the local mode by not recording alias sets but types
39    that are translated to alias sets later.  This is necessary in order stream
40    the information because the alias sets are rebuild at stream-in time and may
41    not correspond to ones seen during analysis.  For this reason part of analysis
42    is duplicated.  */
43
44 #include "config.h"
45 #include "system.h"
46 #include "coretypes.h"
47 #include "backend.h"
48 #include "tree.h"
49 #include "gimple.h"
50 #include "alloc-pool.h"
51 #include "tree-pass.h"
52 #include "gimple-iterator.h"
53 #include "tree-dfa.h"
54 #include "cgraph.h"
55 #include "ipa-utils.h"
56 #include "symbol-summary.h"
57 #include "gimple-pretty-print.h"
58 #include "gimple-walk.h"
59 #include "print-tree.h"
60 #include "tree-streamer.h"
61 #include "alias.h"
62 #include "calls.h"
63 #include "ipa-modref-tree.h"
64 #include "ipa-modref.h"
65
66 /* Class (from which there is one global instance) that holds modref summaries
67    for all analyzed functions.  */
68 class GTY((user)) modref_summaries
69   : public fast_function_summary <modref_summary *, va_gc>
70 {
71 public:
72   modref_summaries (symbol_table *symtab)
73       : fast_function_summary <modref_summary *, va_gc> (symtab) {}
74   virtual void insert (cgraph_node *, modref_summary *state);
75   virtual void duplicate (cgraph_node *src_node,
76                           cgraph_node *dst_node,
77                           modref_summary *src_data,
78                           modref_summary *dst_data);
79   /* This flag controls whether newly inserted functions should be analyzed
80      in IPA or normal mode.  Functions inserted between IPA analysis and
81      ipa-modref pass execution needs to be analyzed in IPA mode while all
82      other insertions leads to normal analysis.  */
83   bool ipa;
84 };
85
86 /* Global variable holding all modref summaries.  */
87 static GTY(()) fast_function_summary <modref_summary *, va_gc> *summaries;
88
89 /* Summary for a single function which this pass produces.  */
90
91 modref_summary::modref_summary ()
92   : loads (NULL), stores (NULL), loads_lto (NULL),
93     stores_lto (NULL), finished (0)
94 {
95 }
96
97 modref_summary::~modref_summary ()
98 {
99   if (loads)
100     ggc_delete (loads);
101   if (stores)
102     ggc_delete (stores);
103   if (loads_lto)
104     ggc_delete (loads_lto);
105   if (stores_lto)
106     ggc_delete (stores_lto);
107 }
108
109 /* Dump records TT to OUT.  */
110
111 static void
112 dump_records (modref_records *tt, FILE *out)
113 {
114   fprintf (out, "    Limits: %i bases, %i refs\n",
115            (int)tt->max_bases, (int)tt->max_refs);
116   if (tt->every_base)
117     {
118       fprintf (out, "    Every base\n");
119       return;
120     }
121   size_t i;
122   modref_base_node <alias_set_type> *n;
123   FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
124     {
125       fprintf (out, "      Base %i: alias set %i\n", (int)i, n->base);
126       if (n->every_ref)
127         {
128           fprintf (out, "      Every ref\n");
129           continue;
130         }
131       size_t j;
132       modref_ref_node <alias_set_type> *r;
133       FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
134         {
135           fprintf (out, "        Ref %i: alias set %i\n", (int)j, r->ref);
136         }
137     }
138 }
139
140 /* Dump records TT to OUT.  */
141
142 static void
143 dump_lto_records (modref_records_lto *tt, FILE *out)
144 {
145   fprintf (out, "    Limits: %i bases, %i refs\n",
146            (int)tt->max_bases, (int)tt->max_refs);
147   if (tt->every_base)
148     {
149       fprintf (out, "    Every base\n");
150       return;
151     }
152   size_t i;
153   modref_base_node <tree> *n;
154   FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
155     {
156       fprintf (out, "      Base %i:", (int)i);
157       print_generic_expr (dump_file, n->base);
158       fprintf (out, " (alias set %i)\n",
159                n->base ? get_alias_set (n->base) : 0);
160       if (n->every_ref)
161         {
162           fprintf (out, "      Every ref\n");
163           continue;
164         }
165       size_t j;
166       modref_ref_node <tree> *r;
167       FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
168         {
169           fprintf (out, "        Ref %i:", (int)j);
170           print_generic_expr (dump_file, r->ref);
171           fprintf (out, " (alias set %i)\n",
172                    r->ref ? get_alias_set (r->ref) : 0);
173         }
174     }
175 }
176
177 /* Dump summary.  */
178
179 void
180 modref_summary::dump (FILE *out)
181 {
182   if (loads)
183     {
184       fprintf (out, "  loads:\n");
185       dump_records (loads, out);
186     }
187   if (stores)
188     {
189       fprintf (out, "  stores:\n");
190       dump_records (stores, out);
191     }
192   if (loads_lto)
193     {
194       fprintf (out, "  LTO loads:\n");
195       dump_lto_records (loads_lto, out);
196     }
197   if (stores_lto)
198     {
199       fprintf (out, "  LTO stores:\n");
200       dump_lto_records (stores_lto, out);
201     }
202 }
203
204
205 /* Get function summary for FUNC if it exists, return NULL otherwise.  */
206
207 modref_summary *
208 get_modref_function_summary (cgraph_node *func)
209 {
210   /* Avoid creation of the summary too early (e.g. when front-end calls us).  */
211   if (!summaries)
212     return NULL;
213
214   /* A single function body may be represented by multiple symbols with
215      different visibility.  For example, if FUNC is an interposable alias,
216      we don't want to return anything, even if we have summary for the target
217      function.  */
218   enum availability avail;
219   func = func->function_or_virtual_thunk_symbol
220              (&avail, cgraph_node::get (current_function_decl));
221   if (avail <= AVAIL_INTERPOSABLE)
222     return NULL;
223
224   /* Attempt to get summary for FUNC.  If analysis of FUNC hasn't finished yet,
225      don't return anything.  */
226   modref_summary *r = summaries->get (func);
227   if (r && r->finished)
228     return r;
229
230   return NULL;
231 }
232
233 /* Record access into the modref_records data structure.  */
234
235 static void
236 record_access (modref_records *tt, ao_ref *ref)
237 {
238   alias_set_type base_set = !flag_strict_aliasing ? 0
239                             : ao_ref_base_alias_set (ref);
240   alias_set_type ref_set = !flag_strict_aliasing ? 0
241                             : (ao_ref_alias_set (ref));
242   if (dump_file)
243     {
244        fprintf (dump_file, "   - Recording base_set=%i ref_set=%i\n",
245                 base_set, ref_set);
246     }
247   tt->insert (base_set, ref_set);
248 }
249
250 /* IPA version of record_access_tree.  */
251
252 static void
253 record_access_lto (modref_records_lto *tt, ao_ref *ref)
254 {
255   /* get_alias_set sometimes use different type to compute the alias set
256      than TREE_TYPE (base).  Do same adjustments.  */
257   tree base_type = NULL_TREE, ref_type = NULL_TREE;
258   if (flag_strict_aliasing)
259     {
260       tree base;
261
262       base = ref->ref;
263       while (handled_component_p (base))
264         base = TREE_OPERAND (base, 0);
265
266       base_type = reference_alias_ptr_type_1 (&base);
267
268       if (!base_type)
269         base_type = TREE_TYPE (base);
270       else
271         base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
272                     ? NULL_TREE : TREE_TYPE (base_type);
273
274       tree ref_expr = ref->ref;
275       ref_type = reference_alias_ptr_type_1 (&ref_expr);
276
277       if (!ref_type)
278         ref_type = TREE_TYPE (ref_expr);
279       else
280         ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
281                    ? NULL_TREE : TREE_TYPE (ref_type);
282
283       /* Sanity check that we are in sync with what get_alias_set does.  */
284       gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
285                            || get_alias_set (base_type)
286                               == ao_ref_base_alias_set (ref));
287       gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
288                            || get_alias_set (ref_type)
289                               == ao_ref_alias_set (ref));
290
291       /* Do not bother to record types that have no meaningful alias set.
292          Also skip variably modified types since these go to local streams.  */
293       if (base_type && (!get_alias_set (base_type)
294                         || variably_modified_type_p (base_type, NULL_TREE)))
295         base_type = NULL_TREE;
296       if (ref_type && (!get_alias_set (ref_type)
297                        || variably_modified_type_p (ref_type, NULL_TREE)))
298         ref_type = NULL_TREE;
299     }
300   if (dump_file)
301     {
302       fprintf (dump_file, "   - Recording base type:");
303       print_generic_expr (dump_file, base_type);
304       fprintf (dump_file, " (alias set %i) ref type:",
305                base_type ? get_alias_set (base_type) : 0);
306       print_generic_expr (dump_file, ref_type);
307       fprintf (dump_file, " (alias set %i)\n",
308                ref_type ? get_alias_set (ref_type) : 0);
309     }
310
311   tt->insert (base_type, ref_type);
312 }
313
314 /* Returns true if and only if we should store the access to EXPR.
315    Some accesses, e.g. loads from automatic variables, are not interesting.  */
316
317 static bool
318 record_access_p (tree expr)
319 {
320   /* Non-escaping memory is fine  */
321   tree t = get_base_address (expr);
322   if (t && (INDIRECT_REF_P (t)
323             || TREE_CODE (t) == MEM_REF
324             || TREE_CODE (t) == TARGET_MEM_REF)
325         && TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME
326         && !ptr_deref_may_alias_global_p (TREE_OPERAND (t, 0)))
327     {
328       if (dump_file)
329         fprintf (dump_file, "   - Non-escaping memory, ignoring.\n");
330       return false;
331     }
332
333   /* Automatic variables are fine.  */
334   if (DECL_P (t)
335       && auto_var_in_fn_p (t, current_function_decl))
336     {
337       if (dump_file)
338         fprintf (dump_file, "   - Automatic variable, ignoring.\n");
339       return false;
340     }
341
342   /* Read-only variables are fine.  */
343   if (DECL_P (t) && TREE_READONLY (t))
344     {
345       if (dump_file)
346         fprintf (dump_file, "   - Read-only variable, ignoring.\n");
347       return false;
348     }
349
350   return true;
351 }
352
353 /* Return true if ECF flags says that stores can be ignored.  */
354
355 static bool
356 ignore_stores_p (tree caller, int flags)
357 {
358   if (flags & ECF_PURE)
359     return true;
360   if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
361       || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
362     return true;
363   return false;
364 }
365
366 /* Analyze function call STMT in function F.  */
367
368 static bool
369 analyze_call (modref_summary *cur_summary,
370               gimple *stmt)
371 {
372   /* Check flags on the function call.  In certain cases, analysis can be
373      simplified.  */
374   int flags = gimple_call_flags (stmt);
375   if (flags & (ECF_CONST | ECF_NOVOPS))
376     {
377       if (dump_file)
378         fprintf (dump_file,
379                  " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
380                  "except for args.\n");
381       return true;
382     }
383
384   /* Pure functions do not affect global memory.  Stores by functions which are
385      noreturn and do not throw can safely be ignored.  */
386   bool ignore_stores = ignore_stores_p (current_function_decl, flags);
387
388   /* Next, we try to get the callee's function declaration.  The goal is to
389      merge their summary with ours.  */
390   tree callee = gimple_call_fndecl (stmt);
391
392   /* Check if this is an indirect call.  */
393   if (!callee)
394     {
395       /* If the indirect call does not write memory, our store summary is
396          unaffected, but we have to discard our loads summary (we don't know
397          anything about the loads that the called function performs).  */
398       if (ignore_stores)
399         {
400           if (dump_file)
401             fprintf (dump_file, " - Indirect call which does not write memory, "
402                     "discarding loads.\n");
403           if (cur_summary->loads)
404             cur_summary->loads->collapse ();
405           if (cur_summary->loads_lto)
406             cur_summary->loads_lto->collapse ();
407           return true;
408         }
409       if (dump_file)
410         fprintf (dump_file, " - Indirect call.\n");
411       return false;
412     }
413
414   struct cgraph_node *callee_node = cgraph_node::get_create (callee);
415
416   /* We can not safely optimize based on summary of callee if it does
417      not always bind to current def: it is possible that memory load
418      was optimized out earlier which may not happen in the interposed
419      variant.  */
420   if (!callee_node->binds_to_current_def_p ())
421     {
422       if (dump_file)
423         fprintf (dump_file, " - May be interposed: collapsing loads.\n");
424       if (cur_summary->loads)
425         cur_summary->loads->collapse ();
426       if (cur_summary->loads_lto)
427         cur_summary->loads_lto->collapse ();
428     }
429
430   /* If this is a recursive call, the target summary is the same as ours, so
431      there's nothing to do.  */
432   if (recursive_call_p (current_function_decl, callee))
433     {
434       if (dump_file)
435         fprintf (dump_file, " - Skipping recursive call.\n");
436       return true;
437     }
438
439   gcc_assert (callee_node != NULL);
440
441   /* Get the function symbol and its availability.  */
442   enum availability avail;
443   callee_node = callee_node->function_symbol (&avail);
444   if (avail <= AVAIL_INTERPOSABLE)
445     {
446       /* Keep stores summary, but discard all loads for interposable function
447          symbols.  */
448       if (ignore_stores)
449         {
450           if (cur_summary->loads)
451             cur_summary->loads->collapse ();
452           if (cur_summary->loads_lto)
453             cur_summary->loads_lto->collapse ();
454           return true;
455         }
456       if (dump_file)
457         fprintf (dump_file, " - Function availability <= AVAIL_INTERPOSABLE.\n");
458       return false;
459     }
460
461   /* Get callee's modref summary.  As above, if there's no summary, we either
462      have to give up or, if stores are ignored, we can just purge loads.  */
463   modref_summary *callee_summary = summaries->get (callee_node);
464   if (!callee_summary)
465     {
466       if (ignore_stores)
467         {
468           if (cur_summary->loads)
469             cur_summary->loads->collapse ();
470           if (cur_summary->loads_lto)
471             cur_summary->loads_lto->collapse ();
472           return true;
473         }
474       if (dump_file)
475         fprintf (dump_file, " - No modref summary available for callee.\n");
476       return false;
477     }
478
479   /* Merge with callee's summary.  */
480   if (cur_summary->loads)
481     cur_summary->loads->merge (callee_summary->loads);
482   if (cur_summary->loads_lto)
483     cur_summary->loads_lto->merge (callee_summary->loads_lto);
484   if (!ignore_stores)
485     {
486       if (cur_summary->stores)
487         cur_summary->stores->merge (callee_summary->stores);
488       if (cur_summary->stores_lto)
489         cur_summary->stores_lto->merge (callee_summary->stores_lto);
490     }
491
492   return true;
493 }
494
495 /* Helper for analyze_stmt.  */
496
497 static bool
498 analyze_load (gimple *, tree, tree op, void *data)
499 {
500   modref_summary *summary = (modref_summary *)data;
501
502   if (dump_file)
503     {
504       fprintf (dump_file, " - Analyzing load: ");
505       print_generic_expr (dump_file, op);
506       fprintf (dump_file, "\n");
507     }
508
509   if (!record_access_p (op))
510     return false;
511
512   ao_ref r;
513   ao_ref_init (&r, op);
514
515   if (summary->loads)
516     record_access (summary->loads, &r);
517   if (summary->loads_lto)
518     record_access_lto (summary->loads_lto, &r);
519   return false;
520 }
521
522 /* Helper for analyze_stmt.  */
523
524 static bool
525 analyze_store (gimple *, tree, tree op, void *data)
526 {
527   modref_summary *summary = (modref_summary *)data;
528
529   if (dump_file)
530     {
531       fprintf (dump_file, " - Analyzing store: ");
532       print_generic_expr (dump_file, op);
533       fprintf (dump_file, "\n");
534     }
535
536   if (!record_access_p (op))
537     return false;
538
539   ao_ref r;
540   ao_ref_init (&r, op);
541
542   if (summary->stores)
543     record_access (((modref_summary *)data)->stores, &r);
544   if (summary->stores_lto)
545     record_access_lto (((modref_summary *)data)->stores_lto, &r);
546   return false;
547 }
548
549 /* Analyze statement STMT of function F.
550    If IPA is true do not merge in side effects of calls.  */
551
552 static bool
553 analyze_stmt (modref_summary *summary, gimple *stmt, bool ipa)
554 {
555   /* Analyze all loads and stores in STMT.  */
556   walk_stmt_load_store_ops (stmt, summary,
557                             analyze_load, analyze_store);
558   /* or call analyze_load_ipa, analyze_store_ipa */
559
560   switch (gimple_code (stmt))
561    {
562    case GIMPLE_ASM:
563      /* If the ASM statement does not read nor write memory, there's nothing
564         to do.  Otherwise just give up.  */
565      if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
566        return true;
567      if (dump_file)
568        fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
569                "which clobbers memory.\n");
570      return false;
571    case GIMPLE_CALL:
572      if (!ipa)
573        return analyze_call (summary, stmt);
574      return true;
575    default:
576      /* Nothing to do for other types of statements.  */
577      return true;
578    }
579 }
580
581 /* Analyze function F.  IPA indicates whether we're running in tree mode (false)
582    or the IPA mode (true).  */
583
584 static void
585 analyze_function (function *f, bool ipa)
586 {
587   if (dump_file)
588     fprintf (dump_file, "modref analyzing '%s' (ipa=%i)...\n",
589              function_name (f), ipa);
590
591   /* Don't analyze this function if it's compiled with -fno-strict-aliasing.  */
592   if (!flag_ipa_modref)
593     return;
594
595   /* Initialize the summary.  */
596   if (!summaries)
597     summaries = new (ggc_alloc <modref_summaries> ())
598                      modref_summaries (symtab);
599   else /* Remove existing summary if we are re-running the pass.  */
600     summaries->remove (cgraph_node::get (f->decl));
601
602   ((modref_summaries *)summaries)->ipa = ipa;
603
604   modref_summary *summary = summaries->get_create (cgraph_node::get (f->decl));
605
606   /* Compute no-LTO summaries when local optimization is going to happen.  */
607   bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
608                 || (in_lto_p && !flag_wpa
609                     && flag_incremental_link != INCREMENTAL_LINK_LTO));
610
611   /* Compute LTO when LTO streaming is going to happen.  */
612   bool lto = ipa && ((flag_lto && !in_lto_p)
613                      || flag_wpa
614                      || flag_incremental_link == INCREMENTAL_LINK_LTO);
615
616   /* Create and initialize summary for F.
617      Note that summaries may be already allocated from previous
618      run of the pass.  */
619   if (nolto)
620     {
621       gcc_assert (!summary->loads);
622       summary->loads
623          = new (ggc_alloc <modref_tree<alias_set_type> > ())
624                 modref_records (param_modref_max_bases,
625                                 param_modref_max_refs);
626       gcc_assert (!summary->stores);
627       summary->stores
628          = new (ggc_alloc <modref_tree<alias_set_type> > ())
629                 modref_records (param_modref_max_bases,
630                                 param_modref_max_refs);
631     }
632   if (lto)
633     {
634       gcc_assert (!summary->loads_lto);
635       summary->loads_lto
636          = new (ggc_alloc <modref_tree<tree> > ())
637                 modref_records_lto (param_modref_max_bases,
638                                     param_modref_max_refs);
639       gcc_assert (!summary->stores_lto);
640       summary->stores_lto
641          = new (ggc_alloc <modref_tree<tree> > ())
642                 modref_records_lto (param_modref_max_bases,
643                                     param_modref_max_refs);
644     }
645   summary->finished = false;
646
647   /* Analyze each statement in each basic block of the function.  If the
648      statement cannot be analyzed (for any reason), the entire function cannot
649      be analyzed by modref.  */
650   basic_block bb;
651   FOR_EACH_BB_FN (bb, f)
652     {
653       gimple_stmt_iterator si;
654       for (si = gsi_after_labels (bb); !gsi_end_p (si); gsi_next (&si))
655         {
656           if (!analyze_stmt (summary, gsi_stmt (si), ipa))
657             {
658               cgraph_node *fnode = cgraph_node::get (current_function_decl);
659               summaries->remove (fnode);
660               if (dump_file)
661                 fprintf (dump_file,
662                          " - modref done with result: not tracked.\n");
663               return;
664             }
665         }
666     }
667
668   if (!ipa)
669     summary->finished = true;
670
671   if (dump_file)
672     {
673       fprintf (dump_file, " - modref done with result: tracked.\n");
674       summary->dump (dump_file);
675     }
676 }
677
678 /* Callback for generate_summary.  */
679
680 static void
681 modref_generate (void)
682 {
683   struct cgraph_node *node;
684   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
685     {
686       function *f = DECL_STRUCT_FUNCTION (node->decl);
687       if (!f)
688         continue;
689       push_cfun (f);
690       analyze_function (f, true);
691       pop_cfun ();
692     }
693 }
694
695 /* Called when a new function is inserted to callgraph late.  */
696
697 void
698 modref_summaries::insert (struct cgraph_node *node, modref_summary *)
699 {
700   if (!DECL_STRUCT_FUNCTION (node->decl))
701     return;
702   push_cfun (DECL_STRUCT_FUNCTION (node->decl));
703   analyze_function (DECL_STRUCT_FUNCTION (node->decl), ipa);
704   pop_cfun ();
705 }
706
707 /* Called when new clone is inserted to callgraph late.  */
708
709 void
710 modref_summaries::duplicate (cgraph_node *, cgraph_node *,
711                              modref_summary *src_data,
712                              modref_summary *dst_data)
713 {
714   dst_data->finished = src_data->finished;
715   if (src_data->stores)
716     {
717       dst_data->stores = new (ggc_alloc <modref_tree<alias_set_type> > ())
718                               modref_records
719                                  (src_data->stores->max_bases,
720                                   src_data->stores->max_refs);
721       dst_data->stores->merge (src_data->stores);
722     }
723   if (src_data->loads)
724     {
725       dst_data->loads = new (ggc_alloc <modref_tree<alias_set_type> > ())
726                              modref_records
727                                 (src_data->loads->max_bases,
728                                  src_data->loads->max_refs);
729       dst_data->loads->merge (src_data->loads);
730     }
731   if (src_data->stores_lto)
732     {
733       dst_data->stores_lto = new (ggc_alloc <modref_tree<tree> > ())
734                                   modref_records_lto
735                                     (src_data->stores_lto->max_bases,
736                                      src_data->stores_lto->max_refs);
737       dst_data->stores_lto->merge (src_data->stores_lto);
738     }
739   if (src_data->loads_lto)
740     {
741       dst_data->loads_lto = new (ggc_alloc <modref_tree<tree> > ())
742                                   modref_records_lto
743                                     (src_data->stores_lto->max_bases,
744                                      src_data->stores_lto->max_refs);
745       dst_data->loads_lto->merge (src_data->loads_lto);
746     }
747 }
748
749 namespace
750 {
751 /* Definition of the modref pass on GIMPLE.  */
752 const pass_data pass_data_modref = {
753   GIMPLE_PASS,
754   "modref",
755   OPTGROUP_IPA,
756   TV_TREE_MODREF,
757   (PROP_cfg | PROP_ssa),
758   0,
759   0,
760   0,
761   0,
762 };
763
764 class pass_modref : public gimple_opt_pass
765 {
766   public:
767     pass_modref (gcc::context *ctxt)
768         : gimple_opt_pass (pass_data_modref, ctxt) {}
769
770     ~pass_modref ()
771       {
772         ggc_delete (summaries);
773         summaries = NULL;
774       }
775
776     /* opt_pass methods: */
777     opt_pass *clone ()
778     {
779       return new pass_modref (m_ctxt);
780     }
781     virtual bool gate (function *)
782     {
783       return flag_ipa_modref;
784     }
785     virtual unsigned int execute (function *);
786 };
787
788 /* Encode TT to the output block OB using the summary streaming API.  */
789
790 static void
791 write_modref_records (modref_records_lto *tt, struct output_block *ob)
792 {
793   streamer_write_uhwi (ob, tt->max_bases);
794   streamer_write_uhwi (ob, tt->max_refs);
795
796   streamer_write_uhwi (ob, tt->every_base);
797   streamer_write_uhwi (ob, vec_safe_length (tt->bases));
798   size_t i;
799   modref_base_node <tree> *base_node;
800   FOR_EACH_VEC_SAFE_ELT (tt->bases, i, base_node)
801     {
802       stream_write_tree (ob, base_node->base, true);
803
804       streamer_write_uhwi (ob, base_node->every_ref);
805       streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
806       size_t j;
807       modref_ref_node <tree> *ref_node;
808       FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
809         {
810           stream_write_tree (ob, ref_node->ref, true);
811         }
812     }
813 }
814
815 /* Read a modref_tree from the input block IB using the data from DATA_IN.
816    This assumes that the tree was encoded using write_modref_tree.
817    Either nolto_ret or lto_ret is initialized by the tree depending whether
818    LTO streaming is expected or not.  */
819
820 void
821 read_modref_records (lto_input_block *ib, struct data_in *data_in,
822                      modref_records **nolto_ret,
823                      modref_records_lto **lto_ret)
824 {
825   size_t max_bases = streamer_read_uhwi (ib);
826   size_t max_refs = streamer_read_uhwi (ib);
827
828   /* Decide whether we want to turn LTO data types to non-LTO (i.e. when
829      LTO re-streaming is not going to happen).  */
830   if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
831     *lto_ret = new (ggc_alloc <modref_records_lto> ()) modref_records_lto
832                               (max_bases, max_refs);
833   else
834     *nolto_ret = new (ggc_alloc <modref_records> ()) modref_records
835                               (max_bases, max_refs);
836
837   size_t every_base = streamer_read_uhwi (ib);
838   size_t nbase = streamer_read_uhwi (ib);
839
840   gcc_assert (!every_base || nbase == 0);
841   if (every_base)
842     {
843       if (*nolto_ret)
844         (*nolto_ret)->collapse ();
845       if (*lto_ret)
846         (*lto_ret)->collapse ();
847     }
848   for (size_t i = 0; i < nbase; i++)
849     {
850       tree base_tree = stream_read_tree (ib, data_in);
851       modref_base_node <alias_set_type> *nolto_base_node = NULL;
852       modref_base_node <tree> *lto_base_node = NULL;
853
854       /* At stream in time we have LTO alias info.  Check if we streamed in
855          something obviously unnecessary.  Do not glob types by alias sets;
856          it is not 100% clear that ltrans types will get merged same way.
857          Types may get refined based on ODR type conflicts.  */
858       if (base_tree && !get_alias_set (base_tree))
859         {
860           if (dump_file)
861             {
862               fprintf (dump_file, "Streamed in alias set 0 type ");
863               print_generic_expr (dump_file, base_tree);
864               fprintf (dump_file, "\n");
865             }
866           base_tree = NULL;
867         }
868
869       if (*nolto_ret)
870         nolto_base_node = (*nolto_ret)->insert_base (base_tree
871                                                      ? get_alias_set (base_tree)
872                                                      : 0);
873       if (*lto_ret)
874         lto_base_node = (*lto_ret)->insert_base (base_tree);
875       size_t every_ref = streamer_read_uhwi (ib);
876       size_t nref = streamer_read_uhwi (ib);
877
878       gcc_assert (!every_ref || nref == 0);
879       if (every_ref)
880         {
881           if (nolto_base_node)
882             nolto_base_node->collapse ();
883           if (lto_base_node)
884             lto_base_node->collapse ();
885         }
886       for (size_t j = 0; j < nref; j++)
887         {
888           tree ref_tree = stream_read_tree (ib, data_in);
889
890           if (ref_tree && !get_alias_set (ref_tree))
891             {
892               if (dump_file)
893                 {
894                   fprintf (dump_file, "Streamed in alias set 0 type ");
895                   print_generic_expr (dump_file, ref_tree);
896                   fprintf (dump_file, "\n");
897                 }
898               base_tree = NULL;
899             }
900
901           if (nolto_base_node)
902             nolto_base_node->insert_ref (ref_tree ? get_alias_set (ref_tree)
903                                          : 0, max_refs);
904           if (lto_base_node)
905             lto_base_node->insert_ref (ref_tree, max_refs);
906         }
907     }
908 }
909
910 /* Callback for write_summary.  */
911
912 static void
913 modref_write ()
914 {
915   struct output_block *ob = create_output_block (LTO_section_ipa_modref);
916   lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
917   unsigned int count = 0;
918   int i;
919
920   if (!summaries)
921     {
922       streamer_write_uhwi (ob, 0);
923       streamer_write_char_stream (ob->main_stream, 0);
924       produce_asm (ob, NULL);
925       destroy_output_block (ob);
926       return;
927     }
928
929   for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
930     {
931       symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
932       cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
933
934       if (cnode && cnode->definition && !cnode->alias
935           && summaries->get (cnode))
936         count++;
937     }
938   streamer_write_uhwi (ob, count);
939
940   for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
941     {
942       symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
943       cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
944
945       if (cnode && cnode->definition && !cnode->alias)
946         {
947
948           modref_summary *r = summaries->get (cnode);
949
950           if (!r)
951             continue;
952
953           streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
954
955           streamer_write_uhwi (ob, r->loads_lto ? 1 : 0);
956           streamer_write_uhwi (ob, r->stores_lto ? 1 : 0);
957           if (r->loads_lto)
958             write_modref_records (r->loads_lto, ob);
959           if (r->stores_lto)
960             write_modref_records (r->stores_lto, ob);
961         }
962     }
963   streamer_write_char_stream (ob->main_stream, 0);
964   produce_asm (ob, NULL);
965   destroy_output_block (ob);
966 }
967
968 static void
969 read_section (struct lto_file_decl_data *file_data, const char *data,
970               size_t len)
971 {
972   const struct lto_function_header *header
973     = (const struct lto_function_header *) data;
974   const int cfg_offset = sizeof (struct lto_function_header);
975   const int main_offset = cfg_offset + header->cfg_size;
976   const int string_offset = main_offset + header->main_size;
977   struct data_in *data_in;
978   unsigned int i;
979   unsigned int f_count;
980
981   lto_input_block ib ((const char *) data + main_offset, header->main_size,
982                       file_data->mode_table);
983
984   data_in
985     = lto_data_in_create (file_data, (const char *) data + string_offset,
986                           header->string_size, vNULL);
987   f_count = streamer_read_uhwi (&ib);
988   for (i = 0; i < f_count; i++)
989     {
990       struct cgraph_node *node;
991       lto_symtab_encoder_t encoder;
992
993       unsigned int index = streamer_read_uhwi (&ib);
994       encoder = file_data->symtab_node_encoder;
995       node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
996                                                                 index));
997
998       modref_summary *modref_sum = summaries->get_create (node);
999       modref_sum->finished = false;
1000       int have_loads = streamer_read_uhwi (&ib);
1001       int have_stores = streamer_read_uhwi (&ib);
1002       gcc_assert (!modref_sum->loads_lto
1003                   && !modref_sum->stores_lto
1004                   && !modref_sum->loads
1005                   && !modref_sum->stores);
1006       if (have_loads)
1007          read_modref_records (&ib, data_in,
1008                               &modref_sum->loads,
1009                               &modref_sum->loads_lto);
1010       if (have_stores)
1011          read_modref_records (&ib, data_in,
1012                               &modref_sum->stores,
1013                               &modref_sum->stores_lto);
1014       if (dump_file)
1015         {
1016           fprintf (dump_file, "Read modref for %s\n",
1017                    node->dump_name ());
1018           modref_sum->dump (dump_file);
1019         }
1020       if (flag_ltrans)
1021         modref_sum->finished = true;
1022     }
1023
1024   lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
1025                          len);
1026   lto_data_in_delete (data_in);
1027 }
1028
1029 /* Callback for read_summary.  */
1030
1031 static void
1032 modref_read (void)
1033 {
1034   struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
1035   struct lto_file_decl_data *file_data;
1036   unsigned int j = 0;
1037
1038   if (!summaries)
1039     summaries = new (ggc_alloc <modref_summaries> ())
1040                      modref_summaries (symtab);
1041   ((modref_summaries *)summaries)->ipa = true;
1042
1043   while ((file_data = file_data_vec[j++]))
1044     {
1045       size_t len;
1046       const char *data = lto_get_summary_section_data (file_data,
1047                                                        LTO_section_ipa_modref,
1048                                                        &len);
1049       if (data)
1050         read_section (file_data, data, len);
1051       else
1052         /* Fatal error here.  We do not want to support compiling ltrans units
1053            with different version of compiler or different flags than the WPA
1054            unit, so this should never happen.  */
1055         fatal_error (input_location,
1056                      "IPA modref summary is missing in input file");
1057     }
1058 }
1059
1060 /* Definition of the modref IPA pass.  */
1061 const pass_data pass_data_ipa_modref =
1062 {
1063   IPA_PASS,           /* type */
1064   "modref",       /* name */
1065   OPTGROUP_IPA,       /* optinfo_flags */
1066   TV_IPA_MODREF, /* tv_id */
1067   0, /* properties_required */
1068   0, /* properties_provided */
1069   0, /* properties_destroyed */
1070   0, /* todo_flags_start */
1071   ( TODO_dump_symtab ), /* todo_flags_finish */
1072 };
1073
1074 class pass_ipa_modref : public ipa_opt_pass_d
1075 {
1076 public:
1077   pass_ipa_modref (gcc::context *ctxt)
1078     : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
1079                       modref_generate, /* generate_summary */
1080                       modref_write,    /* write_summary */
1081                       modref_read,     /* read_summary */
1082                       modref_write,    /* write_optimization_summary */
1083                       modref_read,     /* read_optimization_summary */
1084                       NULL,            /* stmt_fixup */
1085                       0,               /* function_transform_todo_flags_start */
1086                       NULL,            /* function_transform */
1087                       NULL)            /* variable_transform */
1088   {}
1089
1090   /* opt_pass methods: */
1091   opt_pass *clone () { return new pass_ipa_modref (m_ctxt); }
1092   virtual bool gate (function *)
1093   {
1094     return true;
1095   }
1096   virtual unsigned int execute (function *);
1097
1098 };
1099
1100 }
1101
1102 unsigned int pass_modref::execute (function *f)
1103 {
1104   /* If new function is being added during IPA, we can skip analysis.  */
1105   if (summaries && ((modref_summaries *)summaries)->ipa)
1106     return 0;
1107   analyze_function (f, false);
1108   return 0;
1109 }
1110
1111 gimple_opt_pass *
1112 make_pass_modref (gcc::context *ctxt)
1113 {
1114   return new pass_modref (ctxt);
1115 }
1116
1117 ipa_opt_pass_d *
1118 make_pass_ipa_modref (gcc::context *ctxt)
1119 {
1120   return new pass_ipa_modref (ctxt);
1121 }
1122
1123 /* Skip edges from and to nodes without ipa_pure_const enabled.
1124    Ignore not available symbols.  */
1125
1126 static bool
1127 ignore_edge (struct cgraph_edge *e)
1128 {
1129   enum availability avail;
1130   cgraph_node *callee = e->callee->function_or_virtual_thunk_symbol
1131                           (&avail, e->caller);
1132
1133   return (avail <= AVAIL_INTERPOSABLE
1134           || !summaries->get (callee)
1135           || flags_from_decl_or_type (e->callee->decl)
1136              & (ECF_CONST | ECF_NOVOPS));
1137 }
1138
1139 /* Run the IPA pass.  This will take a function's summaries and calls and
1140    construct new summaries which represent a transitive closure.  So that
1141    summary of an analyzed function contains information about the loads and
1142    stores that the function or any function that it calls does.  */
1143
1144 unsigned int pass_ipa_modref::execute (function *)
1145 {
1146   if (!summaries)
1147     return 0;
1148
1149   struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
1150                                          symtab->cgraph_count);
1151   int order_pos;
1152   order_pos = ipa_reduced_postorder (order, true, ignore_edge);
1153   int i;
1154
1155   /* Iterate over all strongly connected components in post-order.  */
1156   for (i = 0; i < order_pos; i++)
1157     {
1158       bool its_hopeless = false;
1159       modref_records *loads = NULL;
1160       modref_records *stores = NULL;
1161       modref_records_lto *loads_lto = NULL;
1162       modref_records_lto *stores_lto = NULL;
1163
1164       /* Get the component's representative.  That's just any node in the
1165          component from which we can traverse the entire component.  */
1166       struct cgraph_node *component_node = order[i];
1167       cgraph_node *first = NULL;
1168
1169       if (dump_file)
1170         fprintf (dump_file, "Start of SCC component\n");
1171
1172       /* Walk the component.  CUR is the current node of the component that's
1173          being processed.  */
1174       for (struct cgraph_node *cur = component_node; cur && !its_hopeless;
1175            cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
1176         {
1177           /* Merge in summaries from CUR.  */
1178           modref_summary *cur_summary = summaries->get (cur);
1179
1180           if (dump_file)
1181             fprintf (dump_file, "  Processing %s\n",
1182                      cur->dump_name ());
1183
1184           /* We don't know anything about CUR, hence we cannot tell anything
1185              about the entire component.  */
1186           if (!cur_summary)
1187             {
1188               if (dump_file)
1189                 fprintf (dump_file, "    No summary\n");
1190               its_hopeless = true;
1191               break;
1192             }
1193
1194           /* Summaries are all going to be same, pick first ones and merge
1195              everything in.  */
1196           if (!first)
1197             {
1198               first = cur;
1199               loads = cur_summary->loads;
1200               stores = cur_summary->stores;
1201               loads_lto = cur_summary->loads_lto;
1202               stores_lto = cur_summary->stores_lto;
1203             }
1204           for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
1205             {
1206               if (e->indirect_info->ecf_flags & (ECF_CONST | ECF_NOVOPS))
1207                 continue;
1208               if (ignore_stores_p (cur->decl, e->indirect_info->ecf_flags))
1209                 {
1210                   if (dump_file)
1211                     fprintf (dump_file, "    Indirect call: "
1212                              "collapsing loads\n");
1213                   if (loads)
1214                     loads->collapse ();
1215                   if (loads_lto)
1216                     loads_lto->collapse ();
1217                 }
1218               else
1219                 {
1220                   if (dump_file)
1221                     fprintf (dump_file, "    Indirect call: giving up\n");
1222                   its_hopeless = true;
1223                 }
1224             }
1225
1226           /* Walk every function that CUR calls and merge its summary.  */
1227           for (cgraph_edge *callee_edge = cur->callees; callee_edge;
1228                callee_edge = callee_edge->next_callee)
1229             {
1230               int flags = flags_from_decl_or_type (callee_edge->callee->decl);
1231               modref_summary *callee_summary;
1232               struct cgraph_node *callee;
1233
1234               if (flags & (ECF_CONST | ECF_NOVOPS))
1235                 continue;
1236
1237               if (dump_file)
1238                 fprintf (dump_file, "    Call to %s\n",
1239                          cur->dump_name ());
1240
1241               /* We can not safely optimize based on summary of callee if it
1242                  does not always bind to current def: it is possible that
1243                  memory load was optimized out earlier which may not happen in
1244                  the interposed variant.  */
1245               if (!callee_edge->binds_to_current_def_p ())
1246                 {
1247                   if (loads)
1248                     loads->collapse ();
1249                   if (loads_lto)
1250                     loads_lto->collapse ();
1251                   if (dump_file)
1252                     fprintf (dump_file, "      May not bind local;"
1253                              " collapsing loads\n");
1254                 }
1255
1256               /* Get the callee and its summary.  */
1257               enum availability avail;
1258               callee = callee_edge->callee->function_or_virtual_thunk_symbol
1259                          (&avail, cur);
1260
1261               /* See if we can derive something from ECF flags.  Be careful on
1262                  not skipping calls within the SCC component:  we must merge
1263                  all their summaries.
1264                  If we switch to iterative dataflow that may be necessary
1265                  for future improvements this may go away.  */
1266               if (callee->aux
1267                   && ((struct ipa_dfs_info *)cur->aux)->scc_no
1268                      == ((struct ipa_dfs_info *)callee->aux)->scc_no)
1269                 flags = 0;
1270
1271               bool ignore_stores = ignore_stores_p (cur->decl, flags);
1272
1273               /* We don't know anything about CALLEE, hence we cannot tell
1274                  anything about the entire component.  */
1275
1276               if (avail <= AVAIL_INTERPOSABLE
1277                   || !(callee_summary = summaries->get (callee)))
1278                 {
1279                   if (!ignore_stores)
1280                     {
1281                       its_hopeless = true;
1282                       if (dump_file && avail <= AVAIL_INTERPOSABLE)
1283                         fprintf (dump_file, "      Call target interposable"
1284                                  "or not available\n");
1285                       else if (dump_file)
1286                         fprintf (dump_file, "      No call target summary\n");
1287                       break;
1288                     }
1289                   else
1290                     {
1291                       if (loads)
1292                         loads->collapse ();
1293                       if (loads_lto)
1294                         loads_lto->collapse ();
1295                       if (dump_file && avail <= AVAIL_INTERPOSABLE)
1296                         fprintf (dump_file, "      Call target interposable"
1297                                  "or not available; collapsing loads\n");
1298                       else if (dump_file)
1299                         fprintf (dump_file, "      No call target summary;"
1300                                  " collapsing loads\n");
1301                       continue;
1302                     }
1303                 }
1304
1305               /* Merge in callee's information.  */
1306               if (callee_summary->loads
1307                   && callee_summary->loads != loads)
1308                 loads->merge (callee_summary->loads);
1309               if (callee_summary->stores
1310                   && callee_summary->stores != stores)
1311                 stores->merge (callee_summary->stores);
1312               if (callee_summary->loads_lto
1313                   && callee_summary->loads_lto != loads_lto)
1314                 loads_lto->merge (callee_summary->loads_lto);
1315               if (callee_summary->stores_lto
1316                   && callee_summary->stores_lto != stores_lto)
1317                 stores_lto->merge (callee_summary->stores_lto);
1318             }
1319         }
1320
1321         /* At this time, ipa_loads and ipa_stores contain information
1322            about all loads and stores done by any of the component's nodes and
1323            all functions that any of the nodes calls.  We will now propagate
1324            this information to all nodes in the component.  Therefore, we will
1325            walk the component one more time to do it.  */
1326         for (struct cgraph_node *cur = component_node; cur;
1327            cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
1328         {
1329           modref_summary *cur_summary = summaries->get (cur);
1330           if (!cur_summary)
1331             {
1332               /* The function doesn't have a summary.  We must have noticed
1333                  that during the first pass and the hopeless flag must
1334                  therefore be set.  Skip the function.  */
1335               gcc_assert (its_hopeless);
1336             }
1337           else if (its_hopeless)
1338             {
1339               if (dump_file)
1340                 fprintf (dump_file, "Cleared modref info for %s\n",
1341                          cur->dump_name ());
1342               summaries->remove (cur);
1343             }
1344           else
1345             {
1346               if (cur == first)
1347                 ;
1348               else
1349                 {
1350                   if (loads)
1351                     cur_summary->loads->merge (loads);
1352                   if (stores)
1353                     cur_summary->stores->merge (stores);
1354                   if (loads_lto)
1355                     cur_summary->loads_lto->merge (loads_lto);
1356                   if (stores_lto)
1357                     cur_summary->stores_lto->merge (stores_lto);
1358                 }
1359               cur_summary->finished = true;
1360               if (dump_file)
1361                 {
1362                   fprintf (dump_file, "Propagated modref for %s%s%s\n",
1363                            cur->dump_name (),
1364                            TREE_READONLY (cur->decl) ? " (const)" : "",
1365                            DECL_PURE_P (cur->decl) ? " (pure)" : "");
1366                   cur_summary->dump (dump_file);
1367                 }
1368             }
1369         }
1370     }
1371   ((modref_summaries *)summaries)->ipa = false;
1372   ipa_free_postorder_info ();
1373   return 0;
1374 }
1375
1376 #include "gt-ipa-modref.h"