Don't warn when alignment of global common data exceeds maximum alignment.
[official-gcc.git] / gcc / ipa-modref.c
blobfafd804d4bae453198bd9f5f38916ef3aeb50d3a
1 /* Search for references that a functions loads or stores.
2 Copyright (C) 2020-2021 Free Software Foundation, Inc.
3 Contributed by David Cepelik and Jan Hubicka
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 /* Mod/ref pass records summary about loads and stores performed by the
22 function. This is later used by alias analysis to disambiguate memory
23 accesses across function calls.
25 This file contains a tree pass and an IPA pass. Both performs the same
26 analysis however tree pass is executed during early and late optimization
27 passes to propagate info downwards in the compilation order. IPA pass
28 propagates across the callgraph and is able to handle recursion and works on
29 whole program during link-time analysis.
31 LTO mode differs from the local mode by not recording alias sets but types
32 that are translated to alias sets later. This is necessary in order stream
33 the information because the alias sets are rebuild at stream-in time and may
34 not correspond to ones seen during analysis. For this reason part of
35 analysis is duplicated.
37 The following information is computed
38 1) load/store access tree described in ipa-modref-tree.h
39 This is used by tree-ssa-alias to disambiguate load/stores
40 2) EAF flags used by points-to analysis (in tree-ssa-structlias).
41 and defined in tree-core.h.
42 and stored to optimization_summaries.
44 There are multiple summaries computed and used during the propagation:
45 - summaries holds summaries from analysis to IPA propagation
46 time.
47 - summaries_lto is same as summaries but holds them in a format
48 that can be streamed (as described above).
49 - fnspec_summary holds fnspec strings for call. This is
50 necessary because gimple_call_fnspec performs additional
51 analysis except for looking callee fndecl.
52 - escape_summary holds escape points for given call edge.
53 That is a vector recording what function parmaeters
54 may escape to a function call (and with what parameter index). */
56 #include "config.h"
57 #include "system.h"
58 #include "coretypes.h"
59 #include "backend.h"
60 #include "tree.h"
61 #include "gimple.h"
62 #include "alloc-pool.h"
63 #include "tree-pass.h"
64 #include "gimple-iterator.h"
65 #include "tree-dfa.h"
66 #include "cgraph.h"
67 #include "ipa-utils.h"
68 #include "symbol-summary.h"
69 #include "gimple-pretty-print.h"
70 #include "gimple-walk.h"
71 #include "print-tree.h"
72 #include "tree-streamer.h"
73 #include "alias.h"
74 #include "calls.h"
75 #include "ipa-modref-tree.h"
76 #include "ipa-modref.h"
77 #include "value-range.h"
78 #include "ipa-prop.h"
79 #include "ipa-fnsummary.h"
80 #include "attr-fnspec.h"
81 #include "symtab-clones.h"
82 #include "gimple-ssa.h"
83 #include "tree-phinodes.h"
84 #include "tree-ssa-operands.h"
85 #include "ssa-iterators.h"
86 #include "stringpool.h"
87 #include "tree-ssanames.h"
90 namespace {
92 /* We record fnspec specifiers for call edges since they depends on actual
93 gimple statements. */
95 class fnspec_summary
97 public:
98 char *fnspec;
100 fnspec_summary ()
101 : fnspec (NULL)
105 ~fnspec_summary ()
107 free (fnspec);
111 /* Summary holding fnspec string for a given call. */
113 class fnspec_summaries_t : public call_summary <fnspec_summary *>
115 public:
116 fnspec_summaries_t (symbol_table *symtab)
117 : call_summary <fnspec_summary *> (symtab) {}
118 /* Hook that is called by summary when an edge is duplicated. */
119 virtual void duplicate (cgraph_edge *,
120 cgraph_edge *,
121 fnspec_summary *src,
122 fnspec_summary *dst)
124 dst->fnspec = xstrdup (src->fnspec);
128 static fnspec_summaries_t *fnspec_summaries = NULL;
130 /* Escape summary holds a vector of param indexes that escape to
131 a given call. */
132 struct escape_entry
134 /* Parameter that escapes at a given call. */
135 unsigned int parm_index;
136 /* Argument it escapes to. */
137 unsigned int arg;
138 /* Minimal flags known about the argument. */
139 eaf_flags_t min_flags;
140 /* Does it escape directly or indirectly? */
141 bool direct;
144 /* Dump EAF flags. */
146 static void
147 dump_eaf_flags (FILE *out, int flags, bool newline = true)
149 if (flags & EAF_DIRECT)
150 fprintf (out, " direct");
151 if (flags & EAF_NOCLOBBER)
152 fprintf (out, " noclobber");
153 if (flags & EAF_NOESCAPE)
154 fprintf (out, " noescape");
155 if (flags & EAF_NODIRECTESCAPE)
156 fprintf (out, " nodirectescape");
157 if (flags & EAF_UNUSED)
158 fprintf (out, " unused");
159 if (flags & EAF_NOT_RETURNED)
160 fprintf (out, " not_returned");
161 if (flags & EAF_NOREAD)
162 fprintf (out, " noread");
163 if (newline)
164 fprintf (out, "\n");
167 struct escape_summary
169 auto_vec <escape_entry> esc;
170 void dump (FILE *out)
172 for (unsigned int i = 0; i < esc.length (); i++)
174 fprintf (out, " parm %i arg %i %s min:",
175 esc[i].parm_index,
176 esc[i].arg,
177 esc[i].direct ? "(direct)" : "(indirect)");
178 dump_eaf_flags (out, esc[i].min_flags, false);
180 fprintf (out, "\n");
184 class escape_summaries_t : public call_summary <escape_summary *>
186 public:
187 escape_summaries_t (symbol_table *symtab)
188 : call_summary <escape_summary *> (symtab) {}
189 /* Hook that is called by summary when an edge is duplicated. */
190 virtual void duplicate (cgraph_edge *,
191 cgraph_edge *,
192 escape_summary *src,
193 escape_summary *dst)
195 dst->esc = src->esc.copy ();
199 static escape_summaries_t *escape_summaries = NULL;
201 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
204 /* Class (from which there is one global instance) that holds modref summaries
205 for all analyzed functions. */
207 class GTY((user)) modref_summaries
208 : public fast_function_summary <modref_summary *, va_gc>
210 public:
211 modref_summaries (symbol_table *symtab)
212 : fast_function_summary <modref_summary *, va_gc> (symtab) {}
213 virtual void insert (cgraph_node *, modref_summary *state);
214 virtual void duplicate (cgraph_node *src_node,
215 cgraph_node *dst_node,
216 modref_summary *src_data,
217 modref_summary *dst_data);
218 static modref_summaries *create_ggc (symbol_table *symtab)
220 return new (ggc_alloc_no_dtor<modref_summaries> ())
221 modref_summaries (symtab);
225 class modref_summary_lto;
227 /* Class (from which there is one global instance) that holds modref summaries
228 for all analyzed functions. */
230 class GTY((user)) modref_summaries_lto
231 : public fast_function_summary <modref_summary_lto *, va_gc>
233 public:
234 modref_summaries_lto (symbol_table *symtab)
235 : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
236 propagated (false) {}
237 virtual void insert (cgraph_node *, modref_summary_lto *state);
238 virtual void duplicate (cgraph_node *src_node,
239 cgraph_node *dst_node,
240 modref_summary_lto *src_data,
241 modref_summary_lto *dst_data);
242 static modref_summaries_lto *create_ggc (symbol_table *symtab)
244 return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
245 modref_summaries_lto (symtab);
247 bool propagated;
250 /* Global variable holding all modref summaries
251 (from analysis to IPA propagation time). */
253 static GTY(()) fast_function_summary <modref_summary *, va_gc>
254 *summaries;
256 /* Global variable holding all modref optimization summaries
257 (from IPA propagation time or used by local optimization pass). */
259 static GTY(()) fast_function_summary <modref_summary *, va_gc>
260 *optimization_summaries;
262 /* LTO summaries hold info from analysis to LTO streaming or from LTO
263 stream-in through propagation to LTO stream-out. */
265 static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
266 *summaries_lto;
268 /* Summary for a single function which this pass produces. */
270 modref_summary::modref_summary ()
271 : loads (NULL), stores (NULL), writes_errno (NULL)
275 modref_summary::~modref_summary ()
277 if (loads)
278 ggc_delete (loads);
279 if (stores)
280 ggc_delete (stores);
283 /* All flags that are implied by the ECF_CONST functions. */
284 const int implicit_const_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
285 | EAF_NODIRECTESCAPE | EAF_NOREAD;
286 /* All flags that are implied by the ECF_PURE function. */
287 const int implicit_pure_eaf_flags = EAF_NOCLOBBER | EAF_NOESCAPE
288 | EAF_NODIRECTESCAPE;
289 /* All flags implied when we know we can ignore stores (i.e. when handling
290 call to noreturn). */
291 const int ignore_stores_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
292 | EAF_NODIRECTESCAPE;
294 /* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
295 useful to track. If returns_void is true moreover clear
296 EAF_NOT_RETURNED. */
297 static int
298 remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
300 if (ecf_flags & ECF_NOVOPS)
301 return 0;
302 if (ecf_flags & ECF_CONST)
303 eaf_flags &= ~implicit_const_eaf_flags;
304 else if (ecf_flags & ECF_PURE)
305 eaf_flags &= ~implicit_pure_eaf_flags;
306 else if ((ecf_flags & ECF_NORETURN) || returns_void)
307 eaf_flags &= ~EAF_NOT_RETURNED;
308 /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
309 in tree-ssa-alias.c). Give up earlier. */
310 if ((eaf_flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
311 return 0;
312 return eaf_flags;
315 /* Return true if FLAGS holds some useful information. */
317 static bool
318 eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags)
320 for (unsigned i = 0; i < flags.length (); i++)
321 if (remove_useless_eaf_flags (flags[i], ecf_flags, false))
322 return true;
323 return false;
326 /* Return true if summary is potentially useful for optimization.
327 If CHECK_FLAGS is false assume that arg_flags are useful. */
329 bool
330 modref_summary::useful_p (int ecf_flags, bool check_flags)
332 if (ecf_flags & ECF_NOVOPS)
333 return false;
334 if (arg_flags.length () && !check_flags)
335 return true;
336 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
337 return true;
338 arg_flags.release ();
339 if (ecf_flags & ECF_CONST)
340 return false;
341 if (loads && !loads->every_base)
342 return true;
343 if (ecf_flags & ECF_PURE)
344 return false;
345 return stores && !stores->every_base;
348 /* Single function summary used for LTO. */
350 typedef modref_tree <tree> modref_records_lto;
351 struct GTY(()) modref_summary_lto
353 /* Load and stores in functions using types rather then alias sets.
355 This is necessary to make the information streamable for LTO but is also
356 more verbose and thus more likely to hit the limits. */
357 modref_records_lto *loads;
358 modref_records_lto *stores;
359 auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
360 bool writes_errno;
362 modref_summary_lto ();
363 ~modref_summary_lto ();
364 void dump (FILE *);
365 bool useful_p (int ecf_flags, bool check_flags = true);
368 /* Summary for a single function which this pass produces. */
370 modref_summary_lto::modref_summary_lto ()
371 : loads (NULL), stores (NULL), writes_errno (NULL)
375 modref_summary_lto::~modref_summary_lto ()
377 if (loads)
378 ggc_delete (loads);
379 if (stores)
380 ggc_delete (stores);
384 /* Return true if lto summary is potentially useful for optimization.
385 If CHECK_FLAGS is false assume that arg_flags are useful. */
387 bool
388 modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
390 if (ecf_flags & ECF_NOVOPS)
391 return false;
392 if (arg_flags.length () && !check_flags)
393 return true;
394 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
395 return true;
396 arg_flags.release ();
397 if (ecf_flags & ECF_CONST)
398 return false;
399 if (loads && !loads->every_base)
400 return true;
401 if (ecf_flags & ECF_PURE)
402 return false;
403 return stores && !stores->every_base;
406 /* Dump A to OUT. */
408 static void
409 dump_access (modref_access_node *a, FILE *out)
411 fprintf (out, " access:");
412 if (a->parm_index != -1)
414 fprintf (out, " Parm %i", a->parm_index);
415 if (a->parm_offset_known)
417 fprintf (out, " param offset:");
418 print_dec ((poly_int64_pod)a->parm_offset, out, SIGNED);
421 if (a->range_info_useful_p ())
423 fprintf (out, " offset:");
424 print_dec ((poly_int64_pod)a->offset, out, SIGNED);
425 fprintf (out, " size:");
426 print_dec ((poly_int64_pod)a->size, out, SIGNED);
427 fprintf (out, " max_size:");
428 print_dec ((poly_int64_pod)a->max_size, out, SIGNED);
430 fprintf (out, "\n");
433 /* Dump records TT to OUT. */
435 static void
436 dump_records (modref_records *tt, FILE *out)
438 fprintf (out, " Limits: %i bases, %i refs\n",
439 (int)tt->max_bases, (int)tt->max_refs);
440 if (tt->every_base)
442 fprintf (out, " Every base\n");
443 return;
445 size_t i;
446 modref_base_node <alias_set_type> *n;
447 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
449 fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
450 if (n->every_ref)
452 fprintf (out, " Every ref\n");
453 continue;
455 size_t j;
456 modref_ref_node <alias_set_type> *r;
457 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
459 fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
460 if (r->every_access)
462 fprintf (out, " Every access\n");
463 continue;
465 size_t k;
466 modref_access_node *a;
467 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
468 dump_access (a, out);
473 /* Dump records TT to OUT. */
475 static void
476 dump_lto_records (modref_records_lto *tt, FILE *out)
478 fprintf (out, " Limits: %i bases, %i refs\n",
479 (int)tt->max_bases, (int)tt->max_refs);
480 if (tt->every_base)
482 fprintf (out, " Every base\n");
483 return;
485 size_t i;
486 modref_base_node <tree> *n;
487 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
489 fprintf (out, " Base %i:", (int)i);
490 print_generic_expr (dump_file, n->base);
491 fprintf (out, " (alias set %i)\n",
492 n->base ? get_alias_set (n->base) : 0);
493 if (n->every_ref)
495 fprintf (out, " Every ref\n");
496 continue;
498 size_t j;
499 modref_ref_node <tree> *r;
500 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
502 fprintf (out, " Ref %i:", (int)j);
503 print_generic_expr (dump_file, r->ref);
504 fprintf (out, " (alias set %i)\n",
505 r->ref ? get_alias_set (r->ref) : 0);
506 if (r->every_access)
508 fprintf (out, " Every access\n");
509 continue;
511 size_t k;
512 modref_access_node *a;
513 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
514 dump_access (a, out);
519 /* Dump all escape points of NODE to OUT. */
521 static void
522 dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
524 int i = 0;
525 if (!escape_summaries)
526 return;
527 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
529 class escape_summary *sum = escape_summaries->get (e);
530 if (sum)
532 fprintf (out, "%*sIndirect call %i in %s escapes:",
533 depth, "", i, node->dump_name ());
534 sum->dump (out);
536 i++;
538 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
540 if (!e->inline_failed)
541 dump_modref_edge_summaries (out, e->callee, depth + 1);
542 class escape_summary *sum = escape_summaries->get (e);
543 if (sum)
545 fprintf (out, "%*sCall %s->%s escapes:", depth, "",
546 node->dump_name (), e->callee->dump_name ());
547 sum->dump (out);
549 class fnspec_summary *fsum = fnspec_summaries->get (e);
550 if (fsum)
552 fprintf (out, "%*sCall %s->%s fnspec: %s\n", depth, "",
553 node->dump_name (), e->callee->dump_name (),
554 fsum->fnspec);
559 /* Remove all call edge summaries associated with NODE. */
561 static void
562 remove_modref_edge_summaries (cgraph_node *node)
564 if (!escape_summaries)
565 return;
566 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
567 escape_summaries->remove (e);
568 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
570 if (!e->inline_failed)
571 remove_modref_edge_summaries (e->callee);
572 escape_summaries->remove (e);
573 fnspec_summaries->remove (e);
577 /* Dump summary. */
579 void
580 modref_summary::dump (FILE *out)
582 if (loads)
584 fprintf (out, " loads:\n");
585 dump_records (loads, out);
587 if (stores)
589 fprintf (out, " stores:\n");
590 dump_records (stores, out);
592 if (writes_errno)
593 fprintf (out, " Writes errno\n");
594 if (arg_flags.length ())
596 for (unsigned int i = 0; i < arg_flags.length (); i++)
597 if (arg_flags[i])
599 fprintf (out, " parm %i flags:", i);
600 dump_eaf_flags (out, arg_flags[i]);
605 /* Dump summary. */
607 void
608 modref_summary_lto::dump (FILE *out)
610 fprintf (out, " loads:\n");
611 dump_lto_records (loads, out);
612 fprintf (out, " stores:\n");
613 dump_lto_records (stores, out);
614 if (writes_errno)
615 fprintf (out, " Writes errno\n");
616 if (arg_flags.length ())
618 for (unsigned int i = 0; i < arg_flags.length (); i++)
619 if (arg_flags[i])
621 fprintf (out, " parm %i flags:", i);
622 dump_eaf_flags (out, arg_flags[i]);
627 /* Get function summary for FUNC if it exists, return NULL otherwise. */
629 modref_summary *
630 get_modref_function_summary (cgraph_node *func)
632 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
633 if (!optimization_summaries)
634 return NULL;
636 /* A single function body may be represented by multiple symbols with
637 different visibility. For example, if FUNC is an interposable alias,
638 we don't want to return anything, even if we have summary for the target
639 function. */
640 enum availability avail;
641 func = func->function_or_virtual_thunk_symbol
642 (&avail, current_function_decl ?
643 cgraph_node::get (current_function_decl) : NULL);
644 if (avail <= AVAIL_INTERPOSABLE)
645 return NULL;
647 modref_summary *r = optimization_summaries->get (func);
648 return r;
651 /* Construct modref_access_node from REF. */
652 static modref_access_node
653 get_access (ao_ref *ref)
655 tree base;
657 base = ao_ref_base (ref);
658 modref_access_node a = {ref->offset, ref->size, ref->max_size,
659 0, -1, false};
660 if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
662 tree memref = base;
663 base = TREE_OPERAND (base, 0);
664 if (TREE_CODE (base) == SSA_NAME
665 && SSA_NAME_IS_DEFAULT_DEF (base)
666 && TREE_CODE (SSA_NAME_VAR (base)) == PARM_DECL)
668 a.parm_index = 0;
669 for (tree t = DECL_ARGUMENTS (current_function_decl);
670 t != SSA_NAME_VAR (base); t = DECL_CHAIN (t))
672 if (!t)
674 a.parm_index = -1;
675 break;
677 a.parm_index++;
679 if (TREE_CODE (memref) == MEM_REF)
681 a.parm_offset_known
682 = wi::to_poly_wide (TREE_OPERAND
683 (memref, 1)).to_shwi (&a.parm_offset);
685 else
686 a.parm_offset_known = false;
688 else
689 a.parm_index = -1;
691 else
692 a.parm_index = -1;
693 return a;
696 /* Record access into the modref_records data structure. */
698 static void
699 record_access (modref_records *tt, ao_ref *ref)
701 alias_set_type base_set = !flag_strict_aliasing ? 0
702 : ao_ref_base_alias_set (ref);
703 alias_set_type ref_set = !flag_strict_aliasing ? 0
704 : (ao_ref_alias_set (ref));
705 modref_access_node a = get_access (ref);
706 if (dump_file)
708 fprintf (dump_file, " - Recording base_set=%i ref_set=%i parm=%i\n",
709 base_set, ref_set, a.parm_index);
711 tt->insert (base_set, ref_set, a);
714 /* IPA version of record_access_tree. */
716 static void
717 record_access_lto (modref_records_lto *tt, ao_ref *ref)
719 /* get_alias_set sometimes use different type to compute the alias set
720 than TREE_TYPE (base). Do same adjustments. */
721 tree base_type = NULL_TREE, ref_type = NULL_TREE;
722 if (flag_strict_aliasing)
724 tree base;
726 base = ref->ref;
727 while (handled_component_p (base))
728 base = TREE_OPERAND (base, 0);
730 base_type = reference_alias_ptr_type_1 (&base);
732 if (!base_type)
733 base_type = TREE_TYPE (base);
734 else
735 base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
736 ? NULL_TREE : TREE_TYPE (base_type);
738 tree ref_expr = ref->ref;
739 ref_type = reference_alias_ptr_type_1 (&ref_expr);
741 if (!ref_type)
742 ref_type = TREE_TYPE (ref_expr);
743 else
744 ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
745 ? NULL_TREE : TREE_TYPE (ref_type);
747 /* Sanity check that we are in sync with what get_alias_set does. */
748 gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
749 || get_alias_set (base_type)
750 == ao_ref_base_alias_set (ref));
751 gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
752 || get_alias_set (ref_type)
753 == ao_ref_alias_set (ref));
755 /* Do not bother to record types that have no meaningful alias set.
756 Also skip variably modified types since these go to local streams. */
757 if (base_type && (!get_alias_set (base_type)
758 || variably_modified_type_p (base_type, NULL_TREE)))
759 base_type = NULL_TREE;
760 if (ref_type && (!get_alias_set (ref_type)
761 || variably_modified_type_p (ref_type, NULL_TREE)))
762 ref_type = NULL_TREE;
764 modref_access_node a = get_access (ref);
765 if (dump_file)
767 fprintf (dump_file, " - Recording base type:");
768 print_generic_expr (dump_file, base_type);
769 fprintf (dump_file, " (alias set %i) ref type:",
770 base_type ? get_alias_set (base_type) : 0);
771 print_generic_expr (dump_file, ref_type);
772 fprintf (dump_file, " (alias set %i) parm:%i\n",
773 ref_type ? get_alias_set (ref_type) : 0,
774 a.parm_index);
777 tt->insert (base_type, ref_type, a);
780 /* Returns true if and only if we should store the access to EXPR.
781 Some accesses, e.g. loads from automatic variables, are not interesting. */
783 static bool
784 record_access_p (tree expr)
786 if (refs_local_or_readonly_memory_p (expr))
788 if (dump_file)
789 fprintf (dump_file, " - Read-only or local, ignoring.\n");
790 return false;
792 return true;
795 /* Return true if ECF flags says that return value can be ignored. */
797 static bool
798 ignore_retval_p (tree caller, int flags)
800 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
801 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
802 return true;
803 return false;
806 /* Return true if ECF flags says that stores can be ignored. */
808 static bool
809 ignore_stores_p (tree caller, int flags)
811 if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
812 return true;
813 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
814 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
815 return true;
816 return false;
819 /* Determine parm_map for argument I of STMT. */
821 modref_parm_map
822 parm_map_for_arg (gimple *stmt, int i)
824 tree op = gimple_call_arg (stmt, i);
825 bool offset_known;
826 poly_int64 offset;
827 struct modref_parm_map parm_map;
829 parm_map.parm_offset_known = false;
830 parm_map.parm_offset = 0;
832 offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
833 if (TREE_CODE (op) == SSA_NAME
834 && SSA_NAME_IS_DEFAULT_DEF (op)
835 && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
837 int index = 0;
838 for (tree t = DECL_ARGUMENTS (current_function_decl);
839 t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
841 if (!t)
843 index = -1;
844 break;
846 index++;
848 parm_map.parm_index = index;
849 parm_map.parm_offset_known = offset_known;
850 parm_map.parm_offset = offset;
852 else if (points_to_local_or_readonly_memory_p (op))
853 parm_map.parm_index = -2;
854 else
855 parm_map.parm_index = -1;
856 return parm_map;
859 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
860 int CUR_SUMMARY. Return true if something changed.
861 If IGNORE_STORES is true, do not merge stores. */
863 bool
864 merge_call_side_effects (modref_summary *cur_summary,
865 gimple *stmt, modref_summary *callee_summary,
866 bool ignore_stores, cgraph_node *callee_node)
868 auto_vec <modref_parm_map, 32> parm_map;
869 bool changed = false;
871 /* We can not safely optimize based on summary of callee if it does
872 not always bind to current def: it is possible that memory load
873 was optimized out earlier which may not happen in the interposed
874 variant. */
875 if (!callee_node->binds_to_current_def_p ())
877 if (dump_file)
878 fprintf (dump_file, " - May be interposed: collapsing loads.\n");
879 cur_summary->loads->collapse ();
882 if (dump_file)
883 fprintf (dump_file, " - Merging side effects of %s with parm map:",
884 callee_node->dump_name ());
886 parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true);
887 for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
889 parm_map[i] = parm_map_for_arg (stmt, i);
890 if (dump_file)
892 fprintf (dump_file, " %i", parm_map[i].parm_index);
893 if (parm_map[i].parm_offset_known)
895 fprintf (dump_file, " offset:");
896 print_dec ((poly_int64_pod)parm_map[i].parm_offset,
897 dump_file, SIGNED);
901 if (dump_file)
902 fprintf (dump_file, "\n");
904 /* Merge with callee's summary. */
905 changed |= cur_summary->loads->merge (callee_summary->loads, &parm_map);
906 if (!ignore_stores)
908 changed |= cur_summary->stores->merge (callee_summary->stores,
909 &parm_map);
910 if (!cur_summary->writes_errno
911 && callee_summary->writes_errno)
913 cur_summary->writes_errno = true;
914 changed = true;
917 return changed;
920 /* Return access mode for argument I of call STMT with FNSPEC. */
922 static modref_access_node
923 get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
924 unsigned int i, modref_parm_map &map)
926 tree size = NULL_TREE;
927 unsigned int size_arg;
929 if (!fnspec.arg_specified_p (i))
931 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
932 size = gimple_call_arg (call, size_arg);
933 else if (fnspec.arg_access_size_given_by_type_p (i))
935 tree callee = gimple_call_fndecl (call);
936 tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
938 for (unsigned int p = 0; p < i; p++)
939 t = TREE_CHAIN (t);
940 size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
942 modref_access_node a = {0, -1, -1,
943 map.parm_offset, map.parm_index,
944 map.parm_offset_known};
945 poly_int64 size_hwi;
946 if (size
947 && poly_int_tree_p (size, &size_hwi)
948 && coeffs_in_range_p (size_hwi, 0,
949 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
951 a.size = -1;
952 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
954 return a;
957 /* Collapse loads and return true if something changed. */
959 static bool
960 collapse_loads (modref_summary *cur_summary,
961 modref_summary_lto *cur_summary_lto)
963 bool changed = false;
965 if (cur_summary && !cur_summary->loads->every_base)
967 cur_summary->loads->collapse ();
968 changed = true;
970 if (cur_summary_lto
971 && !cur_summary_lto->loads->every_base)
973 cur_summary_lto->loads->collapse ();
974 changed = true;
976 return changed;
979 /* Collapse loads and return true if something changed. */
981 static bool
982 collapse_stores (modref_summary *cur_summary,
983 modref_summary_lto *cur_summary_lto)
985 bool changed = false;
987 if (cur_summary && !cur_summary->stores->every_base)
989 cur_summary->stores->collapse ();
990 changed = true;
992 if (cur_summary_lto
993 && !cur_summary_lto->stores->every_base)
995 cur_summary_lto->stores->collapse ();
996 changed = true;
998 return changed;
1002 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1003 If IGNORE_STORES is true ignore them.
1004 Return false if no useful summary can be produced. */
1006 static bool
1007 process_fnspec (modref_summary *cur_summary,
1008 modref_summary_lto *cur_summary_lto,
1009 gcall *call, bool ignore_stores)
1011 attr_fnspec fnspec = gimple_call_fnspec (call);
1012 if (!fnspec.known_p ())
1014 if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
1015 fprintf (dump_file, " Builtin with no fnspec: %s\n",
1016 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
1017 if (ignore_stores)
1019 collapse_loads (cur_summary, cur_summary_lto);
1020 return true;
1022 return false;
1024 if (fnspec.global_memory_read_p ())
1025 collapse_loads (cur_summary, cur_summary_lto);
1026 else
1028 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1029 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1031 else if (!fnspec.arg_specified_p (i)
1032 || fnspec.arg_maybe_read_p (i))
1034 modref_parm_map map = parm_map_for_arg (call, i);
1036 if (map.parm_index == -2)
1037 continue;
1038 if (map.parm_index == -1)
1040 collapse_loads (cur_summary, cur_summary_lto);
1041 break;
1043 if (cur_summary)
1044 cur_summary->loads->insert (0, 0,
1045 get_access_for_fnspec (call,
1046 fnspec, i,
1047 map));
1048 if (cur_summary_lto)
1049 cur_summary_lto->loads->insert (0, 0,
1050 get_access_for_fnspec (call,
1051 fnspec, i,
1052 map));
1055 if (ignore_stores)
1056 return true;
1057 if (fnspec.global_memory_written_p ())
1058 collapse_stores (cur_summary, cur_summary_lto);
1059 else
1061 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1062 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1064 else if (!fnspec.arg_specified_p (i)
1065 || fnspec.arg_maybe_written_p (i))
1067 modref_parm_map map = parm_map_for_arg (call, i);
1069 if (map.parm_index == -2)
1070 continue;
1071 if (map.parm_index == -1)
1073 collapse_stores (cur_summary, cur_summary_lto);
1074 break;
1076 if (cur_summary)
1077 cur_summary->stores->insert (0, 0,
1078 get_access_for_fnspec (call,
1079 fnspec, i,
1080 map));
1081 if (cur_summary_lto)
1082 cur_summary_lto->stores->insert (0, 0,
1083 get_access_for_fnspec (call,
1084 fnspec, i,
1085 map));
1087 if (fnspec.errno_maybe_written_p () && flag_errno_math)
1089 if (cur_summary)
1090 cur_summary->writes_errno = true;
1091 if (cur_summary_lto)
1092 cur_summary_lto->writes_errno = true;
1095 return true;
1098 /* Analyze function call STMT in function F.
1099 Remember recursive calls in RECURSIVE_CALLS. */
1101 static bool
1102 analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto,
1103 gcall *stmt, vec <gimple *> *recursive_calls)
1105 /* Check flags on the function call. In certain cases, analysis can be
1106 simplified. */
1107 int flags = gimple_call_flags (stmt);
1108 if (flags & (ECF_CONST | ECF_NOVOPS))
1110 if (dump_file)
1111 fprintf (dump_file,
1112 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1113 "except for args.\n");
1114 return true;
1117 /* Pure functions do not affect global memory. Stores by functions which are
1118 noreturn and do not throw can safely be ignored. */
1119 bool ignore_stores = ignore_stores_p (current_function_decl, flags);
1121 /* Next, we try to get the callee's function declaration. The goal is to
1122 merge their summary with ours. */
1123 tree callee = gimple_call_fndecl (stmt);
1125 /* Check if this is an indirect call. */
1126 if (!callee)
1128 if (dump_file)
1129 fprintf (dump_file, gimple_call_internal_p (stmt)
1130 ? " - Internal call" : " - Indirect call.\n");
1131 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1133 /* We only need to handle internal calls in IPA mode. */
1134 gcc_checking_assert (!cur_summary_lto);
1136 struct cgraph_node *callee_node = cgraph_node::get_create (callee);
1138 /* If this is a recursive call, the target summary is the same as ours, so
1139 there's nothing to do. */
1140 if (recursive_call_p (current_function_decl, callee))
1142 recursive_calls->safe_push (stmt);
1143 if (dump_file)
1144 fprintf (dump_file, " - Skipping recursive call.\n");
1145 return true;
1148 gcc_assert (callee_node != NULL);
1150 /* Get the function symbol and its availability. */
1151 enum availability avail;
1152 callee_node = callee_node->function_symbol (&avail);
1153 if (avail <= AVAIL_INTERPOSABLE)
1155 if (dump_file)
1156 fprintf (dump_file, " - Function availability <= AVAIL_INTERPOSABLE.\n");
1157 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1160 /* Get callee's modref summary. As above, if there's no summary, we either
1161 have to give up or, if stores are ignored, we can just purge loads. */
1162 modref_summary *callee_summary = optimization_summaries->get (callee_node);
1163 if (!callee_summary)
1165 if (dump_file)
1166 fprintf (dump_file, " - No modref summary available for callee.\n");
1167 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1170 merge_call_side_effects (cur_summary, stmt, callee_summary, ignore_stores,
1171 callee_node);
1173 return true;
1176 /* Support analysis in non-lto and lto mode in parallel. */
1178 struct summary_ptrs
1180 struct modref_summary *nolto;
1181 struct modref_summary_lto *lto;
1184 /* Helper for analyze_stmt. */
1186 static bool
1187 analyze_load (gimple *, tree, tree op, void *data)
1189 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1190 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1192 if (dump_file)
1194 fprintf (dump_file, " - Analyzing load: ");
1195 print_generic_expr (dump_file, op);
1196 fprintf (dump_file, "\n");
1199 if (!record_access_p (op))
1200 return false;
1202 ao_ref r;
1203 ao_ref_init (&r, op);
1205 if (summary)
1206 record_access (summary->loads, &r);
1207 if (summary_lto)
1208 record_access_lto (summary_lto->loads, &r);
1209 return false;
1212 /* Helper for analyze_stmt. */
1214 static bool
1215 analyze_store (gimple *, tree, tree op, void *data)
1217 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1218 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1220 if (dump_file)
1222 fprintf (dump_file, " - Analyzing store: ");
1223 print_generic_expr (dump_file, op);
1224 fprintf (dump_file, "\n");
1227 if (!record_access_p (op))
1228 return false;
1230 ao_ref r;
1231 ao_ref_init (&r, op);
1233 if (summary)
1234 record_access (summary->stores, &r);
1235 if (summary_lto)
1236 record_access_lto (summary_lto->stores, &r);
1237 return false;
1240 /* Analyze statement STMT of function F.
1241 If IPA is true do not merge in side effects of calls. */
1243 static bool
1244 analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
1245 gimple *stmt, bool ipa, vec <gimple *> *recursive_calls)
1247 /* In general we can not ignore clobbers because they are barriers for code
1248 motion, however after inlining it is safe to do because local optimization
1249 passes do not consider clobbers from other functions.
1250 Similar logic is in ipa-pure-const.c. */
1251 if ((ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1252 return true;
1254 struct summary_ptrs sums = {summary, summary_lto};
1256 /* Analyze all loads and stores in STMT. */
1257 walk_stmt_load_store_ops (stmt, &sums,
1258 analyze_load, analyze_store);
1260 switch (gimple_code (stmt))
1262 case GIMPLE_ASM:
1263 /* If the ASM statement does not read nor write memory, there's nothing
1264 to do. Otherwise just give up. */
1265 if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1266 return true;
1267 if (dump_file)
1268 fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1269 "which clobbers memory.\n");
1270 return false;
1271 case GIMPLE_CALL:
1272 if (!ipa || gimple_call_internal_p (stmt))
1273 return analyze_call (summary, summary_lto,
1274 as_a <gcall *> (stmt), recursive_calls);
1275 else
1277 attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1279 if (fnspec.known_p ()
1280 && (!fnspec.global_memory_read_p ()
1281 || !fnspec.global_memory_written_p ()))
1283 cgraph_edge *e = cgraph_node::get (current_function_decl)->get_edge (stmt);
1284 if (e->callee)
1286 fnspec_summaries->get_create (e)->fnspec = xstrdup (fnspec.get_str ());
1287 if (dump_file)
1288 fprintf (dump_file, " Recorded fnspec %s\n", fnspec.get_str ());
1292 return true;
1293 default:
1294 /* Nothing to do for other types of statements. */
1295 return true;
1299 /* Remove summary of current function because during the function body
1300 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1301 mode of scan. */
1303 static void
1304 remove_summary (bool lto, bool nolto, bool ipa)
1306 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1307 if (!ipa)
1308 optimization_summaries->remove (fnode);
1309 else
1311 if (nolto)
1312 summaries->remove (fnode);
1313 if (lto)
1314 summaries_lto->remove (fnode);
1315 remove_modref_edge_summaries (fnode);
1317 if (dump_file)
1318 fprintf (dump_file,
1319 " - modref done with result: not tracked.\n");
1322 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1324 bool
1325 memory_access_to (tree op, tree ssa_name)
1327 tree base = get_base_address (op);
1328 if (!base)
1329 return false;
1330 if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1331 return false;
1332 return TREE_OPERAND (base, 0) == ssa_name;
1335 /* Consider statement val = *arg.
1336 return EAF flags of ARG that can be determined from EAF flags of VAL
1337 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1338 all stores to VAL, i.e. when handling noreturn function. */
1340 static int
1341 deref_flags (int flags, bool ignore_stores)
1343 int ret = EAF_NODIRECTESCAPE;
1344 /* If argument is unused just account for
1345 the read involved in dereference. */
1346 if (flags & EAF_UNUSED)
1347 ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOT_RETURNED;
1348 else
1350 if ((flags & EAF_NOCLOBBER) || ignore_stores)
1351 ret |= EAF_NOCLOBBER;
1352 if ((flags & EAF_NOESCAPE) || ignore_stores)
1353 ret |= EAF_NOESCAPE;
1354 /* If the value dereferenced is not used for another load or store
1355 we can still consider ARG as used only directly.
1357 Consider
1360 test (int *a)
1362 return *a!=0;
1366 if ((flags & (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT))
1367 == (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT)
1368 && ((flags & EAF_NOCLOBBER) || ignore_stores))
1369 ret |= EAF_DIRECT;
1370 if (flags & EAF_NOT_RETURNED)
1371 ret |= EAF_NOT_RETURNED;
1373 return ret;
1376 namespace {
1378 /* Description of an escape point. */
1380 struct escape_point
1382 /* Value escapes to this call. */
1383 gcall *call;
1384 /* Argument it escapes to. */
1385 int arg;
1386 /* Flags already known about the argument (this can save us from recording
1387 esape points if local analysis did good job already). */
1388 eaf_flags_t min_flags;
1389 /* Does value escape directly or indiretly? */
1390 bool direct;
1393 class modref_lattice
1395 public:
1396 /* EAF flags of the SSA name. */
1397 eaf_flags_t flags;
1398 /* DFS bookkkeeping: we don't do real dataflow yet. */
1399 bool known;
1400 bool open;
1402 /* When doing IPA analysis we can not merge in callee escape points;
1403 Only remember them and do the merging at IPA propagation time. */
1404 vec <escape_point, va_heap, vl_ptr> escape_points;
1406 void init ();
1407 void release ();
1408 bool merge (const modref_lattice &with);
1409 bool merge (int flags);
1410 bool merge_deref (const modref_lattice &with, bool ignore_stores);
1411 bool merge_direct_load ();
1412 bool merge_direct_store ();
1413 bool add_escape_point (gcall *call, int arg, int min_flags, bool diret);
1414 void dump (FILE *out, int indent = 0) const;
1417 /* Lattices are saved to vectors, so keep them PODs. */
1418 void
1419 modref_lattice::init ()
1421 /* All flags we track. */
1422 int f = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED
1423 | EAF_NODIRECTESCAPE | EAF_NOT_RETURNED | EAF_NOREAD;
1424 flags = f;
1425 /* Check that eaf_flags_t is wide enough to hold all flags. */
1426 gcc_checking_assert (f == flags);
1427 open = true;
1428 known = false;
1431 /* Release memory. */
1432 void
1433 modref_lattice::release ()
1435 escape_points.release ();
1438 /* Dump lattice to OUT; indent with INDENT spaces. */
1440 void
1441 modref_lattice::dump (FILE *out, int indent) const
1443 dump_eaf_flags (out, flags);
1444 if (escape_points.length ())
1446 fprintf (out, "%*sEscapes:\n", indent, "");
1447 for (unsigned int i = 0; i < escape_points.length (); i++)
1449 fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
1450 escape_points[i].arg,
1451 escape_points[i].direct ? "direct" : "indirect");
1452 dump_eaf_flags (out, escape_points[i].min_flags, false);
1453 fprintf (out, " in call ");
1454 print_gimple_stmt (out, escape_points[i].call, 0);
1459 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1460 point exists. */
1462 bool
1463 modref_lattice::add_escape_point (gcall *call, int arg, int min_flags,
1464 bool direct)
1466 escape_point *ep;
1467 unsigned int i;
1469 /* If we already determined flags to be bad enough,
1470 we do not need to record. */
1471 if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
1472 return false;
1474 FOR_EACH_VEC_ELT (escape_points, i, ep)
1475 if (ep->call == call && ep->arg == arg && ep->direct == direct)
1477 if ((ep->min_flags & min_flags) == min_flags)
1478 return false;
1479 ep->min_flags &= min_flags;
1480 return true;
1482 /* Give up if max escape points is met. */
1483 if ((int)escape_points.length () > param_modref_max_escape_points)
1485 if (dump_file)
1486 fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
1487 merge (0);
1488 return true;
1490 escape_point new_ep = {call, arg, min_flags, direct};
1491 escape_points.safe_push (new_ep);
1492 return true;
1495 /* Merge in flags from F. */
1496 bool
1497 modref_lattice::merge (int f)
1499 if (f & EAF_UNUSED)
1500 return false;
1501 /* Noescape implies that value also does not escape directly.
1502 Fnspec machinery does set both so compensate for this. */
1503 if (f & EAF_NOESCAPE)
1504 f |= EAF_NODIRECTESCAPE;
1505 if ((flags & f) != flags)
1507 flags &= f;
1508 /* Prune obvoiusly useless flags;
1509 We do not have ECF_FLAGS handy which is not big problem since
1510 we will do final flags cleanup before producing summary.
1511 Merging should be fast so it can work well with dataflow. */
1512 flags = remove_useless_eaf_flags (flags, 0, false);
1513 if (!flags)
1514 escape_points.release ();
1515 return true;
1517 return false;
1520 /* Merge in WITH. Return true if anyting changed. */
1522 bool
1523 modref_lattice::merge (const modref_lattice &with)
1525 if (!with.known)
1526 return merge (0);
1528 bool changed = merge (with.flags);
1530 if (!flags)
1531 return changed;
1532 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1533 changed |= add_escape_point (with.escape_points[i].call,
1534 with.escape_points[i].arg,
1535 with.escape_points[i].min_flags,
1536 with.escape_points[i].direct);
1537 return changed;
1540 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1541 stores. Return true if anyting changed. */
1543 bool
1544 modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
1546 if (!with.known)
1547 return merge (0);
1549 bool changed = merge (deref_flags (with.flags, ignore_stores));
1551 if (!flags)
1552 return changed;
1553 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1555 int min_flags = with.escape_points[i].min_flags;
1557 if (with.escape_points[i].direct)
1558 min_flags = deref_flags (min_flags, ignore_stores);
1559 else if (ignore_stores)
1560 min_flags |= ignore_stores_eaf_flags;
1561 changed |= add_escape_point (with.escape_points[i].call,
1562 with.escape_points[i].arg,
1563 min_flags,
1564 false);
1566 return changed;
1569 /* Merge in flags for direct load. */
1571 bool
1572 modref_lattice::merge_direct_load ()
1574 return merge (~(EAF_UNUSED | EAF_NOREAD));
1577 /* Merge in flags for direct store. */
1579 bool
1580 modref_lattice::merge_direct_store ()
1582 return merge (~(EAF_UNUSED | EAF_NOCLOBBER));
1585 } /* ANON namespace. */
1587 static void analyze_ssa_name_flags (tree name,
1588 vec<modref_lattice> &lattice,
1589 int depth, bool ipa);
1591 /* Call statements may return their parameters. Consider argument number
1592 ARG of USE_STMT and determine flags that can needs to be cleared
1593 in case pointer possibly indirectly references from ARG I is returned.
1594 LATTICE, DEPTH and ipa are same as in analyze_ssa_name_flags. */
1596 static void
1597 merge_call_lhs_flags (gcall *call, int arg, int index, bool deref,
1598 vec<modref_lattice> &lattice,
1599 int depth, bool ipa)
1601 /* If there is no return value, no flags are affected. */
1602 if (!gimple_call_lhs (call))
1603 return;
1605 /* If we know that function returns given argument and it is not ARG
1606 we can still be happy. */
1607 int flags = gimple_call_return_flags (call);
1608 if ((flags & ERF_RETURNS_ARG)
1609 && (flags & ERF_RETURN_ARG_MASK) != arg)
1610 return;
1612 if (gimple_call_arg_flags (call, arg) & (EAF_NOT_RETURNED | EAF_UNUSED))
1613 return;
1615 /* If return value is SSA name determine its flags. */
1616 if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
1618 tree lhs = gimple_call_lhs (call);
1619 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1620 if (deref)
1621 lattice[index].merge_deref (lattice[SSA_NAME_VERSION (lhs)], false);
1622 else
1623 lattice[index].merge (lattice[SSA_NAME_VERSION (lhs)]);
1625 /* In the case of memory store we can do nothing. */
1626 else
1627 lattice[index].merge (0);
1630 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
1631 LATTICE is an array of modref_lattices.
1632 DEPTH is a recursion depth used to make debug output prettier.
1633 If IPA is true we analyze for IPA propagation (and thus call escape points
1634 are processed later) */
1636 static void
1637 analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
1638 bool ipa)
1640 imm_use_iterator ui;
1641 gimple *use_stmt;
1642 int index = SSA_NAME_VERSION (name);
1644 /* See if value is already computed. */
1645 if (lattice[index].known)
1646 return;
1647 if (lattice[index].open)
1649 if (dump_file)
1650 fprintf (dump_file,
1651 "%*sGiving up on a cycle in SSA graph\n", depth * 4, "");
1652 return;
1654 if (depth == param_modref_max_depth)
1656 if (dump_file)
1657 fprintf (dump_file,
1658 "%*sGiving up on max depth\n", depth * 4, "");
1659 return;
1661 /* Recursion guard. */
1662 lattice[index].init ();
1664 if (dump_file)
1666 fprintf (dump_file,
1667 "%*sAnalyzing flags of ssa name: ", depth * 4, "");
1668 print_generic_expr (dump_file, name);
1669 fprintf (dump_file, "\n");
1672 FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
1674 if (lattice[index].flags == 0)
1675 break;
1676 if (is_gimple_debug (use_stmt))
1677 continue;
1678 if (dump_file)
1680 fprintf (dump_file, "%*s Analyzing stmt: ", depth * 4, "");
1681 print_gimple_stmt (dump_file, use_stmt, 0);
1683 /* If we see a direct non-debug use, clear unused bit.
1684 All dereferneces should be accounted below using deref_flags. */
1685 lattice[index].merge (~EAF_UNUSED);
1687 /* Gimple return may load the return value.
1688 Returning name counts as an use by tree-ssa-structalias.c */
1689 if (greturn *ret = dyn_cast <greturn *> (use_stmt))
1691 if (gimple_return_retval (ret) == name)
1692 lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED));
1693 else if (memory_access_to (gimple_return_retval (ret), name))
1695 lattice[index].merge_direct_load ();
1696 lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED));
1699 /* Account for LHS store, arg loads and flags from callee function. */
1700 else if (gcall *call = dyn_cast <gcall *> (use_stmt))
1702 tree callee = gimple_call_fndecl (call);
1703 /* Return slot optimization would require bit of propagation;
1704 give up for now. */
1705 if (gimple_call_return_slot_opt_p (call)
1706 && gimple_call_lhs (call) != NULL_TREE
1707 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
1709 if (dump_file)
1710 fprintf (dump_file, "%*s Unhandled return slot opt\n",
1711 depth * 4, "");
1712 lattice[index].merge (0);
1714 /* Recursion would require bit of propagation; give up for now. */
1715 else if (callee && !ipa && recursive_call_p (current_function_decl,
1716 callee))
1717 lattice[index].merge (0);
1718 else
1720 int ecf_flags = gimple_call_flags (call);
1721 bool ignore_stores = ignore_stores_p (current_function_decl,
1722 ecf_flags);
1723 bool ignore_retval = ignore_retval_p (current_function_decl,
1724 ecf_flags);
1726 /* Handle *name = func (...). */
1727 if (gimple_call_lhs (call)
1728 && memory_access_to (gimple_call_lhs (call), name))
1729 lattice[index].merge_direct_store ();
1731 /* We do not track accesses to the static chain (we could)
1732 so give up. */
1733 if (gimple_call_chain (call)
1734 && (gimple_call_chain (call) == name))
1735 lattice[index].merge (0);
1737 /* Process internal functions and right away. */
1738 bool record_ipa = ipa && !gimple_call_internal_p (call);
1740 /* Handle all function parameters. */
1741 for (unsigned i = 0;
1742 i < gimple_call_num_args (call) && lattice[index].flags; i++)
1743 /* Name is directly passed to the callee. */
1744 if (gimple_call_arg (call, i) == name)
1746 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
1748 int call_flags = gimple_call_arg_flags (call, i)
1749 | EAF_NOT_RETURNED;
1750 if (ignore_stores)
1751 call_flags |= ignore_stores_eaf_flags;
1753 if (!record_ipa)
1754 lattice[index].merge (call_flags);
1755 else
1756 lattice[index].add_escape_point (call, i,
1757 call_flags, true);
1759 if (!ignore_retval)
1760 merge_call_lhs_flags (call, i, index, false,
1761 lattice, depth, ipa);
1763 /* Name is dereferenced and passed to a callee. */
1764 else if (memory_access_to (gimple_call_arg (call, i), name))
1766 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
1767 lattice[index].merge_direct_load ();
1768 else
1770 int call_flags = deref_flags
1771 (gimple_call_arg_flags (call, i)
1772 | EAF_NOT_RETURNED, ignore_stores);
1773 if (!record_ipa)
1774 lattice[index].merge (call_flags);
1775 else
1776 lattice[index].add_escape_point (call, i,
1777 call_flags, false);
1779 if (!ignore_retval)
1780 merge_call_lhs_flags (call, i, index, true,
1781 lattice, depth, ipa);
1785 else if (gimple_assign_load_p (use_stmt))
1787 gassign *assign = as_a <gassign *> (use_stmt);
1788 /* Memory to memory copy. */
1789 if (gimple_store_p (assign))
1791 /* Handle *lhs = *name.
1793 We do not track memory locations, so assume that value
1794 is used arbitrarily. */
1795 if (memory_access_to (gimple_assign_rhs1 (assign), name))
1796 lattice[index].merge (0);
1797 /* Handle *name = *exp. */
1798 else if (memory_access_to (gimple_assign_lhs (assign), name))
1799 lattice[index].merge_direct_store ();
1801 /* Handle lhs = *name. */
1802 else if (memory_access_to (gimple_assign_rhs1 (assign), name))
1804 tree lhs = gimple_assign_lhs (assign);
1805 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1806 lattice[index].merge_deref (lattice[SSA_NAME_VERSION (lhs)],
1807 false);
1810 else if (gimple_store_p (use_stmt))
1812 gassign *assign = dyn_cast <gassign *> (use_stmt);
1814 /* Handle *lhs = name. */
1815 if (assign && gimple_assign_rhs1 (assign) == name)
1817 if (dump_file)
1818 fprintf (dump_file, "%*s ssa name saved to memory\n",
1819 depth * 4, "");
1820 lattice[index].merge (0);
1822 /* Handle *name = exp. */
1823 else if (assign
1824 && memory_access_to (gimple_assign_lhs (assign), name))
1826 /* In general we can not ignore clobbers because they are
1827 barriers for code motion, however after inlining it is safe to
1828 do because local optimization passes do not consider clobbers
1829 from other functions. Similar logic is in ipa-pure-const.c. */
1830 if (!cfun->after_inlining || !gimple_clobber_p (assign))
1831 lattice[index].merge_direct_store ();
1833 /* ASM statements etc. */
1834 else if (!assign)
1836 if (dump_file)
1837 fprintf (dump_file, "%*s Unhandled store\n",
1838 depth * 4, "");
1839 lattice[index].merge (0);
1842 else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
1844 enum tree_code code = gimple_assign_rhs_code (assign);
1846 /* See if operation is a merge as considered by
1847 tree-ssa-structalias.c:find_func_aliases. */
1848 if (!truth_value_p (code)
1849 && code != POINTER_DIFF_EXPR
1850 && (code != POINTER_PLUS_EXPR
1851 || gimple_assign_rhs1 (assign) == name))
1853 tree lhs = gimple_assign_lhs (assign);
1854 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1855 lattice[index].merge (lattice[SSA_NAME_VERSION (lhs)]);
1858 else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
1860 tree result = gimple_phi_result (phi);
1861 analyze_ssa_name_flags (result, lattice, depth + 1, ipa);
1862 lattice[index].merge (lattice[SSA_NAME_VERSION (result)]);
1864 /* Conditions are not considered escape points
1865 by tree-ssa-structalias. */
1866 else if (gimple_code (use_stmt) == GIMPLE_COND)
1868 else
1870 if (dump_file)
1871 fprintf (dump_file, "%*s Unhandled stmt\n", depth * 4, "");
1872 lattice[index].merge (0);
1875 if (dump_file)
1877 fprintf (dump_file, "%*s current flags of ", depth * 4, "");
1878 print_generic_expr (dump_file, name);
1879 lattice[index].dump (dump_file, depth * 4 + 4);
1882 if (dump_file)
1884 fprintf (dump_file, "%*sflags of ssa name ", depth * 4, "");
1885 print_generic_expr (dump_file, name);
1886 lattice[index].dump (dump_file, depth * 4 + 2);
1888 lattice[index].open = false;
1889 lattice[index].known = true;
1892 /* Determine EAF flags for function parameters. */
1894 static void
1895 analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
1896 bool ipa)
1898 unsigned int parm_index = 0;
1899 unsigned int count = 0;
1900 int ecf_flags = flags_from_decl_or_type (current_function_decl);
1902 /* For novops functions we have nothing to gain by EAF flags. */
1903 if (ecf_flags & ECF_NOVOPS)
1904 return;
1906 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
1907 parm = TREE_CHAIN (parm))
1908 count++;
1910 if (!count)
1911 return;
1913 auto_vec<modref_lattice> lattice;
1914 lattice.safe_grow_cleared (num_ssa_names, true);
1916 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
1917 parm = TREE_CHAIN (parm))
1919 tree name = ssa_default_def (cfun, parm);
1920 if (!name || has_zero_uses (name))
1922 /* We do not track non-SSA parameters,
1923 but we want to track unused gimple_regs. */
1924 if (!is_gimple_reg (parm))
1925 continue;
1926 if (summary)
1928 if (parm_index >= summary->arg_flags.length ())
1929 summary->arg_flags.safe_grow_cleared (count, true);
1930 summary->arg_flags[parm_index] = EAF_UNUSED;
1932 else if (summary_lto)
1934 if (parm_index >= summary_lto->arg_flags.length ())
1935 summary_lto->arg_flags.safe_grow_cleared (count, true);
1936 summary_lto->arg_flags[parm_index] = EAF_UNUSED;
1938 continue;
1940 analyze_ssa_name_flags (name, lattice, 0, ipa);
1941 int flags = lattice[SSA_NAME_VERSION (name)].flags;
1943 /* Eliminate useless flags so we do not end up storing unnecessary
1944 summaries. */
1946 flags = remove_useless_eaf_flags
1947 (flags, ecf_flags,
1948 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
1950 if (flags)
1952 if (summary)
1954 if (parm_index >= summary->arg_flags.length ())
1955 summary->arg_flags.safe_grow_cleared (count, true);
1956 summary->arg_flags[parm_index] = flags;
1958 else if (summary_lto)
1960 if (parm_index >= summary_lto->arg_flags.length ())
1961 summary_lto->arg_flags.safe_grow_cleared (count, true);
1962 summary_lto->arg_flags[parm_index] = flags;
1964 if (lattice[SSA_NAME_VERSION (name)].escape_points.length ())
1966 escape_point *ep;
1967 unsigned int ip;
1968 cgraph_node *node = cgraph_node::get (current_function_decl);
1970 gcc_checking_assert (ipa);
1971 FOR_EACH_VEC_ELT
1972 (lattice[SSA_NAME_VERSION (name)].escape_points, ip, ep)
1973 if ((ep->min_flags & flags) != flags)
1975 cgraph_edge *e = node->get_edge (ep->call);
1976 struct escape_entry ee = {parm_index, ep->arg,
1977 ep->min_flags, ep->direct};
1979 escape_summaries->get_create (e)->esc.safe_push (ee);
1984 if (ipa)
1985 for (unsigned int i = 0; i < num_ssa_names; i++)
1986 lattice[i].release ();
1989 /* Analyze function F. IPA indicates whether we're running in local mode
1990 (false) or the IPA mode (true). */
1992 static void
1993 analyze_function (function *f, bool ipa)
1995 if (dump_file)
1996 fprintf (dump_file, "modref analyzing '%s' (ipa=%i)%s%s\n",
1997 function_name (f), ipa,
1998 TREE_READONLY (current_function_decl) ? " (const)" : "",
1999 DECL_PURE_P (current_function_decl) ? " (pure)" : "");
2001 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
2002 if (!flag_ipa_modref)
2003 return;
2005 /* Compute no-LTO summaries when local optimization is going to happen. */
2006 bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
2007 || (in_lto_p && !flag_wpa
2008 && flag_incremental_link != INCREMENTAL_LINK_LTO));
2009 /* Compute LTO when LTO streaming is going to happen. */
2010 bool lto = ipa && ((flag_lto && !in_lto_p)
2011 || flag_wpa
2012 || flag_incremental_link == INCREMENTAL_LINK_LTO);
2013 cgraph_node *fnode = cgraph_node::get (current_function_decl);
2015 modref_summary *summary = NULL;
2016 modref_summary_lto *summary_lto = NULL;
2018 /* Initialize the summary.
2019 If we run in local mode there is possibly pre-existing summary from
2020 IPA pass. Dump it so it is easy to compare if mod-ref info has
2021 improved. */
2022 if (!ipa)
2024 if (!optimization_summaries)
2025 optimization_summaries = modref_summaries::create_ggc (symtab);
2026 else /* Remove existing summary if we are re-running the pass. */
2028 if (dump_file
2029 && (summary
2030 = optimization_summaries->get (cgraph_node::get (f->decl)))
2031 != NULL
2032 && summary->loads)
2034 fprintf (dump_file, "Past summary:\n");
2035 optimization_summaries->get
2036 (cgraph_node::get (f->decl))->dump (dump_file);
2038 optimization_summaries->remove (cgraph_node::get (f->decl));
2040 summary = optimization_summaries->get_create (cgraph_node::get (f->decl));
2041 gcc_checking_assert (nolto && !lto);
2043 /* In IPA mode we analyze every function precisely once. Assert that. */
2044 else
2046 if (nolto)
2048 if (!summaries)
2049 summaries = modref_summaries::create_ggc (symtab);
2050 else
2051 summaries->remove (cgraph_node::get (f->decl));
2052 summary = summaries->get_create (cgraph_node::get (f->decl));
2054 if (lto)
2056 if (!summaries_lto)
2057 summaries_lto = modref_summaries_lto::create_ggc (symtab);
2058 else
2059 summaries_lto->remove (cgraph_node::get (f->decl));
2060 summary_lto = summaries_lto->get_create (cgraph_node::get (f->decl));
2062 if (!fnspec_summaries)
2063 fnspec_summaries = new fnspec_summaries_t (symtab);
2064 if (!escape_summaries)
2065 escape_summaries = new escape_summaries_t (symtab);
2069 /* Create and initialize summary for F.
2070 Note that summaries may be already allocated from previous
2071 run of the pass. */
2072 if (nolto)
2074 gcc_assert (!summary->loads);
2075 summary->loads = modref_records::create_ggc (param_modref_max_bases,
2076 param_modref_max_refs,
2077 param_modref_max_accesses);
2078 gcc_assert (!summary->stores);
2079 summary->stores = modref_records::create_ggc (param_modref_max_bases,
2080 param_modref_max_refs,
2081 param_modref_max_accesses);
2082 summary->writes_errno = false;
2084 if (lto)
2086 gcc_assert (!summary_lto->loads);
2087 summary_lto->loads = modref_records_lto::create_ggc
2088 (param_modref_max_bases,
2089 param_modref_max_refs,
2090 param_modref_max_accesses);
2091 gcc_assert (!summary_lto->stores);
2092 summary_lto->stores = modref_records_lto::create_ggc
2093 (param_modref_max_bases,
2094 param_modref_max_refs,
2095 param_modref_max_accesses);
2096 summary_lto->writes_errno = false;
2099 analyze_parms (summary, summary_lto, ipa);
2101 int ecf_flags = flags_from_decl_or_type (current_function_decl);
2102 auto_vec <gimple *, 32> recursive_calls;
2104 /* Analyze each statement in each basic block of the function. If the
2105 statement cannot be analyzed (for any reason), the entire function cannot
2106 be analyzed by modref. */
2107 basic_block bb;
2108 FOR_EACH_BB_FN (bb, f)
2110 gimple_stmt_iterator si;
2111 for (si = gsi_after_labels (bb); !gsi_end_p (si); gsi_next (&si))
2113 if (!analyze_stmt (summary, summary_lto,
2114 gsi_stmt (si), ipa, &recursive_calls)
2115 || ((!summary || !summary->useful_p (ecf_flags, false))
2116 && (!summary_lto
2117 || !summary_lto->useful_p (ecf_flags, false))))
2119 collapse_loads (summary, summary_lto);
2120 collapse_stores (summary, summary_lto);
2121 break;
2126 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2127 This needs to be done after all other side effects are computed. */
2128 if (!ipa)
2130 bool changed = true;
2131 while (changed)
2133 changed = false;
2134 for (unsigned i = 0; i < recursive_calls.length (); i++)
2136 changed |= merge_call_side_effects
2137 (summary, recursive_calls[i], summary,
2138 ignore_stores_p (current_function_decl,
2139 gimple_call_flags
2140 (recursive_calls[i])),
2141 fnode);
2142 if (!summary->useful_p (ecf_flags, false))
2144 remove_summary (lto, nolto, ipa);
2145 return;
2150 if (summary && !summary->useful_p (ecf_flags))
2152 if (!ipa)
2153 optimization_summaries->remove (fnode);
2154 else
2155 summaries->remove (fnode);
2156 summary = NULL;
2158 if (summary_lto && !summary_lto->useful_p (ecf_flags))
2160 summaries_lto->remove (fnode);
2161 summary_lto = NULL;
2163 if (ipa && !summary && !summary_lto)
2164 remove_modref_edge_summaries (fnode);
2166 if (dump_file)
2168 fprintf (dump_file, " - modref done with result: tracked.\n");
2169 if (summary)
2170 summary->dump (dump_file);
2171 if (summary_lto)
2172 summary_lto->dump (dump_file);
2173 dump_modref_edge_summaries (dump_file, fnode, 2);
2177 /* Callback for generate_summary. */
2179 static void
2180 modref_generate (void)
2182 struct cgraph_node *node;
2183 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
2185 function *f = DECL_STRUCT_FUNCTION (node->decl);
2186 if (!f)
2187 continue;
2188 push_cfun (f);
2189 analyze_function (f, true);
2190 pop_cfun ();
2194 /* Called when a new function is inserted to callgraph late. */
2196 void
2197 modref_summaries::insert (struct cgraph_node *node, modref_summary *)
2199 /* Local passes ought to be executed by the pass manager. */
2200 if (this == optimization_summaries)
2202 optimization_summaries->remove (node);
2203 return;
2205 if (!DECL_STRUCT_FUNCTION (node->decl)
2206 || !opt_for_fn (node->decl, flag_ipa_modref))
2208 summaries->remove (node);
2209 return;
2211 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2212 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2213 pop_cfun ();
2216 /* Called when a new function is inserted to callgraph late. */
2218 void
2219 modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
2221 /* We do not support adding new function when IPA information is already
2222 propagated. This is done only by SIMD cloning that is not very
2223 critical. */
2224 if (!DECL_STRUCT_FUNCTION (node->decl)
2225 || !opt_for_fn (node->decl, flag_ipa_modref)
2226 || propagated)
2228 summaries_lto->remove (node);
2229 return;
2231 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2232 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2233 pop_cfun ();
2236 /* Called when new clone is inserted to callgraph late. */
2238 void
2239 modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
2240 modref_summary *src_data,
2241 modref_summary *dst_data)
2243 /* Do not duplicate optimization summaries; we do not handle parameter
2244 transforms on them. */
2245 if (this == optimization_summaries)
2247 optimization_summaries->remove (dst);
2248 return;
2250 dst_data->stores = modref_records::create_ggc
2251 (src_data->stores->max_bases,
2252 src_data->stores->max_refs,
2253 src_data->stores->max_accesses);
2254 dst_data->stores->copy_from (src_data->stores);
2255 dst_data->loads = modref_records::create_ggc
2256 (src_data->loads->max_bases,
2257 src_data->loads->max_refs,
2258 src_data->loads->max_accesses);
2259 dst_data->loads->copy_from (src_data->loads);
2260 dst_data->writes_errno = src_data->writes_errno;
2261 if (src_data->arg_flags.length ())
2262 dst_data->arg_flags = src_data->arg_flags.copy ();
2265 /* Called when new clone is inserted to callgraph late. */
2267 void
2268 modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
2269 modref_summary_lto *src_data,
2270 modref_summary_lto *dst_data)
2272 /* Be sure that no further cloning happens after ipa-modref. If it does
2273 we will need to update signatures for possible param changes. */
2274 gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
2275 dst_data->stores = modref_records_lto::create_ggc
2276 (src_data->stores->max_bases,
2277 src_data->stores->max_refs,
2278 src_data->stores->max_accesses);
2279 dst_data->stores->copy_from (src_data->stores);
2280 dst_data->loads = modref_records_lto::create_ggc
2281 (src_data->loads->max_bases,
2282 src_data->loads->max_refs,
2283 src_data->loads->max_accesses);
2284 dst_data->loads->copy_from (src_data->loads);
2285 dst_data->writes_errno = src_data->writes_errno;
2286 if (src_data->arg_flags.length ())
2287 dst_data->arg_flags = src_data->arg_flags.copy ();
2290 namespace
2292 /* Definition of the modref pass on GIMPLE. */
2293 const pass_data pass_data_modref = {
2294 GIMPLE_PASS,
2295 "modref",
2296 OPTGROUP_IPA,
2297 TV_TREE_MODREF,
2298 (PROP_cfg | PROP_ssa),
2305 class pass_modref : public gimple_opt_pass
2307 public:
2308 pass_modref (gcc::context *ctxt)
2309 : gimple_opt_pass (pass_data_modref, ctxt) {}
2311 /* opt_pass methods: */
2312 opt_pass *clone ()
2314 return new pass_modref (m_ctxt);
2316 virtual bool gate (function *)
2318 return flag_ipa_modref;
2320 virtual unsigned int execute (function *);
2323 /* Encode TT to the output block OB using the summary streaming API. */
2325 static void
2326 write_modref_records (modref_records_lto *tt, struct output_block *ob)
2328 streamer_write_uhwi (ob, tt->max_bases);
2329 streamer_write_uhwi (ob, tt->max_refs);
2330 streamer_write_uhwi (ob, tt->max_accesses);
2332 streamer_write_uhwi (ob, tt->every_base);
2333 streamer_write_uhwi (ob, vec_safe_length (tt->bases));
2334 size_t i;
2335 modref_base_node <tree> *base_node;
2336 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, base_node)
2338 stream_write_tree (ob, base_node->base, true);
2340 streamer_write_uhwi (ob, base_node->every_ref);
2341 streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
2343 size_t j;
2344 modref_ref_node <tree> *ref_node;
2345 FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
2347 stream_write_tree (ob, ref_node->ref, true);
2348 streamer_write_uhwi (ob, ref_node->every_access);
2349 streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
2351 size_t k;
2352 modref_access_node *access_node;
2353 FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
2355 streamer_write_hwi (ob, access_node->parm_index);
2356 if (access_node->parm_index != -1)
2358 streamer_write_uhwi (ob, access_node->parm_offset_known);
2359 if (access_node->parm_offset_known)
2361 streamer_write_poly_int64 (ob, access_node->parm_offset);
2362 streamer_write_poly_int64 (ob, access_node->offset);
2363 streamer_write_poly_int64 (ob, access_node->size);
2364 streamer_write_poly_int64 (ob, access_node->max_size);
2372 /* Read a modref_tree from the input block IB using the data from DATA_IN.
2373 This assumes that the tree was encoded using write_modref_tree.
2374 Either nolto_ret or lto_ret is initialized by the tree depending whether
2375 LTO streaming is expected or not. */
2377 void
2378 read_modref_records (lto_input_block *ib, struct data_in *data_in,
2379 modref_records **nolto_ret,
2380 modref_records_lto **lto_ret)
2382 size_t max_bases = streamer_read_uhwi (ib);
2383 size_t max_refs = streamer_read_uhwi (ib);
2384 size_t max_accesses = streamer_read_uhwi (ib);
2386 if (lto_ret)
2387 *lto_ret = modref_records_lto::create_ggc (max_bases, max_refs,
2388 max_accesses);
2389 if (nolto_ret)
2390 *nolto_ret = modref_records::create_ggc (max_bases, max_refs,
2391 max_accesses);
2392 gcc_checking_assert (lto_ret || nolto_ret);
2394 size_t every_base = streamer_read_uhwi (ib);
2395 size_t nbase = streamer_read_uhwi (ib);
2397 gcc_assert (!every_base || nbase == 0);
2398 if (every_base)
2400 if (nolto_ret)
2401 (*nolto_ret)->collapse ();
2402 if (lto_ret)
2403 (*lto_ret)->collapse ();
2405 for (size_t i = 0; i < nbase; i++)
2407 tree base_tree = stream_read_tree (ib, data_in);
2408 modref_base_node <alias_set_type> *nolto_base_node = NULL;
2409 modref_base_node <tree> *lto_base_node = NULL;
2411 /* At stream in time we have LTO alias info. Check if we streamed in
2412 something obviously unnecessary. Do not glob types by alias sets;
2413 it is not 100% clear that ltrans types will get merged same way.
2414 Types may get refined based on ODR type conflicts. */
2415 if (base_tree && !get_alias_set (base_tree))
2417 if (dump_file)
2419 fprintf (dump_file, "Streamed in alias set 0 type ");
2420 print_generic_expr (dump_file, base_tree);
2421 fprintf (dump_file, "\n");
2423 base_tree = NULL;
2426 if (nolto_ret)
2427 nolto_base_node = (*nolto_ret)->insert_base (base_tree
2428 ? get_alias_set (base_tree)
2429 : 0);
2430 if (lto_ret)
2431 lto_base_node = (*lto_ret)->insert_base (base_tree);
2432 size_t every_ref = streamer_read_uhwi (ib);
2433 size_t nref = streamer_read_uhwi (ib);
2435 gcc_assert (!every_ref || nref == 0);
2436 if (every_ref)
2438 if (nolto_base_node)
2439 nolto_base_node->collapse ();
2440 if (lto_base_node)
2441 lto_base_node->collapse ();
2443 for (size_t j = 0; j < nref; j++)
2445 tree ref_tree = stream_read_tree (ib, data_in);
2447 if (ref_tree && !get_alias_set (ref_tree))
2449 if (dump_file)
2451 fprintf (dump_file, "Streamed in alias set 0 type ");
2452 print_generic_expr (dump_file, ref_tree);
2453 fprintf (dump_file, "\n");
2455 ref_tree = NULL;
2458 modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
2459 modref_ref_node <tree> *lto_ref_node = NULL;
2461 if (nolto_base_node)
2462 nolto_ref_node
2463 = nolto_base_node->insert_ref (ref_tree
2464 ? get_alias_set (ref_tree) : 0,
2465 max_refs);
2466 if (lto_base_node)
2467 lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
2469 size_t every_access = streamer_read_uhwi (ib);
2470 size_t naccesses = streamer_read_uhwi (ib);
2472 if (nolto_ref_node)
2473 nolto_ref_node->every_access = every_access;
2474 if (lto_ref_node)
2475 lto_ref_node->every_access = every_access;
2477 for (size_t k = 0; k < naccesses; k++)
2479 int parm_index = streamer_read_hwi (ib);
2480 bool parm_offset_known = false;
2481 poly_int64 parm_offset = 0;
2482 poly_int64 offset = 0;
2483 poly_int64 size = -1;
2484 poly_int64 max_size = -1;
2486 if (parm_index != -1)
2488 parm_offset_known = streamer_read_uhwi (ib);
2489 if (parm_offset_known)
2491 parm_offset = streamer_read_poly_int64 (ib);
2492 offset = streamer_read_poly_int64 (ib);
2493 size = streamer_read_poly_int64 (ib);
2494 max_size = streamer_read_poly_int64 (ib);
2497 modref_access_node a = {offset, size, max_size, parm_offset,
2498 parm_index, parm_offset_known};
2499 if (nolto_ref_node)
2500 nolto_ref_node->insert_access (a, max_accesses);
2501 if (lto_ref_node)
2502 lto_ref_node->insert_access (a, max_accesses);
2506 if (lto_ret)
2507 (*lto_ret)->cleanup ();
2508 if (nolto_ret)
2509 (*nolto_ret)->cleanup ();
2512 /* Write ESUM to BP. */
2514 static void
2515 modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
2517 if (!esum)
2519 bp_pack_var_len_unsigned (bp, 0);
2520 return;
2522 bp_pack_var_len_unsigned (bp, esum->esc.length ());
2523 unsigned int i;
2524 escape_entry *ee;
2525 FOR_EACH_VEC_ELT (esum->esc, i, ee)
2527 bp_pack_var_len_unsigned (bp, ee->parm_index);
2528 bp_pack_var_len_unsigned (bp, ee->arg);
2529 bp_pack_var_len_unsigned (bp, ee->min_flags);
2530 bp_pack_value (bp, ee->direct, 1);
2534 /* Read escape summary for E from BP. */
2536 static void
2537 modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
2539 unsigned int n = bp_unpack_var_len_unsigned (bp);
2540 if (!n)
2541 return;
2542 escape_summary *esum = escape_summaries->get_create (e);
2543 esum->esc.reserve_exact (n);
2544 for (unsigned int i = 0; i < n; i++)
2546 escape_entry ee;
2547 ee.parm_index = bp_unpack_var_len_unsigned (bp);
2548 ee.arg = bp_unpack_var_len_unsigned (bp);
2549 ee.min_flags = bp_unpack_var_len_unsigned (bp);
2550 ee.direct = bp_unpack_value (bp, 1);
2551 esum->esc.quick_push (ee);
2555 /* Callback for write_summary. */
2557 static void
2558 modref_write ()
2560 struct output_block *ob = create_output_block (LTO_section_ipa_modref);
2561 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
2562 unsigned int count = 0;
2563 int i;
2565 if (!summaries_lto)
2567 streamer_write_uhwi (ob, 0);
2568 streamer_write_char_stream (ob->main_stream, 0);
2569 produce_asm (ob, NULL);
2570 destroy_output_block (ob);
2571 return;
2574 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
2576 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
2577 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
2578 modref_summary_lto *r;
2580 if (cnode && cnode->definition && !cnode->alias
2581 && (r = summaries_lto->get (cnode))
2582 && r->useful_p (flags_from_decl_or_type (cnode->decl)))
2583 count++;
2585 streamer_write_uhwi (ob, count);
2587 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
2589 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
2590 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
2592 if (cnode && cnode->definition && !cnode->alias)
2594 modref_summary_lto *r = summaries_lto->get (cnode);
2596 if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
2597 continue;
2599 streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
2601 streamer_write_uhwi (ob, r->arg_flags.length ());
2602 for (unsigned int i = 0; i < r->arg_flags.length (); i++)
2603 streamer_write_uhwi (ob, r->arg_flags[i]);
2605 write_modref_records (r->loads, ob);
2606 write_modref_records (r->stores, ob);
2608 struct bitpack_d bp = bitpack_create (ob->main_stream);
2609 bp_pack_value (&bp, r->writes_errno, 1);
2610 if (!flag_wpa)
2612 for (cgraph_edge *e = cnode->indirect_calls;
2613 e; e = e->next_callee)
2615 class fnspec_summary *sum = fnspec_summaries->get (e);
2616 bp_pack_value (&bp, sum != NULL, 1);
2617 if (sum)
2618 bp_pack_string (ob, &bp, sum->fnspec, true);
2619 class escape_summary *esum = escape_summaries->get (e);
2620 modref_write_escape_summary (&bp,esum);
2622 for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
2624 class fnspec_summary *sum = fnspec_summaries->get (e);
2625 bp_pack_value (&bp, sum != NULL, 1);
2626 if (sum)
2627 bp_pack_string (ob, &bp, sum->fnspec, true);
2628 class escape_summary *esum = escape_summaries->get (e);
2629 modref_write_escape_summary (&bp,esum);
2632 streamer_write_bitpack (&bp);
2635 streamer_write_char_stream (ob->main_stream, 0);
2636 produce_asm (ob, NULL);
2637 destroy_output_block (ob);
2640 static void
2641 read_section (struct lto_file_decl_data *file_data, const char *data,
2642 size_t len)
2644 const struct lto_function_header *header
2645 = (const struct lto_function_header *) data;
2646 const int cfg_offset = sizeof (struct lto_function_header);
2647 const int main_offset = cfg_offset + header->cfg_size;
2648 const int string_offset = main_offset + header->main_size;
2649 struct data_in *data_in;
2650 unsigned int i;
2651 unsigned int f_count;
2653 lto_input_block ib ((const char *) data + main_offset, header->main_size,
2654 file_data->mode_table);
2656 data_in
2657 = lto_data_in_create (file_data, (const char *) data + string_offset,
2658 header->string_size, vNULL);
2659 f_count = streamer_read_uhwi (&ib);
2660 for (i = 0; i < f_count; i++)
2662 struct cgraph_node *node;
2663 lto_symtab_encoder_t encoder;
2665 unsigned int index = streamer_read_uhwi (&ib);
2666 encoder = file_data->symtab_node_encoder;
2667 node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
2668 index));
2670 modref_summary *modref_sum = summaries
2671 ? summaries->get_create (node) : NULL;
2672 modref_summary_lto *modref_sum_lto = summaries_lto
2673 ? summaries_lto->get_create (node)
2674 : NULL;
2675 if (optimization_summaries)
2676 modref_sum = optimization_summaries->get_create (node);
2678 if (modref_sum)
2679 modref_sum->writes_errno = false;
2680 if (modref_sum_lto)
2681 modref_sum_lto->writes_errno = false;
2683 gcc_assert (!modref_sum || (!modref_sum->loads
2684 && !modref_sum->stores));
2685 gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
2686 && !modref_sum_lto->stores));
2687 unsigned int args = streamer_read_uhwi (&ib);
2688 if (args && modref_sum)
2689 modref_sum->arg_flags.reserve_exact (args);
2690 if (args && modref_sum_lto)
2691 modref_sum_lto->arg_flags.reserve_exact (args);
2692 for (unsigned int i = 0; i < args; i++)
2694 eaf_flags_t flags = streamer_read_uhwi (&ib);
2695 if (modref_sum)
2696 modref_sum->arg_flags.quick_push (flags);
2697 if (modref_sum_lto)
2698 modref_sum_lto->arg_flags.quick_push (flags);
2700 read_modref_records (&ib, data_in,
2701 modref_sum ? &modref_sum->loads : NULL,
2702 modref_sum_lto ? &modref_sum_lto->loads : NULL);
2703 read_modref_records (&ib, data_in,
2704 modref_sum ? &modref_sum->stores : NULL,
2705 modref_sum_lto ? &modref_sum_lto->stores : NULL);
2706 struct bitpack_d bp = streamer_read_bitpack (&ib);
2707 if (bp_unpack_value (&bp, 1))
2709 if (modref_sum)
2710 modref_sum->writes_errno = true;
2711 if (modref_sum_lto)
2712 modref_sum_lto->writes_errno = true;
2714 if (!flag_ltrans)
2716 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
2718 if (bp_unpack_value (&bp, 1))
2720 class fnspec_summary *sum = fnspec_summaries->get_create (e);
2721 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
2723 modref_read_escape_summary (&bp, e);
2725 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
2727 if (bp_unpack_value (&bp, 1))
2729 class fnspec_summary *sum = fnspec_summaries->get_create (e);
2730 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
2732 modref_read_escape_summary (&bp, e);
2735 if (dump_file)
2737 fprintf (dump_file, "Read modref for %s\n",
2738 node->dump_name ());
2739 if (modref_sum)
2740 modref_sum->dump (dump_file);
2741 if (modref_sum_lto)
2742 modref_sum_lto->dump (dump_file);
2743 dump_modref_edge_summaries (dump_file, node, 4);
2747 lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
2748 len);
2749 lto_data_in_delete (data_in);
2752 /* Callback for read_summary. */
2754 static void
2755 modref_read (void)
2757 struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
2758 struct lto_file_decl_data *file_data;
2759 unsigned int j = 0;
2761 gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
2762 if (flag_ltrans)
2763 optimization_summaries = modref_summaries::create_ggc (symtab);
2764 else
2766 if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
2767 summaries_lto = modref_summaries_lto::create_ggc (symtab);
2768 if (!flag_wpa
2769 || (flag_incremental_link == INCREMENTAL_LINK_LTO
2770 && flag_fat_lto_objects))
2771 summaries = modref_summaries::create_ggc (symtab);
2772 if (!fnspec_summaries)
2773 fnspec_summaries = new fnspec_summaries_t (symtab);
2774 if (!escape_summaries)
2775 escape_summaries = new escape_summaries_t (symtab);
2778 while ((file_data = file_data_vec[j++]))
2780 size_t len;
2781 const char *data = lto_get_summary_section_data (file_data,
2782 LTO_section_ipa_modref,
2783 &len);
2784 if (data)
2785 read_section (file_data, data, len);
2786 else
2787 /* Fatal error here. We do not want to support compiling ltrans units
2788 with different version of compiler or different flags than the WPA
2789 unit, so this should never happen. */
2790 fatal_error (input_location,
2791 "IPA modref summary is missing in input file");
2795 /* Recompute arg_flags for param adjustments in INFO. */
2797 static void
2798 remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
2800 auto_vec<eaf_flags_t> old = arg_flags.copy ();
2801 int max = -1;
2802 size_t i;
2803 ipa_adjusted_param *p;
2805 arg_flags.release ();
2807 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2809 int o = info->param_adjustments->get_original_index (i);
2810 if (o >= 0 && (int)old.length () > o && old[o])
2811 max = i;
2813 if (max >= 0)
2814 arg_flags.safe_grow_cleared (max + 1, true);
2815 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2817 int o = info->param_adjustments->get_original_index (i);
2818 if (o >= 0 && (int)old.length () > o && old[o])
2819 arg_flags[i] = old[o];
2823 /* If signature changed, update the summary. */
2825 static void
2826 update_signature (struct cgraph_node *node)
2828 clone_info *info = clone_info::get (node);
2829 if (!info || !info->param_adjustments)
2830 return;
2832 modref_summary *r = optimization_summaries
2833 ? optimization_summaries->get (node) : NULL;
2834 modref_summary_lto *r_lto = summaries_lto
2835 ? summaries_lto->get (node) : NULL;
2836 if (!r && !r_lto)
2837 return;
2838 if (dump_file)
2840 fprintf (dump_file, "Updating summary for %s from:\n",
2841 node->dump_name ());
2842 if (r)
2843 r->dump (dump_file);
2844 if (r_lto)
2845 r_lto->dump (dump_file);
2848 size_t i, max = 0;
2849 ipa_adjusted_param *p;
2851 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2853 int idx = info->param_adjustments->get_original_index (i);
2854 if (idx > (int)max)
2855 max = idx;
2858 auto_vec <int, 32> map;
2860 map.reserve (max + 1);
2861 for (i = 0; i <= max; i++)
2862 map.quick_push (-1);
2863 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2865 int idx = info->param_adjustments->get_original_index (i);
2866 if (idx >= 0)
2867 map[idx] = i;
2869 if (r)
2871 r->loads->remap_params (&map);
2872 r->stores->remap_params (&map);
2873 if (r->arg_flags.length ())
2874 remap_arg_flags (r->arg_flags, info);
2876 if (r_lto)
2878 r_lto->loads->remap_params (&map);
2879 r_lto->stores->remap_params (&map);
2880 if (r_lto->arg_flags.length ())
2881 remap_arg_flags (r_lto->arg_flags, info);
2883 if (dump_file)
2885 fprintf (dump_file, "to:\n");
2886 if (r)
2887 r->dump (dump_file);
2888 if (r_lto)
2889 r_lto->dump (dump_file);
2891 return;
2894 /* Definition of the modref IPA pass. */
2895 const pass_data pass_data_ipa_modref =
2897 IPA_PASS, /* type */
2898 "modref", /* name */
2899 OPTGROUP_IPA, /* optinfo_flags */
2900 TV_IPA_MODREF, /* tv_id */
2901 0, /* properties_required */
2902 0, /* properties_provided */
2903 0, /* properties_destroyed */
2904 0, /* todo_flags_start */
2905 ( TODO_dump_symtab ), /* todo_flags_finish */
2908 class pass_ipa_modref : public ipa_opt_pass_d
2910 public:
2911 pass_ipa_modref (gcc::context *ctxt)
2912 : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
2913 modref_generate, /* generate_summary */
2914 modref_write, /* write_summary */
2915 modref_read, /* read_summary */
2916 modref_write, /* write_optimization_summary */
2917 modref_read, /* read_optimization_summary */
2918 NULL, /* stmt_fixup */
2919 0, /* function_transform_todo_flags_start */
2920 NULL, /* function_transform */
2921 NULL) /* variable_transform */
2924 /* opt_pass methods: */
2925 opt_pass *clone () { return new pass_ipa_modref (m_ctxt); }
2926 virtual bool gate (function *)
2928 return true;
2930 virtual unsigned int execute (function *);
2936 unsigned int pass_modref::execute (function *f)
2938 analyze_function (f, false);
2939 return 0;
2942 gimple_opt_pass *
2943 make_pass_modref (gcc::context *ctxt)
2945 return new pass_modref (ctxt);
2948 ipa_opt_pass_d *
2949 make_pass_ipa_modref (gcc::context *ctxt)
2951 return new pass_ipa_modref (ctxt);
2954 /* Skip edges from and to nodes without ipa_pure_const enabled.
2955 Ignore not available symbols. */
2957 static bool
2958 ignore_edge (struct cgraph_edge *e)
2960 /* We merge summaries of inline clones into summaries of functions they
2961 are inlined to. For that reason the complete function bodies must
2962 act as unit. */
2963 if (!e->inline_failed)
2964 return false;
2965 enum availability avail;
2966 cgraph_node *callee = e->callee->function_or_virtual_thunk_symbol
2967 (&avail, e->caller);
2969 return (avail <= AVAIL_INTERPOSABLE
2970 || ((!optimization_summaries || !optimization_summaries->get (callee))
2971 && (!summaries_lto || !summaries_lto->get (callee)))
2972 || flags_from_decl_or_type (e->callee->decl)
2973 & (ECF_CONST | ECF_NOVOPS));
2976 /* Compute parm_map for CALLEE_EDGE. */
2978 static bool
2979 compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
2981 class ipa_edge_args *args;
2982 if (ipa_node_params_sum
2983 && !callee_edge->call_stmt_cannot_inline_p
2984 && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
2986 int i, count = ipa_get_cs_argument_count (args);
2987 class ipa_node_params *caller_parms_info, *callee_pi;
2988 class ipa_call_summary *es
2989 = ipa_call_summaries->get (callee_edge);
2990 cgraph_node *callee
2991 = callee_edge->callee->function_or_virtual_thunk_symbol
2992 (NULL, callee_edge->caller);
2994 caller_parms_info
2995 = ipa_node_params_sum->get (callee_edge->caller->inlined_to
2996 ? callee_edge->caller->inlined_to
2997 : callee_edge->caller);
2998 callee_pi = ipa_node_params_sum->get (callee);
3000 (*parm_map).safe_grow_cleared (count, true);
3002 for (i = 0; i < count; i++)
3004 if (es && es->param[i].points_to_local_or_readonly_memory)
3006 (*parm_map)[i].parm_index = -2;
3007 continue;
3010 struct ipa_jump_func *jf
3011 = ipa_get_ith_jump_func (args, i);
3012 if (jf && callee_pi)
3014 tree cst = ipa_value_from_jfunc (caller_parms_info,
3016 ipa_get_type
3017 (callee_pi, i));
3018 if (cst && points_to_local_or_readonly_memory_p (cst))
3020 (*parm_map)[i].parm_index = -2;
3021 continue;
3024 if (jf && jf->type == IPA_JF_PASS_THROUGH)
3026 (*parm_map)[i].parm_index
3027 = ipa_get_jf_pass_through_formal_id (jf);
3028 if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
3030 (*parm_map)[i].parm_offset_known = true;
3031 (*parm_map)[i].parm_offset = 0;
3033 else if (ipa_get_jf_pass_through_operation (jf)
3034 == POINTER_PLUS_EXPR
3035 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
3036 &(*parm_map)[i].parm_offset))
3037 (*parm_map)[i].parm_offset_known = true;
3038 else
3039 (*parm_map)[i].parm_offset_known = false;
3040 continue;
3042 if (jf && jf->type == IPA_JF_ANCESTOR)
3044 (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
3045 (*parm_map)[i].parm_offset_known = true;
3046 gcc_checking_assert
3047 (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
3048 (*parm_map)[i].parm_offset
3049 = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
3051 else
3052 (*parm_map)[i].parm_index = -1;
3054 if (dump_file)
3056 fprintf (dump_file, " Parm map: ");
3057 for (i = 0; i < count; i++)
3058 fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
3059 fprintf (dump_file, "\n");
3061 return true;
3063 return false;
3066 /* Map used to translate escape infos. */
3068 struct escape_map
3070 int parm_index;
3071 bool direct;
3074 /* Update escape map fo E. */
3076 static void
3077 update_escape_summary_1 (cgraph_edge *e,
3078 vec <vec <escape_map>> &map,
3079 bool ignore_stores)
3081 escape_summary *sum = escape_summaries->get (e);
3082 if (!sum)
3083 return;
3084 auto_vec <escape_entry> old = sum->esc.copy ();
3085 sum->esc.release ();
3087 unsigned int i;
3088 escape_entry *ee;
3089 FOR_EACH_VEC_ELT (old, i, ee)
3091 unsigned int j;
3092 struct escape_map *em;
3093 if (ee->parm_index >= map.length ())
3094 continue;
3095 FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
3097 int min_flags = ee->min_flags;
3098 if (ee->direct && !em->direct)
3099 min_flags = deref_flags (min_flags, ignore_stores);
3100 struct escape_entry entry = {em->parm_index, ee->arg,
3101 ee->min_flags,
3102 ee->direct & em->direct};
3103 sum->esc.safe_push (entry);
3106 if (!sum->esc.length ())
3107 escape_summaries->remove (e);
3110 /* Update escape map fo NODE. */
3112 static void
3113 update_escape_summary (cgraph_node *node,
3114 vec <vec <escape_map>> &map,
3115 bool ignore_stores)
3117 if (!escape_summaries)
3118 return;
3119 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
3120 update_escape_summary_1 (e, map, ignore_stores);
3121 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3123 if (!e->inline_failed)
3124 update_escape_summary (e->callee, map, ignore_stores);
3125 else
3126 update_escape_summary_1 (e, map, ignore_stores);
3130 /* Call EDGE was inlined; merge summary from callee to the caller. */
3132 void
3133 ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
3135 if (!summaries && !summaries_lto)
3136 return;
3138 struct cgraph_node *to = (edge->caller->inlined_to
3139 ? edge->caller->inlined_to : edge->caller);
3140 class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
3141 class modref_summary_lto *to_info_lto = summaries_lto
3142 ? summaries_lto->get (to) : NULL;
3144 if (!to_info && !to_info_lto)
3146 if (summaries)
3147 summaries->remove (edge->callee);
3148 if (summaries_lto)
3149 summaries_lto->remove (edge->callee);
3150 remove_modref_edge_summaries (edge->callee);
3151 return;
3154 class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
3155 : NULL;
3156 class modref_summary_lto *callee_info_lto
3157 = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
3158 int flags = flags_from_decl_or_type (edge->callee->decl);
3159 bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
3161 if (!callee_info && to_info)
3163 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3164 to_info->loads->collapse ();
3165 if (!ignore_stores)
3166 to_info->stores->collapse ();
3168 if (!callee_info_lto && to_info_lto)
3170 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3171 to_info_lto->loads->collapse ();
3172 if (!ignore_stores)
3173 to_info_lto->stores->collapse ();
3175 if (callee_info || callee_info_lto)
3177 auto_vec <modref_parm_map, 32> parm_map;
3179 compute_parm_map (edge, &parm_map);
3181 if (!ignore_stores)
3183 if (to_info && callee_info)
3184 to_info->stores->merge (callee_info->stores, &parm_map);
3185 if (to_info_lto && callee_info_lto)
3186 to_info_lto->stores->merge (callee_info_lto->stores, &parm_map);
3188 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3190 if (to_info && callee_info)
3191 to_info->loads->merge (callee_info->loads, &parm_map);
3192 if (to_info_lto && callee_info_lto)
3193 to_info_lto->loads->merge (callee_info_lto->loads, &parm_map);
3197 /* Now merge escape summaries.
3198 For every escape to the callee we need to merge calle flags
3199 and remap calees escapes. */
3200 class escape_summary *sum = escape_summaries->get (edge);
3201 int max_escape = -1;
3202 escape_entry *ee;
3203 unsigned int i;
3205 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
3206 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3207 if ((int)ee->arg > max_escape)
3208 max_escape = ee->arg;
3210 auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
3211 emap.safe_grow (max_escape + 1, true);
3212 for (i = 0; (int)i < max_escape + 1; i++)
3213 emap[i] = vNULL;
3215 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
3216 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3218 bool needed = false;
3219 if (to_info && to_info->arg_flags.length () > ee->parm_index)
3221 int flags = callee_info
3222 && callee_info->arg_flags.length () > ee->arg
3223 ? callee_info->arg_flags[ee->arg] : 0;
3224 if (!ee->direct)
3225 flags = deref_flags (flags, ignore_stores);
3226 else if (ignore_stores)
3227 flags |= ignore_stores_eaf_flags;
3228 flags |= ee->min_flags;
3229 to_info->arg_flags[ee->parm_index] &= flags;
3230 if (to_info->arg_flags[ee->parm_index])
3231 needed = true;
3233 if (to_info_lto && to_info_lto->arg_flags.length () > ee->parm_index)
3235 int flags = callee_info_lto
3236 && callee_info_lto->arg_flags.length () > ee->arg
3237 ? callee_info_lto->arg_flags[ee->arg] : 0;
3238 if (!ee->direct)
3239 flags = deref_flags (flags, ignore_stores);
3240 else if (ignore_stores)
3241 flags |= ignore_stores_eaf_flags;
3242 flags |= ee->min_flags;
3243 to_info_lto->arg_flags[ee->parm_index] &= flags;
3244 if (to_info_lto->arg_flags[ee->parm_index])
3245 needed = true;
3247 struct escape_map entry = {ee->parm_index, ee->direct};
3248 if (needed)
3249 emap[ee->arg].safe_push (entry);
3251 update_escape_summary (edge->callee, emap, ignore_stores);
3252 for (i = 0; (int)i < max_escape + 1; i++)
3253 emap[i].release ();
3254 if (sum)
3255 escape_summaries->remove (edge);
3257 if (summaries)
3259 if (to_info && !to_info->useful_p (flags))
3261 if (dump_file)
3262 fprintf (dump_file, "Removed mod-ref summary for %s\n",
3263 to->dump_name ());
3264 summaries->remove (to);
3265 to_info = NULL;
3267 else if (to_info && dump_file)
3269 if (dump_file)
3270 fprintf (dump_file, "Updated mod-ref summary for %s\n",
3271 to->dump_name ());
3272 to_info->dump (dump_file);
3274 if (callee_info)
3275 summaries->remove (edge->callee);
3277 if (summaries_lto)
3279 if (to_info_lto && !to_info_lto->useful_p (flags))
3281 if (dump_file)
3282 fprintf (dump_file, "Removed mod-ref summary for %s\n",
3283 to->dump_name ());
3284 summaries_lto->remove (to);
3286 else if (to_info_lto && dump_file)
3288 if (dump_file)
3289 fprintf (dump_file, "Updated mod-ref summary for %s\n",
3290 to->dump_name ());
3291 to_info_lto->dump (dump_file);
3292 to_info_lto = NULL;
3294 if (callee_info_lto)
3295 summaries_lto->remove (edge->callee);
3297 if (!to_info && !to_info_lto)
3298 remove_modref_edge_summaries (to);
3299 return;
3302 /* Get parameter type from DECL. This is only safe for special cases
3303 like builtins we create fnspec for because the type match is checked
3304 at fnspec creation time. */
3306 static tree
3307 get_parm_type (tree decl, unsigned int i)
3309 tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
3311 for (unsigned int p = 0; p < i; p++)
3312 t = TREE_CHAIN (t);
3313 return TREE_VALUE (t);
3316 /* Return access mode for argument I of call E with FNSPEC. */
3318 static modref_access_node
3319 get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
3320 unsigned int i, modref_parm_map &map)
3322 tree size = NULL_TREE;
3323 unsigned int size_arg;
3325 if (!fnspec.arg_specified_p (i))
3327 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
3329 cgraph_node *node = e->caller->inlined_to
3330 ? e->caller->inlined_to : e->caller;
3331 ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
3332 ipa_edge_args *args = ipa_edge_args_sum->get (e);
3333 struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
3335 if (jf)
3336 size = ipa_value_from_jfunc (caller_parms_info, jf,
3337 get_parm_type (e->callee->decl, size_arg));
3339 else if (fnspec.arg_access_size_given_by_type_p (i))
3340 size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
3341 modref_access_node a = {0, -1, -1,
3342 map.parm_offset, map.parm_index,
3343 map.parm_offset_known};
3344 poly_int64 size_hwi;
3345 if (size
3346 && poly_int_tree_p (size, &size_hwi)
3347 && coeffs_in_range_p (size_hwi, 0,
3348 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
3350 a.size = -1;
3351 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
3353 return a;
3356 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
3357 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
3359 static bool
3360 propagate_unknown_call (cgraph_node *node,
3361 cgraph_edge *e, int ecf_flags,
3362 modref_summary *cur_summary,
3363 modref_summary_lto *cur_summary_lto)
3365 bool changed = false;
3366 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
3367 auto_vec <modref_parm_map, 32> parm_map;
3368 if (fnspec_sum
3369 && compute_parm_map (e, &parm_map))
3371 attr_fnspec fnspec (fnspec_sum->fnspec);
3373 gcc_checking_assert (fnspec.known_p ());
3374 if (fnspec.global_memory_read_p ())
3375 collapse_loads (cur_summary, cur_summary_lto);
3376 else
3378 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
3379 for (unsigned i = 0; i < parm_map.length () && t;
3380 i++, t = TREE_CHAIN (t))
3381 if (!POINTER_TYPE_P (TREE_VALUE (t)))
3383 else if (!fnspec.arg_specified_p (i)
3384 || fnspec.arg_maybe_read_p (i))
3386 modref_parm_map map = parm_map[i];
3387 if (map.parm_index == -2)
3388 continue;
3389 if (map.parm_index == -1)
3391 collapse_loads (cur_summary, cur_summary_lto);
3392 break;
3394 if (cur_summary)
3395 changed |= cur_summary->loads->insert
3396 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
3397 if (cur_summary_lto)
3398 changed |= cur_summary_lto->loads->insert
3399 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
3402 if (ignore_stores_p (node->decl, ecf_flags))
3404 else if (fnspec.global_memory_written_p ())
3405 collapse_stores (cur_summary, cur_summary_lto);
3406 else
3408 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
3409 for (unsigned i = 0; i < parm_map.length () && t;
3410 i++, t = TREE_CHAIN (t))
3411 if (!POINTER_TYPE_P (TREE_VALUE (t)))
3413 else if (!fnspec.arg_specified_p (i)
3414 || fnspec.arg_maybe_written_p (i))
3416 modref_parm_map map = parm_map[i];
3417 if (map.parm_index == -2)
3418 continue;
3419 if (map.parm_index == -1)
3421 collapse_stores (cur_summary, cur_summary_lto);
3422 break;
3424 if (cur_summary)
3425 changed |= cur_summary->stores->insert
3426 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
3427 if (cur_summary_lto)
3428 changed |= cur_summary_lto->stores->insert
3429 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
3432 if (fnspec.errno_maybe_written_p () && flag_errno_math)
3434 if (cur_summary && !cur_summary->writes_errno)
3436 cur_summary->writes_errno = true;
3437 changed = true;
3439 if (cur_summary_lto && !cur_summary_lto->writes_errno)
3441 cur_summary_lto->writes_errno = true;
3442 changed = true;
3445 return changed;
3447 if (dump_file)
3448 fprintf (dump_file, " collapsing loads\n");
3449 changed |= collapse_loads (cur_summary, cur_summary_lto);
3450 if (!ignore_stores_p (node->decl, ecf_flags))
3452 if (dump_file)
3453 fprintf (dump_file, " collapsing stores\n");
3454 changed |= collapse_stores (cur_summary, cur_summary_lto);
3456 return changed;
3459 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
3460 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
3462 static void
3463 remove_useless_summaries (cgraph_node *node,
3464 modref_summary **cur_summary_ptr,
3465 modref_summary_lto **cur_summary_lto_ptr,
3466 int ecf_flags)
3468 if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
3470 optimization_summaries->remove (node);
3471 *cur_summary_ptr = NULL;
3473 if (*cur_summary_lto_ptr
3474 && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
3476 summaries_lto->remove (node);
3477 *cur_summary_lto_ptr = NULL;
3481 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3482 and propagate loads/stores. */
3484 static void
3485 modref_propagate_in_scc (cgraph_node *component_node)
3487 bool changed = true;
3488 int iteration = 0;
3490 while (changed)
3492 changed = false;
3493 for (struct cgraph_node *cur = component_node; cur;
3494 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3496 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
3497 modref_summary *cur_summary = optimization_summaries
3498 ? optimization_summaries->get (node)
3499 : NULL;
3500 modref_summary_lto *cur_summary_lto = summaries_lto
3501 ? summaries_lto->get (node)
3502 : NULL;
3504 if (!cur_summary && !cur_summary_lto)
3505 continue;
3507 int cur_ecf_flags = flags_from_decl_or_type (node->decl);
3509 if (dump_file)
3510 fprintf (dump_file, " Processing %s%s%s\n",
3511 cur->dump_name (),
3512 TREE_READONLY (cur->decl) ? " (const)" : "",
3513 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3515 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
3517 if (e->indirect_info->ecf_flags & (ECF_CONST | ECF_NOVOPS))
3518 continue;
3519 if (dump_file)
3520 fprintf (dump_file, " Indirect call"
3521 "collapsing loads\n");
3522 if (propagate_unknown_call
3523 (node, e, e->indirect_info->ecf_flags,
3524 cur_summary, cur_summary_lto))
3526 changed = true;
3527 remove_useless_summaries (node, &cur_summary,
3528 &cur_summary_lto,
3529 cur_ecf_flags);
3530 if (!cur_summary && !cur_summary_lto)
3531 break;
3535 if (!cur_summary && !cur_summary_lto)
3536 continue;
3538 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
3539 callee_edge = callee_edge->next_callee)
3541 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
3542 modref_summary *callee_summary = NULL;
3543 modref_summary_lto *callee_summary_lto = NULL;
3544 struct cgraph_node *callee;
3546 if (flags & (ECF_CONST | ECF_NOVOPS)
3547 || !callee_edge->inline_failed)
3548 continue;
3550 /* Get the callee and its summary. */
3551 enum availability avail;
3552 callee = callee_edge->callee->function_or_virtual_thunk_symbol
3553 (&avail, cur);
3555 /* It is not necessary to re-process calls outside of the
3556 SCC component. */
3557 if (iteration > 0
3558 && (!callee->aux
3559 || ((struct ipa_dfs_info *)cur->aux)->scc_no
3560 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
3561 continue;
3563 if (dump_file)
3564 fprintf (dump_file, " Call to %s\n",
3565 callee_edge->callee->dump_name ());
3567 bool ignore_stores = ignore_stores_p (cur->decl, flags);
3569 if (avail <= AVAIL_INTERPOSABLE)
3571 if (dump_file)
3572 fprintf (dump_file, " Call target interposable"
3573 " or not available\n");
3574 changed |= propagate_unknown_call
3575 (node, callee_edge, flags,
3576 cur_summary, cur_summary_lto);
3577 if (!cur_summary && !cur_summary_lto)
3578 break;
3579 continue;
3582 /* We don't know anything about CALLEE, hence we cannot tell
3583 anything about the entire component. */
3585 if (cur_summary
3586 && !(callee_summary = optimization_summaries->get (callee)))
3588 if (dump_file)
3589 fprintf (dump_file, " No call target summary\n");
3590 changed |= propagate_unknown_call
3591 (node, callee_edge, flags,
3592 cur_summary, NULL);
3594 if (cur_summary_lto
3595 && !(callee_summary_lto = summaries_lto->get (callee)))
3597 if (dump_file)
3598 fprintf (dump_file, " No call target summary\n");
3599 changed |= propagate_unknown_call
3600 (node, callee_edge, flags,
3601 NULL, cur_summary_lto);
3604 /* We can not safely optimize based on summary of callee if it
3605 does not always bind to current def: it is possible that
3606 memory load was optimized out earlier which may not happen in
3607 the interposed variant. */
3608 if (!callee_edge->binds_to_current_def_p ())
3610 changed |= collapse_loads (cur_summary, cur_summary_lto);
3611 if (dump_file)
3612 fprintf (dump_file, " May not bind local;"
3613 " collapsing loads\n");
3617 auto_vec <modref_parm_map, 32> parm_map;
3619 compute_parm_map (callee_edge, &parm_map);
3621 /* Merge in callee's information. */
3622 if (callee_summary)
3624 changed |= cur_summary->loads->merge
3625 (callee_summary->loads, &parm_map);
3626 if (!ignore_stores)
3628 changed |= cur_summary->stores->merge
3629 (callee_summary->stores, &parm_map);
3630 if (!cur_summary->writes_errno
3631 && callee_summary->writes_errno)
3633 cur_summary->writes_errno = true;
3634 changed = true;
3638 if (callee_summary_lto)
3640 changed |= cur_summary_lto->loads->merge
3641 (callee_summary_lto->loads, &parm_map);
3642 if (!ignore_stores)
3644 changed |= cur_summary_lto->stores->merge
3645 (callee_summary_lto->stores, &parm_map);
3646 if (!cur_summary_lto->writes_errno
3647 && callee_summary_lto->writes_errno)
3649 cur_summary_lto->writes_errno = true;
3650 changed = true;
3654 if (changed)
3655 remove_useless_summaries (node, &cur_summary,
3656 &cur_summary_lto,
3657 cur_ecf_flags);
3658 if (!cur_summary && !cur_summary_lto)
3659 break;
3660 if (dump_file && changed)
3662 if (cur_summary)
3663 cur_summary->dump (dump_file);
3664 if (cur_summary_lto)
3665 cur_summary_lto->dump (dump_file);
3666 dump_modref_edge_summaries (dump_file, node, 4);
3670 iteration++;
3672 if (dump_file)
3673 fprintf (dump_file,
3674 "Propagation finished in %i iterations\n", iteration);
3677 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
3679 static void
3680 modref_propagate_dump_scc (cgraph_node *component_node)
3682 for (struct cgraph_node *cur = component_node; cur;
3683 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3684 if (!cur->inlined_to)
3686 modref_summary *cur_summary = optimization_summaries
3687 ? optimization_summaries->get (cur)
3688 : NULL;
3689 modref_summary_lto *cur_summary_lto = summaries_lto
3690 ? summaries_lto->get (cur)
3691 : NULL;
3693 fprintf (dump_file, "Propagated modref for %s%s%s\n",
3694 cur->dump_name (),
3695 TREE_READONLY (cur->decl) ? " (const)" : "",
3696 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3697 if (optimization_summaries)
3699 if (cur_summary)
3700 cur_summary->dump (dump_file);
3701 else
3702 fprintf (dump_file, " Not tracked\n");
3704 if (summaries_lto)
3706 if (cur_summary_lto)
3707 cur_summary_lto->dump (dump_file);
3708 else
3709 fprintf (dump_file, " Not tracked (lto)\n");
3714 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
3715 and SUMMARY_LTO to CUR_SUMMARY_LTO.
3716 Return true if something changed. */
3718 static bool
3719 modref_merge_call_site_flags (escape_summary *sum,
3720 modref_summary *cur_summary,
3721 modref_summary_lto *cur_summary_lto,
3722 modref_summary *summary,
3723 modref_summary_lto *summary_lto,
3724 tree caller,
3725 int ecf_flags)
3727 escape_entry *ee;
3728 unsigned int i;
3729 bool changed = false;
3730 bool ignore_stores = ignore_stores_p (caller, ecf_flags);
3732 /* If we have no useful info to propagate. */
3733 if ((!cur_summary || !cur_summary->arg_flags.length ())
3734 && (!cur_summary_lto || !cur_summary_lto->arg_flags.length ()))
3735 return false;
3737 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3739 int flags = 0;
3740 int flags_lto = 0;
3742 if (summary && ee->arg < summary->arg_flags.length ())
3743 flags = summary->arg_flags[ee->arg];
3744 if (summary_lto
3745 && ee->arg < summary_lto->arg_flags.length ())
3746 flags_lto = summary_lto->arg_flags[ee->arg];
3747 if (!ee->direct)
3749 flags = deref_flags (flags, ignore_stores);
3750 flags_lto = deref_flags (flags_lto, ignore_stores);
3752 else if (ignore_stores)
3754 flags |= ignore_stores_eaf_flags;
3755 flags_lto |= ignore_stores_eaf_flags;
3757 /* Returning the value is already accounted to at local propagation. */
3758 flags |= ee->min_flags | EAF_NOT_RETURNED;
3759 flags_lto |= ee->min_flags | EAF_NOT_RETURNED;
3760 /* Noescape implies that value also does not escape directly.
3761 Fnspec machinery does set both so compensate for this. */
3762 if (flags & EAF_NOESCAPE)
3763 flags |= EAF_NODIRECTESCAPE;
3764 if (flags_lto & EAF_NOESCAPE)
3765 flags_lto |= EAF_NODIRECTESCAPE;
3766 if (!(flags & EAF_UNUSED)
3767 && cur_summary && ee->parm_index < cur_summary->arg_flags.length ())
3769 int f = cur_summary->arg_flags[ee->parm_index];
3770 if ((f & flags) != f)
3772 f = remove_useless_eaf_flags
3773 (f & flags, ecf_flags,
3774 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
3775 cur_summary->arg_flags[ee->parm_index] = f;
3776 changed = true;
3779 if (!(flags_lto & EAF_UNUSED)
3780 && cur_summary_lto
3781 && ee->parm_index < cur_summary_lto->arg_flags.length ())
3783 int f = cur_summary_lto->arg_flags[ee->parm_index];
3784 if ((f & flags_lto) != f)
3786 f = remove_useless_eaf_flags
3787 (f & flags_lto, ecf_flags,
3788 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
3789 cur_summary_lto->arg_flags[ee->parm_index] = f;
3790 changed = true;
3794 return changed;
3797 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3798 and propagate arg flags. */
3800 static void
3801 modref_propagate_flags_in_scc (cgraph_node *component_node)
3803 bool changed = true;
3804 int iteration = 0;
3806 while (changed)
3808 changed = false;
3809 for (struct cgraph_node *cur = component_node; cur;
3810 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3812 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
3813 modref_summary *cur_summary = optimization_summaries
3814 ? optimization_summaries->get (node)
3815 : NULL;
3816 modref_summary_lto *cur_summary_lto = summaries_lto
3817 ? summaries_lto->get (node)
3818 : NULL;
3820 if (!cur_summary && !cur_summary_lto)
3821 continue;
3823 if (dump_file)
3824 fprintf (dump_file, " Processing %s%s%s\n",
3825 cur->dump_name (),
3826 TREE_READONLY (cur->decl) ? " (const)" : "",
3827 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3829 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
3831 escape_summary *sum = escape_summaries->get (e);
3833 if (!sum || (e->indirect_info->ecf_flags
3834 & (ECF_CONST | ECF_NOVOPS)))
3835 continue;
3837 changed |= modref_merge_call_site_flags
3838 (sum, cur_summary, cur_summary_lto,
3839 NULL, NULL,
3840 node->decl, e->indirect_info->ecf_flags);
3843 if (!cur_summary && !cur_summary_lto)
3844 continue;
3846 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
3847 callee_edge = callee_edge->next_callee)
3849 int ecf_flags = flags_from_decl_or_type
3850 (callee_edge->callee->decl);
3851 modref_summary *callee_summary = NULL;
3852 modref_summary_lto *callee_summary_lto = NULL;
3853 struct cgraph_node *callee;
3855 if (ecf_flags & (ECF_CONST | ECF_NOVOPS)
3856 || !callee_edge->inline_failed)
3857 continue;
3858 /* Get the callee and its summary. */
3859 enum availability avail;
3860 callee = callee_edge->callee->function_or_virtual_thunk_symbol
3861 (&avail, cur);
3863 /* It is not necessary to re-process calls outside of the
3864 SCC component. */
3865 if (iteration > 0
3866 && (!callee->aux
3867 || ((struct ipa_dfs_info *)cur->aux)->scc_no
3868 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
3869 continue;
3871 escape_summary *sum = escape_summaries->get (callee_edge);
3872 if (!sum)
3873 continue;
3875 if (dump_file)
3876 fprintf (dump_file, " Call to %s\n",
3877 callee_edge->callee->dump_name ());
3879 if (avail <= AVAIL_INTERPOSABLE
3880 || callee_edge->call_stmt_cannot_inline_p)
3882 else
3884 if (cur_summary)
3885 callee_summary = optimization_summaries->get (callee);
3886 if (cur_summary_lto)
3887 callee_summary_lto = summaries_lto->get (callee);
3889 changed |= modref_merge_call_site_flags
3890 (sum, cur_summary, cur_summary_lto,
3891 callee_summary, callee_summary_lto,
3892 node->decl, ecf_flags);
3893 if (dump_file && changed)
3895 if (cur_summary)
3896 cur_summary->dump (dump_file);
3897 if (cur_summary_lto)
3898 cur_summary_lto->dump (dump_file);
3902 iteration++;
3904 if (dump_file)
3905 fprintf (dump_file,
3906 "Propagation of flags finished in %i iterations\n", iteration);
3909 /* Run the IPA pass. This will take a function's summaries and calls and
3910 construct new summaries which represent a transitive closure. So that
3911 summary of an analyzed function contains information about the loads and
3912 stores that the function or any function that it calls does. */
3914 unsigned int
3915 pass_ipa_modref::execute (function *)
3917 if (!summaries && !summaries_lto)
3918 return 0;
3920 if (optimization_summaries)
3921 ggc_delete (optimization_summaries);
3922 optimization_summaries = summaries;
3923 summaries = NULL;
3925 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
3926 symtab->cgraph_count);
3927 int order_pos;
3928 order_pos = ipa_reduced_postorder (order, true, ignore_edge);
3929 int i;
3931 /* Iterate over all strongly connected components in post-order. */
3932 for (i = 0; i < order_pos; i++)
3934 /* Get the component's representative. That's just any node in the
3935 component from which we can traverse the entire component. */
3936 struct cgraph_node *component_node = order[i];
3938 if (dump_file)
3939 fprintf (dump_file, "\n\nStart of SCC component\n");
3941 modref_propagate_in_scc (component_node);
3942 modref_propagate_flags_in_scc (component_node);
3943 if (dump_file)
3944 modref_propagate_dump_scc (component_node);
3946 cgraph_node *node;
3947 FOR_EACH_FUNCTION (node)
3948 update_signature (node);
3949 if (summaries_lto)
3950 ((modref_summaries_lto *)summaries_lto)->propagated = true;
3951 ipa_free_postorder_info ();
3952 free (order);
3953 delete fnspec_summaries;
3954 fnspec_summaries = NULL;
3955 delete escape_summaries;
3956 escape_summaries = NULL;
3957 return 0;
3960 /* Summaries must stay alive until end of compilation. */
3962 void
3963 ipa_modref_c_finalize ()
3965 if (optimization_summaries)
3966 ggc_delete (optimization_summaries);
3967 optimization_summaries = NULL;
3968 gcc_checking_assert (!summaries
3969 || flag_incremental_link == INCREMENTAL_LINK_LTO);
3970 if (summaries_lto)
3971 ggc_delete (summaries_lto);
3972 summaries_lto = NULL;
3973 if (fnspec_summaries)
3974 delete fnspec_summaries;
3975 fnspec_summaries = NULL;
3976 if (escape_summaries)
3977 delete escape_summaries;
3978 escape_summaries = NULL;
3981 #include "gt-ipa-modref.h"