testsuite: localclass2 require LTO
[official-gcc.git] / gcc / ipa-modref.c
blobe6cb4a87b691f3f11a172def6bc1d5ce35641d41
1 /* Search for references that a functions loads or stores.
2 Copyright (C) 2020 Free Software Foundation, Inc.
3 Contributed by David Cepelik and Jan Hubicka
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/dtores
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"
89 namespace {
91 /* We record fnspec specifiers for call edges since they depends on actual
92 gimple statements. */
94 class fnspec_summary
96 public:
97 char *fnspec;
99 fnspec_summary ()
100 : fnspec (NULL)
104 ~fnspec_summary ()
106 free (fnspec);
110 /* Summary holding fnspec string for a given call. */
112 class fnspec_summaries_t : public call_summary <fnspec_summary *>
114 public:
115 fnspec_summaries_t (symbol_table *symtab)
116 : call_summary <fnspec_summary *> (symtab) {}
117 /* Hook that is called by summary when an edge is duplicated. */
118 virtual void duplicate (cgraph_edge *,
119 cgraph_edge *,
120 fnspec_summary *src,
121 fnspec_summary *dst)
123 dst->fnspec = xstrdup (src->fnspec);
127 static fnspec_summaries_t *fnspec_summaries = NULL;
129 /* Escape summary holds a vector of param indexes that escape to
130 a given call. */
131 struct escape_entry
133 /* Parameter that escapes at a given call. */
134 unsigned int parm_index;
135 /* Argument it escapes to. */
136 unsigned int arg;
137 /* Minimal flags known about the argument. */
138 char min_flags;
139 /* Does it escape directly or indirectly? */
140 bool direct;
143 /* Dump EAF flags. */
145 static void
146 dump_eaf_flags (FILE *out, int flags, bool newline = true)
148 if (flags & EAF_DIRECT)
149 fprintf (out, " direct");
150 if (flags & EAF_NOCLOBBER)
151 fprintf (out, " noclobber");
152 if (flags & EAF_NOESCAPE)
153 fprintf (out, " noescape");
154 if (flags & EAF_UNUSED)
155 fprintf (out, " unused");
156 if (newline)
157 fprintf (out, "\n");
160 struct escape_summary
162 auto_vec <escape_entry> esc;
163 void dump (FILE *out)
165 for (unsigned int i = 0; i < esc.length (); i++)
167 fprintf (out, " parm %i arg %i %s min:",
168 esc[i].parm_index,
169 esc[i].arg,
170 esc[i].direct ? "(direct)" : "(indirect)");
171 dump_eaf_flags (out, esc[i].min_flags, false);
173 fprintf (out, "\n");
177 class escape_summaries_t : public call_summary <escape_summary *>
179 public:
180 escape_summaries_t (symbol_table *symtab)
181 : call_summary <escape_summary *> (symtab) {}
182 /* Hook that is called by summary when an edge is duplicated. */
183 virtual void duplicate (cgraph_edge *,
184 cgraph_edge *,
185 escape_summary *src,
186 escape_summary *dst)
188 dst->esc = src->esc.copy ();
192 static escape_summaries_t *escape_summaries = NULL;
194 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
197 /* Class (from which there is one global instance) that holds modref summaries
198 for all analyzed functions. */
200 class GTY((user)) modref_summaries
201 : public fast_function_summary <modref_summary *, va_gc>
203 public:
204 modref_summaries (symbol_table *symtab)
205 : fast_function_summary <modref_summary *, va_gc> (symtab) {}
206 virtual void insert (cgraph_node *, modref_summary *state);
207 virtual void duplicate (cgraph_node *src_node,
208 cgraph_node *dst_node,
209 modref_summary *src_data,
210 modref_summary *dst_data);
211 static modref_summaries *create_ggc (symbol_table *symtab)
213 return new (ggc_alloc_no_dtor<modref_summaries> ())
214 modref_summaries (symtab);
218 class modref_summary_lto;
220 /* Class (from which there is one global instance) that holds modref summaries
221 for all analyzed functions. */
223 class GTY((user)) modref_summaries_lto
224 : public fast_function_summary <modref_summary_lto *, va_gc>
226 public:
227 modref_summaries_lto (symbol_table *symtab)
228 : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
229 propagated (false) {}
230 virtual void insert (cgraph_node *, modref_summary_lto *state);
231 virtual void duplicate (cgraph_node *src_node,
232 cgraph_node *dst_node,
233 modref_summary_lto *src_data,
234 modref_summary_lto *dst_data);
235 static modref_summaries_lto *create_ggc (symbol_table *symtab)
237 return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
238 modref_summaries_lto (symtab);
240 bool propagated;
243 /* Global variable holding all modref summaries
244 (from analysis to IPA propagation time). */
246 static GTY(()) fast_function_summary <modref_summary *, va_gc>
247 *summaries;
249 /* Global variable holding all modref optimization summaries
250 (from IPA propagation time or used by local optimization pass). */
252 static GTY(()) fast_function_summary <modref_summary *, va_gc>
253 *optimization_summaries;
255 /* LTO summaries hold info from analysis to LTO streaming or from LTO
256 stream-in through propagation to LTO stream-out. */
258 static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
259 *summaries_lto;
261 /* Summary for a single function which this pass produces. */
263 modref_summary::modref_summary ()
264 : loads (NULL), stores (NULL), writes_errno (NULL)
268 modref_summary::~modref_summary ()
270 if (loads)
271 ggc_delete (loads);
272 if (stores)
273 ggc_delete (stores);
276 /* Return true if FLAGS holds some useful information. */
278 static bool
279 eaf_flags_useful_p (vec <unsigned char> &flags, int ecf_flags)
281 for (unsigned i = 0; i < flags.length (); i++)
282 if (ecf_flags & ECF_PURE)
284 if (flags[i] & (EAF_UNUSED | EAF_DIRECT))
285 return true;
287 else
289 if (flags[i])
290 return true;
292 return false;
295 /* Return true if summary is potentially useful for optimization.
296 If CHECK_FLAGS is false assume that arg_flags are useful. */
298 bool
299 modref_summary::useful_p (int ecf_flags, bool check_flags)
301 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
302 return false;
303 if (arg_flags.length () && !check_flags)
304 return true;
305 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
306 return true;
307 arg_flags.release ();
308 if (loads && !loads->every_base)
309 return true;
310 if (ecf_flags & ECF_PURE)
311 return false;
312 return stores && !stores->every_base;
315 /* Single function summary used for LTO. */
317 typedef modref_tree <tree> modref_records_lto;
318 struct GTY(()) modref_summary_lto
320 /* Load and stores in functions using types rather then alias sets.
322 This is necessary to make the information streamable for LTO but is also
323 more verbose and thus more likely to hit the limits. */
324 modref_records_lto *loads;
325 modref_records_lto *stores;
326 auto_vec<unsigned char> GTY((skip)) arg_flags;
327 bool writes_errno;
329 modref_summary_lto ();
330 ~modref_summary_lto ();
331 void dump (FILE *);
332 bool useful_p (int ecf_flags, bool check_flags = true);
335 /* Summary for a single function which this pass produces. */
337 modref_summary_lto::modref_summary_lto ()
338 : loads (NULL), stores (NULL), writes_errno (NULL)
342 modref_summary_lto::~modref_summary_lto ()
344 if (loads)
345 ggc_delete (loads);
346 if (stores)
347 ggc_delete (stores);
351 /* Return true if lto summary is potentially useful for optimization.
352 If CHECK_FLAGS is false assume that arg_flags are useful. */
354 bool
355 modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
357 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
358 return false;
359 if (arg_flags.length () && !check_flags)
360 return true;
361 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
362 return true;
363 arg_flags.release ();
364 if (loads && !loads->every_base)
365 return true;
366 if (ecf_flags & ECF_PURE)
367 return false;
368 return stores && !stores->every_base;
371 /* Dump A to OUT. */
373 static void
374 dump_access (modref_access_node *a, FILE *out)
376 fprintf (out, " access:");
377 if (a->parm_index != -1)
379 fprintf (out, " Parm %i", a->parm_index);
380 if (a->parm_offset_known)
382 fprintf (out, " param offset:");
383 print_dec ((poly_int64_pod)a->parm_offset, out, SIGNED);
386 if (a->range_info_useful_p ())
388 fprintf (out, " offset:");
389 print_dec ((poly_int64_pod)a->offset, out, SIGNED);
390 fprintf (out, " size:");
391 print_dec ((poly_int64_pod)a->size, out, SIGNED);
392 fprintf (out, " max_size:");
393 print_dec ((poly_int64_pod)a->max_size, out, SIGNED);
395 fprintf (out, "\n");
398 /* Dump records TT to OUT. */
400 static void
401 dump_records (modref_records *tt, FILE *out)
403 fprintf (out, " Limits: %i bases, %i refs\n",
404 (int)tt->max_bases, (int)tt->max_refs);
405 if (tt->every_base)
407 fprintf (out, " Every base\n");
408 return;
410 size_t i;
411 modref_base_node <alias_set_type> *n;
412 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
414 fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
415 if (n->every_ref)
417 fprintf (out, " Every ref\n");
418 continue;
420 size_t j;
421 modref_ref_node <alias_set_type> *r;
422 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
424 fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
425 if (r->every_access)
427 fprintf (out, " Every access\n");
428 continue;
430 size_t k;
431 modref_access_node *a;
432 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
433 dump_access (a, out);
438 /* Dump records TT to OUT. */
440 static void
441 dump_lto_records (modref_records_lto *tt, FILE *out)
443 fprintf (out, " Limits: %i bases, %i refs\n",
444 (int)tt->max_bases, (int)tt->max_refs);
445 if (tt->every_base)
447 fprintf (out, " Every base\n");
448 return;
450 size_t i;
451 modref_base_node <tree> *n;
452 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
454 fprintf (out, " Base %i:", (int)i);
455 print_generic_expr (dump_file, n->base);
456 fprintf (out, " (alias set %i)\n",
457 n->base ? get_alias_set (n->base) : 0);
458 if (n->every_ref)
460 fprintf (out, " Every ref\n");
461 continue;
463 size_t j;
464 modref_ref_node <tree> *r;
465 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
467 fprintf (out, " Ref %i:", (int)j);
468 print_generic_expr (dump_file, r->ref);
469 fprintf (out, " (alias set %i)\n",
470 r->ref ? get_alias_set (r->ref) : 0);
471 if (r->every_access)
473 fprintf (out, " Every access\n");
474 continue;
476 size_t k;
477 modref_access_node *a;
478 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
479 dump_access (a, out);
484 /* Dump all escape points of NODE to OUT. */
486 static void
487 dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
489 int i = 0;
490 if (!escape_summaries)
491 return;
492 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
494 class escape_summary *sum = escape_summaries->get (e);
495 if (sum)
497 fprintf (out, "%*sIndirect call %i in %s escapes:",
498 depth, "", i, node->dump_name ());
499 sum->dump (out);
501 i++;
503 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
505 if (!e->inline_failed)
506 dump_modref_edge_summaries (out, e->callee, depth + 1);
507 class escape_summary *sum = escape_summaries->get (e);
508 if (sum)
510 fprintf (out, "%*sCall %s->%s escapes:", depth, "",
511 node->dump_name (), e->callee->dump_name ());
512 sum->dump (out);
514 class fnspec_summary *fsum = fnspec_summaries->get (e);
515 if (fsum)
517 fprintf (out, "%*sCall %s->%s fnspec: %s\n", depth, "",
518 node->dump_name (), e->callee->dump_name (),
519 fsum->fnspec);
524 /* Remove all call edge summaries associated with NODE. */
526 static void
527 remove_modref_edge_summaries (cgraph_node *node)
529 if (!escape_summaries)
530 return;
531 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
532 escape_summaries->remove (e);
533 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
535 if (!e->inline_failed)
536 remove_modref_edge_summaries (e->callee);
537 escape_summaries->remove (e);
538 fnspec_summaries->remove (e);
542 /* Dump summary. */
544 void
545 modref_summary::dump (FILE *out)
547 if (loads)
549 fprintf (out, " loads:\n");
550 dump_records (loads, out);
552 if (stores)
554 fprintf (out, " stores:\n");
555 dump_records (stores, out);
557 if (writes_errno)
558 fprintf (out, " Writes errno\n");
559 if (arg_flags.length ())
561 for (unsigned int i = 0; i < arg_flags.length (); i++)
562 if (arg_flags[i])
564 fprintf (out, " parm %i flags:", i);
565 dump_eaf_flags (out, arg_flags[i]);
570 /* Dump summary. */
572 void
573 modref_summary_lto::dump (FILE *out)
575 fprintf (out, " loads:\n");
576 dump_lto_records (loads, out);
577 fprintf (out, " stores:\n");
578 dump_lto_records (stores, out);
579 if (writes_errno)
580 fprintf (out, " Writes errno\n");
581 if (arg_flags.length ())
583 for (unsigned int i = 0; i < arg_flags.length (); i++)
584 if (arg_flags[i])
586 fprintf (out, " parm %i flags:", i);
587 dump_eaf_flags (out, arg_flags[i]);
592 /* Get function summary for FUNC if it exists, return NULL otherwise. */
594 modref_summary *
595 get_modref_function_summary (cgraph_node *func)
597 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
598 if (!optimization_summaries)
599 return NULL;
601 /* A single function body may be represented by multiple symbols with
602 different visibility. For example, if FUNC is an interposable alias,
603 we don't want to return anything, even if we have summary for the target
604 function. */
605 enum availability avail;
606 func = func->function_or_virtual_thunk_symbol
607 (&avail, current_function_decl ?
608 cgraph_node::get (current_function_decl) : NULL);
609 if (avail <= AVAIL_INTERPOSABLE)
610 return NULL;
612 modref_summary *r = optimization_summaries->get (func);
613 return r;
616 /* Construct modref_access_node from REF. */
617 static modref_access_node
618 get_access (ao_ref *ref)
620 tree base;
622 base = ao_ref_base (ref);
623 modref_access_node a = {ref->offset, ref->size, ref->max_size,
624 0, -1, false};
625 if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
627 tree memref = base;
628 base = TREE_OPERAND (base, 0);
629 if (TREE_CODE (base) == SSA_NAME
630 && SSA_NAME_IS_DEFAULT_DEF (base)
631 && TREE_CODE (SSA_NAME_VAR (base)) == PARM_DECL)
633 a.parm_index = 0;
634 for (tree t = DECL_ARGUMENTS (current_function_decl);
635 t != SSA_NAME_VAR (base); t = DECL_CHAIN (t))
637 if (!t)
639 a.parm_index = -1;
640 break;
642 a.parm_index++;
644 if (TREE_CODE (memref) == MEM_REF)
646 a.parm_offset_known
647 = wi::to_poly_wide (TREE_OPERAND
648 (memref, 1)).to_shwi (&a.parm_offset);
650 else
651 a.parm_offset_known = false;
653 else
654 a.parm_index = -1;
656 else
657 a.parm_index = -1;
658 return a;
661 /* Record access into the modref_records data structure. */
663 static void
664 record_access (modref_records *tt, ao_ref *ref)
666 alias_set_type base_set = !flag_strict_aliasing ? 0
667 : ao_ref_base_alias_set (ref);
668 alias_set_type ref_set = !flag_strict_aliasing ? 0
669 : (ao_ref_alias_set (ref));
670 modref_access_node a = get_access (ref);
671 if (dump_file)
673 fprintf (dump_file, " - Recording base_set=%i ref_set=%i parm=%i\n",
674 base_set, ref_set, a.parm_index);
676 tt->insert (base_set, ref_set, a);
679 /* IPA version of record_access_tree. */
681 static void
682 record_access_lto (modref_records_lto *tt, ao_ref *ref)
684 /* get_alias_set sometimes use different type to compute the alias set
685 than TREE_TYPE (base). Do same adjustments. */
686 tree base_type = NULL_TREE, ref_type = NULL_TREE;
687 if (flag_strict_aliasing)
689 tree base;
691 base = ref->ref;
692 while (handled_component_p (base))
693 base = TREE_OPERAND (base, 0);
695 base_type = reference_alias_ptr_type_1 (&base);
697 if (!base_type)
698 base_type = TREE_TYPE (base);
699 else
700 base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
701 ? NULL_TREE : TREE_TYPE (base_type);
703 tree ref_expr = ref->ref;
704 ref_type = reference_alias_ptr_type_1 (&ref_expr);
706 if (!ref_type)
707 ref_type = TREE_TYPE (ref_expr);
708 else
709 ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
710 ? NULL_TREE : TREE_TYPE (ref_type);
712 /* Sanity check that we are in sync with what get_alias_set does. */
713 gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
714 || get_alias_set (base_type)
715 == ao_ref_base_alias_set (ref));
716 gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
717 || get_alias_set (ref_type)
718 == ao_ref_alias_set (ref));
720 /* Do not bother to record types that have no meaningful alias set.
721 Also skip variably modified types since these go to local streams. */
722 if (base_type && (!get_alias_set (base_type)
723 || variably_modified_type_p (base_type, NULL_TREE)))
724 base_type = NULL_TREE;
725 if (ref_type && (!get_alias_set (ref_type)
726 || variably_modified_type_p (ref_type, NULL_TREE)))
727 ref_type = NULL_TREE;
729 modref_access_node a = get_access (ref);
730 if (dump_file)
732 fprintf (dump_file, " - Recording base type:");
733 print_generic_expr (dump_file, base_type);
734 fprintf (dump_file, " (alias set %i) ref type:",
735 base_type ? get_alias_set (base_type) : 0);
736 print_generic_expr (dump_file, ref_type);
737 fprintf (dump_file, " (alias set %i) parm:%i\n",
738 ref_type ? get_alias_set (ref_type) : 0,
739 a.parm_index);
742 tt->insert (base_type, ref_type, a);
745 /* Returns true if and only if we should store the access to EXPR.
746 Some accesses, e.g. loads from automatic variables, are not interesting. */
748 static bool
749 record_access_p (tree expr)
751 if (refs_local_or_readonly_memory_p (expr))
753 if (dump_file)
754 fprintf (dump_file, " - Read-only or local, ignoring.\n");
755 return false;
757 return true;
760 /* Return true if ECF flags says that return value can be ignored. */
762 static bool
763 ignore_retval_p (tree caller, int flags)
765 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
766 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
767 return true;
768 return false;
771 /* Return true if ECF flags says that stores can be ignored. */
773 static bool
774 ignore_stores_p (tree caller, int flags)
776 if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
777 return true;
778 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
779 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
780 return true;
781 return false;
784 /* Determine parm_map for argument I of STMT. */
786 modref_parm_map
787 parm_map_for_arg (gimple *stmt, int i)
789 tree op = gimple_call_arg (stmt, i);
790 bool offset_known;
791 poly_int64 offset;
792 struct modref_parm_map parm_map;
794 parm_map.parm_offset_known = false;
795 parm_map.parm_offset = 0;
797 offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
798 if (TREE_CODE (op) == SSA_NAME
799 && SSA_NAME_IS_DEFAULT_DEF (op)
800 && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
802 int index = 0;
803 for (tree t = DECL_ARGUMENTS (current_function_decl);
804 t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
806 if (!t)
808 index = -1;
809 break;
811 index++;
813 parm_map.parm_index = index;
814 parm_map.parm_offset_known = offset_known;
815 parm_map.parm_offset = offset;
817 else if (points_to_local_or_readonly_memory_p (op))
818 parm_map.parm_index = -2;
819 else
820 parm_map.parm_index = -1;
821 return parm_map;
824 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
825 int CUR_SUMMARY. Return true if something changed.
826 If IGNORE_STORES is true, do not merge stores. */
828 bool
829 merge_call_side_effects (modref_summary *cur_summary,
830 gimple *stmt, modref_summary *callee_summary,
831 bool ignore_stores, cgraph_node *callee_node)
833 auto_vec <modref_parm_map, 32> parm_map;
834 bool changed = false;
836 if (dump_file)
837 fprintf (dump_file, " - Merging side effects of %s with parm map:",
838 callee_node->dump_name ());
840 /* We can not safely optimize based on summary of callee if it does
841 not always bind to current def: it is possible that memory load
842 was optimized out earlier which may not happen in the interposed
843 variant. */
844 if (!callee_node->binds_to_current_def_p ())
846 if (dump_file)
847 fprintf (dump_file, " - May be interposed: collapsing loads.\n");
848 cur_summary->loads->collapse ();
851 parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true);
852 for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
854 parm_map[i] = parm_map_for_arg (stmt, i);
855 if (dump_file)
857 fprintf (dump_file, " %i", parm_map[i].parm_index);
858 if (parm_map[i].parm_offset_known)
860 fprintf (dump_file, " offset:");
861 print_dec ((poly_int64_pod)parm_map[i].parm_offset,
862 dump_file, SIGNED);
866 if (dump_file)
867 fprintf (dump_file, "\n");
869 /* Merge with callee's summary. */
870 changed |= cur_summary->loads->merge (callee_summary->loads, &parm_map);
871 if (!ignore_stores)
873 changed |= cur_summary->stores->merge (callee_summary->stores,
874 &parm_map);
875 if (!cur_summary->writes_errno
876 && callee_summary->writes_errno)
878 cur_summary->writes_errno = true;
879 changed = true;
882 return changed;
885 /* Return access mode for argument I of call STMT with FNSPEC. */
887 static modref_access_node
888 get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
889 unsigned int i, modref_parm_map &map)
891 tree size = NULL_TREE;
892 unsigned int size_arg;
894 if (!fnspec.arg_specified_p (i))
896 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
897 size = gimple_call_arg (call, size_arg);
898 else if (fnspec.arg_access_size_given_by_type_p (i))
900 tree callee = gimple_call_fndecl (call);
901 tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
903 for (unsigned int p = 0; p < i; p++)
904 t = TREE_CHAIN (t);
905 size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
907 modref_access_node a = {0, -1, -1,
908 map.parm_offset, map.parm_index,
909 map.parm_offset_known};
910 poly_int64 size_hwi;
911 if (size
912 && poly_int_tree_p (size, &size_hwi)
913 && coeffs_in_range_p (size_hwi, 0,
914 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
916 a.size = -1;
917 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
919 return a;
922 /* Collapse loads and return true if something changed. */
924 static bool
925 collapse_loads (modref_summary *cur_summary,
926 modref_summary_lto *cur_summary_lto)
928 bool changed = false;
930 if (cur_summary && !cur_summary->loads->every_base)
932 cur_summary->loads->collapse ();
933 changed = true;
935 if (cur_summary_lto
936 && !cur_summary_lto->loads->every_base)
938 cur_summary_lto->loads->collapse ();
939 changed = true;
941 return changed;
944 /* Collapse loads and return true if something changed. */
946 static bool
947 collapse_stores (modref_summary *cur_summary,
948 modref_summary_lto *cur_summary_lto)
950 bool changed = false;
952 if (cur_summary && !cur_summary->stores->every_base)
954 cur_summary->stores->collapse ();
955 changed = true;
957 if (cur_summary_lto
958 && !cur_summary_lto->stores->every_base)
960 cur_summary_lto->stores->collapse ();
961 changed = true;
963 return changed;
967 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
968 If IGNORE_STORES is true ignore them.
969 Return false if no useful summary can be produced. */
971 static bool
972 process_fnspec (modref_summary *cur_summary,
973 modref_summary_lto *cur_summary_lto,
974 gcall *call, bool ignore_stores)
976 attr_fnspec fnspec = gimple_call_fnspec (call);
977 if (!fnspec.known_p ())
979 if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
980 fprintf (dump_file, " Builtin with no fnspec: %s\n",
981 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
982 if (ignore_stores)
984 collapse_loads (cur_summary, cur_summary_lto);
985 return true;
987 return false;
989 if (fnspec.global_memory_read_p ())
990 collapse_loads (cur_summary, cur_summary_lto);
991 else
993 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
994 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
996 else if (!fnspec.arg_specified_p (i)
997 || fnspec.arg_maybe_read_p (i))
999 modref_parm_map map = parm_map_for_arg (call, i);
1001 if (map.parm_index == -2)
1002 continue;
1003 if (map.parm_index == -1)
1005 collapse_loads (cur_summary, cur_summary_lto);
1006 break;
1008 if (cur_summary)
1009 cur_summary->loads->insert (0, 0,
1010 get_access_for_fnspec (call,
1011 fnspec, i,
1012 map));
1013 if (cur_summary_lto)
1014 cur_summary_lto->loads->insert (0, 0,
1015 get_access_for_fnspec (call,
1016 fnspec, i,
1017 map));
1020 if (ignore_stores)
1021 return true;
1022 if (fnspec.global_memory_written_p ())
1023 collapse_stores (cur_summary, cur_summary_lto);
1024 else
1026 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1027 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1029 else if (!fnspec.arg_specified_p (i)
1030 || fnspec.arg_maybe_written_p (i))
1032 modref_parm_map map = parm_map_for_arg (call, i);
1034 if (map.parm_index == -2)
1035 continue;
1036 if (map.parm_index == -1)
1038 collapse_stores (cur_summary, cur_summary_lto);
1039 break;
1041 if (cur_summary)
1042 cur_summary->stores->insert (0, 0,
1043 get_access_for_fnspec (call,
1044 fnspec, i,
1045 map));
1046 if (cur_summary_lto)
1047 cur_summary_lto->stores->insert (0, 0,
1048 get_access_for_fnspec (call,
1049 fnspec, i,
1050 map));
1052 if (fnspec.errno_maybe_written_p () && flag_errno_math)
1054 if (cur_summary)
1055 cur_summary->writes_errno = true;
1056 if (cur_summary_lto)
1057 cur_summary_lto->writes_errno = true;
1060 return true;
1063 /* Analyze function call STMT in function F.
1064 Remember recursive calls in RECURSIVE_CALLS. */
1066 static bool
1067 analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto,
1068 gcall *stmt, vec <gimple *> *recursive_calls)
1070 /* Check flags on the function call. In certain cases, analysis can be
1071 simplified. */
1072 int flags = gimple_call_flags (stmt);
1073 if (flags & (ECF_CONST | ECF_NOVOPS))
1075 if (dump_file)
1076 fprintf (dump_file,
1077 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1078 "except for args.\n");
1079 return true;
1082 /* Pure functions do not affect global memory. Stores by functions which are
1083 noreturn and do not throw can safely be ignored. */
1084 bool ignore_stores = ignore_stores_p (current_function_decl, flags);
1086 /* Next, we try to get the callee's function declaration. The goal is to
1087 merge their summary with ours. */
1088 tree callee = gimple_call_fndecl (stmt);
1090 /* Check if this is an indirect call. */
1091 if (!callee)
1093 if (dump_file)
1094 fprintf (dump_file, gimple_call_internal_p (stmt)
1095 ? " - Internal call" : " - Indirect call.\n");
1096 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1098 /* We only need to handle internal calls in IPA mode. */
1099 gcc_checking_assert (!cur_summary_lto);
1101 struct cgraph_node *callee_node = cgraph_node::get_create (callee);
1103 /* If this is a recursive call, the target summary is the same as ours, so
1104 there's nothing to do. */
1105 if (recursive_call_p (current_function_decl, callee))
1107 recursive_calls->safe_push (stmt);
1108 if (dump_file)
1109 fprintf (dump_file, " - Skipping recursive call.\n");
1110 return true;
1113 gcc_assert (callee_node != NULL);
1115 /* Get the function symbol and its availability. */
1116 enum availability avail;
1117 callee_node = callee_node->function_symbol (&avail);
1118 if (avail <= AVAIL_INTERPOSABLE)
1120 if (dump_file)
1121 fprintf (dump_file, " - Function availability <= AVAIL_INTERPOSABLE.\n");
1122 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1125 /* Get callee's modref summary. As above, if there's no summary, we either
1126 have to give up or, if stores are ignored, we can just purge loads. */
1127 modref_summary *callee_summary = optimization_summaries->get (callee_node);
1128 if (!callee_summary)
1130 if (dump_file)
1131 fprintf (dump_file, " - No modref summary available for callee.\n");
1132 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1135 merge_call_side_effects (cur_summary, stmt, callee_summary, ignore_stores,
1136 callee_node);
1138 return true;
1141 /* Support analysis in non-lto and lto mode in parallel. */
1143 struct summary_ptrs
1145 struct modref_summary *nolto;
1146 struct modref_summary_lto *lto;
1149 /* Helper for analyze_stmt. */
1151 static bool
1152 analyze_load (gimple *, tree, tree op, void *data)
1154 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1155 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1157 if (dump_file)
1159 fprintf (dump_file, " - Analyzing load: ");
1160 print_generic_expr (dump_file, op);
1161 fprintf (dump_file, "\n");
1164 if (!record_access_p (op))
1165 return false;
1167 ao_ref r;
1168 ao_ref_init (&r, op);
1170 if (summary)
1171 record_access (summary->loads, &r);
1172 if (summary_lto)
1173 record_access_lto (summary_lto->loads, &r);
1174 return false;
1177 /* Helper for analyze_stmt. */
1179 static bool
1180 analyze_store (gimple *, tree, tree op, void *data)
1182 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1183 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1185 if (dump_file)
1187 fprintf (dump_file, " - Analyzing store: ");
1188 print_generic_expr (dump_file, op);
1189 fprintf (dump_file, "\n");
1192 if (!record_access_p (op))
1193 return false;
1195 ao_ref r;
1196 ao_ref_init (&r, op);
1198 if (summary)
1199 record_access (summary->stores, &r);
1200 if (summary_lto)
1201 record_access_lto (summary_lto->stores, &r);
1202 return false;
1205 /* Analyze statement STMT of function F.
1206 If IPA is true do not merge in side effects of calls. */
1208 static bool
1209 analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
1210 gimple *stmt, bool ipa, vec <gimple *> *recursive_calls)
1212 /* In general we can not ignore clobbers because they are barriers for code
1213 motion, however after inlining it is safe to do because local optimization
1214 passes do not consider clobbers from other functions.
1215 Similar logic is in ipa-pure-const.c. */
1216 if ((ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1217 return true;
1219 struct summary_ptrs sums = {summary, summary_lto};
1221 /* Analyze all loads and stores in STMT. */
1222 walk_stmt_load_store_ops (stmt, &sums,
1223 analyze_load, analyze_store);
1225 switch (gimple_code (stmt))
1227 case GIMPLE_ASM:
1228 /* If the ASM statement does not read nor write memory, there's nothing
1229 to do. Otherwise just give up. */
1230 if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1231 return true;
1232 if (dump_file)
1233 fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1234 "which clobbers memory.\n");
1235 return false;
1236 case GIMPLE_CALL:
1237 if (!ipa || gimple_call_internal_p (stmt))
1238 return analyze_call (summary, summary_lto,
1239 as_a <gcall *> (stmt), recursive_calls);
1240 else
1242 attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1244 if (fnspec.known_p ()
1245 && (!fnspec.global_memory_read_p ()
1246 || !fnspec.global_memory_written_p ()))
1248 fnspec_summaries->get_create
1249 (cgraph_node::get (current_function_decl)->get_edge (stmt))
1250 ->fnspec = xstrdup (fnspec.get_str ());
1251 if (dump_file)
1252 fprintf (dump_file, " Recorded fnspec %s\n", fnspec.get_str ());
1255 return true;
1256 default:
1257 /* Nothing to do for other types of statements. */
1258 return true;
1262 /* Remove summary of current function because during the function body
1263 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1264 mode of scan. */
1266 static void
1267 remove_summary (bool lto, bool nolto, bool ipa)
1269 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1270 if (!ipa)
1271 optimization_summaries->remove (fnode);
1272 else
1274 if (nolto)
1275 summaries->remove (fnode);
1276 if (lto)
1277 summaries_lto->remove (fnode);
1278 remove_modref_edge_summaries (fnode);
1280 if (dump_file)
1281 fprintf (dump_file,
1282 " - modref done with result: not tracked.\n");
1285 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1287 bool
1288 memory_access_to (tree op, tree ssa_name)
1290 tree base = get_base_address (op);
1291 if (!base)
1292 return false;
1293 if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1294 return false;
1295 return TREE_OPERAND (base, 0) == ssa_name;
1298 /* Consider statement val = *arg.
1299 return EAF flags of ARG that can be determined from EAF flags of VAL
1300 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1301 all stores to VAL, i.e. when handling noreturn function. */
1303 static int
1304 deref_flags (int flags, bool ignore_stores)
1306 int ret = 0;
1307 if (flags & EAF_UNUSED)
1308 ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE;
1309 else
1311 if ((flags & EAF_NOCLOBBER) || ignore_stores)
1312 ret |= EAF_NOCLOBBER;
1313 if ((flags & EAF_NOESCAPE) || ignore_stores)
1314 ret |= EAF_NOESCAPE;
1316 return ret;
1319 namespace {
1321 /* Description of an escape point. */
1323 struct escape_point
1325 /* Value escapes to this call. */
1326 gcall *call;
1327 /* Argument it escapes to. */
1328 int arg;
1329 /* Flags already known about the argument (this can save us from recording
1330 esape points if local analysis did good job already). */
1331 char min_flags;
1332 /* Does value escape directly or indiretly? */
1333 bool direct;
1336 class modref_lattice
1338 public:
1339 /* EAF flags of the SSA name. */
1340 int flags;
1341 /* DFS bookkkeeping: we don't do real dataflow yet. */
1342 bool known;
1343 bool open;
1345 /* When doing IPA analysis we can not merge in callee escape points;
1346 Only remember them and do the merging at IPA propagation time. */
1347 vec <escape_point, va_heap, vl_ptr> escape_points;
1349 void init ();
1350 void release ();
1351 bool merge (const modref_lattice &with);
1352 bool merge (int flags);
1353 bool merge_deref (const modref_lattice &with, bool ignore_stores);
1354 bool merge_direct_load ();
1355 bool merge_direct_store ();
1356 bool add_escape_point (gcall *call, int arg, int min_flags, bool diret);
1357 void dump (FILE *out, int indent = 0) const;
1360 /* Lattices are saved to vectors, so keep them PODs. */
1361 void
1362 modref_lattice::init ()
1364 flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED;
1365 open = true;
1366 known = false;
1369 /* Release memory. */
1370 void
1371 modref_lattice::release ()
1373 escape_points.release ();
1376 /* Dump lattice to OUT; indent with INDENT spaces. */
1378 void
1379 modref_lattice::dump (FILE *out, int indent) const
1381 dump_eaf_flags (out, flags);
1382 if (escape_points.length ())
1384 fprintf (out, "%*sEscapes:\n", indent, "");
1385 for (unsigned int i = 0; i < escape_points.length (); i++)
1387 fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
1388 escape_points[i].arg,
1389 escape_points[i].direct ? "direct" : "indirect");
1390 dump_eaf_flags (out, flags, false);
1391 fprintf (out, " in call ");
1392 print_gimple_stmt (out, escape_points[i].call, 0);
1397 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1398 point exists. */
1400 bool
1401 modref_lattice::add_escape_point (gcall *call, int arg, int min_flags,
1402 bool direct)
1404 escape_point *ep;
1405 unsigned int i;
1407 /* If we already determined flags to be bad enough,
1408 * we do not need to record. */
1409 if ((flags & min_flags) == flags)
1410 return false;
1412 FOR_EACH_VEC_ELT (escape_points, i, ep)
1413 if (ep->call == call && ep->arg == arg && ep->direct == direct)
1415 if ((ep->min_flags & min_flags) == min_flags)
1416 return false;
1417 ep->min_flags &= min_flags;
1418 return true;
1420 /* Give up if max escape points is met. */
1421 if ((int)escape_points.length () > param_modref_max_escape_points)
1423 if (dump_file)
1424 fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
1425 merge (0);
1426 return true;
1428 escape_point new_ep = {call, arg, min_flags, direct};
1429 escape_points.safe_push (new_ep);
1430 return true;
1433 /* Merge in flags from F. */
1434 bool
1435 modref_lattice::merge (int f)
1437 if ((flags & f) != flags)
1439 flags &= f;
1440 /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
1441 in tree-ssa-alias.c). Give up earlier. */
1442 if ((flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
1443 flags = 0;
1444 if (!flags)
1445 escape_points.release ();
1446 return true;
1448 return false;
1451 /* Merge in WITH. Return true if anyting changed. */
1453 bool
1454 modref_lattice::merge (const modref_lattice &with)
1456 if (!with.known)
1457 return merge (0);
1459 bool changed = merge (with.flags);
1461 if (!flags)
1462 return changed;
1463 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1464 changed |= add_escape_point (with.escape_points[i].call,
1465 with.escape_points[i].arg,
1466 with.escape_points[i].min_flags,
1467 with.escape_points[i].direct);
1468 return changed;
1471 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1472 stores. Return true if anyting changed. */
1474 bool
1475 modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
1477 if (!with.known)
1478 return merge (0);
1480 bool changed = merge (deref_flags (with.flags, ignore_stores));
1482 if (!flags)
1483 return changed;
1484 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1485 changed |= add_escape_point (with.escape_points[i].call,
1486 with.escape_points[i].arg,
1487 with.escape_points[i].min_flags,
1488 false);
1489 return changed;
1492 /* Merge in flags for direct load. */
1494 bool
1495 modref_lattice::merge_direct_load ()
1497 return merge (~EAF_UNUSED);
1500 /* Merge in flags for direct store. */
1502 bool
1503 modref_lattice::merge_direct_store ()
1505 return merge (~(EAF_UNUSED | EAF_NOCLOBBER));
1508 } /* ANON namespace. */
1510 static void analyze_ssa_name_flags (tree name,
1511 vec<modref_lattice> &lattice,
1512 int depth, bool ipa);
1514 /* Call statements may return their parameters. Consider argument number
1515 ARG of USE_STMT and determine flags that can needs to be cleared
1516 in case pointer possibly indirectly references from ARG I is returned.
1517 LATTICE, DEPTH and ipa are same as in analyze_ssa_name_flags. */
1519 static void
1520 merge_call_lhs_flags (gcall *call, int arg, int index, bool deref,
1521 vec<modref_lattice> &lattice,
1522 int depth, bool ipa)
1524 /* If there is no return value, no flags are affected. */
1525 if (!gimple_call_lhs (call))
1526 return;
1528 /* If we know that function returns given argument and it is not ARG
1529 we can still be happy. */
1530 int flags = gimple_call_return_flags (call);
1531 if ((flags & ERF_RETURNS_ARG)
1532 && (flags & ERF_RETURN_ARG_MASK) != arg)
1533 return;
1535 /* If return value is SSA name determine its flags. */
1536 if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
1538 tree lhs = gimple_call_lhs (call);
1539 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1540 if (deref)
1541 lattice[index].merge (lattice[SSA_NAME_VERSION (lhs)]);
1542 else
1543 lattice[index].merge_deref (lattice[SSA_NAME_VERSION (lhs)], false);
1545 /* In the case of memory store we can do nothing. */
1546 else
1547 lattice[index].merge (0);
1550 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
1551 LATTICE is an array of modref_lattices.
1552 DEPTH is a recursion depth used to make debug output prettier.
1553 If IPA is true we analyze for IPA propagation (and thus call escape points
1554 are processed later) */
1556 static void
1557 analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
1558 bool ipa)
1560 imm_use_iterator ui;
1561 gimple *use_stmt;
1562 int index = SSA_NAME_VERSION (name);
1564 /* See if value is already computed. */
1565 if (lattice[index].known)
1566 return;
1567 if (lattice[index].open)
1569 if (dump_file)
1570 fprintf (dump_file,
1571 "%*sGiving up on a cycle in SSA graph\n", depth * 4, "");
1572 return;
1574 if (depth == param_modref_max_depth)
1576 if (dump_file)
1577 fprintf (dump_file,
1578 "%*sGiving up on max depth\n", depth * 4, "");
1579 return;
1581 /* Recursion guard. */
1582 lattice[index].init ();
1584 if (dump_file)
1586 fprintf (dump_file,
1587 "%*sAnalyzing flags of ssa name: ", depth * 4, "");
1588 print_generic_expr (dump_file, name);
1589 fprintf (dump_file, "\n");
1592 FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
1594 if (lattice[index].flags == 0)
1596 BREAK_FROM_IMM_USE_STMT (ui);
1598 if (is_gimple_debug (use_stmt))
1599 continue;
1600 if (dump_file)
1602 fprintf (dump_file, "%*s Analyzing stmt:", depth * 4, "");
1603 print_gimple_stmt (dump_file, use_stmt, 0);
1606 /* Gimple return may load the return value.
1607 Returning name counts as an use by tree-ssa-structalias.c */
1608 if (greturn *ret = dyn_cast <greturn *> (use_stmt))
1610 if (gimple_return_retval (ret) == name)
1611 lattice[index].merge (~EAF_UNUSED);
1612 else if (memory_access_to (gimple_return_retval (ret), name))
1613 lattice[index].merge_direct_load ();
1615 /* Account for LHS store, arg loads and flags from callee function. */
1616 else if (gcall *call = dyn_cast <gcall *> (use_stmt))
1618 tree callee = gimple_call_fndecl (call);
1620 /* Recursion would require bit of propagation; give up for now. */
1621 if (callee && !ipa && recursive_call_p (current_function_decl,
1622 callee))
1623 lattice[index].merge (0);
1624 else
1626 int ecf_flags = gimple_call_flags (call);
1627 bool ignore_stores = ignore_stores_p (current_function_decl,
1628 ecf_flags);
1629 bool ignore_retval = ignore_retval_p (current_function_decl,
1630 ecf_flags);
1632 /* Handle *name = func (...). */
1633 if (gimple_call_lhs (call)
1634 && memory_access_to (gimple_call_lhs (call), name))
1635 lattice[index].merge_direct_store ();
1637 /* We do not track accesses to the static chain (we could)
1638 so give up. */
1639 if (gimple_call_chain (call)
1640 && (gimple_call_chain (call) == name))
1641 lattice[index].merge (0);
1643 /* Process internal functions and right away. */
1644 bool record_ipa = ipa && !gimple_call_internal_p (call);
1646 /* Handle all function parameters. */
1647 for (unsigned i = 0;
1648 i < gimple_call_num_args (call) && lattice[index].flags; i++)
1649 /* Name is directly passed to the callee. */
1650 if (gimple_call_arg (call, i) == name)
1652 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
1654 int call_flags = gimple_call_arg_flags (call, i);
1655 if (ignore_stores)
1656 call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
1658 if (!record_ipa)
1659 lattice[index].merge (call_flags);
1660 if (record_ipa)
1661 lattice[index].add_escape_point (call, i,
1662 call_flags, true);
1664 if (!ignore_retval)
1665 merge_call_lhs_flags (call, i, index, false,
1666 lattice, depth, ipa);
1668 /* Name is dereferenced and passed to a callee. */
1669 else if (memory_access_to (gimple_call_arg (call, i), name))
1671 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
1672 lattice[index].merge_direct_load ();
1673 else
1675 int call_flags = deref_flags
1676 (gimple_call_arg_flags (call, i), ignore_stores);
1677 if (!record_ipa)
1678 lattice[index].merge (call_flags);
1679 if (record_ipa)
1680 lattice[index].add_escape_point (call, i,
1681 call_flags, false);
1683 if (!ignore_retval)
1684 merge_call_lhs_flags (call, i, index, true,
1685 lattice, depth, ipa);
1689 else if (gimple_assign_load_p (use_stmt))
1691 gassign *assign = as_a <gassign *> (use_stmt);
1692 /* Memory to memory copy. */
1693 if (gimple_store_p (assign))
1695 /* Handle *lhs = *name.
1697 We do not track memory locations, so assume that value
1698 is used arbitrarily. */
1699 if (memory_access_to (gimple_assign_rhs1 (assign), name))
1700 lattice[index].merge (0);
1701 /* Handle *name = *exp. */
1702 else if (memory_access_to (gimple_assign_lhs (assign), name))
1703 lattice[index].merge_direct_store ();
1705 /* Handle lhs = *name. */
1706 else if (memory_access_to (gimple_assign_rhs1 (assign), name))
1708 tree lhs = gimple_assign_lhs (assign);
1709 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1710 lattice[index].merge_deref (lattice[SSA_NAME_VERSION (lhs)],
1711 false);
1714 else if (gimple_store_p (use_stmt))
1716 gassign *assign = dyn_cast <gassign *> (use_stmt);
1718 /* Handle *lhs = name. */
1719 if (assign && gimple_assign_rhs1 (assign) == name)
1721 if (dump_file)
1722 fprintf (dump_file, "%*s ssa name saved to memory\n",
1723 depth * 4, "");
1724 lattice[index].merge (0);
1726 /* Handle *name = exp. */
1727 else if (assign
1728 && memory_access_to (gimple_assign_lhs (assign), name))
1730 /* In general we can not ignore clobbers because they are
1731 barriers for code motion, however after inlining it is safe to
1732 do because local optimization passes do not consider clobbers
1733 from other functions. Similar logic is in ipa-pure-const.c. */
1734 if (!cfun->after_inlining || !gimple_clobber_p (assign))
1735 lattice[index].merge_direct_store ();
1737 /* ASM statements etc. */
1738 else if (!assign)
1740 if (dump_file)
1741 fprintf (dump_file, "%*s Unhandled store\n",
1742 depth * 4, "");
1743 lattice[index].merge (0);
1746 else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
1748 enum tree_code code = gimple_assign_rhs_code (assign);
1750 /* See if operation is a merge as considered by
1751 tree-ssa-structalias.c:find_func_aliases. */
1752 if (!truth_value_p (code)
1753 && code != POINTER_DIFF_EXPR
1754 && (code != POINTER_PLUS_EXPR
1755 || gimple_assign_rhs1 (assign) == name))
1757 tree lhs = gimple_assign_lhs (assign);
1758 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1759 lattice[index].merge (lattice[SSA_NAME_VERSION (lhs)]);
1762 else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
1764 tree result = gimple_phi_result (phi);
1765 analyze_ssa_name_flags (result, lattice, depth + 1, ipa);
1766 lattice[index].merge (lattice[SSA_NAME_VERSION (result)]);
1768 /* Conditions are not considered escape points
1769 by tree-ssa-structalias. */
1770 else if (gimple_code (use_stmt) == GIMPLE_COND)
1772 else
1774 if (dump_file)
1775 fprintf (dump_file, "%*s Unhandled stmt\n", depth * 4, "");
1776 lattice[index].merge (0);
1779 if (dump_file)
1781 fprintf (dump_file, "%*s current flags of ", depth * 4, "");
1782 print_generic_expr (dump_file, name);
1783 lattice[index].dump (dump_file, depth * 4 + 4);
1786 if (dump_file)
1788 fprintf (dump_file, "%*sflags of ssa name ", depth * 4, "");
1789 print_generic_expr (dump_file, name);
1790 lattice[index].dump (dump_file, depth * 4 + 2);
1792 lattice[index].open = false;
1793 lattice[index].known = true;
1796 /* Determine EAF flags for function parameters. */
1798 static void
1799 analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
1800 bool ipa)
1802 unsigned int parm_index = 0;
1803 unsigned int count = 0;
1804 int ecf_flags = flags_from_decl_or_type (current_function_decl);
1806 /* For const functions we have nothing to gain by EAF flags. */
1807 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
1808 return;
1810 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
1811 parm = TREE_CHAIN (parm))
1812 count++;
1814 if (!count)
1815 return;
1817 auto_vec<modref_lattice> lattice;
1818 lattice.safe_grow_cleared (num_ssa_names, true);
1820 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
1821 parm = TREE_CHAIN (parm))
1823 tree name = ssa_default_def (cfun, parm);
1824 if (!name)
1825 continue;
1826 analyze_ssa_name_flags (name, lattice, 0, ipa);
1827 int flags = lattice[SSA_NAME_VERSION (name)].flags;
1829 /* For pure functions we have implicit NOCLOBBER
1830 and NOESCAPE. */
1831 if (ecf_flags & ECF_PURE)
1832 flags &= ~(EAF_NOCLOBBER | EAF_NOESCAPE);
1834 if (flags)
1836 if (summary)
1838 if (parm_index >= summary->arg_flags.length ())
1839 summary->arg_flags.safe_grow_cleared (count, true);
1840 summary->arg_flags[parm_index] = flags;
1842 else if (summary_lto)
1844 if (parm_index >= summary_lto->arg_flags.length ())
1845 summary_lto->arg_flags.safe_grow_cleared (count, true);
1846 summary_lto->arg_flags[parm_index] = flags;
1848 if (lattice[SSA_NAME_VERSION (name)].escape_points.length ())
1850 escape_point *ep;
1851 unsigned int ip;
1852 cgraph_node *node = cgraph_node::get (current_function_decl);
1854 gcc_checking_assert (ipa);
1855 FOR_EACH_VEC_ELT
1856 (lattice[SSA_NAME_VERSION (name)].escape_points, ip, ep)
1857 if ((ep->min_flags & flags) != flags)
1859 cgraph_edge *e = node->get_edge (ep->call);
1860 struct escape_entry ee = {parm_index, ep->arg,
1861 ep->min_flags, ep->direct};
1863 escape_summaries->get_create (e)->esc.safe_push (ee);
1868 if (ipa)
1869 for (unsigned int i = 0; i < num_ssa_names; i++)
1870 lattice[i].release ();
1873 /* Analyze function F. IPA indicates whether we're running in local mode
1874 (false) or the IPA mode (true). */
1876 static void
1877 analyze_function (function *f, bool ipa)
1879 if (dump_file)
1880 fprintf (dump_file, "modref analyzing '%s' (ipa=%i)%s%s\n",
1881 function_name (f), ipa,
1882 TREE_READONLY (current_function_decl) ? " (const)" : "",
1883 DECL_PURE_P (current_function_decl) ? " (pure)" : "");
1885 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
1886 if (!flag_ipa_modref)
1887 return;
1889 /* Compute no-LTO summaries when local optimization is going to happen. */
1890 bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
1891 || (in_lto_p && !flag_wpa
1892 && flag_incremental_link != INCREMENTAL_LINK_LTO));
1893 /* Compute LTO when LTO streaming is going to happen. */
1894 bool lto = ipa && ((flag_lto && !in_lto_p)
1895 || flag_wpa
1896 || flag_incremental_link == INCREMENTAL_LINK_LTO);
1897 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1899 modref_summary *summary = NULL;
1900 modref_summary_lto *summary_lto = NULL;
1902 /* Initialize the summary.
1903 If we run in local mode there is possibly pre-existing summary from
1904 IPA pass. Dump it so it is easy to compare if mod-ref info has
1905 improved. */
1906 if (!ipa)
1908 if (!optimization_summaries)
1909 optimization_summaries = modref_summaries::create_ggc (symtab);
1910 else /* Remove existing summary if we are re-running the pass. */
1912 if (dump_file
1913 && (summary
1914 = optimization_summaries->get (cgraph_node::get (f->decl)))
1915 != NULL
1916 && summary->loads)
1918 fprintf (dump_file, "Past summary:\n");
1919 optimization_summaries->get
1920 (cgraph_node::get (f->decl))->dump (dump_file);
1922 optimization_summaries->remove (cgraph_node::get (f->decl));
1924 summary = optimization_summaries->get_create (cgraph_node::get (f->decl));
1925 gcc_checking_assert (nolto && !lto);
1927 /* In IPA mode we analyze every function precisely once. Assert that. */
1928 else
1930 if (nolto)
1932 if (!summaries)
1933 summaries = modref_summaries::create_ggc (symtab);
1934 else
1935 summaries->remove (cgraph_node::get (f->decl));
1936 summary = summaries->get_create (cgraph_node::get (f->decl));
1938 if (lto)
1940 if (!summaries_lto)
1941 summaries_lto = modref_summaries_lto::create_ggc (symtab);
1942 else
1943 summaries_lto->remove (cgraph_node::get (f->decl));
1944 summary_lto = summaries_lto->get_create (cgraph_node::get (f->decl));
1946 if (!fnspec_summaries)
1947 fnspec_summaries = new fnspec_summaries_t (symtab);
1948 if (!escape_summaries)
1949 escape_summaries = new escape_summaries_t (symtab);
1953 /* Create and initialize summary for F.
1954 Note that summaries may be already allocated from previous
1955 run of the pass. */
1956 if (nolto)
1958 gcc_assert (!summary->loads);
1959 summary->loads = modref_records::create_ggc (param_modref_max_bases,
1960 param_modref_max_refs,
1961 param_modref_max_accesses);
1962 gcc_assert (!summary->stores);
1963 summary->stores = modref_records::create_ggc (param_modref_max_bases,
1964 param_modref_max_refs,
1965 param_modref_max_accesses);
1966 summary->writes_errno = false;
1968 if (lto)
1970 gcc_assert (!summary_lto->loads);
1971 summary_lto->loads = modref_records_lto::create_ggc
1972 (param_modref_max_bases,
1973 param_modref_max_refs,
1974 param_modref_max_accesses);
1975 gcc_assert (!summary_lto->stores);
1976 summary_lto->stores = modref_records_lto::create_ggc
1977 (param_modref_max_bases,
1978 param_modref_max_refs,
1979 param_modref_max_accesses);
1980 summary_lto->writes_errno = false;
1983 analyze_parms (summary, summary_lto, ipa);
1985 int ecf_flags = flags_from_decl_or_type (current_function_decl);
1986 auto_vec <gimple *, 32> recursive_calls;
1988 /* Analyze each statement in each basic block of the function. If the
1989 statement cannot be analyzed (for any reason), the entire function cannot
1990 be analyzed by modref. */
1991 basic_block bb;
1992 FOR_EACH_BB_FN (bb, f)
1994 gimple_stmt_iterator si;
1995 for (si = gsi_after_labels (bb); !gsi_end_p (si); gsi_next (&si))
1997 if (!analyze_stmt (summary, summary_lto,
1998 gsi_stmt (si), ipa, &recursive_calls)
1999 || ((!summary || !summary->useful_p (ecf_flags, false))
2000 && (!summary_lto
2001 || !summary_lto->useful_p (ecf_flags, false))))
2003 collapse_loads (summary, summary_lto);
2004 collapse_stores (summary, summary_lto);
2005 break;
2010 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2011 This needs to be done after all other side effects are computed. */
2012 if (!ipa)
2014 bool changed = true;
2015 while (changed)
2017 changed = false;
2018 for (unsigned i = 0; i < recursive_calls.length (); i++)
2020 changed |= merge_call_side_effects
2021 (summary, recursive_calls[i], summary,
2022 ignore_stores_p (current_function_decl,
2023 gimple_call_flags
2024 (recursive_calls[i])),
2025 fnode);
2026 if (!summary->useful_p (ecf_flags, false))
2028 remove_summary (lto, nolto, ipa);
2029 return;
2034 if (summary && !summary->useful_p (ecf_flags))
2036 if (!ipa)
2037 optimization_summaries->remove (fnode);
2038 else
2039 summaries->remove (fnode);
2040 summary = NULL;
2042 if (summary_lto && !summary_lto->useful_p (ecf_flags))
2044 summaries_lto->remove (fnode);
2045 summary_lto = NULL;
2047 if (ipa && !summary && !summary_lto)
2048 remove_modref_edge_summaries (fnode);
2050 if (dump_file)
2052 fprintf (dump_file, " - modref done with result: tracked.\n");
2053 if (summary)
2054 summary->dump (dump_file);
2055 if (summary_lto)
2056 summary_lto->dump (dump_file);
2057 dump_modref_edge_summaries (dump_file, fnode, 2);
2061 /* Callback for generate_summary. */
2063 static void
2064 modref_generate (void)
2066 struct cgraph_node *node;
2067 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
2069 function *f = DECL_STRUCT_FUNCTION (node->decl);
2070 if (!f)
2071 continue;
2072 push_cfun (f);
2073 analyze_function (f, true);
2074 pop_cfun ();
2078 /* Called when a new function is inserted to callgraph late. */
2080 void
2081 modref_summaries::insert (struct cgraph_node *node, modref_summary *)
2083 /* Local passes ought to be executed by the pass manager. */
2084 if (this == optimization_summaries)
2086 optimization_summaries->remove (node);
2087 return;
2089 if (!DECL_STRUCT_FUNCTION (node->decl)
2090 || !opt_for_fn (node->decl, flag_ipa_modref))
2092 summaries->remove (node);
2093 return;
2095 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2096 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2097 pop_cfun ();
2100 /* Called when a new function is inserted to callgraph late. */
2102 void
2103 modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
2105 /* We do not support adding new function when IPA information is already
2106 propagated. This is done only by SIMD cloning that is not very
2107 critical. */
2108 if (!DECL_STRUCT_FUNCTION (node->decl)
2109 || !opt_for_fn (node->decl, flag_ipa_modref)
2110 || propagated)
2112 summaries_lto->remove (node);
2113 return;
2115 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2116 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2117 pop_cfun ();
2120 /* Called when new clone is inserted to callgraph late. */
2122 void
2123 modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
2124 modref_summary *src_data,
2125 modref_summary *dst_data)
2127 /* Do not duplicate optimization summaries; we do not handle parameter
2128 transforms on them. */
2129 if (this == optimization_summaries)
2131 optimization_summaries->remove (dst);
2132 return;
2134 dst_data->stores = modref_records::create_ggc
2135 (src_data->stores->max_bases,
2136 src_data->stores->max_refs,
2137 src_data->stores->max_accesses);
2138 dst_data->stores->copy_from (src_data->stores);
2139 dst_data->loads = modref_records::create_ggc
2140 (src_data->loads->max_bases,
2141 src_data->loads->max_refs,
2142 src_data->loads->max_accesses);
2143 dst_data->loads->copy_from (src_data->loads);
2144 dst_data->writes_errno = src_data->writes_errno;
2147 /* Called when new clone is inserted to callgraph late. */
2149 void
2150 modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
2151 modref_summary_lto *src_data,
2152 modref_summary_lto *dst_data)
2154 /* Be sure that no further cloning happens after ipa-modref. If it does
2155 we will need to update signatures for possible param changes. */
2156 gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
2157 dst_data->stores = modref_records_lto::create_ggc
2158 (src_data->stores->max_bases,
2159 src_data->stores->max_refs,
2160 src_data->stores->max_accesses);
2161 dst_data->stores->copy_from (src_data->stores);
2162 dst_data->loads = modref_records_lto::create_ggc
2163 (src_data->loads->max_bases,
2164 src_data->loads->max_refs,
2165 src_data->loads->max_accesses);
2166 dst_data->loads->copy_from (src_data->loads);
2167 dst_data->writes_errno = src_data->writes_errno;
2170 namespace
2172 /* Definition of the modref pass on GIMPLE. */
2173 const pass_data pass_data_modref = {
2174 GIMPLE_PASS,
2175 "modref",
2176 OPTGROUP_IPA,
2177 TV_TREE_MODREF,
2178 (PROP_cfg | PROP_ssa),
2185 class pass_modref : public gimple_opt_pass
2187 public:
2188 pass_modref (gcc::context *ctxt)
2189 : gimple_opt_pass (pass_data_modref, ctxt) {}
2191 /* opt_pass methods: */
2192 opt_pass *clone ()
2194 return new pass_modref (m_ctxt);
2196 virtual bool gate (function *)
2198 return flag_ipa_modref;
2200 virtual unsigned int execute (function *);
2203 /* Encode TT to the output block OB using the summary streaming API. */
2205 static void
2206 write_modref_records (modref_records_lto *tt, struct output_block *ob)
2208 streamer_write_uhwi (ob, tt->max_bases);
2209 streamer_write_uhwi (ob, tt->max_refs);
2210 streamer_write_uhwi (ob, tt->max_accesses);
2212 streamer_write_uhwi (ob, tt->every_base);
2213 streamer_write_uhwi (ob, vec_safe_length (tt->bases));
2214 size_t i;
2215 modref_base_node <tree> *base_node;
2216 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, base_node)
2218 stream_write_tree (ob, base_node->base, true);
2220 streamer_write_uhwi (ob, base_node->every_ref);
2221 streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
2223 size_t j;
2224 modref_ref_node <tree> *ref_node;
2225 FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
2227 stream_write_tree (ob, ref_node->ref, true);
2228 streamer_write_uhwi (ob, ref_node->every_access);
2229 streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
2231 size_t k;
2232 modref_access_node *access_node;
2233 FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
2235 streamer_write_hwi (ob, access_node->parm_index);
2236 if (access_node->parm_index != -1)
2238 streamer_write_uhwi (ob, access_node->parm_offset_known);
2239 if (access_node->parm_offset_known)
2241 streamer_write_poly_int64 (ob, access_node->parm_offset);
2242 streamer_write_poly_int64 (ob, access_node->offset);
2243 streamer_write_poly_int64 (ob, access_node->size);
2244 streamer_write_poly_int64 (ob, access_node->max_size);
2252 /* Read a modref_tree from the input block IB using the data from DATA_IN.
2253 This assumes that the tree was encoded using write_modref_tree.
2254 Either nolto_ret or lto_ret is initialized by the tree depending whether
2255 LTO streaming is expected or not. */
2257 void
2258 read_modref_records (lto_input_block *ib, struct data_in *data_in,
2259 modref_records **nolto_ret,
2260 modref_records_lto **lto_ret)
2262 size_t max_bases = streamer_read_uhwi (ib);
2263 size_t max_refs = streamer_read_uhwi (ib);
2264 size_t max_accesses = streamer_read_uhwi (ib);
2266 if (lto_ret)
2267 *lto_ret = modref_records_lto::create_ggc (max_bases, max_refs,
2268 max_accesses);
2269 if (nolto_ret)
2270 *nolto_ret = modref_records::create_ggc (max_bases, max_refs,
2271 max_accesses);
2272 gcc_checking_assert (lto_ret || nolto_ret);
2274 size_t every_base = streamer_read_uhwi (ib);
2275 size_t nbase = streamer_read_uhwi (ib);
2277 gcc_assert (!every_base || nbase == 0);
2278 if (every_base)
2280 if (nolto_ret)
2281 (*nolto_ret)->collapse ();
2282 if (lto_ret)
2283 (*lto_ret)->collapse ();
2285 for (size_t i = 0; i < nbase; i++)
2287 tree base_tree = stream_read_tree (ib, data_in);
2288 modref_base_node <alias_set_type> *nolto_base_node = NULL;
2289 modref_base_node <tree> *lto_base_node = NULL;
2291 /* At stream in time we have LTO alias info. Check if we streamed in
2292 something obviously unnecessary. Do not glob types by alias sets;
2293 it is not 100% clear that ltrans types will get merged same way.
2294 Types may get refined based on ODR type conflicts. */
2295 if (base_tree && !get_alias_set (base_tree))
2297 if (dump_file)
2299 fprintf (dump_file, "Streamed in alias set 0 type ");
2300 print_generic_expr (dump_file, base_tree);
2301 fprintf (dump_file, "\n");
2303 base_tree = NULL;
2306 if (nolto_ret)
2307 nolto_base_node = (*nolto_ret)->insert_base (base_tree
2308 ? get_alias_set (base_tree)
2309 : 0);
2310 if (lto_ret)
2311 lto_base_node = (*lto_ret)->insert_base (base_tree);
2312 size_t every_ref = streamer_read_uhwi (ib);
2313 size_t nref = streamer_read_uhwi (ib);
2315 gcc_assert (!every_ref || nref == 0);
2316 if (every_ref)
2318 if (nolto_base_node)
2319 nolto_base_node->collapse ();
2320 if (lto_base_node)
2321 lto_base_node->collapse ();
2323 for (size_t j = 0; j < nref; j++)
2325 tree ref_tree = stream_read_tree (ib, data_in);
2327 if (ref_tree && !get_alias_set (ref_tree))
2329 if (dump_file)
2331 fprintf (dump_file, "Streamed in alias set 0 type ");
2332 print_generic_expr (dump_file, ref_tree);
2333 fprintf (dump_file, "\n");
2335 ref_tree = NULL;
2338 modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
2339 modref_ref_node <tree> *lto_ref_node = NULL;
2341 if (nolto_base_node)
2342 nolto_ref_node
2343 = nolto_base_node->insert_ref (ref_tree
2344 ? get_alias_set (ref_tree) : 0,
2345 max_refs);
2346 if (lto_base_node)
2347 lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
2349 size_t every_access = streamer_read_uhwi (ib);
2350 size_t naccesses = streamer_read_uhwi (ib);
2352 if (nolto_ref_node)
2353 nolto_ref_node->every_access = every_access;
2354 if (lto_ref_node)
2355 lto_ref_node->every_access = every_access;
2357 for (size_t k = 0; k < naccesses; k++)
2359 int parm_index = streamer_read_hwi (ib);
2360 bool parm_offset_known = false;
2361 poly_int64 parm_offset = 0;
2362 poly_int64 offset = 0;
2363 poly_int64 size = -1;
2364 poly_int64 max_size = -1;
2366 if (parm_index != -1)
2368 parm_offset_known = streamer_read_uhwi (ib);
2369 if (parm_offset_known)
2371 parm_offset = streamer_read_poly_int64 (ib);
2372 offset = streamer_read_poly_int64 (ib);
2373 size = streamer_read_poly_int64 (ib);
2374 max_size = streamer_read_poly_int64 (ib);
2377 modref_access_node a = {offset, size, max_size, parm_offset,
2378 parm_index, parm_offset_known};
2379 if (nolto_ref_node)
2380 nolto_ref_node->insert_access (a, max_accesses);
2381 if (lto_ref_node)
2382 lto_ref_node->insert_access (a, max_accesses);
2386 if (lto_ret)
2387 (*lto_ret)->cleanup ();
2388 if (nolto_ret)
2389 (*nolto_ret)->cleanup ();
2392 /* Write ESUM to BP. */
2394 static void
2395 modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
2397 if (!esum)
2399 bp_pack_var_len_unsigned (bp, 0);
2400 return;
2402 bp_pack_var_len_unsigned (bp, esum->esc.length ());
2403 unsigned int i;
2404 escape_entry *ee;
2405 FOR_EACH_VEC_ELT (esum->esc, i, ee)
2407 bp_pack_var_len_unsigned (bp, ee->parm_index);
2408 bp_pack_var_len_unsigned (bp, ee->arg);
2409 bp_pack_var_len_unsigned (bp, ee->min_flags);
2410 bp_pack_value (bp, ee->direct, 1);
2414 /* Read escape summary for E from BP. */
2416 static void
2417 modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
2419 unsigned int n = bp_unpack_var_len_unsigned (bp);
2420 if (!n)
2421 return;
2422 escape_summary *esum = escape_summaries->get_create (e);
2423 esum->esc.reserve_exact (n);
2424 for (unsigned int i = 0; i < n; i++)
2426 escape_entry ee;
2427 ee.parm_index = bp_unpack_var_len_unsigned (bp);
2428 ee.arg = bp_unpack_var_len_unsigned (bp);
2429 ee.min_flags = bp_unpack_var_len_unsigned (bp);
2430 ee.direct = bp_unpack_value (bp, 1);
2431 esum->esc.quick_push (ee);
2435 /* Callback for write_summary. */
2437 static void
2438 modref_write ()
2440 struct output_block *ob = create_output_block (LTO_section_ipa_modref);
2441 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
2442 unsigned int count = 0;
2443 int i;
2445 if (!summaries_lto)
2447 streamer_write_uhwi (ob, 0);
2448 streamer_write_char_stream (ob->main_stream, 0);
2449 produce_asm (ob, NULL);
2450 destroy_output_block (ob);
2451 return;
2454 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
2456 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
2457 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
2458 modref_summary_lto *r;
2460 if (cnode && cnode->definition && !cnode->alias
2461 && (r = summaries_lto->get (cnode))
2462 && r->useful_p (flags_from_decl_or_type (cnode->decl)))
2463 count++;
2465 streamer_write_uhwi (ob, count);
2467 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
2469 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
2470 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
2472 if (cnode && cnode->definition && !cnode->alias)
2474 modref_summary_lto *r = summaries_lto->get (cnode);
2476 if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
2477 continue;
2479 streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
2481 streamer_write_uhwi (ob, r->arg_flags.length ());
2482 for (unsigned int i = 0; i < r->arg_flags.length (); i++)
2483 streamer_write_char_stream (ob->main_stream, r->arg_flags[i]);
2485 write_modref_records (r->loads, ob);
2486 write_modref_records (r->stores, ob);
2488 struct bitpack_d bp = bitpack_create (ob->main_stream);
2489 bp_pack_value (&bp, r->writes_errno, 1);
2490 if (!flag_wpa)
2492 for (cgraph_edge *e = cnode->indirect_calls;
2493 e; e = e->next_callee)
2495 class fnspec_summary *sum = fnspec_summaries->get (e);
2496 bp_pack_value (&bp, sum != NULL, 1);
2497 if (sum)
2498 bp_pack_string (ob, &bp, sum->fnspec, true);
2499 class escape_summary *esum = escape_summaries->get (e);
2500 modref_write_escape_summary (&bp,esum);
2502 for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
2504 class fnspec_summary *sum = fnspec_summaries->get (e);
2505 bp_pack_value (&bp, sum != NULL, 1);
2506 if (sum)
2507 bp_pack_string (ob, &bp, sum->fnspec, true);
2508 class escape_summary *esum = escape_summaries->get (e);
2509 modref_write_escape_summary (&bp,esum);
2512 streamer_write_bitpack (&bp);
2515 streamer_write_char_stream (ob->main_stream, 0);
2516 produce_asm (ob, NULL);
2517 destroy_output_block (ob);
2520 static void
2521 read_section (struct lto_file_decl_data *file_data, const char *data,
2522 size_t len)
2524 const struct lto_function_header *header
2525 = (const struct lto_function_header *) data;
2526 const int cfg_offset = sizeof (struct lto_function_header);
2527 const int main_offset = cfg_offset + header->cfg_size;
2528 const int string_offset = main_offset + header->main_size;
2529 struct data_in *data_in;
2530 unsigned int i;
2531 unsigned int f_count;
2533 lto_input_block ib ((const char *) data + main_offset, header->main_size,
2534 file_data->mode_table);
2536 data_in
2537 = lto_data_in_create (file_data, (const char *) data + string_offset,
2538 header->string_size, vNULL);
2539 f_count = streamer_read_uhwi (&ib);
2540 for (i = 0; i < f_count; i++)
2542 struct cgraph_node *node;
2543 lto_symtab_encoder_t encoder;
2545 unsigned int index = streamer_read_uhwi (&ib);
2546 encoder = file_data->symtab_node_encoder;
2547 node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
2548 index));
2550 modref_summary *modref_sum = summaries
2551 ? summaries->get_create (node) : NULL;
2552 modref_summary_lto *modref_sum_lto = summaries_lto
2553 ? summaries_lto->get_create (node)
2554 : NULL;
2555 if (optimization_summaries)
2556 modref_sum = optimization_summaries->get_create (node);
2558 if (modref_sum)
2559 modref_sum->writes_errno = false;
2560 if (modref_sum_lto)
2561 modref_sum_lto->writes_errno = false;
2563 gcc_assert (!modref_sum || (!modref_sum->loads
2564 && !modref_sum->stores));
2565 gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
2566 && !modref_sum_lto->stores));
2567 unsigned int args = streamer_read_uhwi (&ib);
2568 if (args && modref_sum)
2569 modref_sum->arg_flags.reserve_exact (args);
2570 if (args && modref_sum_lto)
2571 modref_sum_lto->arg_flags.reserve_exact (args);
2572 for (unsigned int i = 0; i < args; i++)
2574 unsigned char flags = streamer_read_uchar (&ib);
2575 if (modref_sum)
2576 modref_sum->arg_flags.quick_push (flags);
2577 if (modref_sum_lto)
2578 modref_sum_lto->arg_flags.quick_push (flags);
2580 read_modref_records (&ib, data_in,
2581 modref_sum ? &modref_sum->loads : NULL,
2582 modref_sum_lto ? &modref_sum_lto->loads : NULL);
2583 read_modref_records (&ib, data_in,
2584 modref_sum ? &modref_sum->stores : NULL,
2585 modref_sum_lto ? &modref_sum_lto->stores : NULL);
2586 struct bitpack_d bp = streamer_read_bitpack (&ib);
2587 if (bp_unpack_value (&bp, 1))
2589 if (modref_sum)
2590 modref_sum->writes_errno = true;
2591 if (modref_sum_lto)
2592 modref_sum_lto->writes_errno = true;
2594 if (!flag_ltrans)
2596 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
2598 if (bp_unpack_value (&bp, 1))
2600 class fnspec_summary *sum = fnspec_summaries->get_create (e);
2601 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
2603 modref_read_escape_summary (&bp, e);
2605 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
2607 if (bp_unpack_value (&bp, 1))
2609 class fnspec_summary *sum = fnspec_summaries->get_create (e);
2610 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
2612 modref_read_escape_summary (&bp, e);
2615 if (dump_file)
2617 fprintf (dump_file, "Read modref for %s\n",
2618 node->dump_name ());
2619 if (modref_sum)
2620 modref_sum->dump (dump_file);
2621 if (modref_sum_lto)
2622 modref_sum_lto->dump (dump_file);
2623 dump_modref_edge_summaries (dump_file, node, 4);
2627 lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
2628 len);
2629 lto_data_in_delete (data_in);
2632 /* Callback for read_summary. */
2634 static void
2635 modref_read (void)
2637 struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
2638 struct lto_file_decl_data *file_data;
2639 unsigned int j = 0;
2641 gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
2642 if (flag_ltrans)
2643 optimization_summaries = modref_summaries::create_ggc (symtab);
2644 else
2646 if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
2647 summaries_lto = modref_summaries_lto::create_ggc (symtab);
2648 if (!flag_wpa
2649 || (flag_incremental_link == INCREMENTAL_LINK_LTO
2650 && flag_fat_lto_objects))
2651 summaries = modref_summaries::create_ggc (symtab);
2652 if (!fnspec_summaries)
2653 fnspec_summaries = new fnspec_summaries_t (symtab);
2654 if (!escape_summaries)
2655 escape_summaries = new escape_summaries_t (symtab);
2658 while ((file_data = file_data_vec[j++]))
2660 size_t len;
2661 const char *data = lto_get_summary_section_data (file_data,
2662 LTO_section_ipa_modref,
2663 &len);
2664 if (data)
2665 read_section (file_data, data, len);
2666 else
2667 /* Fatal error here. We do not want to support compiling ltrans units
2668 with different version of compiler or different flags than the WPA
2669 unit, so this should never happen. */
2670 fatal_error (input_location,
2671 "IPA modref summary is missing in input file");
2675 /* Recompute arg_flags for param adjustments in INFO. */
2677 static void
2678 remap_arg_flags (auto_vec <unsigned char> &arg_flags, clone_info *info)
2680 auto_vec<unsigned char> old = arg_flags.copy ();
2681 int max = -1;
2682 size_t i;
2683 ipa_adjusted_param *p;
2685 arg_flags.release ();
2687 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2689 int o = info->param_adjustments->get_original_index (i);
2690 if (o >= 0 && (int)old.length () > o && old[o])
2691 max = i;
2693 if (max > 0)
2694 arg_flags.safe_grow_cleared (max + 1, true);
2695 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2697 int o = info->param_adjustments->get_original_index (i);
2698 if (o >= 0 && (int)old.length () > o && old[o])
2699 arg_flags[i] = old[o];
2703 /* If signature changed, update the summary. */
2705 static void
2706 update_signature (struct cgraph_node *node)
2708 clone_info *info = clone_info::get (node);
2709 if (!info || !info->param_adjustments)
2710 return;
2712 modref_summary *r = optimization_summaries
2713 ? optimization_summaries->get (node) : NULL;
2714 modref_summary_lto *r_lto = summaries_lto
2715 ? summaries_lto->get (node) : NULL;
2716 if (!r && !r_lto)
2717 return;
2718 if (dump_file)
2720 fprintf (dump_file, "Updating summary for %s from:\n",
2721 node->dump_name ());
2722 if (r)
2723 r->dump (dump_file);
2724 if (r_lto)
2725 r_lto->dump (dump_file);
2728 size_t i, max = 0;
2729 ipa_adjusted_param *p;
2731 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2733 int idx = info->param_adjustments->get_original_index (i);
2734 if (idx > (int)max)
2735 max = idx;
2738 auto_vec <int, 32> map;
2740 map.reserve (max + 1);
2741 for (i = 0; i <= max; i++)
2742 map.quick_push (-1);
2743 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2745 int idx = info->param_adjustments->get_original_index (i);
2746 if (idx >= 0)
2747 map[idx] = i;
2749 if (r)
2751 r->loads->remap_params (&map);
2752 r->stores->remap_params (&map);
2753 if (r->arg_flags.length ())
2754 remap_arg_flags (r->arg_flags, info);
2756 if (r_lto)
2758 r_lto->loads->remap_params (&map);
2759 r_lto->stores->remap_params (&map);
2760 if (r_lto->arg_flags.length ())
2761 remap_arg_flags (r_lto->arg_flags, info);
2763 if (dump_file)
2765 fprintf (dump_file, "to:\n");
2766 if (r)
2767 r->dump (dump_file);
2768 if (r_lto)
2769 r_lto->dump (dump_file);
2771 return;
2774 /* Definition of the modref IPA pass. */
2775 const pass_data pass_data_ipa_modref =
2777 IPA_PASS, /* type */
2778 "modref", /* name */
2779 OPTGROUP_IPA, /* optinfo_flags */
2780 TV_IPA_MODREF, /* tv_id */
2781 0, /* properties_required */
2782 0, /* properties_provided */
2783 0, /* properties_destroyed */
2784 0, /* todo_flags_start */
2785 ( TODO_dump_symtab ), /* todo_flags_finish */
2788 class pass_ipa_modref : public ipa_opt_pass_d
2790 public:
2791 pass_ipa_modref (gcc::context *ctxt)
2792 : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
2793 modref_generate, /* generate_summary */
2794 modref_write, /* write_summary */
2795 modref_read, /* read_summary */
2796 modref_write, /* write_optimization_summary */
2797 modref_read, /* read_optimization_summary */
2798 NULL, /* stmt_fixup */
2799 0, /* function_transform_todo_flags_start */
2800 NULL, /* function_transform */
2801 NULL) /* variable_transform */
2804 /* opt_pass methods: */
2805 opt_pass *clone () { return new pass_ipa_modref (m_ctxt); }
2806 virtual bool gate (function *)
2808 return true;
2810 virtual unsigned int execute (function *);
2816 unsigned int pass_modref::execute (function *f)
2818 analyze_function (f, false);
2819 return 0;
2822 gimple_opt_pass *
2823 make_pass_modref (gcc::context *ctxt)
2825 return new pass_modref (ctxt);
2828 ipa_opt_pass_d *
2829 make_pass_ipa_modref (gcc::context *ctxt)
2831 return new pass_ipa_modref (ctxt);
2834 /* Skip edges from and to nodes without ipa_pure_const enabled.
2835 Ignore not available symbols. */
2837 static bool
2838 ignore_edge (struct cgraph_edge *e)
2840 /* We merge summaries of inline clones into summaries of functions they
2841 are inlined to. For that reason the complete function bodies must
2842 act as unit. */
2843 if (!e->inline_failed)
2844 return false;
2845 enum availability avail;
2846 cgraph_node *callee = e->callee->function_or_virtual_thunk_symbol
2847 (&avail, e->caller);
2849 return (avail <= AVAIL_INTERPOSABLE
2850 || ((!optimization_summaries || !optimization_summaries->get (callee))
2851 && (!summaries_lto || !summaries_lto->get (callee)))
2852 || flags_from_decl_or_type (e->callee->decl)
2853 & (ECF_CONST | ECF_NOVOPS));
2856 /* Compute parm_map for CALLEE_EDGE. */
2858 static bool
2859 compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
2861 class ipa_edge_args *args;
2862 if (ipa_node_params_sum
2863 && !callee_edge->call_stmt_cannot_inline_p
2864 && (args = IPA_EDGE_REF (callee_edge)) != NULL)
2866 int i, count = ipa_get_cs_argument_count (args);
2867 class ipa_node_params *caller_parms_info, *callee_pi;
2868 class ipa_call_summary *es
2869 = ipa_call_summaries->get (callee_edge);
2870 cgraph_node *callee
2871 = callee_edge->callee->function_or_virtual_thunk_symbol
2872 (NULL, callee_edge->caller);
2874 caller_parms_info = IPA_NODE_REF (callee_edge->caller->inlined_to
2875 ? callee_edge->caller->inlined_to
2876 : callee_edge->caller);
2877 callee_pi = IPA_NODE_REF (callee);
2879 (*parm_map).safe_grow_cleared (count, true);
2881 for (i = 0; i < count; i++)
2883 if (es && es->param[i].points_to_local_or_readonly_memory)
2885 (*parm_map)[i].parm_index = -2;
2886 continue;
2889 struct ipa_jump_func *jf
2890 = ipa_get_ith_jump_func (args, i);
2891 if (jf && callee_pi)
2893 tree cst = ipa_value_from_jfunc (caller_parms_info,
2895 ipa_get_type
2896 (callee_pi, i));
2897 if (cst && points_to_local_or_readonly_memory_p (cst))
2899 (*parm_map)[i].parm_index = -2;
2900 continue;
2903 if (jf && jf->type == IPA_JF_PASS_THROUGH)
2905 (*parm_map)[i].parm_index
2906 = ipa_get_jf_pass_through_formal_id (jf);
2907 if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
2909 (*parm_map)[i].parm_offset_known = true;
2910 (*parm_map)[i].parm_offset = 0;
2912 else if (ipa_get_jf_pass_through_operation (jf)
2913 == POINTER_PLUS_EXPR
2914 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
2915 &(*parm_map)[i].parm_offset))
2916 (*parm_map)[i].parm_offset_known = true;
2917 else
2918 (*parm_map)[i].parm_offset_known = false;
2919 continue;
2921 if (jf && jf->type == IPA_JF_ANCESTOR)
2923 (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
2924 (*parm_map)[i].parm_offset_known = true;
2925 gcc_checking_assert
2926 (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
2927 (*parm_map)[i].parm_offset
2928 = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
2930 else
2931 (*parm_map)[i].parm_index = -1;
2933 if (dump_file)
2935 fprintf (dump_file, " Parm map: ");
2936 for (i = 0; i < count; i++)
2937 fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
2938 fprintf (dump_file, "\n");
2940 return true;
2942 return false;
2945 /* Map used to translate escape infos. */
2947 struct escape_map
2949 int parm_index;
2950 bool direct;
2953 /* Update escape map fo E. */
2955 static void
2956 update_escape_summary_1 (cgraph_edge *e,
2957 vec <vec <escape_map>> &map)
2959 escape_summary *sum = escape_summaries->get (e);
2960 if (!sum)
2961 return;
2962 auto_vec <escape_entry> old = sum->esc.copy ();
2963 sum->esc.release ();
2965 unsigned int i;
2966 escape_entry *ee;
2967 FOR_EACH_VEC_ELT (old, i, ee)
2969 unsigned int j;
2970 struct escape_map *em;
2971 if (ee->parm_index >= map.length ())
2972 continue;
2973 FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
2975 struct escape_entry entry = {em->parm_index, ee->arg,
2976 ee->min_flags,
2977 ee->direct & em->direct};
2978 sum->esc.safe_push (entry);
2981 if (!sum->esc.length ())
2982 escape_summaries->remove (e);
2985 /* Update escape map fo NODE. */
2987 static void
2988 update_escape_summary (cgraph_node *node,
2989 vec <vec <escape_map>> &map)
2991 if (!escape_summaries)
2992 return;
2993 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
2994 update_escape_summary_1 (e, map);
2995 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
2997 if (!e->inline_failed)
2998 update_escape_summary (e->callee, map);
2999 else
3000 update_escape_summary_1 (e, map);
3004 /* Call EDGE was inlined; merge summary from callee to the caller. */
3006 void
3007 ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
3009 if (!summaries && !summaries_lto)
3010 return;
3012 struct cgraph_node *to = (edge->caller->inlined_to
3013 ? edge->caller->inlined_to : edge->caller);
3014 class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
3015 class modref_summary_lto *to_info_lto = summaries_lto
3016 ? summaries_lto->get (to) : NULL;
3018 if (!to_info && !to_info_lto)
3020 if (summaries)
3021 summaries->remove (edge->callee);
3022 if (summaries_lto)
3023 summaries_lto->remove (edge->callee);
3024 remove_modref_edge_summaries (edge->callee);
3025 return;
3028 class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
3029 : NULL;
3030 class modref_summary_lto *callee_info_lto
3031 = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
3032 int flags = flags_from_decl_or_type (edge->callee->decl);
3033 bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
3035 if (!callee_info && to_info)
3037 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3038 to_info->loads->collapse ();
3039 if (ignore_stores)
3040 to_info->stores->collapse ();
3042 if (!callee_info_lto && to_info_lto)
3044 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3045 to_info_lto->loads->collapse ();
3046 if (ignore_stores)
3047 to_info_lto->stores->collapse ();
3049 if (callee_info || callee_info_lto)
3051 auto_vec <modref_parm_map, 32> parm_map;
3053 compute_parm_map (edge, &parm_map);
3055 if (!ignore_stores)
3057 if (to_info && callee_info)
3058 to_info->stores->merge (callee_info->stores, &parm_map);
3059 if (to_info_lto && callee_info_lto)
3060 to_info_lto->stores->merge (callee_info_lto->stores, &parm_map);
3062 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3064 if (to_info && callee_info)
3065 to_info->loads->merge (callee_info->loads, &parm_map);
3066 if (to_info_lto && callee_info_lto)
3067 to_info_lto->loads->merge (callee_info_lto->loads, &parm_map);
3071 /* Now merge escape summaries.
3072 For every escape to the callee we need to merge calle flags
3073 and remap calees escapes. */
3074 class escape_summary *sum = escape_summaries->get (edge);
3075 int max_escape = -1;
3076 escape_entry *ee;
3077 unsigned int i;
3079 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
3080 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3081 if ((int)ee->arg > max_escape)
3082 max_escape = ee->arg;
3084 auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
3085 emap.safe_grow (max_escape + 1, true);
3086 for (i = 0; (int)i < max_escape + 1; i++)
3087 emap[i] = vNULL;
3089 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
3090 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3092 bool needed = false;
3093 if (to_info && to_info->arg_flags.length () > ee->parm_index)
3095 int flags = callee_info
3096 && callee_info->arg_flags.length () > ee->arg
3097 ? callee_info->arg_flags[ee->arg] : 0;
3098 if (!ee->direct)
3099 flags = deref_flags (flags, ignore_stores);
3100 else if (ignore_stores)
3101 flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
3102 flags |= ee->min_flags;
3103 to_info->arg_flags[ee->parm_index] &= flags;
3104 if (to_info->arg_flags[ee->parm_index])
3105 needed = true;
3107 if (to_info_lto && to_info_lto->arg_flags.length () > ee->parm_index)
3109 int flags = callee_info_lto
3110 && callee_info_lto->arg_flags.length () > ee->arg
3111 ? callee_info_lto->arg_flags[ee->arg] : 0;
3112 if (!ee->direct)
3113 flags = deref_flags (flags, ignore_stores);
3114 else if (ignore_stores)
3115 flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
3116 flags |= ee->min_flags;
3117 to_info_lto->arg_flags[ee->parm_index] &= flags;
3118 if (to_info_lto->arg_flags[ee->parm_index])
3119 needed = true;
3121 struct escape_map entry = {ee->parm_index, ee->direct};
3122 if (needed)
3123 emap[ee->arg].safe_push (entry);
3125 update_escape_summary (edge->callee, emap);
3126 for (i = 0; (int)i < max_escape + 1; i++)
3127 emap[i].release ();
3128 if (sum)
3129 escape_summaries->remove (edge);
3131 if (summaries)
3133 if (to_info && !to_info->useful_p (flags))
3135 if (dump_file)
3136 fprintf (dump_file, "Removed mod-ref summary for %s\n",
3137 to->dump_name ());
3138 summaries->remove (to);
3139 to_info = NULL;
3141 else if (to_info && dump_file)
3143 if (dump_file)
3144 fprintf (dump_file, "Updated mod-ref summary for %s\n",
3145 to->dump_name ());
3146 to_info->dump (dump_file);
3148 if (callee_info)
3149 summaries->remove (edge->callee);
3151 if (summaries_lto)
3153 if (to_info_lto && !to_info_lto->useful_p (flags))
3155 if (dump_file)
3156 fprintf (dump_file, "Removed mod-ref summary for %s\n",
3157 to->dump_name ());
3158 summaries_lto->remove (to);
3160 else if (to_info_lto && dump_file)
3162 if (dump_file)
3163 fprintf (dump_file, "Updated mod-ref summary for %s\n",
3164 to->dump_name ());
3165 to_info_lto->dump (dump_file);
3166 to_info_lto = NULL;
3168 if (callee_info_lto)
3169 summaries_lto->remove (edge->callee);
3171 if (!to_info && !to_info_lto)
3172 remove_modref_edge_summaries (to);
3173 return;
3176 /* Get parameter type from DECL. This is only safe for special cases
3177 like builtins we create fnspec for because the type match is checked
3178 at fnspec creation time. */
3180 static tree
3181 get_parm_type (tree decl, unsigned int i)
3183 tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
3185 for (unsigned int p = 0; p < i; p++)
3186 t = TREE_CHAIN (t);
3187 return TREE_VALUE (t);
3190 /* Return access mode for argument I of call E with FNSPEC. */
3192 static modref_access_node
3193 get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
3194 unsigned int i, modref_parm_map &map)
3196 tree size = NULL_TREE;
3197 unsigned int size_arg;
3199 if (!fnspec.arg_specified_p (i))
3201 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
3203 cgraph_node *node = e->caller->inlined_to
3204 ? e->caller->inlined_to : e->caller;
3205 class ipa_node_params *caller_parms_info = IPA_NODE_REF (node);
3206 class ipa_edge_args *args = IPA_EDGE_REF (e);
3207 struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
3209 if (jf)
3210 size = ipa_value_from_jfunc (caller_parms_info, jf,
3211 get_parm_type (e->callee->decl, size_arg));
3213 else if (fnspec.arg_access_size_given_by_type_p (i))
3214 size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
3215 modref_access_node a = {0, -1, -1,
3216 map.parm_offset, map.parm_index,
3217 map.parm_offset_known};
3218 poly_int64 size_hwi;
3219 if (size
3220 && poly_int_tree_p (size, &size_hwi)
3221 && coeffs_in_range_p (size_hwi, 0,
3222 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
3224 a.size = -1;
3225 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
3227 return a;
3230 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
3231 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
3233 static bool
3234 propagate_unknown_call (cgraph_node *node,
3235 cgraph_edge *e, int ecf_flags,
3236 modref_summary *cur_summary,
3237 modref_summary_lto *cur_summary_lto)
3239 bool changed = false;
3240 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
3241 auto_vec <modref_parm_map, 32> parm_map;
3242 if (fnspec_sum
3243 && compute_parm_map (e, &parm_map))
3245 attr_fnspec fnspec (fnspec_sum->fnspec);
3247 gcc_checking_assert (fnspec.known_p ());
3248 if (fnspec.global_memory_read_p ())
3249 collapse_loads (cur_summary, cur_summary_lto);
3250 else
3252 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
3253 for (unsigned i = 0; i < parm_map.length () && t;
3254 i++, t = TREE_CHAIN (t))
3255 if (!POINTER_TYPE_P (TREE_VALUE (t)))
3257 else if (!fnspec.arg_specified_p (i)
3258 || fnspec.arg_maybe_read_p (i))
3260 modref_parm_map map = parm_map[i];
3261 if (map.parm_index == -2)
3262 continue;
3263 if (map.parm_index == -1)
3265 collapse_loads (cur_summary, cur_summary_lto);
3266 break;
3268 if (cur_summary)
3269 changed |= cur_summary->loads->insert
3270 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
3271 if (cur_summary_lto)
3272 changed |= cur_summary_lto->loads->insert
3273 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
3276 if (ignore_stores_p (node->decl, ecf_flags))
3278 else if (fnspec.global_memory_written_p ())
3279 collapse_stores (cur_summary, cur_summary_lto);
3280 else
3282 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
3283 for (unsigned i = 0; i < parm_map.length () && t;
3284 i++, t = TREE_CHAIN (t))
3285 if (!POINTER_TYPE_P (TREE_VALUE (t)))
3287 else if (!fnspec.arg_specified_p (i)
3288 || fnspec.arg_maybe_written_p (i))
3290 modref_parm_map map = parm_map[i];
3291 if (map.parm_index == -2)
3292 continue;
3293 if (map.parm_index == -1)
3295 collapse_stores (cur_summary, cur_summary_lto);
3296 break;
3298 if (cur_summary)
3299 changed |= cur_summary->stores->insert
3300 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
3301 if (cur_summary_lto)
3302 changed |= cur_summary_lto->stores->insert
3303 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
3306 if (fnspec.errno_maybe_written_p () && flag_errno_math)
3308 if (cur_summary && !cur_summary->writes_errno)
3310 cur_summary->writes_errno = true;
3311 changed = true;
3313 if (cur_summary_lto && !cur_summary_lto->writes_errno)
3315 cur_summary_lto->writes_errno = true;
3316 changed = true;
3319 return changed;
3321 if (dump_file)
3322 fprintf (dump_file, " collapsing loads\n");
3323 changed |= collapse_loads (cur_summary, cur_summary_lto);
3324 if (!ignore_stores_p (node->decl, ecf_flags))
3326 if (dump_file)
3327 fprintf (dump_file, " collapsing stores\n");
3328 changed |= collapse_stores (cur_summary, cur_summary_lto);
3330 return changed;
3333 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
3334 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
3336 static void
3337 remove_useless_summaries (cgraph_node *node,
3338 modref_summary **cur_summary_ptr,
3339 modref_summary_lto **cur_summary_lto_ptr,
3340 int ecf_flags)
3342 if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
3344 optimization_summaries->remove (node);
3345 *cur_summary_ptr = NULL;
3347 if (*cur_summary_lto_ptr
3348 && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
3350 summaries_lto->remove (node);
3351 *cur_summary_lto_ptr = NULL;
3355 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3356 and propagate loads/stores. */
3358 static void
3359 modref_propagate_in_scc (cgraph_node *component_node)
3361 bool changed = true;
3362 int iteration = 0;
3364 while (changed)
3366 changed = false;
3367 for (struct cgraph_node *cur = component_node; cur;
3368 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3370 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
3371 modref_summary *cur_summary = optimization_summaries
3372 ? optimization_summaries->get (node)
3373 : NULL;
3374 modref_summary_lto *cur_summary_lto = summaries_lto
3375 ? summaries_lto->get (node)
3376 : NULL;
3378 if (!cur_summary && !cur_summary_lto)
3379 continue;
3381 int cur_ecf_flags = flags_from_decl_or_type (node->decl);
3383 if (dump_file)
3384 fprintf (dump_file, " Processing %s%s%s\n",
3385 cur->dump_name (),
3386 TREE_READONLY (cur->decl) ? " (const)" : "",
3387 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3389 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
3391 if (e->indirect_info->ecf_flags & (ECF_CONST | ECF_NOVOPS))
3392 continue;
3393 if (dump_file)
3394 fprintf (dump_file, " Indirect call"
3395 "collapsing loads\n");
3396 if (propagate_unknown_call
3397 (node, e, e->indirect_info->ecf_flags,
3398 cur_summary, cur_summary_lto))
3400 changed = true;
3401 remove_useless_summaries (node, &cur_summary,
3402 &cur_summary_lto,
3403 cur_ecf_flags);
3404 if (!cur_summary && !cur_summary_lto)
3405 break;
3409 if (!cur_summary && !cur_summary_lto)
3410 continue;
3412 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
3413 callee_edge = callee_edge->next_callee)
3415 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
3416 modref_summary *callee_summary = NULL;
3417 modref_summary_lto *callee_summary_lto = NULL;
3418 struct cgraph_node *callee;
3420 if (flags & (ECF_CONST | ECF_NOVOPS)
3421 || !callee_edge->inline_failed)
3422 continue;
3424 /* Get the callee and its summary. */
3425 enum availability avail;
3426 callee = callee_edge->callee->function_or_virtual_thunk_symbol
3427 (&avail, cur);
3429 /* It is not necessary to re-process calls outside of the
3430 SCC component. */
3431 if (iteration > 0
3432 && (!callee->aux
3433 || ((struct ipa_dfs_info *)cur->aux)->scc_no
3434 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
3435 continue;
3437 if (dump_file)
3438 fprintf (dump_file, " Call to %s\n",
3439 callee_edge->callee->dump_name ());
3441 bool ignore_stores = ignore_stores_p (cur->decl, flags);
3443 if (avail <= AVAIL_INTERPOSABLE)
3445 if (dump_file)
3446 fprintf (dump_file, " Call target interposable"
3447 " or not available\n");
3448 changed |= propagate_unknown_call
3449 (node, callee_edge, flags,
3450 cur_summary, cur_summary_lto);
3451 if (!cur_summary && !cur_summary_lto)
3452 break;
3453 continue;
3456 /* We don't know anything about CALLEE, hence we cannot tell
3457 anything about the entire component. */
3459 if (cur_summary
3460 && !(callee_summary = optimization_summaries->get (callee)))
3462 if (dump_file)
3463 fprintf (dump_file, " No call target summary\n");
3464 changed |= propagate_unknown_call
3465 (node, callee_edge, flags,
3466 cur_summary, NULL);
3468 if (cur_summary_lto
3469 && !(callee_summary_lto = summaries_lto->get (callee)))
3471 if (dump_file)
3472 fprintf (dump_file, " No call target summary\n");
3473 changed |= propagate_unknown_call
3474 (node, callee_edge, flags,
3475 NULL, cur_summary_lto);
3478 /* We can not safely optimize based on summary of callee if it
3479 does not always bind to current def: it is possible that
3480 memory load was optimized out earlier which may not happen in
3481 the interposed variant. */
3482 if (!callee_edge->binds_to_current_def_p ())
3484 changed |= collapse_loads (cur_summary, cur_summary_lto);
3485 if (dump_file)
3486 fprintf (dump_file, " May not bind local;"
3487 " collapsing loads\n");
3491 auto_vec <modref_parm_map, 32> parm_map;
3493 compute_parm_map (callee_edge, &parm_map);
3495 /* Merge in callee's information. */
3496 if (callee_summary)
3498 changed |= cur_summary->loads->merge
3499 (callee_summary->loads, &parm_map);
3500 if (!ignore_stores)
3502 changed |= cur_summary->stores->merge
3503 (callee_summary->stores, &parm_map);
3504 if (!cur_summary->writes_errno
3505 && callee_summary->writes_errno)
3507 cur_summary->writes_errno = true;
3508 changed = true;
3512 if (callee_summary_lto)
3514 changed |= cur_summary_lto->loads->merge
3515 (callee_summary_lto->loads, &parm_map);
3516 if (!ignore_stores)
3518 changed |= cur_summary_lto->stores->merge
3519 (callee_summary_lto->stores, &parm_map);
3520 if (!cur_summary_lto->writes_errno
3521 && callee_summary_lto->writes_errno)
3523 cur_summary_lto->writes_errno = true;
3524 changed = true;
3528 if (changed)
3529 remove_useless_summaries (node, &cur_summary,
3530 &cur_summary_lto,
3531 cur_ecf_flags);
3532 if (!cur_summary && !cur_summary_lto)
3533 break;
3534 if (dump_file && changed)
3536 if (cur_summary)
3537 cur_summary->dump (dump_file);
3538 if (cur_summary_lto)
3539 cur_summary_lto->dump (dump_file);
3540 dump_modref_edge_summaries (dump_file, node, 4);
3544 iteration++;
3546 if (dump_file)
3547 fprintf (dump_file,
3548 "Propagation finished in %i iterations\n", iteration);
3551 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
3553 static void
3554 modref_propagate_dump_scc (cgraph_node *component_node)
3556 for (struct cgraph_node *cur = component_node; cur;
3557 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3558 if (!cur->inlined_to)
3560 modref_summary *cur_summary = optimization_summaries
3561 ? optimization_summaries->get (cur)
3562 : NULL;
3563 modref_summary_lto *cur_summary_lto = summaries_lto
3564 ? summaries_lto->get (cur)
3565 : NULL;
3567 fprintf (dump_file, "Propagated modref for %s%s%s\n",
3568 cur->dump_name (),
3569 TREE_READONLY (cur->decl) ? " (const)" : "",
3570 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3571 if (optimization_summaries)
3573 if (cur_summary)
3574 cur_summary->dump (dump_file);
3575 else
3576 fprintf (dump_file, " Not tracked\n");
3578 if (summaries_lto)
3580 if (cur_summary_lto)
3581 cur_summary_lto->dump (dump_file);
3582 else
3583 fprintf (dump_file, " Not tracked (lto)\n");
3588 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
3589 and SUMMARY_LTO to CUR_SUMMARY_LTO.
3590 Return true if something changed. */
3592 static bool
3593 modref_merge_call_site_flags (escape_summary *sum,
3594 modref_summary *cur_summary,
3595 modref_summary_lto *cur_summary_lto,
3596 modref_summary *summary,
3597 modref_summary_lto *summary_lto,
3598 bool ignore_stores)
3600 escape_entry *ee;
3601 unsigned int i;
3602 bool changed = false;
3604 /* If we have no useful info to propagate. */
3605 if ((!cur_summary || !cur_summary->arg_flags.length ())
3606 && (!cur_summary_lto || !cur_summary_lto->arg_flags.length ()))
3607 return false;
3609 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3611 int flags = 0;
3612 int flags_lto = 0;
3614 if (summary && ee->arg < summary->arg_flags.length ())
3615 flags = summary->arg_flags[ee->arg];
3616 if (summary_lto
3617 && ee->arg < summary_lto->arg_flags.length ())
3618 flags_lto = summary_lto->arg_flags[ee->arg];
3619 if (!ee->direct)
3621 flags = deref_flags (flags, ignore_stores);
3622 flags_lto = deref_flags (flags_lto, ignore_stores);
3624 else if (ignore_stores)
3626 flags |= EAF_NOESCAPE | EAF_NOCLOBBER;
3627 flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER;
3629 flags |= ee->min_flags;
3630 flags_lto |= ee->min_flags;
3631 if (cur_summary && ee->parm_index < cur_summary->arg_flags.length ())
3633 int f = cur_summary->arg_flags[ee->parm_index];
3634 if ((f & flags) != f)
3636 f = f & flags;
3637 if ((f & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
3638 f = 0;
3639 cur_summary->arg_flags[ee->parm_index] = f;
3640 changed = true;
3643 if (cur_summary_lto
3644 && ee->parm_index < cur_summary_lto->arg_flags.length ())
3646 int f = cur_summary_lto->arg_flags[ee->parm_index];
3647 if ((f & flags_lto) != f)
3649 f = f & flags;
3650 if ((f & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
3651 f = 0;
3652 cur_summary_lto->arg_flags[ee->parm_index] = f;
3653 changed = true;
3657 return changed;
3660 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3661 and propagate arg flags. */
3663 static void
3664 modref_propagate_flags_in_scc (cgraph_node *component_node)
3666 bool changed = true;
3667 int iteration = 0;
3669 while (changed)
3671 changed = false;
3672 for (struct cgraph_node *cur = component_node; cur;
3673 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3675 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
3676 modref_summary *cur_summary = optimization_summaries
3677 ? optimization_summaries->get (node)
3678 : NULL;
3679 modref_summary_lto *cur_summary_lto = summaries_lto
3680 ? summaries_lto->get (node)
3681 : NULL;
3683 if (!cur_summary && !cur_summary_lto)
3684 continue;
3686 if (dump_file)
3687 fprintf (dump_file, " Processing %s%s%s\n",
3688 cur->dump_name (),
3689 TREE_READONLY (cur->decl) ? " (const)" : "",
3690 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3692 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
3694 escape_summary *sum = escape_summaries->get (e);
3696 if (!sum || (e->indirect_info->ecf_flags
3697 & (ECF_CONST | ECF_NOVOPS)))
3698 continue;
3700 changed |= modref_merge_call_site_flags
3701 (sum, cur_summary, cur_summary_lto,
3702 NULL, NULL, ignore_stores_p (node->decl,
3703 e->indirect_info->ecf_flags));
3706 if (!cur_summary && !cur_summary_lto)
3707 continue;
3709 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
3710 callee_edge = callee_edge->next_callee)
3712 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
3713 modref_summary *callee_summary = NULL;
3714 modref_summary_lto *callee_summary_lto = NULL;
3715 struct cgraph_node *callee;
3717 if (flags & (ECF_CONST | ECF_NOVOPS)
3718 || !callee_edge->inline_failed)
3719 continue;
3720 /* Get the callee and its summary. */
3721 enum availability avail;
3722 callee = callee_edge->callee->function_or_virtual_thunk_symbol
3723 (&avail, cur);
3725 /* It is not necessary to re-process calls outside of the
3726 SCC component. */
3727 if (iteration > 0
3728 && (!callee->aux
3729 || ((struct ipa_dfs_info *)cur->aux)->scc_no
3730 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
3731 continue;
3733 escape_summary *sum = escape_summaries->get (callee_edge);
3734 if (!sum)
3735 continue;
3737 if (dump_file)
3738 fprintf (dump_file, " Call to %s\n",
3739 callee_edge->callee->dump_name ());
3741 if (avail <= AVAIL_INTERPOSABLE
3742 || callee_edge->call_stmt_cannot_inline_p)
3744 else
3746 if (cur_summary)
3747 callee_summary = optimization_summaries->get (callee);
3748 if (cur_summary_lto)
3749 callee_summary_lto = summaries_lto->get (callee);
3751 changed |= modref_merge_call_site_flags
3752 (sum, cur_summary, cur_summary_lto,
3753 callee_summary, callee_summary_lto,
3754 ignore_stores_p (node->decl, flags));
3755 if (dump_file && changed)
3757 if (cur_summary)
3758 cur_summary->dump (dump_file);
3759 if (cur_summary_lto)
3760 cur_summary_lto->dump (dump_file);
3764 iteration++;
3766 if (dump_file)
3767 fprintf (dump_file,
3768 "Propagation of flags finished in %i iterations\n", iteration);
3771 /* Run the IPA pass. This will take a function's summaries and calls and
3772 construct new summaries which represent a transitive closure. So that
3773 summary of an analyzed function contains information about the loads and
3774 stores that the function or any function that it calls does. */
3776 unsigned int
3777 pass_ipa_modref::execute (function *)
3779 if (!summaries && !summaries_lto)
3780 return 0;
3782 if (optimization_summaries)
3783 ggc_delete (optimization_summaries);
3784 optimization_summaries = summaries;
3785 summaries = NULL;
3787 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
3788 symtab->cgraph_count);
3789 int order_pos;
3790 order_pos = ipa_reduced_postorder (order, true, ignore_edge);
3791 int i;
3793 /* Iterate over all strongly connected components in post-order. */
3794 for (i = 0; i < order_pos; i++)
3796 /* Get the component's representative. That's just any node in the
3797 component from which we can traverse the entire component. */
3798 struct cgraph_node *component_node = order[i];
3800 if (dump_file)
3801 fprintf (dump_file, "\n\nStart of SCC component\n");
3803 modref_propagate_in_scc (component_node);
3804 modref_propagate_flags_in_scc (component_node);
3805 if (dump_file)
3806 modref_propagate_dump_scc (component_node);
3808 cgraph_node *node;
3809 FOR_EACH_FUNCTION (node)
3810 update_signature (node);
3811 if (summaries_lto)
3812 ((modref_summaries_lto *)summaries_lto)->propagated = true;
3813 ipa_free_postorder_info ();
3814 free (order);
3815 delete fnspec_summaries;
3816 fnspec_summaries = NULL;
3817 delete escape_summaries;
3818 escape_summaries = NULL;
3819 return 0;
3822 /* Summaries must stay alive until end of compilation. */
3824 void
3825 ipa_modref_c_finalize ()
3827 if (optimization_summaries)
3828 ggc_delete (optimization_summaries);
3829 optimization_summaries = NULL;
3830 gcc_checking_assert (!summaries);
3831 if (summaries_lto)
3832 ggc_delete (summaries_lto);
3833 summaries_lto = NULL;
3834 if (fnspec_summaries)
3835 delete fnspec_summaries;
3836 fnspec_summaries = NULL;
3837 if (escape_summaries)
3838 delete escape_summaries;
3839 escape_summaries = NULL;
3842 #include "gt-ipa-modref.h"