c++: Implement modules ABI for vtable emissions
[official-gcc.git] / gcc / ipa-modref.cc
bloba5adce8ea396ac6313e35a5cc918eaa4ed252af0
1 /* Search for references that a functions loads or stores.
2 Copyright (C) 2020-2024 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 | ECF_NOVOPS))
338 return ((!side_effects || !nondeterministic)
339 && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
340 if (loads && !loads->every_base)
341 return true;
342 else
343 kills.release ();
344 if (ecf_flags & ECF_PURE)
345 return ((!side_effects || !nondeterministic)
346 && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
347 return stores && !stores->every_base;
350 /* Single function summary used for LTO. */
352 typedef modref_tree <tree> modref_records_lto;
353 struct GTY(()) modref_summary_lto
355 /* Load and stores in functions using types rather then alias sets.
357 This is necessary to make the information streamable for LTO but is also
358 more verbose and thus more likely to hit the limits. */
359 modref_records_lto *loads;
360 modref_records_lto *stores;
361 auto_vec<modref_access_node> GTY((skip)) kills;
362 auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
363 eaf_flags_t retslot_flags;
364 eaf_flags_t static_chain_flags;
365 unsigned writes_errno : 1;
366 unsigned side_effects : 1;
367 unsigned nondeterministic : 1;
368 unsigned calls_interposable : 1;
370 modref_summary_lto ();
371 ~modref_summary_lto ();
372 void dump (FILE *);
373 bool useful_p (int ecf_flags, bool check_flags = true);
376 /* Summary for a single function which this pass produces. */
378 modref_summary_lto::modref_summary_lto ()
379 : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
380 writes_errno (false), side_effects (false), nondeterministic (false),
381 calls_interposable (false)
385 modref_summary_lto::~modref_summary_lto ()
387 if (loads)
388 ggc_delete (loads);
389 if (stores)
390 ggc_delete (stores);
394 /* Return true if lto summary is potentially useful for optimization.
395 If CHECK_FLAGS is false assume that arg_flags are useful. */
397 bool
398 modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
400 if (arg_flags.length () && !check_flags)
401 return true;
402 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
403 return true;
404 arg_flags.release ();
405 if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
406 return true;
407 if (check_flags
408 && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
409 return true;
410 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
411 return ((!side_effects || !nondeterministic)
412 && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
413 if (loads && !loads->every_base)
414 return true;
415 else
416 kills.release ();
417 if (ecf_flags & ECF_PURE)
418 return ((!side_effects || !nondeterministic)
419 && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
420 return stores && !stores->every_base;
423 /* Dump records TT to OUT. */
425 static void
426 dump_records (modref_records *tt, FILE *out)
428 if (tt->every_base)
430 fprintf (out, " Every base\n");
431 return;
433 size_t i;
434 modref_base_node <alias_set_type> *n;
435 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
437 fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
438 if (n->every_ref)
440 fprintf (out, " Every ref\n");
441 continue;
443 size_t j;
444 modref_ref_node <alias_set_type> *r;
445 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
447 fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
448 if (r->every_access)
450 fprintf (out, " Every access\n");
451 continue;
453 size_t k;
454 modref_access_node *a;
455 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
457 fprintf (out, " access:");
458 a->dump (out);
464 /* Dump records TT to OUT. */
466 static void
467 dump_lto_records (modref_records_lto *tt, FILE *out)
469 if (tt->every_base)
471 fprintf (out, " Every base\n");
472 return;
474 size_t i;
475 modref_base_node <tree> *n;
476 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
478 fprintf (out, " Base %i:", (int)i);
479 print_generic_expr (out, n->base);
480 fprintf (out, " (alias set %i)\n",
481 n->base ? get_alias_set (n->base) : 0);
482 if (n->every_ref)
484 fprintf (out, " Every ref\n");
485 continue;
487 size_t j;
488 modref_ref_node <tree> *r;
489 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
491 fprintf (out, " Ref %i:", (int)j);
492 print_generic_expr (out, r->ref);
493 fprintf (out, " (alias set %i)\n",
494 r->ref ? get_alias_set (r->ref) : 0);
495 if (r->every_access)
497 fprintf (out, " Every access\n");
498 continue;
500 size_t k;
501 modref_access_node *a;
502 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
504 fprintf (out, " access:");
505 a->dump (out);
511 /* Dump all escape points of NODE to OUT. */
513 static void
514 dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
516 int i = 0;
517 if (!escape_summaries)
518 return;
519 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
521 class escape_summary *sum = escape_summaries->get (e);
522 if (sum)
524 fprintf (out, "%*sIndirect call %i in %s escapes:",
525 depth, "", i, node->dump_name ());
526 sum->dump (out);
528 i++;
530 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
532 if (!e->inline_failed)
533 dump_modref_edge_summaries (out, e->callee, depth + 1);
534 class escape_summary *sum = escape_summaries->get (e);
535 if (sum)
537 fprintf (out, "%*sCall %s->%s escapes:", depth, "",
538 node->dump_name (), e->callee->dump_name ());
539 sum->dump (out);
541 class fnspec_summary *fsum = fnspec_summaries->get (e);
542 if (fsum)
544 fprintf (out, "%*sCall %s->%s fnspec: %s\n", depth, "",
545 node->dump_name (), e->callee->dump_name (),
546 fsum->fnspec);
551 /* Remove all call edge summaries associated with NODE. */
553 static void
554 remove_modref_edge_summaries (cgraph_node *node)
556 if (!escape_summaries)
557 return;
558 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
559 escape_summaries->remove (e);
560 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
562 if (!e->inline_failed)
563 remove_modref_edge_summaries (e->callee);
564 escape_summaries->remove (e);
565 fnspec_summaries->remove (e);
569 /* Dump summary. */
571 void
572 modref_summary::dump (FILE *out) const
574 if (loads)
576 fprintf (out, " loads:\n");
577 dump_records (loads, out);
579 if (stores)
581 fprintf (out, " stores:\n");
582 dump_records (stores, out);
584 if (kills.length ())
586 fprintf (out, " kills:\n");
587 for (auto kill : kills)
589 fprintf (out, " ");
590 kill.dump (out);
593 if (writes_errno)
594 fprintf (out, " Writes errno\n");
595 if (side_effects)
596 fprintf (out, " Side effects\n");
597 if (nondeterministic)
598 fprintf (out, " Nondeterministic\n");
599 if (calls_interposable)
600 fprintf (out, " Calls interposable\n");
601 if (global_memory_read)
602 fprintf (out, " Global memory read\n");
603 if (global_memory_written)
604 fprintf (out, " Global memory written\n");
605 if (try_dse)
606 fprintf (out, " Try dse\n");
607 if (arg_flags.length ())
609 for (unsigned int i = 0; i < arg_flags.length (); i++)
610 if (arg_flags[i])
612 fprintf (out, " parm %i flags:", i);
613 dump_eaf_flags (out, arg_flags[i]);
616 if (retslot_flags)
618 fprintf (out, " Retslot flags:");
619 dump_eaf_flags (out, retslot_flags);
621 if (static_chain_flags)
623 fprintf (out, " Static chain flags:");
624 dump_eaf_flags (out, static_chain_flags);
628 /* Dump summary. */
630 void
631 modref_summary_lto::dump (FILE *out)
633 fprintf (out, " loads:\n");
634 dump_lto_records (loads, out);
635 fprintf (out, " stores:\n");
636 dump_lto_records (stores, out);
637 if (kills.length ())
639 fprintf (out, " kills:\n");
640 for (auto kill : kills)
642 fprintf (out, " ");
643 kill.dump (out);
646 if (writes_errno)
647 fprintf (out, " Writes errno\n");
648 if (side_effects)
649 fprintf (out, " Side effects\n");
650 if (nondeterministic)
651 fprintf (out, " Nondeterministic\n");
652 if (calls_interposable)
653 fprintf (out, " Calls interposable\n");
654 if (arg_flags.length ())
656 for (unsigned int i = 0; i < arg_flags.length (); i++)
657 if (arg_flags[i])
659 fprintf (out, " parm %i flags:", i);
660 dump_eaf_flags (out, arg_flags[i]);
663 if (retslot_flags)
665 fprintf (out, " Retslot flags:");
666 dump_eaf_flags (out, retslot_flags);
668 if (static_chain_flags)
670 fprintf (out, " Static chain flags:");
671 dump_eaf_flags (out, static_chain_flags);
675 /* Called after summary is produced and before it is used by local analysis.
676 Can be called multiple times in case summary needs to update signature.
677 FUN is decl of function summary is attached to. */
678 void
679 modref_summary::finalize (tree fun)
681 global_memory_read = !loads || loads->global_access_p ();
682 global_memory_written = !stores || stores->global_access_p ();
684 /* We can do DSE if we know function has no side effects and
685 we can analyze all stores. Disable dse if there are too many
686 stores to try. */
687 if (side_effects || global_memory_written || writes_errno)
688 try_dse = false;
689 else
691 try_dse = true;
692 size_t i, j, k;
693 int num_tests = 0, max_tests
694 = opt_for_fn (fun, param_modref_max_tests);
695 modref_base_node <alias_set_type> *base_node;
696 modref_ref_node <alias_set_type> *ref_node;
697 modref_access_node *access_node;
698 FOR_EACH_VEC_SAFE_ELT (stores->bases, i, base_node)
700 if (base_node->every_ref)
702 try_dse = false;
703 break;
705 FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
707 if (base_node->every_ref)
709 try_dse = false;
710 break;
712 FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
713 if (num_tests++ > max_tests
714 || !access_node->parm_offset_known)
716 try_dse = false;
717 break;
719 if (!try_dse)
720 break;
722 if (!try_dse)
723 break;
726 if (loads->every_base)
727 load_accesses = 1;
728 else
730 load_accesses = 0;
731 for (auto base_node : loads->bases)
733 if (base_node->every_ref)
734 load_accesses++;
735 else
736 for (auto ref_node : base_node->refs)
737 if (ref_node->every_access)
738 load_accesses++;
739 else
740 load_accesses += ref_node->accesses->length ();
745 /* Get function summary for FUNC if it exists, return NULL otherwise. */
747 modref_summary *
748 get_modref_function_summary (cgraph_node *func)
750 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
751 if (!optimization_summaries)
752 return NULL;
754 /* A single function body may be represented by multiple symbols with
755 different visibility. For example, if FUNC is an interposable alias,
756 we don't want to return anything, even if we have summary for the target
757 function. */
758 enum availability avail;
759 func = func->ultimate_alias_target
760 (&avail, current_function_decl ?
761 cgraph_node::get (current_function_decl) : NULL);
762 if (avail <= AVAIL_INTERPOSABLE)
763 return NULL;
765 modref_summary *r = optimization_summaries->get (func);
766 return r;
769 /* Get function summary for CALL if it exists, return NULL otherwise.
770 If non-null set interposed to indicate whether function may not
771 bind to current def. In this case sometimes loads from function
772 needs to be ignored. */
774 modref_summary *
775 get_modref_function_summary (gcall *call, bool *interposed)
777 tree callee = gimple_call_fndecl (call);
778 if (!callee)
779 return NULL;
780 struct cgraph_node *node = cgraph_node::get (callee);
781 if (!node)
782 return NULL;
783 modref_summary *r = get_modref_function_summary (node);
784 if (interposed && r)
785 *interposed = r->calls_interposable
786 || !node->binds_to_current_def_p ();
787 return r;
791 namespace {
793 /* Return true if ECF flags says that nondeterminism can be ignored. */
795 static bool
796 ignore_nondeterminism_p (tree caller, int flags)
798 if (flags & (ECF_CONST | ECF_PURE))
799 return true;
800 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
801 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
802 return true;
803 return false;
806 /* Return true if ECF flags says that return value can be ignored. */
808 static bool
809 ignore_retval_p (tree caller, int flags)
811 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
812 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
813 return true;
814 return false;
817 /* Return true if ECF flags says that stores can be ignored. */
819 static bool
820 ignore_stores_p (tree caller, int flags)
822 if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
823 return true;
824 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
825 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
826 return true;
827 return false;
830 /* Determine parm_map for PTR which is supposed to be a pointer. */
832 modref_parm_map
833 parm_map_for_ptr (tree op)
835 bool offset_known;
836 poly_int64 offset;
837 struct modref_parm_map parm_map;
838 gcall *call;
840 parm_map.parm_offset_known = false;
841 parm_map.parm_offset = 0;
843 offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
844 if (TREE_CODE (op) == SSA_NAME
845 && SSA_NAME_IS_DEFAULT_DEF (op)
846 && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
848 int index = 0;
850 if (cfun->static_chain_decl
851 && op == ssa_default_def (cfun, cfun->static_chain_decl))
852 index = MODREF_STATIC_CHAIN_PARM;
853 else
854 for (tree t = DECL_ARGUMENTS (current_function_decl);
855 t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
856 index++;
857 parm_map.parm_index = index;
858 parm_map.parm_offset_known = offset_known;
859 parm_map.parm_offset = offset;
861 else if (points_to_local_or_readonly_memory_p (op))
862 parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM;
863 /* Memory allocated in the function is not visible to caller before the
864 call and thus we do not need to record it as load/stores/kills. */
865 else if (TREE_CODE (op) == SSA_NAME
866 && (call = dyn_cast<gcall *>(SSA_NAME_DEF_STMT (op))) != NULL
867 && gimple_call_flags (call) & ECF_MALLOC)
868 parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM;
869 else
870 parm_map.parm_index = MODREF_UNKNOWN_PARM;
871 return parm_map;
874 /* Return true if ARG with EAF flags FLAGS can not make any caller's parameter
875 used (if LOAD is true we check loads, otherwise stores). */
877 static bool
878 verify_arg (tree arg, int flags, bool load)
880 if (flags & EAF_UNUSED)
881 return true;
882 if (load && (flags & EAF_NO_DIRECT_READ))
883 return true;
884 if (!load
885 && (flags & (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER))
886 == (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER))
887 return true;
888 if (is_gimple_constant (arg))
889 return true;
890 if (DECL_P (arg) && TREE_READONLY (arg))
891 return true;
892 if (TREE_CODE (arg) == ADDR_EXPR)
894 tree t = get_base_address (TREE_OPERAND (arg, 0));
895 if (is_gimple_constant (t))
896 return true;
897 if (DECL_P (t)
898 && (TREE_READONLY (t) || TREE_CODE (t) == FUNCTION_DECL))
899 return true;
901 return false;
904 /* Return true if STMT may access memory that is pointed to by parameters
905 of caller and which is not seen as an escape by PTA.
906 CALLEE_ECF_FLAGS are ECF flags of callee. If LOAD is true then by access
907 we mean load, otherwise we mean store. */
909 static bool
910 may_access_nonescaping_parm_p (gcall *call, int callee_ecf_flags, bool load)
912 int implicit_flags = 0;
914 if (ignore_stores_p (current_function_decl, callee_ecf_flags))
915 implicit_flags |= ignore_stores_eaf_flags;
916 if (callee_ecf_flags & ECF_PURE)
917 implicit_flags |= implicit_pure_eaf_flags;
918 if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
919 implicit_flags |= implicit_const_eaf_flags;
920 if (gimple_call_chain (call)
921 && !verify_arg (gimple_call_chain (call),
922 gimple_call_static_chain_flags (call) | implicit_flags,
923 load))
924 return true;
925 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
926 if (!verify_arg (gimple_call_arg (call, i),
927 gimple_call_arg_flags (call, i) | implicit_flags,
928 load))
929 return true;
930 return false;
934 /* Analyze memory accesses (loads, stores and kills) performed
935 by the function. Set also side_effects, calls_interposable
936 and nondeterminism flags. */
938 class modref_access_analysis
940 public:
941 modref_access_analysis (bool ipa, modref_summary *summary,
942 modref_summary_lto *summary_lto)
943 : m_summary (summary), m_summary_lto (summary_lto), m_ipa (ipa)
946 void analyze ();
947 private:
948 bool set_side_effects ();
949 bool set_nondeterministic ();
950 static modref_access_node get_access (ao_ref *ref);
951 static void record_access (modref_records *, ao_ref *, modref_access_node &);
952 static void record_access_lto (modref_records_lto *, ao_ref *,
953 modref_access_node &a);
954 bool record_access_p (tree);
955 bool record_unknown_load ();
956 bool record_unknown_store ();
957 bool record_global_memory_load ();
958 bool record_global_memory_store ();
959 bool merge_call_side_effects (gimple *, modref_summary *,
960 cgraph_node *, bool);
961 modref_access_node get_access_for_fnspec (gcall *, attr_fnspec &,
962 unsigned int, modref_parm_map &);
963 void process_fnspec (gcall *);
964 void analyze_call (gcall *);
965 static bool analyze_load (gimple *, tree, tree, void *);
966 static bool analyze_store (gimple *, tree, tree, void *);
967 void analyze_stmt (gimple *, bool);
968 void propagate ();
970 /* Summary being computed.
971 We work either with m_summary or m_summary_lto. Never on both. */
972 modref_summary *m_summary;
973 modref_summary_lto *m_summary_lto;
974 /* Recursive calls needs simplistic dataflow after analysis finished.
975 Collect all calls into this vector during analysis and later process
976 them in propagate. */
977 auto_vec <gimple *, 32> m_recursive_calls;
978 /* ECF flags of function being analyzed. */
979 int m_ecf_flags;
980 /* True if IPA propagation will be done later. */
981 bool m_ipa;
982 /* Set true if statement currently analyze is known to be
983 executed each time function is called. */
984 bool m_always_executed;
987 /* Set side_effects flag and return if something changed. */
989 bool
990 modref_access_analysis::set_side_effects ()
992 bool changed = false;
994 if (m_summary && !m_summary->side_effects)
996 m_summary->side_effects = true;
997 changed = true;
999 if (m_summary_lto && !m_summary_lto->side_effects)
1001 m_summary_lto->side_effects = true;
1002 changed = true;
1004 return changed;
1007 /* Set nondeterministic flag and return if something changed. */
1009 bool
1010 modref_access_analysis::set_nondeterministic ()
1012 bool changed = false;
1014 if (m_summary && !m_summary->nondeterministic)
1016 m_summary->side_effects = m_summary->nondeterministic = true;
1017 changed = true;
1019 if (m_summary_lto && !m_summary_lto->nondeterministic)
1021 m_summary_lto->side_effects = m_summary_lto->nondeterministic = true;
1022 changed = true;
1024 return changed;
1027 /* Construct modref_access_node from REF. */
1029 modref_access_node
1030 modref_access_analysis::get_access (ao_ref *ref)
1032 tree base;
1034 base = ao_ref_base (ref);
1035 modref_access_node a = {ref->offset, ref->size, ref->max_size,
1036 0, MODREF_UNKNOWN_PARM, false, 0};
1037 if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
1039 tree memref = base;
1040 modref_parm_map m = parm_map_for_ptr (TREE_OPERAND (base, 0));
1042 a.parm_index = m.parm_index;
1043 if (a.parm_index != MODREF_UNKNOWN_PARM && TREE_CODE (memref) == MEM_REF)
1045 a.parm_offset_known
1046 = wi::to_poly_wide (TREE_OPERAND
1047 (memref, 1)).to_shwi (&a.parm_offset);
1048 if (a.parm_offset_known && m.parm_offset_known)
1049 a.parm_offset += m.parm_offset;
1050 else
1051 a.parm_offset_known = false;
1054 else
1055 a.parm_index = MODREF_UNKNOWN_PARM;
1056 return a;
1059 /* Record access into the modref_records data structure. */
1061 void
1062 modref_access_analysis::record_access (modref_records *tt,
1063 ao_ref *ref,
1064 modref_access_node &a)
1066 alias_set_type base_set = !flag_strict_aliasing
1067 || !flag_ipa_strict_aliasing ? 0
1068 : ao_ref_base_alias_set (ref);
1069 alias_set_type ref_set = !flag_strict_aliasing
1070 || !flag_ipa_strict_aliasing ? 0
1071 : (ao_ref_alias_set (ref));
1072 if (dump_file)
1074 fprintf (dump_file, " - Recording base_set=%i ref_set=%i ",
1075 base_set, ref_set);
1076 a.dump (dump_file);
1078 tt->insert (current_function_decl, base_set, ref_set, a, false);
1081 /* IPA version of record_access_tree. */
1083 void
1084 modref_access_analysis::record_access_lto (modref_records_lto *tt, ao_ref *ref,
1085 modref_access_node &a)
1087 /* get_alias_set sometimes use different type to compute the alias set
1088 than TREE_TYPE (base). Do same adjustments. */
1089 tree base_type = NULL_TREE, ref_type = NULL_TREE;
1090 if (flag_strict_aliasing && flag_ipa_strict_aliasing)
1092 tree base;
1094 base = ref->ref;
1095 while (handled_component_p (base))
1096 base = TREE_OPERAND (base, 0);
1098 base_type = reference_alias_ptr_type_1 (&base);
1100 if (!base_type)
1101 base_type = TREE_TYPE (base);
1102 else
1103 base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
1104 ? NULL_TREE : TREE_TYPE (base_type);
1106 tree ref_expr = ref->ref;
1107 ref_type = reference_alias_ptr_type_1 (&ref_expr);
1109 if (!ref_type)
1110 ref_type = TREE_TYPE (ref_expr);
1111 else
1112 ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
1113 ? NULL_TREE : TREE_TYPE (ref_type);
1115 /* Sanity check that we are in sync with what get_alias_set does. */
1116 gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
1117 || get_alias_set (base_type)
1118 == ao_ref_base_alias_set (ref));
1119 gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
1120 || get_alias_set (ref_type)
1121 == ao_ref_alias_set (ref));
1123 /* Do not bother to record types that have no meaningful alias set.
1124 Also skip variably modified types since these go to local streams. */
1125 if (base_type && (!get_alias_set (base_type)
1126 || variably_modified_type_p (base_type, NULL_TREE)))
1127 base_type = NULL_TREE;
1128 if (ref_type && (!get_alias_set (ref_type)
1129 || variably_modified_type_p (ref_type, NULL_TREE)))
1130 ref_type = NULL_TREE;
1132 if (dump_file)
1134 fprintf (dump_file, " - Recording base type:");
1135 print_generic_expr (dump_file, base_type);
1136 fprintf (dump_file, " (alias set %i) ref type:",
1137 base_type ? get_alias_set (base_type) : 0);
1138 print_generic_expr (dump_file, ref_type);
1139 fprintf (dump_file, " (alias set %i) ",
1140 ref_type ? get_alias_set (ref_type) : 0);
1141 a.dump (dump_file);
1144 tt->insert (current_function_decl, base_type, ref_type, a, false);
1147 /* Returns true if and only if we should store the access to EXPR.
1148 Some accesses, e.g. loads from automatic variables, are not interesting. */
1150 bool
1151 modref_access_analysis::record_access_p (tree expr)
1153 if (TREE_THIS_VOLATILE (expr))
1155 if (dump_file)
1156 fprintf (dump_file, " (volatile; marking nondeterministic) ");
1157 set_nondeterministic ();
1159 if (cfun->can_throw_non_call_exceptions
1160 && tree_could_throw_p (expr))
1162 if (dump_file)
1163 fprintf (dump_file, " (can throw; marking side effects) ");
1164 set_side_effects ();
1167 if (refs_local_or_readonly_memory_p (expr))
1169 if (dump_file)
1170 fprintf (dump_file, " - Read-only or local, ignoring.\n");
1171 return false;
1173 return true;
1176 /* Collapse loads and return true if something changed. */
1178 bool
1179 modref_access_analysis::record_unknown_load ()
1181 bool changed = false;
1183 if (m_summary && !m_summary->loads->every_base)
1185 m_summary->loads->collapse ();
1186 changed = true;
1188 if (m_summary_lto && !m_summary_lto->loads->every_base)
1190 m_summary_lto->loads->collapse ();
1191 changed = true;
1193 return changed;
1196 /* Collapse loads and return true if something changed. */
1198 bool
1199 modref_access_analysis::record_unknown_store ()
1201 bool changed = false;
1203 if (m_summary && !m_summary->stores->every_base)
1205 m_summary->stores->collapse ();
1206 changed = true;
1208 if (m_summary_lto && !m_summary_lto->stores->every_base)
1210 m_summary_lto->stores->collapse ();
1211 changed = true;
1213 return changed;
1216 /* Record unknown load from global memory. */
1218 bool
1219 modref_access_analysis::record_global_memory_load ()
1221 bool changed = false;
1222 modref_access_node a = {0, -1, -1,
1223 0, MODREF_GLOBAL_MEMORY_PARM, false, 0};
1225 if (m_summary && !m_summary->loads->every_base)
1226 changed |= m_summary->loads->insert (current_function_decl, 0, 0, a, false);
1227 if (m_summary_lto && !m_summary_lto->loads->every_base)
1228 changed |= m_summary_lto->loads->insert (current_function_decl,
1229 0, 0, a, false);
1230 return changed;
1233 /* Record unknown store from global memory. */
1235 bool
1236 modref_access_analysis::record_global_memory_store ()
1238 bool changed = false;
1239 modref_access_node a = {0, -1, -1,
1240 0, MODREF_GLOBAL_MEMORY_PARM, false, 0};
1242 if (m_summary && !m_summary->stores->every_base)
1243 changed |= m_summary->stores->insert (current_function_decl,
1244 0, 0, a, false);
1245 if (m_summary_lto && !m_summary_lto->stores->every_base)
1246 changed |= m_summary_lto->stores->insert (current_function_decl,
1247 0, 0, a, false);
1248 return changed;
1251 /* Merge side effects of call STMT to function with CALLEE_SUMMARY.
1252 Return true if something changed.
1253 If IGNORE_STORES is true, do not merge stores.
1254 If RECORD_ADJUSTMENTS is true cap number of adjustments to
1255 a given access to make dataflow finite. */
1257 bool
1258 modref_access_analysis::merge_call_side_effects
1259 (gimple *stmt, modref_summary *callee_summary,
1260 cgraph_node *callee_node, bool record_adjustments)
1262 gcall *call = as_a <gcall *> (stmt);
1263 int flags = gimple_call_flags (call);
1265 /* Nothing to do for non-looping cont functions. */
1266 if ((flags & (ECF_CONST | ECF_NOVOPS))
1267 && !(flags & ECF_LOOPING_CONST_OR_PURE))
1268 return false;
1270 bool changed = false;
1272 if (dump_file)
1273 fprintf (dump_file, " - Merging side effects of %s\n",
1274 callee_node->dump_name ());
1276 /* Merge side effects and non-determinism.
1277 PURE/CONST flags makes functions deterministic and if there is
1278 no LOOPING_CONST_OR_PURE they also have no side effects. */
1279 if (!(flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE))
1280 || (flags & ECF_LOOPING_CONST_OR_PURE))
1282 if (!m_summary->side_effects && callee_summary->side_effects)
1284 if (dump_file)
1285 fprintf (dump_file, " - merging side effects.\n");
1286 m_summary->side_effects = true;
1287 changed = true;
1289 if (!m_summary->nondeterministic && callee_summary->nondeterministic
1290 && !ignore_nondeterminism_p (current_function_decl, flags))
1292 if (dump_file)
1293 fprintf (dump_file, " - merging nondeterministic.\n");
1294 m_summary->nondeterministic = true;
1295 changed = true;
1299 /* For const functions we are done. */
1300 if (flags & (ECF_CONST | ECF_NOVOPS))
1301 return changed;
1303 /* Merge calls_interposable flags. */
1304 if (!m_summary->calls_interposable && callee_summary->calls_interposable)
1306 if (dump_file)
1307 fprintf (dump_file, " - merging calls interposable.\n");
1308 m_summary->calls_interposable = true;
1309 changed = true;
1312 if (!callee_node->binds_to_current_def_p () && !m_summary->calls_interposable)
1314 if (dump_file)
1315 fprintf (dump_file, " - May be interposed.\n");
1316 m_summary->calls_interposable = true;
1317 changed = true;
1320 /* Now merge the actual load, store and kill vectors. For this we need
1321 to compute map translating new parameters to old. */
1322 if (dump_file)
1323 fprintf (dump_file, " Parm map:");
1325 auto_vec <modref_parm_map, 32> parm_map;
1326 parm_map.safe_grow_cleared (gimple_call_num_args (call), true);
1327 for (unsigned i = 0; i < gimple_call_num_args (call); i++)
1329 parm_map[i] = parm_map_for_ptr (gimple_call_arg (call, i));
1330 if (dump_file)
1332 fprintf (dump_file, " %i", parm_map[i].parm_index);
1333 if (parm_map[i].parm_offset_known)
1335 fprintf (dump_file, " offset:");
1336 print_dec ((poly_int64)parm_map[i].parm_offset,
1337 dump_file, SIGNED);
1342 modref_parm_map chain_map;
1343 if (gimple_call_chain (call))
1345 chain_map = parm_map_for_ptr (gimple_call_chain (call));
1346 if (dump_file)
1348 fprintf (dump_file, "static chain %i", chain_map.parm_index);
1349 if (chain_map.parm_offset_known)
1351 fprintf (dump_file, " offset:");
1352 print_dec ((poly_int64)chain_map.parm_offset,
1353 dump_file, SIGNED);
1357 if (dump_file)
1358 fprintf (dump_file, "\n");
1360 /* Kills can me merged in only if we know the function is going to be
1361 always executed. */
1362 if (m_always_executed
1363 && callee_summary->kills.length ()
1364 && (!cfun->can_throw_non_call_exceptions
1365 || !stmt_could_throw_p (cfun, call)))
1367 /* Watch for self recursive updates. */
1368 auto_vec<modref_access_node, 32> saved_kills;
1370 saved_kills.reserve_exact (callee_summary->kills.length ());
1371 saved_kills.splice (callee_summary->kills);
1372 for (auto kill : saved_kills)
1374 if (kill.parm_index >= (int)parm_map.length ())
1375 continue;
1376 modref_parm_map &m
1377 = kill.parm_index == MODREF_STATIC_CHAIN_PARM
1378 ? chain_map
1379 : parm_map[kill.parm_index];
1380 if (m.parm_index == MODREF_LOCAL_MEMORY_PARM
1381 || m.parm_index == MODREF_UNKNOWN_PARM
1382 || m.parm_index == MODREF_RETSLOT_PARM
1383 || !m.parm_offset_known)
1384 continue;
1385 modref_access_node n = kill;
1386 n.parm_index = m.parm_index;
1387 n.parm_offset += m.parm_offset;
1388 if (modref_access_node::insert_kill (m_summary->kills, n,
1389 record_adjustments))
1390 changed = true;
1394 /* Merge in loads. */
1395 changed |= m_summary->loads->merge (current_function_decl,
1396 callee_summary->loads,
1397 &parm_map, &chain_map,
1398 record_adjustments,
1399 !may_access_nonescaping_parm_p
1400 (call, flags, true));
1401 /* Merge in stores. */
1402 if (!ignore_stores_p (current_function_decl, flags))
1404 changed |= m_summary->stores->merge (current_function_decl,
1405 callee_summary->stores,
1406 &parm_map, &chain_map,
1407 record_adjustments,
1408 !may_access_nonescaping_parm_p
1409 (call, flags, false));
1410 if (!m_summary->writes_errno
1411 && callee_summary->writes_errno)
1413 m_summary->writes_errno = true;
1414 changed = true;
1417 return changed;
1420 /* Return access mode for argument I of call STMT with FNSPEC. */
1422 modref_access_node
1423 modref_access_analysis::get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
1424 unsigned int i,
1425 modref_parm_map &map)
1427 tree size = NULL_TREE;
1428 unsigned int size_arg;
1430 if (!fnspec.arg_specified_p (i))
1432 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
1433 size = gimple_call_arg (call, size_arg);
1434 else if (fnspec.arg_access_size_given_by_type_p (i))
1436 tree callee = gimple_call_fndecl (call);
1437 tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
1439 for (unsigned int p = 0; p < i; p++)
1440 t = TREE_CHAIN (t);
1441 size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
1443 modref_access_node a = {0, -1, -1,
1444 map.parm_offset, map.parm_index,
1445 map.parm_offset_known, 0};
1446 poly_int64 size_hwi;
1447 if (size
1448 && poly_int_tree_p (size, &size_hwi)
1449 && coeffs_in_range_p (size_hwi, 0,
1450 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
1452 a.size = -1;
1453 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
1455 return a;
1457 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1458 If IGNORE_STORES is true ignore them.
1459 Return false if no useful summary can be produced. */
1461 void
1462 modref_access_analysis::process_fnspec (gcall *call)
1464 int flags = gimple_call_flags (call);
1466 /* PURE/CONST flags makes functions deterministic and if there is
1467 no LOOPING_CONST_OR_PURE they also have no side effects. */
1468 if (!(flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE))
1469 || (flags & ECF_LOOPING_CONST_OR_PURE)
1470 || (cfun->can_throw_non_call_exceptions
1471 && stmt_could_throw_p (cfun, call)))
1473 set_side_effects ();
1474 if (!ignore_nondeterminism_p (current_function_decl, flags))
1475 set_nondeterministic ();
1478 /* For const functions we are done. */
1479 if (flags & (ECF_CONST | ECF_NOVOPS))
1480 return;
1482 attr_fnspec fnspec = gimple_call_fnspec (call);
1483 /* If there is no fnpec we know nothing about loads & stores. */
1484 if (!fnspec.known_p ())
1486 if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
1487 fprintf (dump_file, " Builtin with no fnspec: %s\n",
1488 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
1489 if (!ignore_stores_p (current_function_decl, flags))
1491 if (!may_access_nonescaping_parm_p (call, flags, false))
1492 record_global_memory_store ();
1493 else
1494 record_unknown_store ();
1495 if (!may_access_nonescaping_parm_p (call, flags, true))
1496 record_global_memory_load ();
1497 else
1498 record_unknown_load ();
1500 else
1502 if (!may_access_nonescaping_parm_p (call, flags, true))
1503 record_global_memory_load ();
1504 else
1505 record_unknown_load ();
1507 return;
1509 /* Process fnspec. */
1510 if (fnspec.global_memory_read_p ())
1512 if (may_access_nonescaping_parm_p (call, flags, true))
1513 record_unknown_load ();
1514 else
1515 record_global_memory_load ();
1517 else
1519 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1520 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1522 else if (!fnspec.arg_specified_p (i)
1523 || fnspec.arg_maybe_read_p (i))
1525 modref_parm_map map = parm_map_for_ptr
1526 (gimple_call_arg (call, i));
1528 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
1529 continue;
1530 if (map.parm_index == MODREF_UNKNOWN_PARM)
1532 record_unknown_load ();
1533 break;
1535 modref_access_node a = get_access_for_fnspec (call, fnspec, i, map);
1536 if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1537 continue;
1538 if (m_summary)
1539 m_summary->loads->insert (current_function_decl, 0, 0, a, false);
1540 if (m_summary_lto)
1541 m_summary_lto->loads->insert (current_function_decl, 0, 0, a,
1542 false);
1545 if (ignore_stores_p (current_function_decl, flags))
1546 return;
1547 if (fnspec.global_memory_written_p ())
1549 if (may_access_nonescaping_parm_p (call, flags, false))
1550 record_unknown_store ();
1551 else
1552 record_global_memory_store ();
1554 else
1556 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1557 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1559 else if (!fnspec.arg_specified_p (i)
1560 || fnspec.arg_maybe_written_p (i))
1562 modref_parm_map map = parm_map_for_ptr
1563 (gimple_call_arg (call, i));
1565 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
1566 continue;
1567 if (map.parm_index == MODREF_UNKNOWN_PARM)
1569 record_unknown_store ();
1570 break;
1572 modref_access_node a = get_access_for_fnspec (call, fnspec, i, map);
1573 if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1574 continue;
1575 if (m_summary)
1576 m_summary->stores->insert (current_function_decl, 0, 0, a, false);
1577 if (m_summary_lto)
1578 m_summary_lto->stores->insert (current_function_decl,
1579 0, 0, a, false);
1581 if (fnspec.errno_maybe_written_p () && flag_errno_math)
1583 if (m_summary)
1584 m_summary->writes_errno = true;
1585 if (m_summary_lto)
1586 m_summary_lto->writes_errno = true;
1591 /* Analyze function call STMT in function F.
1592 Remember recursive calls in RECURSIVE_CALLS. */
1594 void
1595 modref_access_analysis::analyze_call (gcall *stmt)
1597 /* Check flags on the function call. In certain cases, analysis can be
1598 simplified. */
1599 int flags = gimple_call_flags (stmt);
1601 if (dump_file)
1603 fprintf (dump_file, " - Analyzing call:");
1604 print_gimple_stmt (dump_file, stmt, 0);
1607 if ((flags & (ECF_CONST | ECF_NOVOPS))
1608 && !(flags & ECF_LOOPING_CONST_OR_PURE))
1610 if (dump_file)
1611 fprintf (dump_file,
1612 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1613 "except for args.\n");
1614 return;
1617 /* Next, we try to get the callee's function declaration. The goal is to
1618 merge their summary with ours. */
1619 tree callee = gimple_call_fndecl (stmt);
1621 /* Check if this is an indirect call. */
1622 if (!callee)
1624 if (dump_file)
1625 fprintf (dump_file, gimple_call_internal_p (stmt)
1626 ? " - Internal call" : " - Indirect call.\n");
1627 process_fnspec (stmt);
1628 return;
1630 /* We only need to handle internal calls in IPA mode. */
1631 gcc_checking_assert (!m_summary_lto && !m_ipa);
1633 struct cgraph_node *callee_node = cgraph_node::get_create (callee);
1635 /* If this is a recursive call, the target summary is the same as ours, so
1636 there's nothing to do. */
1637 if (recursive_call_p (current_function_decl, callee))
1639 m_recursive_calls.safe_push (stmt);
1640 set_side_effects ();
1641 if (dump_file)
1642 fprintf (dump_file, " - Skipping recursive call.\n");
1643 return;
1646 gcc_assert (callee_node != NULL);
1648 /* Get the function symbol and its availability. */
1649 enum availability avail;
1650 callee_node = callee_node->function_symbol (&avail);
1651 bool looping;
1652 if (builtin_safe_for_const_function_p (&looping, callee))
1654 if (looping)
1655 set_side_effects ();
1656 if (dump_file)
1657 fprintf (dump_file, " - Builtin is safe for const.\n");
1658 return;
1660 if (avail <= AVAIL_INTERPOSABLE)
1662 if (dump_file)
1663 fprintf (dump_file,
1664 " - Function availability <= AVAIL_INTERPOSABLE.\n");
1665 process_fnspec (stmt);
1666 return;
1669 /* Get callee's modref summary. As above, if there's no summary, we either
1670 have to give up or, if stores are ignored, we can just purge loads. */
1671 modref_summary *callee_summary = optimization_summaries->get (callee_node);
1672 if (!callee_summary)
1674 if (dump_file)
1675 fprintf (dump_file, " - No modref summary available for callee.\n");
1676 process_fnspec (stmt);
1677 return;
1680 merge_call_side_effects (stmt, callee_summary, callee_node, false);
1682 return;
1685 /* Helper for analyze_stmt. */
1687 bool
1688 modref_access_analysis::analyze_load (gimple *, tree, tree op, void *data)
1690 modref_access_analysis *t = (modref_access_analysis *)data;
1692 if (dump_file)
1694 fprintf (dump_file, " - Analyzing load: ");
1695 print_generic_expr (dump_file, op);
1696 fprintf (dump_file, "\n");
1699 if (!t->record_access_p (op))
1700 return false;
1702 ao_ref r;
1703 ao_ref_init (&r, op);
1704 modref_access_node a = get_access (&r);
1705 if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1706 return false;
1708 if (t->m_summary)
1709 t->record_access (t->m_summary->loads, &r, a);
1710 if (t->m_summary_lto)
1711 t->record_access_lto (t->m_summary_lto->loads, &r, a);
1712 return false;
1715 /* Helper for analyze_stmt. */
1717 bool
1718 modref_access_analysis::analyze_store (gimple *stmt, tree, tree op, void *data)
1720 modref_access_analysis *t = (modref_access_analysis *)data;
1722 if (dump_file)
1724 fprintf (dump_file, " - Analyzing store: ");
1725 print_generic_expr (dump_file, op);
1726 fprintf (dump_file, "\n");
1729 if (!t->record_access_p (op))
1730 return false;
1732 ao_ref r;
1733 ao_ref_init (&r, op);
1734 modref_access_node a = get_access (&r);
1735 if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1736 return false;
1738 if (t->m_summary)
1739 t->record_access (t->m_summary->stores, &r, a);
1740 if (t->m_summary_lto)
1741 t->record_access_lto (t->m_summary_lto->stores, &r, a);
1742 if (t->m_always_executed
1743 && a.useful_for_kill_p ()
1744 && (!cfun->can_throw_non_call_exceptions
1745 || !stmt_could_throw_p (cfun, stmt)))
1747 if (dump_file)
1748 fprintf (dump_file, " - Recording kill\n");
1749 if (t->m_summary)
1750 modref_access_node::insert_kill (t->m_summary->kills, a, false);
1751 if (t->m_summary_lto)
1752 modref_access_node::insert_kill (t->m_summary_lto->kills, a, false);
1754 return false;
1757 /* Analyze statement STMT of function F.
1758 If IPA is true do not merge in side effects of calls. */
1760 void
1761 modref_access_analysis::analyze_stmt (gimple *stmt, bool always_executed)
1763 m_always_executed = always_executed;
1764 /* In general we can not ignore clobbers because they are barriers for code
1765 motion, however after inlining it is safe to do because local optimization
1766 passes do not consider clobbers from other functions.
1767 Similar logic is in ipa-pure-const.cc. */
1768 if ((m_ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1770 if (always_executed && record_access_p (gimple_assign_lhs (stmt)))
1772 ao_ref r;
1773 ao_ref_init (&r, gimple_assign_lhs (stmt));
1774 modref_access_node a = get_access (&r);
1775 if (a.useful_for_kill_p ())
1777 if (dump_file)
1778 fprintf (dump_file, " - Recording kill\n");
1779 if (m_summary)
1780 modref_access_node::insert_kill (m_summary->kills, a, false);
1781 if (m_summary_lto)
1782 modref_access_node::insert_kill (m_summary_lto->kills,
1783 a, false);
1786 return;
1789 /* Analyze all loads and stores in STMT. */
1790 walk_stmt_load_store_ops (stmt, this,
1791 analyze_load, analyze_store);
1793 switch (gimple_code (stmt))
1795 case GIMPLE_ASM:
1796 if (gimple_asm_volatile_p (as_a <gasm *> (stmt)))
1797 set_nondeterministic ();
1798 if (cfun->can_throw_non_call_exceptions
1799 && stmt_could_throw_p (cfun, stmt))
1800 set_side_effects ();
1801 /* If the ASM statement does not read nor write memory, there's nothing
1802 to do. Otherwise just give up. */
1803 if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1804 return;
1805 if (dump_file)
1806 fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1807 "which clobbers memory.\n");
1808 record_unknown_load ();
1809 record_unknown_store ();
1810 return;
1811 case GIMPLE_CALL:
1812 if (!m_ipa || gimple_call_internal_p (stmt))
1813 analyze_call (as_a <gcall *> (stmt));
1814 else
1816 attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1818 if (fnspec.known_p ()
1819 && (!fnspec.global_memory_read_p ()
1820 || !fnspec.global_memory_written_p ()))
1822 cgraph_edge *e = cgraph_node::get
1823 (current_function_decl)->get_edge (stmt);
1824 if (e->callee)
1826 fnspec_summaries->get_create (e)->fnspec
1827 = xstrdup (fnspec.get_str ());
1828 if (dump_file)
1829 fprintf (dump_file, " Recorded fnspec %s\n",
1830 fnspec.get_str ());
1834 return;
1835 default:
1836 if (cfun->can_throw_non_call_exceptions
1837 && stmt_could_throw_p (cfun, stmt))
1838 set_side_effects ();
1839 return;
1843 /* Propagate load/stores across recursive calls. */
1845 void
1846 modref_access_analysis::propagate ()
1848 if (m_ipa && m_summary)
1849 return;
1851 bool changed = true;
1852 bool first = true;
1853 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1855 m_always_executed = false;
1856 while (changed && m_summary->useful_p (m_ecf_flags, false))
1858 changed = false;
1859 for (unsigned i = 0; i < m_recursive_calls.length (); i++)
1861 changed |= merge_call_side_effects (m_recursive_calls[i], m_summary,
1862 fnode, !first);
1864 first = false;
1868 /* Analyze function. */
1870 void
1871 modref_access_analysis::analyze ()
1873 m_ecf_flags = flags_from_decl_or_type (current_function_decl);
1874 bool summary_useful = true;
1876 /* Analyze each statement in each basic block of the function. If the
1877 statement cannot be analyzed (for any reason), the entire function cannot
1878 be analyzed by modref. */
1879 basic_block bb;
1880 bitmap always_executed_bbs = find_always_executed_bbs (cfun, true);
1881 FOR_EACH_BB_FN (bb, cfun)
1883 gimple_stmt_iterator si;
1884 bool always_executed = bitmap_bit_p (always_executed_bbs, bb->index);
1886 for (si = gsi_start_nondebug_after_labels_bb (bb);
1887 !gsi_end_p (si); gsi_next_nondebug (&si))
1889 /* NULL memory accesses terminates BB. These accesses are known
1890 to trip undefined behavior. gimple-ssa-isolate-paths turns them
1891 to volatile accesses and adds builtin_trap call which would
1892 confuse us otherwise. */
1893 if (infer_nonnull_range_by_dereference (gsi_stmt (si),
1894 null_pointer_node))
1896 if (dump_file)
1897 fprintf (dump_file, " - NULL memory access; terminating BB\n");
1898 if (flag_non_call_exceptions)
1899 set_side_effects ();
1900 break;
1902 analyze_stmt (gsi_stmt (si), always_executed);
1904 /* Avoid doing useless work. */
1905 if ((!m_summary || !m_summary->useful_p (m_ecf_flags, false))
1906 && (!m_summary_lto
1907 || !m_summary_lto->useful_p (m_ecf_flags, false)))
1909 summary_useful = false;
1910 break;
1912 if (always_executed
1913 && stmt_can_throw_external (cfun, gsi_stmt (si)))
1914 always_executed = false;
1916 if (!summary_useful)
1917 break;
1919 /* In non-IPA mode we need to perform iterative dataflow on recursive calls.
1920 This needs to be done after all other side effects are computed. */
1921 if (summary_useful)
1923 if (!m_ipa)
1924 propagate ();
1925 if (m_summary && !m_summary->side_effects && !finite_function_p ())
1926 m_summary->side_effects = true;
1927 if (m_summary_lto && !m_summary_lto->side_effects
1928 && !finite_function_p ())
1929 m_summary_lto->side_effects = true;
1931 BITMAP_FREE (always_executed_bbs);
1934 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1936 bool
1937 memory_access_to (tree op, tree ssa_name)
1939 tree base = get_base_address (op);
1940 if (!base)
1941 return false;
1942 if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1943 return false;
1944 return TREE_OPERAND (base, 0) == ssa_name;
1947 /* Consider statement val = *arg.
1948 return EAF flags of ARG that can be determined from EAF flags of VAL
1949 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1950 all stores to VAL, i.e. when handling noreturn function. */
1952 static int
1953 deref_flags (int flags, bool ignore_stores)
1955 /* Dereference is also a direct read but dereferenced value does not
1956 yield any other direct use. */
1957 int ret = EAF_NO_DIRECT_CLOBBER | EAF_NO_DIRECT_ESCAPE
1958 | EAF_NOT_RETURNED_DIRECTLY;
1959 /* If argument is unused just account for
1960 the read involved in dereference. */
1961 if (flags & EAF_UNUSED)
1962 ret |= EAF_NO_INDIRECT_READ | EAF_NO_INDIRECT_CLOBBER
1963 | EAF_NO_INDIRECT_ESCAPE;
1964 else
1966 /* Direct or indirect accesses leads to indirect accesses. */
1967 if (((flags & EAF_NO_DIRECT_CLOBBER)
1968 && (flags & EAF_NO_INDIRECT_CLOBBER))
1969 || ignore_stores)
1970 ret |= EAF_NO_INDIRECT_CLOBBER;
1971 if (((flags & EAF_NO_DIRECT_ESCAPE)
1972 && (flags & EAF_NO_INDIRECT_ESCAPE))
1973 || ignore_stores)
1974 ret |= EAF_NO_INDIRECT_ESCAPE;
1975 if ((flags & EAF_NO_DIRECT_READ)
1976 && (flags & EAF_NO_INDIRECT_READ))
1977 ret |= EAF_NO_INDIRECT_READ;
1978 if ((flags & EAF_NOT_RETURNED_DIRECTLY)
1979 && (flags & EAF_NOT_RETURNED_INDIRECTLY))
1980 ret |= EAF_NOT_RETURNED_INDIRECTLY;
1982 return ret;
1986 /* Description of an escape point: a call which affects flags of a given
1987 SSA name. */
1989 struct escape_point
1991 /* Value escapes to this call. */
1992 gcall *call;
1993 /* Argument it escapes to. */
1994 int arg;
1995 /* Flags already known about the argument (this can save us from recording
1996 escape points if local analysis did good job already). */
1997 eaf_flags_t min_flags;
1998 /* Does value escape directly or indirectly? */
1999 bool direct;
2002 /* Lattice used during the eaf flags analysis dataflow. For a given SSA name
2003 we aim to compute its flags and escape points. We also use the lattice
2004 to dynamically build dataflow graph to propagate on. */
2006 class modref_lattice
2008 public:
2009 /* EAF flags of the SSA name. */
2010 eaf_flags_t flags;
2011 /* Used during DFS walk to mark names where final value was determined
2012 without need for dataflow. */
2013 bool known;
2014 /* Used during DFS walk to mark open vertices (for cycle detection). */
2015 bool open;
2016 /* Set during DFS walk for names that needs dataflow propagation. */
2017 bool do_dataflow;
2018 /* Used during the iterative dataflow. */
2019 bool changed;
2021 /* When doing IPA analysis we can not merge in callee escape points;
2022 Only remember them and do the merging at IPA propagation time. */
2023 vec <escape_point, va_heap, vl_ptr> escape_points;
2025 /* Representation of a graph for dataflow. This graph is built on-demand
2026 using modref_eaf_analysis::analyze_ssa and later solved by
2027 modref_eaf_analysis::propagate.
2028 Each edge represents the fact that flags of current lattice should be
2029 propagated to lattice of SSA_NAME. */
2030 struct propagate_edge
2032 int ssa_name;
2033 bool deref;
2035 vec <propagate_edge, va_heap, vl_ptr> propagate_to;
2037 void init ();
2038 void release ();
2039 bool merge (const modref_lattice &with);
2040 bool merge (int flags);
2041 bool merge_deref (const modref_lattice &with, bool ignore_stores);
2042 bool merge_direct_load ();
2043 bool merge_direct_store ();
2044 bool add_escape_point (gcall *call, int arg, int min_flags, bool diret);
2045 void dump (FILE *out, int indent = 0) const;
2048 /* Lattices are saved to vectors, so keep them PODs. */
2049 void
2050 modref_lattice::init ()
2052 /* All flags we track. */
2053 int f = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
2054 | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE
2055 | EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ
2056 | EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY
2057 | EAF_UNUSED;
2058 flags = f;
2059 /* Check that eaf_flags_t is wide enough to hold all flags. */
2060 gcc_checking_assert (f == flags);
2061 open = true;
2062 known = false;
2065 /* Release memory. */
2066 void
2067 modref_lattice::release ()
2069 escape_points.release ();
2070 propagate_to.release ();
2073 /* Dump lattice to OUT; indent with INDENT spaces. */
2075 void
2076 modref_lattice::dump (FILE *out, int indent) const
2078 dump_eaf_flags (out, flags);
2079 if (escape_points.length ())
2081 fprintf (out, "%*sEscapes:\n", indent, "");
2082 for (unsigned int i = 0; i < escape_points.length (); i++)
2084 fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
2085 escape_points[i].arg,
2086 escape_points[i].direct ? "direct" : "indirect");
2087 dump_eaf_flags (out, escape_points[i].min_flags, false);
2088 fprintf (out, " in call ");
2089 print_gimple_stmt (out, escape_points[i].call, 0);
2094 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
2095 point exists. */
2097 bool
2098 modref_lattice::add_escape_point (gcall *call, int arg, int min_flags,
2099 bool direct)
2101 escape_point *ep;
2102 unsigned int i;
2104 /* If we already determined flags to be bad enough,
2105 we do not need to record. */
2106 if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
2107 return false;
2109 FOR_EACH_VEC_ELT (escape_points, i, ep)
2110 if (ep->call == call && ep->arg == arg && ep->direct == direct)
2112 if ((ep->min_flags & min_flags) == min_flags)
2113 return false;
2114 ep->min_flags &= min_flags;
2115 return true;
2117 /* Give up if max escape points is met. */
2118 if ((int)escape_points.length () > param_modref_max_escape_points)
2120 if (dump_file)
2121 fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
2122 merge (0);
2123 return true;
2125 escape_point new_ep = {call, arg, min_flags, direct};
2126 escape_points.safe_push (new_ep);
2127 return true;
2130 /* Merge in flags from F. */
2131 bool
2132 modref_lattice::merge (int f)
2134 if (f & EAF_UNUSED)
2135 return false;
2136 /* Check that flags seems sane: if function does not read the parameter
2137 it can not access it indirectly. */
2138 gcc_checking_assert (!(f & EAF_NO_DIRECT_READ)
2139 || ((f & EAF_NO_INDIRECT_READ)
2140 && (f & EAF_NO_INDIRECT_CLOBBER)
2141 && (f & EAF_NO_INDIRECT_ESCAPE)
2142 && (f & EAF_NOT_RETURNED_INDIRECTLY)));
2143 if ((flags & f) != flags)
2145 flags &= f;
2146 /* Prune obviously useless flags;
2147 We do not have ECF_FLAGS handy which is not big problem since
2148 we will do final flags cleanup before producing summary.
2149 Merging should be fast so it can work well with dataflow. */
2150 flags = remove_useless_eaf_flags (flags, 0, false);
2151 if (!flags)
2152 escape_points.release ();
2153 return true;
2155 return false;
2158 /* Merge in WITH. Return true if anything changed. */
2160 bool
2161 modref_lattice::merge (const modref_lattice &with)
2163 if (!with.known)
2164 do_dataflow = true;
2166 bool changed = merge (with.flags);
2168 if (!flags)
2169 return changed;
2170 for (unsigned int i = 0; i < with.escape_points.length (); i++)
2171 changed |= add_escape_point (with.escape_points[i].call,
2172 with.escape_points[i].arg,
2173 with.escape_points[i].min_flags,
2174 with.escape_points[i].direct);
2175 return changed;
2178 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
2179 stores. Return true if anything changed. */
2181 bool
2182 modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
2184 if (!with.known)
2185 do_dataflow = true;
2187 bool changed = merge (deref_flags (with.flags, ignore_stores));
2189 if (!flags)
2190 return changed;
2191 for (unsigned int i = 0; i < with.escape_points.length (); i++)
2193 int min_flags = with.escape_points[i].min_flags;
2195 if (with.escape_points[i].direct)
2196 min_flags = deref_flags (min_flags, ignore_stores);
2197 else if (ignore_stores)
2198 min_flags |= ignore_stores_eaf_flags;
2199 changed |= add_escape_point (with.escape_points[i].call,
2200 with.escape_points[i].arg,
2201 min_flags,
2202 false);
2204 return changed;
2207 /* Merge in flags for direct load. */
2209 bool
2210 modref_lattice::merge_direct_load ()
2212 return merge (~(EAF_UNUSED | EAF_NO_DIRECT_READ));
2215 /* Merge in flags for direct store. */
2217 bool
2218 modref_lattice::merge_direct_store ()
2220 return merge (~(EAF_UNUSED | EAF_NO_DIRECT_CLOBBER));
2223 /* Analyzer of EAF flags.
2224 This is generally dataflow problem over the SSA graph, however we only
2225 care about flags of few selected ssa names (arguments, return slot and
2226 static chain). So we first call analyze_ssa_name on all relevant names
2227 and perform a DFS walk to discover SSA names where flags needs to be
2228 determined. For acyclic graphs we try to determine final flags during
2229 this walk. Once cycles or recursion depth is met we enlist SSA names
2230 for dataflow which is done by propagate call.
2232 After propagation the flags can be obtained using get_ssa_name_flags. */
2234 class modref_eaf_analysis
2236 public:
2237 /* Mark NAME as relevant for analysis. */
2238 void analyze_ssa_name (tree name, bool deferred = false);
2239 /* Dataflow solver. */
2240 void propagate ();
2241 /* Return flags computed earlier for NAME. */
2242 int get_ssa_name_flags (tree name)
2244 int version = SSA_NAME_VERSION (name);
2245 gcc_checking_assert (m_lattice[version].known);
2246 return m_lattice[version].flags;
2248 /* In IPA mode this will record all escape points
2249 determined for NAME to PARM_IDNEX. Flags are minimal
2250 flags known. */
2251 void record_escape_points (tree name, int parm_index, int flags);
2252 modref_eaf_analysis (bool ipa)
2254 m_ipa = ipa;
2255 m_depth = 0;
2256 m_lattice.safe_grow_cleared (num_ssa_names, true);
2258 ~modref_eaf_analysis ()
2260 gcc_checking_assert (!m_depth);
2261 if (m_ipa || m_names_to_propagate.length ())
2262 for (unsigned int i = 0; i < num_ssa_names; i++)
2263 m_lattice[i].release ();
2265 private:
2266 /* If true, we produce analysis for IPA mode. In this case escape points are
2267 collected. */
2268 bool m_ipa;
2269 /* Depth of recursion of analyze_ssa_name. */
2270 int m_depth;
2271 /* Propagation lattice for individual ssa names. */
2272 auto_vec<modref_lattice> m_lattice;
2273 auto_vec<tree> m_deferred_names;
2274 auto_vec<int> m_names_to_propagate;
2276 void merge_with_ssa_name (tree dest, tree src, bool deref);
2277 void merge_call_lhs_flags (gcall *call, int arg, tree name, bool direct,
2278 bool deref);
2282 /* Call statements may return their parameters. Consider argument number
2283 ARG of USE_STMT and determine flags that can needs to be cleared
2284 in case pointer possibly indirectly references from ARG I is returned.
2285 If DIRECT is true consider direct returns and if INDIRECT consider
2286 indirect returns.
2287 LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
2288 ARG is set to -1 for static chain. */
2290 void
2291 modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg,
2292 tree name, bool direct,
2293 bool indirect)
2295 int index = SSA_NAME_VERSION (name);
2296 bool returned_directly = false;
2298 /* If there is no return value, no flags are affected. */
2299 if (!gimple_call_lhs (call))
2300 return;
2302 /* If we know that function returns given argument and it is not ARG
2303 we can still be happy. */
2304 if (arg >= 0)
2306 int flags = gimple_call_return_flags (call);
2307 if (flags & ERF_RETURNS_ARG)
2309 if ((flags & ERF_RETURN_ARG_MASK) == arg)
2310 returned_directly = true;
2311 else
2312 return;
2315 /* Make ERF_RETURNS_ARG overwrite EAF_UNUSED. */
2316 if (returned_directly)
2318 direct = true;
2319 indirect = false;
2321 /* If value is not returned at all, do nothing. */
2322 else if (!direct && !indirect)
2323 return;
2325 /* If return value is SSA name determine its flags. */
2326 if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
2328 tree lhs = gimple_call_lhs (call);
2329 if (direct)
2330 merge_with_ssa_name (name, lhs, false);
2331 if (indirect)
2332 merge_with_ssa_name (name, lhs, true);
2334 /* In the case of memory store we can do nothing. */
2335 else if (!direct)
2336 m_lattice[index].merge (deref_flags (0, false));
2337 else
2338 m_lattice[index].merge (0);
2341 /* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
2342 into flags for caller, update LATTICE of corresponding
2343 argument if needed. */
2345 static int
2346 callee_to_caller_flags (int call_flags, bool ignore_stores,
2347 modref_lattice &lattice)
2349 /* call_flags is about callee returning a value
2350 that is not the same as caller returning it. */
2351 call_flags |= EAF_NOT_RETURNED_DIRECTLY
2352 | EAF_NOT_RETURNED_INDIRECTLY;
2353 if (!ignore_stores && !(call_flags & EAF_UNUSED))
2355 /* If value escapes we are no longer able to track what happens
2356 with it because we can read it from the escaped location
2357 anytime. */
2358 if (!(call_flags & EAF_NO_DIRECT_ESCAPE))
2359 lattice.merge (0);
2360 else if (!(call_flags & EAF_NO_INDIRECT_ESCAPE))
2361 lattice.merge (~(EAF_NOT_RETURNED_INDIRECTLY
2362 | EAF_NO_DIRECT_READ
2363 | EAF_NO_INDIRECT_READ
2364 | EAF_NO_INDIRECT_CLOBBER
2365 | EAF_UNUSED));
2367 else
2368 call_flags |= ignore_stores_eaf_flags;
2369 return call_flags;
2372 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
2373 LATTICE is an array of modref_lattices.
2374 DEPTH is a recursion depth used to make debug output prettier.
2375 If IPA is true we analyze for IPA propagation (and thus call escape points
2376 are processed later) */
2378 void
2379 modref_eaf_analysis::analyze_ssa_name (tree name, bool deferred)
2381 imm_use_iterator ui;
2382 gimple *use_stmt;
2383 int index = SSA_NAME_VERSION (name);
2385 if (!deferred)
2387 /* See if value is already computed. */
2388 if (m_lattice[index].known || m_lattice[index].do_dataflow)
2389 return;
2390 if (m_lattice[index].open)
2392 if (dump_file)
2393 fprintf (dump_file,
2394 "%*sCycle in SSA graph\n",
2395 m_depth * 4, "");
2396 return;
2398 /* Recursion guard. */
2399 m_lattice[index].init ();
2400 if (m_depth == param_modref_max_depth)
2402 if (dump_file)
2403 fprintf (dump_file,
2404 "%*sMax recursion depth reached; postponing\n",
2405 m_depth * 4, "");
2406 m_deferred_names.safe_push (name);
2407 return;
2411 if (dump_file)
2413 fprintf (dump_file,
2414 "%*sAnalyzing flags of ssa name: ", m_depth * 4, "");
2415 print_generic_expr (dump_file, name);
2416 fprintf (dump_file, "\n");
2419 FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
2421 if (m_lattice[index].flags == 0)
2422 break;
2423 if (is_gimple_debug (use_stmt))
2424 continue;
2425 if (dump_file)
2427 fprintf (dump_file, "%*s Analyzing stmt: ", m_depth * 4, "");
2428 print_gimple_stmt (dump_file, use_stmt, 0);
2430 /* If we see a direct non-debug use, clear unused bit.
2431 All dereferences should be accounted below using deref_flags. */
2432 m_lattice[index].merge (~EAF_UNUSED);
2434 /* Gimple return may load the return value.
2435 Returning name counts as an use by tree-ssa-structalias.cc */
2436 if (greturn *ret = dyn_cast <greturn *> (use_stmt))
2438 /* Returning through return slot is seen as memory write earlier. */
2439 if (DECL_RESULT (current_function_decl)
2440 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2442 else if (gimple_return_retval (ret) == name)
2443 m_lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED_DIRECTLY
2444 | EAF_NOT_RETURNED_DIRECTLY));
2445 else if (memory_access_to (gimple_return_retval (ret), name))
2447 m_lattice[index].merge_direct_load ();
2448 m_lattice[index].merge (~(EAF_UNUSED
2449 | EAF_NOT_RETURNED_INDIRECTLY));
2452 /* Account for LHS store, arg loads and flags from callee function. */
2453 else if (gcall *call = dyn_cast <gcall *> (use_stmt))
2455 tree callee = gimple_call_fndecl (call);
2457 /* IPA PTA internally it treats calling a function as "writing" to
2458 the argument space of all functions the function pointer points to
2459 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
2460 is on since that would allow propagation of this from -fno-ipa-pta
2461 to -fipa-pta functions. */
2462 if (gimple_call_fn (use_stmt) == name)
2463 m_lattice[index].merge (~(EAF_NO_DIRECT_CLOBBER | EAF_UNUSED));
2465 /* Recursion would require bit of propagation; give up for now. */
2466 if (callee && !m_ipa && recursive_call_p (current_function_decl,
2467 callee))
2468 m_lattice[index].merge (0);
2469 else
2471 int ecf_flags = gimple_call_flags (call);
2472 bool ignore_stores = ignore_stores_p (current_function_decl,
2473 ecf_flags);
2474 bool ignore_retval = ignore_retval_p (current_function_decl,
2475 ecf_flags);
2477 /* Handle *name = func (...). */
2478 if (gimple_call_lhs (call)
2479 && memory_access_to (gimple_call_lhs (call), name))
2481 m_lattice[index].merge_direct_store ();
2482 /* Return slot optimization passes address of
2483 LHS to callee via hidden parameter and this
2484 may make LHS to escape. See PR 98499. */
2485 if (gimple_call_return_slot_opt_p (call)
2486 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
2488 int call_flags = gimple_call_retslot_flags (call);
2489 bool isretslot = false;
2491 if (DECL_RESULT (current_function_decl)
2492 && DECL_BY_REFERENCE
2493 (DECL_RESULT (current_function_decl)))
2494 isretslot = ssa_default_def
2495 (cfun,
2496 DECL_RESULT (current_function_decl))
2497 == name;
2499 /* Passing returnslot to return slot is special because
2500 not_returned and escape has same meaning.
2501 However passing arg to return slot is different. If
2502 the callee's return slot is returned it means that
2503 arg is written to itself which is an escape.
2504 Since we do not track the memory it is written to we
2505 need to give up on analyzing it. */
2506 if (!isretslot)
2508 if (!(call_flags & (EAF_NOT_RETURNED_DIRECTLY
2509 | EAF_UNUSED)))
2510 m_lattice[index].merge (0);
2511 else gcc_checking_assert
2512 (call_flags & (EAF_NOT_RETURNED_INDIRECTLY
2513 | EAF_UNUSED));
2514 call_flags = callee_to_caller_flags
2515 (call_flags, false,
2516 m_lattice[index]);
2518 m_lattice[index].merge (call_flags);
2522 if (gimple_call_chain (call)
2523 && (gimple_call_chain (call) == name))
2525 int call_flags = gimple_call_static_chain_flags (call);
2526 if (!ignore_retval && !(call_flags & EAF_UNUSED))
2527 merge_call_lhs_flags
2528 (call, -1, name,
2529 !(call_flags & EAF_NOT_RETURNED_DIRECTLY),
2530 !(call_flags & EAF_NOT_RETURNED_INDIRECTLY));
2531 call_flags = callee_to_caller_flags
2532 (call_flags, ignore_stores,
2533 m_lattice[index]);
2534 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2535 m_lattice[index].merge (call_flags);
2538 /* Process internal functions and right away. */
2539 bool record_ipa = m_ipa && !gimple_call_internal_p (call);
2541 /* Handle all function parameters. */
2542 for (unsigned i = 0;
2543 i < gimple_call_num_args (call)
2544 && m_lattice[index].flags; i++)
2545 /* Name is directly passed to the callee. */
2546 if (gimple_call_arg (call, i) == name)
2548 int call_flags = gimple_call_arg_flags (call, i);
2549 if (!ignore_retval)
2550 merge_call_lhs_flags
2551 (call, i, name,
2552 !(call_flags & (EAF_NOT_RETURNED_DIRECTLY
2553 | EAF_UNUSED)),
2554 !(call_flags & (EAF_NOT_RETURNED_INDIRECTLY
2555 | EAF_UNUSED)));
2556 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2558 call_flags = callee_to_caller_flags
2559 (call_flags, ignore_stores,
2560 m_lattice[index]);
2561 if (!record_ipa)
2562 m_lattice[index].merge (call_flags);
2563 else
2564 m_lattice[index].add_escape_point (call, i,
2565 call_flags, true);
2568 /* Name is dereferenced and passed to a callee. */
2569 else if (memory_access_to (gimple_call_arg (call, i), name))
2571 int call_flags = deref_flags
2572 (gimple_call_arg_flags (call, i), ignore_stores);
2573 if (!ignore_retval && !(call_flags & EAF_UNUSED)
2574 && !(call_flags & EAF_NOT_RETURNED_DIRECTLY)
2575 && !(call_flags & EAF_NOT_RETURNED_INDIRECTLY))
2576 merge_call_lhs_flags (call, i, name, false, true);
2577 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
2578 m_lattice[index].merge_direct_load ();
2579 else
2581 call_flags = callee_to_caller_flags
2582 (call_flags, ignore_stores,
2583 m_lattice[index]);
2584 if (!record_ipa)
2585 m_lattice[index].merge (call_flags);
2586 else
2587 m_lattice[index].add_escape_point (call, i,
2588 call_flags, false);
2593 else if (gimple_assign_load_p (use_stmt))
2595 gassign *assign = as_a <gassign *> (use_stmt);
2596 /* Memory to memory copy. */
2597 if (gimple_store_p (assign))
2599 /* Handle *lhs = *name.
2601 We do not track memory locations, so assume that value
2602 is used arbitrarily. */
2603 if (memory_access_to (gimple_assign_rhs1 (assign), name))
2604 m_lattice[index].merge (deref_flags (0, false));
2605 /* Handle *name = *exp. */
2606 else if (memory_access_to (gimple_assign_lhs (assign), name))
2607 m_lattice[index].merge_direct_store ();
2609 /* Handle lhs = *name. */
2610 else if (memory_access_to (gimple_assign_rhs1 (assign), name))
2612 tree lhs = gimple_assign_lhs (assign);
2613 merge_with_ssa_name (name, lhs, true);
2616 else if (gimple_store_p (use_stmt))
2618 gassign *assign = dyn_cast <gassign *> (use_stmt);
2620 /* Handle *lhs = name. */
2621 if (assign && gimple_assign_rhs1 (assign) == name)
2623 if (dump_file)
2624 fprintf (dump_file, "%*s ssa name saved to memory\n",
2625 m_depth * 4, "");
2626 m_lattice[index].merge (0);
2628 /* Handle *name = exp. */
2629 else if (assign
2630 && memory_access_to (gimple_assign_lhs (assign), name))
2632 /* In general we can not ignore clobbers because they are
2633 barriers for code motion, however after inlining it is safe to
2634 do because local optimization passes do not consider clobbers
2635 from other functions.
2636 Similar logic is in ipa-pure-const.cc. */
2637 if (!cfun->after_inlining || !gimple_clobber_p (assign))
2638 m_lattice[index].merge_direct_store ();
2640 /* ASM statements etc. */
2641 else if (!assign)
2643 if (dump_file)
2644 fprintf (dump_file, "%*s Unhandled store\n", m_depth * 4, "");
2645 m_lattice[index].merge (0);
2648 else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
2650 enum tree_code code = gimple_assign_rhs_code (assign);
2652 /* See if operation is a merge as considered by
2653 tree-ssa-structalias.cc:find_func_aliases. */
2654 if (!truth_value_p (code)
2655 && code != POINTER_DIFF_EXPR
2656 && (code != POINTER_PLUS_EXPR
2657 || gimple_assign_rhs1 (assign) == name))
2659 tree lhs = gimple_assign_lhs (assign);
2660 merge_with_ssa_name (name, lhs, false);
2663 else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
2665 tree result = gimple_phi_result (phi);
2666 merge_with_ssa_name (name, result, false);
2668 /* Conditions are not considered escape points
2669 by tree-ssa-structalias. */
2670 else if (gimple_code (use_stmt) == GIMPLE_COND)
2672 else
2674 if (dump_file)
2675 fprintf (dump_file, "%*s Unhandled stmt\n", m_depth * 4, "");
2676 m_lattice[index].merge (0);
2679 if (dump_file)
2681 fprintf (dump_file, "%*s current flags of ", m_depth * 4, "");
2682 print_generic_expr (dump_file, name);
2683 m_lattice[index].dump (dump_file, m_depth * 4 + 4);
2686 if (dump_file)
2688 fprintf (dump_file, "%*sflags of ssa name ", m_depth * 4, "");
2689 print_generic_expr (dump_file, name);
2690 m_lattice[index].dump (dump_file, m_depth * 4 + 2);
2692 m_lattice[index].open = false;
2693 if (!m_lattice[index].do_dataflow)
2694 m_lattice[index].known = true;
2697 /* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
2698 is dereferenced. */
2700 void
2701 modref_eaf_analysis::merge_with_ssa_name (tree dest, tree src, bool deref)
2703 int index = SSA_NAME_VERSION (dest);
2704 int src_index = SSA_NAME_VERSION (src);
2706 /* Merging lattice with itself is a no-op. */
2707 if (!deref && src == dest)
2708 return;
2710 m_depth++;
2711 analyze_ssa_name (src);
2712 m_depth--;
2713 if (deref)
2714 m_lattice[index].merge_deref (m_lattice[src_index], false);
2715 else
2716 m_lattice[index].merge (m_lattice[src_index]);
2718 /* If we failed to produce final solution add an edge to the dataflow
2719 graph. */
2720 if (!m_lattice[src_index].known)
2722 modref_lattice::propagate_edge e = {index, deref};
2724 if (!m_lattice[src_index].propagate_to.length ())
2725 m_names_to_propagate.safe_push (src_index);
2726 m_lattice[src_index].propagate_to.safe_push (e);
2727 m_lattice[src_index].changed = true;
2728 m_lattice[src_index].do_dataflow = true;
2729 if (dump_file)
2730 fprintf (dump_file,
2731 "%*sWill propgate from ssa_name %i to %i%s\n",
2732 m_depth * 4 + 4,
2733 "", src_index, index, deref ? " (deref)" : "");
2737 /* In the case we deferred some SSA names, reprocess them. In the case some
2738 dataflow edges were introduced, do the actual iterative dataflow. */
2740 void
2741 modref_eaf_analysis::propagate ()
2743 int iterations = 0;
2744 size_t i;
2745 int index;
2746 bool changed = true;
2748 while (m_deferred_names.length ())
2750 tree name = m_deferred_names.pop ();
2751 if (dump_file)
2752 fprintf (dump_file, "Analyzing deferred SSA name\n");
2753 analyze_ssa_name (name, true);
2756 if (!m_names_to_propagate.length ())
2757 return;
2758 if (dump_file)
2759 fprintf (dump_file, "Propagating EAF flags\n");
2761 /* Compute reverse postorder. */
2762 auto_vec <int> rpo;
2763 struct stack_entry
2765 int name;
2766 unsigned pos;
2768 auto_vec <struct stack_entry> stack;
2769 int pos = m_names_to_propagate.length () - 1;
2771 rpo.safe_grow (m_names_to_propagate.length (), true);
2772 stack.reserve_exact (m_names_to_propagate.length ());
2774 /* We reuse known flag for RPO DFS walk bookkeeping. */
2775 if (flag_checking)
2776 FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2777 gcc_assert (!m_lattice[index].known && m_lattice[index].changed);
2779 FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2781 if (!m_lattice[index].known)
2783 stack_entry e = {index, 0};
2785 stack.quick_push (e);
2786 m_lattice[index].known = true;
2788 while (stack.length ())
2790 bool found = false;
2791 int index1 = stack.last ().name;
2793 while (stack.last ().pos < m_lattice[index1].propagate_to.length ())
2795 int index2 = m_lattice[index1]
2796 .propagate_to[stack.last ().pos].ssa_name;
2798 stack.last ().pos++;
2799 if (!m_lattice[index2].known
2800 && m_lattice[index2].propagate_to.length ())
2802 stack_entry e = {index2, 0};
2804 stack.quick_push (e);
2805 m_lattice[index2].known = true;
2806 found = true;
2807 break;
2810 if (!found
2811 && stack.last ().pos == m_lattice[index1].propagate_to.length ())
2813 rpo[pos--] = index1;
2814 stack.pop ();
2819 /* Perform iterative dataflow. */
2820 while (changed)
2822 changed = false;
2823 iterations++;
2824 if (dump_file)
2825 fprintf (dump_file, " iteration %i\n", iterations);
2826 FOR_EACH_VEC_ELT (rpo, i, index)
2828 if (m_lattice[index].changed)
2830 size_t j;
2832 m_lattice[index].changed = false;
2833 if (dump_file)
2834 fprintf (dump_file, " Visiting ssa name %i\n", index);
2835 for (j = 0; j < m_lattice[index].propagate_to.length (); j++)
2837 bool ch;
2838 int target = m_lattice[index].propagate_to[j].ssa_name;
2839 bool deref = m_lattice[index].propagate_to[j].deref;
2841 if (dump_file)
2842 fprintf (dump_file, " Propagating flags of ssa name"
2843 " %i to %i%s\n",
2844 index, target, deref ? " (deref)" : "");
2845 m_lattice[target].known = true;
2846 if (!m_lattice[index].propagate_to[j].deref)
2847 ch = m_lattice[target].merge (m_lattice[index]);
2848 else
2849 ch = m_lattice[target].merge_deref (m_lattice[index],
2850 false);
2851 if (!ch)
2852 continue;
2853 if (dump_file)
2855 fprintf (dump_file, " New lattice: ");
2856 m_lattice[target].dump (dump_file);
2858 changed = true;
2859 m_lattice[target].changed = true;
2864 if (dump_file)
2865 fprintf (dump_file, "EAF flags propagated in %i iterations\n", iterations);
2868 /* Record escape points of PARM_INDEX according to LATTICE. */
2870 void
2871 modref_eaf_analysis::record_escape_points (tree name, int parm_index, int flags)
2873 modref_lattice &lattice = m_lattice[SSA_NAME_VERSION (name)];
2875 if (lattice.escape_points.length ())
2877 escape_point *ep;
2878 unsigned int ip;
2879 cgraph_node *node = cgraph_node::get (current_function_decl);
2881 gcc_assert (m_ipa);
2882 FOR_EACH_VEC_ELT (lattice.escape_points, ip, ep)
2883 if ((ep->min_flags & flags) != flags)
2885 cgraph_edge *e = node->get_edge (ep->call);
2886 struct escape_entry ee = {parm_index, ep->arg,
2887 ep->min_flags, ep->direct};
2889 escape_summaries->get_create (e)->esc.safe_push (ee);
2894 /* Determine EAF flags for function parameters
2895 and fill in SUMMARY/SUMMARY_LTO. If IPA is true work in IPA mode
2896 where we also collect escape points.
2897 PAST_FLAGS, PAST_RETSLOT_FLAGS, PAST_STATIC_CHAIN_FLAGS can be
2898 used to preserve flags from previous (IPA) run for cases where
2899 late optimizations changed code in a way we can no longer analyze
2900 it easily. */
2902 static void
2903 analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
2904 bool ipa, vec<eaf_flags_t> &past_flags,
2905 int past_retslot_flags, int past_static_chain_flags)
2907 unsigned int parm_index = 0;
2908 unsigned int count = 0;
2909 int ecf_flags = flags_from_decl_or_type (current_function_decl);
2910 tree retslot = NULL;
2911 tree static_chain = NULL;
2913 /* If there is return slot, look up its SSA name. */
2914 if (DECL_RESULT (current_function_decl)
2915 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2916 retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
2917 if (cfun->static_chain_decl)
2918 static_chain = ssa_default_def (cfun, cfun->static_chain_decl);
2920 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2921 parm = TREE_CHAIN (parm))
2922 count++;
2924 if (!count && !retslot && !static_chain)
2925 return;
2927 modref_eaf_analysis eaf_analysis (ipa);
2929 /* Determine all SSA names we need to know flags for. */
2930 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2931 parm = TREE_CHAIN (parm))
2933 tree name = ssa_default_def (cfun, parm);
2934 if (name)
2935 eaf_analysis.analyze_ssa_name (name);
2937 if (retslot)
2938 eaf_analysis.analyze_ssa_name (retslot);
2939 if (static_chain)
2940 eaf_analysis.analyze_ssa_name (static_chain);
2942 /* Do the dataflow. */
2943 eaf_analysis.propagate ();
2945 tree attr = lookup_attribute ("fn spec",
2946 TYPE_ATTRIBUTES
2947 (TREE_TYPE (current_function_decl)));
2948 attr_fnspec fnspec (attr
2949 ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)))
2950 : "");
2953 /* Store results to summaries. */
2954 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
2955 parm = TREE_CHAIN (parm))
2957 tree name = ssa_default_def (cfun, parm);
2958 if (!name || has_zero_uses (name))
2960 /* We do not track non-SSA parameters,
2961 but we want to track unused gimple_regs. */
2962 if (!is_gimple_reg (parm))
2963 continue;
2964 if (summary)
2966 if (parm_index >= summary->arg_flags.length ())
2967 summary->arg_flags.safe_grow_cleared (count, true);
2968 summary->arg_flags[parm_index] = EAF_UNUSED;
2970 else if (summary_lto)
2972 if (parm_index >= summary_lto->arg_flags.length ())
2973 summary_lto->arg_flags.safe_grow_cleared (count, true);
2974 summary_lto->arg_flags[parm_index] = EAF_UNUSED;
2976 continue;
2978 int flags = eaf_analysis.get_ssa_name_flags (name);
2979 int attr_flags = fnspec.arg_eaf_flags (parm_index);
2981 if (dump_file && (flags | attr_flags) != flags && !(flags & EAF_UNUSED))
2983 fprintf (dump_file,
2984 " Flags for param %i combined with fnspec flags:",
2985 (int)parm_index);
2986 dump_eaf_flags (dump_file, attr_flags, false);
2987 fprintf (dump_file, " determined: ");
2988 dump_eaf_flags (dump_file, flags, true);
2990 flags |= attr_flags;
2992 /* Eliminate useless flags so we do not end up storing unnecessary
2993 summaries. */
2995 flags = remove_useless_eaf_flags
2996 (flags, ecf_flags,
2997 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
2998 if (past_flags.length () > parm_index)
3000 int past = past_flags[parm_index];
3001 past = remove_useless_eaf_flags
3002 (past, ecf_flags,
3003 VOID_TYPE_P (TREE_TYPE
3004 (TREE_TYPE (current_function_decl))));
3005 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
3007 fprintf (dump_file,
3008 " Flags for param %i combined with IPA pass:",
3009 (int)parm_index);
3010 dump_eaf_flags (dump_file, past, false);
3011 fprintf (dump_file, " determined: ");
3012 dump_eaf_flags (dump_file, flags, true);
3014 if (!(flags & EAF_UNUSED))
3015 flags |= past;
3018 if (flags)
3020 if (summary)
3022 if (parm_index >= summary->arg_flags.length ())
3023 summary->arg_flags.safe_grow_cleared (count, true);
3024 summary->arg_flags[parm_index] = flags;
3026 else if (summary_lto)
3028 if (parm_index >= summary_lto->arg_flags.length ())
3029 summary_lto->arg_flags.safe_grow_cleared (count, true);
3030 summary_lto->arg_flags[parm_index] = flags;
3032 eaf_analysis.record_escape_points (name, parm_index, flags);
3035 if (retslot)
3037 int flags = eaf_analysis.get_ssa_name_flags (retslot);
3038 int past = past_retslot_flags;
3040 flags = remove_useless_eaf_flags (flags, ecf_flags, false);
3041 past = remove_useless_eaf_flags
3042 (past, ecf_flags,
3043 VOID_TYPE_P (TREE_TYPE
3044 (TREE_TYPE (current_function_decl))));
3045 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
3047 fprintf (dump_file,
3048 " Retslot flags combined with IPA pass:");
3049 dump_eaf_flags (dump_file, past, false);
3050 fprintf (dump_file, " determined: ");
3051 dump_eaf_flags (dump_file, flags, true);
3053 if (!(flags & EAF_UNUSED))
3054 flags |= past;
3055 if (flags)
3057 if (summary)
3058 summary->retslot_flags = flags;
3059 if (summary_lto)
3060 summary_lto->retslot_flags = flags;
3061 eaf_analysis.record_escape_points (retslot,
3062 MODREF_RETSLOT_PARM, flags);
3065 if (static_chain)
3067 int flags = eaf_analysis.get_ssa_name_flags (static_chain);
3068 int past = past_static_chain_flags;
3070 flags = remove_useless_eaf_flags (flags, ecf_flags, false);
3071 past = remove_useless_eaf_flags
3072 (past, ecf_flags,
3073 VOID_TYPE_P (TREE_TYPE
3074 (TREE_TYPE (current_function_decl))));
3075 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
3077 fprintf (dump_file,
3078 " Static chain flags combined with IPA pass:");
3079 dump_eaf_flags (dump_file, past, false);
3080 fprintf (dump_file, " determined: ");
3081 dump_eaf_flags (dump_file, flags, true);
3083 if (!(flags & EAF_UNUSED))
3084 flags |= past;
3085 if (flags)
3087 if (summary)
3088 summary->static_chain_flags = flags;
3089 if (summary_lto)
3090 summary_lto->static_chain_flags = flags;
3091 eaf_analysis.record_escape_points (static_chain,
3092 MODREF_STATIC_CHAIN_PARM,
3093 flags);
3098 /* Analyze function. IPA indicates whether we're running in local mode
3099 (false) or the IPA mode (true).
3100 Return true if fixup cfg is needed after the pass. */
3102 static bool
3103 analyze_function (bool ipa)
3105 bool fixup_cfg = false;
3106 if (dump_file)
3107 fprintf (dump_file, "\n\nmodref analyzing '%s' (ipa=%i)%s%s\n",
3108 cgraph_node::get (current_function_decl)->dump_name (), ipa,
3109 TREE_READONLY (current_function_decl) ? " (const)" : "",
3110 DECL_PURE_P (current_function_decl) ? " (pure)" : "");
3112 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
3113 if (!flag_ipa_modref
3114 || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
3115 return false;
3117 /* Compute no-LTO summaries when local optimization is going to happen. */
3118 bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
3119 || (in_lto_p && !flag_wpa
3120 && flag_incremental_link != INCREMENTAL_LINK_LTO));
3121 /* Compute LTO when LTO streaming is going to happen. */
3122 bool lto = ipa && ((flag_lto && !in_lto_p)
3123 || flag_wpa
3124 || flag_incremental_link == INCREMENTAL_LINK_LTO);
3125 cgraph_node *fnode = cgraph_node::get (current_function_decl);
3127 modref_summary *summary = NULL;
3128 modref_summary_lto *summary_lto = NULL;
3130 bool past_flags_known = false;
3131 auto_vec <eaf_flags_t> past_flags;
3132 int past_retslot_flags = 0;
3133 int past_static_chain_flags = 0;
3135 /* Initialize the summary.
3136 If we run in local mode there is possibly pre-existing summary from
3137 IPA pass. Dump it so it is easy to compare if mod-ref info has
3138 improved. */
3139 if (!ipa)
3141 if (!optimization_summaries)
3142 optimization_summaries = modref_summaries::create_ggc (symtab);
3143 else /* Remove existing summary if we are re-running the pass. */
3145 summary = optimization_summaries->get (fnode);
3146 if (summary != NULL
3147 && summary->loads)
3149 if (dump_file)
3151 fprintf (dump_file, "Past summary:\n");
3152 optimization_summaries->get (fnode)->dump (dump_file);
3154 past_flags.reserve_exact (summary->arg_flags.length ());
3155 past_flags.splice (summary->arg_flags);
3156 past_retslot_flags = summary->retslot_flags;
3157 past_static_chain_flags = summary->static_chain_flags;
3158 past_flags_known = true;
3160 optimization_summaries->remove (fnode);
3162 summary = optimization_summaries->get_create (fnode);
3163 gcc_checking_assert (nolto && !lto);
3165 /* In IPA mode we analyze every function precisely once. Assert that. */
3166 else
3168 if (nolto)
3170 if (!summaries)
3171 summaries = modref_summaries::create_ggc (symtab);
3172 else
3173 summaries->remove (fnode);
3174 summary = summaries->get_create (fnode);
3176 if (lto)
3178 if (!summaries_lto)
3179 summaries_lto = modref_summaries_lto::create_ggc (symtab);
3180 else
3181 summaries_lto->remove (fnode);
3182 summary_lto = summaries_lto->get_create (fnode);
3184 if (!fnspec_summaries)
3185 fnspec_summaries = new fnspec_summaries_t (symtab);
3186 if (!escape_summaries)
3187 escape_summaries = new escape_summaries_t (symtab);
3191 /* Create and initialize summary for F.
3192 Note that summaries may be already allocated from previous
3193 run of the pass. */
3194 if (nolto)
3196 gcc_assert (!summary->loads);
3197 summary->loads = modref_records::create_ggc ();
3198 gcc_assert (!summary->stores);
3199 summary->stores = modref_records::create_ggc ();
3200 summary->writes_errno = false;
3201 summary->side_effects = false;
3202 summary->nondeterministic = false;
3203 summary->calls_interposable = false;
3205 if (lto)
3207 gcc_assert (!summary_lto->loads);
3208 summary_lto->loads = modref_records_lto::create_ggc ();
3209 gcc_assert (!summary_lto->stores);
3210 summary_lto->stores = modref_records_lto::create_ggc ();
3211 summary_lto->writes_errno = false;
3212 summary_lto->side_effects = false;
3213 summary_lto->nondeterministic = false;
3214 summary_lto->calls_interposable = false;
3217 analyze_parms (summary, summary_lto, ipa,
3218 past_flags, past_retslot_flags, past_static_chain_flags);
3221 modref_access_analysis analyzer (ipa, summary, summary_lto);
3222 analyzer.analyze ();
3225 if (!ipa && flag_ipa_pure_const)
3227 if (!summary->stores->every_base && !summary->stores->bases
3228 && !summary->nondeterministic)
3230 if (!summary->loads->every_base && !summary->loads->bases
3231 && !summary->calls_interposable)
3232 fixup_cfg = ipa_make_function_const (fnode,
3233 summary->side_effects, true);
3234 else
3235 fixup_cfg = ipa_make_function_pure (fnode,
3236 summary->side_effects, true);
3239 int ecf_flags = flags_from_decl_or_type (current_function_decl);
3240 if (summary && !summary->useful_p (ecf_flags))
3242 if (!ipa)
3243 optimization_summaries->remove (fnode);
3244 else
3245 summaries->remove (fnode);
3246 summary = NULL;
3248 if (summary)
3249 summary->finalize (current_function_decl);
3250 if (summary_lto && !summary_lto->useful_p (ecf_flags))
3252 summaries_lto->remove (fnode);
3253 summary_lto = NULL;
3256 if (ipa && !summary && !summary_lto)
3257 remove_modref_edge_summaries (fnode);
3259 if (dump_file)
3261 fprintf (dump_file, " - modref done with result: tracked.\n");
3262 if (summary)
3263 summary->dump (dump_file);
3264 if (summary_lto)
3265 summary_lto->dump (dump_file);
3266 dump_modref_edge_summaries (dump_file, fnode, 2);
3267 /* To simplify debugging, compare IPA and local solutions. */
3268 if (past_flags_known && summary)
3270 size_t len = summary->arg_flags.length ();
3272 if (past_flags.length () > len)
3273 len = past_flags.length ();
3274 for (size_t i = 0; i < len; i++)
3276 int old_flags = i < past_flags.length () ? past_flags[i] : 0;
3277 int new_flags = i < summary->arg_flags.length ()
3278 ? summary->arg_flags[i] : 0;
3279 old_flags = remove_useless_eaf_flags
3280 (old_flags, flags_from_decl_or_type (current_function_decl),
3281 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3282 if (old_flags != new_flags)
3284 if ((old_flags & ~new_flags) == 0
3285 || (new_flags & EAF_UNUSED))
3286 fprintf (dump_file, " Flags for param %i improved:",
3287 (int)i);
3288 else
3289 gcc_unreachable ();
3290 dump_eaf_flags (dump_file, old_flags, false);
3291 fprintf (dump_file, " -> ");
3292 dump_eaf_flags (dump_file, new_flags, true);
3295 past_retslot_flags = remove_useless_eaf_flags
3296 (past_retslot_flags,
3297 flags_from_decl_or_type (current_function_decl),
3298 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3299 if (past_retslot_flags != summary->retslot_flags)
3301 if ((past_retslot_flags & ~summary->retslot_flags) == 0
3302 || (summary->retslot_flags & EAF_UNUSED))
3303 fprintf (dump_file, " Flags for retslot improved:");
3304 else
3305 gcc_unreachable ();
3306 dump_eaf_flags (dump_file, past_retslot_flags, false);
3307 fprintf (dump_file, " -> ");
3308 dump_eaf_flags (dump_file, summary->retslot_flags, true);
3310 past_static_chain_flags = remove_useless_eaf_flags
3311 (past_static_chain_flags,
3312 flags_from_decl_or_type (current_function_decl),
3313 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3314 if (past_static_chain_flags != summary->static_chain_flags)
3316 if ((past_static_chain_flags & ~summary->static_chain_flags) == 0
3317 || (summary->static_chain_flags & EAF_UNUSED))
3318 fprintf (dump_file, " Flags for static chain improved:");
3319 else
3320 gcc_unreachable ();
3321 dump_eaf_flags (dump_file, past_static_chain_flags, false);
3322 fprintf (dump_file, " -> ");
3323 dump_eaf_flags (dump_file, summary->static_chain_flags, true);
3326 else if (past_flags_known && !summary)
3328 for (size_t i = 0; i < past_flags.length (); i++)
3330 int old_flags = past_flags[i];
3331 old_flags = remove_useless_eaf_flags
3332 (old_flags, flags_from_decl_or_type (current_function_decl),
3333 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3334 if (old_flags)
3336 fprintf (dump_file, " Flags for param %i worsened:",
3337 (int)i);
3338 dump_eaf_flags (dump_file, old_flags, false);
3339 fprintf (dump_file, " -> \n");
3342 past_retslot_flags = remove_useless_eaf_flags
3343 (past_retslot_flags,
3344 flags_from_decl_or_type (current_function_decl),
3345 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3346 if (past_retslot_flags)
3348 fprintf (dump_file, " Flags for retslot worsened:");
3349 dump_eaf_flags (dump_file, past_retslot_flags, false);
3350 fprintf (dump_file, " ->\n");
3352 past_static_chain_flags = remove_useless_eaf_flags
3353 (past_static_chain_flags,
3354 flags_from_decl_or_type (current_function_decl),
3355 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3356 if (past_static_chain_flags)
3358 fprintf (dump_file, " Flags for static chain worsened:");
3359 dump_eaf_flags (dump_file, past_static_chain_flags, false);
3360 fprintf (dump_file, " ->\n");
3364 return fixup_cfg;
3367 /* Callback for generate_summary. */
3369 static void
3370 modref_generate (void)
3372 struct cgraph_node *node;
3373 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
3375 function *f = DECL_STRUCT_FUNCTION (node->decl);
3376 if (!f)
3377 continue;
3378 push_cfun (f);
3379 analyze_function (true);
3380 pop_cfun ();
3384 } /* ANON namespace. */
3386 /* Debugging helper. */
3388 void
3389 debug_eaf_flags (int flags)
3391 dump_eaf_flags (stderr, flags, true);
3394 /* Called when a new function is inserted to callgraph late. */
3396 void
3397 modref_summaries::insert (struct cgraph_node *node, modref_summary *)
3399 /* Local passes ought to be executed by the pass manager. */
3400 if (this == optimization_summaries)
3402 optimization_summaries->remove (node);
3403 return;
3405 if (!DECL_STRUCT_FUNCTION (node->decl)
3406 || !opt_for_fn (node->decl, flag_ipa_modref))
3408 summaries->remove (node);
3409 return;
3411 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
3412 analyze_function (true);
3413 pop_cfun ();
3416 /* Called when a new function is inserted to callgraph late. */
3418 void
3419 modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
3421 /* We do not support adding new function when IPA information is already
3422 propagated. This is done only by SIMD cloning that is not very
3423 critical. */
3424 if (!DECL_STRUCT_FUNCTION (node->decl)
3425 || !opt_for_fn (node->decl, flag_ipa_modref)
3426 || propagated)
3428 summaries_lto->remove (node);
3429 return;
3431 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
3432 analyze_function (true);
3433 pop_cfun ();
3436 /* Called when new clone is inserted to callgraph late. */
3438 void
3439 modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
3440 modref_summary *src_data,
3441 modref_summary *dst_data)
3443 /* Do not duplicate optimization summaries; we do not handle parameter
3444 transforms on them. */
3445 if (this == optimization_summaries)
3447 optimization_summaries->remove (dst);
3448 return;
3450 dst_data->stores = modref_records::create_ggc ();
3451 dst_data->stores->copy_from (src_data->stores);
3452 dst_data->loads = modref_records::create_ggc ();
3453 dst_data->loads->copy_from (src_data->loads);
3454 dst_data->kills.reserve_exact (src_data->kills.length ());
3455 dst_data->kills.splice (src_data->kills);
3456 dst_data->writes_errno = src_data->writes_errno;
3457 dst_data->side_effects = src_data->side_effects;
3458 dst_data->nondeterministic = src_data->nondeterministic;
3459 dst_data->calls_interposable = src_data->calls_interposable;
3460 if (src_data->arg_flags.length ())
3461 dst_data->arg_flags = src_data->arg_flags.copy ();
3462 dst_data->retslot_flags = src_data->retslot_flags;
3463 dst_data->static_chain_flags = src_data->static_chain_flags;
3466 /* Called when new clone is inserted to callgraph late. */
3468 void
3469 modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
3470 modref_summary_lto *src_data,
3471 modref_summary_lto *dst_data)
3473 /* Be sure that no further cloning happens after ipa-modref. If it does
3474 we will need to update signatures for possible param changes. */
3475 gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
3476 dst_data->stores = modref_records_lto::create_ggc ();
3477 dst_data->stores->copy_from (src_data->stores);
3478 dst_data->loads = modref_records_lto::create_ggc ();
3479 dst_data->loads->copy_from (src_data->loads);
3480 dst_data->kills.reserve_exact (src_data->kills.length ());
3481 dst_data->kills.splice (src_data->kills);
3482 dst_data->writes_errno = src_data->writes_errno;
3483 dst_data->side_effects = src_data->side_effects;
3484 dst_data->nondeterministic = src_data->nondeterministic;
3485 dst_data->calls_interposable = src_data->calls_interposable;
3486 if (src_data->arg_flags.length ())
3487 dst_data->arg_flags = src_data->arg_flags.copy ();
3488 dst_data->retslot_flags = src_data->retslot_flags;
3489 dst_data->static_chain_flags = src_data->static_chain_flags;
3492 namespace
3494 /* Definition of the modref pass on GIMPLE. */
3495 const pass_data pass_data_modref = {
3496 GIMPLE_PASS,
3497 "modref",
3498 OPTGROUP_IPA,
3499 TV_TREE_MODREF,
3500 (PROP_cfg | PROP_ssa),
3507 class pass_modref : public gimple_opt_pass
3509 public:
3510 pass_modref (gcc::context *ctxt)
3511 : gimple_opt_pass (pass_data_modref, ctxt) {}
3513 /* opt_pass methods: */
3514 opt_pass *clone () final override
3516 return new pass_modref (m_ctxt);
3518 bool gate (function *) final override
3520 return flag_ipa_modref;
3522 unsigned int execute (function *) final override;
3525 /* Encode TT to the output block OB using the summary streaming API. */
3527 static void
3528 write_modref_records (modref_records_lto *tt, struct output_block *ob)
3530 streamer_write_uhwi (ob, tt->every_base);
3531 streamer_write_uhwi (ob, vec_safe_length (tt->bases));
3532 for (auto base_node : tt->bases)
3534 stream_write_tree (ob, base_node->base, true);
3536 streamer_write_uhwi (ob, base_node->every_ref);
3537 streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
3539 for (auto ref_node : base_node->refs)
3541 stream_write_tree (ob, ref_node->ref, true);
3542 streamer_write_uhwi (ob, ref_node->every_access);
3543 streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
3545 for (auto access_node : ref_node->accesses)
3546 access_node.stream_out (ob);
3551 /* Read a modref_tree from the input block IB using the data from DATA_IN.
3552 This assumes that the tree was encoded using write_modref_tree.
3553 Either nolto_ret or lto_ret is initialized by the tree depending whether
3554 LTO streaming is expected or not. */
3556 static void
3557 read_modref_records (tree decl,
3558 lto_input_block *ib, struct data_in *data_in,
3559 modref_records **nolto_ret,
3560 modref_records_lto **lto_ret)
3562 size_t max_bases = opt_for_fn (decl, param_modref_max_bases);
3563 size_t max_refs = opt_for_fn (decl, param_modref_max_refs);
3564 size_t max_accesses = opt_for_fn (decl, param_modref_max_accesses);
3566 if (lto_ret)
3567 *lto_ret = modref_records_lto::create_ggc ();
3568 if (nolto_ret)
3569 *nolto_ret = modref_records::create_ggc ();
3570 gcc_checking_assert (lto_ret || nolto_ret);
3572 size_t every_base = streamer_read_uhwi (ib);
3573 size_t nbase = streamer_read_uhwi (ib);
3575 gcc_assert (!every_base || nbase == 0);
3576 if (every_base)
3578 if (nolto_ret)
3579 (*nolto_ret)->collapse ();
3580 if (lto_ret)
3581 (*lto_ret)->collapse ();
3583 for (size_t i = 0; i < nbase; i++)
3585 tree base_tree = stream_read_tree (ib, data_in);
3586 modref_base_node <alias_set_type> *nolto_base_node = NULL;
3587 modref_base_node <tree> *lto_base_node = NULL;
3589 /* At stream in time we have LTO alias info. Check if we streamed in
3590 something obviously unnecessary. Do not glob types by alias sets;
3591 it is not 100% clear that ltrans types will get merged same way.
3592 Types may get refined based on ODR type conflicts. */
3593 if (base_tree && !get_alias_set (base_tree))
3595 if (dump_file)
3597 fprintf (dump_file, "Streamed in alias set 0 type ");
3598 print_generic_expr (dump_file, base_tree);
3599 fprintf (dump_file, "\n");
3601 base_tree = NULL;
3604 if (nolto_ret)
3605 nolto_base_node = (*nolto_ret)->insert_base (base_tree
3606 ? get_alias_set (base_tree)
3607 : 0, 0, INT_MAX);
3608 if (lto_ret)
3609 lto_base_node = (*lto_ret)->insert_base (base_tree, 0, max_bases);
3610 size_t every_ref = streamer_read_uhwi (ib);
3611 size_t nref = streamer_read_uhwi (ib);
3613 gcc_assert (!every_ref || nref == 0);
3614 if (every_ref)
3616 if (nolto_base_node)
3617 nolto_base_node->collapse ();
3618 if (lto_base_node)
3619 lto_base_node->collapse ();
3621 for (size_t j = 0; j < nref; j++)
3623 tree ref_tree = stream_read_tree (ib, data_in);
3625 if (ref_tree && !get_alias_set (ref_tree))
3627 if (dump_file)
3629 fprintf (dump_file, "Streamed in alias set 0 type ");
3630 print_generic_expr (dump_file, ref_tree);
3631 fprintf (dump_file, "\n");
3633 ref_tree = NULL;
3636 modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
3637 modref_ref_node <tree> *lto_ref_node = NULL;
3639 if (nolto_base_node)
3640 nolto_ref_node
3641 = nolto_base_node->insert_ref (ref_tree
3642 ? get_alias_set (ref_tree) : 0,
3643 max_refs);
3644 if (lto_base_node)
3645 lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
3647 size_t every_access = streamer_read_uhwi (ib);
3648 size_t naccesses = streamer_read_uhwi (ib);
3650 if (nolto_ref_node && every_access)
3651 nolto_ref_node->collapse ();
3652 if (lto_ref_node && every_access)
3653 lto_ref_node->collapse ();
3655 for (size_t k = 0; k < naccesses; k++)
3657 modref_access_node a = modref_access_node::stream_in (ib);
3658 if (nolto_ref_node)
3659 nolto_ref_node->insert_access (a, max_accesses, false);
3660 if (lto_ref_node)
3661 lto_ref_node->insert_access (a, max_accesses, false);
3665 if (lto_ret)
3666 (*lto_ret)->cleanup ();
3667 if (nolto_ret)
3668 (*nolto_ret)->cleanup ();
3671 /* Write ESUM to BP. */
3673 static void
3674 modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
3676 if (!esum)
3678 bp_pack_var_len_unsigned (bp, 0);
3679 return;
3681 bp_pack_var_len_unsigned (bp, esum->esc.length ());
3682 unsigned int i;
3683 escape_entry *ee;
3684 FOR_EACH_VEC_ELT (esum->esc, i, ee)
3686 bp_pack_var_len_int (bp, ee->parm_index);
3687 bp_pack_var_len_unsigned (bp, ee->arg);
3688 bp_pack_var_len_unsigned (bp, ee->min_flags);
3689 bp_pack_value (bp, ee->direct, 1);
3693 /* Read escape summary for E from BP. */
3695 static void
3696 modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
3698 unsigned int n = bp_unpack_var_len_unsigned (bp);
3699 if (!n)
3700 return;
3701 escape_summary *esum = escape_summaries->get_create (e);
3702 esum->esc.reserve_exact (n);
3703 for (unsigned int i = 0; i < n; i++)
3705 escape_entry ee;
3706 ee.parm_index = bp_unpack_var_len_int (bp);
3707 ee.arg = bp_unpack_var_len_unsigned (bp);
3708 ee.min_flags = bp_unpack_var_len_unsigned (bp);
3709 ee.direct = bp_unpack_value (bp, 1);
3710 esum->esc.quick_push (ee);
3714 /* Callback for write_summary. */
3716 static void
3717 modref_write ()
3719 struct output_block *ob = create_output_block (LTO_section_ipa_modref);
3720 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
3721 unsigned int count = 0;
3722 int i;
3724 if (!summaries_lto)
3726 streamer_write_uhwi (ob, 0);
3727 streamer_write_char_stream (ob->main_stream, 0);
3728 produce_asm (ob, NULL);
3729 destroy_output_block (ob);
3730 return;
3733 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3735 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3736 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3737 modref_summary_lto *r;
3739 if (cnode && cnode->definition && !cnode->alias
3740 && (r = summaries_lto->get (cnode))
3741 && r->useful_p (flags_from_decl_or_type (cnode->decl)))
3742 count++;
3744 streamer_write_uhwi (ob, count);
3746 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3748 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3749 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3751 if (cnode && cnode->definition && !cnode->alias)
3753 modref_summary_lto *r = summaries_lto->get (cnode);
3755 if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
3756 continue;
3758 streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
3760 streamer_write_uhwi (ob, r->arg_flags.length ());
3761 for (unsigned int i = 0; i < r->arg_flags.length (); i++)
3762 streamer_write_uhwi (ob, r->arg_flags[i]);
3763 streamer_write_uhwi (ob, r->retslot_flags);
3764 streamer_write_uhwi (ob, r->static_chain_flags);
3766 write_modref_records (r->loads, ob);
3767 write_modref_records (r->stores, ob);
3768 streamer_write_uhwi (ob, r->kills.length ());
3769 for (auto kill : r->kills)
3770 kill.stream_out (ob);
3772 struct bitpack_d bp = bitpack_create (ob->main_stream);
3773 bp_pack_value (&bp, r->writes_errno, 1);
3774 bp_pack_value (&bp, r->side_effects, 1);
3775 bp_pack_value (&bp, r->nondeterministic, 1);
3776 bp_pack_value (&bp, r->calls_interposable, 1);
3777 if (!flag_wpa)
3779 for (cgraph_edge *e = cnode->indirect_calls;
3780 e; e = e->next_callee)
3782 class fnspec_summary *sum = fnspec_summaries->get (e);
3783 bp_pack_value (&bp, sum != NULL, 1);
3784 if (sum)
3785 bp_pack_string (ob, &bp, sum->fnspec, true);
3786 class escape_summary *esum = escape_summaries->get (e);
3787 modref_write_escape_summary (&bp,esum);
3789 for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
3791 class fnspec_summary *sum = fnspec_summaries->get (e);
3792 bp_pack_value (&bp, sum != NULL, 1);
3793 if (sum)
3794 bp_pack_string (ob, &bp, sum->fnspec, true);
3795 class escape_summary *esum = escape_summaries->get (e);
3796 modref_write_escape_summary (&bp,esum);
3799 streamer_write_bitpack (&bp);
3802 streamer_write_char_stream (ob->main_stream, 0);
3803 produce_asm (ob, NULL);
3804 destroy_output_block (ob);
3807 static void
3808 read_section (struct lto_file_decl_data *file_data, const char *data,
3809 size_t len)
3811 const struct lto_function_header *header
3812 = (const struct lto_function_header *) data;
3813 const int cfg_offset = sizeof (struct lto_function_header);
3814 const int main_offset = cfg_offset + header->cfg_size;
3815 const int string_offset = main_offset + header->main_size;
3816 struct data_in *data_in;
3817 unsigned int i;
3818 unsigned int f_count;
3820 lto_input_block ib ((const char *) data + main_offset, header->main_size,
3821 file_data);
3823 data_in
3824 = lto_data_in_create (file_data, (const char *) data + string_offset,
3825 header->string_size, vNULL);
3826 f_count = streamer_read_uhwi (&ib);
3827 for (i = 0; i < f_count; i++)
3829 struct cgraph_node *node;
3830 lto_symtab_encoder_t encoder;
3832 unsigned int index = streamer_read_uhwi (&ib);
3833 encoder = file_data->symtab_node_encoder;
3834 node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
3835 index));
3837 modref_summary *modref_sum = summaries
3838 ? summaries->get_create (node) : NULL;
3839 modref_summary_lto *modref_sum_lto = summaries_lto
3840 ? summaries_lto->get_create (node)
3841 : NULL;
3842 if (optimization_summaries)
3843 modref_sum = optimization_summaries->get_create (node);
3845 if (modref_sum)
3847 modref_sum->writes_errno = false;
3848 modref_sum->side_effects = false;
3849 modref_sum->nondeterministic = false;
3850 modref_sum->calls_interposable = false;
3852 if (modref_sum_lto)
3854 modref_sum_lto->writes_errno = false;
3855 modref_sum_lto->side_effects = false;
3856 modref_sum_lto->nondeterministic = false;
3857 modref_sum_lto->calls_interposable = false;
3860 gcc_assert (!modref_sum || (!modref_sum->loads
3861 && !modref_sum->stores));
3862 gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
3863 && !modref_sum_lto->stores));
3864 unsigned int args = streamer_read_uhwi (&ib);
3865 if (args && modref_sum)
3866 modref_sum->arg_flags.reserve_exact (args);
3867 if (args && modref_sum_lto)
3868 modref_sum_lto->arg_flags.reserve_exact (args);
3869 for (unsigned int i = 0; i < args; i++)
3871 eaf_flags_t flags = streamer_read_uhwi (&ib);
3872 if (modref_sum)
3873 modref_sum->arg_flags.quick_push (flags);
3874 if (modref_sum_lto)
3875 modref_sum_lto->arg_flags.quick_push (flags);
3877 eaf_flags_t flags = streamer_read_uhwi (&ib);
3878 if (modref_sum)
3879 modref_sum->retslot_flags = flags;
3880 if (modref_sum_lto)
3881 modref_sum_lto->retslot_flags = flags;
3883 flags = streamer_read_uhwi (&ib);
3884 if (modref_sum)
3885 modref_sum->static_chain_flags = flags;
3886 if (modref_sum_lto)
3887 modref_sum_lto->static_chain_flags = flags;
3889 read_modref_records (node->decl, &ib, data_in,
3890 modref_sum ? &modref_sum->loads : NULL,
3891 modref_sum_lto ? &modref_sum_lto->loads : NULL);
3892 read_modref_records (node->decl, &ib, data_in,
3893 modref_sum ? &modref_sum->stores : NULL,
3894 modref_sum_lto ? &modref_sum_lto->stores : NULL);
3895 int j = streamer_read_uhwi (&ib);
3896 if (j && modref_sum)
3897 modref_sum->kills.reserve_exact (j);
3898 if (j && modref_sum_lto)
3899 modref_sum_lto->kills.reserve_exact (j);
3900 for (int k = 0; k < j; k++)
3902 modref_access_node a = modref_access_node::stream_in (&ib);
3904 if (modref_sum)
3905 modref_sum->kills.quick_push (a);
3906 if (modref_sum_lto)
3907 modref_sum_lto->kills.quick_push (a);
3909 struct bitpack_d bp = streamer_read_bitpack (&ib);
3910 if (bp_unpack_value (&bp, 1))
3912 if (modref_sum)
3913 modref_sum->writes_errno = true;
3914 if (modref_sum_lto)
3915 modref_sum_lto->writes_errno = true;
3917 if (bp_unpack_value (&bp, 1))
3919 if (modref_sum)
3920 modref_sum->side_effects = true;
3921 if (modref_sum_lto)
3922 modref_sum_lto->side_effects = true;
3924 if (bp_unpack_value (&bp, 1))
3926 if (modref_sum)
3927 modref_sum->nondeterministic = true;
3928 if (modref_sum_lto)
3929 modref_sum_lto->nondeterministic = true;
3931 if (bp_unpack_value (&bp, 1))
3933 if (modref_sum)
3934 modref_sum->calls_interposable = true;
3935 if (modref_sum_lto)
3936 modref_sum_lto->calls_interposable = true;
3938 if (!flag_ltrans)
3940 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
3942 if (bp_unpack_value (&bp, 1))
3944 class fnspec_summary *sum = fnspec_summaries->get_create (e);
3945 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3947 modref_read_escape_summary (&bp, e);
3949 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3951 if (bp_unpack_value (&bp, 1))
3953 class fnspec_summary *sum = fnspec_summaries->get_create (e);
3954 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3956 modref_read_escape_summary (&bp, e);
3959 if (flag_ltrans)
3960 modref_sum->finalize (node->decl);
3961 if (dump_file)
3963 fprintf (dump_file, "Read modref for %s\n",
3964 node->dump_name ());
3965 if (modref_sum)
3966 modref_sum->dump (dump_file);
3967 if (modref_sum_lto)
3968 modref_sum_lto->dump (dump_file);
3969 dump_modref_edge_summaries (dump_file, node, 4);
3973 lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
3974 len);
3975 lto_data_in_delete (data_in);
3978 /* Callback for read_summary. */
3980 static void
3981 modref_read (void)
3983 struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
3984 struct lto_file_decl_data *file_data;
3985 unsigned int j = 0;
3987 gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
3988 if (flag_ltrans)
3989 optimization_summaries = modref_summaries::create_ggc (symtab);
3990 else
3992 if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
3993 summaries_lto = modref_summaries_lto::create_ggc (symtab);
3994 if (!flag_wpa
3995 || (flag_incremental_link == INCREMENTAL_LINK_LTO
3996 && flag_fat_lto_objects))
3997 summaries = modref_summaries::create_ggc (symtab);
3998 if (!fnspec_summaries)
3999 fnspec_summaries = new fnspec_summaries_t (symtab);
4000 if (!escape_summaries)
4001 escape_summaries = new escape_summaries_t (symtab);
4004 while ((file_data = file_data_vec[j++]))
4006 size_t len;
4007 const char *data = lto_get_summary_section_data (file_data,
4008 LTO_section_ipa_modref,
4009 &len);
4010 if (data)
4011 read_section (file_data, data, len);
4012 else
4013 /* Fatal error here. We do not want to support compiling ltrans units
4014 with different version of compiler or different flags than the WPA
4015 unit, so this should never happen. */
4016 fatal_error (input_location,
4017 "IPA modref summary is missing in input file");
4021 /* Recompute arg_flags for param adjustments in INFO. */
4023 static void
4024 remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
4026 auto_vec<eaf_flags_t> old = arg_flags.copy ();
4027 int max = -1;
4028 size_t i;
4029 ipa_adjusted_param *p;
4031 arg_flags.release ();
4033 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4035 int o = info->param_adjustments->get_original_index (i);
4036 if (o >= 0 && (int)old.length () > o && old[o])
4037 max = i;
4039 if (max >= 0)
4040 arg_flags.safe_grow_cleared (max + 1, true);
4041 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4043 int o = info->param_adjustments->get_original_index (i);
4044 if (o >= 0 && (int)old.length () > o && old[o])
4045 arg_flags[i] = old[o];
4049 /* Update kills according to the parm map MAP. */
4051 static void
4052 remap_kills (vec <modref_access_node> &kills, const vec <int> &map)
4054 for (size_t i = 0; i < kills.length ();)
4055 if (kills[i].parm_index >= 0)
4057 if (kills[i].parm_index < (int)map.length ()
4058 && map[kills[i].parm_index] != MODREF_UNKNOWN_PARM)
4060 kills[i].parm_index = map[kills[i].parm_index];
4061 i++;
4063 else
4064 kills.unordered_remove (i);
4066 else
4067 i++;
4070 /* Return true if the V can overlap with KILL. */
4072 static bool
4073 ipcp_argagg_and_kill_overlap_p (const ipa_argagg_value &v,
4074 const modref_access_node &kill)
4076 if (kill.parm_index == v.index)
4078 gcc_assert (kill.parm_offset_known);
4079 gcc_assert (known_eq (kill.max_size, kill.size));
4080 poly_int64 repl_size;
4081 bool ok = poly_int_tree_p (TYPE_SIZE (TREE_TYPE (v.value)),
4082 &repl_size);
4083 gcc_assert (ok);
4084 poly_int64 repl_offset (v.unit_offset);
4085 repl_offset <<= LOG2_BITS_PER_UNIT;
4086 poly_int64 combined_offset
4087 = (kill.parm_offset << LOG2_BITS_PER_UNIT) + kill.offset;
4088 if (ranges_maybe_overlap_p (repl_offset, repl_size,
4089 combined_offset, kill.size))
4090 return true;
4092 return false;
4095 /* If signature changed, update the summary. */
4097 static void
4098 update_signature (struct cgraph_node *node)
4100 modref_summary *r = optimization_summaries
4101 ? optimization_summaries->get (node) : NULL;
4102 modref_summary_lto *r_lto = summaries_lto
4103 ? summaries_lto->get (node) : NULL;
4104 if (!r && !r_lto)
4105 return;
4107 /* Propagating constants in killed memory can lead to eliminated stores in
4108 both callees (because they are considered redundant) and callers, leading
4109 to missing them altogether. */
4110 ipcp_transformation *ipcp_ts = ipcp_get_transformation_summary (node);
4111 if (ipcp_ts)
4113 for (auto &v : ipcp_ts->m_agg_values)
4115 if (!v.by_ref)
4116 continue;
4117 if (r)
4118 for (const modref_access_node &kill : r->kills)
4119 if (ipcp_argagg_and_kill_overlap_p (v, kill))
4121 v.killed = true;
4122 break;
4124 if (!v.killed && r_lto)
4125 for (const modref_access_node &kill : r_lto->kills)
4126 if (ipcp_argagg_and_kill_overlap_p (v, kill))
4128 v.killed = true;
4129 break;
4134 clone_info *info = clone_info::get (node);
4135 if (!info || !info->param_adjustments)
4136 return;
4138 if (dump_file)
4140 fprintf (dump_file, "Updating summary for %s from:\n",
4141 node->dump_name ());
4142 if (r)
4143 r->dump (dump_file);
4144 if (r_lto)
4145 r_lto->dump (dump_file);
4148 size_t i, max = 0;
4149 ipa_adjusted_param *p;
4151 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4153 int idx = info->param_adjustments->get_original_index (i);
4154 if (idx > (int)max)
4155 max = idx;
4158 auto_vec <int, 32> map;
4160 map.reserve (max + 1);
4161 for (i = 0; i <= max; i++)
4162 map.quick_push (MODREF_UNKNOWN_PARM);
4163 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4165 int idx = info->param_adjustments->get_original_index (i);
4166 if (idx >= 0)
4167 map[idx] = i;
4169 if (r)
4171 r->loads->remap_params (&map);
4172 r->stores->remap_params (&map);
4173 remap_kills (r->kills, map);
4174 if (r->arg_flags.length ())
4175 remap_arg_flags (r->arg_flags, info);
4177 if (r_lto)
4179 r_lto->loads->remap_params (&map);
4180 r_lto->stores->remap_params (&map);
4181 remap_kills (r_lto->kills, map);
4182 if (r_lto->arg_flags.length ())
4183 remap_arg_flags (r_lto->arg_flags, info);
4185 if (dump_file)
4187 fprintf (dump_file, "to:\n");
4188 if (r)
4189 r->dump (dump_file);
4190 if (r_lto)
4191 r_lto->dump (dump_file);
4193 if (r)
4194 r->finalize (node->decl);
4195 return;
4198 /* Definition of the modref IPA pass. */
4199 const pass_data pass_data_ipa_modref =
4201 IPA_PASS, /* type */
4202 "modref", /* name */
4203 OPTGROUP_IPA, /* optinfo_flags */
4204 TV_IPA_MODREF, /* tv_id */
4205 0, /* properties_required */
4206 0, /* properties_provided */
4207 0, /* properties_destroyed */
4208 0, /* todo_flags_start */
4209 ( TODO_dump_symtab ), /* todo_flags_finish */
4212 class pass_ipa_modref : public ipa_opt_pass_d
4214 public:
4215 pass_ipa_modref (gcc::context *ctxt)
4216 : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
4217 modref_generate, /* generate_summary */
4218 modref_write, /* write_summary */
4219 modref_read, /* read_summary */
4220 modref_write, /* write_optimization_summary */
4221 modref_read, /* read_optimization_summary */
4222 NULL, /* stmt_fixup */
4223 0, /* function_transform_todo_flags_start */
4224 NULL, /* function_transform */
4225 NULL) /* variable_transform */
4228 /* opt_pass methods: */
4229 opt_pass *clone () final override { return new pass_ipa_modref (m_ctxt); }
4230 bool gate (function *) final override
4232 return true;
4234 unsigned int execute (function *) final override;
4240 unsigned int pass_modref::execute (function *)
4242 if (analyze_function (false))
4243 return execute_fixup_cfg ();
4244 return 0;
4247 gimple_opt_pass *
4248 make_pass_modref (gcc::context *ctxt)
4250 return new pass_modref (ctxt);
4253 ipa_opt_pass_d *
4254 make_pass_ipa_modref (gcc::context *ctxt)
4256 return new pass_ipa_modref (ctxt);
4259 namespace {
4261 /* Skip edges from and to nodes without ipa_pure_const enabled.
4262 Ignore not available symbols. */
4264 static bool
4265 ignore_edge (struct cgraph_edge *e)
4267 /* We merge summaries of inline clones into summaries of functions they
4268 are inlined to. For that reason the complete function bodies must
4269 act as unit. */
4270 if (!e->inline_failed)
4271 return false;
4272 enum availability avail;
4273 cgraph_node *callee = e->callee->ultimate_alias_target
4274 (&avail, e->caller);
4276 return (avail <= AVAIL_INTERPOSABLE
4277 || ((!optimization_summaries || !optimization_summaries->get (callee))
4278 && (!summaries_lto || !summaries_lto->get (callee))));
4281 /* Compute parm_map for CALLEE_EDGE. */
4283 static bool
4284 compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
4286 class ipa_edge_args *args;
4287 if (ipa_node_params_sum
4288 && !callee_edge->call_stmt_cannot_inline_p
4289 && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
4291 int i, count = ipa_get_cs_argument_count (args);
4292 class ipa_node_params *caller_parms_info, *callee_pi;
4293 class ipa_call_summary *es
4294 = ipa_call_summaries->get (callee_edge);
4295 cgraph_node *callee
4296 = callee_edge->callee->ultimate_alias_target
4297 (NULL, callee_edge->caller);
4299 caller_parms_info
4300 = ipa_node_params_sum->get (callee_edge->caller->inlined_to
4301 ? callee_edge->caller->inlined_to
4302 : callee_edge->caller);
4303 callee_pi = ipa_node_params_sum->get (callee);
4305 (*parm_map).safe_grow_cleared (count, true);
4307 for (i = 0; i < count; i++)
4309 if (es && es->param[i].points_to_local_or_readonly_memory)
4311 (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
4312 continue;
4315 struct ipa_jump_func *jf
4316 = ipa_get_ith_jump_func (args, i);
4317 if (jf && callee_pi)
4319 tree cst = ipa_value_from_jfunc (caller_parms_info,
4321 ipa_get_type
4322 (callee_pi, i));
4323 if (cst && points_to_local_or_readonly_memory_p (cst))
4325 (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
4326 continue;
4329 if (jf && jf->type == IPA_JF_PASS_THROUGH)
4331 (*parm_map)[i].parm_index
4332 = ipa_get_jf_pass_through_formal_id (jf);
4333 if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
4335 (*parm_map)[i].parm_offset_known = true;
4336 (*parm_map)[i].parm_offset = 0;
4338 else if (ipa_get_jf_pass_through_operation (jf)
4339 == POINTER_PLUS_EXPR
4340 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
4341 &(*parm_map)[i].parm_offset))
4342 (*parm_map)[i].parm_offset_known = true;
4343 else
4344 (*parm_map)[i].parm_offset_known = false;
4345 continue;
4347 if (jf && jf->type == IPA_JF_ANCESTOR)
4349 (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
4350 (*parm_map)[i].parm_offset_known = true;
4351 gcc_checking_assert
4352 (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
4353 (*parm_map)[i].parm_offset
4354 = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
4356 else
4357 (*parm_map)[i].parm_index = -1;
4359 if (dump_file)
4361 fprintf (dump_file, " Parm map: ");
4362 for (i = 0; i < count; i++)
4363 fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
4364 fprintf (dump_file, "\n");
4366 return true;
4368 return false;
4371 /* Map used to translate escape infos. */
4373 struct escape_map
4375 int parm_index;
4376 bool direct;
4379 /* Update escape map for E. */
4381 static void
4382 update_escape_summary_1 (cgraph_edge *e,
4383 vec <vec <escape_map>> &map,
4384 bool ignore_stores)
4386 escape_summary *sum = escape_summaries->get (e);
4387 if (!sum)
4388 return;
4389 auto_vec <escape_entry> old = sum->esc.copy ();
4390 sum->esc.release ();
4392 unsigned int i;
4393 escape_entry *ee;
4394 FOR_EACH_VEC_ELT (old, i, ee)
4396 unsigned int j;
4397 struct escape_map *em;
4398 /* TODO: We do not have jump functions for return slots, so we
4399 never propagate them to outer function. */
4400 if (ee->parm_index >= (int)map.length ()
4401 || ee->parm_index < 0)
4402 continue;
4403 FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
4405 int min_flags = ee->min_flags;
4406 if (ee->direct && !em->direct)
4407 min_flags = deref_flags (min_flags, ignore_stores);
4408 struct escape_entry entry = {em->parm_index, ee->arg,
4409 min_flags,
4410 ee->direct & em->direct};
4411 sum->esc.safe_push (entry);
4414 if (!sum->esc.length ())
4415 escape_summaries->remove (e);
4418 /* Update escape map for NODE. */
4420 static void
4421 update_escape_summary (cgraph_node *node,
4422 vec <vec <escape_map>> &map,
4423 bool ignore_stores)
4425 if (!escape_summaries)
4426 return;
4427 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
4428 update_escape_summary_1 (e, map, ignore_stores);
4429 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
4431 if (!e->inline_failed)
4432 update_escape_summary (e->callee, map, ignore_stores);
4433 else
4434 update_escape_summary_1 (e, map, ignore_stores);
4438 /* Get parameter type from DECL. This is only safe for special cases
4439 like builtins we create fnspec for because the type match is checked
4440 at fnspec creation time. */
4442 static tree
4443 get_parm_type (tree decl, unsigned int i)
4445 tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
4447 for (unsigned int p = 0; p < i; p++)
4448 t = TREE_CHAIN (t);
4449 return TREE_VALUE (t);
4452 /* Return access mode for argument I of call E with FNSPEC. */
4454 static modref_access_node
4455 get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
4456 unsigned int i, modref_parm_map &map)
4458 tree size = NULL_TREE;
4459 unsigned int size_arg;
4461 if (!fnspec.arg_specified_p (i))
4463 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
4465 cgraph_node *node = e->caller->inlined_to
4466 ? e->caller->inlined_to : e->caller;
4467 ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
4468 ipa_edge_args *args = ipa_edge_args_sum->get (e);
4469 struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
4471 if (jf)
4472 size = ipa_value_from_jfunc (caller_parms_info, jf,
4473 get_parm_type (e->callee->decl, size_arg));
4475 else if (fnspec.arg_access_size_given_by_type_p (i))
4476 size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
4477 modref_access_node a = {0, -1, -1,
4478 map.parm_offset, map.parm_index,
4479 map.parm_offset_known, 0};
4480 poly_int64 size_hwi;
4481 if (size
4482 && poly_int_tree_p (size, &size_hwi)
4483 && coeffs_in_range_p (size_hwi, 0,
4484 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
4486 a.size = -1;
4487 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
4489 return a;
4492 /* Collapse loads and return true if something changed. */
4493 static bool
4494 collapse_loads (modref_summary *cur_summary,
4495 modref_summary_lto *cur_summary_lto)
4497 bool changed = false;
4499 if (cur_summary && !cur_summary->loads->every_base)
4501 cur_summary->loads->collapse ();
4502 changed = true;
4504 if (cur_summary_lto
4505 && !cur_summary_lto->loads->every_base)
4507 cur_summary_lto->loads->collapse ();
4508 changed = true;
4510 return changed;
4513 /* Collapse loads and return true if something changed. */
4515 static bool
4516 collapse_stores (modref_summary *cur_summary,
4517 modref_summary_lto *cur_summary_lto)
4519 bool changed = false;
4521 if (cur_summary && !cur_summary->stores->every_base)
4523 cur_summary->stores->collapse ();
4524 changed = true;
4526 if (cur_summary_lto
4527 && !cur_summary_lto->stores->every_base)
4529 cur_summary_lto->stores->collapse ();
4530 changed = true;
4532 return changed;
4535 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
4536 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
4538 static bool
4539 propagate_unknown_call (cgraph_node *node,
4540 cgraph_edge *e, int ecf_flags,
4541 modref_summary *cur_summary,
4542 modref_summary_lto *cur_summary_lto,
4543 bool nontrivial_scc)
4545 bool changed = false;
4546 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
4547 auto_vec <modref_parm_map, 32> parm_map;
4548 bool looping;
4550 if (e->callee
4551 && builtin_safe_for_const_function_p (&looping, e->callee->decl))
4553 if (looping && cur_summary && !cur_summary->side_effects)
4555 cur_summary->side_effects = true;
4556 changed = true;
4558 if (looping && cur_summary_lto && !cur_summary_lto->side_effects)
4560 cur_summary_lto->side_effects = true;
4561 changed = true;
4563 return changed;
4566 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE))
4567 || (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
4568 || nontrivial_scc)
4570 if (cur_summary && !cur_summary->side_effects)
4572 cur_summary->side_effects = true;
4573 changed = true;
4575 if (cur_summary_lto && !cur_summary_lto->side_effects)
4577 cur_summary_lto->side_effects = true;
4578 changed = true;
4580 if (cur_summary && !cur_summary->nondeterministic
4581 && !ignore_nondeterminism_p (node->decl, ecf_flags))
4583 cur_summary->nondeterministic = true;
4584 changed = true;
4586 if (cur_summary_lto && !cur_summary_lto->nondeterministic
4587 && !ignore_nondeterminism_p (node->decl, ecf_flags))
4589 cur_summary_lto->nondeterministic = true;
4590 changed = true;
4593 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
4594 return changed;
4596 if (fnspec_sum
4597 && compute_parm_map (e, &parm_map))
4599 attr_fnspec fnspec (fnspec_sum->fnspec);
4601 gcc_checking_assert (fnspec.known_p ());
4602 if (fnspec.global_memory_read_p ())
4603 collapse_loads (cur_summary, cur_summary_lto);
4604 else
4606 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4607 for (unsigned i = 0; i < parm_map.length () && t;
4608 i++, t = TREE_CHAIN (t))
4609 if (!POINTER_TYPE_P (TREE_VALUE (t)))
4611 else if (!fnspec.arg_specified_p (i)
4612 || fnspec.arg_maybe_read_p (i))
4614 modref_parm_map map = parm_map[i];
4615 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4616 continue;
4617 if (map.parm_index == MODREF_UNKNOWN_PARM)
4619 collapse_loads (cur_summary, cur_summary_lto);
4620 break;
4622 if (cur_summary)
4623 changed |= cur_summary->loads->insert
4624 (node->decl, 0, 0,
4625 get_access_for_fnspec (e, fnspec, i, map), false);
4626 if (cur_summary_lto)
4627 changed |= cur_summary_lto->loads->insert
4628 (node->decl, 0, 0,
4629 get_access_for_fnspec (e, fnspec, i, map), false);
4632 if (ignore_stores_p (node->decl, ecf_flags))
4634 else if (fnspec.global_memory_written_p ())
4635 collapse_stores (cur_summary, cur_summary_lto);
4636 else
4638 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4639 for (unsigned i = 0; i < parm_map.length () && t;
4640 i++, t = TREE_CHAIN (t))
4641 if (!POINTER_TYPE_P (TREE_VALUE (t)))
4643 else if (!fnspec.arg_specified_p (i)
4644 || fnspec.arg_maybe_written_p (i))
4646 modref_parm_map map = parm_map[i];
4647 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4648 continue;
4649 if (map.parm_index == MODREF_UNKNOWN_PARM)
4651 collapse_stores (cur_summary, cur_summary_lto);
4652 break;
4654 if (cur_summary)
4655 changed |= cur_summary->stores->insert
4656 (node->decl, 0, 0,
4657 get_access_for_fnspec (e, fnspec, i, map), false);
4658 if (cur_summary_lto)
4659 changed |= cur_summary_lto->stores->insert
4660 (node->decl, 0, 0,
4661 get_access_for_fnspec (e, fnspec, i, map), false);
4664 if (fnspec.errno_maybe_written_p () && flag_errno_math)
4666 if (cur_summary && !cur_summary->writes_errno)
4668 cur_summary->writes_errno = true;
4669 changed = true;
4671 if (cur_summary_lto && !cur_summary_lto->writes_errno)
4673 cur_summary_lto->writes_errno = true;
4674 changed = true;
4677 return changed;
4679 if (dump_file)
4680 fprintf (dump_file, " collapsing loads\n");
4681 changed |= collapse_loads (cur_summary, cur_summary_lto);
4682 if (!ignore_stores_p (node->decl, ecf_flags))
4684 if (dump_file)
4685 fprintf (dump_file, " collapsing stores\n");
4686 changed |= collapse_stores (cur_summary, cur_summary_lto);
4688 return changed;
4691 /* Maybe remove summaries of NODE pointed to by CUR_SUMMARY_PTR
4692 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
4694 static void
4695 remove_useless_summaries (cgraph_node *node,
4696 modref_summary **cur_summary_ptr,
4697 modref_summary_lto **cur_summary_lto_ptr,
4698 int ecf_flags)
4700 if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
4702 optimization_summaries->remove (node);
4703 *cur_summary_ptr = NULL;
4705 if (*cur_summary_lto_ptr
4706 && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
4708 summaries_lto->remove (node);
4709 *cur_summary_lto_ptr = NULL;
4713 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4714 and propagate loads/stores. */
4716 static bool
4717 modref_propagate_in_scc (cgraph_node *component_node)
4719 bool changed = true;
4720 bool first = true;
4721 int iteration = 0;
4723 while (changed)
4725 bool nontrivial_scc
4726 = ((struct ipa_dfs_info *) component_node->aux)->next_cycle;
4727 changed = false;
4728 for (struct cgraph_node *cur = component_node; cur;
4729 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4731 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
4732 modref_summary *cur_summary = optimization_summaries
4733 ? optimization_summaries->get (node)
4734 : NULL;
4735 modref_summary_lto *cur_summary_lto = summaries_lto
4736 ? summaries_lto->get (node)
4737 : NULL;
4739 if (!cur_summary && !cur_summary_lto)
4740 continue;
4742 int cur_ecf_flags = flags_from_decl_or_type (node->decl);
4744 if (dump_file)
4745 fprintf (dump_file, " Processing %s%s%s\n",
4746 cur->dump_name (),
4747 TREE_READONLY (cur->decl) ? " (const)" : "",
4748 DECL_PURE_P (cur->decl) ? " (pure)" : "");
4750 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
4752 if (dump_file)
4753 fprintf (dump_file, " Indirect call\n");
4754 if (propagate_unknown_call
4755 (node, e, e->indirect_info->ecf_flags,
4756 cur_summary, cur_summary_lto,
4757 nontrivial_scc))
4759 changed = true;
4760 remove_useless_summaries (node, &cur_summary,
4761 &cur_summary_lto,
4762 cur_ecf_flags);
4763 if (!cur_summary && !cur_summary_lto)
4764 break;
4768 if (!cur_summary && !cur_summary_lto)
4769 continue;
4771 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
4772 callee_edge = callee_edge->next_callee)
4774 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
4775 modref_summary *callee_summary = NULL;
4776 modref_summary_lto *callee_summary_lto = NULL;
4777 struct cgraph_node *callee;
4779 if (!callee_edge->inline_failed
4780 || ((flags & (ECF_CONST | ECF_NOVOPS))
4781 && !(flags & ECF_LOOPING_CONST_OR_PURE)))
4782 continue;
4784 /* Get the callee and its summary. */
4785 enum availability avail;
4786 callee = callee_edge->callee->ultimate_alias_target
4787 (&avail, cur);
4789 /* It is not necessary to re-process calls outside of the
4790 SCC component. */
4791 if (iteration > 0
4792 && (!callee->aux
4793 || ((struct ipa_dfs_info *)cur->aux)->scc_no
4794 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
4795 continue;
4797 if (dump_file)
4798 fprintf (dump_file, " Call to %s\n",
4799 callee_edge->callee->dump_name ());
4801 bool ignore_stores = ignore_stores_p (cur->decl, flags);
4803 if (avail <= AVAIL_INTERPOSABLE)
4805 if (dump_file)
4806 fprintf (dump_file, " Call target interposable"
4807 " or not available\n");
4808 changed |= propagate_unknown_call
4809 (node, callee_edge, flags,
4810 cur_summary, cur_summary_lto,
4811 nontrivial_scc);
4812 if (!cur_summary && !cur_summary_lto)
4813 break;
4814 continue;
4817 /* We don't know anything about CALLEE, hence we cannot tell
4818 anything about the entire component. */
4820 if (cur_summary
4821 && !(callee_summary = optimization_summaries->get (callee)))
4823 if (dump_file)
4824 fprintf (dump_file, " No call target summary\n");
4825 changed |= propagate_unknown_call
4826 (node, callee_edge, flags,
4827 cur_summary, NULL,
4828 nontrivial_scc);
4830 if (cur_summary_lto
4831 && !(callee_summary_lto = summaries_lto->get (callee)))
4833 if (dump_file)
4834 fprintf (dump_file, " No call target summary\n");
4835 changed |= propagate_unknown_call
4836 (node, callee_edge, flags,
4837 NULL, cur_summary_lto,
4838 nontrivial_scc);
4841 if (callee_summary && !cur_summary->side_effects
4842 && (callee_summary->side_effects
4843 || callee_edge->recursive_p ()))
4845 cur_summary->side_effects = true;
4846 changed = true;
4848 if (callee_summary_lto && !cur_summary_lto->side_effects
4849 && (callee_summary_lto->side_effects
4850 || callee_edge->recursive_p ()))
4852 cur_summary_lto->side_effects = true;
4853 changed = true;
4855 if (callee_summary && !cur_summary->nondeterministic
4856 && callee_summary->nondeterministic
4857 && !ignore_nondeterminism_p (cur->decl, flags))
4859 cur_summary->nondeterministic = true;
4860 changed = true;
4862 if (callee_summary_lto && !cur_summary_lto->nondeterministic
4863 && callee_summary_lto->nondeterministic
4864 && !ignore_nondeterminism_p (cur->decl, flags))
4866 cur_summary_lto->nondeterministic = true;
4867 changed = true;
4869 if (flags & (ECF_CONST | ECF_NOVOPS))
4870 continue;
4872 /* We can not safely optimize based on summary of callee if it
4873 does not always bind to current def: it is possible that
4874 memory load was optimized out earlier which may not happen in
4875 the interposed variant. */
4876 if (!callee_edge->binds_to_current_def_p ())
4878 if (cur_summary && !cur_summary->calls_interposable)
4880 cur_summary->calls_interposable = true;
4881 changed = true;
4883 if (cur_summary_lto && !cur_summary_lto->calls_interposable)
4885 cur_summary_lto->calls_interposable = true;
4886 changed = true;
4888 if (dump_file)
4889 fprintf (dump_file, " May not bind local;"
4890 " collapsing loads\n");
4894 auto_vec <modref_parm_map, 32> parm_map;
4895 modref_parm_map chain_map;
4896 /* TODO: Once we get jump functions for static chains we could
4897 compute this. */
4898 chain_map.parm_index = MODREF_UNKNOWN_PARM;
4900 compute_parm_map (callee_edge, &parm_map);
4902 /* Merge in callee's information. */
4903 if (callee_summary)
4905 changed |= cur_summary->loads->merge
4906 (node->decl, callee_summary->loads,
4907 &parm_map, &chain_map, !first);
4908 if (!ignore_stores)
4910 changed |= cur_summary->stores->merge
4911 (node->decl, callee_summary->stores,
4912 &parm_map, &chain_map, !first);
4913 if (!cur_summary->writes_errno
4914 && callee_summary->writes_errno)
4916 cur_summary->writes_errno = true;
4917 changed = true;
4921 if (callee_summary_lto)
4923 changed |= cur_summary_lto->loads->merge
4924 (node->decl, callee_summary_lto->loads,
4925 &parm_map, &chain_map, !first);
4926 if (!ignore_stores)
4928 changed |= cur_summary_lto->stores->merge
4929 (node->decl, callee_summary_lto->stores,
4930 &parm_map, &chain_map, !first);
4931 if (!cur_summary_lto->writes_errno
4932 && callee_summary_lto->writes_errno)
4934 cur_summary_lto->writes_errno = true;
4935 changed = true;
4939 if (changed)
4940 remove_useless_summaries (node, &cur_summary,
4941 &cur_summary_lto,
4942 cur_ecf_flags);
4943 if (!cur_summary && !cur_summary_lto)
4944 break;
4945 if (dump_file && changed)
4947 if (cur_summary)
4948 cur_summary->dump (dump_file);
4949 if (cur_summary_lto)
4950 cur_summary_lto->dump (dump_file);
4951 dump_modref_edge_summaries (dump_file, node, 4);
4955 iteration++;
4956 first = false;
4958 if (dump_file)
4959 fprintf (dump_file,
4960 "Propagation finished in %i iterations\n", iteration);
4961 bool pureconst = false;
4962 for (struct cgraph_node *cur = component_node; cur;
4963 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4964 if (!cur->inlined_to && opt_for_fn (cur->decl, flag_ipa_pure_const))
4966 modref_summary *summary = optimization_summaries
4967 ? optimization_summaries->get (cur)
4968 : NULL;
4969 modref_summary_lto *summary_lto = summaries_lto
4970 ? summaries_lto->get (cur)
4971 : NULL;
4972 if (summary && !summary->stores->every_base && !summary->stores->bases
4973 && !summary->nondeterministic)
4975 if (!summary->loads->every_base && !summary->loads->bases
4976 && !summary->calls_interposable)
4977 pureconst |= ipa_make_function_const
4978 (cur, summary->side_effects, false);
4979 else
4980 pureconst |= ipa_make_function_pure
4981 (cur, summary->side_effects, false);
4983 if (summary_lto && !summary_lto->stores->every_base
4984 && !summary_lto->stores->bases && !summary_lto->nondeterministic)
4986 if (!summary_lto->loads->every_base && !summary_lto->loads->bases
4987 && !summary_lto->calls_interposable)
4988 pureconst |= ipa_make_function_const
4989 (cur, summary_lto->side_effects, false);
4990 else
4991 pureconst |= ipa_make_function_pure
4992 (cur, summary_lto->side_effects, false);
4995 return pureconst;
4998 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
5000 static void
5001 modref_propagate_dump_scc (cgraph_node *component_node)
5003 for (struct cgraph_node *cur = component_node; cur;
5004 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5005 if (!cur->inlined_to)
5007 modref_summary *cur_summary = optimization_summaries
5008 ? optimization_summaries->get (cur)
5009 : NULL;
5010 modref_summary_lto *cur_summary_lto = summaries_lto
5011 ? summaries_lto->get (cur)
5012 : NULL;
5014 fprintf (dump_file, "Propagated modref for %s%s%s\n",
5015 cur->dump_name (),
5016 TREE_READONLY (cur->decl) ? " (const)" : "",
5017 DECL_PURE_P (cur->decl) ? " (pure)" : "");
5018 if (optimization_summaries)
5020 if (cur_summary)
5021 cur_summary->dump (dump_file);
5022 else
5023 fprintf (dump_file, " Not tracked\n");
5025 if (summaries_lto)
5027 if (cur_summary_lto)
5028 cur_summary_lto->dump (dump_file);
5029 else
5030 fprintf (dump_file, " Not tracked (lto)\n");
5035 /* Determine EAF flags know for call E with CALLEE_ECF_FLAGS and ARG. */
5038 implicit_eaf_flags_for_edge_and_arg (cgraph_edge *e, int callee_ecf_flags,
5039 bool ignore_stores, int arg)
5041 /* Returning the value is already accounted to at local propagation. */
5042 int implicit_flags = EAF_NOT_RETURNED_DIRECTLY
5043 | EAF_NOT_RETURNED_INDIRECTLY;
5044 if (ignore_stores)
5045 implicit_flags |= ignore_stores_eaf_flags;
5046 if (callee_ecf_flags & ECF_PURE)
5047 implicit_flags |= implicit_pure_eaf_flags;
5048 if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
5049 implicit_flags |= implicit_const_eaf_flags;
5050 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
5051 if (fnspec_sum)
5053 attr_fnspec fnspec (fnspec_sum->fnspec);
5054 implicit_flags |= fnspec.arg_eaf_flags (arg);
5056 return implicit_flags;
5059 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
5060 and SUMMARY_LTO to CUR_SUMMARY_LTO.
5061 Return true if something changed. */
5063 static bool
5064 modref_merge_call_site_flags (escape_summary *sum,
5065 modref_summary *cur_summary,
5066 modref_summary_lto *cur_summary_lto,
5067 modref_summary *summary,
5068 modref_summary_lto *summary_lto,
5069 tree caller,
5070 cgraph_edge *e,
5071 int caller_ecf_flags,
5072 int callee_ecf_flags,
5073 bool binds_to_current_def)
5075 escape_entry *ee;
5076 unsigned int i;
5077 bool changed = false;
5078 bool ignore_stores = ignore_stores_p (caller, callee_ecf_flags);
5080 /* Return early if we have no useful info to propagate. */
5081 if ((!cur_summary
5082 || (!cur_summary->arg_flags.length ()
5083 && !cur_summary->static_chain_flags
5084 && !cur_summary->retslot_flags))
5085 && (!cur_summary_lto
5086 || (!cur_summary_lto->arg_flags.length ()
5087 && !cur_summary_lto->static_chain_flags
5088 && !cur_summary_lto->retslot_flags)))
5089 return false;
5091 FOR_EACH_VEC_ELT (sum->esc, i, ee)
5093 int flags = 0;
5094 int flags_lto = 0;
5095 int implicit_flags = implicit_eaf_flags_for_edge_and_arg
5096 (e, callee_ecf_flags, ignore_stores, ee->arg);
5098 if (summary && ee->arg < summary->arg_flags.length ())
5099 flags = summary->arg_flags[ee->arg];
5100 if (summary_lto
5101 && ee->arg < summary_lto->arg_flags.length ())
5102 flags_lto = summary_lto->arg_flags[ee->arg];
5103 if (!ee->direct)
5105 flags = deref_flags (flags, ignore_stores);
5106 flags_lto = deref_flags (flags_lto, ignore_stores);
5108 if (ignore_stores)
5109 implicit_flags |= ignore_stores_eaf_flags;
5110 if (callee_ecf_flags & ECF_PURE)
5111 implicit_flags |= implicit_pure_eaf_flags;
5112 if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
5113 implicit_flags |= implicit_const_eaf_flags;
5114 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
5115 if (fnspec_sum)
5117 attr_fnspec fnspec (fnspec_sum->fnspec);
5118 implicit_flags |= fnspec.arg_eaf_flags (ee->arg);
5120 if (!ee->direct)
5121 implicit_flags = deref_flags (implicit_flags, ignore_stores);
5122 flags |= implicit_flags;
5123 flags_lto |= implicit_flags;
5124 if (!binds_to_current_def && (flags || flags_lto))
5126 flags = interposable_eaf_flags (flags, implicit_flags);
5127 flags_lto = interposable_eaf_flags (flags_lto, implicit_flags);
5129 if (!(flags & EAF_UNUSED)
5130 && cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ())
5132 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5133 ? cur_summary->retslot_flags
5134 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5135 ? cur_summary->static_chain_flags
5136 : cur_summary->arg_flags[ee->parm_index];
5137 if ((f & flags) != f)
5139 f = remove_useless_eaf_flags
5140 (f & flags, caller_ecf_flags,
5141 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
5142 changed = true;
5145 if (!(flags_lto & EAF_UNUSED)
5146 && cur_summary_lto
5147 && ee->parm_index < (int)cur_summary_lto->arg_flags.length ())
5149 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5150 ? cur_summary_lto->retslot_flags
5151 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5152 ? cur_summary_lto->static_chain_flags
5153 : cur_summary_lto->arg_flags[ee->parm_index];
5154 if ((f & flags_lto) != f)
5156 f = remove_useless_eaf_flags
5157 (f & flags_lto, caller_ecf_flags,
5158 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
5159 changed = true;
5163 return changed;
5166 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
5167 and propagate arg flags. */
5169 static void
5170 modref_propagate_flags_in_scc (cgraph_node *component_node)
5172 bool changed = true;
5173 int iteration = 0;
5175 while (changed)
5177 changed = false;
5178 for (struct cgraph_node *cur = component_node; cur;
5179 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5181 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
5182 modref_summary *cur_summary = optimization_summaries
5183 ? optimization_summaries->get (node)
5184 : NULL;
5185 modref_summary_lto *cur_summary_lto = summaries_lto
5186 ? summaries_lto->get (node)
5187 : NULL;
5189 if (!cur_summary && !cur_summary_lto)
5190 continue;
5191 int caller_ecf_flags = flags_from_decl_or_type (cur->decl);
5193 if (dump_file)
5194 fprintf (dump_file, " Processing %s%s%s\n",
5195 cur->dump_name (),
5196 TREE_READONLY (cur->decl) ? " (const)" : "",
5197 DECL_PURE_P (cur->decl) ? " (pure)" : "");
5199 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
5201 escape_summary *sum = escape_summaries->get (e);
5203 if (!sum || (e->indirect_info->ecf_flags
5204 & (ECF_CONST | ECF_NOVOPS)))
5205 continue;
5207 changed |= modref_merge_call_site_flags
5208 (sum, cur_summary, cur_summary_lto,
5209 NULL, NULL,
5210 node->decl,
5212 caller_ecf_flags,
5213 e->indirect_info->ecf_flags,
5214 false);
5217 if (!cur_summary && !cur_summary_lto)
5218 continue;
5220 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
5221 callee_edge = callee_edge->next_callee)
5223 int ecf_flags = flags_from_decl_or_type
5224 (callee_edge->callee->decl);
5225 modref_summary *callee_summary = NULL;
5226 modref_summary_lto *callee_summary_lto = NULL;
5227 struct cgraph_node *callee;
5229 if (ecf_flags & (ECF_CONST | ECF_NOVOPS)
5230 || !callee_edge->inline_failed)
5231 continue;
5233 /* Get the callee and its summary. */
5234 enum availability avail;
5235 callee = callee_edge->callee->ultimate_alias_target
5236 (&avail, cur);
5238 /* It is not necessary to re-process calls outside of the
5239 SCC component. */
5240 if (iteration > 0
5241 && (!callee->aux
5242 || ((struct ipa_dfs_info *)cur->aux)->scc_no
5243 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
5244 continue;
5246 escape_summary *sum = escape_summaries->get (callee_edge);
5247 if (!sum)
5248 continue;
5250 if (dump_file)
5251 fprintf (dump_file, " Call to %s\n",
5252 callee_edge->callee->dump_name ());
5254 if (avail <= AVAIL_INTERPOSABLE
5255 || callee_edge->call_stmt_cannot_inline_p)
5257 else
5259 if (cur_summary)
5260 callee_summary = optimization_summaries->get (callee);
5261 if (cur_summary_lto)
5262 callee_summary_lto = summaries_lto->get (callee);
5264 changed |= modref_merge_call_site_flags
5265 (sum, cur_summary, cur_summary_lto,
5266 callee_summary, callee_summary_lto,
5267 node->decl,
5268 callee_edge,
5269 caller_ecf_flags,
5270 ecf_flags,
5271 callee->binds_to_current_def_p ());
5272 if (dump_file && changed)
5274 if (cur_summary)
5275 cur_summary->dump (dump_file);
5276 if (cur_summary_lto)
5277 cur_summary_lto->dump (dump_file);
5281 iteration++;
5283 if (dump_file)
5284 fprintf (dump_file,
5285 "Propagation of flags finished in %i iterations\n", iteration);
5288 } /* ANON namespace. */
5290 /* Call EDGE was inlined; merge summary from callee to the caller. */
5292 void
5293 ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
5295 if (!summaries && !summaries_lto)
5296 return;
5298 struct cgraph_node *to = (edge->caller->inlined_to
5299 ? edge->caller->inlined_to : edge->caller);
5300 class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
5301 class modref_summary_lto *to_info_lto = summaries_lto
5302 ? summaries_lto->get (to) : NULL;
5304 if (!to_info && !to_info_lto)
5306 if (summaries)
5307 summaries->remove (edge->callee);
5308 if (summaries_lto)
5309 summaries_lto->remove (edge->callee);
5310 remove_modref_edge_summaries (edge->callee);
5311 return;
5314 class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
5315 : NULL;
5316 class modref_summary_lto *callee_info_lto
5317 = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
5318 int flags = flags_from_decl_or_type (edge->callee->decl);
5319 /* Combine in outer flags. */
5320 cgraph_node *n;
5321 for (n = edge->caller; n->inlined_to; n = n->callers->caller)
5322 flags |= flags_from_decl_or_type (n->decl);
5323 flags |= flags_from_decl_or_type (n->decl);
5324 bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
5326 if (!callee_info && to_info)
5328 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5329 to_info->loads->collapse ();
5330 if (!ignore_stores)
5331 to_info->stores->collapse ();
5333 if (!callee_info_lto && to_info_lto)
5335 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5336 to_info_lto->loads->collapse ();
5337 if (!ignore_stores)
5338 to_info_lto->stores->collapse ();
5340 /* Merge side effects and non-determinism.
5341 PURE/CONST flags makes functions deterministic and if there is
5342 no LOOPING_CONST_OR_PURE they also have no side effects. */
5343 if (!(flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE))
5344 || (flags & ECF_LOOPING_CONST_OR_PURE))
5346 if (to_info)
5348 if (!callee_info || callee_info->side_effects)
5349 to_info->side_effects = true;
5350 if ((!callee_info || callee_info->nondeterministic)
5351 && !ignore_nondeterminism_p (edge->caller->decl, flags))
5352 to_info->nondeterministic = true;
5354 if (to_info_lto)
5356 if (!callee_info_lto || callee_info_lto->side_effects)
5357 to_info_lto->side_effects = true;
5358 if ((!callee_info_lto || callee_info_lto->nondeterministic)
5359 && !ignore_nondeterminism_p (edge->caller->decl, flags))
5360 to_info_lto->nondeterministic = true;
5363 if (callee_info || callee_info_lto)
5365 auto_vec <modref_parm_map, 32> parm_map;
5366 modref_parm_map chain_map;
5367 /* TODO: Once we get jump functions for static chains we could
5368 compute parm_index. */
5370 compute_parm_map (edge, &parm_map);
5372 if (!ignore_stores)
5374 if (to_info && callee_info)
5375 to_info->stores->merge (to->decl, callee_info->stores, &parm_map,
5376 &chain_map, false);
5377 if (to_info_lto && callee_info_lto)
5378 to_info_lto->stores->merge (to->decl, callee_info_lto->stores,
5379 &parm_map, &chain_map, false);
5381 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5383 if (to_info && callee_info)
5384 to_info->loads->merge (to->decl, callee_info->loads, &parm_map,
5385 &chain_map, false);
5386 if (to_info_lto && callee_info_lto)
5387 to_info_lto->loads->merge (to->decl, callee_info_lto->loads,
5388 &parm_map, &chain_map, false);
5392 /* Now merge escape summaries.
5393 For every escape to the callee we need to merge callee flags
5394 and remap callee's escapes. */
5395 class escape_summary *sum = escape_summaries->get (edge);
5396 int max_escape = -1;
5397 escape_entry *ee;
5398 unsigned int i;
5400 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
5401 FOR_EACH_VEC_ELT (sum->esc, i, ee)
5402 if ((int)ee->arg > max_escape)
5403 max_escape = ee->arg;
5405 auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
5406 emap.safe_grow (max_escape + 1, true);
5407 for (i = 0; (int)i < max_escape + 1; i++)
5408 emap[i] = vNULL;
5410 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
5411 FOR_EACH_VEC_ELT (sum->esc, i, ee)
5413 bool needed = false;
5414 int implicit_flags = implicit_eaf_flags_for_edge_and_arg
5415 (edge, flags, ignore_stores,
5416 ee->arg);
5417 if (!ee->direct)
5418 implicit_flags = deref_flags (implicit_flags, ignore_stores);
5419 if (to_info && (int)to_info->arg_flags.length () > ee->parm_index)
5421 int flags = callee_info
5422 && callee_info->arg_flags.length () > ee->arg
5423 ? callee_info->arg_flags[ee->arg] : 0;
5424 if (!ee->direct)
5425 flags = deref_flags (flags, ignore_stores);
5426 flags |= ee->min_flags | implicit_flags;
5427 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5428 ? to_info->retslot_flags
5429 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5430 ? to_info->static_chain_flags
5431 : to_info->arg_flags[ee->parm_index];
5432 f &= flags;
5433 if (f)
5434 needed = true;
5436 if (to_info_lto
5437 && (int)to_info_lto->arg_flags.length () > ee->parm_index)
5439 int flags = callee_info_lto
5440 && callee_info_lto->arg_flags.length () > ee->arg
5441 ? callee_info_lto->arg_flags[ee->arg] : 0;
5442 if (!ee->direct)
5443 flags = deref_flags (flags, ignore_stores);
5444 flags |= ee->min_flags | implicit_flags;
5445 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5446 ? to_info_lto->retslot_flags
5447 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5448 ? to_info_lto->static_chain_flags
5449 : to_info_lto->arg_flags[ee->parm_index];
5450 f &= flags;
5451 if (f)
5452 needed = true;
5454 struct escape_map entry = {ee->parm_index, ee->direct};
5455 if (needed)
5456 emap[ee->arg].safe_push (entry);
5458 update_escape_summary (edge->callee, emap, ignore_stores);
5459 for (i = 0; (int)i < max_escape + 1; i++)
5460 emap[i].release ();
5461 if (sum)
5462 escape_summaries->remove (edge);
5464 if (summaries)
5466 if (to_info && !to_info->useful_p (flags))
5468 if (dump_file)
5469 fprintf (dump_file, "Removed mod-ref summary for %s\n",
5470 to->dump_name ());
5471 summaries->remove (to);
5472 to_info = NULL;
5474 else if (to_info && dump_file)
5476 if (dump_file)
5477 fprintf (dump_file, "Updated mod-ref summary for %s\n",
5478 to->dump_name ());
5479 to_info->dump (dump_file);
5481 if (callee_info)
5482 summaries->remove (edge->callee);
5484 if (summaries_lto)
5486 if (to_info_lto && !to_info_lto->useful_p (flags))
5488 if (dump_file)
5489 fprintf (dump_file, "Removed mod-ref summary for %s\n",
5490 to->dump_name ());
5491 summaries_lto->remove (to);
5492 to_info_lto = NULL;
5494 else if (to_info_lto && dump_file)
5496 if (dump_file)
5497 fprintf (dump_file, "Updated mod-ref summary for %s\n",
5498 to->dump_name ());
5499 to_info_lto->dump (dump_file);
5501 if (callee_info_lto)
5502 summaries_lto->remove (edge->callee);
5504 if (!to_info && !to_info_lto)
5505 remove_modref_edge_summaries (to);
5506 return;
5509 /* Run the IPA pass. This will take a function's summaries and calls and
5510 construct new summaries which represent a transitive closure. So that
5511 summary of an analyzed function contains information about the loads and
5512 stores that the function or any function that it calls does. */
5514 unsigned int
5515 pass_ipa_modref::execute (function *)
5517 if (!summaries && !summaries_lto)
5518 return 0;
5519 bool pureconst = false;
5521 if (optimization_summaries)
5522 ggc_delete (optimization_summaries);
5523 optimization_summaries = summaries;
5524 summaries = NULL;
5526 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
5527 symtab->cgraph_count);
5528 int order_pos;
5529 order_pos = ipa_reduced_postorder (order, true, ignore_edge);
5530 int i;
5532 /* Iterate over all strongly connected components in post-order. */
5533 for (i = 0; i < order_pos; i++)
5535 /* Get the component's representative. That's just any node in the
5536 component from which we can traverse the entire component. */
5537 struct cgraph_node *component_node = order[i];
5539 if (dump_file)
5540 fprintf (dump_file, "\n\nStart of SCC component\n");
5542 pureconst |= modref_propagate_in_scc (component_node);
5543 modref_propagate_flags_in_scc (component_node);
5544 if (optimization_summaries)
5545 for (struct cgraph_node *cur = component_node; cur;
5546 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5547 if (modref_summary *sum = optimization_summaries->get (cur))
5548 sum->finalize (cur->decl);
5549 if (dump_file)
5550 modref_propagate_dump_scc (component_node);
5552 cgraph_node *node;
5553 FOR_EACH_FUNCTION (node)
5554 update_signature (node);
5555 if (summaries_lto)
5556 ((modref_summaries_lto *)summaries_lto)->propagated = true;
5557 ipa_free_postorder_info ();
5558 free (order);
5559 delete fnspec_summaries;
5560 fnspec_summaries = NULL;
5561 delete escape_summaries;
5562 escape_summaries = NULL;
5564 /* If we possibly made constructors const/pure we may need to remove
5565 them. */
5566 return pureconst ? TODO_remove_functions : 0;
5569 /* Summaries must stay alive until end of compilation. */
5571 void
5572 ipa_modref_cc_finalize ()
5574 if (optimization_summaries)
5575 ggc_delete (optimization_summaries);
5576 optimization_summaries = NULL;
5577 if (summaries_lto)
5578 ggc_delete (summaries_lto);
5579 summaries_lto = NULL;
5580 if (fnspec_summaries)
5581 delete fnspec_summaries;
5582 fnspec_summaries = NULL;
5583 if (escape_summaries)
5584 delete escape_summaries;
5585 escape_summaries = NULL;
5588 #include "gt-ipa-modref.h"