Support TI mode and soft float on PA64
[official-gcc.git] / gcc / ipa-modref.c
blobdb071d2212f0cb374ba9e8247063f0cee882e813
1 /* Search for references that a functions loads or stores.
2 Copyright (C) 2020-2021 Free Software Foundation, Inc.
3 Contributed by David Cepelik and Jan Hubicka
5 This file is part of GCC.
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.
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.
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/>. */
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.
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.
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.
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-structlias).
41 and defined in tree-core.h.
42 and stored to optimization_summaries.
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 parmaeters
54 may escape to a function call (and with what parameter index). */
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"
92 namespace {
94 /* We record fnspec specifiers for call edges since they depends on actual
95 gimple statements. */
97 class fnspec_summary
99 public:
100 char *fnspec;
102 fnspec_summary ()
103 : fnspec (NULL)
107 ~fnspec_summary ()
109 free (fnspec);
113 /* Summary holding fnspec string for a given call. */
115 class fnspec_summaries_t : public call_summary <fnspec_summary *>
117 public:
118 fnspec_summaries_t (symbol_table *symtab)
119 : call_summary <fnspec_summary *> (symtab) {}
120 /* Hook that is called by summary when an edge is duplicated. */
121 virtual void duplicate (cgraph_edge *,
122 cgraph_edge *,
123 fnspec_summary *src,
124 fnspec_summary *dst)
126 dst->fnspec = xstrdup (src->fnspec);
130 static fnspec_summaries_t *fnspec_summaries = NULL;
132 /* Escape summary holds a vector of param indexes that escape to
133 a given call. */
134 struct escape_entry
136 /* Parameter that escapes at a given call. */
137 int parm_index;
138 /* Argument it escapes to. */
139 unsigned int arg;
140 /* Minimal flags known about the argument. */
141 eaf_flags_t min_flags;
142 /* Does it escape directly or indirectly? */
143 bool direct;
146 /* Dump EAF flags. */
148 static void
149 dump_eaf_flags (FILE *out, int flags, bool newline = true)
151 if (flags & EAF_DIRECT)
152 fprintf (out, " direct");
153 if (flags & EAF_NOCLOBBER)
154 fprintf (out, " noclobber");
155 if (flags & EAF_NOESCAPE)
156 fprintf (out, " noescape");
157 if (flags & EAF_NODIRECTESCAPE)
158 fprintf (out, " nodirectescape");
159 if (flags & EAF_UNUSED)
160 fprintf (out, " unused");
161 if (flags & EAF_NOT_RETURNED)
162 fprintf (out, " not_returned");
163 if (flags & EAF_NOT_RETURNED_DIRECTLY)
164 fprintf (out, " not_returned_directly");
165 if (flags & EAF_NOREAD)
166 fprintf (out, " noread");
167 if (newline)
168 fprintf (out, "\n");
171 struct escape_summary
173 auto_vec <escape_entry> esc;
174 void dump (FILE *out)
176 for (unsigned int i = 0; i < esc.length (); i++)
178 fprintf (out, " parm %i arg %i %s min:",
179 esc[i].parm_index,
180 esc[i].arg,
181 esc[i].direct ? "(direct)" : "(indirect)");
182 dump_eaf_flags (out, esc[i].min_flags, false);
184 fprintf (out, "\n");
188 class escape_summaries_t : public call_summary <escape_summary *>
190 public:
191 escape_summaries_t (symbol_table *symtab)
192 : call_summary <escape_summary *> (symtab) {}
193 /* Hook that is called by summary when an edge is duplicated. */
194 virtual void duplicate (cgraph_edge *,
195 cgraph_edge *,
196 escape_summary *src,
197 escape_summary *dst)
199 dst->esc = src->esc.copy ();
203 static escape_summaries_t *escape_summaries = NULL;
205 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
208 /* Class (from which there is one global instance) that holds modref summaries
209 for all analyzed functions. */
211 class GTY((user)) modref_summaries
212 : public fast_function_summary <modref_summary *, va_gc>
214 public:
215 modref_summaries (symbol_table *symtab)
216 : fast_function_summary <modref_summary *, va_gc> (symtab) {}
217 virtual void insert (cgraph_node *, modref_summary *state);
218 virtual void duplicate (cgraph_node *src_node,
219 cgraph_node *dst_node,
220 modref_summary *src_data,
221 modref_summary *dst_data);
222 static modref_summaries *create_ggc (symbol_table *symtab)
224 return new (ggc_alloc_no_dtor<modref_summaries> ())
225 modref_summaries (symtab);
229 class modref_summary_lto;
231 /* Class (from which there is one global instance) that holds modref summaries
232 for all analyzed functions. */
234 class GTY((user)) modref_summaries_lto
235 : public fast_function_summary <modref_summary_lto *, va_gc>
237 public:
238 modref_summaries_lto (symbol_table *symtab)
239 : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
240 propagated (false) {}
241 virtual void insert (cgraph_node *, modref_summary_lto *state);
242 virtual void duplicate (cgraph_node *src_node,
243 cgraph_node *dst_node,
244 modref_summary_lto *src_data,
245 modref_summary_lto *dst_data);
246 static modref_summaries_lto *create_ggc (symbol_table *symtab)
248 return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
249 modref_summaries_lto (symtab);
251 bool propagated;
254 /* Global variable holding all modref summaries
255 (from analysis to IPA propagation time). */
257 static GTY(()) fast_function_summary <modref_summary *, va_gc>
258 *summaries;
260 /* Global variable holding all modref optimization summaries
261 (from IPA propagation time or used by local optimization pass). */
263 static GTY(()) fast_function_summary <modref_summary *, va_gc>
264 *optimization_summaries;
266 /* LTO summaries hold info from analysis to LTO streaming or from LTO
267 stream-in through propagation to LTO stream-out. */
269 static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
270 *summaries_lto;
272 /* Summary for a single function which this pass produces. */
274 modref_summary::modref_summary ()
275 : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
276 writes_errno (false)
280 modref_summary::~modref_summary ()
282 if (loads)
283 ggc_delete (loads);
284 if (stores)
285 ggc_delete (stores);
288 /* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
289 useful to track. If returns_void is true moreover clear
290 EAF_NOT_RETURNED. */
291 static int
292 remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
294 if (ecf_flags & ECF_NOVOPS)
295 return 0;
296 if (ecf_flags & ECF_CONST)
297 eaf_flags &= ~implicit_const_eaf_flags;
298 else if (ecf_flags & ECF_PURE)
299 eaf_flags &= ~implicit_pure_eaf_flags;
300 else if ((ecf_flags & ECF_NORETURN) || returns_void)
301 eaf_flags &= ~(EAF_NOT_RETURNED | EAF_NOT_RETURNED_DIRECTLY);
302 return eaf_flags;
305 /* Return true if FLAGS holds some useful information. */
307 static bool
308 eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags)
310 for (unsigned i = 0; i < flags.length (); i++)
311 if (remove_useless_eaf_flags (flags[i], ecf_flags, false))
312 return true;
313 return false;
316 /* Return true if summary is potentially useful for optimization.
317 If CHECK_FLAGS is false assume that arg_flags are useful. */
319 bool
320 modref_summary::useful_p (int ecf_flags, bool check_flags)
322 if (ecf_flags & ECF_NOVOPS)
323 return false;
324 if (arg_flags.length () && !check_flags)
325 return true;
326 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
327 return true;
328 arg_flags.release ();
329 if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
330 return true;
331 if (check_flags
332 && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
333 return true;
334 if (ecf_flags & ECF_CONST)
335 return false;
336 if (loads && !loads->every_base)
337 return true;
338 if (ecf_flags & ECF_PURE)
339 return false;
340 return stores && !stores->every_base;
343 /* Return true if global memory is read
344 (that is loads summary contains global memory access). */
345 bool
346 modref_summary::global_memory_read_p ()
348 if (!loads)
349 return true;
350 return loads->global_access_p ();
353 /* Return true if global memory is written. */
354 bool
355 modref_summary::global_memory_written_p ()
357 if (!stores)
358 return true;
359 return stores->global_access_p ();
363 /* Single function summary used for LTO. */
365 typedef modref_tree <tree> modref_records_lto;
366 struct GTY(()) modref_summary_lto
368 /* Load and stores in functions using types rather then alias sets.
370 This is necessary to make the information streamable for LTO but is also
371 more verbose and thus more likely to hit the limits. */
372 modref_records_lto *loads;
373 modref_records_lto *stores;
374 auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
375 eaf_flags_t retslot_flags;
376 eaf_flags_t static_chain_flags;
377 bool writes_errno;
379 modref_summary_lto ();
380 ~modref_summary_lto ();
381 void dump (FILE *);
382 bool useful_p (int ecf_flags, bool check_flags = true);
385 /* Summary for a single function which this pass produces. */
387 modref_summary_lto::modref_summary_lto ()
388 : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
389 writes_errno (false)
393 modref_summary_lto::~modref_summary_lto ()
395 if (loads)
396 ggc_delete (loads);
397 if (stores)
398 ggc_delete (stores);
402 /* Return true if lto summary is potentially useful for optimization.
403 If CHECK_FLAGS is false assume that arg_flags are useful. */
405 bool
406 modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
408 if (ecf_flags & ECF_NOVOPS)
409 return false;
410 if (arg_flags.length () && !check_flags)
411 return true;
412 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
413 return true;
414 arg_flags.release ();
415 if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
416 return true;
417 if (check_flags
418 && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
419 return true;
420 if (ecf_flags & ECF_CONST)
421 return false;
422 if (loads && !loads->every_base)
423 return true;
424 if (ecf_flags & ECF_PURE)
425 return false;
426 return stores && !stores->every_base;
429 /* Dump A to OUT. */
431 static void
432 dump_access (modref_access_node *a, FILE *out)
434 fprintf (out, " access:");
435 if (a->parm_index != -1)
437 fprintf (out, " Parm %i", a->parm_index);
438 if (a->parm_offset_known)
440 fprintf (out, " param offset:");
441 print_dec ((poly_int64_pod)a->parm_offset, out, SIGNED);
444 if (a->range_info_useful_p ())
446 fprintf (out, " offset:");
447 print_dec ((poly_int64_pod)a->offset, out, SIGNED);
448 fprintf (out, " size:");
449 print_dec ((poly_int64_pod)a->size, out, SIGNED);
450 fprintf (out, " max_size:");
451 print_dec ((poly_int64_pod)a->max_size, out, SIGNED);
452 if (a->adjustments)
453 fprintf (out, " adjusted %i times", a->adjustments);
455 fprintf (out, "\n");
458 /* Dump records TT to OUT. */
460 static void
461 dump_records (modref_records *tt, FILE *out)
463 fprintf (out, " Limits: %i bases, %i refs\n",
464 (int)tt->max_bases, (int)tt->max_refs);
465 if (tt->every_base)
467 fprintf (out, " Every base\n");
468 return;
470 size_t i;
471 modref_base_node <alias_set_type> *n;
472 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
474 fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
475 if (n->every_ref)
477 fprintf (out, " Every ref\n");
478 continue;
480 size_t j;
481 modref_ref_node <alias_set_type> *r;
482 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
484 fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
485 if (r->every_access)
487 fprintf (out, " Every access\n");
488 continue;
490 size_t k;
491 modref_access_node *a;
492 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
493 dump_access (a, out);
498 /* Dump records TT to OUT. */
500 static void
501 dump_lto_records (modref_records_lto *tt, FILE *out)
503 fprintf (out, " Limits: %i bases, %i refs\n",
504 (int)tt->max_bases, (int)tt->max_refs);
505 if (tt->every_base)
507 fprintf (out, " Every base\n");
508 return;
510 size_t i;
511 modref_base_node <tree> *n;
512 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
514 fprintf (out, " Base %i:", (int)i);
515 print_generic_expr (dump_file, n->base);
516 fprintf (out, " (alias set %i)\n",
517 n->base ? get_alias_set (n->base) : 0);
518 if (n->every_ref)
520 fprintf (out, " Every ref\n");
521 continue;
523 size_t j;
524 modref_ref_node <tree> *r;
525 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
527 fprintf (out, " Ref %i:", (int)j);
528 print_generic_expr (dump_file, r->ref);
529 fprintf (out, " (alias set %i)\n",
530 r->ref ? get_alias_set (r->ref) : 0);
531 if (r->every_access)
533 fprintf (out, " Every access\n");
534 continue;
536 size_t k;
537 modref_access_node *a;
538 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
539 dump_access (a, out);
544 /* Dump all escape points of NODE to OUT. */
546 static void
547 dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
549 int i = 0;
550 if (!escape_summaries)
551 return;
552 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
554 class escape_summary *sum = escape_summaries->get (e);
555 if (sum)
557 fprintf (out, "%*sIndirect call %i in %s escapes:",
558 depth, "", i, node->dump_name ());
559 sum->dump (out);
561 i++;
563 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
565 if (!e->inline_failed)
566 dump_modref_edge_summaries (out, e->callee, depth + 1);
567 class escape_summary *sum = escape_summaries->get (e);
568 if (sum)
570 fprintf (out, "%*sCall %s->%s escapes:", depth, "",
571 node->dump_name (), e->callee->dump_name ());
572 sum->dump (out);
574 class fnspec_summary *fsum = fnspec_summaries->get (e);
575 if (fsum)
577 fprintf (out, "%*sCall %s->%s fnspec: %s\n", depth, "",
578 node->dump_name (), e->callee->dump_name (),
579 fsum->fnspec);
584 /* Remove all call edge summaries associated with NODE. */
586 static void
587 remove_modref_edge_summaries (cgraph_node *node)
589 if (!escape_summaries)
590 return;
591 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
592 escape_summaries->remove (e);
593 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
595 if (!e->inline_failed)
596 remove_modref_edge_summaries (e->callee);
597 escape_summaries->remove (e);
598 fnspec_summaries->remove (e);
602 /* Dump summary. */
604 void
605 modref_summary::dump (FILE *out)
607 if (loads)
609 fprintf (out, " loads:\n");
610 dump_records (loads, out);
612 if (stores)
614 fprintf (out, " stores:\n");
615 dump_records (stores, out);
617 if (writes_errno)
618 fprintf (out, " Writes errno\n");
619 if (arg_flags.length ())
621 for (unsigned int i = 0; i < arg_flags.length (); i++)
622 if (arg_flags[i])
624 fprintf (out, " parm %i flags:", i);
625 dump_eaf_flags (out, arg_flags[i]);
628 if (retslot_flags)
630 fprintf (out, " Retslot flags:");
631 dump_eaf_flags (out, retslot_flags);
633 if (static_chain_flags)
635 fprintf (out, " Static chain flags:");
636 dump_eaf_flags (out, static_chain_flags);
640 /* Dump summary. */
642 void
643 modref_summary_lto::dump (FILE *out)
645 fprintf (out, " loads:\n");
646 dump_lto_records (loads, out);
647 fprintf (out, " stores:\n");
648 dump_lto_records (stores, out);
649 if (writes_errno)
650 fprintf (out, " Writes errno\n");
651 if (arg_flags.length ())
653 for (unsigned int i = 0; i < arg_flags.length (); i++)
654 if (arg_flags[i])
656 fprintf (out, " parm %i flags:", i);
657 dump_eaf_flags (out, arg_flags[i]);
660 if (retslot_flags)
662 fprintf (out, " Retslot flags:");
663 dump_eaf_flags (out, retslot_flags);
665 if (static_chain_flags)
667 fprintf (out, " Static chain flags:");
668 dump_eaf_flags (out, static_chain_flags);
672 /* Get function summary for FUNC if it exists, return NULL otherwise. */
674 modref_summary *
675 get_modref_function_summary (cgraph_node *func)
677 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
678 if (!optimization_summaries)
679 return NULL;
681 /* A single function body may be represented by multiple symbols with
682 different visibility. For example, if FUNC is an interposable alias,
683 we don't want to return anything, even if we have summary for the target
684 function. */
685 enum availability avail;
686 func = func->function_or_virtual_thunk_symbol
687 (&avail, current_function_decl ?
688 cgraph_node::get (current_function_decl) : NULL);
689 if (avail <= AVAIL_INTERPOSABLE)
690 return NULL;
692 modref_summary *r = optimization_summaries->get (func);
693 return r;
696 namespace {
698 /* Construct modref_access_node from REF. */
699 static modref_access_node
700 get_access (ao_ref *ref)
702 tree base;
704 base = ao_ref_base (ref);
705 modref_access_node a = {ref->offset, ref->size, ref->max_size,
706 0, -1, false, 0};
707 if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
709 tree memref = base;
710 base = TREE_OPERAND (base, 0);
711 if (TREE_CODE (base) == SSA_NAME
712 && SSA_NAME_IS_DEFAULT_DEF (base)
713 && TREE_CODE (SSA_NAME_VAR (base)) == PARM_DECL)
715 a.parm_index = 0;
716 for (tree t = DECL_ARGUMENTS (current_function_decl);
717 t != SSA_NAME_VAR (base); t = DECL_CHAIN (t))
719 if (!t)
721 a.parm_index = -1;
722 break;
724 a.parm_index++;
726 if (TREE_CODE (memref) == MEM_REF)
728 a.parm_offset_known
729 = wi::to_poly_wide (TREE_OPERAND
730 (memref, 1)).to_shwi (&a.parm_offset);
732 else
733 a.parm_offset_known = false;
735 else
736 a.parm_index = -1;
738 else
739 a.parm_index = -1;
740 return a;
743 /* Record access into the modref_records data structure. */
745 static void
746 record_access (modref_records *tt, ao_ref *ref)
748 alias_set_type base_set = !flag_strict_aliasing ? 0
749 : ao_ref_base_alias_set (ref);
750 alias_set_type ref_set = !flag_strict_aliasing ? 0
751 : (ao_ref_alias_set (ref));
752 modref_access_node a = get_access (ref);
753 if (dump_file)
755 fprintf (dump_file, " - Recording base_set=%i ref_set=%i parm=%i\n",
756 base_set, ref_set, a.parm_index);
758 tt->insert (base_set, ref_set, a, false);
761 /* IPA version of record_access_tree. */
763 static void
764 record_access_lto (modref_records_lto *tt, ao_ref *ref)
766 /* get_alias_set sometimes use different type to compute the alias set
767 than TREE_TYPE (base). Do same adjustments. */
768 tree base_type = NULL_TREE, ref_type = NULL_TREE;
769 if (flag_strict_aliasing)
771 tree base;
773 base = ref->ref;
774 while (handled_component_p (base))
775 base = TREE_OPERAND (base, 0);
777 base_type = reference_alias_ptr_type_1 (&base);
779 if (!base_type)
780 base_type = TREE_TYPE (base);
781 else
782 base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
783 ? NULL_TREE : TREE_TYPE (base_type);
785 tree ref_expr = ref->ref;
786 ref_type = reference_alias_ptr_type_1 (&ref_expr);
788 if (!ref_type)
789 ref_type = TREE_TYPE (ref_expr);
790 else
791 ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
792 ? NULL_TREE : TREE_TYPE (ref_type);
794 /* Sanity check that we are in sync with what get_alias_set does. */
795 gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
796 || get_alias_set (base_type)
797 == ao_ref_base_alias_set (ref));
798 gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
799 || get_alias_set (ref_type)
800 == ao_ref_alias_set (ref));
802 /* Do not bother to record types that have no meaningful alias set.
803 Also skip variably modified types since these go to local streams. */
804 if (base_type && (!get_alias_set (base_type)
805 || variably_modified_type_p (base_type, NULL_TREE)))
806 base_type = NULL_TREE;
807 if (ref_type && (!get_alias_set (ref_type)
808 || variably_modified_type_p (ref_type, NULL_TREE)))
809 ref_type = NULL_TREE;
811 modref_access_node a = get_access (ref);
812 if (dump_file)
814 fprintf (dump_file, " - Recording base type:");
815 print_generic_expr (dump_file, base_type);
816 fprintf (dump_file, " (alias set %i) ref type:",
817 base_type ? get_alias_set (base_type) : 0);
818 print_generic_expr (dump_file, ref_type);
819 fprintf (dump_file, " (alias set %i) parm:%i\n",
820 ref_type ? get_alias_set (ref_type) : 0,
821 a.parm_index);
824 tt->insert (base_type, ref_type, a, false);
827 /* Returns true if and only if we should store the access to EXPR.
828 Some accesses, e.g. loads from automatic variables, are not interesting. */
830 static bool
831 record_access_p (tree expr)
833 if (refs_local_or_readonly_memory_p (expr))
835 if (dump_file)
836 fprintf (dump_file, " - Read-only or local, ignoring.\n");
837 return false;
839 return true;
842 /* Return true if ECF flags says that return value can be ignored. */
844 static bool
845 ignore_retval_p (tree caller, int flags)
847 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
848 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
849 return true;
850 return false;
853 /* Return true if ECF flags says that stores can be ignored. */
855 static bool
856 ignore_stores_p (tree caller, int flags)
858 if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
859 return true;
860 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
861 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
862 return true;
863 return false;
866 /* Determine parm_map for argument I of STMT. */
868 modref_parm_map
869 parm_map_for_arg (gimple *stmt, int i)
871 tree op = gimple_call_arg (stmt, i);
872 bool offset_known;
873 poly_int64 offset;
874 struct modref_parm_map parm_map;
876 parm_map.parm_offset_known = false;
877 parm_map.parm_offset = 0;
879 offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
880 if (TREE_CODE (op) == SSA_NAME
881 && SSA_NAME_IS_DEFAULT_DEF (op)
882 && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
884 int index = 0;
885 for (tree t = DECL_ARGUMENTS (current_function_decl);
886 t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
888 if (!t)
890 index = -1;
891 break;
893 index++;
895 parm_map.parm_index = index;
896 parm_map.parm_offset_known = offset_known;
897 parm_map.parm_offset = offset;
899 else if (points_to_local_or_readonly_memory_p (op))
900 parm_map.parm_index = -2;
901 else
902 parm_map.parm_index = -1;
903 return parm_map;
906 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
907 int CUR_SUMMARY. Return true if something changed.
908 If IGNORE_STORES is true, do not merge stores.
909 If RECORD_ADJUSTMENTS is true cap number of adjustments to
910 a given access to make dataflow finite. */
912 bool
913 merge_call_side_effects (modref_summary *cur_summary,
914 gimple *stmt, modref_summary *callee_summary,
915 bool ignore_stores, cgraph_node *callee_node,
916 bool record_adjustments)
918 auto_vec <modref_parm_map, 32> parm_map;
919 bool changed = false;
921 /* We can not safely optimize based on summary of callee if it does
922 not always bind to current def: it is possible that memory load
923 was optimized out earlier which may not happen in the interposed
924 variant. */
925 if (!callee_node->binds_to_current_def_p ())
927 if (dump_file)
928 fprintf (dump_file, " - May be interposed: collapsing loads.\n");
929 cur_summary->loads->collapse ();
932 if (dump_file)
933 fprintf (dump_file, " - Merging side effects of %s with parm map:",
934 callee_node->dump_name ());
936 parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true);
937 for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
939 parm_map[i] = parm_map_for_arg (stmt, i);
940 if (dump_file)
942 fprintf (dump_file, " %i", parm_map[i].parm_index);
943 if (parm_map[i].parm_offset_known)
945 fprintf (dump_file, " offset:");
946 print_dec ((poly_int64_pod)parm_map[i].parm_offset,
947 dump_file, SIGNED);
951 if (dump_file)
952 fprintf (dump_file, "\n");
954 /* Merge with callee's summary. */
955 changed |= cur_summary->loads->merge (callee_summary->loads, &parm_map,
956 record_adjustments);
957 if (!ignore_stores)
959 changed |= cur_summary->stores->merge (callee_summary->stores,
960 &parm_map,
961 record_adjustments);
962 if (!cur_summary->writes_errno
963 && callee_summary->writes_errno)
965 cur_summary->writes_errno = true;
966 changed = true;
969 return changed;
972 /* Return access mode for argument I of call STMT with FNSPEC. */
974 static modref_access_node
975 get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
976 unsigned int i, modref_parm_map &map)
978 tree size = NULL_TREE;
979 unsigned int size_arg;
981 if (!fnspec.arg_specified_p (i))
983 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
984 size = gimple_call_arg (call, size_arg);
985 else if (fnspec.arg_access_size_given_by_type_p (i))
987 tree callee = gimple_call_fndecl (call);
988 tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
990 for (unsigned int p = 0; p < i; p++)
991 t = TREE_CHAIN (t);
992 size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
994 modref_access_node a = {0, -1, -1,
995 map.parm_offset, map.parm_index,
996 map.parm_offset_known, 0};
997 poly_int64 size_hwi;
998 if (size
999 && poly_int_tree_p (size, &size_hwi)
1000 && coeffs_in_range_p (size_hwi, 0,
1001 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
1003 a.size = -1;
1004 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
1006 return a;
1009 /* Collapse loads and return true if something changed. */
1011 static bool
1012 collapse_loads (modref_summary *cur_summary,
1013 modref_summary_lto *cur_summary_lto)
1015 bool changed = false;
1017 if (cur_summary && !cur_summary->loads->every_base)
1019 cur_summary->loads->collapse ();
1020 changed = true;
1022 if (cur_summary_lto
1023 && !cur_summary_lto->loads->every_base)
1025 cur_summary_lto->loads->collapse ();
1026 changed = true;
1028 return changed;
1031 /* Collapse loads and return true if something changed. */
1033 static bool
1034 collapse_stores (modref_summary *cur_summary,
1035 modref_summary_lto *cur_summary_lto)
1037 bool changed = false;
1039 if (cur_summary && !cur_summary->stores->every_base)
1041 cur_summary->stores->collapse ();
1042 changed = true;
1044 if (cur_summary_lto
1045 && !cur_summary_lto->stores->every_base)
1047 cur_summary_lto->stores->collapse ();
1048 changed = true;
1050 return changed;
1054 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1055 If IGNORE_STORES is true ignore them.
1056 Return false if no useful summary can be produced. */
1058 static bool
1059 process_fnspec (modref_summary *cur_summary,
1060 modref_summary_lto *cur_summary_lto,
1061 gcall *call, bool ignore_stores)
1063 attr_fnspec fnspec = gimple_call_fnspec (call);
1064 if (!fnspec.known_p ())
1066 if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
1067 fprintf (dump_file, " Builtin with no fnspec: %s\n",
1068 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
1069 if (ignore_stores)
1071 collapse_loads (cur_summary, cur_summary_lto);
1072 return true;
1074 return false;
1076 if (fnspec.global_memory_read_p ())
1077 collapse_loads (cur_summary, cur_summary_lto);
1078 else
1080 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1081 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1083 else if (!fnspec.arg_specified_p (i)
1084 || fnspec.arg_maybe_read_p (i))
1086 modref_parm_map map = parm_map_for_arg (call, i);
1088 if (map.parm_index == -2)
1089 continue;
1090 if (map.parm_index == -1)
1092 collapse_loads (cur_summary, cur_summary_lto);
1093 break;
1095 if (cur_summary)
1096 cur_summary->loads->insert (0, 0,
1097 get_access_for_fnspec (call,
1098 fnspec, i,
1099 map),
1100 false);
1101 if (cur_summary_lto)
1102 cur_summary_lto->loads->insert (0, 0,
1103 get_access_for_fnspec (call,
1104 fnspec, i,
1105 map),
1106 false);
1109 if (ignore_stores)
1110 return true;
1111 if (fnspec.global_memory_written_p ())
1112 collapse_stores (cur_summary, cur_summary_lto);
1113 else
1115 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1116 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1118 else if (!fnspec.arg_specified_p (i)
1119 || fnspec.arg_maybe_written_p (i))
1121 modref_parm_map map = parm_map_for_arg (call, i);
1123 if (map.parm_index == -2)
1124 continue;
1125 if (map.parm_index == -1)
1127 collapse_stores (cur_summary, cur_summary_lto);
1128 break;
1130 if (cur_summary)
1131 cur_summary->stores->insert (0, 0,
1132 get_access_for_fnspec (call,
1133 fnspec, i,
1134 map),
1135 false);
1136 if (cur_summary_lto)
1137 cur_summary_lto->stores->insert (0, 0,
1138 get_access_for_fnspec (call,
1139 fnspec, i,
1140 map),
1141 false);
1143 if (fnspec.errno_maybe_written_p () && flag_errno_math)
1145 if (cur_summary)
1146 cur_summary->writes_errno = true;
1147 if (cur_summary_lto)
1148 cur_summary_lto->writes_errno = true;
1151 return true;
1154 /* Analyze function call STMT in function F.
1155 Remember recursive calls in RECURSIVE_CALLS. */
1157 static bool
1158 analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto,
1159 gcall *stmt, vec <gimple *> *recursive_calls)
1161 /* Check flags on the function call. In certain cases, analysis can be
1162 simplified. */
1163 int flags = gimple_call_flags (stmt);
1164 if (flags & (ECF_CONST | ECF_NOVOPS))
1166 if (dump_file)
1167 fprintf (dump_file,
1168 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1169 "except for args.\n");
1170 return true;
1173 /* Pure functions do not affect global memory. Stores by functions which are
1174 noreturn and do not throw can safely be ignored. */
1175 bool ignore_stores = ignore_stores_p (current_function_decl, flags);
1177 /* Next, we try to get the callee's function declaration. The goal is to
1178 merge their summary with ours. */
1179 tree callee = gimple_call_fndecl (stmt);
1181 /* Check if this is an indirect call. */
1182 if (!callee)
1184 if (dump_file)
1185 fprintf (dump_file, gimple_call_internal_p (stmt)
1186 ? " - Internal call" : " - Indirect call.\n");
1187 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1189 /* We only need to handle internal calls in IPA mode. */
1190 gcc_checking_assert (!cur_summary_lto);
1192 struct cgraph_node *callee_node = cgraph_node::get_create (callee);
1194 /* If this is a recursive call, the target summary is the same as ours, so
1195 there's nothing to do. */
1196 if (recursive_call_p (current_function_decl, callee))
1198 recursive_calls->safe_push (stmt);
1199 if (dump_file)
1200 fprintf (dump_file, " - Skipping recursive call.\n");
1201 return true;
1204 gcc_assert (callee_node != NULL);
1206 /* Get the function symbol and its availability. */
1207 enum availability avail;
1208 callee_node = callee_node->function_symbol (&avail);
1209 if (avail <= AVAIL_INTERPOSABLE)
1211 if (dump_file)
1212 fprintf (dump_file, " - Function availability <= AVAIL_INTERPOSABLE.\n");
1213 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1216 /* Get callee's modref summary. As above, if there's no summary, we either
1217 have to give up or, if stores are ignored, we can just purge loads. */
1218 modref_summary *callee_summary = optimization_summaries->get (callee_node);
1219 if (!callee_summary)
1221 if (dump_file)
1222 fprintf (dump_file, " - No modref summary available for callee.\n");
1223 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1226 merge_call_side_effects (cur_summary, stmt, callee_summary, ignore_stores,
1227 callee_node, false);
1229 return true;
1232 /* Support analysis in non-lto and lto mode in parallel. */
1234 struct summary_ptrs
1236 struct modref_summary *nolto;
1237 struct modref_summary_lto *lto;
1240 /* Helper for analyze_stmt. */
1242 static bool
1243 analyze_load (gimple *, tree, tree op, void *data)
1245 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1246 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1248 if (dump_file)
1250 fprintf (dump_file, " - Analyzing load: ");
1251 print_generic_expr (dump_file, op);
1252 fprintf (dump_file, "\n");
1255 if (!record_access_p (op))
1256 return false;
1258 ao_ref r;
1259 ao_ref_init (&r, op);
1261 if (summary)
1262 record_access (summary->loads, &r);
1263 if (summary_lto)
1264 record_access_lto (summary_lto->loads, &r);
1265 return false;
1268 /* Helper for analyze_stmt. */
1270 static bool
1271 analyze_store (gimple *, tree, tree op, void *data)
1273 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1274 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1276 if (dump_file)
1278 fprintf (dump_file, " - Analyzing store: ");
1279 print_generic_expr (dump_file, op);
1280 fprintf (dump_file, "\n");
1283 if (!record_access_p (op))
1284 return false;
1286 ao_ref r;
1287 ao_ref_init (&r, op);
1289 if (summary)
1290 record_access (summary->stores, &r);
1291 if (summary_lto)
1292 record_access_lto (summary_lto->stores, &r);
1293 return false;
1296 /* Analyze statement STMT of function F.
1297 If IPA is true do not merge in side effects of calls. */
1299 static bool
1300 analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
1301 gimple *stmt, bool ipa, vec <gimple *> *recursive_calls)
1303 /* In general we can not ignore clobbers because they are barriers for code
1304 motion, however after inlining it is safe to do because local optimization
1305 passes do not consider clobbers from other functions.
1306 Similar logic is in ipa-pure-const.c. */
1307 if ((ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1308 return true;
1310 struct summary_ptrs sums = {summary, summary_lto};
1312 /* Analyze all loads and stores in STMT. */
1313 walk_stmt_load_store_ops (stmt, &sums,
1314 analyze_load, analyze_store);
1316 switch (gimple_code (stmt))
1318 case GIMPLE_ASM:
1319 /* If the ASM statement does not read nor write memory, there's nothing
1320 to do. Otherwise just give up. */
1321 if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1322 return true;
1323 if (dump_file)
1324 fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1325 "which clobbers memory.\n");
1326 return false;
1327 case GIMPLE_CALL:
1328 if (!ipa || gimple_call_internal_p (stmt))
1329 return analyze_call (summary, summary_lto,
1330 as_a <gcall *> (stmt), recursive_calls);
1331 else
1333 attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1335 if (fnspec.known_p ()
1336 && (!fnspec.global_memory_read_p ()
1337 || !fnspec.global_memory_written_p ()))
1339 cgraph_edge *e = cgraph_node::get (current_function_decl)->get_edge (stmt);
1340 if (e->callee)
1342 fnspec_summaries->get_create (e)->fnspec = xstrdup (fnspec.get_str ());
1343 if (dump_file)
1344 fprintf (dump_file, " Recorded fnspec %s\n", fnspec.get_str ());
1348 return true;
1349 default:
1350 /* Nothing to do for other types of statements. */
1351 return true;
1355 /* Remove summary of current function because during the function body
1356 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1357 mode of scan. */
1359 static void
1360 remove_summary (bool lto, bool nolto, bool ipa)
1362 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1363 if (!ipa)
1364 optimization_summaries->remove (fnode);
1365 else
1367 if (nolto)
1368 summaries->remove (fnode);
1369 if (lto)
1370 summaries_lto->remove (fnode);
1371 remove_modref_edge_summaries (fnode);
1373 if (dump_file)
1374 fprintf (dump_file,
1375 " - modref done with result: not tracked.\n");
1378 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1380 bool
1381 memory_access_to (tree op, tree ssa_name)
1383 tree base = get_base_address (op);
1384 if (!base)
1385 return false;
1386 if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1387 return false;
1388 return TREE_OPERAND (base, 0) == ssa_name;
1391 /* Consider statement val = *arg.
1392 return EAF flags of ARG that can be determined from EAF flags of VAL
1393 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1394 all stores to VAL, i.e. when handling noreturn function. */
1396 static int
1397 deref_flags (int flags, bool ignore_stores)
1399 int ret = EAF_NODIRECTESCAPE | EAF_NOT_RETURNED_DIRECTLY;
1400 /* If argument is unused just account for
1401 the read involved in dereference. */
1402 if (flags & EAF_UNUSED)
1403 ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOT_RETURNED;
1404 else
1406 if ((flags & EAF_NOCLOBBER) || ignore_stores)
1407 ret |= EAF_NOCLOBBER;
1408 if ((flags & EAF_NOESCAPE) || ignore_stores)
1409 ret |= EAF_NOESCAPE;
1410 /* If the value dereferenced is not used for another load or store
1411 we can still consider ARG as used only directly.
1413 Consider
1416 test (int *a)
1418 return *a!=0;
1422 if ((flags & (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT))
1423 == (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT)
1424 && ((flags & EAF_NOCLOBBER) || ignore_stores))
1425 ret |= EAF_DIRECT;
1426 if (flags & EAF_NOT_RETURNED)
1427 ret |= EAF_NOT_RETURNED;
1429 return ret;
1433 /* Description of an escape point. */
1435 struct escape_point
1437 /* Extra hidden args we keep track of. */
1438 enum hidden_args
1440 retslot_arg = -1,
1441 static_chain_arg = -2
1443 /* Value escapes to this call. */
1444 gcall *call;
1445 /* Argument it escapes to. */
1446 int arg;
1447 /* Flags already known about the argument (this can save us from recording
1448 esape points if local analysis did good job already). */
1449 eaf_flags_t min_flags;
1450 /* Does value escape directly or indiretly? */
1451 bool direct;
1454 class modref_lattice
1456 public:
1457 /* EAF flags of the SSA name. */
1458 eaf_flags_t flags;
1459 /* DFS bookkkeeping: we don't do real dataflow yet. */
1460 bool known;
1461 bool open;
1463 /* When doing IPA analysis we can not merge in callee escape points;
1464 Only remember them and do the merging at IPA propagation time. */
1465 vec <escape_point, va_heap, vl_ptr> escape_points;
1467 void init ();
1468 void release ();
1469 bool merge (const modref_lattice &with);
1470 bool merge (int flags);
1471 bool merge_deref (const modref_lattice &with, bool ignore_stores);
1472 bool merge_direct_load ();
1473 bool merge_direct_store ();
1474 bool add_escape_point (gcall *call, int arg, int min_flags, bool diret);
1475 void dump (FILE *out, int indent = 0) const;
1478 /* Lattices are saved to vectors, so keep them PODs. */
1479 void
1480 modref_lattice::init ()
1482 /* All flags we track. */
1483 int f = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED
1484 | EAF_NODIRECTESCAPE | EAF_NOT_RETURNED |
1485 EAF_NOT_RETURNED_DIRECTLY | EAF_NOREAD;
1486 flags = f;
1487 /* Check that eaf_flags_t is wide enough to hold all flags. */
1488 gcc_checking_assert (f == flags);
1489 open = true;
1490 known = false;
1493 /* Release memory. */
1494 void
1495 modref_lattice::release ()
1497 escape_points.release ();
1500 /* Dump lattice to OUT; indent with INDENT spaces. */
1502 void
1503 modref_lattice::dump (FILE *out, int indent) const
1505 dump_eaf_flags (out, flags);
1506 if (escape_points.length ())
1508 fprintf (out, "%*sEscapes:\n", indent, "");
1509 for (unsigned int i = 0; i < escape_points.length (); i++)
1511 fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
1512 escape_points[i].arg,
1513 escape_points[i].direct ? "direct" : "indirect");
1514 dump_eaf_flags (out, escape_points[i].min_flags, false);
1515 fprintf (out, " in call ");
1516 print_gimple_stmt (out, escape_points[i].call, 0);
1521 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1522 point exists. */
1524 bool
1525 modref_lattice::add_escape_point (gcall *call, int arg, int min_flags,
1526 bool direct)
1528 escape_point *ep;
1529 unsigned int i;
1531 /* If we already determined flags to be bad enough,
1532 we do not need to record. */
1533 if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
1534 return false;
1536 FOR_EACH_VEC_ELT (escape_points, i, ep)
1537 if (ep->call == call && ep->arg == arg && ep->direct == direct)
1539 if ((ep->min_flags & min_flags) == min_flags)
1540 return false;
1541 ep->min_flags &= min_flags;
1542 return true;
1544 /* Give up if max escape points is met. */
1545 if ((int)escape_points.length () > param_modref_max_escape_points)
1547 if (dump_file)
1548 fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
1549 merge (0);
1550 return true;
1552 escape_point new_ep = {call, arg, min_flags, direct};
1553 escape_points.safe_push (new_ep);
1554 return true;
1557 /* Merge in flags from F. */
1558 bool
1559 modref_lattice::merge (int f)
1561 if (f & EAF_UNUSED)
1562 return false;
1563 /* Noescape implies that value also does not escape directly.
1564 Fnspec machinery does set both so compensate for this. */
1565 if (f & EAF_NOESCAPE)
1566 f |= EAF_NODIRECTESCAPE;
1567 if (f & EAF_NOT_RETURNED)
1568 f |= EAF_NOT_RETURNED_DIRECTLY;
1569 if ((flags & f) != flags)
1571 flags &= f;
1572 /* Prune obvoiusly useless flags;
1573 We do not have ECF_FLAGS handy which is not big problem since
1574 we will do final flags cleanup before producing summary.
1575 Merging should be fast so it can work well with dataflow. */
1576 flags = remove_useless_eaf_flags (flags, 0, false);
1577 if (!flags)
1578 escape_points.release ();
1579 return true;
1581 return false;
1584 /* Merge in WITH. Return true if anyting changed. */
1586 bool
1587 modref_lattice::merge (const modref_lattice &with)
1589 if (!with.known)
1590 return merge (0);
1592 bool changed = merge (with.flags);
1594 if (!flags)
1595 return changed;
1596 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1597 changed |= add_escape_point (with.escape_points[i].call,
1598 with.escape_points[i].arg,
1599 with.escape_points[i].min_flags,
1600 with.escape_points[i].direct);
1601 return changed;
1604 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1605 stores. Return true if anyting changed. */
1607 bool
1608 modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
1610 if (!with.known)
1611 return merge (0);
1613 bool changed = merge (deref_flags (with.flags, ignore_stores));
1615 if (!flags)
1616 return changed;
1617 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1619 int min_flags = with.escape_points[i].min_flags;
1621 if (with.escape_points[i].direct)
1622 min_flags = deref_flags (min_flags, ignore_stores);
1623 else if (ignore_stores)
1624 min_flags |= ignore_stores_eaf_flags;
1625 changed |= add_escape_point (with.escape_points[i].call,
1626 with.escape_points[i].arg,
1627 min_flags,
1628 false);
1630 return changed;
1633 /* Merge in flags for direct load. */
1635 bool
1636 modref_lattice::merge_direct_load ()
1638 return merge (~(EAF_UNUSED | EAF_NOREAD));
1641 /* Merge in flags for direct store. */
1643 bool
1644 modref_lattice::merge_direct_store ()
1646 return merge (~(EAF_UNUSED | EAF_NOCLOBBER));
1649 /* Analyzer of EAF flags. */
1651 class modref_eaf_analysis
1653 public:
1654 /* Compute flags for NAME. */
1655 void analyze_ssa_name (tree name);
1656 /* Return flags computed earlier for NAME. */
1657 int get_ssa_name_flags (tree name)
1659 int version = SSA_NAME_VERSION (name);
1660 gcc_checking_assert (m_lattice[version].known);
1661 return m_lattice[version].flags;
1663 /* In IPA mode this will record all escape points
1664 determined for NAME to PARM_IDNEX. Flags are minimal
1665 flags known. */
1666 void record_escape_points (tree name, int parm_index, int flags);
1667 modref_eaf_analysis (bool ipa)
1669 m_ipa = ipa;
1670 m_depth = 0;
1671 m_lattice.safe_grow_cleared (num_ssa_names, true);
1673 ~modref_eaf_analysis ()
1675 gcc_checking_assert (!m_depth);
1676 if (m_ipa)
1677 for (unsigned int i = 0; i < num_ssa_names; i++)
1678 m_lattice[i].release ();
1680 private:
1681 /* If true, we produce analysis for IPA mode. In this case escape points ar
1682 collected. */
1683 bool m_ipa;
1684 /* Depth of recursion of analyze_ssa_name. */
1685 int m_depth;
1686 /* Propagation lattice for individual ssa names. */
1687 auto_vec<modref_lattice> m_lattice;
1689 void merge_with_ssa_name (tree dest, tree src, bool deref);
1690 void merge_call_lhs_flags (gcall *call, int arg, tree name, bool deref);
1694 /* Call statements may return their parameters. Consider argument number
1695 ARG of USE_STMT and determine flags that can needs to be cleared
1696 in case pointer possibly indirectly references from ARG I is returned.
1697 LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
1698 ARG is set to -1 for static chain. */
1700 void
1701 modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg,
1702 tree name, bool deref)
1704 int index = SSA_NAME_VERSION (name);
1706 /* If there is no return value, no flags are affected. */
1707 if (!gimple_call_lhs (call))
1708 return;
1710 /* If we know that function returns given argument and it is not ARG
1711 we can still be happy. */
1712 if (arg >= 0)
1714 int flags = gimple_call_return_flags (call);
1715 if ((flags & ERF_RETURNS_ARG)
1716 && (flags & ERF_RETURN_ARG_MASK) != arg)
1717 return;
1720 /* If return value is SSA name determine its flags. */
1721 if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
1723 tree lhs = gimple_call_lhs (call);
1724 merge_with_ssa_name (name, lhs, deref);
1726 /* In the case of memory store we can do nothing. */
1727 else if (deref)
1728 m_lattice[index].merge (deref_flags (0, false));
1729 else
1730 m_lattice[index].merge (0);
1733 /* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
1734 into flags for caller, update LATTICE of corresponding
1735 argument if needed. */
1737 static int
1738 callee_to_caller_flags (int call_flags, bool ignore_stores,
1739 modref_lattice &lattice)
1741 /* call_flags is about callee returning a value
1742 that is not the same as caller returning it. */
1743 call_flags |= EAF_NOT_RETURNED
1744 | EAF_NOT_RETURNED_DIRECTLY;
1745 /* TODO: We miss return value propagation.
1746 Be conservative and if value escapes to memory
1747 also mark it as escaping. */
1748 if (!ignore_stores && !(call_flags & EAF_UNUSED))
1750 if (!(call_flags & EAF_NOESCAPE))
1751 lattice.merge (~(EAF_NOT_RETURNED | EAF_UNUSED));
1752 if (!(call_flags & (EAF_NODIRECTESCAPE | EAF_NOESCAPE)))
1753 lattice.merge (~(EAF_NOT_RETURNED_DIRECTLY
1754 | EAF_NOT_RETURNED
1755 | EAF_UNUSED));
1757 else
1758 call_flags |= ignore_stores_eaf_flags;
1759 return call_flags;
1762 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
1763 LATTICE is an array of modref_lattices.
1764 DEPTH is a recursion depth used to make debug output prettier.
1765 If IPA is true we analyze for IPA propagation (and thus call escape points
1766 are processed later) */
1768 void
1769 modref_eaf_analysis::analyze_ssa_name (tree name)
1771 imm_use_iterator ui;
1772 gimple *use_stmt;
1773 int index = SSA_NAME_VERSION (name);
1775 /* See if value is already computed. */
1776 if (m_lattice[index].known)
1777 return;
1778 if (m_lattice[index].open)
1780 if (dump_file)
1781 fprintf (dump_file,
1782 "%*sGiving up on a cycle in SSA graph\n",
1783 m_depth * 4, "");
1784 return;
1786 if (m_depth == param_modref_max_depth)
1788 if (dump_file)
1789 fprintf (dump_file,
1790 "%*sGiving up on max depth\n",
1791 m_depth * 4, "");
1792 return;
1794 /* Recursion guard. */
1795 m_lattice[index].init ();
1797 if (dump_file)
1799 fprintf (dump_file,
1800 "%*sAnalyzing flags of ssa name: ", m_depth * 4, "");
1801 print_generic_expr (dump_file, name);
1802 fprintf (dump_file, "\n");
1805 FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
1807 if (m_lattice[index].flags == 0)
1808 break;
1809 if (is_gimple_debug (use_stmt))
1810 continue;
1811 if (dump_file)
1813 fprintf (dump_file, "%*s Analyzing stmt: ", m_depth * 4, "");
1814 print_gimple_stmt (dump_file, use_stmt, 0);
1816 /* If we see a direct non-debug use, clear unused bit.
1817 All dereferneces should be accounted below using deref_flags. */
1818 m_lattice[index].merge (~EAF_UNUSED);
1820 /* Gimple return may load the return value.
1821 Returning name counts as an use by tree-ssa-structalias.c */
1822 if (greturn *ret = dyn_cast <greturn *> (use_stmt))
1824 /* Returning through return slot is seen as memory write earlier. */
1825 if (DECL_RESULT (current_function_decl)
1826 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
1828 else if (gimple_return_retval (ret) == name)
1829 m_lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED
1830 | EAF_NOT_RETURNED_DIRECTLY));
1831 else if (memory_access_to (gimple_return_retval (ret), name))
1833 m_lattice[index].merge_direct_load ();
1834 m_lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED
1835 | EAF_NOT_RETURNED_DIRECTLY));
1838 /* Account for LHS store, arg loads and flags from callee function. */
1839 else if (gcall *call = dyn_cast <gcall *> (use_stmt))
1841 tree callee = gimple_call_fndecl (call);
1843 /* IPA PTA internally it treats calling a function as "writing" to
1844 the argument space of all functions the function pointer points to
1845 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
1846 is on since that would allow propagation of this from -fno-ipa-pta
1847 to -fipa-pta functions. */
1848 if (gimple_call_fn (use_stmt) == name)
1849 m_lattice[index].merge (~(EAF_NOCLOBBER | EAF_UNUSED));
1851 /* Recursion would require bit of propagation; give up for now. */
1852 if (callee && !m_ipa && recursive_call_p (current_function_decl,
1853 callee))
1854 m_lattice[index].merge (0);
1855 else
1857 int ecf_flags = gimple_call_flags (call);
1858 bool ignore_stores = ignore_stores_p (current_function_decl,
1859 ecf_flags);
1860 bool ignore_retval = ignore_retval_p (current_function_decl,
1861 ecf_flags);
1863 /* Handle *name = func (...). */
1864 if (gimple_call_lhs (call)
1865 && memory_access_to (gimple_call_lhs (call), name))
1867 m_lattice[index].merge_direct_store ();
1868 /* Return slot optimization passes address of
1869 LHS to callee via hidden parameter and this
1870 may make LHS to escape. See PR 98499. */
1871 if (gimple_call_return_slot_opt_p (call)
1872 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
1874 int call_flags = gimple_call_retslot_flags (call);
1875 bool isretslot = false;
1877 if (DECL_RESULT (current_function_decl)
1878 && DECL_BY_REFERENCE
1879 (DECL_RESULT (current_function_decl)))
1880 isretslot = ssa_default_def
1881 (cfun,
1882 DECL_RESULT (current_function_decl))
1883 == name;
1885 /* Passing returnslot to return slot is special because
1886 not_returned and escape has same meaning.
1887 However passing arg to return slot is different. If
1888 the callee's return slot is returned it means that
1889 arg is written to itself which is an escape. */
1890 if (!isretslot)
1892 if (!(call_flags & (EAF_NOT_RETURNED | EAF_UNUSED)))
1893 m_lattice[index].merge (~(EAF_NOESCAPE
1894 | EAF_UNUSED));
1895 if (!(call_flags & (EAF_NOT_RETURNED_DIRECTLY
1896 | EAF_UNUSED
1897 | EAF_NOT_RETURNED)))
1898 m_lattice[index].merge (~(EAF_NODIRECTESCAPE
1899 | EAF_NOESCAPE
1900 | EAF_UNUSED));
1901 call_flags = callee_to_caller_flags
1902 (call_flags, false,
1903 m_lattice[index]);
1905 m_lattice[index].merge (call_flags);
1909 if (gimple_call_chain (call)
1910 && (gimple_call_chain (call) == name))
1912 int call_flags = gimple_call_static_chain_flags (call);
1913 if (!ignore_retval
1914 && !(call_flags & (EAF_NOT_RETURNED | EAF_UNUSED)))
1915 merge_call_lhs_flags (call, -1, name, false);
1916 call_flags = callee_to_caller_flags
1917 (call_flags, ignore_stores,
1918 m_lattice[index]);
1919 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
1920 m_lattice[index].merge (call_flags);
1923 /* Process internal functions and right away. */
1924 bool record_ipa = m_ipa && !gimple_call_internal_p (call);
1926 /* Handle all function parameters. */
1927 for (unsigned i = 0;
1928 i < gimple_call_num_args (call)
1929 && m_lattice[index].flags; i++)
1930 /* Name is directly passed to the callee. */
1931 if (gimple_call_arg (call, i) == name)
1933 int call_flags = gimple_call_arg_flags (call, i);
1934 if (!ignore_retval && !(call_flags
1935 & (EAF_NOT_RETURNED | EAF_UNUSED)))
1936 merge_call_lhs_flags
1937 (call, i, name,
1938 call_flags & EAF_NOT_RETURNED_DIRECTLY);
1939 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
1941 call_flags = callee_to_caller_flags
1942 (call_flags, ignore_stores,
1943 m_lattice[index]);
1944 if (!record_ipa)
1945 m_lattice[index].merge (call_flags);
1946 else
1947 m_lattice[index].add_escape_point (call, i,
1948 call_flags, true);
1951 /* Name is dereferenced and passed to a callee. */
1952 else if (memory_access_to (gimple_call_arg (call, i), name))
1954 int call_flags = deref_flags
1955 (gimple_call_arg_flags (call, i), ignore_stores);
1956 if (!ignore_retval
1957 && !(call_flags & (EAF_NOT_RETURNED | EAF_UNUSED)))
1958 merge_call_lhs_flags (call, i, name, true);
1959 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
1960 m_lattice[index].merge_direct_load ();
1961 else
1963 call_flags = callee_to_caller_flags
1964 (call_flags, ignore_stores,
1965 m_lattice[index]);
1966 if (!record_ipa)
1967 m_lattice[index].merge (call_flags);
1968 else
1969 m_lattice[index].add_escape_point (call, i,
1970 call_flags, false);
1975 else if (gimple_assign_load_p (use_stmt))
1977 gassign *assign = as_a <gassign *> (use_stmt);
1978 /* Memory to memory copy. */
1979 if (gimple_store_p (assign))
1981 /* Handle *lhs = *name.
1983 We do not track memory locations, so assume that value
1984 is used arbitrarily. */
1985 if (memory_access_to (gimple_assign_rhs1 (assign), name))
1986 m_lattice[index].merge (deref_flags (0, false));
1987 /* Handle *name = *exp. */
1988 else if (memory_access_to (gimple_assign_lhs (assign), name))
1989 m_lattice[index].merge_direct_store ();
1991 /* Handle lhs = *name. */
1992 else if (memory_access_to (gimple_assign_rhs1 (assign), name))
1994 tree lhs = gimple_assign_lhs (assign);
1995 merge_with_ssa_name (name, lhs, true);
1998 else if (gimple_store_p (use_stmt))
2000 gassign *assign = dyn_cast <gassign *> (use_stmt);
2002 /* Handle *lhs = name. */
2003 if (assign && gimple_assign_rhs1 (assign) == name)
2005 if (dump_file)
2006 fprintf (dump_file, "%*s ssa name saved to memory\n",
2007 m_depth * 4, "");
2008 m_lattice[index].merge (0);
2010 /* Handle *name = exp. */
2011 else if (assign
2012 && memory_access_to (gimple_assign_lhs (assign), name))
2014 /* In general we can not ignore clobbers because they are
2015 barriers for code motion, however after inlining it is safe to
2016 do because local optimization passes do not consider clobbers
2017 from other functions.
2018 Similar logic is in ipa-pure-const.c. */
2019 if (!cfun->after_inlining || !gimple_clobber_p (assign))
2020 m_lattice[index].merge_direct_store ();
2022 /* ASM statements etc. */
2023 else if (!assign)
2025 if (dump_file)
2026 fprintf (dump_file, "%*s Unhandled store\n", m_depth * 4, "");
2027 m_lattice[index].merge (0);
2030 else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
2032 enum tree_code code = gimple_assign_rhs_code (assign);
2034 /* See if operation is a merge as considered by
2035 tree-ssa-structalias.c:find_func_aliases. */
2036 if (!truth_value_p (code)
2037 && code != POINTER_DIFF_EXPR
2038 && (code != POINTER_PLUS_EXPR
2039 || gimple_assign_rhs1 (assign) == name))
2041 tree lhs = gimple_assign_lhs (assign);
2042 merge_with_ssa_name (name, lhs, false);
2045 else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
2047 tree result = gimple_phi_result (phi);
2048 merge_with_ssa_name (name, result, false);
2050 /* Conditions are not considered escape points
2051 by tree-ssa-structalias. */
2052 else if (gimple_code (use_stmt) == GIMPLE_COND)
2054 else
2056 if (dump_file)
2057 fprintf (dump_file, "%*s Unhandled stmt\n", m_depth * 4, "");
2058 m_lattice[index].merge (0);
2061 if (dump_file)
2063 fprintf (dump_file, "%*s current flags of ", m_depth * 4, "");
2064 print_generic_expr (dump_file, name);
2065 m_lattice[index].dump (dump_file, m_depth * 4 + 4);
2068 if (dump_file)
2070 fprintf (dump_file, "%*sflags of ssa name ", m_depth * 4, "");
2071 print_generic_expr (dump_file, name);
2072 m_lattice[index].dump (dump_file, m_depth * 4 + 2);
2074 m_lattice[index].open = false;
2075 m_lattice[index].known = true;
2078 /* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
2079 is dereferenced. */
2081 void
2082 modref_eaf_analysis::merge_with_ssa_name (tree dest, tree src, bool deref)
2084 int index = SSA_NAME_VERSION (dest);
2085 int src_index = SSA_NAME_VERSION (src);
2087 m_depth++;
2088 analyze_ssa_name (src);
2089 m_depth--;
2090 if (deref)
2091 m_lattice[index].merge_deref (m_lattice[src_index], false);
2092 else
2093 m_lattice[index].merge (m_lattice[src_index]);
2096 /* Record escape points of PARM_INDEX according to LATTICE. */
2098 void
2099 modref_eaf_analysis::record_escape_points (tree name, int parm_index, int flags)
2101 modref_lattice &lattice = m_lattice[SSA_NAME_VERSION (name)];
2103 if (lattice.escape_points.length ())
2105 escape_point *ep;
2106 unsigned int ip;
2107 cgraph_node *node = cgraph_node::get (current_function_decl);
2109 gcc_assert (m_ipa);
2110 FOR_EACH_VEC_ELT (lattice.escape_points, ip, ep)
2111 if ((ep->min_flags & flags) != flags)
2113 cgraph_edge *e = node->get_edge (ep->call);
2114 struct escape_entry ee = {parm_index, ep->arg,
2115 ep->min_flags, ep->direct};
2117 escape_summaries->get_create (e)->esc.safe_push (ee);
2122 /* Determine EAF flags for function parameters. */
2124 static void
2125 analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
2126 bool ipa)
2128 unsigned int parm_index = 0;
2129 unsigned int count = 0;
2130 int ecf_flags = flags_from_decl_or_type (current_function_decl);
2131 tree retslot = NULL;
2132 tree static_chain = NULL;
2134 /* For novops functions we have nothing to gain by EAF flags. */
2135 if (ecf_flags & ECF_NOVOPS)
2136 return;
2138 /* If there is return slot, look up its SSA name. */
2139 if (DECL_RESULT (current_function_decl)
2140 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2141 retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
2142 if (cfun->static_chain_decl)
2143 static_chain = ssa_default_def (cfun, cfun->static_chain_decl);
2145 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2146 parm = TREE_CHAIN (parm))
2147 count++;
2149 if (!count && !retslot && !static_chain)
2150 return;
2152 modref_eaf_analysis eaf_analysis (ipa);
2154 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
2155 parm = TREE_CHAIN (parm))
2157 tree name = ssa_default_def (cfun, parm);
2158 if (!name || has_zero_uses (name))
2160 /* We do not track non-SSA parameters,
2161 but we want to track unused gimple_regs. */
2162 if (!is_gimple_reg (parm))
2163 continue;
2164 if (summary)
2166 if (parm_index >= summary->arg_flags.length ())
2167 summary->arg_flags.safe_grow_cleared (count, true);
2168 summary->arg_flags[parm_index] = EAF_UNUSED;
2170 else if (summary_lto)
2172 if (parm_index >= summary_lto->arg_flags.length ())
2173 summary_lto->arg_flags.safe_grow_cleared (count, true);
2174 summary_lto->arg_flags[parm_index] = EAF_UNUSED;
2176 continue;
2178 eaf_analysis.analyze_ssa_name (name);
2179 int flags = eaf_analysis.get_ssa_name_flags (name);
2181 /* Eliminate useless flags so we do not end up storing unnecessary
2182 summaries. */
2184 flags = remove_useless_eaf_flags
2185 (flags, ecf_flags,
2186 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
2188 if (flags)
2190 if (summary)
2192 if (parm_index >= summary->arg_flags.length ())
2193 summary->arg_flags.safe_grow_cleared (count, true);
2194 summary->arg_flags[parm_index] = flags;
2196 else if (summary_lto)
2198 if (parm_index >= summary_lto->arg_flags.length ())
2199 summary_lto->arg_flags.safe_grow_cleared (count, true);
2200 summary_lto->arg_flags[parm_index] = flags;
2202 eaf_analysis.record_escape_points (name, parm_index, flags);
2205 if (retslot)
2207 eaf_analysis.analyze_ssa_name (retslot);
2208 int flags = eaf_analysis.get_ssa_name_flags (retslot);
2210 flags = remove_useless_eaf_flags (flags, ecf_flags, false);
2211 if (flags)
2213 if (summary)
2214 summary->retslot_flags = flags;
2215 if (summary_lto)
2216 summary_lto->retslot_flags = flags;
2217 eaf_analysis.record_escape_points (retslot,
2218 escape_point::retslot_arg, flags);
2221 if (static_chain)
2223 eaf_analysis.analyze_ssa_name (static_chain);
2224 int flags = eaf_analysis.get_ssa_name_flags (static_chain);
2226 flags = remove_useless_eaf_flags (flags, ecf_flags, false);
2227 if (flags)
2229 if (summary)
2230 summary->static_chain_flags = flags;
2231 if (summary_lto)
2232 summary_lto->static_chain_flags = flags;
2233 eaf_analysis.record_escape_points (static_chain,
2234 escape_point::static_chain_arg,
2235 flags);
2240 /* Analyze function F. IPA indicates whether we're running in local mode
2241 (false) or the IPA mode (true). */
2243 static void
2244 analyze_function (function *f, bool ipa)
2246 if (dump_file)
2247 fprintf (dump_file, "modref analyzing '%s' (ipa=%i)%s%s\n",
2248 function_name (f), ipa,
2249 TREE_READONLY (current_function_decl) ? " (const)" : "",
2250 DECL_PURE_P (current_function_decl) ? " (pure)" : "");
2252 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
2253 if (!flag_ipa_modref
2254 || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
2255 return;
2257 /* Compute no-LTO summaries when local optimization is going to happen. */
2258 bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
2259 || (in_lto_p && !flag_wpa
2260 && flag_incremental_link != INCREMENTAL_LINK_LTO));
2261 /* Compute LTO when LTO streaming is going to happen. */
2262 bool lto = ipa && ((flag_lto && !in_lto_p)
2263 || flag_wpa
2264 || flag_incremental_link == INCREMENTAL_LINK_LTO);
2265 cgraph_node *fnode = cgraph_node::get (current_function_decl);
2267 modref_summary *summary = NULL;
2268 modref_summary_lto *summary_lto = NULL;
2270 /* Initialize the summary.
2271 If we run in local mode there is possibly pre-existing summary from
2272 IPA pass. Dump it so it is easy to compare if mod-ref info has
2273 improved. */
2274 if (!ipa)
2276 if (!optimization_summaries)
2277 optimization_summaries = modref_summaries::create_ggc (symtab);
2278 else /* Remove existing summary if we are re-running the pass. */
2280 if (dump_file
2281 && (summary
2282 = optimization_summaries->get (cgraph_node::get (f->decl)))
2283 != NULL
2284 && summary->loads)
2286 fprintf (dump_file, "Past summary:\n");
2287 optimization_summaries->get
2288 (cgraph_node::get (f->decl))->dump (dump_file);
2290 optimization_summaries->remove (cgraph_node::get (f->decl));
2292 summary = optimization_summaries->get_create (cgraph_node::get (f->decl));
2293 gcc_checking_assert (nolto && !lto);
2295 /* In IPA mode we analyze every function precisely once. Assert that. */
2296 else
2298 if (nolto)
2300 if (!summaries)
2301 summaries = modref_summaries::create_ggc (symtab);
2302 else
2303 summaries->remove (cgraph_node::get (f->decl));
2304 summary = summaries->get_create (cgraph_node::get (f->decl));
2306 if (lto)
2308 if (!summaries_lto)
2309 summaries_lto = modref_summaries_lto::create_ggc (symtab);
2310 else
2311 summaries_lto->remove (cgraph_node::get (f->decl));
2312 summary_lto = summaries_lto->get_create (cgraph_node::get (f->decl));
2314 if (!fnspec_summaries)
2315 fnspec_summaries = new fnspec_summaries_t (symtab);
2316 if (!escape_summaries)
2317 escape_summaries = new escape_summaries_t (symtab);
2321 /* Create and initialize summary for F.
2322 Note that summaries may be already allocated from previous
2323 run of the pass. */
2324 if (nolto)
2326 gcc_assert (!summary->loads);
2327 summary->loads = modref_records::create_ggc (param_modref_max_bases,
2328 param_modref_max_refs,
2329 param_modref_max_accesses);
2330 gcc_assert (!summary->stores);
2331 summary->stores = modref_records::create_ggc (param_modref_max_bases,
2332 param_modref_max_refs,
2333 param_modref_max_accesses);
2334 summary->writes_errno = false;
2336 if (lto)
2338 gcc_assert (!summary_lto->loads);
2339 summary_lto->loads = modref_records_lto::create_ggc
2340 (param_modref_max_bases,
2341 param_modref_max_refs,
2342 param_modref_max_accesses);
2343 gcc_assert (!summary_lto->stores);
2344 summary_lto->stores = modref_records_lto::create_ggc
2345 (param_modref_max_bases,
2346 param_modref_max_refs,
2347 param_modref_max_accesses);
2348 summary_lto->writes_errno = false;
2351 analyze_parms (summary, summary_lto, ipa);
2353 int ecf_flags = flags_from_decl_or_type (current_function_decl);
2354 auto_vec <gimple *, 32> recursive_calls;
2356 /* Analyze each statement in each basic block of the function. If the
2357 statement cannot be analyzed (for any reason), the entire function cannot
2358 be analyzed by modref. */
2359 basic_block bb;
2360 FOR_EACH_BB_FN (bb, f)
2362 gimple_stmt_iterator si;
2363 for (si = gsi_start_nondebug_after_labels_bb (bb);
2364 !gsi_end_p (si); gsi_next_nondebug (&si))
2366 if (!analyze_stmt (summary, summary_lto,
2367 gsi_stmt (si), ipa, &recursive_calls)
2368 || ((!summary || !summary->useful_p (ecf_flags, false))
2369 && (!summary_lto
2370 || !summary_lto->useful_p (ecf_flags, false))))
2372 collapse_loads (summary, summary_lto);
2373 collapse_stores (summary, summary_lto);
2374 break;
2379 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2380 This needs to be done after all other side effects are computed. */
2381 if (!ipa)
2383 bool changed = true;
2384 bool first = true;
2385 while (changed)
2387 changed = false;
2388 for (unsigned i = 0; i < recursive_calls.length (); i++)
2390 changed |= merge_call_side_effects
2391 (summary, recursive_calls[i], summary,
2392 ignore_stores_p (current_function_decl,
2393 gimple_call_flags
2394 (recursive_calls[i])),
2395 fnode, !first);
2396 if (!summary->useful_p (ecf_flags, false))
2398 remove_summary (lto, nolto, ipa);
2399 return;
2402 first = false;
2405 if (summary && !summary->useful_p (ecf_flags))
2407 if (!ipa)
2408 optimization_summaries->remove (fnode);
2409 else
2410 summaries->remove (fnode);
2411 summary = NULL;
2413 if (summary_lto && !summary_lto->useful_p (ecf_flags))
2415 summaries_lto->remove (fnode);
2416 summary_lto = NULL;
2418 if (ipa && !summary && !summary_lto)
2419 remove_modref_edge_summaries (fnode);
2421 if (dump_file)
2423 fprintf (dump_file, " - modref done with result: tracked.\n");
2424 if (summary)
2425 summary->dump (dump_file);
2426 if (summary_lto)
2427 summary_lto->dump (dump_file);
2428 dump_modref_edge_summaries (dump_file, fnode, 2);
2432 /* Callback for generate_summary. */
2434 static void
2435 modref_generate (void)
2437 struct cgraph_node *node;
2438 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
2440 function *f = DECL_STRUCT_FUNCTION (node->decl);
2441 if (!f)
2442 continue;
2443 push_cfun (f);
2444 analyze_function (f, true);
2445 pop_cfun ();
2449 } /* ANON namespace. */
2451 /* Called when a new function is inserted to callgraph late. */
2453 void
2454 modref_summaries::insert (struct cgraph_node *node, modref_summary *)
2456 /* Local passes ought to be executed by the pass manager. */
2457 if (this == optimization_summaries)
2459 optimization_summaries->remove (node);
2460 return;
2462 if (!DECL_STRUCT_FUNCTION (node->decl)
2463 || !opt_for_fn (node->decl, flag_ipa_modref))
2465 summaries->remove (node);
2466 return;
2468 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2469 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2470 pop_cfun ();
2473 /* Called when a new function is inserted to callgraph late. */
2475 void
2476 modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
2478 /* We do not support adding new function when IPA information is already
2479 propagated. This is done only by SIMD cloning that is not very
2480 critical. */
2481 if (!DECL_STRUCT_FUNCTION (node->decl)
2482 || !opt_for_fn (node->decl, flag_ipa_modref)
2483 || propagated)
2485 summaries_lto->remove (node);
2486 return;
2488 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2489 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2490 pop_cfun ();
2493 /* Called when new clone is inserted to callgraph late. */
2495 void
2496 modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
2497 modref_summary *src_data,
2498 modref_summary *dst_data)
2500 /* Do not duplicate optimization summaries; we do not handle parameter
2501 transforms on them. */
2502 if (this == optimization_summaries)
2504 optimization_summaries->remove (dst);
2505 return;
2507 dst_data->stores = modref_records::create_ggc
2508 (src_data->stores->max_bases,
2509 src_data->stores->max_refs,
2510 src_data->stores->max_accesses);
2511 dst_data->stores->copy_from (src_data->stores);
2512 dst_data->loads = modref_records::create_ggc
2513 (src_data->loads->max_bases,
2514 src_data->loads->max_refs,
2515 src_data->loads->max_accesses);
2516 dst_data->loads->copy_from (src_data->loads);
2517 dst_data->writes_errno = src_data->writes_errno;
2518 if (src_data->arg_flags.length ())
2519 dst_data->arg_flags = src_data->arg_flags.copy ();
2520 dst_data->retslot_flags = src_data->retslot_flags;
2521 dst_data->static_chain_flags = src_data->static_chain_flags;
2524 /* Called when new clone is inserted to callgraph late. */
2526 void
2527 modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
2528 modref_summary_lto *src_data,
2529 modref_summary_lto *dst_data)
2531 /* Be sure that no further cloning happens after ipa-modref. If it does
2532 we will need to update signatures for possible param changes. */
2533 gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
2534 dst_data->stores = modref_records_lto::create_ggc
2535 (src_data->stores->max_bases,
2536 src_data->stores->max_refs,
2537 src_data->stores->max_accesses);
2538 dst_data->stores->copy_from (src_data->stores);
2539 dst_data->loads = modref_records_lto::create_ggc
2540 (src_data->loads->max_bases,
2541 src_data->loads->max_refs,
2542 src_data->loads->max_accesses);
2543 dst_data->loads->copy_from (src_data->loads);
2544 dst_data->writes_errno = src_data->writes_errno;
2545 if (src_data->arg_flags.length ())
2546 dst_data->arg_flags = src_data->arg_flags.copy ();
2547 dst_data->retslot_flags = src_data->retslot_flags;
2548 dst_data->static_chain_flags = src_data->static_chain_flags;
2551 namespace
2553 /* Definition of the modref pass on GIMPLE. */
2554 const pass_data pass_data_modref = {
2555 GIMPLE_PASS,
2556 "modref",
2557 OPTGROUP_IPA,
2558 TV_TREE_MODREF,
2559 (PROP_cfg | PROP_ssa),
2566 class pass_modref : public gimple_opt_pass
2568 public:
2569 pass_modref (gcc::context *ctxt)
2570 : gimple_opt_pass (pass_data_modref, ctxt) {}
2572 /* opt_pass methods: */
2573 opt_pass *clone ()
2575 return new pass_modref (m_ctxt);
2577 virtual bool gate (function *)
2579 return flag_ipa_modref;
2581 virtual unsigned int execute (function *);
2584 /* Encode TT to the output block OB using the summary streaming API. */
2586 static void
2587 write_modref_records (modref_records_lto *tt, struct output_block *ob)
2589 streamer_write_uhwi (ob, tt->max_bases);
2590 streamer_write_uhwi (ob, tt->max_refs);
2591 streamer_write_uhwi (ob, tt->max_accesses);
2593 streamer_write_uhwi (ob, tt->every_base);
2594 streamer_write_uhwi (ob, vec_safe_length (tt->bases));
2595 size_t i;
2596 modref_base_node <tree> *base_node;
2597 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, base_node)
2599 stream_write_tree (ob, base_node->base, true);
2601 streamer_write_uhwi (ob, base_node->every_ref);
2602 streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
2604 size_t j;
2605 modref_ref_node <tree> *ref_node;
2606 FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
2608 stream_write_tree (ob, ref_node->ref, true);
2609 streamer_write_uhwi (ob, ref_node->every_access);
2610 streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
2612 size_t k;
2613 modref_access_node *access_node;
2614 FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
2616 streamer_write_hwi (ob, access_node->parm_index);
2617 if (access_node->parm_index != -1)
2619 streamer_write_uhwi (ob, access_node->parm_offset_known);
2620 if (access_node->parm_offset_known)
2622 streamer_write_poly_int64 (ob, access_node->parm_offset);
2623 streamer_write_poly_int64 (ob, access_node->offset);
2624 streamer_write_poly_int64 (ob, access_node->size);
2625 streamer_write_poly_int64 (ob, access_node->max_size);
2633 /* Read a modref_tree from the input block IB using the data from DATA_IN.
2634 This assumes that the tree was encoded using write_modref_tree.
2635 Either nolto_ret or lto_ret is initialized by the tree depending whether
2636 LTO streaming is expected or not. */
2638 static void
2639 read_modref_records (lto_input_block *ib, struct data_in *data_in,
2640 modref_records **nolto_ret,
2641 modref_records_lto **lto_ret)
2643 size_t max_bases = streamer_read_uhwi (ib);
2644 size_t max_refs = streamer_read_uhwi (ib);
2645 size_t max_accesses = streamer_read_uhwi (ib);
2647 if (lto_ret)
2648 *lto_ret = modref_records_lto::create_ggc (max_bases, max_refs,
2649 max_accesses);
2650 if (nolto_ret)
2651 *nolto_ret = modref_records::create_ggc (max_bases, max_refs,
2652 max_accesses);
2653 gcc_checking_assert (lto_ret || nolto_ret);
2655 size_t every_base = streamer_read_uhwi (ib);
2656 size_t nbase = streamer_read_uhwi (ib);
2658 gcc_assert (!every_base || nbase == 0);
2659 if (every_base)
2661 if (nolto_ret)
2662 (*nolto_ret)->collapse ();
2663 if (lto_ret)
2664 (*lto_ret)->collapse ();
2666 for (size_t i = 0; i < nbase; i++)
2668 tree base_tree = stream_read_tree (ib, data_in);
2669 modref_base_node <alias_set_type> *nolto_base_node = NULL;
2670 modref_base_node <tree> *lto_base_node = NULL;
2672 /* At stream in time we have LTO alias info. Check if we streamed in
2673 something obviously unnecessary. Do not glob types by alias sets;
2674 it is not 100% clear that ltrans types will get merged same way.
2675 Types may get refined based on ODR type conflicts. */
2676 if (base_tree && !get_alias_set (base_tree))
2678 if (dump_file)
2680 fprintf (dump_file, "Streamed in alias set 0 type ");
2681 print_generic_expr (dump_file, base_tree);
2682 fprintf (dump_file, "\n");
2684 base_tree = NULL;
2687 if (nolto_ret)
2688 nolto_base_node = (*nolto_ret)->insert_base (base_tree
2689 ? get_alias_set (base_tree)
2690 : 0, 0);
2691 if (lto_ret)
2692 lto_base_node = (*lto_ret)->insert_base (base_tree, 0);
2693 size_t every_ref = streamer_read_uhwi (ib);
2694 size_t nref = streamer_read_uhwi (ib);
2696 gcc_assert (!every_ref || nref == 0);
2697 if (every_ref)
2699 if (nolto_base_node)
2700 nolto_base_node->collapse ();
2701 if (lto_base_node)
2702 lto_base_node->collapse ();
2704 for (size_t j = 0; j < nref; j++)
2706 tree ref_tree = stream_read_tree (ib, data_in);
2708 if (ref_tree && !get_alias_set (ref_tree))
2710 if (dump_file)
2712 fprintf (dump_file, "Streamed in alias set 0 type ");
2713 print_generic_expr (dump_file, ref_tree);
2714 fprintf (dump_file, "\n");
2716 ref_tree = NULL;
2719 modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
2720 modref_ref_node <tree> *lto_ref_node = NULL;
2722 if (nolto_base_node)
2723 nolto_ref_node
2724 = nolto_base_node->insert_ref (ref_tree
2725 ? get_alias_set (ref_tree) : 0,
2726 max_refs);
2727 if (lto_base_node)
2728 lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
2730 size_t every_access = streamer_read_uhwi (ib);
2731 size_t naccesses = streamer_read_uhwi (ib);
2733 if (nolto_ref_node)
2734 nolto_ref_node->every_access = every_access;
2735 if (lto_ref_node)
2736 lto_ref_node->every_access = every_access;
2738 for (size_t k = 0; k < naccesses; k++)
2740 int parm_index = streamer_read_hwi (ib);
2741 bool parm_offset_known = false;
2742 poly_int64 parm_offset = 0;
2743 poly_int64 offset = 0;
2744 poly_int64 size = -1;
2745 poly_int64 max_size = -1;
2747 if (parm_index != -1)
2749 parm_offset_known = streamer_read_uhwi (ib);
2750 if (parm_offset_known)
2752 parm_offset = streamer_read_poly_int64 (ib);
2753 offset = streamer_read_poly_int64 (ib);
2754 size = streamer_read_poly_int64 (ib);
2755 max_size = streamer_read_poly_int64 (ib);
2758 modref_access_node a = {offset, size, max_size, parm_offset,
2759 parm_index, parm_offset_known, false};
2760 if (nolto_ref_node)
2761 nolto_ref_node->insert_access (a, max_accesses, false);
2762 if (lto_ref_node)
2763 lto_ref_node->insert_access (a, max_accesses, false);
2767 if (lto_ret)
2768 (*lto_ret)->cleanup ();
2769 if (nolto_ret)
2770 (*nolto_ret)->cleanup ();
2773 /* Write ESUM to BP. */
2775 static void
2776 modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
2778 if (!esum)
2780 bp_pack_var_len_unsigned (bp, 0);
2781 return;
2783 bp_pack_var_len_unsigned (bp, esum->esc.length ());
2784 unsigned int i;
2785 escape_entry *ee;
2786 FOR_EACH_VEC_ELT (esum->esc, i, ee)
2788 bp_pack_var_len_int (bp, ee->parm_index);
2789 bp_pack_var_len_unsigned (bp, ee->arg);
2790 bp_pack_var_len_unsigned (bp, ee->min_flags);
2791 bp_pack_value (bp, ee->direct, 1);
2795 /* Read escape summary for E from BP. */
2797 static void
2798 modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
2800 unsigned int n = bp_unpack_var_len_unsigned (bp);
2801 if (!n)
2802 return;
2803 escape_summary *esum = escape_summaries->get_create (e);
2804 esum->esc.reserve_exact (n);
2805 for (unsigned int i = 0; i < n; i++)
2807 escape_entry ee;
2808 ee.parm_index = bp_unpack_var_len_int (bp);
2809 ee.arg = bp_unpack_var_len_unsigned (bp);
2810 ee.min_flags = bp_unpack_var_len_unsigned (bp);
2811 ee.direct = bp_unpack_value (bp, 1);
2812 esum->esc.quick_push (ee);
2816 /* Callback for write_summary. */
2818 static void
2819 modref_write ()
2821 struct output_block *ob = create_output_block (LTO_section_ipa_modref);
2822 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
2823 unsigned int count = 0;
2824 int i;
2826 if (!summaries_lto)
2828 streamer_write_uhwi (ob, 0);
2829 streamer_write_char_stream (ob->main_stream, 0);
2830 produce_asm (ob, NULL);
2831 destroy_output_block (ob);
2832 return;
2835 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
2837 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
2838 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
2839 modref_summary_lto *r;
2841 if (cnode && cnode->definition && !cnode->alias
2842 && (r = summaries_lto->get (cnode))
2843 && r->useful_p (flags_from_decl_or_type (cnode->decl)))
2844 count++;
2846 streamer_write_uhwi (ob, count);
2848 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
2850 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
2851 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
2853 if (cnode && cnode->definition && !cnode->alias)
2855 modref_summary_lto *r = summaries_lto->get (cnode);
2857 if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
2858 continue;
2860 streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
2862 streamer_write_uhwi (ob, r->arg_flags.length ());
2863 for (unsigned int i = 0; i < r->arg_flags.length (); i++)
2864 streamer_write_uhwi (ob, r->arg_flags[i]);
2865 streamer_write_uhwi (ob, r->retslot_flags);
2866 streamer_write_uhwi (ob, r->static_chain_flags);
2868 write_modref_records (r->loads, ob);
2869 write_modref_records (r->stores, ob);
2871 struct bitpack_d bp = bitpack_create (ob->main_stream);
2872 bp_pack_value (&bp, r->writes_errno, 1);
2873 if (!flag_wpa)
2875 for (cgraph_edge *e = cnode->indirect_calls;
2876 e; e = e->next_callee)
2878 class fnspec_summary *sum = fnspec_summaries->get (e);
2879 bp_pack_value (&bp, sum != NULL, 1);
2880 if (sum)
2881 bp_pack_string (ob, &bp, sum->fnspec, true);
2882 class escape_summary *esum = escape_summaries->get (e);
2883 modref_write_escape_summary (&bp,esum);
2885 for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
2887 class fnspec_summary *sum = fnspec_summaries->get (e);
2888 bp_pack_value (&bp, sum != NULL, 1);
2889 if (sum)
2890 bp_pack_string (ob, &bp, sum->fnspec, true);
2891 class escape_summary *esum = escape_summaries->get (e);
2892 modref_write_escape_summary (&bp,esum);
2895 streamer_write_bitpack (&bp);
2898 streamer_write_char_stream (ob->main_stream, 0);
2899 produce_asm (ob, NULL);
2900 destroy_output_block (ob);
2903 static void
2904 read_section (struct lto_file_decl_data *file_data, const char *data,
2905 size_t len)
2907 const struct lto_function_header *header
2908 = (const struct lto_function_header *) data;
2909 const int cfg_offset = sizeof (struct lto_function_header);
2910 const int main_offset = cfg_offset + header->cfg_size;
2911 const int string_offset = main_offset + header->main_size;
2912 struct data_in *data_in;
2913 unsigned int i;
2914 unsigned int f_count;
2916 lto_input_block ib ((const char *) data + main_offset, header->main_size,
2917 file_data->mode_table);
2919 data_in
2920 = lto_data_in_create (file_data, (const char *) data + string_offset,
2921 header->string_size, vNULL);
2922 f_count = streamer_read_uhwi (&ib);
2923 for (i = 0; i < f_count; i++)
2925 struct cgraph_node *node;
2926 lto_symtab_encoder_t encoder;
2928 unsigned int index = streamer_read_uhwi (&ib);
2929 encoder = file_data->symtab_node_encoder;
2930 node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
2931 index));
2933 modref_summary *modref_sum = summaries
2934 ? summaries->get_create (node) : NULL;
2935 modref_summary_lto *modref_sum_lto = summaries_lto
2936 ? summaries_lto->get_create (node)
2937 : NULL;
2938 if (optimization_summaries)
2939 modref_sum = optimization_summaries->get_create (node);
2941 if (modref_sum)
2942 modref_sum->writes_errno = false;
2943 if (modref_sum_lto)
2944 modref_sum_lto->writes_errno = false;
2946 gcc_assert (!modref_sum || (!modref_sum->loads
2947 && !modref_sum->stores));
2948 gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
2949 && !modref_sum_lto->stores));
2950 unsigned int args = streamer_read_uhwi (&ib);
2951 if (args && modref_sum)
2952 modref_sum->arg_flags.reserve_exact (args);
2953 if (args && modref_sum_lto)
2954 modref_sum_lto->arg_flags.reserve_exact (args);
2955 for (unsigned int i = 0; i < args; i++)
2957 eaf_flags_t flags = streamer_read_uhwi (&ib);
2958 if (modref_sum)
2959 modref_sum->arg_flags.quick_push (flags);
2960 if (modref_sum_lto)
2961 modref_sum_lto->arg_flags.quick_push (flags);
2963 eaf_flags_t flags = streamer_read_uhwi (&ib);
2964 if (modref_sum)
2965 modref_sum->retslot_flags = flags;
2966 if (modref_sum_lto)
2967 modref_sum_lto->retslot_flags = flags;
2969 flags = streamer_read_uhwi (&ib);
2970 if (modref_sum)
2971 modref_sum->static_chain_flags = flags;
2972 if (modref_sum_lto)
2973 modref_sum_lto->static_chain_flags = flags;
2975 read_modref_records (&ib, data_in,
2976 modref_sum ? &modref_sum->loads : NULL,
2977 modref_sum_lto ? &modref_sum_lto->loads : NULL);
2978 read_modref_records (&ib, data_in,
2979 modref_sum ? &modref_sum->stores : NULL,
2980 modref_sum_lto ? &modref_sum_lto->stores : NULL);
2981 struct bitpack_d bp = streamer_read_bitpack (&ib);
2982 if (bp_unpack_value (&bp, 1))
2984 if (modref_sum)
2985 modref_sum->writes_errno = true;
2986 if (modref_sum_lto)
2987 modref_sum_lto->writes_errno = true;
2989 if (!flag_ltrans)
2991 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
2993 if (bp_unpack_value (&bp, 1))
2995 class fnspec_summary *sum = fnspec_summaries->get_create (e);
2996 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
2998 modref_read_escape_summary (&bp, e);
3000 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3002 if (bp_unpack_value (&bp, 1))
3004 class fnspec_summary *sum = fnspec_summaries->get_create (e);
3005 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3007 modref_read_escape_summary (&bp, e);
3010 if (dump_file)
3012 fprintf (dump_file, "Read modref for %s\n",
3013 node->dump_name ());
3014 if (modref_sum)
3015 modref_sum->dump (dump_file);
3016 if (modref_sum_lto)
3017 modref_sum_lto->dump (dump_file);
3018 dump_modref_edge_summaries (dump_file, node, 4);
3022 lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
3023 len);
3024 lto_data_in_delete (data_in);
3027 /* Callback for read_summary. */
3029 static void
3030 modref_read (void)
3032 struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
3033 struct lto_file_decl_data *file_data;
3034 unsigned int j = 0;
3036 gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
3037 if (flag_ltrans)
3038 optimization_summaries = modref_summaries::create_ggc (symtab);
3039 else
3041 if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
3042 summaries_lto = modref_summaries_lto::create_ggc (symtab);
3043 if (!flag_wpa
3044 || (flag_incremental_link == INCREMENTAL_LINK_LTO
3045 && flag_fat_lto_objects))
3046 summaries = modref_summaries::create_ggc (symtab);
3047 if (!fnspec_summaries)
3048 fnspec_summaries = new fnspec_summaries_t (symtab);
3049 if (!escape_summaries)
3050 escape_summaries = new escape_summaries_t (symtab);
3053 while ((file_data = file_data_vec[j++]))
3055 size_t len;
3056 const char *data = lto_get_summary_section_data (file_data,
3057 LTO_section_ipa_modref,
3058 &len);
3059 if (data)
3060 read_section (file_data, data, len);
3061 else
3062 /* Fatal error here. We do not want to support compiling ltrans units
3063 with different version of compiler or different flags than the WPA
3064 unit, so this should never happen. */
3065 fatal_error (input_location,
3066 "IPA modref summary is missing in input file");
3070 /* Recompute arg_flags for param adjustments in INFO. */
3072 static void
3073 remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
3075 auto_vec<eaf_flags_t> old = arg_flags.copy ();
3076 int max = -1;
3077 size_t i;
3078 ipa_adjusted_param *p;
3080 arg_flags.release ();
3082 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
3084 int o = info->param_adjustments->get_original_index (i);
3085 if (o >= 0 && (int)old.length () > o && old[o])
3086 max = i;
3088 if (max >= 0)
3089 arg_flags.safe_grow_cleared (max + 1, true);
3090 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
3092 int o = info->param_adjustments->get_original_index (i);
3093 if (o >= 0 && (int)old.length () > o && old[o])
3094 arg_flags[i] = old[o];
3098 /* If signature changed, update the summary. */
3100 static void
3101 update_signature (struct cgraph_node *node)
3103 clone_info *info = clone_info::get (node);
3104 if (!info || !info->param_adjustments)
3105 return;
3107 modref_summary *r = optimization_summaries
3108 ? optimization_summaries->get (node) : NULL;
3109 modref_summary_lto *r_lto = summaries_lto
3110 ? summaries_lto->get (node) : NULL;
3111 if (!r && !r_lto)
3112 return;
3113 if (dump_file)
3115 fprintf (dump_file, "Updating summary for %s from:\n",
3116 node->dump_name ());
3117 if (r)
3118 r->dump (dump_file);
3119 if (r_lto)
3120 r_lto->dump (dump_file);
3123 size_t i, max = 0;
3124 ipa_adjusted_param *p;
3126 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
3128 int idx = info->param_adjustments->get_original_index (i);
3129 if (idx > (int)max)
3130 max = idx;
3133 auto_vec <int, 32> map;
3135 map.reserve (max + 1);
3136 for (i = 0; i <= max; i++)
3137 map.quick_push (-1);
3138 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
3140 int idx = info->param_adjustments->get_original_index (i);
3141 if (idx >= 0)
3142 map[idx] = i;
3144 if (r)
3146 r->loads->remap_params (&map);
3147 r->stores->remap_params (&map);
3148 if (r->arg_flags.length ())
3149 remap_arg_flags (r->arg_flags, info);
3151 if (r_lto)
3153 r_lto->loads->remap_params (&map);
3154 r_lto->stores->remap_params (&map);
3155 if (r_lto->arg_flags.length ())
3156 remap_arg_flags (r_lto->arg_flags, info);
3158 if (dump_file)
3160 fprintf (dump_file, "to:\n");
3161 if (r)
3162 r->dump (dump_file);
3163 if (r_lto)
3164 r_lto->dump (dump_file);
3166 return;
3169 /* Definition of the modref IPA pass. */
3170 const pass_data pass_data_ipa_modref =
3172 IPA_PASS, /* type */
3173 "modref", /* name */
3174 OPTGROUP_IPA, /* optinfo_flags */
3175 TV_IPA_MODREF, /* tv_id */
3176 0, /* properties_required */
3177 0, /* properties_provided */
3178 0, /* properties_destroyed */
3179 0, /* todo_flags_start */
3180 ( TODO_dump_symtab ), /* todo_flags_finish */
3183 class pass_ipa_modref : public ipa_opt_pass_d
3185 public:
3186 pass_ipa_modref (gcc::context *ctxt)
3187 : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
3188 modref_generate, /* generate_summary */
3189 modref_write, /* write_summary */
3190 modref_read, /* read_summary */
3191 modref_write, /* write_optimization_summary */
3192 modref_read, /* read_optimization_summary */
3193 NULL, /* stmt_fixup */
3194 0, /* function_transform_todo_flags_start */
3195 NULL, /* function_transform */
3196 NULL) /* variable_transform */
3199 /* opt_pass methods: */
3200 opt_pass *clone () { return new pass_ipa_modref (m_ctxt); }
3201 virtual bool gate (function *)
3203 return true;
3205 virtual unsigned int execute (function *);
3211 unsigned int pass_modref::execute (function *f)
3213 analyze_function (f, false);
3214 return 0;
3217 gimple_opt_pass *
3218 make_pass_modref (gcc::context *ctxt)
3220 return new pass_modref (ctxt);
3223 ipa_opt_pass_d *
3224 make_pass_ipa_modref (gcc::context *ctxt)
3226 return new pass_ipa_modref (ctxt);
3229 namespace {
3231 /* Skip edges from and to nodes without ipa_pure_const enabled.
3232 Ignore not available symbols. */
3234 static bool
3235 ignore_edge (struct cgraph_edge *e)
3237 /* We merge summaries of inline clones into summaries of functions they
3238 are inlined to. For that reason the complete function bodies must
3239 act as unit. */
3240 if (!e->inline_failed)
3241 return false;
3242 enum availability avail;
3243 cgraph_node *callee = e->callee->function_or_virtual_thunk_symbol
3244 (&avail, e->caller);
3246 return (avail <= AVAIL_INTERPOSABLE
3247 || ((!optimization_summaries || !optimization_summaries->get (callee))
3248 && (!summaries_lto || !summaries_lto->get (callee)))
3249 || flags_from_decl_or_type (e->callee->decl)
3250 & (ECF_CONST | ECF_NOVOPS));
3253 /* Compute parm_map for CALLEE_EDGE. */
3255 static bool
3256 compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
3258 class ipa_edge_args *args;
3259 if (ipa_node_params_sum
3260 && !callee_edge->call_stmt_cannot_inline_p
3261 && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
3263 int i, count = ipa_get_cs_argument_count (args);
3264 class ipa_node_params *caller_parms_info, *callee_pi;
3265 class ipa_call_summary *es
3266 = ipa_call_summaries->get (callee_edge);
3267 cgraph_node *callee
3268 = callee_edge->callee->function_or_virtual_thunk_symbol
3269 (NULL, callee_edge->caller);
3271 caller_parms_info
3272 = ipa_node_params_sum->get (callee_edge->caller->inlined_to
3273 ? callee_edge->caller->inlined_to
3274 : callee_edge->caller);
3275 callee_pi = ipa_node_params_sum->get (callee);
3277 (*parm_map).safe_grow_cleared (count, true);
3279 for (i = 0; i < count; i++)
3281 if (es && es->param[i].points_to_local_or_readonly_memory)
3283 (*parm_map)[i].parm_index = -2;
3284 continue;
3287 struct ipa_jump_func *jf
3288 = ipa_get_ith_jump_func (args, i);
3289 if (jf && callee_pi)
3291 tree cst = ipa_value_from_jfunc (caller_parms_info,
3293 ipa_get_type
3294 (callee_pi, i));
3295 if (cst && points_to_local_or_readonly_memory_p (cst))
3297 (*parm_map)[i].parm_index = -2;
3298 continue;
3301 if (jf && jf->type == IPA_JF_PASS_THROUGH)
3303 (*parm_map)[i].parm_index
3304 = ipa_get_jf_pass_through_formal_id (jf);
3305 if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
3307 (*parm_map)[i].parm_offset_known = true;
3308 (*parm_map)[i].parm_offset = 0;
3310 else if (ipa_get_jf_pass_through_operation (jf)
3311 == POINTER_PLUS_EXPR
3312 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
3313 &(*parm_map)[i].parm_offset))
3314 (*parm_map)[i].parm_offset_known = true;
3315 else
3316 (*parm_map)[i].parm_offset_known = false;
3317 continue;
3319 if (jf && jf->type == IPA_JF_ANCESTOR)
3321 (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
3322 (*parm_map)[i].parm_offset_known = true;
3323 gcc_checking_assert
3324 (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
3325 (*parm_map)[i].parm_offset
3326 = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
3328 else
3329 (*parm_map)[i].parm_index = -1;
3331 if (dump_file)
3333 fprintf (dump_file, " Parm map: ");
3334 for (i = 0; i < count; i++)
3335 fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
3336 fprintf (dump_file, "\n");
3338 return true;
3340 return false;
3343 /* Map used to translate escape infos. */
3345 struct escape_map
3347 int parm_index;
3348 bool direct;
3351 /* Update escape map for E. */
3353 static void
3354 update_escape_summary_1 (cgraph_edge *e,
3355 vec <vec <escape_map>> &map,
3356 bool ignore_stores)
3358 escape_summary *sum = escape_summaries->get (e);
3359 if (!sum)
3360 return;
3361 auto_vec <escape_entry> old = sum->esc.copy ();
3362 sum->esc.release ();
3364 unsigned int i;
3365 escape_entry *ee;
3366 FOR_EACH_VEC_ELT (old, i, ee)
3368 unsigned int j;
3369 struct escape_map *em;
3370 /* TODO: We do not have jump functions for return slots, so we
3371 never propagate them to outer function. */
3372 if (ee->parm_index >= (int)map.length ()
3373 || ee->parm_index < 0)
3374 continue;
3375 FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
3377 int min_flags = ee->min_flags;
3378 if (ee->direct && !em->direct)
3379 min_flags = deref_flags (min_flags, ignore_stores);
3380 struct escape_entry entry = {em->parm_index, ee->arg,
3381 ee->min_flags,
3382 ee->direct & em->direct};
3383 sum->esc.safe_push (entry);
3386 if (!sum->esc.length ())
3387 escape_summaries->remove (e);
3390 /* Update escape map fo NODE. */
3392 static void
3393 update_escape_summary (cgraph_node *node,
3394 vec <vec <escape_map>> &map,
3395 bool ignore_stores)
3397 if (!escape_summaries)
3398 return;
3399 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
3400 update_escape_summary_1 (e, map, ignore_stores);
3401 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3403 if (!e->inline_failed)
3404 update_escape_summary (e->callee, map, ignore_stores);
3405 else
3406 update_escape_summary_1 (e, map, ignore_stores);
3410 /* Get parameter type from DECL. This is only safe for special cases
3411 like builtins we create fnspec for because the type match is checked
3412 at fnspec creation time. */
3414 static tree
3415 get_parm_type (tree decl, unsigned int i)
3417 tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
3419 for (unsigned int p = 0; p < i; p++)
3420 t = TREE_CHAIN (t);
3421 return TREE_VALUE (t);
3424 /* Return access mode for argument I of call E with FNSPEC. */
3426 static modref_access_node
3427 get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
3428 unsigned int i, modref_parm_map &map)
3430 tree size = NULL_TREE;
3431 unsigned int size_arg;
3433 if (!fnspec.arg_specified_p (i))
3435 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
3437 cgraph_node *node = e->caller->inlined_to
3438 ? e->caller->inlined_to : e->caller;
3439 ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
3440 ipa_edge_args *args = ipa_edge_args_sum->get (e);
3441 struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
3443 if (jf)
3444 size = ipa_value_from_jfunc (caller_parms_info, jf,
3445 get_parm_type (e->callee->decl, size_arg));
3447 else if (fnspec.arg_access_size_given_by_type_p (i))
3448 size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
3449 modref_access_node a = {0, -1, -1,
3450 map.parm_offset, map.parm_index,
3451 map.parm_offset_known, 0};
3452 poly_int64 size_hwi;
3453 if (size
3454 && poly_int_tree_p (size, &size_hwi)
3455 && coeffs_in_range_p (size_hwi, 0,
3456 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
3458 a.size = -1;
3459 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
3461 return a;
3464 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
3465 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
3467 static bool
3468 propagate_unknown_call (cgraph_node *node,
3469 cgraph_edge *e, int ecf_flags,
3470 modref_summary *cur_summary,
3471 modref_summary_lto *cur_summary_lto)
3473 bool changed = false;
3474 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
3475 auto_vec <modref_parm_map, 32> parm_map;
3476 if (fnspec_sum
3477 && compute_parm_map (e, &parm_map))
3479 attr_fnspec fnspec (fnspec_sum->fnspec);
3481 gcc_checking_assert (fnspec.known_p ());
3482 if (fnspec.global_memory_read_p ())
3483 collapse_loads (cur_summary, cur_summary_lto);
3484 else
3486 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
3487 for (unsigned i = 0; i < parm_map.length () && t;
3488 i++, t = TREE_CHAIN (t))
3489 if (!POINTER_TYPE_P (TREE_VALUE (t)))
3491 else if (!fnspec.arg_specified_p (i)
3492 || fnspec.arg_maybe_read_p (i))
3494 modref_parm_map map = parm_map[i];
3495 if (map.parm_index == -2)
3496 continue;
3497 if (map.parm_index == -1)
3499 collapse_loads (cur_summary, cur_summary_lto);
3500 break;
3502 if (cur_summary)
3503 changed |= cur_summary->loads->insert
3504 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
3505 if (cur_summary_lto)
3506 changed |= cur_summary_lto->loads->insert
3507 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
3510 if (ignore_stores_p (node->decl, ecf_flags))
3512 else if (fnspec.global_memory_written_p ())
3513 collapse_stores (cur_summary, cur_summary_lto);
3514 else
3516 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
3517 for (unsigned i = 0; i < parm_map.length () && t;
3518 i++, t = TREE_CHAIN (t))
3519 if (!POINTER_TYPE_P (TREE_VALUE (t)))
3521 else if (!fnspec.arg_specified_p (i)
3522 || fnspec.arg_maybe_written_p (i))
3524 modref_parm_map map = parm_map[i];
3525 if (map.parm_index == -2)
3526 continue;
3527 if (map.parm_index == -1)
3529 collapse_stores (cur_summary, cur_summary_lto);
3530 break;
3532 if (cur_summary)
3533 changed |= cur_summary->stores->insert
3534 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
3535 if (cur_summary_lto)
3536 changed |= cur_summary_lto->stores->insert
3537 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
3540 if (fnspec.errno_maybe_written_p () && flag_errno_math)
3542 if (cur_summary && !cur_summary->writes_errno)
3544 cur_summary->writes_errno = true;
3545 changed = true;
3547 if (cur_summary_lto && !cur_summary_lto->writes_errno)
3549 cur_summary_lto->writes_errno = true;
3550 changed = true;
3553 return changed;
3555 if (dump_file)
3556 fprintf (dump_file, " collapsing loads\n");
3557 changed |= collapse_loads (cur_summary, cur_summary_lto);
3558 if (!ignore_stores_p (node->decl, ecf_flags))
3560 if (dump_file)
3561 fprintf (dump_file, " collapsing stores\n");
3562 changed |= collapse_stores (cur_summary, cur_summary_lto);
3564 return changed;
3567 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
3568 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
3570 static void
3571 remove_useless_summaries (cgraph_node *node,
3572 modref_summary **cur_summary_ptr,
3573 modref_summary_lto **cur_summary_lto_ptr,
3574 int ecf_flags)
3576 if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
3578 optimization_summaries->remove (node);
3579 *cur_summary_ptr = NULL;
3581 if (*cur_summary_lto_ptr
3582 && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
3584 summaries_lto->remove (node);
3585 *cur_summary_lto_ptr = NULL;
3589 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3590 and propagate loads/stores. */
3592 static void
3593 modref_propagate_in_scc (cgraph_node *component_node)
3595 bool changed = true;
3596 bool first = true;
3597 int iteration = 0;
3599 while (changed)
3601 changed = false;
3602 for (struct cgraph_node *cur = component_node; cur;
3603 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3605 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
3606 modref_summary *cur_summary = optimization_summaries
3607 ? optimization_summaries->get (node)
3608 : NULL;
3609 modref_summary_lto *cur_summary_lto = summaries_lto
3610 ? summaries_lto->get (node)
3611 : NULL;
3613 if (!cur_summary && !cur_summary_lto)
3614 continue;
3616 int cur_ecf_flags = flags_from_decl_or_type (node->decl);
3618 if (dump_file)
3619 fprintf (dump_file, " Processing %s%s%s\n",
3620 cur->dump_name (),
3621 TREE_READONLY (cur->decl) ? " (const)" : "",
3622 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3624 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
3626 if (e->indirect_info->ecf_flags & (ECF_CONST | ECF_NOVOPS))
3627 continue;
3628 if (dump_file)
3629 fprintf (dump_file, " Indirect call"
3630 "collapsing loads\n");
3631 if (propagate_unknown_call
3632 (node, e, e->indirect_info->ecf_flags,
3633 cur_summary, cur_summary_lto))
3635 changed = true;
3636 remove_useless_summaries (node, &cur_summary,
3637 &cur_summary_lto,
3638 cur_ecf_flags);
3639 if (!cur_summary && !cur_summary_lto)
3640 break;
3644 if (!cur_summary && !cur_summary_lto)
3645 continue;
3647 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
3648 callee_edge = callee_edge->next_callee)
3650 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
3651 modref_summary *callee_summary = NULL;
3652 modref_summary_lto *callee_summary_lto = NULL;
3653 struct cgraph_node *callee;
3655 if (flags & (ECF_CONST | ECF_NOVOPS)
3656 || !callee_edge->inline_failed)
3657 continue;
3659 /* Get the callee and its summary. */
3660 enum availability avail;
3661 callee = callee_edge->callee->function_or_virtual_thunk_symbol
3662 (&avail, cur);
3664 /* It is not necessary to re-process calls outside of the
3665 SCC component. */
3666 if (iteration > 0
3667 && (!callee->aux
3668 || ((struct ipa_dfs_info *)cur->aux)->scc_no
3669 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
3670 continue;
3672 if (dump_file)
3673 fprintf (dump_file, " Call to %s\n",
3674 callee_edge->callee->dump_name ());
3676 bool ignore_stores = ignore_stores_p (cur->decl, flags);
3678 if (avail <= AVAIL_INTERPOSABLE)
3680 if (dump_file)
3681 fprintf (dump_file, " Call target interposable"
3682 " or not available\n");
3683 changed |= propagate_unknown_call
3684 (node, callee_edge, flags,
3685 cur_summary, cur_summary_lto);
3686 if (!cur_summary && !cur_summary_lto)
3687 break;
3688 continue;
3691 /* We don't know anything about CALLEE, hence we cannot tell
3692 anything about the entire component. */
3694 if (cur_summary
3695 && !(callee_summary = optimization_summaries->get (callee)))
3697 if (dump_file)
3698 fprintf (dump_file, " No call target summary\n");
3699 changed |= propagate_unknown_call
3700 (node, callee_edge, flags,
3701 cur_summary, NULL);
3703 if (cur_summary_lto
3704 && !(callee_summary_lto = summaries_lto->get (callee)))
3706 if (dump_file)
3707 fprintf (dump_file, " No call target summary\n");
3708 changed |= propagate_unknown_call
3709 (node, callee_edge, flags,
3710 NULL, cur_summary_lto);
3713 /* We can not safely optimize based on summary of callee if it
3714 does not always bind to current def: it is possible that
3715 memory load was optimized out earlier which may not happen in
3716 the interposed variant. */
3717 if (!callee_edge->binds_to_current_def_p ())
3719 changed |= collapse_loads (cur_summary, cur_summary_lto);
3720 if (dump_file)
3721 fprintf (dump_file, " May not bind local;"
3722 " collapsing loads\n");
3726 auto_vec <modref_parm_map, 32> parm_map;
3728 compute_parm_map (callee_edge, &parm_map);
3730 /* Merge in callee's information. */
3731 if (callee_summary)
3733 changed |= cur_summary->loads->merge
3734 (callee_summary->loads, &parm_map, !first);
3735 if (!ignore_stores)
3737 changed |= cur_summary->stores->merge
3738 (callee_summary->stores, &parm_map,
3739 !first);
3740 if (!cur_summary->writes_errno
3741 && callee_summary->writes_errno)
3743 cur_summary->writes_errno = true;
3744 changed = true;
3748 if (callee_summary_lto)
3750 changed |= cur_summary_lto->loads->merge
3751 (callee_summary_lto->loads, &parm_map,
3752 !first);
3753 if (!ignore_stores)
3755 changed |= cur_summary_lto->stores->merge
3756 (callee_summary_lto->stores, &parm_map,
3757 !first);
3758 if (!cur_summary_lto->writes_errno
3759 && callee_summary_lto->writes_errno)
3761 cur_summary_lto->writes_errno = true;
3762 changed = true;
3766 if (changed)
3767 remove_useless_summaries (node, &cur_summary,
3768 &cur_summary_lto,
3769 cur_ecf_flags);
3770 if (!cur_summary && !cur_summary_lto)
3771 break;
3772 if (dump_file && changed)
3774 if (cur_summary)
3775 cur_summary->dump (dump_file);
3776 if (cur_summary_lto)
3777 cur_summary_lto->dump (dump_file);
3778 dump_modref_edge_summaries (dump_file, node, 4);
3782 iteration++;
3783 first = false;
3785 if (dump_file)
3786 fprintf (dump_file,
3787 "Propagation finished in %i iterations\n", iteration);
3790 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
3792 static void
3793 modref_propagate_dump_scc (cgraph_node *component_node)
3795 for (struct cgraph_node *cur = component_node; cur;
3796 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3797 if (!cur->inlined_to)
3799 modref_summary *cur_summary = optimization_summaries
3800 ? optimization_summaries->get (cur)
3801 : NULL;
3802 modref_summary_lto *cur_summary_lto = summaries_lto
3803 ? summaries_lto->get (cur)
3804 : NULL;
3806 fprintf (dump_file, "Propagated modref for %s%s%s\n",
3807 cur->dump_name (),
3808 TREE_READONLY (cur->decl) ? " (const)" : "",
3809 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3810 if (optimization_summaries)
3812 if (cur_summary)
3813 cur_summary->dump (dump_file);
3814 else
3815 fprintf (dump_file, " Not tracked\n");
3817 if (summaries_lto)
3819 if (cur_summary_lto)
3820 cur_summary_lto->dump (dump_file);
3821 else
3822 fprintf (dump_file, " Not tracked (lto)\n");
3827 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
3828 and SUMMARY_LTO to CUR_SUMMARY_LTO.
3829 Return true if something changed. */
3831 static bool
3832 modref_merge_call_site_flags (escape_summary *sum,
3833 modref_summary *cur_summary,
3834 modref_summary_lto *cur_summary_lto,
3835 modref_summary *summary,
3836 modref_summary_lto *summary_lto,
3837 tree caller,
3838 int ecf_flags)
3840 escape_entry *ee;
3841 unsigned int i;
3842 bool changed = false;
3843 bool ignore_stores = ignore_stores_p (caller, ecf_flags);
3845 /* If we have no useful info to propagate. */
3846 if ((!cur_summary || !cur_summary->arg_flags.length ())
3847 && (!cur_summary_lto || !cur_summary_lto->arg_flags.length ()))
3848 return false;
3850 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3852 int flags = 0;
3853 int flags_lto = 0;
3855 if (summary && ee->arg < summary->arg_flags.length ())
3856 flags = summary->arg_flags[ee->arg];
3857 if (summary_lto
3858 && ee->arg < summary_lto->arg_flags.length ())
3859 flags_lto = summary_lto->arg_flags[ee->arg];
3860 if (!ee->direct)
3862 flags = deref_flags (flags, ignore_stores);
3863 flags_lto = deref_flags (flags_lto, ignore_stores);
3865 else if (ignore_stores)
3867 flags |= ignore_stores_eaf_flags;
3868 flags_lto |= ignore_stores_eaf_flags;
3870 /* Returning the value is already accounted to at local propagation. */
3871 flags |= ee->min_flags | EAF_NOT_RETURNED | EAF_NOT_RETURNED_DIRECTLY;
3872 flags_lto |= ee->min_flags | EAF_NOT_RETURNED | EAF_NOT_RETURNED_DIRECTLY;
3873 /* Noescape implies that value also does not escape directly.
3874 Fnspec machinery does set both so compensate for this. */
3875 if (flags & EAF_NOESCAPE)
3876 flags |= EAF_NODIRECTESCAPE;
3877 if (flags_lto & EAF_NOESCAPE)
3878 flags_lto |= EAF_NODIRECTESCAPE;
3879 if (flags & EAF_NOT_RETURNED)
3880 flags |= EAF_NOT_RETURNED_DIRECTLY;
3881 if (flags_lto & EAF_NOT_RETURNED)
3882 flags_lto |= EAF_NOT_RETURNED_DIRECTLY;
3883 if (!(flags & EAF_UNUSED)
3884 && cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ())
3886 eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg
3887 ? cur_summary->retslot_flags
3888 : ee->parm_index == escape_point::static_chain_arg
3889 ? cur_summary->static_chain_flags
3890 : cur_summary->arg_flags[ee->parm_index];
3891 if ((f & flags) != f)
3893 f = remove_useless_eaf_flags
3894 (f & flags, ecf_flags,
3895 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
3896 changed = true;
3899 if (!(flags_lto & EAF_UNUSED)
3900 && cur_summary_lto
3901 && ee->parm_index < (int)cur_summary_lto->arg_flags.length ())
3903 eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg
3904 ? cur_summary_lto->retslot_flags
3905 : ee->parm_index == escape_point::static_chain_arg
3906 ? cur_summary_lto->static_chain_flags
3907 : cur_summary_lto->arg_flags[ee->parm_index];
3908 if ((f & flags_lto) != f)
3910 f = remove_useless_eaf_flags
3911 (f & flags_lto, ecf_flags,
3912 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
3913 changed = true;
3917 return changed;
3920 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3921 and propagate arg flags. */
3923 static void
3924 modref_propagate_flags_in_scc (cgraph_node *component_node)
3926 bool changed = true;
3927 int iteration = 0;
3929 while (changed)
3931 changed = false;
3932 for (struct cgraph_node *cur = component_node; cur;
3933 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3935 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
3936 modref_summary *cur_summary = optimization_summaries
3937 ? optimization_summaries->get (node)
3938 : NULL;
3939 modref_summary_lto *cur_summary_lto = summaries_lto
3940 ? summaries_lto->get (node)
3941 : NULL;
3943 if (!cur_summary && !cur_summary_lto)
3944 continue;
3946 if (dump_file)
3947 fprintf (dump_file, " Processing %s%s%s\n",
3948 cur->dump_name (),
3949 TREE_READONLY (cur->decl) ? " (const)" : "",
3950 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3952 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
3954 escape_summary *sum = escape_summaries->get (e);
3956 if (!sum || (e->indirect_info->ecf_flags
3957 & (ECF_CONST | ECF_NOVOPS)))
3958 continue;
3960 changed |= modref_merge_call_site_flags
3961 (sum, cur_summary, cur_summary_lto,
3962 NULL, NULL,
3963 node->decl, e->indirect_info->ecf_flags);
3966 if (!cur_summary && !cur_summary_lto)
3967 continue;
3969 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
3970 callee_edge = callee_edge->next_callee)
3972 int ecf_flags = flags_from_decl_or_type
3973 (callee_edge->callee->decl);
3974 modref_summary *callee_summary = NULL;
3975 modref_summary_lto *callee_summary_lto = NULL;
3976 struct cgraph_node *callee;
3978 if (ecf_flags & (ECF_CONST | ECF_NOVOPS)
3979 || !callee_edge->inline_failed)
3980 continue;
3981 /* Get the callee and its summary. */
3982 enum availability avail;
3983 callee = callee_edge->callee->function_or_virtual_thunk_symbol
3984 (&avail, cur);
3986 /* It is not necessary to re-process calls outside of the
3987 SCC component. */
3988 if (iteration > 0
3989 && (!callee->aux
3990 || ((struct ipa_dfs_info *)cur->aux)->scc_no
3991 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
3992 continue;
3994 escape_summary *sum = escape_summaries->get (callee_edge);
3995 if (!sum)
3996 continue;
3998 if (dump_file)
3999 fprintf (dump_file, " Call to %s\n",
4000 callee_edge->callee->dump_name ());
4002 if (avail <= AVAIL_INTERPOSABLE
4003 || callee_edge->call_stmt_cannot_inline_p)
4005 else
4007 if (cur_summary)
4008 callee_summary = optimization_summaries->get (callee);
4009 if (cur_summary_lto)
4010 callee_summary_lto = summaries_lto->get (callee);
4012 changed |= modref_merge_call_site_flags
4013 (sum, cur_summary, cur_summary_lto,
4014 callee_summary, callee_summary_lto,
4015 node->decl, ecf_flags);
4016 if (dump_file && changed)
4018 if (cur_summary)
4019 cur_summary->dump (dump_file);
4020 if (cur_summary_lto)
4021 cur_summary_lto->dump (dump_file);
4025 iteration++;
4027 if (dump_file)
4028 fprintf (dump_file,
4029 "Propagation of flags finished in %i iterations\n", iteration);
4032 } /* ANON namespace. */
4034 /* Call EDGE was inlined; merge summary from callee to the caller. */
4036 void
4037 ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
4039 if (!summaries && !summaries_lto)
4040 return;
4042 struct cgraph_node *to = (edge->caller->inlined_to
4043 ? edge->caller->inlined_to : edge->caller);
4044 class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
4045 class modref_summary_lto *to_info_lto = summaries_lto
4046 ? summaries_lto->get (to) : NULL;
4048 if (!to_info && !to_info_lto)
4050 if (summaries)
4051 summaries->remove (edge->callee);
4052 if (summaries_lto)
4053 summaries_lto->remove (edge->callee);
4054 remove_modref_edge_summaries (edge->callee);
4055 return;
4058 class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
4059 : NULL;
4060 class modref_summary_lto *callee_info_lto
4061 = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
4062 int flags = flags_from_decl_or_type (edge->callee->decl);
4063 bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
4065 if (!callee_info && to_info)
4067 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
4068 to_info->loads->collapse ();
4069 if (!ignore_stores)
4070 to_info->stores->collapse ();
4072 if (!callee_info_lto && to_info_lto)
4074 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
4075 to_info_lto->loads->collapse ();
4076 if (!ignore_stores)
4077 to_info_lto->stores->collapse ();
4079 if (callee_info || callee_info_lto)
4081 auto_vec <modref_parm_map, 32> parm_map;
4083 compute_parm_map (edge, &parm_map);
4085 if (!ignore_stores)
4087 if (to_info && callee_info)
4088 to_info->stores->merge (callee_info->stores, &parm_map, false);
4089 if (to_info_lto && callee_info_lto)
4090 to_info_lto->stores->merge (callee_info_lto->stores, &parm_map,
4091 false);
4093 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
4095 if (to_info && callee_info)
4096 to_info->loads->merge (callee_info->loads, &parm_map, false);
4097 if (to_info_lto && callee_info_lto)
4098 to_info_lto->loads->merge (callee_info_lto->loads, &parm_map,
4099 false);
4103 /* Now merge escape summaries.
4104 For every escape to the callee we need to merge calle flags
4105 and remap calees escapes. */
4106 class escape_summary *sum = escape_summaries->get (edge);
4107 int max_escape = -1;
4108 escape_entry *ee;
4109 unsigned int i;
4111 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
4112 FOR_EACH_VEC_ELT (sum->esc, i, ee)
4113 if ((int)ee->arg > max_escape)
4114 max_escape = ee->arg;
4116 auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
4117 emap.safe_grow (max_escape + 1, true);
4118 for (i = 0; (int)i < max_escape + 1; i++)
4119 emap[i] = vNULL;
4121 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
4122 FOR_EACH_VEC_ELT (sum->esc, i, ee)
4124 bool needed = false;
4125 /* TODO: We do not have jump functions for return slots, so we
4126 never propagate them to outer function. */
4127 if (ee->parm_index < 0)
4128 continue;
4129 if (to_info && (int)to_info->arg_flags.length () > ee->parm_index)
4131 int flags = callee_info
4132 && callee_info->arg_flags.length () > ee->arg
4133 ? callee_info->arg_flags[ee->arg] : 0;
4134 if (!ee->direct)
4135 flags = deref_flags (flags, ignore_stores);
4136 else if (ignore_stores)
4137 flags |= ignore_stores_eaf_flags;
4138 flags |= ee->min_flags;
4139 to_info->arg_flags[ee->parm_index] &= flags;
4140 if (to_info->arg_flags[ee->parm_index])
4141 needed = true;
4143 if (to_info_lto
4144 && (int)to_info_lto->arg_flags.length () > ee->parm_index)
4146 int flags = callee_info_lto
4147 && callee_info_lto->arg_flags.length () > ee->arg
4148 ? callee_info_lto->arg_flags[ee->arg] : 0;
4149 if (!ee->direct)
4150 flags = deref_flags (flags, ignore_stores);
4151 else if (ignore_stores)
4152 flags |= ignore_stores_eaf_flags;
4153 flags |= ee->min_flags;
4154 to_info_lto->arg_flags[ee->parm_index] &= flags;
4155 if (to_info_lto->arg_flags[ee->parm_index])
4156 needed = true;
4158 struct escape_map entry = {ee->parm_index, ee->direct};
4159 if (needed)
4160 emap[ee->arg].safe_push (entry);
4162 update_escape_summary (edge->callee, emap, ignore_stores);
4163 for (i = 0; (int)i < max_escape + 1; i++)
4164 emap[i].release ();
4165 if (sum)
4166 escape_summaries->remove (edge);
4168 if (summaries)
4170 if (to_info && !to_info->useful_p (flags))
4172 if (dump_file)
4173 fprintf (dump_file, "Removed mod-ref summary for %s\n",
4174 to->dump_name ());
4175 summaries->remove (to);
4176 to_info = NULL;
4178 else if (to_info && dump_file)
4180 if (dump_file)
4181 fprintf (dump_file, "Updated mod-ref summary for %s\n",
4182 to->dump_name ());
4183 to_info->dump (dump_file);
4185 if (callee_info)
4186 summaries->remove (edge->callee);
4188 if (summaries_lto)
4190 if (to_info_lto && !to_info_lto->useful_p (flags))
4192 if (dump_file)
4193 fprintf (dump_file, "Removed mod-ref summary for %s\n",
4194 to->dump_name ());
4195 summaries_lto->remove (to);
4197 else if (to_info_lto && dump_file)
4199 if (dump_file)
4200 fprintf (dump_file, "Updated mod-ref summary for %s\n",
4201 to->dump_name ());
4202 to_info_lto->dump (dump_file);
4203 to_info_lto = NULL;
4205 if (callee_info_lto)
4206 summaries_lto->remove (edge->callee);
4208 if (!to_info && !to_info_lto)
4209 remove_modref_edge_summaries (to);
4210 return;
4213 /* Run the IPA pass. This will take a function's summaries and calls and
4214 construct new summaries which represent a transitive closure. So that
4215 summary of an analyzed function contains information about the loads and
4216 stores that the function or any function that it calls does. */
4218 unsigned int
4219 pass_ipa_modref::execute (function *)
4221 if (!summaries && !summaries_lto)
4222 return 0;
4224 if (optimization_summaries)
4225 ggc_delete (optimization_summaries);
4226 optimization_summaries = summaries;
4227 summaries = NULL;
4229 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
4230 symtab->cgraph_count);
4231 int order_pos;
4232 order_pos = ipa_reduced_postorder (order, true, ignore_edge);
4233 int i;
4235 /* Iterate over all strongly connected components in post-order. */
4236 for (i = 0; i < order_pos; i++)
4238 /* Get the component's representative. That's just any node in the
4239 component from which we can traverse the entire component. */
4240 struct cgraph_node *component_node = order[i];
4242 if (dump_file)
4243 fprintf (dump_file, "\n\nStart of SCC component\n");
4245 modref_propagate_in_scc (component_node);
4246 modref_propagate_flags_in_scc (component_node);
4247 if (dump_file)
4248 modref_propagate_dump_scc (component_node);
4250 cgraph_node *node;
4251 FOR_EACH_FUNCTION (node)
4252 update_signature (node);
4253 if (summaries_lto)
4254 ((modref_summaries_lto *)summaries_lto)->propagated = true;
4255 ipa_free_postorder_info ();
4256 free (order);
4257 delete fnspec_summaries;
4258 fnspec_summaries = NULL;
4259 delete escape_summaries;
4260 escape_summaries = NULL;
4261 return 0;
4264 /* Summaries must stay alive until end of compilation. */
4266 void
4267 ipa_modref_c_finalize ()
4269 if (optimization_summaries)
4270 ggc_delete (optimization_summaries);
4271 optimization_summaries = NULL;
4272 gcc_checking_assert (!summaries
4273 || flag_incremental_link == INCREMENTAL_LINK_LTO);
4274 if (summaries_lto)
4275 ggc_delete (summaries_lto);
4276 summaries_lto = NULL;
4277 if (fnspec_summaries)
4278 delete fnspec_summaries;
4279 fnspec_summaries = NULL;
4280 if (escape_summaries)
4281 delete escape_summaries;
4282 escape_summaries = NULL;
4285 #include "gt-ipa-modref.h"