Revise -mdisable-fpregs option and add new -msoft-mult option
[official-gcc.git] / gcc / ipa-modref.c
blob0bbec8df0a2676fa8e337e33584c483fb7326db8
1 /* Search for references that a functions loads or stores.
2 Copyright (C) 2020-2021 Free Software Foundation, Inc.
3 Contributed by David Cepelik and Jan Hubicka
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 /* Mod/ref pass records summary about loads and stores performed by the
22 function. This is later used by alias analysis to disambiguate memory
23 accesses across function calls.
25 This file contains a tree pass and an IPA pass. Both performs the same
26 analysis however tree pass is executed during early and late optimization
27 passes to propagate info downwards in the compilation order. IPA pass
28 propagates across the callgraph and is able to handle recursion and works on
29 whole program during link-time analysis.
31 LTO mode differs from the local mode by not recording alias sets but types
32 that are translated to alias sets later. This is necessary in order stream
33 the information because the alias sets are rebuild at stream-in time and may
34 not correspond to ones seen during analysis. For this reason part of
35 analysis is duplicated.
37 The following information is computed
38 1) load/store access tree described in ipa-modref-tree.h
39 This is used by tree-ssa-alias to disambiguate load/stores
40 2) EAF flags used by points-to analysis (in tree-ssa-structlias).
41 and defined in tree-core.h.
42 and stored to optimization_summaries.
44 There are multiple summaries computed and used during the propagation:
45 - summaries holds summaries from analysis to IPA propagation
46 time.
47 - summaries_lto is same as summaries but holds them in a format
48 that can be streamed (as described above).
49 - fnspec_summary holds fnspec strings for call. This is
50 necessary because gimple_call_fnspec performs additional
51 analysis except for looking callee fndecl.
52 - escape_summary holds escape points for given call edge.
53 That is a vector recording what function parmaeters
54 may escape to a function call (and with what parameter index). */
56 #include "config.h"
57 #include "system.h"
58 #include "coretypes.h"
59 #include "backend.h"
60 #include "tree.h"
61 #include "gimple.h"
62 #include "alloc-pool.h"
63 #include "tree-pass.h"
64 #include "gimple-iterator.h"
65 #include "tree-dfa.h"
66 #include "cgraph.h"
67 #include "ipa-utils.h"
68 #include "symbol-summary.h"
69 #include "gimple-pretty-print.h"
70 #include "gimple-walk.h"
71 #include "print-tree.h"
72 #include "tree-streamer.h"
73 #include "alias.h"
74 #include "calls.h"
75 #include "ipa-modref-tree.h"
76 #include "ipa-modref.h"
77 #include "value-range.h"
78 #include "ipa-prop.h"
79 #include "ipa-fnsummary.h"
80 #include "attr-fnspec.h"
81 #include "symtab-clones.h"
82 #include "gimple-ssa.h"
83 #include "tree-phinodes.h"
84 #include "tree-ssa-operands.h"
85 #include "ssa-iterators.h"
86 #include "stringpool.h"
87 #include "tree-ssanames.h"
88 #include "attribs.h"
91 namespace {
93 /* We record fnspec specifiers for call edges since they depends on actual
94 gimple statements. */
96 class fnspec_summary
98 public:
99 char *fnspec;
101 fnspec_summary ()
102 : fnspec (NULL)
106 ~fnspec_summary ()
108 free (fnspec);
112 /* Summary holding fnspec string for a given call. */
114 class fnspec_summaries_t : public call_summary <fnspec_summary *>
116 public:
117 fnspec_summaries_t (symbol_table *symtab)
118 : call_summary <fnspec_summary *> (symtab) {}
119 /* Hook that is called by summary when an edge is duplicated. */
120 virtual void duplicate (cgraph_edge *,
121 cgraph_edge *,
122 fnspec_summary *src,
123 fnspec_summary *dst)
125 dst->fnspec = xstrdup (src->fnspec);
129 static fnspec_summaries_t *fnspec_summaries = NULL;
131 /* Escape summary holds a vector of param indexes that escape to
132 a given call. */
133 struct escape_entry
135 /* Parameter that escapes at a given call. */
136 unsigned int parm_index;
137 /* Argument it escapes to. */
138 unsigned int arg;
139 /* Minimal flags known about the argument. */
140 eaf_flags_t min_flags;
141 /* Does it escape directly or indirectly? */
142 bool direct;
145 /* Dump EAF flags. */
147 static void
148 dump_eaf_flags (FILE *out, int flags, bool newline = true)
150 if (flags & EAF_DIRECT)
151 fprintf (out, " direct");
152 if (flags & EAF_NOCLOBBER)
153 fprintf (out, " noclobber");
154 if (flags & EAF_NOESCAPE)
155 fprintf (out, " noescape");
156 if (flags & EAF_NODIRECTESCAPE)
157 fprintf (out, " nodirectescape");
158 if (flags & EAF_UNUSED)
159 fprintf (out, " unused");
160 if (flags & EAF_NOT_RETURNED)
161 fprintf (out, " not_returned");
162 if (flags & EAF_NOREAD)
163 fprintf (out, " noread");
164 if (newline)
165 fprintf (out, "\n");
168 struct escape_summary
170 auto_vec <escape_entry> esc;
171 void dump (FILE *out)
173 for (unsigned int i = 0; i < esc.length (); i++)
175 fprintf (out, " parm %i arg %i %s min:",
176 esc[i].parm_index,
177 esc[i].arg,
178 esc[i].direct ? "(direct)" : "(indirect)");
179 dump_eaf_flags (out, esc[i].min_flags, false);
181 fprintf (out, "\n");
185 class escape_summaries_t : public call_summary <escape_summary *>
187 public:
188 escape_summaries_t (symbol_table *symtab)
189 : call_summary <escape_summary *> (symtab) {}
190 /* Hook that is called by summary when an edge is duplicated. */
191 virtual void duplicate (cgraph_edge *,
192 cgraph_edge *,
193 escape_summary *src,
194 escape_summary *dst)
196 dst->esc = src->esc.copy ();
200 static escape_summaries_t *escape_summaries = NULL;
202 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
205 /* Class (from which there is one global instance) that holds modref summaries
206 for all analyzed functions. */
208 class GTY((user)) modref_summaries
209 : public fast_function_summary <modref_summary *, va_gc>
211 public:
212 modref_summaries (symbol_table *symtab)
213 : fast_function_summary <modref_summary *, va_gc> (symtab) {}
214 virtual void insert (cgraph_node *, modref_summary *state);
215 virtual void duplicate (cgraph_node *src_node,
216 cgraph_node *dst_node,
217 modref_summary *src_data,
218 modref_summary *dst_data);
219 static modref_summaries *create_ggc (symbol_table *symtab)
221 return new (ggc_alloc_no_dtor<modref_summaries> ())
222 modref_summaries (symtab);
226 class modref_summary_lto;
228 /* Class (from which there is one global instance) that holds modref summaries
229 for all analyzed functions. */
231 class GTY((user)) modref_summaries_lto
232 : public fast_function_summary <modref_summary_lto *, va_gc>
234 public:
235 modref_summaries_lto (symbol_table *symtab)
236 : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
237 propagated (false) {}
238 virtual void insert (cgraph_node *, modref_summary_lto *state);
239 virtual void duplicate (cgraph_node *src_node,
240 cgraph_node *dst_node,
241 modref_summary_lto *src_data,
242 modref_summary_lto *dst_data);
243 static modref_summaries_lto *create_ggc (symbol_table *symtab)
245 return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
246 modref_summaries_lto (symtab);
248 bool propagated;
251 /* Global variable holding all modref summaries
252 (from analysis to IPA propagation time). */
254 static GTY(()) fast_function_summary <modref_summary *, va_gc>
255 *summaries;
257 /* Global variable holding all modref optimization summaries
258 (from IPA propagation time or used by local optimization pass). */
260 static GTY(()) fast_function_summary <modref_summary *, va_gc>
261 *optimization_summaries;
263 /* LTO summaries hold info from analysis to LTO streaming or from LTO
264 stream-in through propagation to LTO stream-out. */
266 static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
267 *summaries_lto;
269 /* Summary for a single function which this pass produces. */
271 modref_summary::modref_summary ()
272 : loads (NULL), stores (NULL), writes_errno (NULL)
276 modref_summary::~modref_summary ()
278 if (loads)
279 ggc_delete (loads);
280 if (stores)
281 ggc_delete (stores);
284 /* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
285 useful to track. If returns_void is true moreover clear
286 EAF_NOT_RETURNED. */
287 static int
288 remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
290 if (ecf_flags & ECF_NOVOPS)
291 return 0;
292 if (ecf_flags & ECF_CONST)
293 eaf_flags &= ~implicit_const_eaf_flags;
294 else if (ecf_flags & ECF_PURE)
295 eaf_flags &= ~implicit_pure_eaf_flags;
296 else if ((ecf_flags & ECF_NORETURN) || returns_void)
297 eaf_flags &= ~EAF_NOT_RETURNED;
298 return eaf_flags;
301 /* Return true if FLAGS holds some useful information. */
303 static bool
304 eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags)
306 for (unsigned i = 0; i < flags.length (); i++)
307 if (remove_useless_eaf_flags (flags[i], ecf_flags, false))
308 return true;
309 return false;
312 /* Return true if summary is potentially useful for optimization.
313 If CHECK_FLAGS is false assume that arg_flags are useful. */
315 bool
316 modref_summary::useful_p (int ecf_flags, bool check_flags)
318 if (ecf_flags & ECF_NOVOPS)
319 return false;
320 if (arg_flags.length () && !check_flags)
321 return true;
322 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
323 return true;
324 arg_flags.release ();
325 if (ecf_flags & ECF_CONST)
326 return false;
327 if (loads && !loads->every_base)
328 return true;
329 if (ecf_flags & ECF_PURE)
330 return false;
331 return stores && !stores->every_base;
334 /* Return true if global memory is read
335 (that is loads summary contains global memory access). */
336 bool
337 modref_summary::global_memory_read_p ()
339 if (!loads)
340 return true;
341 return loads->global_access_p ();
344 /* Return true if global memory is written. */
345 bool
346 modref_summary::global_memory_written_p ()
348 if (!stores)
349 return true;
350 return stores->global_access_p ();
354 /* Single function summary used for LTO. */
356 typedef modref_tree <tree> modref_records_lto;
357 struct GTY(()) modref_summary_lto
359 /* Load and stores in functions using types rather then alias sets.
361 This is necessary to make the information streamable for LTO but is also
362 more verbose and thus more likely to hit the limits. */
363 modref_records_lto *loads;
364 modref_records_lto *stores;
365 auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
366 bool writes_errno;
368 modref_summary_lto ();
369 ~modref_summary_lto ();
370 void dump (FILE *);
371 bool useful_p (int ecf_flags, bool check_flags = true);
374 /* Summary for a single function which this pass produces. */
376 modref_summary_lto::modref_summary_lto ()
377 : loads (NULL), stores (NULL), writes_errno (NULL)
381 modref_summary_lto::~modref_summary_lto ()
383 if (loads)
384 ggc_delete (loads);
385 if (stores)
386 ggc_delete (stores);
390 /* Return true if lto summary is potentially useful for optimization.
391 If CHECK_FLAGS is false assume that arg_flags are useful. */
393 bool
394 modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
396 if (ecf_flags & ECF_NOVOPS)
397 return false;
398 if (arg_flags.length () && !check_flags)
399 return true;
400 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
401 return true;
402 arg_flags.release ();
403 if (ecf_flags & ECF_CONST)
404 return false;
405 if (loads && !loads->every_base)
406 return true;
407 if (ecf_flags & ECF_PURE)
408 return false;
409 return stores && !stores->every_base;
412 /* Dump A to OUT. */
414 static void
415 dump_access (modref_access_node *a, FILE *out)
417 fprintf (out, " access:");
418 if (a->parm_index != -1)
420 fprintf (out, " Parm %i", a->parm_index);
421 if (a->parm_offset_known)
423 fprintf (out, " param offset:");
424 print_dec ((poly_int64_pod)a->parm_offset, out, SIGNED);
427 if (a->range_info_useful_p ())
429 fprintf (out, " offset:");
430 print_dec ((poly_int64_pod)a->offset, out, SIGNED);
431 fprintf (out, " size:");
432 print_dec ((poly_int64_pod)a->size, out, SIGNED);
433 fprintf (out, " max_size:");
434 print_dec ((poly_int64_pod)a->max_size, out, SIGNED);
435 if (a->adjustments)
436 fprintf (out, " adjusted %i times", a->adjustments);
438 fprintf (out, "\n");
441 /* Dump records TT to OUT. */
443 static void
444 dump_records (modref_records *tt, FILE *out)
446 fprintf (out, " Limits: %i bases, %i refs\n",
447 (int)tt->max_bases, (int)tt->max_refs);
448 if (tt->every_base)
450 fprintf (out, " Every base\n");
451 return;
453 size_t i;
454 modref_base_node <alias_set_type> *n;
455 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
457 fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
458 if (n->every_ref)
460 fprintf (out, " Every ref\n");
461 continue;
463 size_t j;
464 modref_ref_node <alias_set_type> *r;
465 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
467 fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
468 if (r->every_access)
470 fprintf (out, " Every access\n");
471 continue;
473 size_t k;
474 modref_access_node *a;
475 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
476 dump_access (a, out);
481 /* Dump records TT to OUT. */
483 static void
484 dump_lto_records (modref_records_lto *tt, FILE *out)
486 fprintf (out, " Limits: %i bases, %i refs\n",
487 (int)tt->max_bases, (int)tt->max_refs);
488 if (tt->every_base)
490 fprintf (out, " Every base\n");
491 return;
493 size_t i;
494 modref_base_node <tree> *n;
495 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
497 fprintf (out, " Base %i:", (int)i);
498 print_generic_expr (dump_file, n->base);
499 fprintf (out, " (alias set %i)\n",
500 n->base ? get_alias_set (n->base) : 0);
501 if (n->every_ref)
503 fprintf (out, " Every ref\n");
504 continue;
506 size_t j;
507 modref_ref_node <tree> *r;
508 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
510 fprintf (out, " Ref %i:", (int)j);
511 print_generic_expr (dump_file, r->ref);
512 fprintf (out, " (alias set %i)\n",
513 r->ref ? get_alias_set (r->ref) : 0);
514 if (r->every_access)
516 fprintf (out, " Every access\n");
517 continue;
519 size_t k;
520 modref_access_node *a;
521 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
522 dump_access (a, out);
527 /* Dump all escape points of NODE to OUT. */
529 static void
530 dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
532 int i = 0;
533 if (!escape_summaries)
534 return;
535 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
537 class escape_summary *sum = escape_summaries->get (e);
538 if (sum)
540 fprintf (out, "%*sIndirect call %i in %s escapes:",
541 depth, "", i, node->dump_name ());
542 sum->dump (out);
544 i++;
546 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
548 if (!e->inline_failed)
549 dump_modref_edge_summaries (out, e->callee, depth + 1);
550 class escape_summary *sum = escape_summaries->get (e);
551 if (sum)
553 fprintf (out, "%*sCall %s->%s escapes:", depth, "",
554 node->dump_name (), e->callee->dump_name ());
555 sum->dump (out);
557 class fnspec_summary *fsum = fnspec_summaries->get (e);
558 if (fsum)
560 fprintf (out, "%*sCall %s->%s fnspec: %s\n", depth, "",
561 node->dump_name (), e->callee->dump_name (),
562 fsum->fnspec);
567 /* Remove all call edge summaries associated with NODE. */
569 static void
570 remove_modref_edge_summaries (cgraph_node *node)
572 if (!escape_summaries)
573 return;
574 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
575 escape_summaries->remove (e);
576 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
578 if (!e->inline_failed)
579 remove_modref_edge_summaries (e->callee);
580 escape_summaries->remove (e);
581 fnspec_summaries->remove (e);
585 /* Dump summary. */
587 void
588 modref_summary::dump (FILE *out)
590 if (loads)
592 fprintf (out, " loads:\n");
593 dump_records (loads, out);
595 if (stores)
597 fprintf (out, " stores:\n");
598 dump_records (stores, out);
600 if (writes_errno)
601 fprintf (out, " Writes errno\n");
602 if (arg_flags.length ())
604 for (unsigned int i = 0; i < arg_flags.length (); i++)
605 if (arg_flags[i])
607 fprintf (out, " parm %i flags:", i);
608 dump_eaf_flags (out, arg_flags[i]);
613 /* Dump summary. */
615 void
616 modref_summary_lto::dump (FILE *out)
618 fprintf (out, " loads:\n");
619 dump_lto_records (loads, out);
620 fprintf (out, " stores:\n");
621 dump_lto_records (stores, out);
622 if (writes_errno)
623 fprintf (out, " Writes errno\n");
624 if (arg_flags.length ())
626 for (unsigned int i = 0; i < arg_flags.length (); i++)
627 if (arg_flags[i])
629 fprintf (out, " parm %i flags:", i);
630 dump_eaf_flags (out, arg_flags[i]);
635 /* Get function summary for FUNC if it exists, return NULL otherwise. */
637 modref_summary *
638 get_modref_function_summary (cgraph_node *func)
640 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
641 if (!optimization_summaries)
642 return NULL;
644 /* A single function body may be represented by multiple symbols with
645 different visibility. For example, if FUNC is an interposable alias,
646 we don't want to return anything, even if we have summary for the target
647 function. */
648 enum availability avail;
649 func = func->function_or_virtual_thunk_symbol
650 (&avail, current_function_decl ?
651 cgraph_node::get (current_function_decl) : NULL);
652 if (avail <= AVAIL_INTERPOSABLE)
653 return NULL;
655 modref_summary *r = optimization_summaries->get (func);
656 return r;
659 /* Construct modref_access_node from REF. */
660 static modref_access_node
661 get_access (ao_ref *ref)
663 tree base;
665 base = ao_ref_base (ref);
666 modref_access_node a = {ref->offset, ref->size, ref->max_size,
667 0, -1, false, 0};
668 if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
670 tree memref = base;
671 base = TREE_OPERAND (base, 0);
672 if (TREE_CODE (base) == SSA_NAME
673 && SSA_NAME_IS_DEFAULT_DEF (base)
674 && TREE_CODE (SSA_NAME_VAR (base)) == PARM_DECL)
676 a.parm_index = 0;
677 for (tree t = DECL_ARGUMENTS (current_function_decl);
678 t != SSA_NAME_VAR (base); t = DECL_CHAIN (t))
680 if (!t)
682 a.parm_index = -1;
683 break;
685 a.parm_index++;
687 if (TREE_CODE (memref) == MEM_REF)
689 a.parm_offset_known
690 = wi::to_poly_wide (TREE_OPERAND
691 (memref, 1)).to_shwi (&a.parm_offset);
693 else
694 a.parm_offset_known = false;
696 else
697 a.parm_index = -1;
699 else
700 a.parm_index = -1;
701 return a;
704 /* Record access into the modref_records data structure. */
706 static void
707 record_access (modref_records *tt, ao_ref *ref)
709 alias_set_type base_set = !flag_strict_aliasing ? 0
710 : ao_ref_base_alias_set (ref);
711 alias_set_type ref_set = !flag_strict_aliasing ? 0
712 : (ao_ref_alias_set (ref));
713 modref_access_node a = get_access (ref);
714 if (dump_file)
716 fprintf (dump_file, " - Recording base_set=%i ref_set=%i parm=%i\n",
717 base_set, ref_set, a.parm_index);
719 tt->insert (base_set, ref_set, a, false);
722 /* IPA version of record_access_tree. */
724 static void
725 record_access_lto (modref_records_lto *tt, ao_ref *ref)
727 /* get_alias_set sometimes use different type to compute the alias set
728 than TREE_TYPE (base). Do same adjustments. */
729 tree base_type = NULL_TREE, ref_type = NULL_TREE;
730 if (flag_strict_aliasing)
732 tree base;
734 base = ref->ref;
735 while (handled_component_p (base))
736 base = TREE_OPERAND (base, 0);
738 base_type = reference_alias_ptr_type_1 (&base);
740 if (!base_type)
741 base_type = TREE_TYPE (base);
742 else
743 base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
744 ? NULL_TREE : TREE_TYPE (base_type);
746 tree ref_expr = ref->ref;
747 ref_type = reference_alias_ptr_type_1 (&ref_expr);
749 if (!ref_type)
750 ref_type = TREE_TYPE (ref_expr);
751 else
752 ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
753 ? NULL_TREE : TREE_TYPE (ref_type);
755 /* Sanity check that we are in sync with what get_alias_set does. */
756 gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
757 || get_alias_set (base_type)
758 == ao_ref_base_alias_set (ref));
759 gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
760 || get_alias_set (ref_type)
761 == ao_ref_alias_set (ref));
763 /* Do not bother to record types that have no meaningful alias set.
764 Also skip variably modified types since these go to local streams. */
765 if (base_type && (!get_alias_set (base_type)
766 || variably_modified_type_p (base_type, NULL_TREE)))
767 base_type = NULL_TREE;
768 if (ref_type && (!get_alias_set (ref_type)
769 || variably_modified_type_p (ref_type, NULL_TREE)))
770 ref_type = NULL_TREE;
772 modref_access_node a = get_access (ref);
773 if (dump_file)
775 fprintf (dump_file, " - Recording base type:");
776 print_generic_expr (dump_file, base_type);
777 fprintf (dump_file, " (alias set %i) ref type:",
778 base_type ? get_alias_set (base_type) : 0);
779 print_generic_expr (dump_file, ref_type);
780 fprintf (dump_file, " (alias set %i) parm:%i\n",
781 ref_type ? get_alias_set (ref_type) : 0,
782 a.parm_index);
785 tt->insert (base_type, ref_type, a, false);
788 /* Returns true if and only if we should store the access to EXPR.
789 Some accesses, e.g. loads from automatic variables, are not interesting. */
791 static bool
792 record_access_p (tree expr)
794 if (refs_local_or_readonly_memory_p (expr))
796 if (dump_file)
797 fprintf (dump_file, " - Read-only or local, ignoring.\n");
798 return false;
800 return true;
803 /* Return true if ECF flags says that return value can be ignored. */
805 static bool
806 ignore_retval_p (tree caller, int flags)
808 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
809 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
810 return true;
811 return false;
814 /* Return true if ECF flags says that stores can be ignored. */
816 static bool
817 ignore_stores_p (tree caller, int flags)
819 if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
820 return true;
821 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
822 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
823 return true;
824 return false;
827 /* Determine parm_map for argument I of STMT. */
829 modref_parm_map
830 parm_map_for_arg (gimple *stmt, int i)
832 tree op = gimple_call_arg (stmt, i);
833 bool offset_known;
834 poly_int64 offset;
835 struct modref_parm_map parm_map;
837 parm_map.parm_offset_known = false;
838 parm_map.parm_offset = 0;
840 offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
841 if (TREE_CODE (op) == SSA_NAME
842 && SSA_NAME_IS_DEFAULT_DEF (op)
843 && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
845 int index = 0;
846 for (tree t = DECL_ARGUMENTS (current_function_decl);
847 t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
849 if (!t)
851 index = -1;
852 break;
854 index++;
856 parm_map.parm_index = index;
857 parm_map.parm_offset_known = offset_known;
858 parm_map.parm_offset = offset;
860 else if (points_to_local_or_readonly_memory_p (op))
861 parm_map.parm_index = -2;
862 else
863 parm_map.parm_index = -1;
864 return parm_map;
867 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
868 int CUR_SUMMARY. Return true if something changed.
869 If IGNORE_STORES is true, do not merge stores.
870 If RECORD_ADJUSTMENTS is true cap number of adjustments to
871 a given access to make dataflow finite. */
873 bool
874 merge_call_side_effects (modref_summary *cur_summary,
875 gimple *stmt, modref_summary *callee_summary,
876 bool ignore_stores, cgraph_node *callee_node,
877 bool record_adjustments)
879 auto_vec <modref_parm_map, 32> parm_map;
880 bool changed = false;
882 /* We can not safely optimize based on summary of callee if it does
883 not always bind to current def: it is possible that memory load
884 was optimized out earlier which may not happen in the interposed
885 variant. */
886 if (!callee_node->binds_to_current_def_p ())
888 if (dump_file)
889 fprintf (dump_file, " - May be interposed: collapsing loads.\n");
890 cur_summary->loads->collapse ();
893 if (dump_file)
894 fprintf (dump_file, " - Merging side effects of %s with parm map:",
895 callee_node->dump_name ());
897 parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true);
898 for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
900 parm_map[i] = parm_map_for_arg (stmt, i);
901 if (dump_file)
903 fprintf (dump_file, " %i", parm_map[i].parm_index);
904 if (parm_map[i].parm_offset_known)
906 fprintf (dump_file, " offset:");
907 print_dec ((poly_int64_pod)parm_map[i].parm_offset,
908 dump_file, SIGNED);
912 if (dump_file)
913 fprintf (dump_file, "\n");
915 /* Merge with callee's summary. */
916 changed |= cur_summary->loads->merge (callee_summary->loads, &parm_map,
917 record_adjustments);
918 if (!ignore_stores)
920 changed |= cur_summary->stores->merge (callee_summary->stores,
921 &parm_map,
922 record_adjustments);
923 if (!cur_summary->writes_errno
924 && callee_summary->writes_errno)
926 cur_summary->writes_errno = true;
927 changed = true;
930 return changed;
933 /* Return access mode for argument I of call STMT with FNSPEC. */
935 static modref_access_node
936 get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
937 unsigned int i, modref_parm_map &map)
939 tree size = NULL_TREE;
940 unsigned int size_arg;
942 if (!fnspec.arg_specified_p (i))
944 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
945 size = gimple_call_arg (call, size_arg);
946 else if (fnspec.arg_access_size_given_by_type_p (i))
948 tree callee = gimple_call_fndecl (call);
949 tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
951 for (unsigned int p = 0; p < i; p++)
952 t = TREE_CHAIN (t);
953 size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
955 modref_access_node a = {0, -1, -1,
956 map.parm_offset, map.parm_index,
957 map.parm_offset_known, 0};
958 poly_int64 size_hwi;
959 if (size
960 && poly_int_tree_p (size, &size_hwi)
961 && coeffs_in_range_p (size_hwi, 0,
962 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
964 a.size = -1;
965 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
967 return a;
970 /* Collapse loads and return true if something changed. */
972 static bool
973 collapse_loads (modref_summary *cur_summary,
974 modref_summary_lto *cur_summary_lto)
976 bool changed = false;
978 if (cur_summary && !cur_summary->loads->every_base)
980 cur_summary->loads->collapse ();
981 changed = true;
983 if (cur_summary_lto
984 && !cur_summary_lto->loads->every_base)
986 cur_summary_lto->loads->collapse ();
987 changed = true;
989 return changed;
992 /* Collapse loads and return true if something changed. */
994 static bool
995 collapse_stores (modref_summary *cur_summary,
996 modref_summary_lto *cur_summary_lto)
998 bool changed = false;
1000 if (cur_summary && !cur_summary->stores->every_base)
1002 cur_summary->stores->collapse ();
1003 changed = true;
1005 if (cur_summary_lto
1006 && !cur_summary_lto->stores->every_base)
1008 cur_summary_lto->stores->collapse ();
1009 changed = true;
1011 return changed;
1015 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1016 If IGNORE_STORES is true ignore them.
1017 Return false if no useful summary can be produced. */
1019 static bool
1020 process_fnspec (modref_summary *cur_summary,
1021 modref_summary_lto *cur_summary_lto,
1022 gcall *call, bool ignore_stores)
1024 attr_fnspec fnspec = gimple_call_fnspec (call);
1025 if (!fnspec.known_p ())
1027 if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
1028 fprintf (dump_file, " Builtin with no fnspec: %s\n",
1029 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
1030 if (ignore_stores)
1032 collapse_loads (cur_summary, cur_summary_lto);
1033 return true;
1035 return false;
1037 if (fnspec.global_memory_read_p ())
1038 collapse_loads (cur_summary, cur_summary_lto);
1039 else
1041 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1042 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1044 else if (!fnspec.arg_specified_p (i)
1045 || fnspec.arg_maybe_read_p (i))
1047 modref_parm_map map = parm_map_for_arg (call, i);
1049 if (map.parm_index == -2)
1050 continue;
1051 if (map.parm_index == -1)
1053 collapse_loads (cur_summary, cur_summary_lto);
1054 break;
1056 if (cur_summary)
1057 cur_summary->loads->insert (0, 0,
1058 get_access_for_fnspec (call,
1059 fnspec, i,
1060 map),
1061 false);
1062 if (cur_summary_lto)
1063 cur_summary_lto->loads->insert (0, 0,
1064 get_access_for_fnspec (call,
1065 fnspec, i,
1066 map),
1067 false);
1070 if (ignore_stores)
1071 return true;
1072 if (fnspec.global_memory_written_p ())
1073 collapse_stores (cur_summary, cur_summary_lto);
1074 else
1076 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1077 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1079 else if (!fnspec.arg_specified_p (i)
1080 || fnspec.arg_maybe_written_p (i))
1082 modref_parm_map map = parm_map_for_arg (call, i);
1084 if (map.parm_index == -2)
1085 continue;
1086 if (map.parm_index == -1)
1088 collapse_stores (cur_summary, cur_summary_lto);
1089 break;
1091 if (cur_summary)
1092 cur_summary->stores->insert (0, 0,
1093 get_access_for_fnspec (call,
1094 fnspec, i,
1095 map),
1096 false);
1097 if (cur_summary_lto)
1098 cur_summary_lto->stores->insert (0, 0,
1099 get_access_for_fnspec (call,
1100 fnspec, i,
1101 map),
1102 false);
1104 if (fnspec.errno_maybe_written_p () && flag_errno_math)
1106 if (cur_summary)
1107 cur_summary->writes_errno = true;
1108 if (cur_summary_lto)
1109 cur_summary_lto->writes_errno = true;
1112 return true;
1115 /* Analyze function call STMT in function F.
1116 Remember recursive calls in RECURSIVE_CALLS. */
1118 static bool
1119 analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto,
1120 gcall *stmt, vec <gimple *> *recursive_calls)
1122 /* Check flags on the function call. In certain cases, analysis can be
1123 simplified. */
1124 int flags = gimple_call_flags (stmt);
1125 if (flags & (ECF_CONST | ECF_NOVOPS))
1127 if (dump_file)
1128 fprintf (dump_file,
1129 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1130 "except for args.\n");
1131 return true;
1134 /* Pure functions do not affect global memory. Stores by functions which are
1135 noreturn and do not throw can safely be ignored. */
1136 bool ignore_stores = ignore_stores_p (current_function_decl, flags);
1138 /* Next, we try to get the callee's function declaration. The goal is to
1139 merge their summary with ours. */
1140 tree callee = gimple_call_fndecl (stmt);
1142 /* Check if this is an indirect call. */
1143 if (!callee)
1145 if (dump_file)
1146 fprintf (dump_file, gimple_call_internal_p (stmt)
1147 ? " - Internal call" : " - Indirect call.\n");
1148 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1150 /* We only need to handle internal calls in IPA mode. */
1151 gcc_checking_assert (!cur_summary_lto);
1153 struct cgraph_node *callee_node = cgraph_node::get_create (callee);
1155 /* If this is a recursive call, the target summary is the same as ours, so
1156 there's nothing to do. */
1157 if (recursive_call_p (current_function_decl, callee))
1159 recursive_calls->safe_push (stmt);
1160 if (dump_file)
1161 fprintf (dump_file, " - Skipping recursive call.\n");
1162 return true;
1165 gcc_assert (callee_node != NULL);
1167 /* Get the function symbol and its availability. */
1168 enum availability avail;
1169 callee_node = callee_node->function_symbol (&avail);
1170 if (avail <= AVAIL_INTERPOSABLE)
1172 if (dump_file)
1173 fprintf (dump_file, " - Function availability <= AVAIL_INTERPOSABLE.\n");
1174 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1177 /* Get callee's modref summary. As above, if there's no summary, we either
1178 have to give up or, if stores are ignored, we can just purge loads. */
1179 modref_summary *callee_summary = optimization_summaries->get (callee_node);
1180 if (!callee_summary)
1182 if (dump_file)
1183 fprintf (dump_file, " - No modref summary available for callee.\n");
1184 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1187 merge_call_side_effects (cur_summary, stmt, callee_summary, ignore_stores,
1188 callee_node, false);
1190 return true;
1193 /* Support analysis in non-lto and lto mode in parallel. */
1195 struct summary_ptrs
1197 struct modref_summary *nolto;
1198 struct modref_summary_lto *lto;
1201 /* Helper for analyze_stmt. */
1203 static bool
1204 analyze_load (gimple *, tree, tree op, void *data)
1206 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1207 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1209 if (dump_file)
1211 fprintf (dump_file, " - Analyzing load: ");
1212 print_generic_expr (dump_file, op);
1213 fprintf (dump_file, "\n");
1216 if (!record_access_p (op))
1217 return false;
1219 ao_ref r;
1220 ao_ref_init (&r, op);
1222 if (summary)
1223 record_access (summary->loads, &r);
1224 if (summary_lto)
1225 record_access_lto (summary_lto->loads, &r);
1226 return false;
1229 /* Helper for analyze_stmt. */
1231 static bool
1232 analyze_store (gimple *, tree, tree op, void *data)
1234 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1235 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1237 if (dump_file)
1239 fprintf (dump_file, " - Analyzing store: ");
1240 print_generic_expr (dump_file, op);
1241 fprintf (dump_file, "\n");
1244 if (!record_access_p (op))
1245 return false;
1247 ao_ref r;
1248 ao_ref_init (&r, op);
1250 if (summary)
1251 record_access (summary->stores, &r);
1252 if (summary_lto)
1253 record_access_lto (summary_lto->stores, &r);
1254 return false;
1257 /* Analyze statement STMT of function F.
1258 If IPA is true do not merge in side effects of calls. */
1260 static bool
1261 analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
1262 gimple *stmt, bool ipa, vec <gimple *> *recursive_calls)
1264 /* In general we can not ignore clobbers because they are barriers for code
1265 motion, however after inlining it is safe to do because local optimization
1266 passes do not consider clobbers from other functions.
1267 Similar logic is in ipa-pure-const.c. */
1268 if ((ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1269 return true;
1271 struct summary_ptrs sums = {summary, summary_lto};
1273 /* Analyze all loads and stores in STMT. */
1274 walk_stmt_load_store_ops (stmt, &sums,
1275 analyze_load, analyze_store);
1277 switch (gimple_code (stmt))
1279 case GIMPLE_ASM:
1280 /* If the ASM statement does not read nor write memory, there's nothing
1281 to do. Otherwise just give up. */
1282 if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1283 return true;
1284 if (dump_file)
1285 fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1286 "which clobbers memory.\n");
1287 return false;
1288 case GIMPLE_CALL:
1289 if (!ipa || gimple_call_internal_p (stmt))
1290 return analyze_call (summary, summary_lto,
1291 as_a <gcall *> (stmt), recursive_calls);
1292 else
1294 attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1296 if (fnspec.known_p ()
1297 && (!fnspec.global_memory_read_p ()
1298 || !fnspec.global_memory_written_p ()))
1300 cgraph_edge *e = cgraph_node::get (current_function_decl)->get_edge (stmt);
1301 if (e->callee)
1303 fnspec_summaries->get_create (e)->fnspec = xstrdup (fnspec.get_str ());
1304 if (dump_file)
1305 fprintf (dump_file, " Recorded fnspec %s\n", fnspec.get_str ());
1309 return true;
1310 default:
1311 /* Nothing to do for other types of statements. */
1312 return true;
1316 /* Remove summary of current function because during the function body
1317 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1318 mode of scan. */
1320 static void
1321 remove_summary (bool lto, bool nolto, bool ipa)
1323 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1324 if (!ipa)
1325 optimization_summaries->remove (fnode);
1326 else
1328 if (nolto)
1329 summaries->remove (fnode);
1330 if (lto)
1331 summaries_lto->remove (fnode);
1332 remove_modref_edge_summaries (fnode);
1334 if (dump_file)
1335 fprintf (dump_file,
1336 " - modref done with result: not tracked.\n");
1339 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1341 bool
1342 memory_access_to (tree op, tree ssa_name)
1344 tree base = get_base_address (op);
1345 if (!base)
1346 return false;
1347 if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1348 return false;
1349 return TREE_OPERAND (base, 0) == ssa_name;
1352 /* Consider statement val = *arg.
1353 return EAF flags of ARG that can be determined from EAF flags of VAL
1354 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1355 all stores to VAL, i.e. when handling noreturn function. */
1357 static int
1358 deref_flags (int flags, bool ignore_stores)
1360 int ret = EAF_NODIRECTESCAPE;
1361 /* If argument is unused just account for
1362 the read involved in dereference. */
1363 if (flags & EAF_UNUSED)
1364 ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOT_RETURNED;
1365 else
1367 if ((flags & EAF_NOCLOBBER) || ignore_stores)
1368 ret |= EAF_NOCLOBBER;
1369 if ((flags & EAF_NOESCAPE) || ignore_stores)
1370 ret |= EAF_NOESCAPE;
1371 /* If the value dereferenced is not used for another load or store
1372 we can still consider ARG as used only directly.
1374 Consider
1377 test (int *a)
1379 return *a!=0;
1383 if ((flags & (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT))
1384 == (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT)
1385 && ((flags & EAF_NOCLOBBER) || ignore_stores))
1386 ret |= EAF_DIRECT;
1387 if (flags & EAF_NOT_RETURNED)
1388 ret |= EAF_NOT_RETURNED;
1390 return ret;
1393 namespace {
1395 /* Description of an escape point. */
1397 struct escape_point
1399 /* Value escapes to this call. */
1400 gcall *call;
1401 /* Argument it escapes to. */
1402 int arg;
1403 /* Flags already known about the argument (this can save us from recording
1404 esape points if local analysis did good job already). */
1405 eaf_flags_t min_flags;
1406 /* Does value escape directly or indiretly? */
1407 bool direct;
1410 class modref_lattice
1412 public:
1413 /* EAF flags of the SSA name. */
1414 eaf_flags_t flags;
1415 /* DFS bookkkeeping: we don't do real dataflow yet. */
1416 bool known;
1417 bool open;
1419 /* When doing IPA analysis we can not merge in callee escape points;
1420 Only remember them and do the merging at IPA propagation time. */
1421 vec <escape_point, va_heap, vl_ptr> escape_points;
1423 void init ();
1424 void release ();
1425 bool merge (const modref_lattice &with);
1426 bool merge (int flags);
1427 bool merge_deref (const modref_lattice &with, bool ignore_stores);
1428 bool merge_direct_load ();
1429 bool merge_direct_store ();
1430 bool add_escape_point (gcall *call, int arg, int min_flags, bool diret);
1431 void dump (FILE *out, int indent = 0) const;
1434 /* Lattices are saved to vectors, so keep them PODs. */
1435 void
1436 modref_lattice::init ()
1438 /* All flags we track. */
1439 int f = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED
1440 | EAF_NODIRECTESCAPE | EAF_NOT_RETURNED | EAF_NOREAD;
1441 flags = f;
1442 /* Check that eaf_flags_t is wide enough to hold all flags. */
1443 gcc_checking_assert (f == flags);
1444 open = true;
1445 known = false;
1448 /* Release memory. */
1449 void
1450 modref_lattice::release ()
1452 escape_points.release ();
1455 /* Dump lattice to OUT; indent with INDENT spaces. */
1457 void
1458 modref_lattice::dump (FILE *out, int indent) const
1460 dump_eaf_flags (out, flags);
1461 if (escape_points.length ())
1463 fprintf (out, "%*sEscapes:\n", indent, "");
1464 for (unsigned int i = 0; i < escape_points.length (); i++)
1466 fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
1467 escape_points[i].arg,
1468 escape_points[i].direct ? "direct" : "indirect");
1469 dump_eaf_flags (out, escape_points[i].min_flags, false);
1470 fprintf (out, " in call ");
1471 print_gimple_stmt (out, escape_points[i].call, 0);
1476 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1477 point exists. */
1479 bool
1480 modref_lattice::add_escape_point (gcall *call, int arg, int min_flags,
1481 bool direct)
1483 escape_point *ep;
1484 unsigned int i;
1486 /* If we already determined flags to be bad enough,
1487 we do not need to record. */
1488 if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
1489 return false;
1491 FOR_EACH_VEC_ELT (escape_points, i, ep)
1492 if (ep->call == call && ep->arg == arg && ep->direct == direct)
1494 if ((ep->min_flags & min_flags) == min_flags)
1495 return false;
1496 ep->min_flags &= min_flags;
1497 return true;
1499 /* Give up if max escape points is met. */
1500 if ((int)escape_points.length () > param_modref_max_escape_points)
1502 if (dump_file)
1503 fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
1504 merge (0);
1505 return true;
1507 escape_point new_ep = {call, arg, min_flags, direct};
1508 escape_points.safe_push (new_ep);
1509 return true;
1512 /* Merge in flags from F. */
1513 bool
1514 modref_lattice::merge (int f)
1516 if (f & EAF_UNUSED)
1517 return false;
1518 /* Noescape implies that value also does not escape directly.
1519 Fnspec machinery does set both so compensate for this. */
1520 if (f & EAF_NOESCAPE)
1521 f |= EAF_NODIRECTESCAPE;
1522 if ((flags & f) != flags)
1524 flags &= f;
1525 /* Prune obvoiusly useless flags;
1526 We do not have ECF_FLAGS handy which is not big problem since
1527 we will do final flags cleanup before producing summary.
1528 Merging should be fast so it can work well with dataflow. */
1529 flags = remove_useless_eaf_flags (flags, 0, false);
1530 if (!flags)
1531 escape_points.release ();
1532 return true;
1534 return false;
1537 /* Merge in WITH. Return true if anyting changed. */
1539 bool
1540 modref_lattice::merge (const modref_lattice &with)
1542 if (!with.known)
1543 return merge (0);
1545 bool changed = merge (with.flags);
1547 if (!flags)
1548 return changed;
1549 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1550 changed |= add_escape_point (with.escape_points[i].call,
1551 with.escape_points[i].arg,
1552 with.escape_points[i].min_flags,
1553 with.escape_points[i].direct);
1554 return changed;
1557 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1558 stores. Return true if anyting changed. */
1560 bool
1561 modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
1563 if (!with.known)
1564 return merge (0);
1566 bool changed = merge (deref_flags (with.flags, ignore_stores));
1568 if (!flags)
1569 return changed;
1570 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1572 int min_flags = with.escape_points[i].min_flags;
1574 if (with.escape_points[i].direct)
1575 min_flags = deref_flags (min_flags, ignore_stores);
1576 else if (ignore_stores)
1577 min_flags |= ignore_stores_eaf_flags;
1578 changed |= add_escape_point (with.escape_points[i].call,
1579 with.escape_points[i].arg,
1580 min_flags,
1581 false);
1583 return changed;
1586 /* Merge in flags for direct load. */
1588 bool
1589 modref_lattice::merge_direct_load ()
1591 return merge (~(EAF_UNUSED | EAF_NOREAD));
1594 /* Merge in flags for direct store. */
1596 bool
1597 modref_lattice::merge_direct_store ()
1599 return merge (~(EAF_UNUSED | EAF_NOCLOBBER));
1602 } /* ANON namespace. */
1604 static void analyze_ssa_name_flags (tree name,
1605 vec<modref_lattice> &lattice,
1606 int depth, bool ipa);
1608 /* Call statements may return their parameters. Consider argument number
1609 ARG of USE_STMT and determine flags that can needs to be cleared
1610 in case pointer possibly indirectly references from ARG I is returned.
1611 LATTICE, DEPTH and ipa are same as in analyze_ssa_name_flags. */
1613 static void
1614 merge_call_lhs_flags (gcall *call, int arg, int index, bool deref,
1615 vec<modref_lattice> &lattice,
1616 int depth, bool ipa)
1618 /* If there is no return value, no flags are affected. */
1619 if (!gimple_call_lhs (call))
1620 return;
1622 /* If we know that function returns given argument and it is not ARG
1623 we can still be happy. */
1624 int flags = gimple_call_return_flags (call);
1625 if ((flags & ERF_RETURNS_ARG)
1626 && (flags & ERF_RETURN_ARG_MASK) != arg)
1627 return;
1629 if (gimple_call_arg_flags (call, arg) & (EAF_NOT_RETURNED | EAF_UNUSED))
1630 return;
1632 /* If return value is SSA name determine its flags. */
1633 if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
1635 tree lhs = gimple_call_lhs (call);
1636 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1637 if (deref)
1638 lattice[index].merge_deref (lattice[SSA_NAME_VERSION (lhs)], false);
1639 else
1640 lattice[index].merge (lattice[SSA_NAME_VERSION (lhs)]);
1642 /* In the case of memory store we can do nothing. */
1643 else
1644 lattice[index].merge (0);
1647 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
1648 LATTICE is an array of modref_lattices.
1649 DEPTH is a recursion depth used to make debug output prettier.
1650 If IPA is true we analyze for IPA propagation (and thus call escape points
1651 are processed later) */
1653 static void
1654 analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
1655 bool ipa)
1657 imm_use_iterator ui;
1658 gimple *use_stmt;
1659 int index = SSA_NAME_VERSION (name);
1661 /* See if value is already computed. */
1662 if (lattice[index].known)
1663 return;
1664 if (lattice[index].open)
1666 if (dump_file)
1667 fprintf (dump_file,
1668 "%*sGiving up on a cycle in SSA graph\n", depth * 4, "");
1669 return;
1671 if (depth == param_modref_max_depth)
1673 if (dump_file)
1674 fprintf (dump_file,
1675 "%*sGiving up on max depth\n", depth * 4, "");
1676 return;
1678 /* Recursion guard. */
1679 lattice[index].init ();
1681 if (dump_file)
1683 fprintf (dump_file,
1684 "%*sAnalyzing flags of ssa name: ", depth * 4, "");
1685 print_generic_expr (dump_file, name);
1686 fprintf (dump_file, "\n");
1689 FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
1691 if (lattice[index].flags == 0)
1692 break;
1693 if (is_gimple_debug (use_stmt))
1694 continue;
1695 if (dump_file)
1697 fprintf (dump_file, "%*s Analyzing stmt: ", depth * 4, "");
1698 print_gimple_stmt (dump_file, use_stmt, 0);
1700 /* If we see a direct non-debug use, clear unused bit.
1701 All dereferneces should be accounted below using deref_flags. */
1702 lattice[index].merge (~EAF_UNUSED);
1704 /* Gimple return may load the return value.
1705 Returning name counts as an use by tree-ssa-structalias.c */
1706 if (greturn *ret = dyn_cast <greturn *> (use_stmt))
1708 if (gimple_return_retval (ret) == name)
1709 lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED));
1710 else if (memory_access_to (gimple_return_retval (ret), name))
1712 lattice[index].merge_direct_load ();
1713 lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED));
1716 /* Account for LHS store, arg loads and flags from callee function. */
1717 else if (gcall *call = dyn_cast <gcall *> (use_stmt))
1719 tree callee = gimple_call_fndecl (call);
1721 /* IPA PTA internally it treats calling a function as "writing" to
1722 the argument space of all functions the function pointer points to
1723 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
1724 is on since that would allow propagation of this from -fno-ipa-pta
1725 to -fipa-pta functions. */
1726 if (gimple_call_fn (use_stmt) == name)
1727 lattice[index].merge (~(EAF_NOCLOBBER | EAF_UNUSED));
1729 /* Recursion would require bit of propagation; give up for now. */
1730 if (callee && !ipa && recursive_call_p (current_function_decl,
1731 callee))
1732 lattice[index].merge (0);
1733 else
1735 int ecf_flags = gimple_call_flags (call);
1736 bool ignore_stores = ignore_stores_p (current_function_decl,
1737 ecf_flags);
1738 bool ignore_retval = ignore_retval_p (current_function_decl,
1739 ecf_flags);
1741 /* Handle *name = func (...). */
1742 if (gimple_call_lhs (call)
1743 && memory_access_to (gimple_call_lhs (call), name))
1745 lattice[index].merge_direct_store ();
1746 /* Return slot optimization passes address of
1747 LHS to callee via hidden parameter and this
1748 may make LHS to escape. See PR 98499. */
1749 if (gimple_call_return_slot_opt_p (call)
1750 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
1751 lattice[index].merge (EAF_NOREAD | EAF_DIRECT);
1754 /* We do not track accesses to the static chain (we could)
1755 so give up. */
1756 if (gimple_call_chain (call)
1757 && (gimple_call_chain (call) == name))
1758 lattice[index].merge (0);
1760 /* Process internal functions and right away. */
1761 bool record_ipa = ipa && !gimple_call_internal_p (call);
1763 /* Handle all function parameters. */
1764 for (unsigned i = 0;
1765 i < gimple_call_num_args (call) && lattice[index].flags; i++)
1766 /* Name is directly passed to the callee. */
1767 if (gimple_call_arg (call, i) == name)
1769 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
1771 int call_flags = gimple_call_arg_flags (call, i)
1772 | EAF_NOT_RETURNED;
1773 if (ignore_stores)
1774 call_flags |= ignore_stores_eaf_flags;
1776 if (!record_ipa)
1777 lattice[index].merge (call_flags);
1778 else
1779 lattice[index].add_escape_point (call, i,
1780 call_flags, true);
1782 if (!ignore_retval)
1783 merge_call_lhs_flags (call, i, index, false,
1784 lattice, depth, ipa);
1786 /* Name is dereferenced and passed to a callee. */
1787 else if (memory_access_to (gimple_call_arg (call, i), name))
1789 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
1790 lattice[index].merge_direct_load ();
1791 else
1793 int call_flags = deref_flags
1794 (gimple_call_arg_flags (call, i)
1795 | EAF_NOT_RETURNED, ignore_stores);
1796 if (!record_ipa)
1797 lattice[index].merge (call_flags);
1798 else
1799 lattice[index].add_escape_point (call, i,
1800 call_flags, false);
1802 if (!ignore_retval)
1803 merge_call_lhs_flags (call, i, index, true,
1804 lattice, depth, ipa);
1808 else if (gimple_assign_load_p (use_stmt))
1810 gassign *assign = as_a <gassign *> (use_stmt);
1811 /* Memory to memory copy. */
1812 if (gimple_store_p (assign))
1814 /* Handle *lhs = *name.
1816 We do not track memory locations, so assume that value
1817 is used arbitrarily. */
1818 if (memory_access_to (gimple_assign_rhs1 (assign), name))
1819 lattice[index].merge (0);
1820 /* Handle *name = *exp. */
1821 else if (memory_access_to (gimple_assign_lhs (assign), name))
1822 lattice[index].merge_direct_store ();
1824 /* Handle lhs = *name. */
1825 else if (memory_access_to (gimple_assign_rhs1 (assign), name))
1827 tree lhs = gimple_assign_lhs (assign);
1828 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1829 lattice[index].merge_deref (lattice[SSA_NAME_VERSION (lhs)],
1830 false);
1833 else if (gimple_store_p (use_stmt))
1835 gassign *assign = dyn_cast <gassign *> (use_stmt);
1837 /* Handle *lhs = name. */
1838 if (assign && gimple_assign_rhs1 (assign) == name)
1840 if (dump_file)
1841 fprintf (dump_file, "%*s ssa name saved to memory\n",
1842 depth * 4, "");
1843 lattice[index].merge (0);
1845 /* Handle *name = exp. */
1846 else if (assign
1847 && memory_access_to (gimple_assign_lhs (assign), name))
1849 /* In general we can not ignore clobbers because they are
1850 barriers for code motion, however after inlining it is safe to
1851 do because local optimization passes do not consider clobbers
1852 from other functions. Similar logic is in ipa-pure-const.c. */
1853 if (!cfun->after_inlining || !gimple_clobber_p (assign))
1854 lattice[index].merge_direct_store ();
1856 /* ASM statements etc. */
1857 else if (!assign)
1859 if (dump_file)
1860 fprintf (dump_file, "%*s Unhandled store\n",
1861 depth * 4, "");
1862 lattice[index].merge (0);
1865 else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
1867 enum tree_code code = gimple_assign_rhs_code (assign);
1869 /* See if operation is a merge as considered by
1870 tree-ssa-structalias.c:find_func_aliases. */
1871 if (!truth_value_p (code)
1872 && code != POINTER_DIFF_EXPR
1873 && (code != POINTER_PLUS_EXPR
1874 || gimple_assign_rhs1 (assign) == name))
1876 tree lhs = gimple_assign_lhs (assign);
1877 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1878 lattice[index].merge (lattice[SSA_NAME_VERSION (lhs)]);
1881 else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
1883 tree result = gimple_phi_result (phi);
1884 analyze_ssa_name_flags (result, lattice, depth + 1, ipa);
1885 lattice[index].merge (lattice[SSA_NAME_VERSION (result)]);
1887 /* Conditions are not considered escape points
1888 by tree-ssa-structalias. */
1889 else if (gimple_code (use_stmt) == GIMPLE_COND)
1891 else
1893 if (dump_file)
1894 fprintf (dump_file, "%*s Unhandled stmt\n", depth * 4, "");
1895 lattice[index].merge (0);
1898 if (dump_file)
1900 fprintf (dump_file, "%*s current flags of ", depth * 4, "");
1901 print_generic_expr (dump_file, name);
1902 lattice[index].dump (dump_file, depth * 4 + 4);
1905 if (dump_file)
1907 fprintf (dump_file, "%*sflags of ssa name ", depth * 4, "");
1908 print_generic_expr (dump_file, name);
1909 lattice[index].dump (dump_file, depth * 4 + 2);
1911 lattice[index].open = false;
1912 lattice[index].known = true;
1915 /* Determine EAF flags for function parameters. */
1917 static void
1918 analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
1919 bool ipa)
1921 unsigned int parm_index = 0;
1922 unsigned int count = 0;
1923 int ecf_flags = flags_from_decl_or_type (current_function_decl);
1925 /* For novops functions we have nothing to gain by EAF flags. */
1926 if (ecf_flags & ECF_NOVOPS)
1927 return;
1929 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
1930 parm = TREE_CHAIN (parm))
1931 count++;
1933 if (!count)
1934 return;
1936 auto_vec<modref_lattice> lattice;
1937 lattice.safe_grow_cleared (num_ssa_names, true);
1939 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
1940 parm = TREE_CHAIN (parm))
1942 tree name = ssa_default_def (cfun, parm);
1943 if (!name || has_zero_uses (name))
1945 /* We do not track non-SSA parameters,
1946 but we want to track unused gimple_regs. */
1947 if (!is_gimple_reg (parm))
1948 continue;
1949 if (summary)
1951 if (parm_index >= summary->arg_flags.length ())
1952 summary->arg_flags.safe_grow_cleared (count, true);
1953 summary->arg_flags[parm_index] = EAF_UNUSED;
1955 else if (summary_lto)
1957 if (parm_index >= summary_lto->arg_flags.length ())
1958 summary_lto->arg_flags.safe_grow_cleared (count, true);
1959 summary_lto->arg_flags[parm_index] = EAF_UNUSED;
1961 continue;
1963 analyze_ssa_name_flags (name, lattice, 0, ipa);
1964 int flags = lattice[SSA_NAME_VERSION (name)].flags;
1966 /* Eliminate useless flags so we do not end up storing unnecessary
1967 summaries. */
1969 flags = remove_useless_eaf_flags
1970 (flags, ecf_flags,
1971 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
1973 if (flags)
1975 if (summary)
1977 if (parm_index >= summary->arg_flags.length ())
1978 summary->arg_flags.safe_grow_cleared (count, true);
1979 summary->arg_flags[parm_index] = flags;
1981 else if (summary_lto)
1983 if (parm_index >= summary_lto->arg_flags.length ())
1984 summary_lto->arg_flags.safe_grow_cleared (count, true);
1985 summary_lto->arg_flags[parm_index] = flags;
1987 if (lattice[SSA_NAME_VERSION (name)].escape_points.length ())
1989 escape_point *ep;
1990 unsigned int ip;
1991 cgraph_node *node = cgraph_node::get (current_function_decl);
1993 gcc_checking_assert (ipa);
1994 FOR_EACH_VEC_ELT
1995 (lattice[SSA_NAME_VERSION (name)].escape_points, ip, ep)
1996 if ((ep->min_flags & flags) != flags)
1998 cgraph_edge *e = node->get_edge (ep->call);
1999 struct escape_entry ee = {parm_index, ep->arg,
2000 ep->min_flags, ep->direct};
2002 escape_summaries->get_create (e)->esc.safe_push (ee);
2007 if (ipa)
2008 for (unsigned int i = 0; i < num_ssa_names; i++)
2009 lattice[i].release ();
2012 /* Analyze function F. IPA indicates whether we're running in local mode
2013 (false) or the IPA mode (true). */
2015 static void
2016 analyze_function (function *f, bool ipa)
2018 if (dump_file)
2019 fprintf (dump_file, "modref analyzing '%s' (ipa=%i)%s%s\n",
2020 function_name (f), ipa,
2021 TREE_READONLY (current_function_decl) ? " (const)" : "",
2022 DECL_PURE_P (current_function_decl) ? " (pure)" : "");
2024 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
2025 if (!flag_ipa_modref
2026 || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
2027 return;
2029 /* Compute no-LTO summaries when local optimization is going to happen. */
2030 bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
2031 || (in_lto_p && !flag_wpa
2032 && flag_incremental_link != INCREMENTAL_LINK_LTO));
2033 /* Compute LTO when LTO streaming is going to happen. */
2034 bool lto = ipa && ((flag_lto && !in_lto_p)
2035 || flag_wpa
2036 || flag_incremental_link == INCREMENTAL_LINK_LTO);
2037 cgraph_node *fnode = cgraph_node::get (current_function_decl);
2039 modref_summary *summary = NULL;
2040 modref_summary_lto *summary_lto = NULL;
2042 /* Initialize the summary.
2043 If we run in local mode there is possibly pre-existing summary from
2044 IPA pass. Dump it so it is easy to compare if mod-ref info has
2045 improved. */
2046 if (!ipa)
2048 if (!optimization_summaries)
2049 optimization_summaries = modref_summaries::create_ggc (symtab);
2050 else /* Remove existing summary if we are re-running the pass. */
2052 if (dump_file
2053 && (summary
2054 = optimization_summaries->get (cgraph_node::get (f->decl)))
2055 != NULL
2056 && summary->loads)
2058 fprintf (dump_file, "Past summary:\n");
2059 optimization_summaries->get
2060 (cgraph_node::get (f->decl))->dump (dump_file);
2062 optimization_summaries->remove (cgraph_node::get (f->decl));
2064 summary = optimization_summaries->get_create (cgraph_node::get (f->decl));
2065 gcc_checking_assert (nolto && !lto);
2067 /* In IPA mode we analyze every function precisely once. Assert that. */
2068 else
2070 if (nolto)
2072 if (!summaries)
2073 summaries = modref_summaries::create_ggc (symtab);
2074 else
2075 summaries->remove (cgraph_node::get (f->decl));
2076 summary = summaries->get_create (cgraph_node::get (f->decl));
2078 if (lto)
2080 if (!summaries_lto)
2081 summaries_lto = modref_summaries_lto::create_ggc (symtab);
2082 else
2083 summaries_lto->remove (cgraph_node::get (f->decl));
2084 summary_lto = summaries_lto->get_create (cgraph_node::get (f->decl));
2086 if (!fnspec_summaries)
2087 fnspec_summaries = new fnspec_summaries_t (symtab);
2088 if (!escape_summaries)
2089 escape_summaries = new escape_summaries_t (symtab);
2093 /* Create and initialize summary for F.
2094 Note that summaries may be already allocated from previous
2095 run of the pass. */
2096 if (nolto)
2098 gcc_assert (!summary->loads);
2099 summary->loads = modref_records::create_ggc (param_modref_max_bases,
2100 param_modref_max_refs,
2101 param_modref_max_accesses);
2102 gcc_assert (!summary->stores);
2103 summary->stores = modref_records::create_ggc (param_modref_max_bases,
2104 param_modref_max_refs,
2105 param_modref_max_accesses);
2106 summary->writes_errno = false;
2108 if (lto)
2110 gcc_assert (!summary_lto->loads);
2111 summary_lto->loads = modref_records_lto::create_ggc
2112 (param_modref_max_bases,
2113 param_modref_max_refs,
2114 param_modref_max_accesses);
2115 gcc_assert (!summary_lto->stores);
2116 summary_lto->stores = modref_records_lto::create_ggc
2117 (param_modref_max_bases,
2118 param_modref_max_refs,
2119 param_modref_max_accesses);
2120 summary_lto->writes_errno = false;
2123 analyze_parms (summary, summary_lto, ipa);
2125 int ecf_flags = flags_from_decl_or_type (current_function_decl);
2126 auto_vec <gimple *, 32> recursive_calls;
2128 /* Analyze each statement in each basic block of the function. If the
2129 statement cannot be analyzed (for any reason), the entire function cannot
2130 be analyzed by modref. */
2131 basic_block bb;
2132 FOR_EACH_BB_FN (bb, f)
2134 gimple_stmt_iterator si;
2135 for (si = gsi_start_nondebug_after_labels_bb (bb);
2136 !gsi_end_p (si); gsi_next_nondebug (&si))
2138 if (!analyze_stmt (summary, summary_lto,
2139 gsi_stmt (si), ipa, &recursive_calls)
2140 || ((!summary || !summary->useful_p (ecf_flags, false))
2141 && (!summary_lto
2142 || !summary_lto->useful_p (ecf_flags, false))))
2144 collapse_loads (summary, summary_lto);
2145 collapse_stores (summary, summary_lto);
2146 break;
2151 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2152 This needs to be done after all other side effects are computed. */
2153 if (!ipa)
2155 bool changed = true;
2156 bool first = true;
2157 while (changed)
2159 changed = false;
2160 for (unsigned i = 0; i < recursive_calls.length (); i++)
2162 changed |= merge_call_side_effects
2163 (summary, recursive_calls[i], summary,
2164 ignore_stores_p (current_function_decl,
2165 gimple_call_flags
2166 (recursive_calls[i])),
2167 fnode, !first);
2168 if (!summary->useful_p (ecf_flags, false))
2170 remove_summary (lto, nolto, ipa);
2171 return;
2174 first = false;
2177 if (summary && !summary->useful_p (ecf_flags))
2179 if (!ipa)
2180 optimization_summaries->remove (fnode);
2181 else
2182 summaries->remove (fnode);
2183 summary = NULL;
2185 if (summary_lto && !summary_lto->useful_p (ecf_flags))
2187 summaries_lto->remove (fnode);
2188 summary_lto = NULL;
2190 if (ipa && !summary && !summary_lto)
2191 remove_modref_edge_summaries (fnode);
2193 if (dump_file)
2195 fprintf (dump_file, " - modref done with result: tracked.\n");
2196 if (summary)
2197 summary->dump (dump_file);
2198 if (summary_lto)
2199 summary_lto->dump (dump_file);
2200 dump_modref_edge_summaries (dump_file, fnode, 2);
2204 /* Callback for generate_summary. */
2206 static void
2207 modref_generate (void)
2209 struct cgraph_node *node;
2210 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
2212 function *f = DECL_STRUCT_FUNCTION (node->decl);
2213 if (!f)
2214 continue;
2215 push_cfun (f);
2216 analyze_function (f, true);
2217 pop_cfun ();
2221 /* Called when a new function is inserted to callgraph late. */
2223 void
2224 modref_summaries::insert (struct cgraph_node *node, modref_summary *)
2226 /* Local passes ought to be executed by the pass manager. */
2227 if (this == optimization_summaries)
2229 optimization_summaries->remove (node);
2230 return;
2232 if (!DECL_STRUCT_FUNCTION (node->decl)
2233 || !opt_for_fn (node->decl, flag_ipa_modref))
2235 summaries->remove (node);
2236 return;
2238 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2239 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2240 pop_cfun ();
2243 /* Called when a new function is inserted to callgraph late. */
2245 void
2246 modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
2248 /* We do not support adding new function when IPA information is already
2249 propagated. This is done only by SIMD cloning that is not very
2250 critical. */
2251 if (!DECL_STRUCT_FUNCTION (node->decl)
2252 || !opt_for_fn (node->decl, flag_ipa_modref)
2253 || propagated)
2255 summaries_lto->remove (node);
2256 return;
2258 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2259 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2260 pop_cfun ();
2263 /* Called when new clone is inserted to callgraph late. */
2265 void
2266 modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
2267 modref_summary *src_data,
2268 modref_summary *dst_data)
2270 /* Do not duplicate optimization summaries; we do not handle parameter
2271 transforms on them. */
2272 if (this == optimization_summaries)
2274 optimization_summaries->remove (dst);
2275 return;
2277 dst_data->stores = modref_records::create_ggc
2278 (src_data->stores->max_bases,
2279 src_data->stores->max_refs,
2280 src_data->stores->max_accesses);
2281 dst_data->stores->copy_from (src_data->stores);
2282 dst_data->loads = modref_records::create_ggc
2283 (src_data->loads->max_bases,
2284 src_data->loads->max_refs,
2285 src_data->loads->max_accesses);
2286 dst_data->loads->copy_from (src_data->loads);
2287 dst_data->writes_errno = src_data->writes_errno;
2288 if (src_data->arg_flags.length ())
2289 dst_data->arg_flags = src_data->arg_flags.copy ();
2292 /* Called when new clone is inserted to callgraph late. */
2294 void
2295 modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
2296 modref_summary_lto *src_data,
2297 modref_summary_lto *dst_data)
2299 /* Be sure that no further cloning happens after ipa-modref. If it does
2300 we will need to update signatures for possible param changes. */
2301 gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
2302 dst_data->stores = modref_records_lto::create_ggc
2303 (src_data->stores->max_bases,
2304 src_data->stores->max_refs,
2305 src_data->stores->max_accesses);
2306 dst_data->stores->copy_from (src_data->stores);
2307 dst_data->loads = modref_records_lto::create_ggc
2308 (src_data->loads->max_bases,
2309 src_data->loads->max_refs,
2310 src_data->loads->max_accesses);
2311 dst_data->loads->copy_from (src_data->loads);
2312 dst_data->writes_errno = src_data->writes_errno;
2313 if (src_data->arg_flags.length ())
2314 dst_data->arg_flags = src_data->arg_flags.copy ();
2317 namespace
2319 /* Definition of the modref pass on GIMPLE. */
2320 const pass_data pass_data_modref = {
2321 GIMPLE_PASS,
2322 "modref",
2323 OPTGROUP_IPA,
2324 TV_TREE_MODREF,
2325 (PROP_cfg | PROP_ssa),
2332 class pass_modref : public gimple_opt_pass
2334 public:
2335 pass_modref (gcc::context *ctxt)
2336 : gimple_opt_pass (pass_data_modref, ctxt) {}
2338 /* opt_pass methods: */
2339 opt_pass *clone ()
2341 return new pass_modref (m_ctxt);
2343 virtual bool gate (function *)
2345 return flag_ipa_modref;
2347 virtual unsigned int execute (function *);
2350 /* Encode TT to the output block OB using the summary streaming API. */
2352 static void
2353 write_modref_records (modref_records_lto *tt, struct output_block *ob)
2355 streamer_write_uhwi (ob, tt->max_bases);
2356 streamer_write_uhwi (ob, tt->max_refs);
2357 streamer_write_uhwi (ob, tt->max_accesses);
2359 streamer_write_uhwi (ob, tt->every_base);
2360 streamer_write_uhwi (ob, vec_safe_length (tt->bases));
2361 size_t i;
2362 modref_base_node <tree> *base_node;
2363 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, base_node)
2365 stream_write_tree (ob, base_node->base, true);
2367 streamer_write_uhwi (ob, base_node->every_ref);
2368 streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
2370 size_t j;
2371 modref_ref_node <tree> *ref_node;
2372 FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
2374 stream_write_tree (ob, ref_node->ref, true);
2375 streamer_write_uhwi (ob, ref_node->every_access);
2376 streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
2378 size_t k;
2379 modref_access_node *access_node;
2380 FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
2382 streamer_write_hwi (ob, access_node->parm_index);
2383 if (access_node->parm_index != -1)
2385 streamer_write_uhwi (ob, access_node->parm_offset_known);
2386 if (access_node->parm_offset_known)
2388 streamer_write_poly_int64 (ob, access_node->parm_offset);
2389 streamer_write_poly_int64 (ob, access_node->offset);
2390 streamer_write_poly_int64 (ob, access_node->size);
2391 streamer_write_poly_int64 (ob, access_node->max_size);
2399 /* Read a modref_tree from the input block IB using the data from DATA_IN.
2400 This assumes that the tree was encoded using write_modref_tree.
2401 Either nolto_ret or lto_ret is initialized by the tree depending whether
2402 LTO streaming is expected or not. */
2404 void
2405 read_modref_records (lto_input_block *ib, struct data_in *data_in,
2406 modref_records **nolto_ret,
2407 modref_records_lto **lto_ret)
2409 size_t max_bases = streamer_read_uhwi (ib);
2410 size_t max_refs = streamer_read_uhwi (ib);
2411 size_t max_accesses = streamer_read_uhwi (ib);
2413 if (lto_ret)
2414 *lto_ret = modref_records_lto::create_ggc (max_bases, max_refs,
2415 max_accesses);
2416 if (nolto_ret)
2417 *nolto_ret = modref_records::create_ggc (max_bases, max_refs,
2418 max_accesses);
2419 gcc_checking_assert (lto_ret || nolto_ret);
2421 size_t every_base = streamer_read_uhwi (ib);
2422 size_t nbase = streamer_read_uhwi (ib);
2424 gcc_assert (!every_base || nbase == 0);
2425 if (every_base)
2427 if (nolto_ret)
2428 (*nolto_ret)->collapse ();
2429 if (lto_ret)
2430 (*lto_ret)->collapse ();
2432 for (size_t i = 0; i < nbase; i++)
2434 tree base_tree = stream_read_tree (ib, data_in);
2435 modref_base_node <alias_set_type> *nolto_base_node = NULL;
2436 modref_base_node <tree> *lto_base_node = NULL;
2438 /* At stream in time we have LTO alias info. Check if we streamed in
2439 something obviously unnecessary. Do not glob types by alias sets;
2440 it is not 100% clear that ltrans types will get merged same way.
2441 Types may get refined based on ODR type conflicts. */
2442 if (base_tree && !get_alias_set (base_tree))
2444 if (dump_file)
2446 fprintf (dump_file, "Streamed in alias set 0 type ");
2447 print_generic_expr (dump_file, base_tree);
2448 fprintf (dump_file, "\n");
2450 base_tree = NULL;
2453 if (nolto_ret)
2454 nolto_base_node = (*nolto_ret)->insert_base (base_tree
2455 ? get_alias_set (base_tree)
2456 : 0, 0);
2457 if (lto_ret)
2458 lto_base_node = (*lto_ret)->insert_base (base_tree, 0);
2459 size_t every_ref = streamer_read_uhwi (ib);
2460 size_t nref = streamer_read_uhwi (ib);
2462 gcc_assert (!every_ref || nref == 0);
2463 if (every_ref)
2465 if (nolto_base_node)
2466 nolto_base_node->collapse ();
2467 if (lto_base_node)
2468 lto_base_node->collapse ();
2470 for (size_t j = 0; j < nref; j++)
2472 tree ref_tree = stream_read_tree (ib, data_in);
2474 if (ref_tree && !get_alias_set (ref_tree))
2476 if (dump_file)
2478 fprintf (dump_file, "Streamed in alias set 0 type ");
2479 print_generic_expr (dump_file, ref_tree);
2480 fprintf (dump_file, "\n");
2482 ref_tree = NULL;
2485 modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
2486 modref_ref_node <tree> *lto_ref_node = NULL;
2488 if (nolto_base_node)
2489 nolto_ref_node
2490 = nolto_base_node->insert_ref (ref_tree
2491 ? get_alias_set (ref_tree) : 0,
2492 max_refs);
2493 if (lto_base_node)
2494 lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
2496 size_t every_access = streamer_read_uhwi (ib);
2497 size_t naccesses = streamer_read_uhwi (ib);
2499 if (nolto_ref_node)
2500 nolto_ref_node->every_access = every_access;
2501 if (lto_ref_node)
2502 lto_ref_node->every_access = every_access;
2504 for (size_t k = 0; k < naccesses; k++)
2506 int parm_index = streamer_read_hwi (ib);
2507 bool parm_offset_known = false;
2508 poly_int64 parm_offset = 0;
2509 poly_int64 offset = 0;
2510 poly_int64 size = -1;
2511 poly_int64 max_size = -1;
2513 if (parm_index != -1)
2515 parm_offset_known = streamer_read_uhwi (ib);
2516 if (parm_offset_known)
2518 parm_offset = streamer_read_poly_int64 (ib);
2519 offset = streamer_read_poly_int64 (ib);
2520 size = streamer_read_poly_int64 (ib);
2521 max_size = streamer_read_poly_int64 (ib);
2524 modref_access_node a = {offset, size, max_size, parm_offset,
2525 parm_index, parm_offset_known, false};
2526 if (nolto_ref_node)
2527 nolto_ref_node->insert_access (a, max_accesses, false);
2528 if (lto_ref_node)
2529 lto_ref_node->insert_access (a, max_accesses, false);
2533 if (lto_ret)
2534 (*lto_ret)->cleanup ();
2535 if (nolto_ret)
2536 (*nolto_ret)->cleanup ();
2539 /* Write ESUM to BP. */
2541 static void
2542 modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
2544 if (!esum)
2546 bp_pack_var_len_unsigned (bp, 0);
2547 return;
2549 bp_pack_var_len_unsigned (bp, esum->esc.length ());
2550 unsigned int i;
2551 escape_entry *ee;
2552 FOR_EACH_VEC_ELT (esum->esc, i, ee)
2554 bp_pack_var_len_unsigned (bp, ee->parm_index);
2555 bp_pack_var_len_unsigned (bp, ee->arg);
2556 bp_pack_var_len_unsigned (bp, ee->min_flags);
2557 bp_pack_value (bp, ee->direct, 1);
2561 /* Read escape summary for E from BP. */
2563 static void
2564 modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
2566 unsigned int n = bp_unpack_var_len_unsigned (bp);
2567 if (!n)
2568 return;
2569 escape_summary *esum = escape_summaries->get_create (e);
2570 esum->esc.reserve_exact (n);
2571 for (unsigned int i = 0; i < n; i++)
2573 escape_entry ee;
2574 ee.parm_index = bp_unpack_var_len_unsigned (bp);
2575 ee.arg = bp_unpack_var_len_unsigned (bp);
2576 ee.min_flags = bp_unpack_var_len_unsigned (bp);
2577 ee.direct = bp_unpack_value (bp, 1);
2578 esum->esc.quick_push (ee);
2582 /* Callback for write_summary. */
2584 static void
2585 modref_write ()
2587 struct output_block *ob = create_output_block (LTO_section_ipa_modref);
2588 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
2589 unsigned int count = 0;
2590 int i;
2592 if (!summaries_lto)
2594 streamer_write_uhwi (ob, 0);
2595 streamer_write_char_stream (ob->main_stream, 0);
2596 produce_asm (ob, NULL);
2597 destroy_output_block (ob);
2598 return;
2601 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
2603 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
2604 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
2605 modref_summary_lto *r;
2607 if (cnode && cnode->definition && !cnode->alias
2608 && (r = summaries_lto->get (cnode))
2609 && r->useful_p (flags_from_decl_or_type (cnode->decl)))
2610 count++;
2612 streamer_write_uhwi (ob, count);
2614 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
2616 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
2617 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
2619 if (cnode && cnode->definition && !cnode->alias)
2621 modref_summary_lto *r = summaries_lto->get (cnode);
2623 if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
2624 continue;
2626 streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
2628 streamer_write_uhwi (ob, r->arg_flags.length ());
2629 for (unsigned int i = 0; i < r->arg_flags.length (); i++)
2630 streamer_write_uhwi (ob, r->arg_flags[i]);
2632 write_modref_records (r->loads, ob);
2633 write_modref_records (r->stores, ob);
2635 struct bitpack_d bp = bitpack_create (ob->main_stream);
2636 bp_pack_value (&bp, r->writes_errno, 1);
2637 if (!flag_wpa)
2639 for (cgraph_edge *e = cnode->indirect_calls;
2640 e; e = e->next_callee)
2642 class fnspec_summary *sum = fnspec_summaries->get (e);
2643 bp_pack_value (&bp, sum != NULL, 1);
2644 if (sum)
2645 bp_pack_string (ob, &bp, sum->fnspec, true);
2646 class escape_summary *esum = escape_summaries->get (e);
2647 modref_write_escape_summary (&bp,esum);
2649 for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
2651 class fnspec_summary *sum = fnspec_summaries->get (e);
2652 bp_pack_value (&bp, sum != NULL, 1);
2653 if (sum)
2654 bp_pack_string (ob, &bp, sum->fnspec, true);
2655 class escape_summary *esum = escape_summaries->get (e);
2656 modref_write_escape_summary (&bp,esum);
2659 streamer_write_bitpack (&bp);
2662 streamer_write_char_stream (ob->main_stream, 0);
2663 produce_asm (ob, NULL);
2664 destroy_output_block (ob);
2667 static void
2668 read_section (struct lto_file_decl_data *file_data, const char *data,
2669 size_t len)
2671 const struct lto_function_header *header
2672 = (const struct lto_function_header *) data;
2673 const int cfg_offset = sizeof (struct lto_function_header);
2674 const int main_offset = cfg_offset + header->cfg_size;
2675 const int string_offset = main_offset + header->main_size;
2676 struct data_in *data_in;
2677 unsigned int i;
2678 unsigned int f_count;
2680 lto_input_block ib ((const char *) data + main_offset, header->main_size,
2681 file_data->mode_table);
2683 data_in
2684 = lto_data_in_create (file_data, (const char *) data + string_offset,
2685 header->string_size, vNULL);
2686 f_count = streamer_read_uhwi (&ib);
2687 for (i = 0; i < f_count; i++)
2689 struct cgraph_node *node;
2690 lto_symtab_encoder_t encoder;
2692 unsigned int index = streamer_read_uhwi (&ib);
2693 encoder = file_data->symtab_node_encoder;
2694 node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
2695 index));
2697 modref_summary *modref_sum = summaries
2698 ? summaries->get_create (node) : NULL;
2699 modref_summary_lto *modref_sum_lto = summaries_lto
2700 ? summaries_lto->get_create (node)
2701 : NULL;
2702 if (optimization_summaries)
2703 modref_sum = optimization_summaries->get_create (node);
2705 if (modref_sum)
2706 modref_sum->writes_errno = false;
2707 if (modref_sum_lto)
2708 modref_sum_lto->writes_errno = false;
2710 gcc_assert (!modref_sum || (!modref_sum->loads
2711 && !modref_sum->stores));
2712 gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
2713 && !modref_sum_lto->stores));
2714 unsigned int args = streamer_read_uhwi (&ib);
2715 if (args && modref_sum)
2716 modref_sum->arg_flags.reserve_exact (args);
2717 if (args && modref_sum_lto)
2718 modref_sum_lto->arg_flags.reserve_exact (args);
2719 for (unsigned int i = 0; i < args; i++)
2721 eaf_flags_t flags = streamer_read_uhwi (&ib);
2722 if (modref_sum)
2723 modref_sum->arg_flags.quick_push (flags);
2724 if (modref_sum_lto)
2725 modref_sum_lto->arg_flags.quick_push (flags);
2727 read_modref_records (&ib, data_in,
2728 modref_sum ? &modref_sum->loads : NULL,
2729 modref_sum_lto ? &modref_sum_lto->loads : NULL);
2730 read_modref_records (&ib, data_in,
2731 modref_sum ? &modref_sum->stores : NULL,
2732 modref_sum_lto ? &modref_sum_lto->stores : NULL);
2733 struct bitpack_d bp = streamer_read_bitpack (&ib);
2734 if (bp_unpack_value (&bp, 1))
2736 if (modref_sum)
2737 modref_sum->writes_errno = true;
2738 if (modref_sum_lto)
2739 modref_sum_lto->writes_errno = true;
2741 if (!flag_ltrans)
2743 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
2745 if (bp_unpack_value (&bp, 1))
2747 class fnspec_summary *sum = fnspec_summaries->get_create (e);
2748 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
2750 modref_read_escape_summary (&bp, e);
2752 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
2754 if (bp_unpack_value (&bp, 1))
2756 class fnspec_summary *sum = fnspec_summaries->get_create (e);
2757 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
2759 modref_read_escape_summary (&bp, e);
2762 if (dump_file)
2764 fprintf (dump_file, "Read modref for %s\n",
2765 node->dump_name ());
2766 if (modref_sum)
2767 modref_sum->dump (dump_file);
2768 if (modref_sum_lto)
2769 modref_sum_lto->dump (dump_file);
2770 dump_modref_edge_summaries (dump_file, node, 4);
2774 lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
2775 len);
2776 lto_data_in_delete (data_in);
2779 /* Callback for read_summary. */
2781 static void
2782 modref_read (void)
2784 struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
2785 struct lto_file_decl_data *file_data;
2786 unsigned int j = 0;
2788 gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
2789 if (flag_ltrans)
2790 optimization_summaries = modref_summaries::create_ggc (symtab);
2791 else
2793 if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
2794 summaries_lto = modref_summaries_lto::create_ggc (symtab);
2795 if (!flag_wpa
2796 || (flag_incremental_link == INCREMENTAL_LINK_LTO
2797 && flag_fat_lto_objects))
2798 summaries = modref_summaries::create_ggc (symtab);
2799 if (!fnspec_summaries)
2800 fnspec_summaries = new fnspec_summaries_t (symtab);
2801 if (!escape_summaries)
2802 escape_summaries = new escape_summaries_t (symtab);
2805 while ((file_data = file_data_vec[j++]))
2807 size_t len;
2808 const char *data = lto_get_summary_section_data (file_data,
2809 LTO_section_ipa_modref,
2810 &len);
2811 if (data)
2812 read_section (file_data, data, len);
2813 else
2814 /* Fatal error here. We do not want to support compiling ltrans units
2815 with different version of compiler or different flags than the WPA
2816 unit, so this should never happen. */
2817 fatal_error (input_location,
2818 "IPA modref summary is missing in input file");
2822 /* Recompute arg_flags for param adjustments in INFO. */
2824 static void
2825 remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
2827 auto_vec<eaf_flags_t> old = arg_flags.copy ();
2828 int max = -1;
2829 size_t i;
2830 ipa_adjusted_param *p;
2832 arg_flags.release ();
2834 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2836 int o = info->param_adjustments->get_original_index (i);
2837 if (o >= 0 && (int)old.length () > o && old[o])
2838 max = i;
2840 if (max >= 0)
2841 arg_flags.safe_grow_cleared (max + 1, true);
2842 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2844 int o = info->param_adjustments->get_original_index (i);
2845 if (o >= 0 && (int)old.length () > o && old[o])
2846 arg_flags[i] = old[o];
2850 /* If signature changed, update the summary. */
2852 static void
2853 update_signature (struct cgraph_node *node)
2855 clone_info *info = clone_info::get (node);
2856 if (!info || !info->param_adjustments)
2857 return;
2859 modref_summary *r = optimization_summaries
2860 ? optimization_summaries->get (node) : NULL;
2861 modref_summary_lto *r_lto = summaries_lto
2862 ? summaries_lto->get (node) : NULL;
2863 if (!r && !r_lto)
2864 return;
2865 if (dump_file)
2867 fprintf (dump_file, "Updating summary for %s from:\n",
2868 node->dump_name ());
2869 if (r)
2870 r->dump (dump_file);
2871 if (r_lto)
2872 r_lto->dump (dump_file);
2875 size_t i, max = 0;
2876 ipa_adjusted_param *p;
2878 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2880 int idx = info->param_adjustments->get_original_index (i);
2881 if (idx > (int)max)
2882 max = idx;
2885 auto_vec <int, 32> map;
2887 map.reserve (max + 1);
2888 for (i = 0; i <= max; i++)
2889 map.quick_push (-1);
2890 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2892 int idx = info->param_adjustments->get_original_index (i);
2893 if (idx >= 0)
2894 map[idx] = i;
2896 if (r)
2898 r->loads->remap_params (&map);
2899 r->stores->remap_params (&map);
2900 if (r->arg_flags.length ())
2901 remap_arg_flags (r->arg_flags, info);
2903 if (r_lto)
2905 r_lto->loads->remap_params (&map);
2906 r_lto->stores->remap_params (&map);
2907 if (r_lto->arg_flags.length ())
2908 remap_arg_flags (r_lto->arg_flags, info);
2910 if (dump_file)
2912 fprintf (dump_file, "to:\n");
2913 if (r)
2914 r->dump (dump_file);
2915 if (r_lto)
2916 r_lto->dump (dump_file);
2918 return;
2921 /* Definition of the modref IPA pass. */
2922 const pass_data pass_data_ipa_modref =
2924 IPA_PASS, /* type */
2925 "modref", /* name */
2926 OPTGROUP_IPA, /* optinfo_flags */
2927 TV_IPA_MODREF, /* tv_id */
2928 0, /* properties_required */
2929 0, /* properties_provided */
2930 0, /* properties_destroyed */
2931 0, /* todo_flags_start */
2932 ( TODO_dump_symtab ), /* todo_flags_finish */
2935 class pass_ipa_modref : public ipa_opt_pass_d
2937 public:
2938 pass_ipa_modref (gcc::context *ctxt)
2939 : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
2940 modref_generate, /* generate_summary */
2941 modref_write, /* write_summary */
2942 modref_read, /* read_summary */
2943 modref_write, /* write_optimization_summary */
2944 modref_read, /* read_optimization_summary */
2945 NULL, /* stmt_fixup */
2946 0, /* function_transform_todo_flags_start */
2947 NULL, /* function_transform */
2948 NULL) /* variable_transform */
2951 /* opt_pass methods: */
2952 opt_pass *clone () { return new pass_ipa_modref (m_ctxt); }
2953 virtual bool gate (function *)
2955 return true;
2957 virtual unsigned int execute (function *);
2963 unsigned int pass_modref::execute (function *f)
2965 analyze_function (f, false);
2966 return 0;
2969 gimple_opt_pass *
2970 make_pass_modref (gcc::context *ctxt)
2972 return new pass_modref (ctxt);
2975 ipa_opt_pass_d *
2976 make_pass_ipa_modref (gcc::context *ctxt)
2978 return new pass_ipa_modref (ctxt);
2981 /* Skip edges from and to nodes without ipa_pure_const enabled.
2982 Ignore not available symbols. */
2984 static bool
2985 ignore_edge (struct cgraph_edge *e)
2987 /* We merge summaries of inline clones into summaries of functions they
2988 are inlined to. For that reason the complete function bodies must
2989 act as unit. */
2990 if (!e->inline_failed)
2991 return false;
2992 enum availability avail;
2993 cgraph_node *callee = e->callee->function_or_virtual_thunk_symbol
2994 (&avail, e->caller);
2996 return (avail <= AVAIL_INTERPOSABLE
2997 || ((!optimization_summaries || !optimization_summaries->get (callee))
2998 && (!summaries_lto || !summaries_lto->get (callee)))
2999 || flags_from_decl_or_type (e->callee->decl)
3000 & (ECF_CONST | ECF_NOVOPS));
3003 /* Compute parm_map for CALLEE_EDGE. */
3005 static bool
3006 compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
3008 class ipa_edge_args *args;
3009 if (ipa_node_params_sum
3010 && !callee_edge->call_stmt_cannot_inline_p
3011 && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
3013 int i, count = ipa_get_cs_argument_count (args);
3014 class ipa_node_params *caller_parms_info, *callee_pi;
3015 class ipa_call_summary *es
3016 = ipa_call_summaries->get (callee_edge);
3017 cgraph_node *callee
3018 = callee_edge->callee->function_or_virtual_thunk_symbol
3019 (NULL, callee_edge->caller);
3021 caller_parms_info
3022 = ipa_node_params_sum->get (callee_edge->caller->inlined_to
3023 ? callee_edge->caller->inlined_to
3024 : callee_edge->caller);
3025 callee_pi = ipa_node_params_sum->get (callee);
3027 (*parm_map).safe_grow_cleared (count, true);
3029 for (i = 0; i < count; i++)
3031 if (es && es->param[i].points_to_local_or_readonly_memory)
3033 (*parm_map)[i].parm_index = -2;
3034 continue;
3037 struct ipa_jump_func *jf
3038 = ipa_get_ith_jump_func (args, i);
3039 if (jf && callee_pi)
3041 tree cst = ipa_value_from_jfunc (caller_parms_info,
3043 ipa_get_type
3044 (callee_pi, i));
3045 if (cst && points_to_local_or_readonly_memory_p (cst))
3047 (*parm_map)[i].parm_index = -2;
3048 continue;
3051 if (jf && jf->type == IPA_JF_PASS_THROUGH)
3053 (*parm_map)[i].parm_index
3054 = ipa_get_jf_pass_through_formal_id (jf);
3055 if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
3057 (*parm_map)[i].parm_offset_known = true;
3058 (*parm_map)[i].parm_offset = 0;
3060 else if (ipa_get_jf_pass_through_operation (jf)
3061 == POINTER_PLUS_EXPR
3062 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
3063 &(*parm_map)[i].parm_offset))
3064 (*parm_map)[i].parm_offset_known = true;
3065 else
3066 (*parm_map)[i].parm_offset_known = false;
3067 continue;
3069 if (jf && jf->type == IPA_JF_ANCESTOR)
3071 (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
3072 (*parm_map)[i].parm_offset_known = true;
3073 gcc_checking_assert
3074 (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
3075 (*parm_map)[i].parm_offset
3076 = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
3078 else
3079 (*parm_map)[i].parm_index = -1;
3081 if (dump_file)
3083 fprintf (dump_file, " Parm map: ");
3084 for (i = 0; i < count; i++)
3085 fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
3086 fprintf (dump_file, "\n");
3088 return true;
3090 return false;
3093 /* Map used to translate escape infos. */
3095 struct escape_map
3097 int parm_index;
3098 bool direct;
3101 /* Update escape map fo E. */
3103 static void
3104 update_escape_summary_1 (cgraph_edge *e,
3105 vec <vec <escape_map>> &map,
3106 bool ignore_stores)
3108 escape_summary *sum = escape_summaries->get (e);
3109 if (!sum)
3110 return;
3111 auto_vec <escape_entry> old = sum->esc.copy ();
3112 sum->esc.release ();
3114 unsigned int i;
3115 escape_entry *ee;
3116 FOR_EACH_VEC_ELT (old, i, ee)
3118 unsigned int j;
3119 struct escape_map *em;
3120 if (ee->parm_index >= map.length ())
3121 continue;
3122 FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
3124 int min_flags = ee->min_flags;
3125 if (ee->direct && !em->direct)
3126 min_flags = deref_flags (min_flags, ignore_stores);
3127 struct escape_entry entry = {em->parm_index, ee->arg,
3128 ee->min_flags,
3129 ee->direct & em->direct};
3130 sum->esc.safe_push (entry);
3133 if (!sum->esc.length ())
3134 escape_summaries->remove (e);
3137 /* Update escape map fo NODE. */
3139 static void
3140 update_escape_summary (cgraph_node *node,
3141 vec <vec <escape_map>> &map,
3142 bool ignore_stores)
3144 if (!escape_summaries)
3145 return;
3146 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
3147 update_escape_summary_1 (e, map, ignore_stores);
3148 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3150 if (!e->inline_failed)
3151 update_escape_summary (e->callee, map, ignore_stores);
3152 else
3153 update_escape_summary_1 (e, map, ignore_stores);
3157 /* Call EDGE was inlined; merge summary from callee to the caller. */
3159 void
3160 ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
3162 if (!summaries && !summaries_lto)
3163 return;
3165 struct cgraph_node *to = (edge->caller->inlined_to
3166 ? edge->caller->inlined_to : edge->caller);
3167 class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
3168 class modref_summary_lto *to_info_lto = summaries_lto
3169 ? summaries_lto->get (to) : NULL;
3171 if (!to_info && !to_info_lto)
3173 if (summaries)
3174 summaries->remove (edge->callee);
3175 if (summaries_lto)
3176 summaries_lto->remove (edge->callee);
3177 remove_modref_edge_summaries (edge->callee);
3178 return;
3181 class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
3182 : NULL;
3183 class modref_summary_lto *callee_info_lto
3184 = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
3185 int flags = flags_from_decl_or_type (edge->callee->decl);
3186 bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
3188 if (!callee_info && to_info)
3190 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3191 to_info->loads->collapse ();
3192 if (!ignore_stores)
3193 to_info->stores->collapse ();
3195 if (!callee_info_lto && to_info_lto)
3197 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3198 to_info_lto->loads->collapse ();
3199 if (!ignore_stores)
3200 to_info_lto->stores->collapse ();
3202 if (callee_info || callee_info_lto)
3204 auto_vec <modref_parm_map, 32> parm_map;
3206 compute_parm_map (edge, &parm_map);
3208 if (!ignore_stores)
3210 if (to_info && callee_info)
3211 to_info->stores->merge (callee_info->stores, &parm_map, false);
3212 if (to_info_lto && callee_info_lto)
3213 to_info_lto->stores->merge (callee_info_lto->stores, &parm_map,
3214 false);
3216 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3218 if (to_info && callee_info)
3219 to_info->loads->merge (callee_info->loads, &parm_map, false);
3220 if (to_info_lto && callee_info_lto)
3221 to_info_lto->loads->merge (callee_info_lto->loads, &parm_map,
3222 false);
3226 /* Now merge escape summaries.
3227 For every escape to the callee we need to merge calle flags
3228 and remap calees escapes. */
3229 class escape_summary *sum = escape_summaries->get (edge);
3230 int max_escape = -1;
3231 escape_entry *ee;
3232 unsigned int i;
3234 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
3235 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3236 if ((int)ee->arg > max_escape)
3237 max_escape = ee->arg;
3239 auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
3240 emap.safe_grow (max_escape + 1, true);
3241 for (i = 0; (int)i < max_escape + 1; i++)
3242 emap[i] = vNULL;
3244 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
3245 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3247 bool needed = false;
3248 if (to_info && to_info->arg_flags.length () > ee->parm_index)
3250 int flags = callee_info
3251 && callee_info->arg_flags.length () > ee->arg
3252 ? callee_info->arg_flags[ee->arg] : 0;
3253 if (!ee->direct)
3254 flags = deref_flags (flags, ignore_stores);
3255 else if (ignore_stores)
3256 flags |= ignore_stores_eaf_flags;
3257 flags |= ee->min_flags;
3258 to_info->arg_flags[ee->parm_index] &= flags;
3259 if (to_info->arg_flags[ee->parm_index])
3260 needed = true;
3262 if (to_info_lto && to_info_lto->arg_flags.length () > ee->parm_index)
3264 int flags = callee_info_lto
3265 && callee_info_lto->arg_flags.length () > ee->arg
3266 ? callee_info_lto->arg_flags[ee->arg] : 0;
3267 if (!ee->direct)
3268 flags = deref_flags (flags, ignore_stores);
3269 else if (ignore_stores)
3270 flags |= ignore_stores_eaf_flags;
3271 flags |= ee->min_flags;
3272 to_info_lto->arg_flags[ee->parm_index] &= flags;
3273 if (to_info_lto->arg_flags[ee->parm_index])
3274 needed = true;
3276 struct escape_map entry = {ee->parm_index, ee->direct};
3277 if (needed)
3278 emap[ee->arg].safe_push (entry);
3280 update_escape_summary (edge->callee, emap, ignore_stores);
3281 for (i = 0; (int)i < max_escape + 1; i++)
3282 emap[i].release ();
3283 if (sum)
3284 escape_summaries->remove (edge);
3286 if (summaries)
3288 if (to_info && !to_info->useful_p (flags))
3290 if (dump_file)
3291 fprintf (dump_file, "Removed mod-ref summary for %s\n",
3292 to->dump_name ());
3293 summaries->remove (to);
3294 to_info = NULL;
3296 else if (to_info && dump_file)
3298 if (dump_file)
3299 fprintf (dump_file, "Updated mod-ref summary for %s\n",
3300 to->dump_name ());
3301 to_info->dump (dump_file);
3303 if (callee_info)
3304 summaries->remove (edge->callee);
3306 if (summaries_lto)
3308 if (to_info_lto && !to_info_lto->useful_p (flags))
3310 if (dump_file)
3311 fprintf (dump_file, "Removed mod-ref summary for %s\n",
3312 to->dump_name ());
3313 summaries_lto->remove (to);
3315 else if (to_info_lto && dump_file)
3317 if (dump_file)
3318 fprintf (dump_file, "Updated mod-ref summary for %s\n",
3319 to->dump_name ());
3320 to_info_lto->dump (dump_file);
3321 to_info_lto = NULL;
3323 if (callee_info_lto)
3324 summaries_lto->remove (edge->callee);
3326 if (!to_info && !to_info_lto)
3327 remove_modref_edge_summaries (to);
3328 return;
3331 /* Get parameter type from DECL. This is only safe for special cases
3332 like builtins we create fnspec for because the type match is checked
3333 at fnspec creation time. */
3335 static tree
3336 get_parm_type (tree decl, unsigned int i)
3338 tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
3340 for (unsigned int p = 0; p < i; p++)
3341 t = TREE_CHAIN (t);
3342 return TREE_VALUE (t);
3345 /* Return access mode for argument I of call E with FNSPEC. */
3347 static modref_access_node
3348 get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
3349 unsigned int i, modref_parm_map &map)
3351 tree size = NULL_TREE;
3352 unsigned int size_arg;
3354 if (!fnspec.arg_specified_p (i))
3356 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
3358 cgraph_node *node = e->caller->inlined_to
3359 ? e->caller->inlined_to : e->caller;
3360 ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
3361 ipa_edge_args *args = ipa_edge_args_sum->get (e);
3362 struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
3364 if (jf)
3365 size = ipa_value_from_jfunc (caller_parms_info, jf,
3366 get_parm_type (e->callee->decl, size_arg));
3368 else if (fnspec.arg_access_size_given_by_type_p (i))
3369 size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
3370 modref_access_node a = {0, -1, -1,
3371 map.parm_offset, map.parm_index,
3372 map.parm_offset_known, 0};
3373 poly_int64 size_hwi;
3374 if (size
3375 && poly_int_tree_p (size, &size_hwi)
3376 && coeffs_in_range_p (size_hwi, 0,
3377 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
3379 a.size = -1;
3380 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
3382 return a;
3385 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
3386 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
3388 static bool
3389 propagate_unknown_call (cgraph_node *node,
3390 cgraph_edge *e, int ecf_flags,
3391 modref_summary *cur_summary,
3392 modref_summary_lto *cur_summary_lto)
3394 bool changed = false;
3395 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
3396 auto_vec <modref_parm_map, 32> parm_map;
3397 if (fnspec_sum
3398 && compute_parm_map (e, &parm_map))
3400 attr_fnspec fnspec (fnspec_sum->fnspec);
3402 gcc_checking_assert (fnspec.known_p ());
3403 if (fnspec.global_memory_read_p ())
3404 collapse_loads (cur_summary, cur_summary_lto);
3405 else
3407 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
3408 for (unsigned i = 0; i < parm_map.length () && t;
3409 i++, t = TREE_CHAIN (t))
3410 if (!POINTER_TYPE_P (TREE_VALUE (t)))
3412 else if (!fnspec.arg_specified_p (i)
3413 || fnspec.arg_maybe_read_p (i))
3415 modref_parm_map map = parm_map[i];
3416 if (map.parm_index == -2)
3417 continue;
3418 if (map.parm_index == -1)
3420 collapse_loads (cur_summary, cur_summary_lto);
3421 break;
3423 if (cur_summary)
3424 changed |= cur_summary->loads->insert
3425 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
3426 if (cur_summary_lto)
3427 changed |= cur_summary_lto->loads->insert
3428 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
3431 if (ignore_stores_p (node->decl, ecf_flags))
3433 else if (fnspec.global_memory_written_p ())
3434 collapse_stores (cur_summary, cur_summary_lto);
3435 else
3437 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
3438 for (unsigned i = 0; i < parm_map.length () && t;
3439 i++, t = TREE_CHAIN (t))
3440 if (!POINTER_TYPE_P (TREE_VALUE (t)))
3442 else if (!fnspec.arg_specified_p (i)
3443 || fnspec.arg_maybe_written_p (i))
3445 modref_parm_map map = parm_map[i];
3446 if (map.parm_index == -2)
3447 continue;
3448 if (map.parm_index == -1)
3450 collapse_stores (cur_summary, cur_summary_lto);
3451 break;
3453 if (cur_summary)
3454 changed |= cur_summary->stores->insert
3455 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
3456 if (cur_summary_lto)
3457 changed |= cur_summary_lto->stores->insert
3458 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
3461 if (fnspec.errno_maybe_written_p () && flag_errno_math)
3463 if (cur_summary && !cur_summary->writes_errno)
3465 cur_summary->writes_errno = true;
3466 changed = true;
3468 if (cur_summary_lto && !cur_summary_lto->writes_errno)
3470 cur_summary_lto->writes_errno = true;
3471 changed = true;
3474 return changed;
3476 if (dump_file)
3477 fprintf (dump_file, " collapsing loads\n");
3478 changed |= collapse_loads (cur_summary, cur_summary_lto);
3479 if (!ignore_stores_p (node->decl, ecf_flags))
3481 if (dump_file)
3482 fprintf (dump_file, " collapsing stores\n");
3483 changed |= collapse_stores (cur_summary, cur_summary_lto);
3485 return changed;
3488 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
3489 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
3491 static void
3492 remove_useless_summaries (cgraph_node *node,
3493 modref_summary **cur_summary_ptr,
3494 modref_summary_lto **cur_summary_lto_ptr,
3495 int ecf_flags)
3497 if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
3499 optimization_summaries->remove (node);
3500 *cur_summary_ptr = NULL;
3502 if (*cur_summary_lto_ptr
3503 && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
3505 summaries_lto->remove (node);
3506 *cur_summary_lto_ptr = NULL;
3510 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3511 and propagate loads/stores. */
3513 static void
3514 modref_propagate_in_scc (cgraph_node *component_node)
3516 bool changed = true;
3517 bool first = true;
3518 int iteration = 0;
3520 while (changed)
3522 changed = false;
3523 for (struct cgraph_node *cur = component_node; cur;
3524 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3526 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
3527 modref_summary *cur_summary = optimization_summaries
3528 ? optimization_summaries->get (node)
3529 : NULL;
3530 modref_summary_lto *cur_summary_lto = summaries_lto
3531 ? summaries_lto->get (node)
3532 : NULL;
3534 if (!cur_summary && !cur_summary_lto)
3535 continue;
3537 int cur_ecf_flags = flags_from_decl_or_type (node->decl);
3539 if (dump_file)
3540 fprintf (dump_file, " Processing %s%s%s\n",
3541 cur->dump_name (),
3542 TREE_READONLY (cur->decl) ? " (const)" : "",
3543 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3545 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
3547 if (e->indirect_info->ecf_flags & (ECF_CONST | ECF_NOVOPS))
3548 continue;
3549 if (dump_file)
3550 fprintf (dump_file, " Indirect call"
3551 "collapsing loads\n");
3552 if (propagate_unknown_call
3553 (node, e, e->indirect_info->ecf_flags,
3554 cur_summary, cur_summary_lto))
3556 changed = true;
3557 remove_useless_summaries (node, &cur_summary,
3558 &cur_summary_lto,
3559 cur_ecf_flags);
3560 if (!cur_summary && !cur_summary_lto)
3561 break;
3565 if (!cur_summary && !cur_summary_lto)
3566 continue;
3568 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
3569 callee_edge = callee_edge->next_callee)
3571 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
3572 modref_summary *callee_summary = NULL;
3573 modref_summary_lto *callee_summary_lto = NULL;
3574 struct cgraph_node *callee;
3576 if (flags & (ECF_CONST | ECF_NOVOPS)
3577 || !callee_edge->inline_failed)
3578 continue;
3580 /* Get the callee and its summary. */
3581 enum availability avail;
3582 callee = callee_edge->callee->function_or_virtual_thunk_symbol
3583 (&avail, cur);
3585 /* It is not necessary to re-process calls outside of the
3586 SCC component. */
3587 if (iteration > 0
3588 && (!callee->aux
3589 || ((struct ipa_dfs_info *)cur->aux)->scc_no
3590 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
3591 continue;
3593 if (dump_file)
3594 fprintf (dump_file, " Call to %s\n",
3595 callee_edge->callee->dump_name ());
3597 bool ignore_stores = ignore_stores_p (cur->decl, flags);
3599 if (avail <= AVAIL_INTERPOSABLE)
3601 if (dump_file)
3602 fprintf (dump_file, " Call target interposable"
3603 " or not available\n");
3604 changed |= propagate_unknown_call
3605 (node, callee_edge, flags,
3606 cur_summary, cur_summary_lto);
3607 if (!cur_summary && !cur_summary_lto)
3608 break;
3609 continue;
3612 /* We don't know anything about CALLEE, hence we cannot tell
3613 anything about the entire component. */
3615 if (cur_summary
3616 && !(callee_summary = optimization_summaries->get (callee)))
3618 if (dump_file)
3619 fprintf (dump_file, " No call target summary\n");
3620 changed |= propagate_unknown_call
3621 (node, callee_edge, flags,
3622 cur_summary, NULL);
3624 if (cur_summary_lto
3625 && !(callee_summary_lto = summaries_lto->get (callee)))
3627 if (dump_file)
3628 fprintf (dump_file, " No call target summary\n");
3629 changed |= propagate_unknown_call
3630 (node, callee_edge, flags,
3631 NULL, cur_summary_lto);
3634 /* We can not safely optimize based on summary of callee if it
3635 does not always bind to current def: it is possible that
3636 memory load was optimized out earlier which may not happen in
3637 the interposed variant. */
3638 if (!callee_edge->binds_to_current_def_p ())
3640 changed |= collapse_loads (cur_summary, cur_summary_lto);
3641 if (dump_file)
3642 fprintf (dump_file, " May not bind local;"
3643 " collapsing loads\n");
3647 auto_vec <modref_parm_map, 32> parm_map;
3649 compute_parm_map (callee_edge, &parm_map);
3651 /* Merge in callee's information. */
3652 if (callee_summary)
3654 changed |= cur_summary->loads->merge
3655 (callee_summary->loads, &parm_map, !first);
3656 if (!ignore_stores)
3658 changed |= cur_summary->stores->merge
3659 (callee_summary->stores, &parm_map,
3660 !first);
3661 if (!cur_summary->writes_errno
3662 && callee_summary->writes_errno)
3664 cur_summary->writes_errno = true;
3665 changed = true;
3669 if (callee_summary_lto)
3671 changed |= cur_summary_lto->loads->merge
3672 (callee_summary_lto->loads, &parm_map,
3673 !first);
3674 if (!ignore_stores)
3676 changed |= cur_summary_lto->stores->merge
3677 (callee_summary_lto->stores, &parm_map,
3678 !first);
3679 if (!cur_summary_lto->writes_errno
3680 && callee_summary_lto->writes_errno)
3682 cur_summary_lto->writes_errno = true;
3683 changed = true;
3687 if (changed)
3688 remove_useless_summaries (node, &cur_summary,
3689 &cur_summary_lto,
3690 cur_ecf_flags);
3691 if (!cur_summary && !cur_summary_lto)
3692 break;
3693 if (dump_file && changed)
3695 if (cur_summary)
3696 cur_summary->dump (dump_file);
3697 if (cur_summary_lto)
3698 cur_summary_lto->dump (dump_file);
3699 dump_modref_edge_summaries (dump_file, node, 4);
3703 iteration++;
3704 first = false;
3706 if (dump_file)
3707 fprintf (dump_file,
3708 "Propagation finished in %i iterations\n", iteration);
3711 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
3713 static void
3714 modref_propagate_dump_scc (cgraph_node *component_node)
3716 for (struct cgraph_node *cur = component_node; cur;
3717 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3718 if (!cur->inlined_to)
3720 modref_summary *cur_summary = optimization_summaries
3721 ? optimization_summaries->get (cur)
3722 : NULL;
3723 modref_summary_lto *cur_summary_lto = summaries_lto
3724 ? summaries_lto->get (cur)
3725 : NULL;
3727 fprintf (dump_file, "Propagated modref for %s%s%s\n",
3728 cur->dump_name (),
3729 TREE_READONLY (cur->decl) ? " (const)" : "",
3730 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3731 if (optimization_summaries)
3733 if (cur_summary)
3734 cur_summary->dump (dump_file);
3735 else
3736 fprintf (dump_file, " Not tracked\n");
3738 if (summaries_lto)
3740 if (cur_summary_lto)
3741 cur_summary_lto->dump (dump_file);
3742 else
3743 fprintf (dump_file, " Not tracked (lto)\n");
3748 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
3749 and SUMMARY_LTO to CUR_SUMMARY_LTO.
3750 Return true if something changed. */
3752 static bool
3753 modref_merge_call_site_flags (escape_summary *sum,
3754 modref_summary *cur_summary,
3755 modref_summary_lto *cur_summary_lto,
3756 modref_summary *summary,
3757 modref_summary_lto *summary_lto,
3758 tree caller,
3759 int ecf_flags)
3761 escape_entry *ee;
3762 unsigned int i;
3763 bool changed = false;
3764 bool ignore_stores = ignore_stores_p (caller, ecf_flags);
3766 /* If we have no useful info to propagate. */
3767 if ((!cur_summary || !cur_summary->arg_flags.length ())
3768 && (!cur_summary_lto || !cur_summary_lto->arg_flags.length ()))
3769 return false;
3771 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3773 int flags = 0;
3774 int flags_lto = 0;
3776 if (summary && ee->arg < summary->arg_flags.length ())
3777 flags = summary->arg_flags[ee->arg];
3778 if (summary_lto
3779 && ee->arg < summary_lto->arg_flags.length ())
3780 flags_lto = summary_lto->arg_flags[ee->arg];
3781 if (!ee->direct)
3783 flags = deref_flags (flags, ignore_stores);
3784 flags_lto = deref_flags (flags_lto, ignore_stores);
3786 else if (ignore_stores)
3788 flags |= ignore_stores_eaf_flags;
3789 flags_lto |= ignore_stores_eaf_flags;
3791 /* Returning the value is already accounted to at local propagation. */
3792 flags |= ee->min_flags | EAF_NOT_RETURNED;
3793 flags_lto |= ee->min_flags | EAF_NOT_RETURNED;
3794 /* Noescape implies that value also does not escape directly.
3795 Fnspec machinery does set both so compensate for this. */
3796 if (flags & EAF_NOESCAPE)
3797 flags |= EAF_NODIRECTESCAPE;
3798 if (flags_lto & EAF_NOESCAPE)
3799 flags_lto |= EAF_NODIRECTESCAPE;
3800 if (!(flags & EAF_UNUSED)
3801 && cur_summary && ee->parm_index < cur_summary->arg_flags.length ())
3803 int f = cur_summary->arg_flags[ee->parm_index];
3804 if ((f & flags) != f)
3806 f = remove_useless_eaf_flags
3807 (f & flags, ecf_flags,
3808 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
3809 cur_summary->arg_flags[ee->parm_index] = f;
3810 changed = true;
3813 if (!(flags_lto & EAF_UNUSED)
3814 && cur_summary_lto
3815 && ee->parm_index < cur_summary_lto->arg_flags.length ())
3817 int f = cur_summary_lto->arg_flags[ee->parm_index];
3818 if ((f & flags_lto) != f)
3820 f = remove_useless_eaf_flags
3821 (f & flags_lto, ecf_flags,
3822 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
3823 cur_summary_lto->arg_flags[ee->parm_index] = f;
3824 changed = true;
3828 return changed;
3831 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3832 and propagate arg flags. */
3834 static void
3835 modref_propagate_flags_in_scc (cgraph_node *component_node)
3837 bool changed = true;
3838 int iteration = 0;
3840 while (changed)
3842 changed = false;
3843 for (struct cgraph_node *cur = component_node; cur;
3844 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3846 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
3847 modref_summary *cur_summary = optimization_summaries
3848 ? optimization_summaries->get (node)
3849 : NULL;
3850 modref_summary_lto *cur_summary_lto = summaries_lto
3851 ? summaries_lto->get (node)
3852 : NULL;
3854 if (!cur_summary && !cur_summary_lto)
3855 continue;
3857 if (dump_file)
3858 fprintf (dump_file, " Processing %s%s%s\n",
3859 cur->dump_name (),
3860 TREE_READONLY (cur->decl) ? " (const)" : "",
3861 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3863 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
3865 escape_summary *sum = escape_summaries->get (e);
3867 if (!sum || (e->indirect_info->ecf_flags
3868 & (ECF_CONST | ECF_NOVOPS)))
3869 continue;
3871 changed |= modref_merge_call_site_flags
3872 (sum, cur_summary, cur_summary_lto,
3873 NULL, NULL,
3874 node->decl, e->indirect_info->ecf_flags);
3877 if (!cur_summary && !cur_summary_lto)
3878 continue;
3880 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
3881 callee_edge = callee_edge->next_callee)
3883 int ecf_flags = flags_from_decl_or_type
3884 (callee_edge->callee->decl);
3885 modref_summary *callee_summary = NULL;
3886 modref_summary_lto *callee_summary_lto = NULL;
3887 struct cgraph_node *callee;
3889 if (ecf_flags & (ECF_CONST | ECF_NOVOPS)
3890 || !callee_edge->inline_failed)
3891 continue;
3892 /* Get the callee and its summary. */
3893 enum availability avail;
3894 callee = callee_edge->callee->function_or_virtual_thunk_symbol
3895 (&avail, cur);
3897 /* It is not necessary to re-process calls outside of the
3898 SCC component. */
3899 if (iteration > 0
3900 && (!callee->aux
3901 || ((struct ipa_dfs_info *)cur->aux)->scc_no
3902 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
3903 continue;
3905 escape_summary *sum = escape_summaries->get (callee_edge);
3906 if (!sum)
3907 continue;
3909 if (dump_file)
3910 fprintf (dump_file, " Call to %s\n",
3911 callee_edge->callee->dump_name ());
3913 if (avail <= AVAIL_INTERPOSABLE
3914 || callee_edge->call_stmt_cannot_inline_p)
3916 else
3918 if (cur_summary)
3919 callee_summary = optimization_summaries->get (callee);
3920 if (cur_summary_lto)
3921 callee_summary_lto = summaries_lto->get (callee);
3923 changed |= modref_merge_call_site_flags
3924 (sum, cur_summary, cur_summary_lto,
3925 callee_summary, callee_summary_lto,
3926 node->decl, ecf_flags);
3927 if (dump_file && changed)
3929 if (cur_summary)
3930 cur_summary->dump (dump_file);
3931 if (cur_summary_lto)
3932 cur_summary_lto->dump (dump_file);
3936 iteration++;
3938 if (dump_file)
3939 fprintf (dump_file,
3940 "Propagation of flags finished in %i iterations\n", iteration);
3943 /* Run the IPA pass. This will take a function's summaries and calls and
3944 construct new summaries which represent a transitive closure. So that
3945 summary of an analyzed function contains information about the loads and
3946 stores that the function or any function that it calls does. */
3948 unsigned int
3949 pass_ipa_modref::execute (function *)
3951 if (!summaries && !summaries_lto)
3952 return 0;
3954 if (optimization_summaries)
3955 ggc_delete (optimization_summaries);
3956 optimization_summaries = summaries;
3957 summaries = NULL;
3959 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
3960 symtab->cgraph_count);
3961 int order_pos;
3962 order_pos = ipa_reduced_postorder (order, true, ignore_edge);
3963 int i;
3965 /* Iterate over all strongly connected components in post-order. */
3966 for (i = 0; i < order_pos; i++)
3968 /* Get the component's representative. That's just any node in the
3969 component from which we can traverse the entire component. */
3970 struct cgraph_node *component_node = order[i];
3972 if (dump_file)
3973 fprintf (dump_file, "\n\nStart of SCC component\n");
3975 modref_propagate_in_scc (component_node);
3976 modref_propagate_flags_in_scc (component_node);
3977 if (dump_file)
3978 modref_propagate_dump_scc (component_node);
3980 cgraph_node *node;
3981 FOR_EACH_FUNCTION (node)
3982 update_signature (node);
3983 if (summaries_lto)
3984 ((modref_summaries_lto *)summaries_lto)->propagated = true;
3985 ipa_free_postorder_info ();
3986 free (order);
3987 delete fnspec_summaries;
3988 fnspec_summaries = NULL;
3989 delete escape_summaries;
3990 escape_summaries = NULL;
3991 return 0;
3994 /* Summaries must stay alive until end of compilation. */
3996 void
3997 ipa_modref_c_finalize ()
3999 if (optimization_summaries)
4000 ggc_delete (optimization_summaries);
4001 optimization_summaries = NULL;
4002 gcc_checking_assert (!summaries
4003 || flag_incremental_link == INCREMENTAL_LINK_LTO);
4004 if (summaries_lto)
4005 ggc_delete (summaries_lto);
4006 summaries_lto = NULL;
4007 if (fnspec_summaries)
4008 delete fnspec_summaries;
4009 fnspec_summaries = NULL;
4010 if (escape_summaries)
4011 delete escape_summaries;
4012 escape_summaries = NULL;
4015 #include "gt-ipa-modref.h"