[PATCH] RISC-V: Move UNSPEC_SSP_SET and UNSPEC_SSP_TEST to correct enum
[gcc.git] / gcc / ipa-modref.cc
blobf1d88abf3cf2a1ca8ae7c48c7accd5e766026ae0
1 /* Search for references that a functions loads or stores.
2 Copyright (C) 2020-2025 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-structalias).
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 parameters
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 "sreal.h"
79 #include "ipa-cp.h"
80 #include "ipa-prop.h"
81 #include "ipa-fnsummary.h"
82 #include "attr-fnspec.h"
83 #include "symtab-clones.h"
84 #include "gimple-ssa.h"
85 #include "tree-phinodes.h"
86 #include "tree-ssa-operands.h"
87 #include "ssa-iterators.h"
88 #include "stringpool.h"
89 #include "tree-ssanames.h"
90 #include "attribs.h"
91 #include "tree-cfg.h"
92 #include "tree-eh.h"
95 namespace {
97 /* We record fnspec specifiers for call edges since they depends on actual
98 gimple statements. */
100 class fnspec_summary
102 public:
103 char *fnspec;
105 fnspec_summary ()
106 : fnspec (NULL)
110 ~fnspec_summary ()
112 free (fnspec);
116 /* Summary holding fnspec string for a given call. */
118 class fnspec_summaries_t : public call_summary <fnspec_summary *>
120 public:
121 fnspec_summaries_t (symbol_table *symtab)
122 : call_summary <fnspec_summary *> (symtab) {}
123 /* Hook that is called by summary when an edge is duplicated. */
124 void duplicate (cgraph_edge *,
125 cgraph_edge *,
126 fnspec_summary *src,
127 fnspec_summary *dst) final override
129 dst->fnspec = xstrdup (src->fnspec);
133 static fnspec_summaries_t *fnspec_summaries = NULL;
135 /* Escape summary holds a vector of param indexes that escape to
136 a given call. */
137 struct escape_entry
139 /* Parameter that escapes at a given call. */
140 int parm_index;
141 /* Argument it escapes to. */
142 unsigned int arg;
143 /* Minimal flags known about the argument. */
144 eaf_flags_t min_flags;
145 /* Does it escape directly or indirectly? */
146 bool direct;
149 /* Dump EAF flags. */
151 static void
152 dump_eaf_flags (FILE *out, int flags, bool newline = true)
154 if (flags & EAF_UNUSED)
155 fprintf (out, " unused");
156 if (flags & EAF_NO_DIRECT_CLOBBER)
157 fprintf (out, " no_direct_clobber");
158 if (flags & EAF_NO_INDIRECT_CLOBBER)
159 fprintf (out, " no_indirect_clobber");
160 if (flags & EAF_NO_DIRECT_ESCAPE)
161 fprintf (out, " no_direct_escape");
162 if (flags & EAF_NO_INDIRECT_ESCAPE)
163 fprintf (out, " no_indirect_escape");
164 if (flags & EAF_NOT_RETURNED_DIRECTLY)
165 fprintf (out, " not_returned_directly");
166 if (flags & EAF_NOT_RETURNED_INDIRECTLY)
167 fprintf (out, " not_returned_indirectly");
168 if (flags & EAF_NO_DIRECT_READ)
169 fprintf (out, " no_direct_read");
170 if (flags & EAF_NO_INDIRECT_READ)
171 fprintf (out, " no_indirect_read");
172 if (newline)
173 fprintf (out, "\n");
176 struct escape_summary
178 auto_vec <escape_entry> esc;
179 void dump (FILE *out)
181 for (unsigned int i = 0; i < esc.length (); i++)
183 fprintf (out, " parm %i arg %i %s min:",
184 esc[i].parm_index,
185 esc[i].arg,
186 esc[i].direct ? "(direct)" : "(indirect)");
187 dump_eaf_flags (out, esc[i].min_flags, false);
189 fprintf (out, "\n");
193 class escape_summaries_t : public call_summary <escape_summary *>
195 public:
196 escape_summaries_t (symbol_table *symtab)
197 : call_summary <escape_summary *> (symtab) {}
198 /* Hook that is called by summary when an edge is duplicated. */
199 void duplicate (cgraph_edge *,
200 cgraph_edge *,
201 escape_summary *src,
202 escape_summary *dst) final override
204 dst->esc = src->esc.copy ();
208 static escape_summaries_t *escape_summaries = NULL;
210 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
213 /* Class (from which there is one global instance) that holds modref summaries
214 for all analyzed functions. */
216 class GTY((user)) modref_summaries
217 : public fast_function_summary <modref_summary *, va_gc>
219 public:
220 modref_summaries (symbol_table *symtab)
221 : fast_function_summary <modref_summary *, va_gc> (symtab) {}
222 void insert (cgraph_node *, modref_summary *state) final override;
223 void duplicate (cgraph_node *src_node,
224 cgraph_node *dst_node,
225 modref_summary *src_data,
226 modref_summary *dst_data) final override;
227 static modref_summaries *create_ggc (symbol_table *symtab)
229 return new (ggc_alloc_no_dtor<modref_summaries> ())
230 modref_summaries (symtab);
234 class modref_summary_lto;
236 /* Class (from which there is one global instance) that holds modref summaries
237 for all analyzed functions. */
239 class GTY((user)) modref_summaries_lto
240 : public fast_function_summary <modref_summary_lto *, va_gc>
242 public:
243 modref_summaries_lto (symbol_table *symtab)
244 : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
245 propagated (false) {}
246 void insert (cgraph_node *, modref_summary_lto *state) final override;
247 void duplicate (cgraph_node *src_node,
248 cgraph_node *dst_node,
249 modref_summary_lto *src_data,
250 modref_summary_lto *dst_data) final override;
251 static modref_summaries_lto *create_ggc (symbol_table *symtab)
253 return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
254 modref_summaries_lto (symtab);
256 bool propagated;
259 /* Global variable holding all modref summaries
260 (from analysis to IPA propagation time). */
262 static GTY(()) fast_function_summary <modref_summary *, va_gc>
263 *summaries;
265 /* Global variable holding all modref optimization summaries
266 (from IPA propagation time or used by local optimization pass). */
268 static GTY(()) fast_function_summary <modref_summary *, va_gc>
269 *optimization_summaries;
271 /* LTO summaries hold info from analysis to LTO streaming or from LTO
272 stream-in through propagation to LTO stream-out. */
274 static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
275 *summaries_lto;
277 /* Summary for a single function which this pass produces. */
279 modref_summary::modref_summary ()
280 : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
281 writes_errno (false), side_effects (false), nondeterministic (false),
282 calls_interposable (false), global_memory_read (false),
283 global_memory_written (false), try_dse (false)
287 modref_summary::~modref_summary ()
289 if (loads)
290 ggc_delete (loads);
291 if (stores)
292 ggc_delete (stores);
295 /* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
296 useful to track. If returns_void is true moreover clear
297 EAF_NOT_RETURNED. */
298 static int
299 remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
301 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
302 eaf_flags &= ~implicit_const_eaf_flags;
303 else if (ecf_flags & ECF_PURE)
304 eaf_flags &= ~implicit_pure_eaf_flags;
305 else if ((ecf_flags & ECF_NORETURN) || returns_void)
306 eaf_flags &= ~(EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY);
307 return eaf_flags;
310 /* Return true if FLAGS holds some useful information. */
312 static bool
313 eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags)
315 for (unsigned i = 0; i < flags.length (); i++)
316 if (remove_useless_eaf_flags (flags[i], ecf_flags, false))
317 return true;
318 return false;
321 /* Return true if summary is potentially useful for optimization.
322 If CHECK_FLAGS is false assume that arg_flags are useful. */
324 bool
325 modref_summary::useful_p (int ecf_flags, bool check_flags)
327 if (arg_flags.length () && !check_flags)
328 return true;
329 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
330 return true;
331 arg_flags.release ();
332 if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
333 return true;
334 if (check_flags
335 && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
336 return true;
337 if (ecf_flags & ECF_CONST)
338 return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
339 if (loads && !loads->every_base)
340 return true;
341 else
342 kills.release ();
343 if (ecf_flags & ECF_PURE)
344 return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
345 return stores && !stores->every_base;
348 /* Single function summary used for LTO. */
350 typedef modref_tree <tree> modref_records_lto;
351 struct GTY(()) modref_summary_lto
353 /* Load and stores in functions using types rather then alias sets.
355 This is necessary to make the information streamable for LTO but is also
356 more verbose and thus more likely to hit the limits. */
357 modref_records_lto *loads;
358 modref_records_lto *stores;
359 auto_vec<modref_access_node> GTY((skip)) kills;
360 auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
361 eaf_flags_t retslot_flags;
362 eaf_flags_t static_chain_flags;
363 unsigned writes_errno : 1;
364 unsigned side_effects : 1;
365 unsigned nondeterministic : 1;
366 unsigned calls_interposable : 1;
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), retslot_flags (0), static_chain_flags (0),
378 writes_errno (false), side_effects (false), nondeterministic (false),
379 calls_interposable (false)
383 modref_summary_lto::~modref_summary_lto ()
385 if (loads)
386 ggc_delete (loads);
387 if (stores)
388 ggc_delete (stores);
392 /* Return true if lto summary is potentially useful for optimization.
393 If CHECK_FLAGS is false assume that arg_flags are useful. */
395 bool
396 modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
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 (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
404 return true;
405 if (check_flags
406 && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
407 return true;
408 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
409 return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
410 if (loads && !loads->every_base)
411 return true;
412 else
413 kills.release ();
414 if (ecf_flags & ECF_PURE)
415 return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
416 return stores && !stores->every_base;
419 /* Dump records TT to OUT. */
421 static void
422 dump_records (modref_records *tt, FILE *out)
424 if (tt->every_base)
426 fprintf (out, " Every base\n");
427 return;
429 size_t i;
430 modref_base_node <alias_set_type> *n;
431 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
433 fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
434 if (n->every_ref)
436 fprintf (out, " Every ref\n");
437 continue;
439 size_t j;
440 modref_ref_node <alias_set_type> *r;
441 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
443 fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
444 if (r->every_access)
446 fprintf (out, " Every access\n");
447 continue;
449 size_t k;
450 modref_access_node *a;
451 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
453 fprintf (out, " access:");
454 a->dump (out);
460 /* Dump records TT to OUT. */
462 static void
463 dump_lto_records (modref_records_lto *tt, FILE *out)
465 if (tt->every_base)
467 fprintf (out, " Every base\n");
468 return;
470 size_t i;
471 modref_base_node <tree> *n;
472 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
474 fprintf (out, " Base %i:", (int)i);
475 print_generic_expr (out, n->base);
476 fprintf (out, " (alias set %i)\n",
477 n->base ? get_alias_set (n->base) : 0);
478 if (n->every_ref)
480 fprintf (out, " Every ref\n");
481 continue;
483 size_t j;
484 modref_ref_node <tree> *r;
485 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
487 fprintf (out, " Ref %i:", (int)j);
488 print_generic_expr (out, r->ref);
489 fprintf (out, " (alias set %i)\n",
490 r->ref ? get_alias_set (r->ref) : 0);
491 if (r->every_access)
493 fprintf (out, " Every access\n");
494 continue;
496 size_t k;
497 modref_access_node *a;
498 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
500 fprintf (out, " access:");
501 a->dump (out);
507 /* Dump all escape points of NODE to OUT. */
509 static void
510 dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
512 int i = 0;
513 if (!escape_summaries)
514 return;
515 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
517 class escape_summary *sum = escape_summaries->get (e);
518 if (sum)
520 fprintf (out, "%*sIndirect call %i in %s escapes:",
521 depth, "", i, node->dump_name ());
522 sum->dump (out);
524 i++;
526 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
528 if (!e->inline_failed)
529 dump_modref_edge_summaries (out, e->callee, depth + 1);
530 class escape_summary *sum = escape_summaries->get (e);
531 if (sum)
533 fprintf (out, "%*sCall %s->%s escapes:", depth, "",
534 node->dump_name (), e->callee->dump_name ());
535 sum->dump (out);
537 class fnspec_summary *fsum = fnspec_summaries->get (e);
538 if (fsum)
540 fprintf (out, "%*sCall %s->%s fnspec: %s\n", depth, "",
541 node->dump_name (), e->callee->dump_name (),
542 fsum->fnspec);
547 /* Remove all call edge summaries associated with NODE. */
549 static void
550 remove_modref_edge_summaries (cgraph_node *node)
552 if (!escape_summaries)
553 return;
554 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
555 escape_summaries->remove (e);
556 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
558 if (!e->inline_failed)
559 remove_modref_edge_summaries (e->callee);
560 escape_summaries->remove (e);
561 fnspec_summaries->remove (e);
565 /* Dump summary. */
567 void
568 modref_summary::dump (FILE *out) const
570 if (loads)
572 fprintf (out, " loads:\n");
573 dump_records (loads, out);
575 if (stores)
577 fprintf (out, " stores:\n");
578 dump_records (stores, out);
580 if (kills.length ())
582 fprintf (out, " kills:\n");
583 for (auto kill : kills)
585 fprintf (out, " ");
586 kill.dump (out);
589 if (writes_errno)
590 fprintf (out, " Writes errno\n");
591 if (side_effects)
592 fprintf (out, " Side effects\n");
593 if (nondeterministic)
594 fprintf (out, " Nondeterministic\n");
595 if (calls_interposable)
596 fprintf (out, " Calls interposable\n");
597 if (global_memory_read)
598 fprintf (out, " Global memory read\n");
599 if (global_memory_written)
600 fprintf (out, " Global memory written\n");
601 if (try_dse)
602 fprintf (out, " Try dse\n");
603 if (arg_flags.length ())
605 for (unsigned int i = 0; i < arg_flags.length (); i++)
606 if (arg_flags[i])
608 fprintf (out, " parm %i flags:", i);
609 dump_eaf_flags (out, arg_flags[i]);
612 if (retslot_flags)
614 fprintf (out, " Retslot flags:");
615 dump_eaf_flags (out, retslot_flags);
617 if (static_chain_flags)
619 fprintf (out, " Static chain flags:");
620 dump_eaf_flags (out, static_chain_flags);
624 /* Dump summary. */
626 void
627 modref_summary_lto::dump (FILE *out)
629 fprintf (out, " loads:\n");
630 dump_lto_records (loads, out);
631 fprintf (out, " stores:\n");
632 dump_lto_records (stores, out);
633 if (kills.length ())
635 fprintf (out, " kills:\n");
636 for (auto kill : kills)
638 fprintf (out, " ");
639 kill.dump (out);
642 if (writes_errno)
643 fprintf (out, " Writes errno\n");
644 if (side_effects)
645 fprintf (out, " Side effects\n");
646 if (nondeterministic)
647 fprintf (out, " Nondeterministic\n");
648 if (calls_interposable)
649 fprintf (out, " Calls interposable\n");
650 if (arg_flags.length ())
652 for (unsigned int i = 0; i < arg_flags.length (); i++)
653 if (arg_flags[i])
655 fprintf (out, " parm %i flags:", i);
656 dump_eaf_flags (out, arg_flags[i]);
659 if (retslot_flags)
661 fprintf (out, " Retslot flags:");
662 dump_eaf_flags (out, retslot_flags);
664 if (static_chain_flags)
666 fprintf (out, " Static chain flags:");
667 dump_eaf_flags (out, static_chain_flags);
671 /* Called after summary is produced and before it is used by local analysis.
672 Can be called multiple times in case summary needs to update signature.
673 FUN is decl of function summary is attached to. */
674 void
675 modref_summary::finalize (tree fun)
677 global_memory_read = !loads || loads->global_access_p ();
678 global_memory_written = !stores || stores->global_access_p ();
680 /* We can do DSE if we know function has no side effects and
681 we can analyze all stores. Disable dse if there are too many
682 stores to try. */
683 if (side_effects || global_memory_written || writes_errno)
684 try_dse = false;
685 else
687 try_dse = true;
688 size_t i, j, k;
689 int num_tests = 0, max_tests
690 = opt_for_fn (fun, param_modref_max_tests);
691 modref_base_node <alias_set_type> *base_node;
692 modref_ref_node <alias_set_type> *ref_node;
693 modref_access_node *access_node;
694 FOR_EACH_VEC_SAFE_ELT (stores->bases, i, base_node)
696 if (base_node->every_ref)
698 try_dse = false;
699 break;
701 FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
703 if (base_node->every_ref)
705 try_dse = false;
706 break;
708 FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
709 if (num_tests++ > max_tests
710 || !access_node->parm_offset_known)
712 try_dse = false;
713 break;
715 if (!try_dse)
716 break;
718 if (!try_dse)
719 break;
722 if (loads->every_base)
723 load_accesses = 1;
724 else
726 load_accesses = 0;
727 for (auto base_node : loads->bases)
729 if (base_node->every_ref)
730 load_accesses++;
731 else
732 for (auto ref_node : base_node->refs)
733 if (ref_node->every_access)
734 load_accesses++;
735 else
736 load_accesses += ref_node->accesses->length ();
741 /* Get function summary for FUNC if it exists, return NULL otherwise. */
743 modref_summary *
744 get_modref_function_summary (cgraph_node *func)
746 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
747 if (!optimization_summaries)
748 return NULL;
750 /* A single function body may be represented by multiple symbols with
751 different visibility. For example, if FUNC is an interposable alias,
752 we don't want to return anything, even if we have summary for the target
753 function. */
754 enum availability avail;
755 func = func->ultimate_alias_target
756 (&avail, current_function_decl ?
757 cgraph_node::get (current_function_decl) : NULL);
758 if (avail <= AVAIL_INTERPOSABLE)
759 return NULL;
761 modref_summary *r = optimization_summaries->get (func);
762 return r;
765 /* Get function summary for CALL if it exists, return NULL otherwise.
766 If non-null set interposed to indicate whether function may not
767 bind to current def. In this case sometimes loads from function
768 needs to be ignored. */
770 modref_summary *
771 get_modref_function_summary (gcall *call, bool *interposed)
773 tree callee = gimple_call_fndecl (call);
774 if (!callee)
775 return NULL;
776 struct cgraph_node *node = cgraph_node::get (callee);
777 if (!node)
778 return NULL;
779 modref_summary *r = get_modref_function_summary (node);
780 if (interposed && r)
781 *interposed = r->calls_interposable
782 || !node->binds_to_current_def_p ();
783 return r;
787 namespace {
789 /* Return true if ECF flags says that nondeterminism can be ignored. */
791 static bool
792 ignore_nondeterminism_p (tree caller, int flags, tree callee_fntype)
794 int caller_flags = flags_from_decl_or_type (caller);
795 if ((flags | caller_flags) & (ECF_CONST | ECF_PURE))
796 return true;
797 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
798 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
799 return true;
800 /* C language defines unsequenced and reproducible functions
801 to be deterministic. */
802 if (lookup_attribute ("unsequenced", TYPE_ATTRIBUTES (TREE_TYPE (caller)))
803 || lookup_attribute ("reproducible",
804 TYPE_ATTRIBUTES (TREE_TYPE (caller))))
805 return true;
806 if (callee_fntype
807 && (lookup_attribute ("unsequenced", TYPE_ATTRIBUTES (callee_fntype))
808 || lookup_attribute ("reproducible",
809 TYPE_ATTRIBUTES (callee_fntype))))
810 return true;
811 return false;
814 /* Return true if ECF flags says that return value can be ignored. */
816 static bool
817 ignore_retval_p (tree caller, int flags)
819 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
820 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
821 return true;
822 return false;
825 /* Return true if ECF flags says that stores can be ignored. */
827 static bool
828 ignore_stores_p (tree caller, int flags)
830 if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
831 return true;
832 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
833 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
834 return true;
835 return false;
838 /* Determine parm_map for PTR which is supposed to be a pointer. */
840 modref_parm_map
841 parm_map_for_ptr (tree op)
843 bool offset_known;
844 poly_int64 offset;
845 struct modref_parm_map parm_map;
846 gcall *call;
848 parm_map.parm_offset_known = false;
849 parm_map.parm_offset = 0;
851 offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
852 if (TREE_CODE (op) == SSA_NAME
853 && SSA_NAME_IS_DEFAULT_DEF (op)
854 && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
856 int index = 0;
858 if (cfun->static_chain_decl
859 && op == ssa_default_def (cfun, cfun->static_chain_decl))
860 index = MODREF_STATIC_CHAIN_PARM;
861 else
862 for (tree t = DECL_ARGUMENTS (current_function_decl);
863 t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
864 index++;
865 parm_map.parm_index = index;
866 parm_map.parm_offset_known = offset_known;
867 parm_map.parm_offset = offset;
869 else if (points_to_local_or_readonly_memory_p (op))
870 parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM;
871 /* Memory allocated in the function is not visible to caller before the
872 call and thus we do not need to record it as load/stores/kills. */
873 else if (TREE_CODE (op) == SSA_NAME
874 && (call = dyn_cast<gcall *>(SSA_NAME_DEF_STMT (op))) != NULL
875 && gimple_call_flags (call) & ECF_MALLOC)
876 parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM;
877 else
878 parm_map.parm_index = MODREF_UNKNOWN_PARM;
879 return parm_map;
882 /* Return true if ARG with EAF flags FLAGS can not make any caller's parameter
883 used (if LOAD is true we check loads, otherwise stores). */
885 static bool
886 verify_arg (tree arg, int flags, bool load)
888 if (flags & EAF_UNUSED)
889 return true;
890 if (load && (flags & EAF_NO_DIRECT_READ))
891 return true;
892 if (!load
893 && (flags & (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER))
894 == (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER))
895 return true;
896 if (is_gimple_constant (arg))
897 return true;
898 if (DECL_P (arg) && TREE_READONLY (arg))
899 return true;
900 if (TREE_CODE (arg) == ADDR_EXPR)
902 tree t = get_base_address (TREE_OPERAND (arg, 0));
903 if (is_gimple_constant (t))
904 return true;
905 if (DECL_P (t)
906 && (TREE_READONLY (t) || TREE_CODE (t) == FUNCTION_DECL))
907 return true;
909 return false;
912 /* Return true if STMT may access memory that is pointed to by parameters
913 of caller and which is not seen as an escape by PTA.
914 CALLEE_ECF_FLAGS are ECF flags of callee. If LOAD is true then by access
915 we mean load, otherwise we mean store. */
917 static bool
918 may_access_nonescaping_parm_p (gcall *call, int callee_ecf_flags, bool load)
920 int implicit_flags = 0;
922 if (ignore_stores_p (current_function_decl, callee_ecf_flags))
923 implicit_flags |= ignore_stores_eaf_flags;
924 if (callee_ecf_flags & ECF_PURE)
925 implicit_flags |= implicit_pure_eaf_flags;
926 if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
927 implicit_flags |= implicit_const_eaf_flags;
928 if (gimple_call_chain (call)
929 && !verify_arg (gimple_call_chain (call),
930 gimple_call_static_chain_flags (call) | implicit_flags,
931 load))
932 return true;
933 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
934 if (!verify_arg (gimple_call_arg (call, i),
935 gimple_call_arg_flags (call, i) | implicit_flags,
936 load))
937 return true;
938 return false;
942 /* Analyze memory accesses (loads, stores and kills) performed
943 by the function. Set also side_effects, calls_interposable
944 and nondeterminism flags. */
946 class modref_access_analysis
948 public:
949 modref_access_analysis (bool ipa, modref_summary *summary,
950 modref_summary_lto *summary_lto)
951 : m_summary (summary), m_summary_lto (summary_lto), m_ipa (ipa)
954 void analyze ();
955 private:
956 bool set_side_effects ();
957 bool set_nondeterministic ();
958 static modref_access_node get_access (ao_ref *ref);
959 static void record_access (modref_records *, ao_ref *, modref_access_node &);
960 static void record_access_lto (modref_records_lto *, ao_ref *,
961 modref_access_node &a);
962 bool record_access_p (tree);
963 bool record_unknown_load ();
964 bool record_unknown_store ();
965 bool record_global_memory_load ();
966 bool record_global_memory_store ();
967 bool merge_call_side_effects (gimple *, modref_summary *,
968 cgraph_node *, bool);
969 modref_access_node get_access_for_fnspec (gcall *, attr_fnspec &,
970 unsigned int, modref_parm_map &);
971 void process_fnspec (gcall *);
972 void analyze_call (gcall *);
973 static bool analyze_load (gimple *, tree, tree, void *);
974 static bool analyze_store (gimple *, tree, tree, void *);
975 void analyze_stmt (gimple *, bool);
976 void propagate ();
978 /* Summary being computed.
979 We work either with m_summary or m_summary_lto. Never on both. */
980 modref_summary *m_summary;
981 modref_summary_lto *m_summary_lto;
982 /* Recursive calls needs simplistic dataflow after analysis finished.
983 Collect all calls into this vector during analysis and later process
984 them in propagate. */
985 auto_vec <gimple *, 32> m_recursive_calls;
986 /* ECF flags of function being analyzed. */
987 int m_ecf_flags;
988 /* True if IPA propagation will be done later. */
989 bool m_ipa;
990 /* Set true if statement currently analyze is known to be
991 executed each time function is called. */
992 bool m_always_executed;
995 /* Set side_effects flag and return if something changed. */
997 bool
998 modref_access_analysis::set_side_effects ()
1000 bool changed = false;
1002 if (m_summary && !m_summary->side_effects)
1004 m_summary->side_effects = true;
1005 changed = true;
1007 if (m_summary_lto && !m_summary_lto->side_effects)
1009 m_summary_lto->side_effects = true;
1010 changed = true;
1012 return changed;
1015 /* Set nondeterministic flag and return if something changed. */
1017 bool
1018 modref_access_analysis::set_nondeterministic ()
1020 bool changed = false;
1022 if (m_summary && !m_summary->nondeterministic)
1024 m_summary->side_effects = m_summary->nondeterministic = true;
1025 changed = true;
1027 if (m_summary_lto && !m_summary_lto->nondeterministic)
1029 m_summary_lto->side_effects = m_summary_lto->nondeterministic = true;
1030 changed = true;
1032 return changed;
1035 /* Construct modref_access_node from REF. */
1037 modref_access_node
1038 modref_access_analysis::get_access (ao_ref *ref)
1040 tree base;
1042 base = ao_ref_base (ref);
1043 modref_access_node a = {ref->offset, ref->size, ref->max_size,
1044 0, MODREF_UNKNOWN_PARM, false, 0};
1045 if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
1047 tree memref = base;
1048 modref_parm_map m = parm_map_for_ptr (TREE_OPERAND (base, 0));
1050 a.parm_index = m.parm_index;
1051 if (a.parm_index != MODREF_UNKNOWN_PARM && TREE_CODE (memref) == MEM_REF)
1053 a.parm_offset_known
1054 = wi::to_poly_wide (TREE_OPERAND
1055 (memref, 1)).to_shwi (&a.parm_offset);
1056 if (a.parm_offset_known && m.parm_offset_known)
1057 a.parm_offset += m.parm_offset;
1058 else
1059 a.parm_offset_known = false;
1062 else
1063 a.parm_index = MODREF_UNKNOWN_PARM;
1064 return a;
1067 /* Record access into the modref_records data structure. */
1069 void
1070 modref_access_analysis::record_access (modref_records *tt,
1071 ao_ref *ref,
1072 modref_access_node &a)
1074 alias_set_type base_set = !flag_strict_aliasing
1075 || !flag_ipa_strict_aliasing ? 0
1076 : ao_ref_base_alias_set (ref);
1077 alias_set_type ref_set = !flag_strict_aliasing
1078 || !flag_ipa_strict_aliasing ? 0
1079 : (ao_ref_alias_set (ref));
1080 if (dump_file)
1082 fprintf (dump_file, " - Recording base_set=%i ref_set=%i ",
1083 base_set, ref_set);
1084 a.dump (dump_file);
1086 tt->insert (current_function_decl, base_set, ref_set, a, false);
1089 /* IPA version of record_access_tree. */
1091 void
1092 modref_access_analysis::record_access_lto (modref_records_lto *tt, ao_ref *ref,
1093 modref_access_node &a)
1095 /* get_alias_set sometimes use different type to compute the alias set
1096 than TREE_TYPE (base). Do same adjustments. */
1097 tree base_type = NULL_TREE, ref_type = NULL_TREE;
1098 if (flag_strict_aliasing && flag_ipa_strict_aliasing)
1100 tree base;
1102 base = ref->ref;
1103 while (handled_component_p (base))
1104 base = TREE_OPERAND (base, 0);
1106 base_type = reference_alias_ptr_type_1 (&base);
1108 if (!base_type)
1109 base_type = TREE_TYPE (base);
1110 else
1111 base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
1112 ? NULL_TREE : TREE_TYPE (base_type);
1114 tree ref_expr = ref->ref;
1115 ref_type = reference_alias_ptr_type_1 (&ref_expr);
1117 if (!ref_type)
1118 ref_type = TREE_TYPE (ref_expr);
1119 else
1120 ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
1121 ? NULL_TREE : TREE_TYPE (ref_type);
1123 /* Sanity check that we are in sync with what get_alias_set does. */
1124 gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
1125 || get_alias_set (base_type)
1126 == ao_ref_base_alias_set (ref));
1127 gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
1128 || get_alias_set (ref_type)
1129 == ao_ref_alias_set (ref));
1131 /* Do not bother to record types that have no meaningful alias set.
1132 Also skip variably modified types since these go to local streams. */
1133 if (base_type && (!get_alias_set (base_type)
1134 || variably_modified_type_p (base_type, NULL_TREE)))
1135 base_type = NULL_TREE;
1136 if (ref_type && (!get_alias_set (ref_type)
1137 || variably_modified_type_p (ref_type, NULL_TREE)))
1138 ref_type = NULL_TREE;
1140 if (dump_file)
1142 fprintf (dump_file, " - Recording base type:");
1143 print_generic_expr (dump_file, base_type);
1144 fprintf (dump_file, " (alias set %i) ref type:",
1145 base_type ? get_alias_set (base_type) : 0);
1146 print_generic_expr (dump_file, ref_type);
1147 fprintf (dump_file, " (alias set %i) ",
1148 ref_type ? get_alias_set (ref_type) : 0);
1149 a.dump (dump_file);
1152 tt->insert (current_function_decl, base_type, ref_type, a, false);
1155 /* Returns true if and only if we should store the access to EXPR.
1156 Some accesses, e.g. loads from automatic variables, are not interesting. */
1158 bool
1159 modref_access_analysis::record_access_p (tree expr)
1161 if (TREE_THIS_VOLATILE (expr)
1162 && !ignore_nondeterminism_p (current_function_decl, 0, NULL))
1164 if (dump_file)
1165 fprintf (dump_file, " (volatile; marking nondeterministic) ");
1166 set_nondeterministic ();
1168 if (cfun->can_throw_non_call_exceptions
1169 && tree_could_throw_p (expr))
1171 if (dump_file)
1172 fprintf (dump_file, " (can throw; marking side effects) ");
1173 set_side_effects ();
1176 if (refs_local_or_readonly_memory_p (expr))
1178 if (dump_file)
1179 fprintf (dump_file, " - Read-only or local, ignoring.\n");
1180 return false;
1182 return true;
1185 /* Collapse loads and return true if something changed. */
1187 bool
1188 modref_access_analysis::record_unknown_load ()
1190 bool changed = false;
1192 if (m_summary && !m_summary->loads->every_base)
1194 m_summary->loads->collapse ();
1195 changed = true;
1197 if (m_summary_lto && !m_summary_lto->loads->every_base)
1199 m_summary_lto->loads->collapse ();
1200 changed = true;
1202 return changed;
1205 /* Collapse loads and return true if something changed. */
1207 bool
1208 modref_access_analysis::record_unknown_store ()
1210 bool changed = false;
1212 if (m_summary && !m_summary->stores->every_base)
1214 m_summary->stores->collapse ();
1215 changed = true;
1217 if (m_summary_lto && !m_summary_lto->stores->every_base)
1219 m_summary_lto->stores->collapse ();
1220 changed = true;
1222 return changed;
1225 /* Record unknown load from global memory. */
1227 bool
1228 modref_access_analysis::record_global_memory_load ()
1230 bool changed = false;
1231 modref_access_node a = {0, -1, -1,
1232 0, MODREF_GLOBAL_MEMORY_PARM, false, 0};
1234 if (m_summary && !m_summary->loads->every_base)
1235 changed |= m_summary->loads->insert (current_function_decl, 0, 0, a, false);
1236 if (m_summary_lto && !m_summary_lto->loads->every_base)
1237 changed |= m_summary_lto->loads->insert (current_function_decl,
1238 0, 0, a, false);
1239 return changed;
1242 /* Record unknown store from global memory. */
1244 bool
1245 modref_access_analysis::record_global_memory_store ()
1247 bool changed = false;
1248 modref_access_node a = {0, -1, -1,
1249 0, MODREF_GLOBAL_MEMORY_PARM, false, 0};
1251 if (m_summary && !m_summary->stores->every_base)
1252 changed |= m_summary->stores->insert (current_function_decl,
1253 0, 0, a, false);
1254 if (m_summary_lto && !m_summary_lto->stores->every_base)
1255 changed |= m_summary_lto->stores->insert (current_function_decl,
1256 0, 0, a, false);
1257 return changed;
1260 /* Merge side effects of call STMT to function with CALLEE_SUMMARY.
1261 Return true if something changed.
1262 If IGNORE_STORES is true, do not merge stores.
1263 If RECORD_ADJUSTMENTS is true cap number of adjustments to
1264 a given access to make dataflow finite. */
1266 bool
1267 modref_access_analysis::merge_call_side_effects
1268 (gimple *stmt, modref_summary *callee_summary,
1269 cgraph_node *callee_node, bool record_adjustments)
1271 gcall *call = as_a <gcall *> (stmt);
1272 int flags = gimple_call_flags (call);
1274 /* Nothing to do for non-looping cont functions. */
1275 if ((flags & ECF_CONST)
1276 && !(flags & ECF_LOOPING_CONST_OR_PURE))
1277 return false;
1279 bool changed = false;
1281 if (dump_file)
1282 fprintf (dump_file, " - Merging side effects of %s\n",
1283 callee_node->dump_name ());
1285 /* Merge side effects and non-determinism.
1286 PURE/CONST flags makes functions deterministic and if there is
1287 no LOOPING_CONST_OR_PURE they also have no side effects. */
1288 if (!(flags & (ECF_CONST | ECF_PURE))
1289 || (flags & ECF_LOOPING_CONST_OR_PURE))
1291 if (!m_summary->side_effects && callee_summary->side_effects)
1293 if (dump_file)
1294 fprintf (dump_file, " - merging side effects.\n");
1295 m_summary->side_effects = true;
1296 changed = true;
1298 if (!m_summary->nondeterministic && callee_summary->nondeterministic
1299 && !ignore_nondeterminism_p (current_function_decl, flags,
1300 gimple_call_fntype (call)))
1302 if (dump_file)
1303 fprintf (dump_file, " - merging nondeterministic.\n");
1304 m_summary->nondeterministic = true;
1305 changed = true;
1309 /* For const functions we are done. */
1310 if (flags & (ECF_CONST | ECF_NOVOPS))
1311 return changed;
1313 /* Merge calls_interposable flags. */
1314 if (!m_summary->calls_interposable && callee_summary->calls_interposable)
1316 if (dump_file)
1317 fprintf (dump_file, " - merging calls interposable.\n");
1318 m_summary->calls_interposable = true;
1319 changed = true;
1322 if (!callee_node->binds_to_current_def_p () && !m_summary->calls_interposable)
1324 if (dump_file)
1325 fprintf (dump_file, " - May be interposed.\n");
1326 m_summary->calls_interposable = true;
1327 changed = true;
1330 /* Now merge the actual load, store and kill vectors. For this we need
1331 to compute map translating new parameters to old. */
1332 if (dump_file)
1333 fprintf (dump_file, " Parm map:");
1335 auto_vec <modref_parm_map, 32> parm_map;
1336 parm_map.safe_grow_cleared (gimple_call_num_args (call), true);
1337 for (unsigned i = 0; i < gimple_call_num_args (call); i++)
1339 parm_map[i] = parm_map_for_ptr (gimple_call_arg (call, i));
1340 if (dump_file)
1342 fprintf (dump_file, " %i", parm_map[i].parm_index);
1343 if (parm_map[i].parm_offset_known)
1345 fprintf (dump_file, " offset:");
1346 print_dec ((poly_int64)parm_map[i].parm_offset,
1347 dump_file, SIGNED);
1352 modref_parm_map chain_map;
1353 if (gimple_call_chain (call))
1355 chain_map = parm_map_for_ptr (gimple_call_chain (call));
1356 if (dump_file)
1358 fprintf (dump_file, "static chain %i", chain_map.parm_index);
1359 if (chain_map.parm_offset_known)
1361 fprintf (dump_file, " offset:");
1362 print_dec ((poly_int64)chain_map.parm_offset,
1363 dump_file, SIGNED);
1367 if (dump_file)
1368 fprintf (dump_file, "\n");
1370 /* Kills can me merged in only if we know the function is going to be
1371 always executed. */
1372 if (m_always_executed
1373 && callee_summary->kills.length ()
1374 && (!cfun->can_throw_non_call_exceptions
1375 || !stmt_could_throw_p (cfun, call)))
1377 /* Watch for self recursive updates. */
1378 auto_vec<modref_access_node, 32> saved_kills;
1380 saved_kills.reserve_exact (callee_summary->kills.length ());
1381 saved_kills.splice (callee_summary->kills);
1382 for (auto kill : saved_kills)
1384 if (kill.parm_index >= (int)parm_map.length ())
1385 continue;
1386 modref_parm_map &m
1387 = kill.parm_index == MODREF_STATIC_CHAIN_PARM
1388 ? chain_map
1389 : parm_map[kill.parm_index];
1390 if (m.parm_index == MODREF_LOCAL_MEMORY_PARM
1391 || m.parm_index == MODREF_UNKNOWN_PARM
1392 || m.parm_index == MODREF_RETSLOT_PARM
1393 || !m.parm_offset_known)
1394 continue;
1395 modref_access_node n = kill;
1396 n.parm_index = m.parm_index;
1397 n.parm_offset += m.parm_offset;
1398 if (modref_access_node::insert_kill (m_summary->kills, n,
1399 record_adjustments))
1400 changed = true;
1404 /* Merge in loads. */
1405 changed |= m_summary->loads->merge (current_function_decl,
1406 callee_summary->loads,
1407 &parm_map, &chain_map,
1408 record_adjustments,
1409 !may_access_nonescaping_parm_p
1410 (call, flags, true));
1411 /* Merge in stores. */
1412 if (!ignore_stores_p (current_function_decl, flags))
1414 changed |= m_summary->stores->merge (current_function_decl,
1415 callee_summary->stores,
1416 &parm_map, &chain_map,
1417 record_adjustments,
1418 !may_access_nonescaping_parm_p
1419 (call, flags, false));
1420 if (!m_summary->writes_errno
1421 && callee_summary->writes_errno)
1423 m_summary->writes_errno = true;
1424 changed = true;
1427 return changed;
1430 /* Return access mode for argument I of call STMT with FNSPEC. */
1432 modref_access_node
1433 modref_access_analysis::get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
1434 unsigned int i,
1435 modref_parm_map &map)
1437 tree size = NULL_TREE;
1438 unsigned int size_arg;
1440 if (!fnspec.arg_specified_p (i))
1442 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
1443 size = gimple_call_arg (call, size_arg);
1444 else if (fnspec.arg_access_size_given_by_type_p (i))
1446 tree callee = gimple_call_fndecl (call);
1447 tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
1449 for (unsigned int p = 0; p < i; p++)
1450 t = TREE_CHAIN (t);
1451 size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
1453 modref_access_node a = {0, -1, -1,
1454 map.parm_offset, map.parm_index,
1455 map.parm_offset_known, 0};
1456 poly_int64 size_hwi;
1457 if (size
1458 && poly_int_tree_p (size, &size_hwi)
1459 && coeffs_in_range_p (size_hwi, 0,
1460 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
1462 a.size = -1;
1463 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
1465 return a;
1468 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1469 If IGNORE_STORES is true ignore them.
1470 Return false if no useful summary can be produced. */
1472 void
1473 modref_access_analysis::process_fnspec (gcall *call)
1475 int flags = gimple_call_flags (call);
1477 /* PURE/CONST flags makes functions deterministic and if there is
1478 no LOOPING_CONST_OR_PURE they also have no side effects. */
1479 if (!(flags & (ECF_CONST | ECF_PURE))
1480 || (flags & ECF_LOOPING_CONST_OR_PURE)
1481 || (cfun->can_throw_non_call_exceptions
1482 && stmt_could_throw_p (cfun, call)))
1484 set_side_effects ();
1485 if (!ignore_nondeterminism_p (current_function_decl, flags,
1486 gimple_call_fntype (call)))
1487 set_nondeterministic ();
1490 /* For const functions we are done. */
1491 if (flags & (ECF_CONST | ECF_NOVOPS))
1492 return;
1494 attr_fnspec fnspec = gimple_call_fnspec (call);
1495 /* If there is no fnpec we know nothing about loads & stores. */
1496 if (!fnspec.known_p ())
1498 if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
1499 fprintf (dump_file, " Builtin with no fnspec: %s\n",
1500 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
1501 if (!ignore_stores_p (current_function_decl, flags))
1503 if (!may_access_nonescaping_parm_p (call, flags, false))
1504 record_global_memory_store ();
1505 else
1506 record_unknown_store ();
1507 if (!may_access_nonescaping_parm_p (call, flags, true))
1508 record_global_memory_load ();
1509 else
1510 record_unknown_load ();
1512 else
1514 if (!may_access_nonescaping_parm_p (call, flags, true))
1515 record_global_memory_load ();
1516 else
1517 record_unknown_load ();
1519 return;
1521 /* Process fnspec. */
1522 if (fnspec.global_memory_read_p ())
1524 if (may_access_nonescaping_parm_p (call, flags, true))
1525 record_unknown_load ();
1526 else
1527 record_global_memory_load ();
1529 else
1531 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1532 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1534 else if (!fnspec.arg_specified_p (i)
1535 || fnspec.arg_maybe_read_p (i))
1537 modref_parm_map map = parm_map_for_ptr
1538 (gimple_call_arg (call, i));
1540 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
1541 continue;
1542 if (map.parm_index == MODREF_UNKNOWN_PARM)
1544 record_unknown_load ();
1545 break;
1547 modref_access_node a = get_access_for_fnspec (call, fnspec, i, map);
1548 if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1549 continue;
1550 if (m_summary)
1551 m_summary->loads->insert (current_function_decl, 0, 0, a, false);
1552 if (m_summary_lto)
1553 m_summary_lto->loads->insert (current_function_decl, 0, 0, a,
1554 false);
1557 if (ignore_stores_p (current_function_decl, flags))
1558 return;
1559 if (fnspec.global_memory_written_p ())
1561 if (may_access_nonescaping_parm_p (call, flags, false))
1562 record_unknown_store ();
1563 else
1564 record_global_memory_store ();
1566 else
1568 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1569 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1571 else if (!fnspec.arg_specified_p (i)
1572 || fnspec.arg_maybe_written_p (i))
1574 modref_parm_map map = parm_map_for_ptr
1575 (gimple_call_arg (call, i));
1577 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
1578 continue;
1579 if (map.parm_index == MODREF_UNKNOWN_PARM)
1581 record_unknown_store ();
1582 break;
1584 modref_access_node a = get_access_for_fnspec (call, fnspec, i, map);
1585 if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1586 continue;
1587 if (m_summary)
1588 m_summary->stores->insert (current_function_decl, 0, 0, a, false);
1589 if (m_summary_lto)
1590 m_summary_lto->stores->insert (current_function_decl,
1591 0, 0, a, false);
1593 if (fnspec.errno_maybe_written_p () && flag_errno_math)
1595 if (m_summary)
1596 m_summary->writes_errno = true;
1597 if (m_summary_lto)
1598 m_summary_lto->writes_errno = true;
1603 /* Analyze function call STMT in function F.
1604 Remember recursive calls in RECURSIVE_CALLS. */
1606 void
1607 modref_access_analysis::analyze_call (gcall *stmt)
1609 /* Check flags on the function call. In certain cases, analysis can be
1610 simplified. */
1611 int flags = gimple_call_flags (stmt);
1613 if (dump_file)
1615 fprintf (dump_file, " - Analyzing call:");
1616 print_gimple_stmt (dump_file, stmt, 0);
1619 if ((flags & ECF_CONST)
1620 && !(flags & ECF_LOOPING_CONST_OR_PURE))
1622 if (dump_file)
1623 fprintf (dump_file,
1624 " - ECF_CONST, ignoring all stores and all loads "
1625 "except for args.\n");
1626 return;
1629 /* Next, we try to get the callee's function declaration. The goal is to
1630 merge their summary with ours. */
1631 tree callee = gimple_call_fndecl (stmt);
1633 /* Check if this is an indirect call. */
1634 if (!callee)
1636 if (dump_file)
1637 fprintf (dump_file, gimple_call_internal_p (stmt)
1638 ? " - Internal call" : " - Indirect call.\n");
1639 process_fnspec (stmt);
1640 return;
1642 /* We only need to handle internal calls in IPA mode. */
1643 gcc_checking_assert (!m_summary_lto && !m_ipa);
1645 struct cgraph_node *callee_node = cgraph_node::get_create (callee);
1647 /* If this is a recursive call, the target summary is the same as ours, so
1648 there's nothing to do. */
1649 if (recursive_call_p (current_function_decl, callee))
1651 m_recursive_calls.safe_push (stmt);
1652 set_side_effects ();
1653 if (dump_file)
1654 fprintf (dump_file, " - Skipping recursive call.\n");
1655 return;
1658 gcc_assert (callee_node != NULL);
1660 /* Get the function symbol and its availability. */
1661 enum availability avail;
1662 callee_node = callee_node->function_symbol (&avail);
1663 bool looping;
1664 if (builtin_safe_for_const_function_p (&looping, callee))
1666 if (looping)
1667 set_side_effects ();
1668 if (dump_file)
1669 fprintf (dump_file, " - Builtin is safe for const.\n");
1670 return;
1672 if (avail <= AVAIL_INTERPOSABLE)
1674 if (dump_file)
1675 fprintf (dump_file,
1676 " - Function availability <= AVAIL_INTERPOSABLE.\n");
1677 process_fnspec (stmt);
1678 return;
1681 /* Get callee's modref summary. As above, if there's no summary, we either
1682 have to give up or, if stores are ignored, we can just purge loads. */
1683 modref_summary *callee_summary = optimization_summaries->get (callee_node);
1684 if (!callee_summary)
1686 if (dump_file)
1687 fprintf (dump_file, " - No modref summary available for callee.\n");
1688 process_fnspec (stmt);
1689 return;
1692 merge_call_side_effects (stmt, callee_summary, callee_node, false);
1694 return;
1697 /* Helper for analyze_stmt. */
1699 bool
1700 modref_access_analysis::analyze_load (gimple *, tree, tree op, void *data)
1702 modref_access_analysis *t = (modref_access_analysis *)data;
1704 if (dump_file)
1706 fprintf (dump_file, " - Analyzing load: ");
1707 print_generic_expr (dump_file, op);
1708 fprintf (dump_file, "\n");
1711 if (!t->record_access_p (op))
1712 return false;
1714 ao_ref r;
1715 ao_ref_init (&r, op);
1716 modref_access_node a = get_access (&r);
1717 if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1718 return false;
1720 if (t->m_summary)
1721 t->record_access (t->m_summary->loads, &r, a);
1722 if (t->m_summary_lto)
1723 t->record_access_lto (t->m_summary_lto->loads, &r, a);
1724 return false;
1727 /* Helper for analyze_stmt. */
1729 bool
1730 modref_access_analysis::analyze_store (gimple *stmt, tree, tree op, void *data)
1732 modref_access_analysis *t = (modref_access_analysis *)data;
1734 if (dump_file)
1736 fprintf (dump_file, " - Analyzing store: ");
1737 print_generic_expr (dump_file, op);
1738 fprintf (dump_file, "\n");
1741 if (!t->record_access_p (op))
1742 return false;
1744 ao_ref r;
1745 ao_ref_init (&r, op);
1746 modref_access_node a = get_access (&r);
1747 if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1748 return false;
1750 if (t->m_summary)
1751 t->record_access (t->m_summary->stores, &r, a);
1752 if (t->m_summary_lto)
1753 t->record_access_lto (t->m_summary_lto->stores, &r, a);
1754 if (t->m_always_executed
1755 && a.useful_for_kill_p ()
1756 && (!cfun->can_throw_non_call_exceptions
1757 || !stmt_could_throw_p (cfun, stmt)))
1759 if (dump_file)
1760 fprintf (dump_file, " - Recording kill\n");
1761 if (t->m_summary)
1762 modref_access_node::insert_kill (t->m_summary->kills, a, false);
1763 if (t->m_summary_lto)
1764 modref_access_node::insert_kill (t->m_summary_lto->kills, a, false);
1766 return false;
1769 /* Analyze statement STMT of function F.
1770 If IPA is true do not merge in side effects of calls. */
1772 void
1773 modref_access_analysis::analyze_stmt (gimple *stmt, bool always_executed)
1775 m_always_executed = always_executed;
1776 /* In general we can not ignore clobbers because they are barriers for code
1777 motion, however after inlining it is safe to do because local optimization
1778 passes do not consider clobbers from other functions.
1779 Similar logic is in ipa-pure-const.cc. */
1780 if ((m_ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1782 if (always_executed && record_access_p (gimple_assign_lhs (stmt)))
1784 ao_ref r;
1785 ao_ref_init (&r, gimple_assign_lhs (stmt));
1786 modref_access_node a = get_access (&r);
1787 if (a.useful_for_kill_p ())
1789 if (dump_file)
1790 fprintf (dump_file, " - Recording kill\n");
1791 if (m_summary)
1792 modref_access_node::insert_kill (m_summary->kills, a, false);
1793 if (m_summary_lto)
1794 modref_access_node::insert_kill (m_summary_lto->kills,
1795 a, false);
1798 return;
1801 /* Analyze all loads and stores in STMT. */
1802 walk_stmt_load_store_ops (stmt, this,
1803 analyze_load, analyze_store);
1805 switch (gimple_code (stmt))
1807 case GIMPLE_ASM:
1808 if (gimple_asm_volatile_p (as_a <gasm *> (stmt))
1809 && !ignore_nondeterminism_p (current_function_decl, 0, NULL))
1810 set_nondeterministic ();
1811 if (cfun->can_throw_non_call_exceptions
1812 && stmt_could_throw_p (cfun, stmt))
1813 set_side_effects ();
1814 /* If the ASM statement does not read nor write memory, there's nothing
1815 to do. Otherwise just give up. */
1816 if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1817 return;
1818 if (dump_file)
1819 fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1820 "which clobbers memory.\n");
1821 record_unknown_load ();
1822 record_unknown_store ();
1823 return;
1824 case GIMPLE_CALL:
1825 if (!m_ipa || gimple_call_internal_p (stmt))
1826 analyze_call (as_a <gcall *> (stmt));
1827 else
1829 attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1831 if (fnspec.known_p ()
1832 && (!fnspec.global_memory_read_p ()
1833 || !fnspec.global_memory_written_p ()))
1835 cgraph_edge *e = cgraph_node::get
1836 (current_function_decl)->get_edge (stmt);
1837 if (e->callee)
1839 fnspec_summaries->get_create (e)->fnspec
1840 = xstrdup (fnspec.get_str ());
1841 if (dump_file)
1842 fprintf (dump_file, " Recorded fnspec %s\n",
1843 fnspec.get_str ());
1847 return;
1848 default:
1849 if (cfun->can_throw_non_call_exceptions
1850 && stmt_could_throw_p (cfun, stmt))
1851 set_side_effects ();
1852 return;
1856 /* Propagate load/stores across recursive calls. */
1858 void
1859 modref_access_analysis::propagate ()
1861 if (m_ipa && m_summary)
1862 return;
1864 bool changed = true;
1865 bool first = true;
1866 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1868 m_always_executed = false;
1869 while (changed && m_summary->useful_p (m_ecf_flags, false))
1871 changed = false;
1872 for (unsigned i = 0; i < m_recursive_calls.length (); i++)
1874 changed |= merge_call_side_effects (m_recursive_calls[i], m_summary,
1875 fnode, !first);
1877 first = false;
1881 /* Analyze function. */
1883 void
1884 modref_access_analysis::analyze ()
1886 m_ecf_flags = flags_from_decl_or_type (current_function_decl);
1887 bool summary_useful = true;
1889 /* Analyze each statement in each basic block of the function. If the
1890 statement cannot be analyzed (for any reason), the entire function cannot
1891 be analyzed by modref. */
1892 basic_block bb;
1893 bitmap always_executed_bbs = find_always_executed_bbs (cfun, true);
1894 FOR_EACH_BB_FN (bb, cfun)
1896 gimple_stmt_iterator si;
1897 bool always_executed = bitmap_bit_p (always_executed_bbs, bb->index);
1899 for (si = gsi_start_nondebug_after_labels_bb (bb);
1900 !gsi_end_p (si); gsi_next_nondebug (&si))
1902 /* NULL memory accesses terminates BB. These accesses are known
1903 to trip undefined behavior. gimple-ssa-isolate-paths turns them
1904 to volatile accesses and adds builtin_trap call which would
1905 confuse us otherwise. */
1906 if (infer_nonnull_range_by_dereference (gsi_stmt (si),
1907 null_pointer_node))
1909 if (dump_file)
1910 fprintf (dump_file, " - NULL memory access; terminating BB\n");
1911 if (flag_non_call_exceptions)
1912 set_side_effects ();
1913 break;
1915 analyze_stmt (gsi_stmt (si), always_executed);
1917 /* Avoid doing useless work. */
1918 if ((!m_summary || !m_summary->useful_p (m_ecf_flags, false))
1919 && (!m_summary_lto
1920 || !m_summary_lto->useful_p (m_ecf_flags, false)))
1922 summary_useful = false;
1923 break;
1925 if (always_executed
1926 && stmt_can_throw_external (cfun, gsi_stmt (si)))
1927 always_executed = false;
1929 if (!summary_useful)
1930 break;
1932 /* In non-IPA mode we need to perform iterative dataflow on recursive calls.
1933 This needs to be done after all other side effects are computed. */
1934 if (summary_useful)
1936 if (!m_ipa)
1937 propagate ();
1938 if (m_summary && !m_summary->side_effects && !finite_function_p ())
1939 m_summary->side_effects = true;
1940 if (m_summary_lto && !m_summary_lto->side_effects
1941 && !finite_function_p ())
1942 m_summary_lto->side_effects = true;
1944 BITMAP_FREE (always_executed_bbs);
1947 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1949 bool
1950 memory_access_to (tree op, tree ssa_name)
1952 tree base = get_base_address (op);
1953 if (!base)
1954 return false;
1955 if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1956 return false;
1957 return TREE_OPERAND (base, 0) == ssa_name;
1960 /* Consider statement val = *arg.
1961 return EAF flags of ARG that can be determined from EAF flags of VAL
1962 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1963 all stores to VAL, i.e. when handling noreturn function. */
1965 static int
1966 deref_flags (int flags, bool ignore_stores)
1968 /* Dereference is also a direct read but dereferenced value does not
1969 yield any other direct use. */
1970 int ret = EAF_NO_DIRECT_CLOBBER | EAF_NO_DIRECT_ESCAPE
1971 | EAF_NOT_RETURNED_DIRECTLY;
1972 /* If argument is unused just account for
1973 the read involved in dereference. */
1974 if (flags & EAF_UNUSED)
1975 ret |= EAF_NO_INDIRECT_READ | EAF_NO_INDIRECT_CLOBBER
1976 | EAF_NO_INDIRECT_ESCAPE;
1977 else
1979 /* Direct or indirect accesses leads to indirect accesses. */
1980 if (((flags & EAF_NO_DIRECT_CLOBBER)
1981 && (flags & EAF_NO_INDIRECT_CLOBBER))
1982 || ignore_stores)
1983 ret |= EAF_NO_INDIRECT_CLOBBER;
1984 if (((flags & EAF_NO_DIRECT_ESCAPE)
1985 && (flags & EAF_NO_INDIRECT_ESCAPE))
1986 || ignore_stores)
1987 ret |= EAF_NO_INDIRECT_ESCAPE;
1988 if ((flags & EAF_NO_DIRECT_READ)
1989 && (flags & EAF_NO_INDIRECT_READ))
1990 ret |= EAF_NO_INDIRECT_READ;
1991 if ((flags & EAF_NOT_RETURNED_DIRECTLY)
1992 && (flags & EAF_NOT_RETURNED_INDIRECTLY))
1993 ret |= EAF_NOT_RETURNED_INDIRECTLY;
1995 return ret;
1999 /* Description of an escape point: a call which affects flags of a given
2000 SSA name. */
2002 struct escape_point
2004 /* Value escapes to this call. */
2005 gcall *call;
2006 /* Argument it escapes to. */
2007 unsigned int arg;
2008 /* Flags already known about the argument (this can save us from recording
2009 escape points if local analysis did good job already). */
2010 eaf_flags_t min_flags;
2011 /* Does value escape directly or indirectly? */
2012 bool direct;
2015 /* Lattice used during the eaf flags analysis dataflow. For a given SSA name
2016 we aim to compute its flags and escape points. We also use the lattice
2017 to dynamically build dataflow graph to propagate on. */
2019 class modref_lattice
2021 public:
2022 /* EAF flags of the SSA name. */
2023 eaf_flags_t flags;
2024 /* Used during DFS walk to mark names where final value was determined
2025 without need for dataflow. */
2026 bool known;
2027 /* Used during DFS walk to mark open vertices (for cycle detection). */
2028 bool open;
2029 /* Set during DFS walk for names that needs dataflow propagation. */
2030 bool do_dataflow;
2031 /* Used during the iterative dataflow. */
2032 bool changed;
2034 /* When doing IPA analysis we can not merge in callee escape points;
2035 Only remember them and do the merging at IPA propagation time. */
2036 vec <escape_point, va_heap, vl_ptr> escape_points;
2038 /* Representation of a graph for dataflow. This graph is built on-demand
2039 using modref_eaf_analysis::analyze_ssa and later solved by
2040 modref_eaf_analysis::propagate.
2041 Each edge represents the fact that flags of current lattice should be
2042 propagated to lattice of SSA_NAME. */
2043 struct propagate_edge
2045 int ssa_name;
2046 bool deref;
2048 vec <propagate_edge, va_heap, vl_ptr> propagate_to;
2050 void init ();
2051 void release ();
2052 bool merge (const modref_lattice &with);
2053 bool merge (int flags);
2054 bool merge_deref (const modref_lattice &with, bool ignore_stores);
2055 bool merge_direct_load ();
2056 bool merge_direct_store ();
2057 bool add_escape_point (gcall *call, unsigned int arg,
2058 eaf_flags_t min_flags, bool direct);
2059 void dump (FILE *out, int indent = 0) const;
2062 /* Lattices are saved to vectors, so keep them PODs. */
2063 void
2064 modref_lattice::init ()
2066 /* All flags we track. */
2067 int f = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
2068 | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE
2069 | EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ
2070 | EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY
2071 | EAF_UNUSED;
2072 flags = f;
2073 /* Check that eaf_flags_t is wide enough to hold all flags. */
2074 gcc_checking_assert (f == flags);
2075 open = true;
2076 known = false;
2079 /* Release memory. */
2080 void
2081 modref_lattice::release ()
2083 escape_points.release ();
2084 propagate_to.release ();
2087 /* Dump lattice to OUT; indent with INDENT spaces. */
2089 void
2090 modref_lattice::dump (FILE *out, int indent) const
2092 dump_eaf_flags (out, flags);
2093 if (escape_points.length ())
2095 fprintf (out, "%*sEscapes:\n", indent, "");
2096 for (unsigned int i = 0; i < escape_points.length (); i++)
2098 fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
2099 escape_points[i].arg,
2100 escape_points[i].direct ? "direct" : "indirect");
2101 dump_eaf_flags (out, escape_points[i].min_flags, false);
2102 fprintf (out, " in call ");
2103 print_gimple_stmt (out, escape_points[i].call, 0);
2108 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
2109 point exists. */
2111 bool
2112 modref_lattice::add_escape_point (gcall *call, unsigned arg,
2113 eaf_flags_t min_flags, bool direct)
2115 escape_point *ep;
2116 unsigned int i;
2118 /* If we already determined flags to be bad enough,
2119 we do not need to record. */
2120 if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
2121 return false;
2123 FOR_EACH_VEC_ELT (escape_points, i, ep)
2124 if (ep->call == call && ep->arg == arg && ep->direct == direct)
2126 if ((ep->min_flags & min_flags) == min_flags)
2127 return false;
2128 ep->min_flags &= min_flags;
2129 return true;
2131 /* Give up if max escape points is met. */
2132 if ((int)escape_points.length () > param_modref_max_escape_points)
2134 if (dump_file)
2135 fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
2136 merge (0);
2137 return true;
2139 escape_point new_ep = {call, arg, min_flags, direct};
2140 escape_points.safe_push (new_ep);
2141 return true;
2144 /* Merge in flags from F. */
2145 bool
2146 modref_lattice::merge (int f)
2148 if (f & EAF_UNUSED)
2149 return false;
2150 /* Check that flags seems sane: if function does not read the parameter
2151 it can not access it indirectly. */
2152 gcc_checking_assert (!(f & EAF_NO_DIRECT_READ)
2153 || ((f & EAF_NO_INDIRECT_READ)
2154 && (f & EAF_NO_INDIRECT_CLOBBER)
2155 && (f & EAF_NO_INDIRECT_ESCAPE)
2156 && (f & EAF_NOT_RETURNED_INDIRECTLY)));
2157 if ((flags & f) != flags)
2159 flags &= f;
2160 /* Prune obviously useless flags;
2161 We do not have ECF_FLAGS handy which is not big problem since
2162 we will do final flags cleanup before producing summary.
2163 Merging should be fast so it can work well with dataflow. */
2164 flags = remove_useless_eaf_flags (flags, 0, false);
2165 if (!flags)
2166 escape_points.release ();
2167 return true;
2169 return false;
2172 /* Merge in WITH. Return true if anything changed. */
2174 bool
2175 modref_lattice::merge (const modref_lattice &with)
2177 if (!with.known)
2178 do_dataflow = true;
2180 bool changed = merge (with.flags);
2182 if (!flags)
2183 return changed;
2184 for (unsigned int i = 0; i < with.escape_points.length (); i++)
2185 changed |= add_escape_point (with.escape_points[i].call,
2186 with.escape_points[i].arg,
2187 with.escape_points[i].min_flags,
2188 with.escape_points[i].direct);
2189 return changed;
2192 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
2193 stores. Return true if anything changed. */
2195 bool
2196 modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
2198 if (!with.known)
2199 do_dataflow = true;
2201 bool changed = merge (deref_flags (with.flags, ignore_stores));
2203 if (!flags)
2204 return changed;
2205 for (unsigned int i = 0; i < with.escape_points.length (); i++)
2207 int min_flags = with.escape_points[i].min_flags;
2209 if (with.escape_points[i].direct)
2210 min_flags = deref_flags (min_flags, ignore_stores);
2211 else if (ignore_stores)
2212 min_flags |= ignore_stores_eaf_flags;
2213 changed |= add_escape_point (with.escape_points[i].call,
2214 with.escape_points[i].arg,
2215 min_flags,
2216 false);
2218 return changed;
2221 /* Merge in flags for direct load. */
2223 bool
2224 modref_lattice::merge_direct_load ()
2226 return merge (~(EAF_UNUSED | EAF_NO_DIRECT_READ));
2229 /* Merge in flags for direct store. */
2231 bool
2232 modref_lattice::merge_direct_store ()
2234 return merge (~(EAF_UNUSED | EAF_NO_DIRECT_CLOBBER));
2237 /* Analyzer of EAF flags.
2238 This is generally dataflow problem over the SSA graph, however we only
2239 care about flags of few selected ssa names (arguments, return slot and
2240 static chain). So we first call analyze_ssa_name on all relevant names
2241 and perform a DFS walk to discover SSA names where flags needs to be
2242 determined. For acyclic graphs we try to determine final flags during
2243 this walk. Once cycles or recursion depth is met we enlist SSA names
2244 for dataflow which is done by propagate call.
2246 After propagation the flags can be obtained using get_ssa_name_flags. */
2248 class modref_eaf_analysis
2250 public:
2251 /* Mark NAME as relevant for analysis. */
2252 void analyze_ssa_name (tree name, bool deferred = false);
2253 /* Dataflow solver. */
2254 void propagate ();
2255 /* Return flags computed earlier for NAME. */
2256 int get_ssa_name_flags (tree name)
2258 int version = SSA_NAME_VERSION (name);
2259 gcc_checking_assert (m_lattice[version].known);
2260 return m_lattice[version].flags;
2262 /* In IPA mode this will record all escape points
2263 determined for NAME to PARM_IDNEX. Flags are minimal
2264 flags known. */
2265 void record_escape_points (tree name, int parm_index, int flags);
2266 modref_eaf_analysis (bool ipa)
2268 m_ipa = ipa;
2269 m_depth = 0;
2270 m_lattice.safe_grow_cleared (num_ssa_names, true);
2272 ~modref_eaf_analysis ()
2274 gcc_checking_assert (!m_depth);
2275 if (m_ipa || m_names_to_propagate.length ())
2276 for (unsigned int i = 0; i < num_ssa_names; i++)
2277 m_lattice[i].release ();
2279 private:
2280 /* If true, we produce analysis for IPA mode. In this case escape points are
2281 collected. */
2282 bool m_ipa;
2283 /* Depth of recursion of analyze_ssa_name. */
2284 int m_depth;
2285 /* Propagation lattice for individual ssa names. */
2286 auto_vec<modref_lattice> m_lattice;
2287 auto_vec<tree> m_deferred_names;
2288 auto_vec<int> m_names_to_propagate;
2290 void merge_with_ssa_name (tree dest, tree src, bool deref);
2291 void merge_call_lhs_flags (gcall *call, int arg, tree name, bool direct,
2292 bool deref);
2296 /* Call statements may return their parameters. Consider argument number
2297 ARG of USE_STMT and determine flags that can needs to be cleared
2298 in case pointer possibly indirectly references from ARG I is returned.
2299 If DIRECT is true consider direct returns and if INDIRECT consider
2300 indirect returns.
2301 LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
2302 ARG is set to -1 for static chain. */
2304 void
2305 modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg,
2306 tree name, bool direct,
2307 bool indirect)
2309 int index = SSA_NAME_VERSION (name);
2310 bool returned_directly = false;
2312 /* If there is no return value, no flags are affected. */
2313 if (!gimple_call_lhs (call))
2314 return;
2316 /* If we know that function returns given argument and it is not ARG
2317 we can still be happy. */
2318 if (arg >= 0)
2320 int flags = gimple_call_return_flags (call);
2321 if (flags & ERF_RETURNS_ARG)
2323 if ((flags & ERF_RETURN_ARG_MASK) == arg)
2324 returned_directly = true;
2325 else
2326 return;
2329 /* Make ERF_RETURNS_ARG overwrite EAF_UNUSED. */
2330 if (returned_directly)
2332 direct = true;
2333 indirect = false;
2335 /* If value is not returned at all, do nothing. */
2336 else if (!direct && !indirect)
2337 return;
2339 /* If return value is SSA name determine its flags. */
2340 if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
2342 tree lhs = gimple_call_lhs (call);
2343 if (direct)
2344 merge_with_ssa_name (name, lhs, false);
2345 if (indirect)
2346 merge_with_ssa_name (name, lhs, true);
2348 /* In the case of memory store we can do nothing. */
2349 else if (!direct)
2350 m_lattice[index].merge (deref_flags (0, false));
2351 else
2352 m_lattice[index].merge (0);
2355 /* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
2356 into flags for caller, update LATTICE of corresponding
2357 argument if needed. */
2359 static int
2360 callee_to_caller_flags (int call_flags, bool ignore_stores,
2361 modref_lattice &lattice)
2363 /* call_flags is about callee returning a value
2364 that is not the same as caller returning it. */
2365 call_flags |= EAF_NOT_RETURNED_DIRECTLY
2366 | EAF_NOT_RETURNED_INDIRECTLY;
2367 if (!ignore_stores && !(call_flags & EAF_UNUSED))
2369 /* If value escapes we are no longer able to track what happens
2370 with it because we can read it from the escaped location
2371 anytime. */
2372 if (!(call_flags & EAF_NO_DIRECT_ESCAPE))
2373 lattice.merge (0);
2374 else if (!(call_flags & EAF_NO_INDIRECT_ESCAPE))
2375 lattice.merge (~(EAF_NOT_RETURNED_INDIRECTLY
2376 | EAF_NO_DIRECT_READ
2377 | EAF_NO_INDIRECT_READ
2378 | EAF_NO_INDIRECT_CLOBBER
2379 | EAF_UNUSED));
2381 else
2382 call_flags |= ignore_stores_eaf_flags;
2383 return call_flags;
2386 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
2387 LATTICE is an array of modref_lattices.
2388 DEPTH is a recursion depth used to make debug output prettier.
2389 If IPA is true we analyze for IPA propagation (and thus call escape points
2390 are processed later) */
2392 void
2393 modref_eaf_analysis::analyze_ssa_name (tree name, bool deferred)
2395 imm_use_iterator ui;
2396 gimple *use_stmt;
2397 int index = SSA_NAME_VERSION (name);
2399 if (!deferred)
2401 /* See if value is already computed. */
2402 if (m_lattice[index].known || m_lattice[index].do_dataflow)
2403 return;
2404 if (m_lattice[index].open)
2406 if (dump_file)
2407 fprintf (dump_file,
2408 "%*sCycle in SSA graph\n",
2409 m_depth * 4, "");
2410 return;
2412 /* Recursion guard. */
2413 m_lattice[index].init ();
2414 if (m_depth == param_modref_max_depth)
2416 if (dump_file)
2417 fprintf (dump_file,
2418 "%*sMax recursion depth reached; postponing\n",
2419 m_depth * 4, "");
2420 m_deferred_names.safe_push (name);
2421 return;
2425 if (dump_file)
2427 fprintf (dump_file,
2428 "%*sAnalyzing flags of ssa name: ", m_depth * 4, "");
2429 print_generic_expr (dump_file, name);
2430 fprintf (dump_file, "\n");
2433 FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
2435 if (m_lattice[index].flags == 0)
2436 break;
2437 if (is_gimple_debug (use_stmt))
2438 continue;
2439 if (dump_file)
2441 fprintf (dump_file, "%*s Analyzing stmt: ", m_depth * 4, "");
2442 print_gimple_stmt (dump_file, use_stmt, 0);
2444 /* If we see a direct non-debug use, clear unused bit.
2445 All dereferences should be accounted below using deref_flags. */
2446 m_lattice[index].merge (~EAF_UNUSED);
2448 /* Gimple return may load the return value.
2449 Returning name counts as an use by tree-ssa-structalias.cc */
2450 if (greturn *ret = dyn_cast <greturn *> (use_stmt))
2452 /* Returning through return slot is seen as memory write earlier. */
2453 if (DECL_RESULT (current_function_decl)
2454 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2456 else if (gimple_return_retval (ret) == name)
2457 m_lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED_DIRECTLY
2458 | EAF_NOT_RETURNED_DIRECTLY));
2459 else if (memory_access_to (gimple_return_retval (ret), name))
2461 m_lattice[index].merge_direct_load ();
2462 m_lattice[index].merge (~(EAF_UNUSED
2463 | EAF_NOT_RETURNED_INDIRECTLY));
2466 /* Account for LHS store, arg loads and flags from callee function. */
2467 else if (gcall *call = dyn_cast <gcall *> (use_stmt))
2469 tree callee = gimple_call_fndecl (call);
2471 /* IPA PTA internally it treats calling a function as "writing" to
2472 the argument space of all functions the function pointer points to
2473 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
2474 is on since that would allow propagation of this from -fno-ipa-pta
2475 to -fipa-pta functions. */
2476 if (gimple_call_fn (use_stmt) == name)
2477 m_lattice[index].merge (~(EAF_NO_DIRECT_CLOBBER | EAF_UNUSED));
2479 /* Recursion would require bit of propagation; give up for now. */
2480 if (callee && !m_ipa && recursive_call_p (current_function_decl,
2481 callee))
2482 m_lattice[index].merge (0);
2483 else
2485 int ecf_flags = gimple_call_flags (call);
2486 bool ignore_stores = ignore_stores_p (current_function_decl,
2487 ecf_flags);
2488 bool ignore_retval = ignore_retval_p (current_function_decl,
2489 ecf_flags);
2491 /* Handle *name = func (...). */
2492 if (gimple_call_lhs (call)
2493 && memory_access_to (gimple_call_lhs (call), name))
2495 m_lattice[index].merge_direct_store ();
2496 /* Return slot optimization passes address of
2497 LHS to callee via hidden parameter and this
2498 may make LHS to escape. See PR 98499. */
2499 if (gimple_call_return_slot_opt_p (call)
2500 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
2502 int call_flags = gimple_call_retslot_flags (call);
2503 bool isretslot = false;
2505 if (DECL_RESULT (current_function_decl)
2506 && DECL_BY_REFERENCE
2507 (DECL_RESULT (current_function_decl)))
2508 isretslot = ssa_default_def
2509 (cfun,
2510 DECL_RESULT (current_function_decl))
2511 == name;
2513 /* Passing returnslot to return slot is special because
2514 not_returned and escape has same meaning.
2515 However passing arg to return slot is different. If
2516 the callee's return slot is returned it means that
2517 arg is written to itself which is an escape.
2518 Since we do not track the memory it is written to we
2519 need to give up on analyzing it. */
2520 if (!isretslot)
2522 if (!(call_flags & (EAF_NOT_RETURNED_DIRECTLY
2523 | EAF_UNUSED)))
2524 m_lattice[index].merge (0);
2525 else gcc_checking_assert
2526 (call_flags & (EAF_NOT_RETURNED_INDIRECTLY
2527 | EAF_UNUSED));
2528 call_flags = callee_to_caller_flags
2529 (call_flags, false,
2530 m_lattice[index]);
2532 m_lattice[index].merge (call_flags);
2536 if (gimple_call_chain (call)
2537 && (gimple_call_chain (call) == name))
2539 int call_flags = gimple_call_static_chain_flags (call);
2540 if (!ignore_retval && !(call_flags & EAF_UNUSED))
2541 merge_call_lhs_flags
2542 (call, -1, name,
2543 !(call_flags & EAF_NOT_RETURNED_DIRECTLY),
2544 !(call_flags & EAF_NOT_RETURNED_INDIRECTLY));
2545 call_flags = callee_to_caller_flags
2546 (call_flags, ignore_stores,
2547 m_lattice[index]);
2548 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2549 m_lattice[index].merge (call_flags);
2552 /* Process internal functions and right away. */
2553 bool record_ipa = m_ipa && !gimple_call_internal_p (call);
2555 /* Handle all function parameters. */
2556 for (unsigned i = 0;
2557 i < gimple_call_num_args (call)
2558 && m_lattice[index].flags; i++)
2559 /* Name is directly passed to the callee. */
2560 if (gimple_call_arg (call, i) == name)
2562 int call_flags = gimple_call_arg_flags (call, i);
2563 if (!ignore_retval)
2564 merge_call_lhs_flags
2565 (call, i, name,
2566 !(call_flags & (EAF_NOT_RETURNED_DIRECTLY
2567 | EAF_UNUSED)),
2568 !(call_flags & (EAF_NOT_RETURNED_INDIRECTLY
2569 | EAF_UNUSED)));
2570 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2572 call_flags = callee_to_caller_flags
2573 (call_flags, ignore_stores,
2574 m_lattice[index]);
2575 if (!record_ipa)
2576 m_lattice[index].merge (call_flags);
2577 else
2578 m_lattice[index].add_escape_point (call, i,
2579 call_flags, true);
2582 /* Name is dereferenced and passed to a callee. */
2583 else if (memory_access_to (gimple_call_arg (call, i), name))
2585 int call_flags = deref_flags
2586 (gimple_call_arg_flags (call, i), ignore_stores);
2587 if (!ignore_retval && !(call_flags & EAF_UNUSED)
2588 && (call_flags & (EAF_NOT_RETURNED_DIRECTLY
2589 | EAF_NOT_RETURNED_INDIRECTLY))
2590 != (EAF_NOT_RETURNED_DIRECTLY
2591 | EAF_NOT_RETURNED_INDIRECTLY))
2592 merge_call_lhs_flags (call, i, name, false, true);
2593 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
2594 m_lattice[index].merge_direct_load ();
2595 else
2597 call_flags = callee_to_caller_flags
2598 (call_flags, ignore_stores,
2599 m_lattice[index]);
2600 if (!record_ipa)
2601 m_lattice[index].merge (call_flags);
2602 else
2603 m_lattice[index].add_escape_point (call, i,
2604 call_flags, false);
2609 else if (gimple_assign_load_p (use_stmt))
2611 gassign *assign = as_a <gassign *> (use_stmt);
2612 /* Memory to memory copy. */
2613 if (gimple_store_p (assign))
2615 /* Handle *lhs = *name.
2617 We do not track memory locations, so assume that value
2618 is used arbitrarily. */
2619 if (memory_access_to (gimple_assign_rhs1 (assign), name))
2620 m_lattice[index].merge (deref_flags (0, false));
2622 /* Handle *name = *exp. */
2623 if (memory_access_to (gimple_assign_lhs (assign), name))
2624 m_lattice[index].merge_direct_store ();
2626 /* Handle lhs = *name. */
2627 else if (memory_access_to (gimple_assign_rhs1 (assign), name))
2629 tree lhs = gimple_assign_lhs (assign);
2630 merge_with_ssa_name (name, lhs, true);
2633 else if (gimple_store_p (use_stmt))
2635 gassign *assign = dyn_cast <gassign *> (use_stmt);
2637 /* Handle *lhs = name. */
2638 if (assign && gimple_assign_rhs1 (assign) == name)
2640 if (dump_file)
2641 fprintf (dump_file, "%*s ssa name saved to memory\n",
2642 m_depth * 4, "");
2643 m_lattice[index].merge (0);
2645 /* Handle *name = exp. */
2646 else if (assign
2647 && memory_access_to (gimple_assign_lhs (assign), name))
2649 /* In general we can not ignore clobbers because they are
2650 barriers for code motion, however after inlining it is safe to
2651 do because local optimization passes do not consider clobbers
2652 from other functions.
2653 Similar logic is in ipa-pure-const.cc. */
2654 if (!cfun->after_inlining || !gimple_clobber_p (assign))
2655 m_lattice[index].merge_direct_store ();
2657 /* ASM statements etc. */
2658 else if (!assign)
2660 if (dump_file)
2661 fprintf (dump_file, "%*s Unhandled store\n", m_depth * 4, "");
2662 m_lattice[index].merge (0);
2665 else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
2667 enum tree_code code = gimple_assign_rhs_code (assign);
2669 /* See if operation is a merge as considered by
2670 tree-ssa-structalias.cc:find_func_aliases. */
2671 if (!truth_value_p (code)
2672 && code != POINTER_DIFF_EXPR
2673 && (code != POINTER_PLUS_EXPR
2674 || gimple_assign_rhs1 (assign) == name))
2676 tree lhs = gimple_assign_lhs (assign);
2677 merge_with_ssa_name (name, lhs, false);
2680 else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
2682 tree result = gimple_phi_result (phi);
2683 merge_with_ssa_name (name, result, false);
2685 /* Conditions are not considered escape points
2686 by tree-ssa-structalias. */
2687 else if (gimple_code (use_stmt) == GIMPLE_COND)
2689 else
2691 if (dump_file)
2692 fprintf (dump_file, "%*s Unhandled stmt\n", m_depth * 4, "");
2693 m_lattice[index].merge (0);
2696 if (dump_file)
2698 fprintf (dump_file, "%*s current flags of ", m_depth * 4, "");
2699 print_generic_expr (dump_file, name);
2700 m_lattice[index].dump (dump_file, m_depth * 4 + 4);
2703 if (dump_file)
2705 fprintf (dump_file, "%*sflags of ssa name ", m_depth * 4, "");
2706 print_generic_expr (dump_file, name);
2707 m_lattice[index].dump (dump_file, m_depth * 4 + 2);
2709 m_lattice[index].open = false;
2710 if (!m_lattice[index].do_dataflow)
2711 m_lattice[index].known = true;
2714 /* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
2715 is dereferenced. */
2717 void
2718 modref_eaf_analysis::merge_with_ssa_name (tree dest, tree src, bool deref)
2720 int index = SSA_NAME_VERSION (dest);
2721 int src_index = SSA_NAME_VERSION (src);
2723 /* Merging lattice with itself is a no-op. */
2724 if (!deref && src == dest)
2725 return;
2727 m_depth++;
2728 analyze_ssa_name (src);
2729 m_depth--;
2730 if (deref)
2731 m_lattice[index].merge_deref (m_lattice[src_index], false);
2732 else
2733 m_lattice[index].merge (m_lattice[src_index]);
2735 /* If we failed to produce final solution add an edge to the dataflow
2736 graph. */
2737 if (!m_lattice[src_index].known)
2739 modref_lattice::propagate_edge e = {index, deref};
2741 if (!m_lattice[src_index].propagate_to.length ())
2742 m_names_to_propagate.safe_push (src_index);
2743 m_lattice[src_index].propagate_to.safe_push (e);
2744 m_lattice[src_index].changed = true;
2745 m_lattice[src_index].do_dataflow = true;
2746 if (dump_file)
2747 fprintf (dump_file,
2748 "%*sWill propgate from ssa_name %i to %i%s\n",
2749 m_depth * 4 + 4,
2750 "", src_index, index, deref ? " (deref)" : "");
2754 /* In the case we deferred some SSA names, reprocess them. In the case some
2755 dataflow edges were introduced, do the actual iterative dataflow. */
2757 void
2758 modref_eaf_analysis::propagate ()
2760 int iterations = 0;
2761 size_t i;
2762 int index;
2763 bool changed = true;
2765 while (m_deferred_names.length ())
2767 tree name = m_deferred_names.pop ();
2768 if (dump_file)
2769 fprintf (dump_file, "Analyzing deferred SSA name\n");
2770 analyze_ssa_name (name, true);
2773 if (!m_names_to_propagate.length ())
2774 return;
2775 if (dump_file)
2776 fprintf (dump_file, "Propagating EAF flags\n");
2778 /* Compute reverse postorder. */
2779 auto_vec <int> rpo;
2780 struct stack_entry
2782 int name;
2783 unsigned pos;
2785 auto_vec <struct stack_entry> stack;
2786 int pos = m_names_to_propagate.length () - 1;
2788 rpo.safe_grow (m_names_to_propagate.length (), true);
2789 stack.reserve_exact (m_names_to_propagate.length ());
2791 /* We reuse known flag for RPO DFS walk bookkeeping. */
2792 if (flag_checking)
2793 FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2794 gcc_assert (!m_lattice[index].known && m_lattice[index].changed);
2796 FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2798 if (!m_lattice[index].known)
2800 stack_entry e = {index, 0};
2802 stack.quick_push (e);
2803 m_lattice[index].known = true;
2805 while (stack.length ())
2807 bool found = false;
2808 int index1 = stack.last ().name;
2810 while (stack.last ().pos < m_lattice[index1].propagate_to.length ())
2812 int index2 = m_lattice[index1]
2813 .propagate_to[stack.last ().pos].ssa_name;
2815 stack.last ().pos++;
2816 if (!m_lattice[index2].known
2817 && m_lattice[index2].propagate_to.length ())
2819 stack_entry e = {index2, 0};
2821 stack.quick_push (e);
2822 m_lattice[index2].known = true;
2823 found = true;
2824 break;
2827 if (!found
2828 && stack.last ().pos == m_lattice[index1].propagate_to.length ())
2830 rpo[pos--] = index1;
2831 stack.pop ();
2836 /* Perform iterative dataflow. */
2837 while (changed)
2839 changed = false;
2840 iterations++;
2841 if (dump_file)
2842 fprintf (dump_file, " iteration %i\n", iterations);
2843 FOR_EACH_VEC_ELT (rpo, i, index)
2845 if (m_lattice[index].changed)
2847 size_t j;
2849 m_lattice[index].changed = false;
2850 if (dump_file)
2851 fprintf (dump_file, " Visiting ssa name %i\n", index);
2852 for (j = 0; j < m_lattice[index].propagate_to.length (); j++)
2854 bool ch;
2855 int target = m_lattice[index].propagate_to[j].ssa_name;
2856 bool deref = m_lattice[index].propagate_to[j].deref;
2858 if (dump_file)
2859 fprintf (dump_file, " Propagating flags of ssa name"
2860 " %i to %i%s\n",
2861 index, target, deref ? " (deref)" : "");
2862 m_lattice[target].known = true;
2863 if (!m_lattice[index].propagate_to[j].deref)
2864 ch = m_lattice[target].merge (m_lattice[index]);
2865 else
2866 ch = m_lattice[target].merge_deref (m_lattice[index],
2867 false);
2868 if (!ch)
2869 continue;
2870 if (dump_file)
2872 fprintf (dump_file, " New lattice: ");
2873 m_lattice[target].dump (dump_file);
2875 changed = true;
2876 m_lattice[target].changed = true;
2881 if (dump_file)
2882 fprintf (dump_file, "EAF flags propagated in %i iterations\n", iterations);
2885 /* Record escape points of PARM_INDEX according to LATTICE. */
2887 void
2888 modref_eaf_analysis::record_escape_points (tree name, int parm_index, int flags)
2890 modref_lattice &lattice = m_lattice[SSA_NAME_VERSION (name)];
2892 if (lattice.escape_points.length ())
2894 escape_point *ep;
2895 unsigned int ip;
2896 cgraph_node *node = cgraph_node::get (current_function_decl);
2898 gcc_assert (m_ipa);
2899 FOR_EACH_VEC_ELT (lattice.escape_points, ip, ep)
2900 if ((ep->min_flags & flags) != flags)
2902 cgraph_edge *e = node->get_edge (ep->call);
2903 struct escape_entry ee = {parm_index, ep->arg,
2904 ep->min_flags, ep->direct};
2906 escape_summaries->get_create (e)->esc.safe_push (ee);
2911 /* Determine EAF flags for function parameters
2912 and fill in SUMMARY/SUMMARY_LTO. If IPA is true work in IPA mode
2913 where we also collect escape points.
2914 PAST_FLAGS, PAST_RETSLOT_FLAGS, PAST_STATIC_CHAIN_FLAGS can be
2915 used to preserve flags from previous (IPA) run for cases where
2916 late optimizations changed code in a way we can no longer analyze
2917 it easily. */
2919 static void
2920 analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
2921 bool ipa, vec<eaf_flags_t> &past_flags,
2922 int past_retslot_flags, int past_static_chain_flags)
2924 unsigned int parm_index = 0;
2925 unsigned int count = 0;
2926 int ecf_flags = flags_from_decl_or_type (current_function_decl);
2927 tree retslot = NULL;
2928 tree static_chain = NULL;
2930 /* If there is return slot, look up its SSA name. */
2931 if (DECL_RESULT (current_function_decl)
2932 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2933 retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
2934 if (cfun->static_chain_decl)
2935 static_chain = ssa_default_def (cfun, cfun->static_chain_decl);
2937 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2938 parm = TREE_CHAIN (parm))
2939 count++;
2941 if (!count && !retslot && !static_chain)
2942 return;
2944 modref_eaf_analysis eaf_analysis (ipa);
2946 /* Determine all SSA names we need to know flags for. */
2947 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2948 parm = TREE_CHAIN (parm))
2950 tree name = ssa_default_def (cfun, parm);
2951 if (name)
2952 eaf_analysis.analyze_ssa_name (name);
2954 if (retslot)
2955 eaf_analysis.analyze_ssa_name (retslot);
2956 if (static_chain)
2957 eaf_analysis.analyze_ssa_name (static_chain);
2959 /* Do the dataflow. */
2960 eaf_analysis.propagate ();
2962 tree attr = lookup_attribute ("fn spec",
2963 TYPE_ATTRIBUTES
2964 (TREE_TYPE (current_function_decl)));
2965 attr_fnspec fnspec (attr
2966 ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)))
2967 : "");
2970 /* Store results to summaries. */
2971 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
2972 parm = TREE_CHAIN (parm))
2974 tree name = ssa_default_def (cfun, parm);
2975 if (!name || has_zero_uses (name))
2977 /* We do not track non-SSA parameters,
2978 but we want to track unused gimple_regs. */
2979 if (!is_gimple_reg (parm))
2980 continue;
2981 if (summary)
2983 if (parm_index >= summary->arg_flags.length ())
2984 summary->arg_flags.safe_grow_cleared (count, true);
2985 summary->arg_flags[parm_index] = EAF_UNUSED;
2987 if (summary_lto)
2989 if (parm_index >= summary_lto->arg_flags.length ())
2990 summary_lto->arg_flags.safe_grow_cleared (count, true);
2991 summary_lto->arg_flags[parm_index] = EAF_UNUSED;
2993 continue;
2995 int flags = eaf_analysis.get_ssa_name_flags (name);
2996 int attr_flags = fnspec.arg_eaf_flags (parm_index);
2998 if (dump_file && (flags | attr_flags) != flags && !(flags & EAF_UNUSED))
3000 fprintf (dump_file,
3001 " Flags for param %i combined with fnspec flags:",
3002 (int)parm_index);
3003 dump_eaf_flags (dump_file, attr_flags, false);
3004 fprintf (dump_file, " determined: ");
3005 dump_eaf_flags (dump_file, flags, true);
3007 flags |= attr_flags;
3009 /* Eliminate useless flags so we do not end up storing unnecessary
3010 summaries. */
3012 flags = remove_useless_eaf_flags
3013 (flags, ecf_flags,
3014 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3015 if (past_flags.length () > parm_index)
3017 int past = past_flags[parm_index];
3018 past = remove_useless_eaf_flags
3019 (past, ecf_flags,
3020 VOID_TYPE_P (TREE_TYPE
3021 (TREE_TYPE (current_function_decl))));
3022 /* Store merging can produce reads when combining together multiple
3023 bitfields. See PR111613. */
3024 past &= ~(EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ);
3025 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
3027 fprintf (dump_file,
3028 " Flags for param %i combined with IPA pass:",
3029 (int)parm_index);
3030 dump_eaf_flags (dump_file, past, false);
3031 fprintf (dump_file, " determined: ");
3032 dump_eaf_flags (dump_file, flags, true);
3034 if (!(flags & EAF_UNUSED))
3035 flags |= past;
3038 if (flags)
3040 if (summary)
3042 if (parm_index >= summary->arg_flags.length ())
3043 summary->arg_flags.safe_grow_cleared (count, true);
3044 summary->arg_flags[parm_index] = flags;
3046 if (summary_lto)
3048 if (parm_index >= summary_lto->arg_flags.length ())
3049 summary_lto->arg_flags.safe_grow_cleared (count, true);
3050 summary_lto->arg_flags[parm_index] = flags;
3052 eaf_analysis.record_escape_points (name, parm_index, flags);
3055 if (retslot)
3057 int flags = eaf_analysis.get_ssa_name_flags (retslot);
3058 int past = past_retslot_flags;
3060 flags = remove_useless_eaf_flags (flags, ecf_flags, false);
3061 past = remove_useless_eaf_flags
3062 (past, ecf_flags,
3063 VOID_TYPE_P (TREE_TYPE
3064 (TREE_TYPE (current_function_decl))));
3065 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
3067 fprintf (dump_file,
3068 " Retslot flags combined with IPA pass:");
3069 dump_eaf_flags (dump_file, past, false);
3070 fprintf (dump_file, " determined: ");
3071 dump_eaf_flags (dump_file, flags, true);
3073 if (!(flags & EAF_UNUSED))
3074 flags |= past;
3075 if (flags)
3077 if (summary)
3078 summary->retslot_flags = flags;
3079 if (summary_lto)
3080 summary_lto->retslot_flags = flags;
3081 eaf_analysis.record_escape_points (retslot,
3082 MODREF_RETSLOT_PARM, flags);
3085 if (static_chain)
3087 int flags = eaf_analysis.get_ssa_name_flags (static_chain);
3088 int past = past_static_chain_flags;
3090 flags = remove_useless_eaf_flags (flags, ecf_flags, false);
3091 past = remove_useless_eaf_flags
3092 (past, ecf_flags,
3093 VOID_TYPE_P (TREE_TYPE
3094 (TREE_TYPE (current_function_decl))));
3095 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
3097 fprintf (dump_file,
3098 " Static chain flags combined with IPA pass:");
3099 dump_eaf_flags (dump_file, past, false);
3100 fprintf (dump_file, " determined: ");
3101 dump_eaf_flags (dump_file, flags, true);
3103 if (!(flags & EAF_UNUSED))
3104 flags |= past;
3105 if (flags)
3107 if (summary)
3108 summary->static_chain_flags = flags;
3109 if (summary_lto)
3110 summary_lto->static_chain_flags = flags;
3111 eaf_analysis.record_escape_points (static_chain,
3112 MODREF_STATIC_CHAIN_PARM,
3113 flags);
3118 /* Analyze function. IPA indicates whether we're running in local mode
3119 (false) or the IPA mode (true).
3120 Return true if fixup cfg is needed after the pass. */
3122 static bool
3123 analyze_function (bool ipa)
3125 bool fixup_cfg = false;
3126 if (dump_file)
3127 fprintf (dump_file, "\n\nmodref analyzing '%s' (ipa=%i)%s%s\n",
3128 cgraph_node::get (current_function_decl)->dump_name (), ipa,
3129 TREE_READONLY (current_function_decl) ? " (const)" : "",
3130 DECL_PURE_P (current_function_decl) ? " (pure)" : "");
3132 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
3133 if (!flag_ipa_modref
3134 || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
3135 return false;
3137 /* Compute no-LTO summaries when local optimization is going to happen. */
3138 bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
3139 || (in_lto_p && !flag_wpa
3140 && flag_incremental_link != INCREMENTAL_LINK_LTO));
3141 /* Compute LTO when LTO streaming is going to happen. */
3142 bool lto = ipa && ((flag_lto && !in_lto_p)
3143 || flag_wpa
3144 || flag_incremental_link == INCREMENTAL_LINK_LTO);
3145 cgraph_node *fnode = cgraph_node::get (current_function_decl);
3147 modref_summary *summary = NULL;
3148 modref_summary_lto *summary_lto = NULL;
3150 bool past_flags_known = false;
3151 auto_vec <eaf_flags_t> past_flags;
3152 int past_retslot_flags = 0;
3153 int past_static_chain_flags = 0;
3155 /* Initialize the summary.
3156 If we run in local mode there is possibly pre-existing summary from
3157 IPA pass. Dump it so it is easy to compare if mod-ref info has
3158 improved. */
3159 if (!ipa)
3161 if (!optimization_summaries)
3162 optimization_summaries = modref_summaries::create_ggc (symtab);
3163 else /* Remove existing summary if we are re-running the pass. */
3165 summary = optimization_summaries->get (fnode);
3166 if (summary != NULL
3167 && summary->loads)
3169 if (dump_file)
3171 fprintf (dump_file, "Past summary:\n");
3172 optimization_summaries->get (fnode)->dump (dump_file);
3174 past_flags.reserve_exact (summary->arg_flags.length ());
3175 past_flags.splice (summary->arg_flags);
3176 past_retslot_flags = summary->retslot_flags;
3177 past_static_chain_flags = summary->static_chain_flags;
3178 past_flags_known = true;
3180 optimization_summaries->remove (fnode);
3182 summary = optimization_summaries->get_create (fnode);
3183 gcc_checking_assert (nolto && !lto);
3185 /* In IPA mode we analyze every function precisely once. Assert that. */
3186 else
3188 if (nolto)
3190 if (!summaries)
3191 summaries = modref_summaries::create_ggc (symtab);
3192 else
3193 summaries->remove (fnode);
3194 summary = summaries->get_create (fnode);
3196 if (lto)
3198 if (!summaries_lto)
3199 summaries_lto = modref_summaries_lto::create_ggc (symtab);
3200 else
3201 summaries_lto->remove (fnode);
3202 summary_lto = summaries_lto->get_create (fnode);
3204 if (!fnspec_summaries)
3205 fnspec_summaries = new fnspec_summaries_t (symtab);
3206 if (!escape_summaries)
3207 escape_summaries = new escape_summaries_t (symtab);
3211 /* Create and initialize summary for F.
3212 Note that summaries may be already allocated from previous
3213 run of the pass. */
3214 if (nolto)
3216 gcc_assert (!summary->loads);
3217 summary->loads = modref_records::create_ggc ();
3218 gcc_assert (!summary->stores);
3219 summary->stores = modref_records::create_ggc ();
3220 summary->writes_errno = false;
3221 summary->side_effects = false;
3222 summary->nondeterministic = false;
3223 summary->calls_interposable = false;
3225 if (lto)
3227 gcc_assert (!summary_lto->loads);
3228 summary_lto->loads = modref_records_lto::create_ggc ();
3229 gcc_assert (!summary_lto->stores);
3230 summary_lto->stores = modref_records_lto::create_ggc ();
3231 summary_lto->writes_errno = false;
3232 summary_lto->side_effects = false;
3233 summary_lto->nondeterministic = false;
3234 summary_lto->calls_interposable = false;
3237 analyze_parms (summary, summary_lto, ipa,
3238 past_flags, past_retslot_flags, past_static_chain_flags);
3241 modref_access_analysis analyzer (ipa, summary, summary_lto);
3242 analyzer.analyze ();
3245 if (!ipa && flag_ipa_pure_const)
3247 if (!summary->stores->every_base && !summary->stores->bases
3248 && !summary->nondeterministic)
3250 if (!summary->loads->every_base && !summary->loads->bases
3251 && !summary->calls_interposable)
3252 fixup_cfg = ipa_make_function_const (fnode,
3253 summary->side_effects, true);
3254 else
3255 fixup_cfg = ipa_make_function_pure (fnode,
3256 summary->side_effects, true);
3259 int ecf_flags = flags_from_decl_or_type (current_function_decl);
3260 if (summary && !summary->useful_p (ecf_flags))
3262 if (!ipa)
3263 optimization_summaries->remove (fnode);
3264 else
3265 summaries->remove (fnode);
3266 summary = NULL;
3268 if (summary)
3269 summary->finalize (current_function_decl);
3270 if (summary_lto && !summary_lto->useful_p (ecf_flags))
3272 summaries_lto->remove (fnode);
3273 summary_lto = NULL;
3276 if (ipa && !summary && !summary_lto)
3277 remove_modref_edge_summaries (fnode);
3279 if (dump_file)
3281 fprintf (dump_file, " - modref done with result: tracked.\n");
3282 if (summary)
3283 summary->dump (dump_file);
3284 if (summary_lto)
3285 summary_lto->dump (dump_file);
3286 dump_modref_edge_summaries (dump_file, fnode, 2);
3287 /* To simplify debugging, compare IPA and local solutions. */
3288 if (past_flags_known && summary)
3290 size_t len = summary->arg_flags.length ();
3292 if (past_flags.length () > len)
3293 len = past_flags.length ();
3294 for (size_t i = 0; i < len; i++)
3296 int old_flags = i < past_flags.length () ? past_flags[i] : 0;
3297 int new_flags = i < summary->arg_flags.length ()
3298 ? summary->arg_flags[i] : 0;
3299 old_flags = remove_useless_eaf_flags
3300 (old_flags, flags_from_decl_or_type (current_function_decl),
3301 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3302 if (old_flags != new_flags)
3304 if ((old_flags & ~new_flags) == 0
3305 || (new_flags & EAF_UNUSED))
3306 fprintf (dump_file, " Flags for param %i improved:",
3307 (int)i);
3308 else
3309 fprintf (dump_file, " Flags for param %i changed:",
3310 (int)i);
3311 dump_eaf_flags (dump_file, old_flags, false);
3312 fprintf (dump_file, " -> ");
3313 dump_eaf_flags (dump_file, new_flags, true);
3316 past_retslot_flags = remove_useless_eaf_flags
3317 (past_retslot_flags,
3318 flags_from_decl_or_type (current_function_decl),
3319 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3320 if (past_retslot_flags != summary->retslot_flags)
3322 if ((past_retslot_flags & ~summary->retslot_flags) == 0
3323 || (summary->retslot_flags & EAF_UNUSED))
3324 fprintf (dump_file, " Flags for retslot improved:");
3325 else
3326 fprintf (dump_file, " Flags for retslot changed:");
3327 dump_eaf_flags (dump_file, past_retslot_flags, false);
3328 fprintf (dump_file, " -> ");
3329 dump_eaf_flags (dump_file, summary->retslot_flags, true);
3331 past_static_chain_flags = remove_useless_eaf_flags
3332 (past_static_chain_flags,
3333 flags_from_decl_or_type (current_function_decl),
3334 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3335 if (past_static_chain_flags != summary->static_chain_flags)
3337 if ((past_static_chain_flags & ~summary->static_chain_flags) == 0
3338 || (summary->static_chain_flags & EAF_UNUSED))
3339 fprintf (dump_file, " Flags for static chain improved:");
3340 else
3341 fprintf (dump_file, " Flags for static chain changed:");
3342 dump_eaf_flags (dump_file, past_static_chain_flags, false);
3343 fprintf (dump_file, " -> ");
3344 dump_eaf_flags (dump_file, summary->static_chain_flags, true);
3347 else if (past_flags_known && !summary)
3349 for (size_t i = 0; i < past_flags.length (); i++)
3351 int old_flags = past_flags[i];
3352 old_flags = remove_useless_eaf_flags
3353 (old_flags, flags_from_decl_or_type (current_function_decl),
3354 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3355 if (old_flags)
3357 fprintf (dump_file, " Flags for param %i worsened:",
3358 (int)i);
3359 dump_eaf_flags (dump_file, old_flags, false);
3360 fprintf (dump_file, " -> \n");
3363 past_retslot_flags = remove_useless_eaf_flags
3364 (past_retslot_flags,
3365 flags_from_decl_or_type (current_function_decl),
3366 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3367 if (past_retslot_flags)
3369 fprintf (dump_file, " Flags for retslot worsened:");
3370 dump_eaf_flags (dump_file, past_retslot_flags, false);
3371 fprintf (dump_file, " ->\n");
3373 past_static_chain_flags = remove_useless_eaf_flags
3374 (past_static_chain_flags,
3375 flags_from_decl_or_type (current_function_decl),
3376 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3377 if (past_static_chain_flags)
3379 fprintf (dump_file, " Flags for static chain worsened:");
3380 dump_eaf_flags (dump_file, past_static_chain_flags, false);
3381 fprintf (dump_file, " ->\n");
3385 return fixup_cfg;
3388 /* Callback for generate_summary. */
3390 static void
3391 modref_generate (void)
3393 struct cgraph_node *node;
3394 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
3396 function *f = DECL_STRUCT_FUNCTION (node->decl);
3397 if (!f)
3398 continue;
3399 push_cfun (f);
3400 analyze_function (true);
3401 pop_cfun ();
3405 } /* ANON namespace. */
3407 /* Debugging helper. */
3409 void
3410 debug_eaf_flags (int flags)
3412 dump_eaf_flags (stderr, flags, true);
3415 /* Called when a new function is inserted to callgraph late. */
3417 void
3418 modref_summaries::insert (struct cgraph_node *node, modref_summary *)
3420 /* Local passes ought to be executed by the pass manager. */
3421 if (this == optimization_summaries)
3423 optimization_summaries->remove (node);
3424 return;
3426 if (!DECL_STRUCT_FUNCTION (node->decl)
3427 || !opt_for_fn (node->decl, flag_ipa_modref))
3429 summaries->remove (node);
3430 return;
3432 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
3433 analyze_function (true);
3434 pop_cfun ();
3437 /* Called when a new function is inserted to callgraph late. */
3439 void
3440 modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
3442 /* We do not support adding new function when IPA information is already
3443 propagated. This is done only by SIMD cloning that is not very
3444 critical. */
3445 if (!DECL_STRUCT_FUNCTION (node->decl)
3446 || !opt_for_fn (node->decl, flag_ipa_modref)
3447 || propagated)
3449 summaries_lto->remove (node);
3450 return;
3452 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
3453 analyze_function (true);
3454 pop_cfun ();
3457 /* Called when new clone is inserted to callgraph late. */
3459 void
3460 modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
3461 modref_summary *src_data,
3462 modref_summary *dst_data)
3464 /* Do not duplicate optimization summaries; we do not handle parameter
3465 transforms on them. */
3466 if (this == optimization_summaries)
3468 optimization_summaries->remove (dst);
3469 return;
3471 dst_data->stores = modref_records::create_ggc ();
3472 dst_data->stores->copy_from (src_data->stores);
3473 dst_data->loads = modref_records::create_ggc ();
3474 dst_data->loads->copy_from (src_data->loads);
3475 dst_data->kills.reserve_exact (src_data->kills.length ());
3476 dst_data->kills.splice (src_data->kills);
3477 dst_data->writes_errno = src_data->writes_errno;
3478 dst_data->side_effects = src_data->side_effects;
3479 dst_data->nondeterministic = src_data->nondeterministic;
3480 dst_data->calls_interposable = src_data->calls_interposable;
3481 if (src_data->arg_flags.length ())
3482 dst_data->arg_flags = src_data->arg_flags.copy ();
3483 dst_data->retslot_flags = src_data->retslot_flags;
3484 dst_data->static_chain_flags = src_data->static_chain_flags;
3487 /* Called when new clone is inserted to callgraph late. */
3489 void
3490 modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
3491 modref_summary_lto *src_data,
3492 modref_summary_lto *dst_data)
3494 /* Be sure that no further cloning happens after ipa-modref. If it does
3495 we will need to update signatures for possible param changes. */
3496 gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
3497 dst_data->stores = modref_records_lto::create_ggc ();
3498 dst_data->stores->copy_from (src_data->stores);
3499 dst_data->loads = modref_records_lto::create_ggc ();
3500 dst_data->loads->copy_from (src_data->loads);
3501 dst_data->kills.reserve_exact (src_data->kills.length ());
3502 dst_data->kills.splice (src_data->kills);
3503 dst_data->writes_errno = src_data->writes_errno;
3504 dst_data->side_effects = src_data->side_effects;
3505 dst_data->nondeterministic = src_data->nondeterministic;
3506 dst_data->calls_interposable = src_data->calls_interposable;
3507 if (src_data->arg_flags.length ())
3508 dst_data->arg_flags = src_data->arg_flags.copy ();
3509 dst_data->retslot_flags = src_data->retslot_flags;
3510 dst_data->static_chain_flags = src_data->static_chain_flags;
3513 namespace
3515 /* Definition of the modref pass on GIMPLE. */
3516 const pass_data pass_data_modref = {
3517 GIMPLE_PASS,
3518 "modref",
3519 OPTGROUP_IPA,
3520 TV_TREE_MODREF,
3521 (PROP_cfg | PROP_ssa),
3528 class pass_modref : public gimple_opt_pass
3530 public:
3531 pass_modref (gcc::context *ctxt)
3532 : gimple_opt_pass (pass_data_modref, ctxt) {}
3534 /* opt_pass methods: */
3535 opt_pass *clone () final override
3537 return new pass_modref (m_ctxt);
3539 bool gate (function *) final override
3541 return flag_ipa_modref;
3543 unsigned int execute (function *) final override;
3546 /* Encode TT to the output block OB using the summary streaming API. */
3548 static void
3549 write_modref_records (modref_records_lto *tt, struct output_block *ob)
3551 streamer_write_uhwi (ob, tt->every_base);
3552 streamer_write_uhwi (ob, vec_safe_length (tt->bases));
3553 for (auto base_node : tt->bases)
3555 stream_write_tree (ob, base_node->base, true);
3557 streamer_write_uhwi (ob, base_node->every_ref);
3558 streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
3560 for (auto ref_node : base_node->refs)
3562 stream_write_tree (ob, ref_node->ref, true);
3563 streamer_write_uhwi (ob, ref_node->every_access);
3564 streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
3566 for (auto access_node : ref_node->accesses)
3567 access_node.stream_out (ob);
3572 /* Read a modref_tree from the input block IB using the data from DATA_IN.
3573 This assumes that the tree was encoded using write_modref_tree.
3574 Either nolto_ret or lto_ret is initialized by the tree depending whether
3575 LTO streaming is expected or not. */
3577 static void
3578 read_modref_records (tree decl,
3579 lto_input_block *ib, struct data_in *data_in,
3580 modref_records **nolto_ret,
3581 modref_records_lto **lto_ret)
3583 size_t max_bases = opt_for_fn (decl, param_modref_max_bases);
3584 size_t max_refs = opt_for_fn (decl, param_modref_max_refs);
3585 size_t max_accesses = opt_for_fn (decl, param_modref_max_accesses);
3587 if (lto_ret)
3588 *lto_ret = modref_records_lto::create_ggc ();
3589 if (nolto_ret)
3590 *nolto_ret = modref_records::create_ggc ();
3591 gcc_checking_assert (lto_ret || nolto_ret);
3593 size_t every_base = streamer_read_uhwi (ib);
3594 size_t nbase = streamer_read_uhwi (ib);
3596 gcc_assert (!every_base || nbase == 0);
3597 if (every_base)
3599 if (nolto_ret)
3600 (*nolto_ret)->collapse ();
3601 if (lto_ret)
3602 (*lto_ret)->collapse ();
3604 for (size_t i = 0; i < nbase; i++)
3606 tree base_tree = stream_read_tree (ib, data_in);
3607 modref_base_node <alias_set_type> *nolto_base_node = NULL;
3608 modref_base_node <tree> *lto_base_node = NULL;
3610 /* At stream in time we have LTO alias info. Check if we streamed in
3611 something obviously unnecessary. Do not glob types by alias sets;
3612 it is not 100% clear that ltrans types will get merged same way.
3613 Types may get refined based on ODR type conflicts. */
3614 if (base_tree && !get_alias_set (base_tree))
3616 if (dump_file)
3618 fprintf (dump_file, "Streamed in alias set 0 type ");
3619 print_generic_expr (dump_file, base_tree);
3620 fprintf (dump_file, "\n");
3622 base_tree = NULL;
3625 if (nolto_ret)
3626 nolto_base_node = (*nolto_ret)->insert_base (base_tree
3627 ? get_alias_set (base_tree)
3628 : 0, 0, INT_MAX);
3629 if (lto_ret)
3630 lto_base_node = (*lto_ret)->insert_base (base_tree, 0, max_bases);
3631 size_t every_ref = streamer_read_uhwi (ib);
3632 size_t nref = streamer_read_uhwi (ib);
3634 gcc_assert (!every_ref || nref == 0);
3635 if (every_ref)
3637 if (nolto_base_node)
3638 nolto_base_node->collapse ();
3639 if (lto_base_node)
3640 lto_base_node->collapse ();
3642 for (size_t j = 0; j < nref; j++)
3644 tree ref_tree = stream_read_tree (ib, data_in);
3646 if (ref_tree && !get_alias_set (ref_tree))
3648 if (dump_file)
3650 fprintf (dump_file, "Streamed in alias set 0 type ");
3651 print_generic_expr (dump_file, ref_tree);
3652 fprintf (dump_file, "\n");
3654 ref_tree = NULL;
3657 modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
3658 modref_ref_node <tree> *lto_ref_node = NULL;
3660 if (nolto_base_node)
3661 nolto_ref_node
3662 = nolto_base_node->insert_ref (ref_tree
3663 ? get_alias_set (ref_tree) : 0,
3664 max_refs);
3665 if (lto_base_node)
3666 lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
3668 size_t every_access = streamer_read_uhwi (ib);
3669 size_t naccesses = streamer_read_uhwi (ib);
3671 if (nolto_ref_node && every_access)
3672 nolto_ref_node->collapse ();
3673 if (lto_ref_node && every_access)
3674 lto_ref_node->collapse ();
3676 for (size_t k = 0; k < naccesses; k++)
3678 modref_access_node a = modref_access_node::stream_in (ib);
3679 if (nolto_ref_node)
3680 nolto_ref_node->insert_access (a, max_accesses, false);
3681 if (lto_ref_node)
3682 lto_ref_node->insert_access (a, max_accesses, false);
3686 if (lto_ret)
3687 (*lto_ret)->cleanup ();
3688 if (nolto_ret)
3689 (*nolto_ret)->cleanup ();
3692 /* Write ESUM to BP. */
3694 static void
3695 modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
3697 if (!esum)
3699 bp_pack_var_len_unsigned (bp, 0);
3700 return;
3702 bp_pack_var_len_unsigned (bp, esum->esc.length ());
3703 unsigned int i;
3704 escape_entry *ee;
3705 FOR_EACH_VEC_ELT (esum->esc, i, ee)
3707 bp_pack_var_len_int (bp, ee->parm_index);
3708 bp_pack_var_len_unsigned (bp, ee->arg);
3709 bp_pack_var_len_unsigned (bp, ee->min_flags);
3710 bp_pack_value (bp, ee->direct, 1);
3714 /* Read escape summary for E from BP. */
3716 static void
3717 modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
3719 unsigned int n = bp_unpack_var_len_unsigned (bp);
3720 if (!n)
3721 return;
3722 escape_summary *esum = escape_summaries->get_create (e);
3723 esum->esc.reserve_exact (n);
3724 for (unsigned int i = 0; i < n; i++)
3726 escape_entry ee;
3727 ee.parm_index = bp_unpack_var_len_int (bp);
3728 ee.arg = bp_unpack_var_len_unsigned (bp);
3729 ee.min_flags = bp_unpack_var_len_unsigned (bp);
3730 ee.direct = bp_unpack_value (bp, 1);
3731 esum->esc.quick_push (ee);
3735 /* Callback for write_summary. */
3737 static void
3738 modref_write ()
3740 struct output_block *ob = create_output_block (LTO_section_ipa_modref);
3741 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
3742 unsigned int count = 0;
3743 int i;
3745 if (!summaries_lto)
3747 streamer_write_uhwi (ob, 0);
3748 streamer_write_char_stream (ob->main_stream, 0);
3749 produce_asm (ob);
3750 destroy_output_block (ob);
3751 return;
3754 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3756 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3757 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3758 modref_summary_lto *r;
3760 if (cnode && cnode->definition && !cnode->alias
3761 && (r = summaries_lto->get (cnode))
3762 && r->useful_p (flags_from_decl_or_type (cnode->decl)))
3763 count++;
3765 streamer_write_uhwi (ob, count);
3767 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3769 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3770 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3772 if (cnode && cnode->definition && !cnode->alias)
3774 modref_summary_lto *r = summaries_lto->get (cnode);
3776 if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
3777 continue;
3779 streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
3781 streamer_write_uhwi (ob, r->arg_flags.length ());
3782 for (unsigned int i = 0; i < r->arg_flags.length (); i++)
3783 streamer_write_uhwi (ob, r->arg_flags[i]);
3784 streamer_write_uhwi (ob, r->retslot_flags);
3785 streamer_write_uhwi (ob, r->static_chain_flags);
3787 write_modref_records (r->loads, ob);
3788 write_modref_records (r->stores, ob);
3789 streamer_write_uhwi (ob, r->kills.length ());
3790 for (auto kill : r->kills)
3791 kill.stream_out (ob);
3793 struct bitpack_d bp = bitpack_create (ob->main_stream);
3794 bp_pack_value (&bp, r->writes_errno, 1);
3795 bp_pack_value (&bp, r->side_effects, 1);
3796 bp_pack_value (&bp, r->nondeterministic, 1);
3797 bp_pack_value (&bp, r->calls_interposable, 1);
3798 if (!flag_wpa)
3800 for (cgraph_edge *e = cnode->indirect_calls;
3801 e; e = e->next_callee)
3803 class fnspec_summary *sum = fnspec_summaries->get (e);
3804 bp_pack_value (&bp, sum != NULL, 1);
3805 if (sum)
3806 bp_pack_string (ob, &bp, sum->fnspec, true);
3807 class escape_summary *esum = escape_summaries->get (e);
3808 modref_write_escape_summary (&bp,esum);
3810 for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
3812 class fnspec_summary *sum = fnspec_summaries->get (e);
3813 bp_pack_value (&bp, sum != NULL, 1);
3814 if (sum)
3815 bp_pack_string (ob, &bp, sum->fnspec, true);
3816 class escape_summary *esum = escape_summaries->get (e);
3817 modref_write_escape_summary (&bp,esum);
3820 streamer_write_bitpack (&bp);
3823 streamer_write_char_stream (ob->main_stream, 0);
3824 produce_asm (ob);
3825 destroy_output_block (ob);
3828 static void
3829 read_section (struct lto_file_decl_data *file_data, const char *data,
3830 size_t len)
3832 const struct lto_function_header *header
3833 = (const struct lto_function_header *) data;
3834 const int cfg_offset = sizeof (struct lto_function_header);
3835 const int main_offset = cfg_offset + header->cfg_size;
3836 const int string_offset = main_offset + header->main_size;
3837 struct data_in *data_in;
3838 unsigned int i;
3839 unsigned int f_count;
3841 lto_input_block ib ((const char *) data + main_offset, header->main_size,
3842 file_data);
3844 data_in
3845 = lto_data_in_create (file_data, (const char *) data + string_offset,
3846 header->string_size, vNULL);
3847 f_count = streamer_read_uhwi (&ib);
3848 for (i = 0; i < f_count; i++)
3850 struct cgraph_node *node;
3851 lto_symtab_encoder_t encoder;
3853 unsigned int index = streamer_read_uhwi (&ib);
3854 encoder = file_data->symtab_node_encoder;
3855 node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
3856 index));
3858 modref_summary *modref_sum = summaries
3859 ? summaries->get_create (node) : NULL;
3860 modref_summary_lto *modref_sum_lto = summaries_lto
3861 ? summaries_lto->get_create (node)
3862 : NULL;
3863 if (optimization_summaries)
3864 modref_sum = optimization_summaries->get_create (node);
3866 if (modref_sum)
3868 modref_sum->writes_errno = false;
3869 modref_sum->side_effects = false;
3870 modref_sum->nondeterministic = false;
3871 modref_sum->calls_interposable = false;
3873 if (modref_sum_lto)
3875 modref_sum_lto->writes_errno = false;
3876 modref_sum_lto->side_effects = false;
3877 modref_sum_lto->nondeterministic = false;
3878 modref_sum_lto->calls_interposable = false;
3881 gcc_assert (!modref_sum || (!modref_sum->loads
3882 && !modref_sum->stores));
3883 gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
3884 && !modref_sum_lto->stores));
3885 unsigned int args = streamer_read_uhwi (&ib);
3886 if (args && modref_sum)
3887 modref_sum->arg_flags.reserve_exact (args);
3888 if (args && modref_sum_lto)
3889 modref_sum_lto->arg_flags.reserve_exact (args);
3890 for (unsigned int i = 0; i < args; i++)
3892 eaf_flags_t flags = streamer_read_uhwi (&ib);
3893 if (modref_sum)
3894 modref_sum->arg_flags.quick_push (flags);
3895 if (modref_sum_lto)
3896 modref_sum_lto->arg_flags.quick_push (flags);
3898 eaf_flags_t flags = streamer_read_uhwi (&ib);
3899 if (modref_sum)
3900 modref_sum->retslot_flags = flags;
3901 if (modref_sum_lto)
3902 modref_sum_lto->retslot_flags = flags;
3904 flags = streamer_read_uhwi (&ib);
3905 if (modref_sum)
3906 modref_sum->static_chain_flags = flags;
3907 if (modref_sum_lto)
3908 modref_sum_lto->static_chain_flags = flags;
3910 read_modref_records (node->decl, &ib, data_in,
3911 modref_sum ? &modref_sum->loads : NULL,
3912 modref_sum_lto ? &modref_sum_lto->loads : NULL);
3913 read_modref_records (node->decl, &ib, data_in,
3914 modref_sum ? &modref_sum->stores : NULL,
3915 modref_sum_lto ? &modref_sum_lto->stores : NULL);
3916 int j = streamer_read_uhwi (&ib);
3917 if (j && modref_sum)
3918 modref_sum->kills.reserve_exact (j);
3919 if (j && modref_sum_lto)
3920 modref_sum_lto->kills.reserve_exact (j);
3921 for (int k = 0; k < j; k++)
3923 modref_access_node a = modref_access_node::stream_in (&ib);
3925 if (modref_sum)
3926 modref_sum->kills.quick_push (a);
3927 if (modref_sum_lto)
3928 modref_sum_lto->kills.quick_push (a);
3930 struct bitpack_d bp = streamer_read_bitpack (&ib);
3931 if (bp_unpack_value (&bp, 1))
3933 if (modref_sum)
3934 modref_sum->writes_errno = true;
3935 if (modref_sum_lto)
3936 modref_sum_lto->writes_errno = true;
3938 if (bp_unpack_value (&bp, 1))
3940 if (modref_sum)
3941 modref_sum->side_effects = true;
3942 if (modref_sum_lto)
3943 modref_sum_lto->side_effects = true;
3945 if (bp_unpack_value (&bp, 1))
3947 if (modref_sum)
3948 modref_sum->nondeterministic = true;
3949 if (modref_sum_lto)
3950 modref_sum_lto->nondeterministic = true;
3952 if (bp_unpack_value (&bp, 1))
3954 if (modref_sum)
3955 modref_sum->calls_interposable = true;
3956 if (modref_sum_lto)
3957 modref_sum_lto->calls_interposable = true;
3959 if (!flag_ltrans)
3961 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
3963 if (bp_unpack_value (&bp, 1))
3965 class fnspec_summary *sum = fnspec_summaries->get_create (e);
3966 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3968 modref_read_escape_summary (&bp, e);
3970 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3972 if (bp_unpack_value (&bp, 1))
3974 class fnspec_summary *sum = fnspec_summaries->get_create (e);
3975 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3977 modref_read_escape_summary (&bp, e);
3980 if (flag_ltrans)
3981 modref_sum->finalize (node->decl);
3982 if (dump_file)
3984 fprintf (dump_file, "Read modref for %s\n",
3985 node->dump_name ());
3986 if (modref_sum)
3987 modref_sum->dump (dump_file);
3988 if (modref_sum_lto)
3989 modref_sum_lto->dump (dump_file);
3990 dump_modref_edge_summaries (dump_file, node, 4);
3994 lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
3995 len);
3996 lto_data_in_delete (data_in);
3999 /* Callback for read_summary. */
4001 static void
4002 modref_read (void)
4004 struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
4005 struct lto_file_decl_data *file_data;
4006 unsigned int j = 0;
4008 gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
4009 if (flag_ltrans)
4010 optimization_summaries = modref_summaries::create_ggc (symtab);
4011 else
4013 if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
4014 summaries_lto = modref_summaries_lto::create_ggc (symtab);
4015 if (!flag_wpa
4016 || (flag_incremental_link == INCREMENTAL_LINK_LTO
4017 && flag_fat_lto_objects))
4018 summaries = modref_summaries::create_ggc (symtab);
4019 if (!fnspec_summaries)
4020 fnspec_summaries = new fnspec_summaries_t (symtab);
4021 if (!escape_summaries)
4022 escape_summaries = new escape_summaries_t (symtab);
4025 while ((file_data = file_data_vec[j++]))
4027 size_t len;
4028 const char *data = lto_get_summary_section_data (file_data,
4029 LTO_section_ipa_modref,
4030 &len);
4031 if (data)
4032 read_section (file_data, data, len);
4033 else
4034 /* Fatal error here. We do not want to support compiling ltrans units
4035 with different version of compiler or different flags than the WPA
4036 unit, so this should never happen. */
4037 fatal_error (input_location,
4038 "IPA modref summary is missing in input file");
4042 /* Recompute arg_flags for param adjustments in INFO. */
4044 static void
4045 remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
4047 auto_vec<eaf_flags_t> old = arg_flags.copy ();
4048 int max = -1;
4049 size_t i;
4050 ipa_adjusted_param *p;
4052 arg_flags.release ();
4054 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4056 int o = info->param_adjustments->get_original_index (i);
4057 if (o >= 0 && (int)old.length () > o && old[o])
4058 max = i;
4060 if (max >= 0)
4061 arg_flags.safe_grow_cleared (max + 1, true);
4062 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4064 int o = info->param_adjustments->get_original_index (i);
4065 if (o >= 0 && (int)old.length () > o && old[o])
4066 arg_flags[i] = old[o];
4070 /* Update kills according to the parm map MAP. */
4072 static void
4073 remap_kills (vec <modref_access_node> &kills, const vec <int> &map)
4075 for (size_t i = 0; i < kills.length ();)
4076 if (kills[i].parm_index >= 0)
4078 if (kills[i].parm_index < (int)map.length ()
4079 && map[kills[i].parm_index] != MODREF_UNKNOWN_PARM)
4081 kills[i].parm_index = map[kills[i].parm_index];
4082 i++;
4084 else
4085 kills.unordered_remove (i);
4087 else
4088 i++;
4091 /* Return true if the V can overlap with KILL. */
4093 static bool
4094 ipcp_argagg_and_kill_overlap_p (const ipa_argagg_value &v,
4095 const modref_access_node &kill)
4097 if (kill.parm_index == v.index)
4099 gcc_assert (kill.parm_offset_known);
4100 gcc_assert (known_eq (kill.max_size, kill.size));
4101 poly_int64 repl_size;
4102 bool ok = poly_int_tree_p (TYPE_SIZE (TREE_TYPE (v.value)),
4103 &repl_size);
4104 gcc_assert (ok);
4105 poly_int64 repl_offset (v.unit_offset);
4106 repl_offset <<= LOG2_BITS_PER_UNIT;
4107 poly_int64 combined_offset
4108 = (kill.parm_offset << LOG2_BITS_PER_UNIT) + kill.offset;
4109 if (ranges_maybe_overlap_p (repl_offset, repl_size,
4110 combined_offset, kill.size))
4111 return true;
4113 return false;
4116 /* If signature changed, update the summary. */
4118 static void
4119 update_signature (struct cgraph_node *node)
4121 modref_summary *r = optimization_summaries
4122 ? optimization_summaries->get (node) : NULL;
4123 modref_summary_lto *r_lto = summaries_lto
4124 ? summaries_lto->get (node) : NULL;
4125 if (!r && !r_lto)
4126 return;
4128 /* Propagating constants in killed memory can lead to eliminated stores in
4129 both callees (because they are considered redundant) and callers, leading
4130 to missing them altogether. */
4131 ipcp_transformation *ipcp_ts = ipcp_get_transformation_summary (node);
4132 if (ipcp_ts)
4134 for (auto &v : ipcp_ts->m_agg_values)
4136 if (!v.by_ref)
4137 continue;
4138 if (r)
4139 for (const modref_access_node &kill : r->kills)
4140 if (ipcp_argagg_and_kill_overlap_p (v, kill))
4142 v.killed = true;
4143 break;
4145 if (!v.killed && r_lto)
4146 for (const modref_access_node &kill : r_lto->kills)
4147 if (ipcp_argagg_and_kill_overlap_p (v, kill))
4149 v.killed = true;
4150 break;
4155 clone_info *info = clone_info::get (node);
4156 if (!info || !info->param_adjustments)
4157 return;
4159 if (dump_file)
4161 fprintf (dump_file, "Updating summary for %s from:\n",
4162 node->dump_name ());
4163 if (r)
4164 r->dump (dump_file);
4165 if (r_lto)
4166 r_lto->dump (dump_file);
4169 size_t i, max = 0;
4170 ipa_adjusted_param *p;
4172 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4174 int idx = info->param_adjustments->get_original_index (i);
4175 if (idx > (int)max)
4176 max = idx;
4179 auto_vec <int, 32> map;
4181 map.reserve (max + 1);
4182 for (i = 0; i <= max; i++)
4183 map.quick_push (MODREF_UNKNOWN_PARM);
4184 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4186 int idx = info->param_adjustments->get_original_index (i);
4187 if (idx >= 0)
4188 map[idx] = i;
4190 if (r)
4192 r->loads->remap_params (&map);
4193 r->stores->remap_params (&map);
4194 remap_kills (r->kills, map);
4195 if (r->arg_flags.length ())
4196 remap_arg_flags (r->arg_flags, info);
4198 if (r_lto)
4200 r_lto->loads->remap_params (&map);
4201 r_lto->stores->remap_params (&map);
4202 remap_kills (r_lto->kills, map);
4203 if (r_lto->arg_flags.length ())
4204 remap_arg_flags (r_lto->arg_flags, info);
4206 if (dump_file)
4208 fprintf (dump_file, "to:\n");
4209 if (r)
4210 r->dump (dump_file);
4211 if (r_lto)
4212 r_lto->dump (dump_file);
4214 if (r)
4215 r->finalize (node->decl);
4216 return;
4219 /* Definition of the modref IPA pass. */
4220 const pass_data pass_data_ipa_modref =
4222 IPA_PASS, /* type */
4223 "modref", /* name */
4224 OPTGROUP_IPA, /* optinfo_flags */
4225 TV_IPA_MODREF, /* tv_id */
4226 0, /* properties_required */
4227 0, /* properties_provided */
4228 0, /* properties_destroyed */
4229 0, /* todo_flags_start */
4230 ( TODO_dump_symtab ), /* todo_flags_finish */
4233 class pass_ipa_modref : public ipa_opt_pass_d
4235 public:
4236 pass_ipa_modref (gcc::context *ctxt)
4237 : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
4238 modref_generate, /* generate_summary */
4239 modref_write, /* write_summary */
4240 modref_read, /* read_summary */
4241 modref_write, /* write_optimization_summary */
4242 modref_read, /* read_optimization_summary */
4243 NULL, /* stmt_fixup */
4244 0, /* function_transform_todo_flags_start */
4245 NULL, /* function_transform */
4246 NULL) /* variable_transform */
4249 /* opt_pass methods: */
4250 opt_pass *clone () final override { return new pass_ipa_modref (m_ctxt); }
4251 bool gate (function *) final override
4253 return true;
4255 unsigned int execute (function *) final override;
4261 unsigned int pass_modref::execute (function *)
4263 if (analyze_function (false))
4264 return execute_fixup_cfg ();
4265 return 0;
4268 gimple_opt_pass *
4269 make_pass_modref (gcc::context *ctxt)
4271 return new pass_modref (ctxt);
4274 ipa_opt_pass_d *
4275 make_pass_ipa_modref (gcc::context *ctxt)
4277 return new pass_ipa_modref (ctxt);
4280 namespace {
4282 /* Skip edges from and to nodes without ipa_pure_const enabled.
4283 Ignore not available symbols. */
4285 static bool
4286 ignore_edge (struct cgraph_edge *e)
4288 /* We merge summaries of inline clones into summaries of functions they
4289 are inlined to. For that reason the complete function bodies must
4290 act as unit. */
4291 if (!e->inline_failed)
4292 return false;
4293 enum availability avail;
4294 cgraph_node *callee = e->callee->ultimate_alias_target
4295 (&avail, e->caller);
4297 return (avail <= AVAIL_INTERPOSABLE
4298 || ((!optimization_summaries || !optimization_summaries->get (callee))
4299 && (!summaries_lto || !summaries_lto->get (callee))));
4302 /* Compute parm_map for CALLEE_EDGE. */
4304 static bool
4305 compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
4307 class ipa_edge_args *args;
4308 if (ipa_node_params_sum
4309 && !callee_edge->call_stmt_cannot_inline_p
4310 && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
4312 int i, count = ipa_get_cs_argument_count (args);
4313 class ipa_node_params *caller_parms_info, *callee_pi;
4314 class ipa_call_summary *es
4315 = ipa_call_summaries->get (callee_edge);
4316 cgraph_node *callee
4317 = callee_edge->callee->ultimate_alias_target
4318 (NULL, callee_edge->caller);
4320 caller_parms_info
4321 = ipa_node_params_sum->get (callee_edge->caller->inlined_to
4322 ? callee_edge->caller->inlined_to
4323 : callee_edge->caller);
4324 callee_pi = ipa_node_params_sum->get (callee);
4326 (*parm_map).safe_grow_cleared (count, true);
4328 for (i = 0; i < count; i++)
4330 if (es && es->param[i].points_to_local_or_readonly_memory)
4332 (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
4333 continue;
4336 struct ipa_jump_func *jf
4337 = ipa_get_ith_jump_func (args, i);
4338 if (jf && callee_pi)
4340 tree cst = ipa_value_from_jfunc (caller_parms_info,
4342 ipa_get_type
4343 (callee_pi, i));
4344 if (cst && points_to_local_or_readonly_memory_p (cst))
4346 (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
4347 continue;
4350 if (jf && jf->type == IPA_JF_PASS_THROUGH)
4352 (*parm_map)[i].parm_index
4353 = ipa_get_jf_pass_through_formal_id (jf);
4354 if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
4356 (*parm_map)[i].parm_offset_known = true;
4357 (*parm_map)[i].parm_offset = 0;
4359 else if (ipa_get_jf_pass_through_operation (jf)
4360 == POINTER_PLUS_EXPR
4361 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
4362 &(*parm_map)[i].parm_offset))
4363 (*parm_map)[i].parm_offset_known = true;
4364 else
4365 (*parm_map)[i].parm_offset_known = false;
4366 continue;
4368 if (jf && jf->type == IPA_JF_ANCESTOR)
4370 (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
4371 (*parm_map)[i].parm_offset_known = true;
4372 gcc_checking_assert
4373 (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
4374 (*parm_map)[i].parm_offset
4375 = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
4377 else
4378 (*parm_map)[i].parm_index = -1;
4380 if (dump_file)
4382 fprintf (dump_file, " Parm map: ");
4383 for (i = 0; i < count; i++)
4384 fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
4385 fprintf (dump_file, "\n");
4387 return true;
4389 return false;
4392 /* Map used to translate escape infos. */
4394 struct escape_map
4396 int parm_index;
4397 bool direct;
4400 /* Update escape map for E. */
4402 static void
4403 update_escape_summary_1 (cgraph_edge *e,
4404 vec <vec <escape_map>> &map,
4405 bool ignore_stores)
4407 escape_summary *sum = escape_summaries->get (e);
4408 if (!sum)
4409 return;
4410 auto_vec <escape_entry> old = sum->esc.copy ();
4411 sum->esc.release ();
4413 unsigned int i;
4414 escape_entry *ee;
4415 FOR_EACH_VEC_ELT (old, i, ee)
4417 unsigned int j;
4418 struct escape_map *em;
4419 /* TODO: We do not have jump functions for return slots, so we
4420 never propagate them to outer function. */
4421 if (ee->parm_index >= (int)map.length ()
4422 || ee->parm_index < 0)
4423 continue;
4424 FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
4426 eaf_flags_t min_flags = ee->min_flags;
4427 if (ee->direct && !em->direct)
4428 min_flags = deref_flags (min_flags, ignore_stores);
4429 struct escape_entry entry = {em->parm_index, ee->arg,
4430 min_flags,
4431 ee->direct && em->direct};
4432 sum->esc.safe_push (entry);
4435 if (!sum->esc.length ())
4436 escape_summaries->remove (e);
4439 /* Update escape map for NODE. */
4441 static void
4442 update_escape_summary (cgraph_node *node,
4443 vec <vec <escape_map>> &map,
4444 bool ignore_stores)
4446 if (!escape_summaries)
4447 return;
4448 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
4449 update_escape_summary_1 (e, map, ignore_stores);
4450 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
4452 if (!e->inline_failed)
4453 update_escape_summary (e->callee, map, ignore_stores);
4454 else
4455 update_escape_summary_1 (e, map, ignore_stores);
4459 /* Get parameter type from DECL. This is only safe for special cases
4460 like builtins we create fnspec for because the type match is checked
4461 at fnspec creation time. */
4463 static tree
4464 get_parm_type (tree decl, unsigned int i)
4466 tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
4468 for (unsigned int p = 0; p < i; p++)
4469 t = TREE_CHAIN (t);
4470 return TREE_VALUE (t);
4473 /* Return access mode for argument I of call E with FNSPEC. */
4475 static modref_access_node
4476 get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
4477 unsigned int i, modref_parm_map &map)
4479 tree size = NULL_TREE;
4480 unsigned int size_arg;
4482 if (!fnspec.arg_specified_p (i))
4484 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
4486 cgraph_node *node = e->caller->inlined_to
4487 ? e->caller->inlined_to : e->caller;
4488 ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
4489 ipa_edge_args *args = ipa_edge_args_sum->get (e);
4490 struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
4492 if (jf)
4493 size = ipa_value_from_jfunc (caller_parms_info, jf,
4494 get_parm_type (e->callee->decl, size_arg));
4496 else if (fnspec.arg_access_size_given_by_type_p (i))
4497 size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
4498 modref_access_node a = {0, -1, -1,
4499 map.parm_offset, map.parm_index,
4500 map.parm_offset_known, 0};
4501 poly_int64 size_hwi;
4502 if (size
4503 && poly_int_tree_p (size, &size_hwi)
4504 && coeffs_in_range_p (size_hwi, 0,
4505 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
4507 a.size = -1;
4508 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
4510 return a;
4513 /* Collapse loads and return true if something changed. */
4514 static bool
4515 collapse_loads (modref_summary *cur_summary,
4516 modref_summary_lto *cur_summary_lto)
4518 bool changed = false;
4520 if (cur_summary && !cur_summary->loads->every_base)
4522 cur_summary->loads->collapse ();
4523 changed = true;
4525 if (cur_summary_lto
4526 && !cur_summary_lto->loads->every_base)
4528 cur_summary_lto->loads->collapse ();
4529 changed = true;
4531 return changed;
4534 /* Collapse loads and return true if something changed. */
4536 static bool
4537 collapse_stores (modref_summary *cur_summary,
4538 modref_summary_lto *cur_summary_lto)
4540 bool changed = false;
4542 if (cur_summary && !cur_summary->stores->every_base)
4544 cur_summary->stores->collapse ();
4545 changed = true;
4547 if (cur_summary_lto
4548 && !cur_summary_lto->stores->every_base)
4550 cur_summary_lto->stores->collapse ();
4551 changed = true;
4553 return changed;
4556 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
4557 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
4559 static bool
4560 propagate_unknown_call (cgraph_node *node,
4561 cgraph_edge *e, int ecf_flags,
4562 modref_summary *cur_summary,
4563 modref_summary_lto *cur_summary_lto,
4564 bool nontrivial_scc)
4566 bool changed = false;
4567 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
4568 auto_vec <modref_parm_map, 32> parm_map;
4569 bool looping;
4571 if (e->callee
4572 && builtin_safe_for_const_function_p (&looping, e->callee->decl))
4574 if (looping && cur_summary && !cur_summary->side_effects)
4576 cur_summary->side_effects = true;
4577 changed = true;
4579 if (looping && cur_summary_lto && !cur_summary_lto->side_effects)
4581 cur_summary_lto->side_effects = true;
4582 changed = true;
4584 return changed;
4587 if (!(ecf_flags & (ECF_CONST | ECF_PURE))
4588 || (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
4589 || nontrivial_scc)
4591 if (cur_summary && !cur_summary->side_effects)
4593 cur_summary->side_effects = true;
4594 changed = true;
4596 if (cur_summary_lto && !cur_summary_lto->side_effects)
4598 cur_summary_lto->side_effects = true;
4599 changed = true;
4601 if (!ignore_nondeterminism_p (node->decl, ecf_flags,
4602 e->callee ? TREE_TYPE (e->callee->decl)
4603 : NULL_TREE))
4605 if (cur_summary && !cur_summary->nondeterministic)
4607 cur_summary->nondeterministic = true;
4608 changed = true;
4610 if (cur_summary_lto && !cur_summary_lto->nondeterministic)
4612 cur_summary_lto->nondeterministic = true;
4613 changed = true;
4617 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
4618 return changed;
4620 if (fnspec_sum
4621 && compute_parm_map (e, &parm_map))
4623 attr_fnspec fnspec (fnspec_sum->fnspec);
4625 gcc_checking_assert (fnspec.known_p ());
4626 if (fnspec.global_memory_read_p ())
4627 collapse_loads (cur_summary, cur_summary_lto);
4628 else
4630 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4631 for (unsigned i = 0; i < parm_map.length () && t;
4632 i++, t = TREE_CHAIN (t))
4633 if (!POINTER_TYPE_P (TREE_VALUE (t)))
4635 else if (!fnspec.arg_specified_p (i)
4636 || fnspec.arg_maybe_read_p (i))
4638 modref_parm_map map = parm_map[i];
4639 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4640 continue;
4641 if (map.parm_index == MODREF_UNKNOWN_PARM)
4643 collapse_loads (cur_summary, cur_summary_lto);
4644 break;
4646 if (cur_summary)
4647 changed |= cur_summary->loads->insert
4648 (node->decl, 0, 0,
4649 get_access_for_fnspec (e, fnspec, i, map), false);
4650 if (cur_summary_lto)
4651 changed |= cur_summary_lto->loads->insert
4652 (node->decl, 0, 0,
4653 get_access_for_fnspec (e, fnspec, i, map), false);
4656 if (ignore_stores_p (node->decl, ecf_flags))
4658 else if (fnspec.global_memory_written_p ())
4659 collapse_stores (cur_summary, cur_summary_lto);
4660 else
4662 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4663 for (unsigned i = 0; i < parm_map.length () && t;
4664 i++, t = TREE_CHAIN (t))
4665 if (!POINTER_TYPE_P (TREE_VALUE (t)))
4667 else if (!fnspec.arg_specified_p (i)
4668 || fnspec.arg_maybe_written_p (i))
4670 modref_parm_map map = parm_map[i];
4671 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4672 continue;
4673 if (map.parm_index == MODREF_UNKNOWN_PARM)
4675 collapse_stores (cur_summary, cur_summary_lto);
4676 break;
4678 if (cur_summary)
4679 changed |= cur_summary->stores->insert
4680 (node->decl, 0, 0,
4681 get_access_for_fnspec (e, fnspec, i, map), false);
4682 if (cur_summary_lto)
4683 changed |= cur_summary_lto->stores->insert
4684 (node->decl, 0, 0,
4685 get_access_for_fnspec (e, fnspec, i, map), false);
4688 if (fnspec.errno_maybe_written_p () && flag_errno_math)
4690 if (cur_summary && !cur_summary->writes_errno)
4692 cur_summary->writes_errno = true;
4693 changed = true;
4695 if (cur_summary_lto && !cur_summary_lto->writes_errno)
4697 cur_summary_lto->writes_errno = true;
4698 changed = true;
4701 return changed;
4703 if (dump_file)
4704 fprintf (dump_file, " collapsing loads\n");
4705 changed |= collapse_loads (cur_summary, cur_summary_lto);
4706 if (!ignore_stores_p (node->decl, ecf_flags))
4708 if (dump_file)
4709 fprintf (dump_file, " collapsing stores\n");
4710 changed |= collapse_stores (cur_summary, cur_summary_lto);
4712 return changed;
4715 /* Maybe remove summaries of NODE pointed to by CUR_SUMMARY_PTR
4716 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
4718 static void
4719 remove_useless_summaries (cgraph_node *node,
4720 modref_summary **cur_summary_ptr,
4721 modref_summary_lto **cur_summary_lto_ptr,
4722 int ecf_flags)
4724 if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
4726 optimization_summaries->remove (node);
4727 *cur_summary_ptr = NULL;
4729 if (*cur_summary_lto_ptr
4730 && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
4732 summaries_lto->remove (node);
4733 *cur_summary_lto_ptr = NULL;
4737 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4738 and propagate loads/stores. */
4740 static bool
4741 modref_propagate_in_scc (cgraph_node *component_node)
4743 bool changed = true;
4744 bool first = true;
4745 int iteration = 0;
4747 while (changed)
4749 bool nontrivial_scc
4750 = ((struct ipa_dfs_info *) component_node->aux)->next_cycle;
4751 changed = false;
4752 for (struct cgraph_node *cur = component_node; cur;
4753 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4755 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
4756 modref_summary *cur_summary = optimization_summaries
4757 ? optimization_summaries->get (node)
4758 : NULL;
4759 modref_summary_lto *cur_summary_lto = summaries_lto
4760 ? summaries_lto->get (node)
4761 : NULL;
4763 if (!cur_summary && !cur_summary_lto)
4764 continue;
4766 int cur_ecf_flags = flags_from_decl_or_type (node->decl);
4768 if (dump_file)
4769 fprintf (dump_file, " Processing %s%s%s\n",
4770 cur->dump_name (),
4771 TREE_READONLY (cur->decl) ? " (const)" : "",
4772 DECL_PURE_P (cur->decl) ? " (pure)" : "");
4774 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
4776 if (dump_file)
4777 fprintf (dump_file, " Indirect call\n");
4778 if (propagate_unknown_call
4779 (node, e, e->indirect_info->ecf_flags,
4780 cur_summary, cur_summary_lto,
4781 nontrivial_scc))
4783 changed = true;
4784 remove_useless_summaries (node, &cur_summary,
4785 &cur_summary_lto,
4786 cur_ecf_flags);
4787 if (!cur_summary && !cur_summary_lto)
4788 break;
4792 if (!cur_summary && !cur_summary_lto)
4793 continue;
4795 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
4796 callee_edge = callee_edge->next_callee)
4798 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
4799 modref_summary *callee_summary = NULL;
4800 modref_summary_lto *callee_summary_lto = NULL;
4801 struct cgraph_node *callee;
4803 if (!callee_edge->inline_failed
4804 || ((flags & ECF_CONST)
4805 && !(flags & ECF_LOOPING_CONST_OR_PURE)))
4806 continue;
4808 /* Get the callee and its summary. */
4809 enum availability avail;
4810 callee = callee_edge->callee->ultimate_alias_target
4811 (&avail, cur);
4813 /* It is not necessary to re-process calls outside of the
4814 SCC component. */
4815 if (iteration > 0
4816 && (!callee->aux
4817 || ((struct ipa_dfs_info *)cur->aux)->scc_no
4818 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
4819 continue;
4821 if (dump_file)
4822 fprintf (dump_file, " Call to %s\n",
4823 callee_edge->callee->dump_name ());
4825 bool ignore_stores = ignore_stores_p (cur->decl, flags);
4827 if (avail <= AVAIL_INTERPOSABLE)
4829 if (dump_file)
4830 fprintf (dump_file, " Call target interposable"
4831 " or not available\n");
4832 changed |= propagate_unknown_call
4833 (node, callee_edge, flags,
4834 cur_summary, cur_summary_lto,
4835 nontrivial_scc);
4836 if (!cur_summary && !cur_summary_lto)
4837 break;
4838 continue;
4841 /* We don't know anything about CALLEE, hence we cannot tell
4842 anything about the entire component. */
4844 if (cur_summary
4845 && !(callee_summary = optimization_summaries->get (callee)))
4847 if (dump_file)
4848 fprintf (dump_file, " No call target summary\n");
4849 changed |= propagate_unknown_call
4850 (node, callee_edge, flags,
4851 cur_summary, NULL,
4852 nontrivial_scc);
4854 if (cur_summary_lto
4855 && !(callee_summary_lto = summaries_lto->get (callee)))
4857 if (dump_file)
4858 fprintf (dump_file, " No call target summary\n");
4859 changed |= propagate_unknown_call
4860 (node, callee_edge, flags,
4861 NULL, cur_summary_lto,
4862 nontrivial_scc);
4865 if (callee_summary && !cur_summary->side_effects
4866 && (callee_summary->side_effects
4867 || callee_edge->recursive_p ()))
4869 cur_summary->side_effects = true;
4870 changed = true;
4872 if (callee_summary_lto && !cur_summary_lto->side_effects
4873 && (callee_summary_lto->side_effects
4874 || callee_edge->recursive_p ()))
4876 cur_summary_lto->side_effects = true;
4877 changed = true;
4879 if (callee_summary && !cur_summary->nondeterministic
4880 && callee_summary->nondeterministic
4881 && !ignore_nondeterminism_p
4882 (cur->decl, flags,
4883 TREE_TYPE (callee_edge->callee->decl)))
4885 cur_summary->nondeterministic = true;
4886 changed = true;
4888 if (callee_summary_lto && !cur_summary_lto->nondeterministic
4889 && callee_summary_lto->nondeterministic
4890 && !ignore_nondeterminism_p
4891 (cur->decl, flags,
4892 TREE_TYPE (callee_edge->callee->decl)))
4894 cur_summary_lto->nondeterministic = true;
4895 changed = true;
4897 if (flags & (ECF_CONST | ECF_NOVOPS))
4898 continue;
4900 /* We can not safely optimize based on summary of callee if it
4901 does not always bind to current def: it is possible that
4902 memory load was optimized out earlier which may not happen in
4903 the interposed variant. */
4904 if (!callee_edge->binds_to_current_def_p ())
4906 if (cur_summary && !cur_summary->calls_interposable)
4908 cur_summary->calls_interposable = true;
4909 changed = true;
4911 if (cur_summary_lto && !cur_summary_lto->calls_interposable)
4913 cur_summary_lto->calls_interposable = true;
4914 changed = true;
4916 if (dump_file)
4917 fprintf (dump_file, " May not bind local;"
4918 " collapsing loads\n");
4922 auto_vec <modref_parm_map, 32> parm_map;
4923 modref_parm_map chain_map;
4924 /* TODO: Once we get jump functions for static chains we could
4925 compute this. */
4926 chain_map.parm_index = MODREF_UNKNOWN_PARM;
4928 compute_parm_map (callee_edge, &parm_map);
4930 /* Merge in callee's information. */
4931 if (callee_summary)
4933 changed |= cur_summary->loads->merge
4934 (node->decl, callee_summary->loads,
4935 &parm_map, &chain_map, !first);
4936 if (!ignore_stores)
4938 changed |= cur_summary->stores->merge
4939 (node->decl, callee_summary->stores,
4940 &parm_map, &chain_map, !first);
4941 if (!cur_summary->writes_errno
4942 && callee_summary->writes_errno)
4944 cur_summary->writes_errno = true;
4945 changed = true;
4949 if (callee_summary_lto)
4951 changed |= cur_summary_lto->loads->merge
4952 (node->decl, callee_summary_lto->loads,
4953 &parm_map, &chain_map, !first);
4954 if (!ignore_stores)
4956 changed |= cur_summary_lto->stores->merge
4957 (node->decl, callee_summary_lto->stores,
4958 &parm_map, &chain_map, !first);
4959 if (!cur_summary_lto->writes_errno
4960 && callee_summary_lto->writes_errno)
4962 cur_summary_lto->writes_errno = true;
4963 changed = true;
4967 if (changed)
4968 remove_useless_summaries (node, &cur_summary,
4969 &cur_summary_lto,
4970 cur_ecf_flags);
4971 if (!cur_summary && !cur_summary_lto)
4972 break;
4973 if (dump_file && changed)
4975 if (cur_summary)
4976 cur_summary->dump (dump_file);
4977 if (cur_summary_lto)
4978 cur_summary_lto->dump (dump_file);
4979 dump_modref_edge_summaries (dump_file, node, 4);
4983 iteration++;
4984 first = false;
4986 if (dump_file)
4987 fprintf (dump_file,
4988 "Propagation finished in %i iterations\n", iteration);
4989 bool pureconst = false;
4990 for (struct cgraph_node *cur = component_node; cur;
4991 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4992 if (!cur->inlined_to && opt_for_fn (cur->decl, flag_ipa_pure_const))
4994 modref_summary *summary = optimization_summaries
4995 ? optimization_summaries->get (cur)
4996 : NULL;
4997 modref_summary_lto *summary_lto = summaries_lto
4998 ? summaries_lto->get (cur)
4999 : NULL;
5000 if (summary && !summary->stores->every_base && !summary->stores->bases
5001 && !summary->nondeterministic)
5003 if (!summary->loads->every_base && !summary->loads->bases
5004 && !summary->calls_interposable)
5005 pureconst |= ipa_make_function_const
5006 (cur, summary->side_effects, false);
5007 else
5008 pureconst |= ipa_make_function_pure
5009 (cur, summary->side_effects, false);
5011 if (summary_lto && !summary_lto->stores->every_base
5012 && !summary_lto->stores->bases && !summary_lto->nondeterministic)
5014 if (!summary_lto->loads->every_base && !summary_lto->loads->bases
5015 && !summary_lto->calls_interposable)
5016 pureconst |= ipa_make_function_const
5017 (cur, summary_lto->side_effects, false);
5018 else
5019 pureconst |= ipa_make_function_pure
5020 (cur, summary_lto->side_effects, false);
5023 return pureconst;
5026 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
5028 static void
5029 modref_propagate_dump_scc (cgraph_node *component_node)
5031 for (struct cgraph_node *cur = component_node; cur;
5032 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5033 if (!cur->inlined_to)
5035 modref_summary *cur_summary = optimization_summaries
5036 ? optimization_summaries->get (cur)
5037 : NULL;
5038 modref_summary_lto *cur_summary_lto = summaries_lto
5039 ? summaries_lto->get (cur)
5040 : NULL;
5042 fprintf (dump_file, "Propagated modref for %s%s%s\n",
5043 cur->dump_name (),
5044 TREE_READONLY (cur->decl) ? " (const)" : "",
5045 DECL_PURE_P (cur->decl) ? " (pure)" : "");
5046 if (optimization_summaries)
5048 if (cur_summary)
5049 cur_summary->dump (dump_file);
5050 else
5051 fprintf (dump_file, " Not tracked\n");
5053 if (summaries_lto)
5055 if (cur_summary_lto)
5056 cur_summary_lto->dump (dump_file);
5057 else
5058 fprintf (dump_file, " Not tracked (lto)\n");
5063 /* Determine EAF flags know for call E with CALLEE_ECF_FLAGS and ARG. */
5066 implicit_eaf_flags_for_edge_and_arg (cgraph_edge *e, int callee_ecf_flags,
5067 bool ignore_stores, int arg)
5069 /* Returning the value is already accounted to at local propagation. */
5070 int implicit_flags = EAF_NOT_RETURNED_DIRECTLY
5071 | EAF_NOT_RETURNED_INDIRECTLY;
5072 if (ignore_stores)
5073 implicit_flags |= ignore_stores_eaf_flags;
5074 if (callee_ecf_flags & ECF_PURE)
5075 implicit_flags |= implicit_pure_eaf_flags;
5076 if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
5077 implicit_flags |= implicit_const_eaf_flags;
5078 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
5079 if (fnspec_sum)
5081 attr_fnspec fnspec (fnspec_sum->fnspec);
5082 implicit_flags |= fnspec.arg_eaf_flags (arg);
5084 return implicit_flags;
5087 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
5088 and SUMMARY_LTO to CUR_SUMMARY_LTO.
5089 Return true if something changed. */
5091 static bool
5092 modref_merge_call_site_flags (escape_summary *sum,
5093 modref_summary *cur_summary,
5094 modref_summary_lto *cur_summary_lto,
5095 modref_summary *summary,
5096 modref_summary_lto *summary_lto,
5097 tree caller,
5098 cgraph_edge *e,
5099 int caller_ecf_flags,
5100 int callee_ecf_flags,
5101 bool binds_to_current_def)
5103 escape_entry *ee;
5104 unsigned int i;
5105 bool changed = false;
5106 bool ignore_stores = ignore_stores_p (caller, callee_ecf_flags);
5108 /* Return early if we have no useful info to propagate. */
5109 if ((!cur_summary
5110 || (!cur_summary->arg_flags.length ()
5111 && !cur_summary->static_chain_flags
5112 && !cur_summary->retslot_flags))
5113 && (!cur_summary_lto
5114 || (!cur_summary_lto->arg_flags.length ()
5115 && !cur_summary_lto->static_chain_flags
5116 && !cur_summary_lto->retslot_flags)))
5117 return false;
5119 FOR_EACH_VEC_ELT (sum->esc, i, ee)
5121 int flags = 0;
5122 int flags_lto = 0;
5123 int implicit_flags = implicit_eaf_flags_for_edge_and_arg
5124 (e, callee_ecf_flags, ignore_stores, ee->arg);
5126 if (summary && ee->arg < summary->arg_flags.length ())
5127 flags = summary->arg_flags[ee->arg];
5128 if (summary_lto
5129 && ee->arg < summary_lto->arg_flags.length ())
5130 flags_lto = summary_lto->arg_flags[ee->arg];
5131 if (!ee->direct)
5133 flags = deref_flags (flags, ignore_stores);
5134 flags_lto = deref_flags (flags_lto, ignore_stores);
5136 if (ignore_stores)
5137 implicit_flags |= ignore_stores_eaf_flags;
5138 if (callee_ecf_flags & ECF_PURE)
5139 implicit_flags |= implicit_pure_eaf_flags;
5140 if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
5141 implicit_flags |= implicit_const_eaf_flags;
5142 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
5143 if (fnspec_sum)
5145 attr_fnspec fnspec (fnspec_sum->fnspec);
5146 implicit_flags |= fnspec.arg_eaf_flags (ee->arg);
5148 if (!ee->direct)
5149 implicit_flags = deref_flags (implicit_flags, ignore_stores);
5150 flags |= implicit_flags;
5151 flags_lto |= implicit_flags;
5152 if (!binds_to_current_def && (flags || flags_lto))
5154 flags = interposable_eaf_flags (flags, implicit_flags);
5155 flags_lto = interposable_eaf_flags (flags_lto, implicit_flags);
5157 if (!(flags & EAF_UNUSED)
5158 && cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ())
5160 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5161 ? cur_summary->retslot_flags
5162 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5163 ? cur_summary->static_chain_flags
5164 : cur_summary->arg_flags[ee->parm_index];
5165 if ((f & flags) != f)
5167 f = remove_useless_eaf_flags
5168 (f & flags, caller_ecf_flags,
5169 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
5170 changed = true;
5173 if (!(flags_lto & EAF_UNUSED)
5174 && cur_summary_lto
5175 && ee->parm_index < (int)cur_summary_lto->arg_flags.length ())
5177 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5178 ? cur_summary_lto->retslot_flags
5179 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5180 ? cur_summary_lto->static_chain_flags
5181 : cur_summary_lto->arg_flags[ee->parm_index];
5182 if ((f & flags_lto) != f)
5184 f = remove_useless_eaf_flags
5185 (f & flags_lto, caller_ecf_flags,
5186 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
5187 changed = true;
5191 return changed;
5194 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
5195 and propagate arg flags. */
5197 static void
5198 modref_propagate_flags_in_scc (cgraph_node *component_node)
5200 bool changed = true;
5201 int iteration = 0;
5203 while (changed)
5205 changed = false;
5206 for (struct cgraph_node *cur = component_node; cur;
5207 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5209 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
5210 modref_summary *cur_summary = optimization_summaries
5211 ? optimization_summaries->get (node)
5212 : NULL;
5213 modref_summary_lto *cur_summary_lto = summaries_lto
5214 ? summaries_lto->get (node)
5215 : NULL;
5217 if (!cur_summary && !cur_summary_lto)
5218 continue;
5219 int caller_ecf_flags = flags_from_decl_or_type (cur->decl);
5221 if (dump_file)
5222 fprintf (dump_file, " Processing %s%s%s\n",
5223 cur->dump_name (),
5224 TREE_READONLY (cur->decl) ? " (const)" : "",
5225 DECL_PURE_P (cur->decl) ? " (pure)" : "");
5227 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
5229 escape_summary *sum = escape_summaries->get (e);
5231 if (!sum || ((e->indirect_info->ecf_flags & ECF_CONST)
5232 && !(e->indirect_info->ecf_flags & ECF_LOOPING_CONST_OR_PURE)))
5233 continue;
5235 changed |= modref_merge_call_site_flags
5236 (sum, cur_summary, cur_summary_lto,
5237 NULL, NULL,
5238 node->decl,
5240 caller_ecf_flags,
5241 e->indirect_info->ecf_flags,
5242 false);
5245 if (!cur_summary && !cur_summary_lto)
5246 continue;
5248 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
5249 callee_edge = callee_edge->next_callee)
5251 int ecf_flags = flags_from_decl_or_type
5252 (callee_edge->callee->decl);
5253 modref_summary *callee_summary = NULL;
5254 modref_summary_lto *callee_summary_lto = NULL;
5255 struct cgraph_node *callee;
5257 if ((ecf_flags & ECF_CONST)
5258 && !(ecf_flags & ECF_LOOPING_CONST_OR_PURE))
5259 continue;
5261 /* Get the callee and its summary. */
5262 enum availability avail;
5263 callee = callee_edge->callee->ultimate_alias_target
5264 (&avail, cur);
5266 /* It is not necessary to re-process calls outside of the
5267 SCC component. */
5268 if (iteration > 0
5269 && (!callee->aux
5270 || ((struct ipa_dfs_info *)cur->aux)->scc_no
5271 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
5272 continue;
5274 escape_summary *sum = escape_summaries->get (callee_edge);
5275 if (!sum)
5276 continue;
5278 if (dump_file)
5279 fprintf (dump_file, " Call to %s\n",
5280 callee_edge->callee->dump_name ());
5282 if (avail <= AVAIL_INTERPOSABLE
5283 || callee_edge->call_stmt_cannot_inline_p)
5285 else
5287 if (cur_summary)
5288 callee_summary = optimization_summaries->get (callee);
5289 if (cur_summary_lto)
5290 callee_summary_lto = summaries_lto->get (callee);
5292 changed |= modref_merge_call_site_flags
5293 (sum, cur_summary, cur_summary_lto,
5294 callee_summary, callee_summary_lto,
5295 node->decl,
5296 callee_edge,
5297 caller_ecf_flags,
5298 ecf_flags,
5299 callee->binds_to_current_def_p ());
5300 if (dump_file && changed)
5302 if (cur_summary)
5303 cur_summary->dump (dump_file);
5304 if (cur_summary_lto)
5305 cur_summary_lto->dump (dump_file);
5309 iteration++;
5311 if (dump_file)
5312 fprintf (dump_file,
5313 "Propagation of flags finished in %i iterations\n", iteration);
5316 } /* ANON namespace. */
5318 /* Call EDGE was inlined; merge summary from callee to the caller. */
5320 void
5321 ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
5323 if (!summaries && !summaries_lto)
5324 return;
5326 struct cgraph_node *to = (edge->caller->inlined_to
5327 ? edge->caller->inlined_to : edge->caller);
5328 class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
5329 class modref_summary_lto *to_info_lto = summaries_lto
5330 ? summaries_lto->get (to) : NULL;
5332 if (!to_info && !to_info_lto)
5334 if (summaries)
5335 summaries->remove (edge->callee);
5336 if (summaries_lto)
5337 summaries_lto->remove (edge->callee);
5338 remove_modref_edge_summaries (edge->callee);
5339 return;
5342 class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
5343 : NULL;
5344 class modref_summary_lto *callee_info_lto
5345 = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
5346 int flags = flags_from_decl_or_type (edge->callee->decl);
5347 /* Combine in outer flags. */
5348 cgraph_node *n;
5349 for (n = edge->caller; n->inlined_to; n = n->callers->caller)
5350 flags |= flags_from_decl_or_type (n->decl);
5351 flags |= flags_from_decl_or_type (n->decl);
5352 bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
5354 if (!callee_info && to_info)
5356 if (!(flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
5357 to_info->loads->collapse ();
5358 if (!ignore_stores)
5359 to_info->stores->collapse ();
5361 if (!callee_info_lto && to_info_lto)
5363 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5364 to_info_lto->loads->collapse ();
5365 if (!ignore_stores)
5366 to_info_lto->stores->collapse ();
5368 /* Merge side effects and non-determinism.
5369 PURE/CONST flags makes functions deterministic and if there is
5370 no LOOPING_CONST_OR_PURE they also have no side effects. */
5371 if (!(flags & (ECF_CONST | ECF_PURE))
5372 || (flags & ECF_LOOPING_CONST_OR_PURE))
5374 bool set_nondeterministic
5375 = !ignore_nondeterminism_p
5376 (edge->caller->decl, flags,
5377 TREE_TYPE (edge->callee->decl));
5378 if (to_info)
5380 if (!callee_info || callee_info->side_effects)
5381 to_info->side_effects = true;
5382 if (set_nondeterministic)
5383 to_info->nondeterministic = true;
5385 if (to_info_lto)
5387 if (!callee_info_lto || callee_info_lto->side_effects)
5388 to_info_lto->side_effects = true;
5389 if (set_nondeterministic)
5390 to_info_lto->nondeterministic = true;
5393 if (callee_info || callee_info_lto)
5395 auto_vec <modref_parm_map, 32> parm_map;
5396 modref_parm_map chain_map;
5397 /* TODO: Once we get jump functions for static chains we could
5398 compute parm_index. */
5400 compute_parm_map (edge, &parm_map);
5402 if (!ignore_stores)
5404 if (to_info && callee_info)
5405 to_info->stores->merge (to->decl, callee_info->stores, &parm_map,
5406 &chain_map, false);
5407 if (to_info_lto && callee_info_lto)
5408 to_info_lto->stores->merge (to->decl, callee_info_lto->stores,
5409 &parm_map, &chain_map, false);
5411 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5413 if (to_info && callee_info)
5414 to_info->loads->merge (to->decl, callee_info->loads, &parm_map,
5415 &chain_map, false);
5416 if (to_info_lto && callee_info_lto)
5417 to_info_lto->loads->merge (to->decl, callee_info_lto->loads,
5418 &parm_map, &chain_map, false);
5422 /* Now merge escape summaries.
5423 For every escape to the callee we need to merge callee flags
5424 and remap callee's escapes. */
5425 class escape_summary *sum = escape_summaries->get (edge);
5426 int max_escape = -1;
5427 escape_entry *ee;
5428 unsigned int i;
5430 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
5431 FOR_EACH_VEC_ELT (sum->esc, i, ee)
5432 if ((int)ee->arg > max_escape)
5433 max_escape = ee->arg;
5435 auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
5436 emap.safe_grow (max_escape + 1, true);
5437 for (i = 0; (int)i < max_escape + 1; i++)
5438 emap[i] = vNULL;
5440 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
5441 FOR_EACH_VEC_ELT (sum->esc, i, ee)
5443 bool needed = false;
5444 int implicit_flags = implicit_eaf_flags_for_edge_and_arg
5445 (edge, flags, ignore_stores,
5446 ee->arg);
5447 if (!ee->direct)
5448 implicit_flags = deref_flags (implicit_flags, ignore_stores);
5449 if (to_info && (int)to_info->arg_flags.length () > ee->parm_index)
5451 int flags = callee_info
5452 && callee_info->arg_flags.length () > ee->arg
5453 ? callee_info->arg_flags[ee->arg] : 0;
5454 if (!ee->direct)
5455 flags = deref_flags (flags, ignore_stores);
5456 flags |= ee->min_flags | implicit_flags;
5457 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5458 ? to_info->retslot_flags
5459 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5460 ? to_info->static_chain_flags
5461 : to_info->arg_flags[ee->parm_index];
5462 f &= flags;
5463 if (f)
5464 needed = true;
5466 if (to_info_lto
5467 && (int)to_info_lto->arg_flags.length () > ee->parm_index)
5469 int flags = callee_info_lto
5470 && callee_info_lto->arg_flags.length () > ee->arg
5471 ? callee_info_lto->arg_flags[ee->arg] : 0;
5472 if (!ee->direct)
5473 flags = deref_flags (flags, ignore_stores);
5474 flags |= ee->min_flags | implicit_flags;
5475 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5476 ? to_info_lto->retslot_flags
5477 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5478 ? to_info_lto->static_chain_flags
5479 : to_info_lto->arg_flags[ee->parm_index];
5480 f &= flags;
5481 if (f)
5482 needed = true;
5484 struct escape_map entry = {ee->parm_index, ee->direct};
5485 if (needed)
5486 emap[ee->arg].safe_push (entry);
5488 update_escape_summary (edge->callee, emap, ignore_stores);
5489 for (i = 0; (int)i < max_escape + 1; i++)
5490 emap[i].release ();
5491 if (sum)
5492 escape_summaries->remove (edge);
5494 if (summaries)
5496 if (to_info && !to_info->useful_p (flags))
5498 if (dump_file)
5499 fprintf (dump_file, "Removed mod-ref summary for %s\n",
5500 to->dump_name ());
5501 summaries->remove (to);
5502 to_info = NULL;
5504 else if (to_info && dump_file)
5506 if (dump_file)
5507 fprintf (dump_file, "Updated mod-ref summary for %s\n",
5508 to->dump_name ());
5509 to_info->dump (dump_file);
5511 if (callee_info)
5512 summaries->remove (edge->callee);
5514 if (summaries_lto)
5516 if (to_info_lto && !to_info_lto->useful_p (flags))
5518 if (dump_file)
5519 fprintf (dump_file, "Removed mod-ref summary for %s\n",
5520 to->dump_name ());
5521 summaries_lto->remove (to);
5522 to_info_lto = NULL;
5524 else if (to_info_lto && dump_file)
5526 if (dump_file)
5527 fprintf (dump_file, "Updated mod-ref summary for %s\n",
5528 to->dump_name ());
5529 to_info_lto->dump (dump_file);
5531 if (callee_info_lto)
5532 summaries_lto->remove (edge->callee);
5534 if (!to_info && !to_info_lto)
5535 remove_modref_edge_summaries (to);
5536 return;
5539 /* Run the IPA pass. This will take a function's summaries and calls and
5540 construct new summaries which represent a transitive closure. So that
5541 summary of an analyzed function contains information about the loads and
5542 stores that the function or any function that it calls does. */
5544 unsigned int
5545 pass_ipa_modref::execute (function *)
5547 if (!summaries && !summaries_lto)
5548 return 0;
5549 bool pureconst = false;
5551 if (optimization_summaries)
5552 ggc_delete (optimization_summaries);
5553 optimization_summaries = summaries;
5554 summaries = NULL;
5556 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
5557 symtab->cgraph_count);
5558 int order_pos;
5559 order_pos = ipa_reduced_postorder (order, true, ignore_edge);
5560 int i;
5562 /* Iterate over all strongly connected components in post-order. */
5563 for (i = 0; i < order_pos; i++)
5565 /* Get the component's representative. That's just any node in the
5566 component from which we can traverse the entire component. */
5567 struct cgraph_node *component_node = order[i];
5569 if (dump_file)
5570 fprintf (dump_file, "\n\nStart of SCC component\n");
5572 pureconst |= modref_propagate_in_scc (component_node);
5573 modref_propagate_flags_in_scc (component_node);
5574 if (optimization_summaries)
5575 for (struct cgraph_node *cur = component_node; cur;
5576 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5577 if (modref_summary *sum = optimization_summaries->get (cur))
5578 sum->finalize (cur->decl);
5579 if (dump_file)
5580 modref_propagate_dump_scc (component_node);
5582 cgraph_node *node;
5583 FOR_EACH_FUNCTION (node)
5584 update_signature (node);
5585 if (summaries_lto)
5586 ((modref_summaries_lto *)summaries_lto)->propagated = true;
5587 ipa_free_postorder_info ();
5588 free (order);
5589 delete fnspec_summaries;
5590 fnspec_summaries = NULL;
5591 delete escape_summaries;
5592 escape_summaries = NULL;
5594 /* If we possibly made constructors const/pure we may need to remove
5595 them. */
5596 return pureconst ? TODO_remove_functions : 0;
5599 /* Summaries must stay alive until end of compilation. */
5601 void
5602 ipa_modref_cc_finalize ()
5604 if (optimization_summaries)
5605 ggc_delete (optimization_summaries);
5606 optimization_summaries = NULL;
5607 if (summaries_lto)
5608 ggc_delete (summaries_lto);
5609 summaries_lto = NULL;
5610 if (fnspec_summaries)
5611 delete fnspec_summaries;
5612 fnspec_summaries = NULL;
5613 if (escape_summaries)
5614 delete escape_summaries;
5615 escape_summaries = NULL;
5618 /* Return true if call is known to perform no memory reads. */
5620 bool
5621 ipa_modref_callee_reads_no_memory_p (gcall *call)
5623 if (gimple_call_flags (call) & ECF_CONST)
5624 return true;
5625 attr_fnspec fnspec = gimple_call_fnspec (call);
5626 if (fnspec.known_p ()
5627 && !fnspec.global_memory_read_p ())
5629 bool found = false;
5630 for (unsigned int i = 0; i < gimple_call_num_args (call) && !found; i++)
5631 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
5633 else if (!fnspec.arg_specified_p (i)
5634 || fnspec.arg_maybe_read_p (i))
5635 found = true;
5636 if (!found)
5637 return true;
5640 /* For interposed calls we can not be sure that the other, semantically
5641 equivalent body, will not perform some redundant load from memory
5642 that may become undefined if we optimize out some stores. */
5643 bool interposed;
5644 modref_summary *sum = get_modref_function_summary (call, &interposed);
5645 if (sum && !interposed && !sum->global_memory_read && !sum->loads)
5646 return true;
5647 return false;
5650 #include "gt-ipa-modref.h"