libcpp, c, middle-end: Optimize initializers using #embed in C
[official-gcc.git] / gcc / ipa-modref.cc
blob19359662f8ffcce7ce9aedc066d565a6a79d1bf8
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)
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)
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_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_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)
1608 && !(flags & ECF_LOOPING_CONST_OR_PURE))
1610 if (dump_file)
1611 fprintf (dump_file,
1612 " - ECF_CONST, 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 if (flags & ECF_NOVOPS)
1629 set_side_effects ();
1630 set_nondeterministic ();
1632 else
1633 process_fnspec (stmt);
1634 return;
1636 /* We only need to handle internal calls in IPA mode. */
1637 gcc_checking_assert (!m_summary_lto && !m_ipa);
1639 struct cgraph_node *callee_node = cgraph_node::get_create (callee);
1641 /* If this is a recursive call, the target summary is the same as ours, so
1642 there's nothing to do. */
1643 if (recursive_call_p (current_function_decl, callee))
1645 m_recursive_calls.safe_push (stmt);
1646 set_side_effects ();
1647 if (dump_file)
1648 fprintf (dump_file, " - Skipping recursive call.\n");
1649 return;
1652 gcc_assert (callee_node != NULL);
1654 /* Get the function symbol and its availability. */
1655 enum availability avail;
1656 callee_node = callee_node->function_symbol (&avail);
1657 bool looping;
1658 if (builtin_safe_for_const_function_p (&looping, callee))
1660 if (looping)
1661 set_side_effects ();
1662 if (dump_file)
1663 fprintf (dump_file, " - Builtin is safe for const.\n");
1664 return;
1666 if (avail <= AVAIL_INTERPOSABLE)
1668 if (dump_file)
1669 fprintf (dump_file,
1670 " - Function availability <= AVAIL_INTERPOSABLE.\n");
1671 process_fnspec (stmt);
1672 return;
1675 /* Get callee's modref summary. As above, if there's no summary, we either
1676 have to give up or, if stores are ignored, we can just purge loads. */
1677 modref_summary *callee_summary = optimization_summaries->get (callee_node);
1678 if (!callee_summary)
1680 if (dump_file)
1681 fprintf (dump_file, " - No modref summary available for callee.\n");
1682 process_fnspec (stmt);
1683 return;
1686 merge_call_side_effects (stmt, callee_summary, callee_node, false);
1688 return;
1691 /* Helper for analyze_stmt. */
1693 bool
1694 modref_access_analysis::analyze_load (gimple *, tree, tree op, void *data)
1696 modref_access_analysis *t = (modref_access_analysis *)data;
1698 if (dump_file)
1700 fprintf (dump_file, " - Analyzing load: ");
1701 print_generic_expr (dump_file, op);
1702 fprintf (dump_file, "\n");
1705 if (!t->record_access_p (op))
1706 return false;
1708 ao_ref r;
1709 ao_ref_init (&r, op);
1710 modref_access_node a = get_access (&r);
1711 if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1712 return false;
1714 if (t->m_summary)
1715 t->record_access (t->m_summary->loads, &r, a);
1716 if (t->m_summary_lto)
1717 t->record_access_lto (t->m_summary_lto->loads, &r, a);
1718 return false;
1721 /* Helper for analyze_stmt. */
1723 bool
1724 modref_access_analysis::analyze_store (gimple *stmt, tree, tree op, void *data)
1726 modref_access_analysis *t = (modref_access_analysis *)data;
1728 if (dump_file)
1730 fprintf (dump_file, " - Analyzing store: ");
1731 print_generic_expr (dump_file, op);
1732 fprintf (dump_file, "\n");
1735 if (!t->record_access_p (op))
1736 return false;
1738 ao_ref r;
1739 ao_ref_init (&r, op);
1740 modref_access_node a = get_access (&r);
1741 if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1742 return false;
1744 if (t->m_summary)
1745 t->record_access (t->m_summary->stores, &r, a);
1746 if (t->m_summary_lto)
1747 t->record_access_lto (t->m_summary_lto->stores, &r, a);
1748 if (t->m_always_executed
1749 && a.useful_for_kill_p ()
1750 && (!cfun->can_throw_non_call_exceptions
1751 || !stmt_could_throw_p (cfun, stmt)))
1753 if (dump_file)
1754 fprintf (dump_file, " - Recording kill\n");
1755 if (t->m_summary)
1756 modref_access_node::insert_kill (t->m_summary->kills, a, false);
1757 if (t->m_summary_lto)
1758 modref_access_node::insert_kill (t->m_summary_lto->kills, a, false);
1760 return false;
1763 /* Analyze statement STMT of function F.
1764 If IPA is true do not merge in side effects of calls. */
1766 void
1767 modref_access_analysis::analyze_stmt (gimple *stmt, bool always_executed)
1769 m_always_executed = always_executed;
1770 /* In general we can not ignore clobbers because they are barriers for code
1771 motion, however after inlining it is safe to do because local optimization
1772 passes do not consider clobbers from other functions.
1773 Similar logic is in ipa-pure-const.cc. */
1774 if ((m_ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1776 if (always_executed && record_access_p (gimple_assign_lhs (stmt)))
1778 ao_ref r;
1779 ao_ref_init (&r, gimple_assign_lhs (stmt));
1780 modref_access_node a = get_access (&r);
1781 if (a.useful_for_kill_p ())
1783 if (dump_file)
1784 fprintf (dump_file, " - Recording kill\n");
1785 if (m_summary)
1786 modref_access_node::insert_kill (m_summary->kills, a, false);
1787 if (m_summary_lto)
1788 modref_access_node::insert_kill (m_summary_lto->kills,
1789 a, false);
1792 return;
1795 /* Analyze all loads and stores in STMT. */
1796 walk_stmt_load_store_ops (stmt, this,
1797 analyze_load, analyze_store);
1799 switch (gimple_code (stmt))
1801 case GIMPLE_ASM:
1802 if (gimple_asm_volatile_p (as_a <gasm *> (stmt)))
1803 set_nondeterministic ();
1804 if (cfun->can_throw_non_call_exceptions
1805 && stmt_could_throw_p (cfun, stmt))
1806 set_side_effects ();
1807 /* If the ASM statement does not read nor write memory, there's nothing
1808 to do. Otherwise just give up. */
1809 if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1810 return;
1811 if (dump_file)
1812 fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1813 "which clobbers memory.\n");
1814 record_unknown_load ();
1815 record_unknown_store ();
1816 return;
1817 case GIMPLE_CALL:
1818 if (!m_ipa || gimple_call_internal_p (stmt))
1819 analyze_call (as_a <gcall *> (stmt));
1820 else
1822 attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1824 if (fnspec.known_p ()
1825 && (!fnspec.global_memory_read_p ()
1826 || !fnspec.global_memory_written_p ()))
1828 cgraph_edge *e = cgraph_node::get
1829 (current_function_decl)->get_edge (stmt);
1830 if (e->callee)
1832 fnspec_summaries->get_create (e)->fnspec
1833 = xstrdup (fnspec.get_str ());
1834 if (dump_file)
1835 fprintf (dump_file, " Recorded fnspec %s\n",
1836 fnspec.get_str ());
1840 return;
1841 default:
1842 if (cfun->can_throw_non_call_exceptions
1843 && stmt_could_throw_p (cfun, stmt))
1844 set_side_effects ();
1845 return;
1849 /* Propagate load/stores across recursive calls. */
1851 void
1852 modref_access_analysis::propagate ()
1854 if (m_ipa && m_summary)
1855 return;
1857 bool changed = true;
1858 bool first = true;
1859 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1861 m_always_executed = false;
1862 while (changed && m_summary->useful_p (m_ecf_flags, false))
1864 changed = false;
1865 for (unsigned i = 0; i < m_recursive_calls.length (); i++)
1867 changed |= merge_call_side_effects (m_recursive_calls[i], m_summary,
1868 fnode, !first);
1870 first = false;
1874 /* Analyze function. */
1876 void
1877 modref_access_analysis::analyze ()
1879 m_ecf_flags = flags_from_decl_or_type (current_function_decl);
1880 bool summary_useful = true;
1882 /* Analyze each statement in each basic block of the function. If the
1883 statement cannot be analyzed (for any reason), the entire function cannot
1884 be analyzed by modref. */
1885 basic_block bb;
1886 bitmap always_executed_bbs = find_always_executed_bbs (cfun, true);
1887 FOR_EACH_BB_FN (bb, cfun)
1889 gimple_stmt_iterator si;
1890 bool always_executed = bitmap_bit_p (always_executed_bbs, bb->index);
1892 for (si = gsi_start_nondebug_after_labels_bb (bb);
1893 !gsi_end_p (si); gsi_next_nondebug (&si))
1895 /* NULL memory accesses terminates BB. These accesses are known
1896 to trip undefined behavior. gimple-ssa-isolate-paths turns them
1897 to volatile accesses and adds builtin_trap call which would
1898 confuse us otherwise. */
1899 if (infer_nonnull_range_by_dereference (gsi_stmt (si),
1900 null_pointer_node))
1902 if (dump_file)
1903 fprintf (dump_file, " - NULL memory access; terminating BB\n");
1904 if (flag_non_call_exceptions)
1905 set_side_effects ();
1906 break;
1908 analyze_stmt (gsi_stmt (si), always_executed);
1910 /* Avoid doing useless work. */
1911 if ((!m_summary || !m_summary->useful_p (m_ecf_flags, false))
1912 && (!m_summary_lto
1913 || !m_summary_lto->useful_p (m_ecf_flags, false)))
1915 summary_useful = false;
1916 break;
1918 if (always_executed
1919 && stmt_can_throw_external (cfun, gsi_stmt (si)))
1920 always_executed = false;
1922 if (!summary_useful)
1923 break;
1925 /* In non-IPA mode we need to perform iterative dataflow on recursive calls.
1926 This needs to be done after all other side effects are computed. */
1927 if (summary_useful)
1929 if (!m_ipa)
1930 propagate ();
1931 if (m_summary && !m_summary->side_effects && !finite_function_p ())
1932 m_summary->side_effects = true;
1933 if (m_summary_lto && !m_summary_lto->side_effects
1934 && !finite_function_p ())
1935 m_summary_lto->side_effects = true;
1937 BITMAP_FREE (always_executed_bbs);
1940 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1942 bool
1943 memory_access_to (tree op, tree ssa_name)
1945 tree base = get_base_address (op);
1946 if (!base)
1947 return false;
1948 if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1949 return false;
1950 return TREE_OPERAND (base, 0) == ssa_name;
1953 /* Consider statement val = *arg.
1954 return EAF flags of ARG that can be determined from EAF flags of VAL
1955 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1956 all stores to VAL, i.e. when handling noreturn function. */
1958 static int
1959 deref_flags (int flags, bool ignore_stores)
1961 /* Dereference is also a direct read but dereferenced value does not
1962 yield any other direct use. */
1963 int ret = EAF_NO_DIRECT_CLOBBER | EAF_NO_DIRECT_ESCAPE
1964 | EAF_NOT_RETURNED_DIRECTLY;
1965 /* If argument is unused just account for
1966 the read involved in dereference. */
1967 if (flags & EAF_UNUSED)
1968 ret |= EAF_NO_INDIRECT_READ | EAF_NO_INDIRECT_CLOBBER
1969 | EAF_NO_INDIRECT_ESCAPE;
1970 else
1972 /* Direct or indirect accesses leads to indirect accesses. */
1973 if (((flags & EAF_NO_DIRECT_CLOBBER)
1974 && (flags & EAF_NO_INDIRECT_CLOBBER))
1975 || ignore_stores)
1976 ret |= EAF_NO_INDIRECT_CLOBBER;
1977 if (((flags & EAF_NO_DIRECT_ESCAPE)
1978 && (flags & EAF_NO_INDIRECT_ESCAPE))
1979 || ignore_stores)
1980 ret |= EAF_NO_INDIRECT_ESCAPE;
1981 if ((flags & EAF_NO_DIRECT_READ)
1982 && (flags & EAF_NO_INDIRECT_READ))
1983 ret |= EAF_NO_INDIRECT_READ;
1984 if ((flags & EAF_NOT_RETURNED_DIRECTLY)
1985 && (flags & EAF_NOT_RETURNED_INDIRECTLY))
1986 ret |= EAF_NOT_RETURNED_INDIRECTLY;
1988 return ret;
1992 /* Description of an escape point: a call which affects flags of a given
1993 SSA name. */
1995 struct escape_point
1997 /* Value escapes to this call. */
1998 gcall *call;
1999 /* Argument it escapes to. */
2000 unsigned int arg;
2001 /* Flags already known about the argument (this can save us from recording
2002 escape points if local analysis did good job already). */
2003 eaf_flags_t min_flags;
2004 /* Does value escape directly or indirectly? */
2005 bool direct;
2008 /* Lattice used during the eaf flags analysis dataflow. For a given SSA name
2009 we aim to compute its flags and escape points. We also use the lattice
2010 to dynamically build dataflow graph to propagate on. */
2012 class modref_lattice
2014 public:
2015 /* EAF flags of the SSA name. */
2016 eaf_flags_t flags;
2017 /* Used during DFS walk to mark names where final value was determined
2018 without need for dataflow. */
2019 bool known;
2020 /* Used during DFS walk to mark open vertices (for cycle detection). */
2021 bool open;
2022 /* Set during DFS walk for names that needs dataflow propagation. */
2023 bool do_dataflow;
2024 /* Used during the iterative dataflow. */
2025 bool changed;
2027 /* When doing IPA analysis we can not merge in callee escape points;
2028 Only remember them and do the merging at IPA propagation time. */
2029 vec <escape_point, va_heap, vl_ptr> escape_points;
2031 /* Representation of a graph for dataflow. This graph is built on-demand
2032 using modref_eaf_analysis::analyze_ssa and later solved by
2033 modref_eaf_analysis::propagate.
2034 Each edge represents the fact that flags of current lattice should be
2035 propagated to lattice of SSA_NAME. */
2036 struct propagate_edge
2038 int ssa_name;
2039 bool deref;
2041 vec <propagate_edge, va_heap, vl_ptr> propagate_to;
2043 void init ();
2044 void release ();
2045 bool merge (const modref_lattice &with);
2046 bool merge (int flags);
2047 bool merge_deref (const modref_lattice &with, bool ignore_stores);
2048 bool merge_direct_load ();
2049 bool merge_direct_store ();
2050 bool add_escape_point (gcall *call, unsigned int arg,
2051 eaf_flags_t min_flags, bool direct);
2052 void dump (FILE *out, int indent = 0) const;
2055 /* Lattices are saved to vectors, so keep them PODs. */
2056 void
2057 modref_lattice::init ()
2059 /* All flags we track. */
2060 int f = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
2061 | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE
2062 | EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ
2063 | EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY
2064 | EAF_UNUSED;
2065 flags = f;
2066 /* Check that eaf_flags_t is wide enough to hold all flags. */
2067 gcc_checking_assert (f == flags);
2068 open = true;
2069 known = false;
2072 /* Release memory. */
2073 void
2074 modref_lattice::release ()
2076 escape_points.release ();
2077 propagate_to.release ();
2080 /* Dump lattice to OUT; indent with INDENT spaces. */
2082 void
2083 modref_lattice::dump (FILE *out, int indent) const
2085 dump_eaf_flags (out, flags);
2086 if (escape_points.length ())
2088 fprintf (out, "%*sEscapes:\n", indent, "");
2089 for (unsigned int i = 0; i < escape_points.length (); i++)
2091 fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
2092 escape_points[i].arg,
2093 escape_points[i].direct ? "direct" : "indirect");
2094 dump_eaf_flags (out, escape_points[i].min_flags, false);
2095 fprintf (out, " in call ");
2096 print_gimple_stmt (out, escape_points[i].call, 0);
2101 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
2102 point exists. */
2104 bool
2105 modref_lattice::add_escape_point (gcall *call, unsigned arg,
2106 eaf_flags_t min_flags, bool direct)
2108 escape_point *ep;
2109 unsigned int i;
2111 /* If we already determined flags to be bad enough,
2112 we do not need to record. */
2113 if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
2114 return false;
2116 FOR_EACH_VEC_ELT (escape_points, i, ep)
2117 if (ep->call == call && ep->arg == arg && ep->direct == direct)
2119 if ((ep->min_flags & min_flags) == min_flags)
2120 return false;
2121 ep->min_flags &= min_flags;
2122 return true;
2124 /* Give up if max escape points is met. */
2125 if ((int)escape_points.length () > param_modref_max_escape_points)
2127 if (dump_file)
2128 fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
2129 merge (0);
2130 return true;
2132 escape_point new_ep = {call, arg, min_flags, direct};
2133 escape_points.safe_push (new_ep);
2134 return true;
2137 /* Merge in flags from F. */
2138 bool
2139 modref_lattice::merge (int f)
2141 if (f & EAF_UNUSED)
2142 return false;
2143 /* Check that flags seems sane: if function does not read the parameter
2144 it can not access it indirectly. */
2145 gcc_checking_assert (!(f & EAF_NO_DIRECT_READ)
2146 || ((f & EAF_NO_INDIRECT_READ)
2147 && (f & EAF_NO_INDIRECT_CLOBBER)
2148 && (f & EAF_NO_INDIRECT_ESCAPE)
2149 && (f & EAF_NOT_RETURNED_INDIRECTLY)));
2150 if ((flags & f) != flags)
2152 flags &= f;
2153 /* Prune obviously useless flags;
2154 We do not have ECF_FLAGS handy which is not big problem since
2155 we will do final flags cleanup before producing summary.
2156 Merging should be fast so it can work well with dataflow. */
2157 flags = remove_useless_eaf_flags (flags, 0, false);
2158 if (!flags)
2159 escape_points.release ();
2160 return true;
2162 return false;
2165 /* Merge in WITH. Return true if anything changed. */
2167 bool
2168 modref_lattice::merge (const modref_lattice &with)
2170 if (!with.known)
2171 do_dataflow = true;
2173 bool changed = merge (with.flags);
2175 if (!flags)
2176 return changed;
2177 for (unsigned int i = 0; i < with.escape_points.length (); i++)
2178 changed |= add_escape_point (with.escape_points[i].call,
2179 with.escape_points[i].arg,
2180 with.escape_points[i].min_flags,
2181 with.escape_points[i].direct);
2182 return changed;
2185 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
2186 stores. Return true if anything changed. */
2188 bool
2189 modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
2191 if (!with.known)
2192 do_dataflow = true;
2194 bool changed = merge (deref_flags (with.flags, ignore_stores));
2196 if (!flags)
2197 return changed;
2198 for (unsigned int i = 0; i < with.escape_points.length (); i++)
2200 int min_flags = with.escape_points[i].min_flags;
2202 if (with.escape_points[i].direct)
2203 min_flags = deref_flags (min_flags, ignore_stores);
2204 else if (ignore_stores)
2205 min_flags |= ignore_stores_eaf_flags;
2206 changed |= add_escape_point (with.escape_points[i].call,
2207 with.escape_points[i].arg,
2208 min_flags,
2209 false);
2211 return changed;
2214 /* Merge in flags for direct load. */
2216 bool
2217 modref_lattice::merge_direct_load ()
2219 return merge (~(EAF_UNUSED | EAF_NO_DIRECT_READ));
2222 /* Merge in flags for direct store. */
2224 bool
2225 modref_lattice::merge_direct_store ()
2227 return merge (~(EAF_UNUSED | EAF_NO_DIRECT_CLOBBER));
2230 /* Analyzer of EAF flags.
2231 This is generally dataflow problem over the SSA graph, however we only
2232 care about flags of few selected ssa names (arguments, return slot and
2233 static chain). So we first call analyze_ssa_name on all relevant names
2234 and perform a DFS walk to discover SSA names where flags needs to be
2235 determined. For acyclic graphs we try to determine final flags during
2236 this walk. Once cycles or recursion depth is met we enlist SSA names
2237 for dataflow which is done by propagate call.
2239 After propagation the flags can be obtained using get_ssa_name_flags. */
2241 class modref_eaf_analysis
2243 public:
2244 /* Mark NAME as relevant for analysis. */
2245 void analyze_ssa_name (tree name, bool deferred = false);
2246 /* Dataflow solver. */
2247 void propagate ();
2248 /* Return flags computed earlier for NAME. */
2249 int get_ssa_name_flags (tree name)
2251 int version = SSA_NAME_VERSION (name);
2252 gcc_checking_assert (m_lattice[version].known);
2253 return m_lattice[version].flags;
2255 /* In IPA mode this will record all escape points
2256 determined for NAME to PARM_IDNEX. Flags are minimal
2257 flags known. */
2258 void record_escape_points (tree name, int parm_index, int flags);
2259 modref_eaf_analysis (bool ipa)
2261 m_ipa = ipa;
2262 m_depth = 0;
2263 m_lattice.safe_grow_cleared (num_ssa_names, true);
2265 ~modref_eaf_analysis ()
2267 gcc_checking_assert (!m_depth);
2268 if (m_ipa || m_names_to_propagate.length ())
2269 for (unsigned int i = 0; i < num_ssa_names; i++)
2270 m_lattice[i].release ();
2272 private:
2273 /* If true, we produce analysis for IPA mode. In this case escape points are
2274 collected. */
2275 bool m_ipa;
2276 /* Depth of recursion of analyze_ssa_name. */
2277 int m_depth;
2278 /* Propagation lattice for individual ssa names. */
2279 auto_vec<modref_lattice> m_lattice;
2280 auto_vec<tree> m_deferred_names;
2281 auto_vec<int> m_names_to_propagate;
2283 void merge_with_ssa_name (tree dest, tree src, bool deref);
2284 void merge_call_lhs_flags (gcall *call, int arg, tree name, bool direct,
2285 bool deref);
2289 /* Call statements may return their parameters. Consider argument number
2290 ARG of USE_STMT and determine flags that can needs to be cleared
2291 in case pointer possibly indirectly references from ARG I is returned.
2292 If DIRECT is true consider direct returns and if INDIRECT consider
2293 indirect returns.
2294 LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
2295 ARG is set to -1 for static chain. */
2297 void
2298 modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg,
2299 tree name, bool direct,
2300 bool indirect)
2302 int index = SSA_NAME_VERSION (name);
2303 bool returned_directly = false;
2305 /* If there is no return value, no flags are affected. */
2306 if (!gimple_call_lhs (call))
2307 return;
2309 /* If we know that function returns given argument and it is not ARG
2310 we can still be happy. */
2311 if (arg >= 0)
2313 int flags = gimple_call_return_flags (call);
2314 if (flags & ERF_RETURNS_ARG)
2316 if ((flags & ERF_RETURN_ARG_MASK) == arg)
2317 returned_directly = true;
2318 else
2319 return;
2322 /* Make ERF_RETURNS_ARG overwrite EAF_UNUSED. */
2323 if (returned_directly)
2325 direct = true;
2326 indirect = false;
2328 /* If value is not returned at all, do nothing. */
2329 else if (!direct && !indirect)
2330 return;
2332 /* If return value is SSA name determine its flags. */
2333 if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
2335 tree lhs = gimple_call_lhs (call);
2336 if (direct)
2337 merge_with_ssa_name (name, lhs, false);
2338 if (indirect)
2339 merge_with_ssa_name (name, lhs, true);
2341 /* In the case of memory store we can do nothing. */
2342 else if (!direct)
2343 m_lattice[index].merge (deref_flags (0, false));
2344 else
2345 m_lattice[index].merge (0);
2348 /* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
2349 into flags for caller, update LATTICE of corresponding
2350 argument if needed. */
2352 static int
2353 callee_to_caller_flags (int call_flags, bool ignore_stores,
2354 modref_lattice &lattice)
2356 /* call_flags is about callee returning a value
2357 that is not the same as caller returning it. */
2358 call_flags |= EAF_NOT_RETURNED_DIRECTLY
2359 | EAF_NOT_RETURNED_INDIRECTLY;
2360 if (!ignore_stores && !(call_flags & EAF_UNUSED))
2362 /* If value escapes we are no longer able to track what happens
2363 with it because we can read it from the escaped location
2364 anytime. */
2365 if (!(call_flags & EAF_NO_DIRECT_ESCAPE))
2366 lattice.merge (0);
2367 else if (!(call_flags & EAF_NO_INDIRECT_ESCAPE))
2368 lattice.merge (~(EAF_NOT_RETURNED_INDIRECTLY
2369 | EAF_NO_DIRECT_READ
2370 | EAF_NO_INDIRECT_READ
2371 | EAF_NO_INDIRECT_CLOBBER
2372 | EAF_UNUSED));
2374 else
2375 call_flags |= ignore_stores_eaf_flags;
2376 return call_flags;
2379 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
2380 LATTICE is an array of modref_lattices.
2381 DEPTH is a recursion depth used to make debug output prettier.
2382 If IPA is true we analyze for IPA propagation (and thus call escape points
2383 are processed later) */
2385 void
2386 modref_eaf_analysis::analyze_ssa_name (tree name, bool deferred)
2388 imm_use_iterator ui;
2389 gimple *use_stmt;
2390 int index = SSA_NAME_VERSION (name);
2392 if (!deferred)
2394 /* See if value is already computed. */
2395 if (m_lattice[index].known || m_lattice[index].do_dataflow)
2396 return;
2397 if (m_lattice[index].open)
2399 if (dump_file)
2400 fprintf (dump_file,
2401 "%*sCycle in SSA graph\n",
2402 m_depth * 4, "");
2403 return;
2405 /* Recursion guard. */
2406 m_lattice[index].init ();
2407 if (m_depth == param_modref_max_depth)
2409 if (dump_file)
2410 fprintf (dump_file,
2411 "%*sMax recursion depth reached; postponing\n",
2412 m_depth * 4, "");
2413 m_deferred_names.safe_push (name);
2414 return;
2418 if (dump_file)
2420 fprintf (dump_file,
2421 "%*sAnalyzing flags of ssa name: ", m_depth * 4, "");
2422 print_generic_expr (dump_file, name);
2423 fprintf (dump_file, "\n");
2426 FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
2428 if (m_lattice[index].flags == 0)
2429 break;
2430 if (is_gimple_debug (use_stmt))
2431 continue;
2432 if (dump_file)
2434 fprintf (dump_file, "%*s Analyzing stmt: ", m_depth * 4, "");
2435 print_gimple_stmt (dump_file, use_stmt, 0);
2437 /* If we see a direct non-debug use, clear unused bit.
2438 All dereferences should be accounted below using deref_flags. */
2439 m_lattice[index].merge (~EAF_UNUSED);
2441 /* Gimple return may load the return value.
2442 Returning name counts as an use by tree-ssa-structalias.cc */
2443 if (greturn *ret = dyn_cast <greturn *> (use_stmt))
2445 /* Returning through return slot is seen as memory write earlier. */
2446 if (DECL_RESULT (current_function_decl)
2447 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2449 else if (gimple_return_retval (ret) == name)
2450 m_lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED_DIRECTLY
2451 | EAF_NOT_RETURNED_DIRECTLY));
2452 else if (memory_access_to (gimple_return_retval (ret), name))
2454 m_lattice[index].merge_direct_load ();
2455 m_lattice[index].merge (~(EAF_UNUSED
2456 | EAF_NOT_RETURNED_INDIRECTLY));
2459 /* Account for LHS store, arg loads and flags from callee function. */
2460 else if (gcall *call = dyn_cast <gcall *> (use_stmt))
2462 tree callee = gimple_call_fndecl (call);
2464 /* IPA PTA internally it treats calling a function as "writing" to
2465 the argument space of all functions the function pointer points to
2466 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
2467 is on since that would allow propagation of this from -fno-ipa-pta
2468 to -fipa-pta functions. */
2469 if (gimple_call_fn (use_stmt) == name)
2470 m_lattice[index].merge (~(EAF_NO_DIRECT_CLOBBER | EAF_UNUSED));
2472 /* Recursion would require bit of propagation; give up for now. */
2473 if (callee && !m_ipa && recursive_call_p (current_function_decl,
2474 callee))
2475 m_lattice[index].merge (0);
2476 else
2478 int ecf_flags = gimple_call_flags (call);
2479 bool ignore_stores = ignore_stores_p (current_function_decl,
2480 ecf_flags);
2481 bool ignore_retval = ignore_retval_p (current_function_decl,
2482 ecf_flags);
2484 /* Handle *name = func (...). */
2485 if (gimple_call_lhs (call)
2486 && memory_access_to (gimple_call_lhs (call), name))
2488 m_lattice[index].merge_direct_store ();
2489 /* Return slot optimization passes address of
2490 LHS to callee via hidden parameter and this
2491 may make LHS to escape. See PR 98499. */
2492 if (gimple_call_return_slot_opt_p (call)
2493 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
2495 int call_flags = gimple_call_retslot_flags (call);
2496 bool isretslot = false;
2498 if (DECL_RESULT (current_function_decl)
2499 && DECL_BY_REFERENCE
2500 (DECL_RESULT (current_function_decl)))
2501 isretslot = ssa_default_def
2502 (cfun,
2503 DECL_RESULT (current_function_decl))
2504 == name;
2506 /* Passing returnslot to return slot is special because
2507 not_returned and escape has same meaning.
2508 However passing arg to return slot is different. If
2509 the callee's return slot is returned it means that
2510 arg is written to itself which is an escape.
2511 Since we do not track the memory it is written to we
2512 need to give up on analyzing it. */
2513 if (!isretslot)
2515 if (!(call_flags & (EAF_NOT_RETURNED_DIRECTLY
2516 | EAF_UNUSED)))
2517 m_lattice[index].merge (0);
2518 else gcc_checking_assert
2519 (call_flags & (EAF_NOT_RETURNED_INDIRECTLY
2520 | EAF_UNUSED));
2521 call_flags = callee_to_caller_flags
2522 (call_flags, false,
2523 m_lattice[index]);
2525 m_lattice[index].merge (call_flags);
2529 if (gimple_call_chain (call)
2530 && (gimple_call_chain (call) == name))
2532 int call_flags = gimple_call_static_chain_flags (call);
2533 if (!ignore_retval && !(call_flags & EAF_UNUSED))
2534 merge_call_lhs_flags
2535 (call, -1, name,
2536 !(call_flags & EAF_NOT_RETURNED_DIRECTLY),
2537 !(call_flags & EAF_NOT_RETURNED_INDIRECTLY));
2538 call_flags = callee_to_caller_flags
2539 (call_flags, ignore_stores,
2540 m_lattice[index]);
2541 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2542 m_lattice[index].merge (call_flags);
2545 /* Process internal functions and right away. */
2546 bool record_ipa = m_ipa && !gimple_call_internal_p (call);
2548 /* Handle all function parameters. */
2549 for (unsigned i = 0;
2550 i < gimple_call_num_args (call)
2551 && m_lattice[index].flags; i++)
2552 /* Name is directly passed to the callee. */
2553 if (gimple_call_arg (call, i) == name)
2555 int call_flags = gimple_call_arg_flags (call, i);
2556 if (!ignore_retval)
2557 merge_call_lhs_flags
2558 (call, i, name,
2559 !(call_flags & (EAF_NOT_RETURNED_DIRECTLY
2560 | EAF_UNUSED)),
2561 !(call_flags & (EAF_NOT_RETURNED_INDIRECTLY
2562 | EAF_UNUSED)));
2563 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2565 call_flags = callee_to_caller_flags
2566 (call_flags, ignore_stores,
2567 m_lattice[index]);
2568 if (!record_ipa)
2569 m_lattice[index].merge (call_flags);
2570 else
2571 m_lattice[index].add_escape_point (call, i,
2572 call_flags, true);
2575 /* Name is dereferenced and passed to a callee. */
2576 else if (memory_access_to (gimple_call_arg (call, i), name))
2578 int call_flags = deref_flags
2579 (gimple_call_arg_flags (call, i), ignore_stores);
2580 if (!ignore_retval && !(call_flags & EAF_UNUSED)
2581 && (call_flags & (EAF_NOT_RETURNED_DIRECTLY
2582 | EAF_NOT_RETURNED_INDIRECTLY))
2583 != (EAF_NOT_RETURNED_DIRECTLY
2584 | EAF_NOT_RETURNED_INDIRECTLY))
2585 merge_call_lhs_flags (call, i, name, false, true);
2586 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
2587 m_lattice[index].merge_direct_load ();
2588 else
2590 call_flags = callee_to_caller_flags
2591 (call_flags, ignore_stores,
2592 m_lattice[index]);
2593 if (!record_ipa)
2594 m_lattice[index].merge (call_flags);
2595 else
2596 m_lattice[index].add_escape_point (call, i,
2597 call_flags, false);
2602 else if (gimple_assign_load_p (use_stmt))
2604 gassign *assign = as_a <gassign *> (use_stmt);
2605 /* Memory to memory copy. */
2606 if (gimple_store_p (assign))
2608 /* Handle *lhs = *name.
2610 We do not track memory locations, so assume that value
2611 is used arbitrarily. */
2612 if (memory_access_to (gimple_assign_rhs1 (assign), name))
2613 m_lattice[index].merge (deref_flags (0, false));
2615 /* Handle *name = *exp. */
2616 if (memory_access_to (gimple_assign_lhs (assign), name))
2617 m_lattice[index].merge_direct_store ();
2619 /* Handle lhs = *name. */
2620 else if (memory_access_to (gimple_assign_rhs1 (assign), name))
2622 tree lhs = gimple_assign_lhs (assign);
2623 merge_with_ssa_name (name, lhs, true);
2626 else if (gimple_store_p (use_stmt))
2628 gassign *assign = dyn_cast <gassign *> (use_stmt);
2630 /* Handle *lhs = name. */
2631 if (assign && gimple_assign_rhs1 (assign) == name)
2633 if (dump_file)
2634 fprintf (dump_file, "%*s ssa name saved to memory\n",
2635 m_depth * 4, "");
2636 m_lattice[index].merge (0);
2638 /* Handle *name = exp. */
2639 else if (assign
2640 && memory_access_to (gimple_assign_lhs (assign), name))
2642 /* In general we can not ignore clobbers because they are
2643 barriers for code motion, however after inlining it is safe to
2644 do because local optimization passes do not consider clobbers
2645 from other functions.
2646 Similar logic is in ipa-pure-const.cc. */
2647 if (!cfun->after_inlining || !gimple_clobber_p (assign))
2648 m_lattice[index].merge_direct_store ();
2650 /* ASM statements etc. */
2651 else if (!assign)
2653 if (dump_file)
2654 fprintf (dump_file, "%*s Unhandled store\n", m_depth * 4, "");
2655 m_lattice[index].merge (0);
2658 else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
2660 enum tree_code code = gimple_assign_rhs_code (assign);
2662 /* See if operation is a merge as considered by
2663 tree-ssa-structalias.cc:find_func_aliases. */
2664 if (!truth_value_p (code)
2665 && code != POINTER_DIFF_EXPR
2666 && (code != POINTER_PLUS_EXPR
2667 || gimple_assign_rhs1 (assign) == name))
2669 tree lhs = gimple_assign_lhs (assign);
2670 merge_with_ssa_name (name, lhs, false);
2673 else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
2675 tree result = gimple_phi_result (phi);
2676 merge_with_ssa_name (name, result, false);
2678 /* Conditions are not considered escape points
2679 by tree-ssa-structalias. */
2680 else if (gimple_code (use_stmt) == GIMPLE_COND)
2682 else
2684 if (dump_file)
2685 fprintf (dump_file, "%*s Unhandled stmt\n", m_depth * 4, "");
2686 m_lattice[index].merge (0);
2689 if (dump_file)
2691 fprintf (dump_file, "%*s current flags of ", m_depth * 4, "");
2692 print_generic_expr (dump_file, name);
2693 m_lattice[index].dump (dump_file, m_depth * 4 + 4);
2696 if (dump_file)
2698 fprintf (dump_file, "%*sflags of ssa name ", m_depth * 4, "");
2699 print_generic_expr (dump_file, name);
2700 m_lattice[index].dump (dump_file, m_depth * 4 + 2);
2702 m_lattice[index].open = false;
2703 if (!m_lattice[index].do_dataflow)
2704 m_lattice[index].known = true;
2707 /* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
2708 is dereferenced. */
2710 void
2711 modref_eaf_analysis::merge_with_ssa_name (tree dest, tree src, bool deref)
2713 int index = SSA_NAME_VERSION (dest);
2714 int src_index = SSA_NAME_VERSION (src);
2716 /* Merging lattice with itself is a no-op. */
2717 if (!deref && src == dest)
2718 return;
2720 m_depth++;
2721 analyze_ssa_name (src);
2722 m_depth--;
2723 if (deref)
2724 m_lattice[index].merge_deref (m_lattice[src_index], false);
2725 else
2726 m_lattice[index].merge (m_lattice[src_index]);
2728 /* If we failed to produce final solution add an edge to the dataflow
2729 graph. */
2730 if (!m_lattice[src_index].known)
2732 modref_lattice::propagate_edge e = {index, deref};
2734 if (!m_lattice[src_index].propagate_to.length ())
2735 m_names_to_propagate.safe_push (src_index);
2736 m_lattice[src_index].propagate_to.safe_push (e);
2737 m_lattice[src_index].changed = true;
2738 m_lattice[src_index].do_dataflow = true;
2739 if (dump_file)
2740 fprintf (dump_file,
2741 "%*sWill propgate from ssa_name %i to %i%s\n",
2742 m_depth * 4 + 4,
2743 "", src_index, index, deref ? " (deref)" : "");
2747 /* In the case we deferred some SSA names, reprocess them. In the case some
2748 dataflow edges were introduced, do the actual iterative dataflow. */
2750 void
2751 modref_eaf_analysis::propagate ()
2753 int iterations = 0;
2754 size_t i;
2755 int index;
2756 bool changed = true;
2758 while (m_deferred_names.length ())
2760 tree name = m_deferred_names.pop ();
2761 if (dump_file)
2762 fprintf (dump_file, "Analyzing deferred SSA name\n");
2763 analyze_ssa_name (name, true);
2766 if (!m_names_to_propagate.length ())
2767 return;
2768 if (dump_file)
2769 fprintf (dump_file, "Propagating EAF flags\n");
2771 /* Compute reverse postorder. */
2772 auto_vec <int> rpo;
2773 struct stack_entry
2775 int name;
2776 unsigned pos;
2778 auto_vec <struct stack_entry> stack;
2779 int pos = m_names_to_propagate.length () - 1;
2781 rpo.safe_grow (m_names_to_propagate.length (), true);
2782 stack.reserve_exact (m_names_to_propagate.length ());
2784 /* We reuse known flag for RPO DFS walk bookkeeping. */
2785 if (flag_checking)
2786 FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2787 gcc_assert (!m_lattice[index].known && m_lattice[index].changed);
2789 FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2791 if (!m_lattice[index].known)
2793 stack_entry e = {index, 0};
2795 stack.quick_push (e);
2796 m_lattice[index].known = true;
2798 while (stack.length ())
2800 bool found = false;
2801 int index1 = stack.last ().name;
2803 while (stack.last ().pos < m_lattice[index1].propagate_to.length ())
2805 int index2 = m_lattice[index1]
2806 .propagate_to[stack.last ().pos].ssa_name;
2808 stack.last ().pos++;
2809 if (!m_lattice[index2].known
2810 && m_lattice[index2].propagate_to.length ())
2812 stack_entry e = {index2, 0};
2814 stack.quick_push (e);
2815 m_lattice[index2].known = true;
2816 found = true;
2817 break;
2820 if (!found
2821 && stack.last ().pos == m_lattice[index1].propagate_to.length ())
2823 rpo[pos--] = index1;
2824 stack.pop ();
2829 /* Perform iterative dataflow. */
2830 while (changed)
2832 changed = false;
2833 iterations++;
2834 if (dump_file)
2835 fprintf (dump_file, " iteration %i\n", iterations);
2836 FOR_EACH_VEC_ELT (rpo, i, index)
2838 if (m_lattice[index].changed)
2840 size_t j;
2842 m_lattice[index].changed = false;
2843 if (dump_file)
2844 fprintf (dump_file, " Visiting ssa name %i\n", index);
2845 for (j = 0; j < m_lattice[index].propagate_to.length (); j++)
2847 bool ch;
2848 int target = m_lattice[index].propagate_to[j].ssa_name;
2849 bool deref = m_lattice[index].propagate_to[j].deref;
2851 if (dump_file)
2852 fprintf (dump_file, " Propagating flags of ssa name"
2853 " %i to %i%s\n",
2854 index, target, deref ? " (deref)" : "");
2855 m_lattice[target].known = true;
2856 if (!m_lattice[index].propagate_to[j].deref)
2857 ch = m_lattice[target].merge (m_lattice[index]);
2858 else
2859 ch = m_lattice[target].merge_deref (m_lattice[index],
2860 false);
2861 if (!ch)
2862 continue;
2863 if (dump_file)
2865 fprintf (dump_file, " New lattice: ");
2866 m_lattice[target].dump (dump_file);
2868 changed = true;
2869 m_lattice[target].changed = true;
2874 if (dump_file)
2875 fprintf (dump_file, "EAF flags propagated in %i iterations\n", iterations);
2878 /* Record escape points of PARM_INDEX according to LATTICE. */
2880 void
2881 modref_eaf_analysis::record_escape_points (tree name, int parm_index, int flags)
2883 modref_lattice &lattice = m_lattice[SSA_NAME_VERSION (name)];
2885 if (lattice.escape_points.length ())
2887 escape_point *ep;
2888 unsigned int ip;
2889 cgraph_node *node = cgraph_node::get (current_function_decl);
2891 gcc_assert (m_ipa);
2892 FOR_EACH_VEC_ELT (lattice.escape_points, ip, ep)
2893 if ((ep->min_flags & flags) != flags)
2895 cgraph_edge *e = node->get_edge (ep->call);
2896 struct escape_entry ee = {parm_index, ep->arg,
2897 ep->min_flags, ep->direct};
2899 escape_summaries->get_create (e)->esc.safe_push (ee);
2904 /* Determine EAF flags for function parameters
2905 and fill in SUMMARY/SUMMARY_LTO. If IPA is true work in IPA mode
2906 where we also collect escape points.
2907 PAST_FLAGS, PAST_RETSLOT_FLAGS, PAST_STATIC_CHAIN_FLAGS can be
2908 used to preserve flags from previous (IPA) run for cases where
2909 late optimizations changed code in a way we can no longer analyze
2910 it easily. */
2912 static void
2913 analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
2914 bool ipa, vec<eaf_flags_t> &past_flags,
2915 int past_retslot_flags, int past_static_chain_flags)
2917 unsigned int parm_index = 0;
2918 unsigned int count = 0;
2919 int ecf_flags = flags_from_decl_or_type (current_function_decl);
2920 tree retslot = NULL;
2921 tree static_chain = NULL;
2923 /* If there is return slot, look up its SSA name. */
2924 if (DECL_RESULT (current_function_decl)
2925 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2926 retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
2927 if (cfun->static_chain_decl)
2928 static_chain = ssa_default_def (cfun, cfun->static_chain_decl);
2930 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2931 parm = TREE_CHAIN (parm))
2932 count++;
2934 if (!count && !retslot && !static_chain)
2935 return;
2937 modref_eaf_analysis eaf_analysis (ipa);
2939 /* Determine all SSA names we need to know flags for. */
2940 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2941 parm = TREE_CHAIN (parm))
2943 tree name = ssa_default_def (cfun, parm);
2944 if (name)
2945 eaf_analysis.analyze_ssa_name (name);
2947 if (retslot)
2948 eaf_analysis.analyze_ssa_name (retslot);
2949 if (static_chain)
2950 eaf_analysis.analyze_ssa_name (static_chain);
2952 /* Do the dataflow. */
2953 eaf_analysis.propagate ();
2955 tree attr = lookup_attribute ("fn spec",
2956 TYPE_ATTRIBUTES
2957 (TREE_TYPE (current_function_decl)));
2958 attr_fnspec fnspec (attr
2959 ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)))
2960 : "");
2963 /* Store results to summaries. */
2964 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
2965 parm = TREE_CHAIN (parm))
2967 tree name = ssa_default_def (cfun, parm);
2968 if (!name || has_zero_uses (name))
2970 /* We do not track non-SSA parameters,
2971 but we want to track unused gimple_regs. */
2972 if (!is_gimple_reg (parm))
2973 continue;
2974 if (summary)
2976 if (parm_index >= summary->arg_flags.length ())
2977 summary->arg_flags.safe_grow_cleared (count, true);
2978 summary->arg_flags[parm_index] = EAF_UNUSED;
2980 if (summary_lto)
2982 if (parm_index >= summary_lto->arg_flags.length ())
2983 summary_lto->arg_flags.safe_grow_cleared (count, true);
2984 summary_lto->arg_flags[parm_index] = EAF_UNUSED;
2986 continue;
2988 int flags = eaf_analysis.get_ssa_name_flags (name);
2989 int attr_flags = fnspec.arg_eaf_flags (parm_index);
2991 if (dump_file && (flags | attr_flags) != flags && !(flags & EAF_UNUSED))
2993 fprintf (dump_file,
2994 " Flags for param %i combined with fnspec flags:",
2995 (int)parm_index);
2996 dump_eaf_flags (dump_file, attr_flags, false);
2997 fprintf (dump_file, " determined: ");
2998 dump_eaf_flags (dump_file, flags, true);
3000 flags |= attr_flags;
3002 /* Eliminate useless flags so we do not end up storing unnecessary
3003 summaries. */
3005 flags = remove_useless_eaf_flags
3006 (flags, ecf_flags,
3007 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3008 if (past_flags.length () > parm_index)
3010 int past = past_flags[parm_index];
3011 past = remove_useless_eaf_flags
3012 (past, ecf_flags,
3013 VOID_TYPE_P (TREE_TYPE
3014 (TREE_TYPE (current_function_decl))));
3015 /* Store merging can produce reads when combining together multiple
3016 bitfields. See PR111613. */
3017 past &= ~(EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ);
3018 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
3020 fprintf (dump_file,
3021 " Flags for param %i combined with IPA pass:",
3022 (int)parm_index);
3023 dump_eaf_flags (dump_file, past, false);
3024 fprintf (dump_file, " determined: ");
3025 dump_eaf_flags (dump_file, flags, true);
3027 if (!(flags & EAF_UNUSED))
3028 flags |= past;
3031 if (flags)
3033 if (summary)
3035 if (parm_index >= summary->arg_flags.length ())
3036 summary->arg_flags.safe_grow_cleared (count, true);
3037 summary->arg_flags[parm_index] = flags;
3039 if (summary_lto)
3041 if (parm_index >= summary_lto->arg_flags.length ())
3042 summary_lto->arg_flags.safe_grow_cleared (count, true);
3043 summary_lto->arg_flags[parm_index] = flags;
3045 eaf_analysis.record_escape_points (name, parm_index, flags);
3048 if (retslot)
3050 int flags = eaf_analysis.get_ssa_name_flags (retslot);
3051 int past = past_retslot_flags;
3053 flags = remove_useless_eaf_flags (flags, ecf_flags, false);
3054 past = remove_useless_eaf_flags
3055 (past, ecf_flags,
3056 VOID_TYPE_P (TREE_TYPE
3057 (TREE_TYPE (current_function_decl))));
3058 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
3060 fprintf (dump_file,
3061 " Retslot flags combined with IPA pass:");
3062 dump_eaf_flags (dump_file, past, false);
3063 fprintf (dump_file, " determined: ");
3064 dump_eaf_flags (dump_file, flags, true);
3066 if (!(flags & EAF_UNUSED))
3067 flags |= past;
3068 if (flags)
3070 if (summary)
3071 summary->retslot_flags = flags;
3072 if (summary_lto)
3073 summary_lto->retslot_flags = flags;
3074 eaf_analysis.record_escape_points (retslot,
3075 MODREF_RETSLOT_PARM, flags);
3078 if (static_chain)
3080 int flags = eaf_analysis.get_ssa_name_flags (static_chain);
3081 int past = past_static_chain_flags;
3083 flags = remove_useless_eaf_flags (flags, ecf_flags, false);
3084 past = remove_useless_eaf_flags
3085 (past, ecf_flags,
3086 VOID_TYPE_P (TREE_TYPE
3087 (TREE_TYPE (current_function_decl))));
3088 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
3090 fprintf (dump_file,
3091 " Static chain flags combined with IPA pass:");
3092 dump_eaf_flags (dump_file, past, false);
3093 fprintf (dump_file, " determined: ");
3094 dump_eaf_flags (dump_file, flags, true);
3096 if (!(flags & EAF_UNUSED))
3097 flags |= past;
3098 if (flags)
3100 if (summary)
3101 summary->static_chain_flags = flags;
3102 if (summary_lto)
3103 summary_lto->static_chain_flags = flags;
3104 eaf_analysis.record_escape_points (static_chain,
3105 MODREF_STATIC_CHAIN_PARM,
3106 flags);
3111 /* Analyze function. IPA indicates whether we're running in local mode
3112 (false) or the IPA mode (true).
3113 Return true if fixup cfg is needed after the pass. */
3115 static bool
3116 analyze_function (bool ipa)
3118 bool fixup_cfg = false;
3119 if (dump_file)
3120 fprintf (dump_file, "\n\nmodref analyzing '%s' (ipa=%i)%s%s\n",
3121 cgraph_node::get (current_function_decl)->dump_name (), ipa,
3122 TREE_READONLY (current_function_decl) ? " (const)" : "",
3123 DECL_PURE_P (current_function_decl) ? " (pure)" : "");
3125 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
3126 if (!flag_ipa_modref
3127 || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
3128 return false;
3130 /* Compute no-LTO summaries when local optimization is going to happen. */
3131 bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
3132 || (in_lto_p && !flag_wpa
3133 && flag_incremental_link != INCREMENTAL_LINK_LTO));
3134 /* Compute LTO when LTO streaming is going to happen. */
3135 bool lto = ipa && ((flag_lto && !in_lto_p)
3136 || flag_wpa
3137 || flag_incremental_link == INCREMENTAL_LINK_LTO);
3138 cgraph_node *fnode = cgraph_node::get (current_function_decl);
3140 modref_summary *summary = NULL;
3141 modref_summary_lto *summary_lto = NULL;
3143 bool past_flags_known = false;
3144 auto_vec <eaf_flags_t> past_flags;
3145 int past_retslot_flags = 0;
3146 int past_static_chain_flags = 0;
3148 /* Initialize the summary.
3149 If we run in local mode there is possibly pre-existing summary from
3150 IPA pass. Dump it so it is easy to compare if mod-ref info has
3151 improved. */
3152 if (!ipa)
3154 if (!optimization_summaries)
3155 optimization_summaries = modref_summaries::create_ggc (symtab);
3156 else /* Remove existing summary if we are re-running the pass. */
3158 summary = optimization_summaries->get (fnode);
3159 if (summary != NULL
3160 && summary->loads)
3162 if (dump_file)
3164 fprintf (dump_file, "Past summary:\n");
3165 optimization_summaries->get (fnode)->dump (dump_file);
3167 past_flags.reserve_exact (summary->arg_flags.length ());
3168 past_flags.splice (summary->arg_flags);
3169 past_retslot_flags = summary->retslot_flags;
3170 past_static_chain_flags = summary->static_chain_flags;
3171 past_flags_known = true;
3173 optimization_summaries->remove (fnode);
3175 summary = optimization_summaries->get_create (fnode);
3176 gcc_checking_assert (nolto && !lto);
3178 /* In IPA mode we analyze every function precisely once. Assert that. */
3179 else
3181 if (nolto)
3183 if (!summaries)
3184 summaries = modref_summaries::create_ggc (symtab);
3185 else
3186 summaries->remove (fnode);
3187 summary = summaries->get_create (fnode);
3189 if (lto)
3191 if (!summaries_lto)
3192 summaries_lto = modref_summaries_lto::create_ggc (symtab);
3193 else
3194 summaries_lto->remove (fnode);
3195 summary_lto = summaries_lto->get_create (fnode);
3197 if (!fnspec_summaries)
3198 fnspec_summaries = new fnspec_summaries_t (symtab);
3199 if (!escape_summaries)
3200 escape_summaries = new escape_summaries_t (symtab);
3204 /* Create and initialize summary for F.
3205 Note that summaries may be already allocated from previous
3206 run of the pass. */
3207 if (nolto)
3209 gcc_assert (!summary->loads);
3210 summary->loads = modref_records::create_ggc ();
3211 gcc_assert (!summary->stores);
3212 summary->stores = modref_records::create_ggc ();
3213 summary->writes_errno = false;
3214 summary->side_effects = false;
3215 summary->nondeterministic = false;
3216 summary->calls_interposable = false;
3218 if (lto)
3220 gcc_assert (!summary_lto->loads);
3221 summary_lto->loads = modref_records_lto::create_ggc ();
3222 gcc_assert (!summary_lto->stores);
3223 summary_lto->stores = modref_records_lto::create_ggc ();
3224 summary_lto->writes_errno = false;
3225 summary_lto->side_effects = false;
3226 summary_lto->nondeterministic = false;
3227 summary_lto->calls_interposable = false;
3230 analyze_parms (summary, summary_lto, ipa,
3231 past_flags, past_retslot_flags, past_static_chain_flags);
3234 modref_access_analysis analyzer (ipa, summary, summary_lto);
3235 analyzer.analyze ();
3238 if (!ipa && flag_ipa_pure_const)
3240 if (!summary->stores->every_base && !summary->stores->bases
3241 && !summary->nondeterministic)
3243 if (!summary->loads->every_base && !summary->loads->bases
3244 && !summary->calls_interposable)
3245 fixup_cfg = ipa_make_function_const (fnode,
3246 summary->side_effects, true);
3247 else
3248 fixup_cfg = ipa_make_function_pure (fnode,
3249 summary->side_effects, true);
3252 int ecf_flags = flags_from_decl_or_type (current_function_decl);
3253 if (summary && !summary->useful_p (ecf_flags))
3255 if (!ipa)
3256 optimization_summaries->remove (fnode);
3257 else
3258 summaries->remove (fnode);
3259 summary = NULL;
3261 if (summary)
3262 summary->finalize (current_function_decl);
3263 if (summary_lto && !summary_lto->useful_p (ecf_flags))
3265 summaries_lto->remove (fnode);
3266 summary_lto = NULL;
3269 if (ipa && !summary && !summary_lto)
3270 remove_modref_edge_summaries (fnode);
3272 if (dump_file)
3274 fprintf (dump_file, " - modref done with result: tracked.\n");
3275 if (summary)
3276 summary->dump (dump_file);
3277 if (summary_lto)
3278 summary_lto->dump (dump_file);
3279 dump_modref_edge_summaries (dump_file, fnode, 2);
3280 /* To simplify debugging, compare IPA and local solutions. */
3281 if (past_flags_known && summary)
3283 size_t len = summary->arg_flags.length ();
3285 if (past_flags.length () > len)
3286 len = past_flags.length ();
3287 for (size_t i = 0; i < len; i++)
3289 int old_flags = i < past_flags.length () ? past_flags[i] : 0;
3290 int new_flags = i < summary->arg_flags.length ()
3291 ? summary->arg_flags[i] : 0;
3292 old_flags = remove_useless_eaf_flags
3293 (old_flags, flags_from_decl_or_type (current_function_decl),
3294 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3295 if (old_flags != new_flags)
3297 if ((old_flags & ~new_flags) == 0
3298 || (new_flags & EAF_UNUSED))
3299 fprintf (dump_file, " Flags for param %i improved:",
3300 (int)i);
3301 else
3302 fprintf (dump_file, " Flags for param %i changed:",
3303 (int)i);
3304 dump_eaf_flags (dump_file, old_flags, false);
3305 fprintf (dump_file, " -> ");
3306 dump_eaf_flags (dump_file, new_flags, true);
3309 past_retslot_flags = remove_useless_eaf_flags
3310 (past_retslot_flags,
3311 flags_from_decl_or_type (current_function_decl),
3312 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3313 if (past_retslot_flags != summary->retslot_flags)
3315 if ((past_retslot_flags & ~summary->retslot_flags) == 0
3316 || (summary->retslot_flags & EAF_UNUSED))
3317 fprintf (dump_file, " Flags for retslot improved:");
3318 else
3319 fprintf (dump_file, " Flags for retslot changed:");
3320 dump_eaf_flags (dump_file, past_retslot_flags, false);
3321 fprintf (dump_file, " -> ");
3322 dump_eaf_flags (dump_file, summary->retslot_flags, true);
3324 past_static_chain_flags = remove_useless_eaf_flags
3325 (past_static_chain_flags,
3326 flags_from_decl_or_type (current_function_decl),
3327 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3328 if (past_static_chain_flags != summary->static_chain_flags)
3330 if ((past_static_chain_flags & ~summary->static_chain_flags) == 0
3331 || (summary->static_chain_flags & EAF_UNUSED))
3332 fprintf (dump_file, " Flags for static chain improved:");
3333 else
3334 fprintf (dump_file, " Flags for static chain changed:");
3335 dump_eaf_flags (dump_file, past_static_chain_flags, false);
3336 fprintf (dump_file, " -> ");
3337 dump_eaf_flags (dump_file, summary->static_chain_flags, true);
3340 else if (past_flags_known && !summary)
3342 for (size_t i = 0; i < past_flags.length (); i++)
3344 int old_flags = past_flags[i];
3345 old_flags = remove_useless_eaf_flags
3346 (old_flags, flags_from_decl_or_type (current_function_decl),
3347 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3348 if (old_flags)
3350 fprintf (dump_file, " Flags for param %i worsened:",
3351 (int)i);
3352 dump_eaf_flags (dump_file, old_flags, false);
3353 fprintf (dump_file, " -> \n");
3356 past_retslot_flags = remove_useless_eaf_flags
3357 (past_retslot_flags,
3358 flags_from_decl_or_type (current_function_decl),
3359 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3360 if (past_retslot_flags)
3362 fprintf (dump_file, " Flags for retslot worsened:");
3363 dump_eaf_flags (dump_file, past_retslot_flags, false);
3364 fprintf (dump_file, " ->\n");
3366 past_static_chain_flags = remove_useless_eaf_flags
3367 (past_static_chain_flags,
3368 flags_from_decl_or_type (current_function_decl),
3369 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3370 if (past_static_chain_flags)
3372 fprintf (dump_file, " Flags for static chain worsened:");
3373 dump_eaf_flags (dump_file, past_static_chain_flags, false);
3374 fprintf (dump_file, " ->\n");
3378 return fixup_cfg;
3381 /* Callback for generate_summary. */
3383 static void
3384 modref_generate (void)
3386 struct cgraph_node *node;
3387 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
3389 function *f = DECL_STRUCT_FUNCTION (node->decl);
3390 if (!f)
3391 continue;
3392 push_cfun (f);
3393 analyze_function (true);
3394 pop_cfun ();
3398 } /* ANON namespace. */
3400 /* Debugging helper. */
3402 void
3403 debug_eaf_flags (int flags)
3405 dump_eaf_flags (stderr, flags, true);
3408 /* Called when a new function is inserted to callgraph late. */
3410 void
3411 modref_summaries::insert (struct cgraph_node *node, modref_summary *)
3413 /* Local passes ought to be executed by the pass manager. */
3414 if (this == optimization_summaries)
3416 optimization_summaries->remove (node);
3417 return;
3419 if (!DECL_STRUCT_FUNCTION (node->decl)
3420 || !opt_for_fn (node->decl, flag_ipa_modref))
3422 summaries->remove (node);
3423 return;
3425 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
3426 analyze_function (true);
3427 pop_cfun ();
3430 /* Called when a new function is inserted to callgraph late. */
3432 void
3433 modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
3435 /* We do not support adding new function when IPA information is already
3436 propagated. This is done only by SIMD cloning that is not very
3437 critical. */
3438 if (!DECL_STRUCT_FUNCTION (node->decl)
3439 || !opt_for_fn (node->decl, flag_ipa_modref)
3440 || propagated)
3442 summaries_lto->remove (node);
3443 return;
3445 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
3446 analyze_function (true);
3447 pop_cfun ();
3450 /* Called when new clone is inserted to callgraph late. */
3452 void
3453 modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
3454 modref_summary *src_data,
3455 modref_summary *dst_data)
3457 /* Do not duplicate optimization summaries; we do not handle parameter
3458 transforms on them. */
3459 if (this == optimization_summaries)
3461 optimization_summaries->remove (dst);
3462 return;
3464 dst_data->stores = modref_records::create_ggc ();
3465 dst_data->stores->copy_from (src_data->stores);
3466 dst_data->loads = modref_records::create_ggc ();
3467 dst_data->loads->copy_from (src_data->loads);
3468 dst_data->kills.reserve_exact (src_data->kills.length ());
3469 dst_data->kills.splice (src_data->kills);
3470 dst_data->writes_errno = src_data->writes_errno;
3471 dst_data->side_effects = src_data->side_effects;
3472 dst_data->nondeterministic = src_data->nondeterministic;
3473 dst_data->calls_interposable = src_data->calls_interposable;
3474 if (src_data->arg_flags.length ())
3475 dst_data->arg_flags = src_data->arg_flags.copy ();
3476 dst_data->retslot_flags = src_data->retslot_flags;
3477 dst_data->static_chain_flags = src_data->static_chain_flags;
3480 /* Called when new clone is inserted to callgraph late. */
3482 void
3483 modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
3484 modref_summary_lto *src_data,
3485 modref_summary_lto *dst_data)
3487 /* Be sure that no further cloning happens after ipa-modref. If it does
3488 we will need to update signatures for possible param changes. */
3489 gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
3490 dst_data->stores = modref_records_lto::create_ggc ();
3491 dst_data->stores->copy_from (src_data->stores);
3492 dst_data->loads = modref_records_lto::create_ggc ();
3493 dst_data->loads->copy_from (src_data->loads);
3494 dst_data->kills.reserve_exact (src_data->kills.length ());
3495 dst_data->kills.splice (src_data->kills);
3496 dst_data->writes_errno = src_data->writes_errno;
3497 dst_data->side_effects = src_data->side_effects;
3498 dst_data->nondeterministic = src_data->nondeterministic;
3499 dst_data->calls_interposable = src_data->calls_interposable;
3500 if (src_data->arg_flags.length ())
3501 dst_data->arg_flags = src_data->arg_flags.copy ();
3502 dst_data->retslot_flags = src_data->retslot_flags;
3503 dst_data->static_chain_flags = src_data->static_chain_flags;
3506 namespace
3508 /* Definition of the modref pass on GIMPLE. */
3509 const pass_data pass_data_modref = {
3510 GIMPLE_PASS,
3511 "modref",
3512 OPTGROUP_IPA,
3513 TV_TREE_MODREF,
3514 (PROP_cfg | PROP_ssa),
3521 class pass_modref : public gimple_opt_pass
3523 public:
3524 pass_modref (gcc::context *ctxt)
3525 : gimple_opt_pass (pass_data_modref, ctxt) {}
3527 /* opt_pass methods: */
3528 opt_pass *clone () final override
3530 return new pass_modref (m_ctxt);
3532 bool gate (function *) final override
3534 return flag_ipa_modref;
3536 unsigned int execute (function *) final override;
3539 /* Encode TT to the output block OB using the summary streaming API. */
3541 static void
3542 write_modref_records (modref_records_lto *tt, struct output_block *ob)
3544 streamer_write_uhwi (ob, tt->every_base);
3545 streamer_write_uhwi (ob, vec_safe_length (tt->bases));
3546 for (auto base_node : tt->bases)
3548 stream_write_tree (ob, base_node->base, true);
3550 streamer_write_uhwi (ob, base_node->every_ref);
3551 streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
3553 for (auto ref_node : base_node->refs)
3555 stream_write_tree (ob, ref_node->ref, true);
3556 streamer_write_uhwi (ob, ref_node->every_access);
3557 streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
3559 for (auto access_node : ref_node->accesses)
3560 access_node.stream_out (ob);
3565 /* Read a modref_tree from the input block IB using the data from DATA_IN.
3566 This assumes that the tree was encoded using write_modref_tree.
3567 Either nolto_ret or lto_ret is initialized by the tree depending whether
3568 LTO streaming is expected or not. */
3570 static void
3571 read_modref_records (tree decl,
3572 lto_input_block *ib, struct data_in *data_in,
3573 modref_records **nolto_ret,
3574 modref_records_lto **lto_ret)
3576 size_t max_bases = opt_for_fn (decl, param_modref_max_bases);
3577 size_t max_refs = opt_for_fn (decl, param_modref_max_refs);
3578 size_t max_accesses = opt_for_fn (decl, param_modref_max_accesses);
3580 if (lto_ret)
3581 *lto_ret = modref_records_lto::create_ggc ();
3582 if (nolto_ret)
3583 *nolto_ret = modref_records::create_ggc ();
3584 gcc_checking_assert (lto_ret || nolto_ret);
3586 size_t every_base = streamer_read_uhwi (ib);
3587 size_t nbase = streamer_read_uhwi (ib);
3589 gcc_assert (!every_base || nbase == 0);
3590 if (every_base)
3592 if (nolto_ret)
3593 (*nolto_ret)->collapse ();
3594 if (lto_ret)
3595 (*lto_ret)->collapse ();
3597 for (size_t i = 0; i < nbase; i++)
3599 tree base_tree = stream_read_tree (ib, data_in);
3600 modref_base_node <alias_set_type> *nolto_base_node = NULL;
3601 modref_base_node <tree> *lto_base_node = NULL;
3603 /* At stream in time we have LTO alias info. Check if we streamed in
3604 something obviously unnecessary. Do not glob types by alias sets;
3605 it is not 100% clear that ltrans types will get merged same way.
3606 Types may get refined based on ODR type conflicts. */
3607 if (base_tree && !get_alias_set (base_tree))
3609 if (dump_file)
3611 fprintf (dump_file, "Streamed in alias set 0 type ");
3612 print_generic_expr (dump_file, base_tree);
3613 fprintf (dump_file, "\n");
3615 base_tree = NULL;
3618 if (nolto_ret)
3619 nolto_base_node = (*nolto_ret)->insert_base (base_tree
3620 ? get_alias_set (base_tree)
3621 : 0, 0, INT_MAX);
3622 if (lto_ret)
3623 lto_base_node = (*lto_ret)->insert_base (base_tree, 0, max_bases);
3624 size_t every_ref = streamer_read_uhwi (ib);
3625 size_t nref = streamer_read_uhwi (ib);
3627 gcc_assert (!every_ref || nref == 0);
3628 if (every_ref)
3630 if (nolto_base_node)
3631 nolto_base_node->collapse ();
3632 if (lto_base_node)
3633 lto_base_node->collapse ();
3635 for (size_t j = 0; j < nref; j++)
3637 tree ref_tree = stream_read_tree (ib, data_in);
3639 if (ref_tree && !get_alias_set (ref_tree))
3641 if (dump_file)
3643 fprintf (dump_file, "Streamed in alias set 0 type ");
3644 print_generic_expr (dump_file, ref_tree);
3645 fprintf (dump_file, "\n");
3647 ref_tree = NULL;
3650 modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
3651 modref_ref_node <tree> *lto_ref_node = NULL;
3653 if (nolto_base_node)
3654 nolto_ref_node
3655 = nolto_base_node->insert_ref (ref_tree
3656 ? get_alias_set (ref_tree) : 0,
3657 max_refs);
3658 if (lto_base_node)
3659 lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
3661 size_t every_access = streamer_read_uhwi (ib);
3662 size_t naccesses = streamer_read_uhwi (ib);
3664 if (nolto_ref_node && every_access)
3665 nolto_ref_node->collapse ();
3666 if (lto_ref_node && every_access)
3667 lto_ref_node->collapse ();
3669 for (size_t k = 0; k < naccesses; k++)
3671 modref_access_node a = modref_access_node::stream_in (ib);
3672 if (nolto_ref_node)
3673 nolto_ref_node->insert_access (a, max_accesses, false);
3674 if (lto_ref_node)
3675 lto_ref_node->insert_access (a, max_accesses, false);
3679 if (lto_ret)
3680 (*lto_ret)->cleanup ();
3681 if (nolto_ret)
3682 (*nolto_ret)->cleanup ();
3685 /* Write ESUM to BP. */
3687 static void
3688 modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
3690 if (!esum)
3692 bp_pack_var_len_unsigned (bp, 0);
3693 return;
3695 bp_pack_var_len_unsigned (bp, esum->esc.length ());
3696 unsigned int i;
3697 escape_entry *ee;
3698 FOR_EACH_VEC_ELT (esum->esc, i, ee)
3700 bp_pack_var_len_int (bp, ee->parm_index);
3701 bp_pack_var_len_unsigned (bp, ee->arg);
3702 bp_pack_var_len_unsigned (bp, ee->min_flags);
3703 bp_pack_value (bp, ee->direct, 1);
3707 /* Read escape summary for E from BP. */
3709 static void
3710 modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
3712 unsigned int n = bp_unpack_var_len_unsigned (bp);
3713 if (!n)
3714 return;
3715 escape_summary *esum = escape_summaries->get_create (e);
3716 esum->esc.reserve_exact (n);
3717 for (unsigned int i = 0; i < n; i++)
3719 escape_entry ee;
3720 ee.parm_index = bp_unpack_var_len_int (bp);
3721 ee.arg = bp_unpack_var_len_unsigned (bp);
3722 ee.min_flags = bp_unpack_var_len_unsigned (bp);
3723 ee.direct = bp_unpack_value (bp, 1);
3724 esum->esc.quick_push (ee);
3728 /* Callback for write_summary. */
3730 static void
3731 modref_write ()
3733 struct output_block *ob = create_output_block (LTO_section_ipa_modref);
3734 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
3735 unsigned int count = 0;
3736 int i;
3738 if (!summaries_lto)
3740 streamer_write_uhwi (ob, 0);
3741 streamer_write_char_stream (ob->main_stream, 0);
3742 produce_asm (ob, NULL);
3743 destroy_output_block (ob);
3744 return;
3747 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3749 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3750 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3751 modref_summary_lto *r;
3753 if (cnode && cnode->definition && !cnode->alias
3754 && (r = summaries_lto->get (cnode))
3755 && r->useful_p (flags_from_decl_or_type (cnode->decl)))
3756 count++;
3758 streamer_write_uhwi (ob, count);
3760 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3762 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3763 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3765 if (cnode && cnode->definition && !cnode->alias)
3767 modref_summary_lto *r = summaries_lto->get (cnode);
3769 if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
3770 continue;
3772 streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
3774 streamer_write_uhwi (ob, r->arg_flags.length ());
3775 for (unsigned int i = 0; i < r->arg_flags.length (); i++)
3776 streamer_write_uhwi (ob, r->arg_flags[i]);
3777 streamer_write_uhwi (ob, r->retslot_flags);
3778 streamer_write_uhwi (ob, r->static_chain_flags);
3780 write_modref_records (r->loads, ob);
3781 write_modref_records (r->stores, ob);
3782 streamer_write_uhwi (ob, r->kills.length ());
3783 for (auto kill : r->kills)
3784 kill.stream_out (ob);
3786 struct bitpack_d bp = bitpack_create (ob->main_stream);
3787 bp_pack_value (&bp, r->writes_errno, 1);
3788 bp_pack_value (&bp, r->side_effects, 1);
3789 bp_pack_value (&bp, r->nondeterministic, 1);
3790 bp_pack_value (&bp, r->calls_interposable, 1);
3791 if (!flag_wpa)
3793 for (cgraph_edge *e = cnode->indirect_calls;
3794 e; e = e->next_callee)
3796 class fnspec_summary *sum = fnspec_summaries->get (e);
3797 bp_pack_value (&bp, sum != NULL, 1);
3798 if (sum)
3799 bp_pack_string (ob, &bp, sum->fnspec, true);
3800 class escape_summary *esum = escape_summaries->get (e);
3801 modref_write_escape_summary (&bp,esum);
3803 for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
3805 class fnspec_summary *sum = fnspec_summaries->get (e);
3806 bp_pack_value (&bp, sum != NULL, 1);
3807 if (sum)
3808 bp_pack_string (ob, &bp, sum->fnspec, true);
3809 class escape_summary *esum = escape_summaries->get (e);
3810 modref_write_escape_summary (&bp,esum);
3813 streamer_write_bitpack (&bp);
3816 streamer_write_char_stream (ob->main_stream, 0);
3817 produce_asm (ob, NULL);
3818 destroy_output_block (ob);
3821 static void
3822 read_section (struct lto_file_decl_data *file_data, const char *data,
3823 size_t len)
3825 const struct lto_function_header *header
3826 = (const struct lto_function_header *) data;
3827 const int cfg_offset = sizeof (struct lto_function_header);
3828 const int main_offset = cfg_offset + header->cfg_size;
3829 const int string_offset = main_offset + header->main_size;
3830 struct data_in *data_in;
3831 unsigned int i;
3832 unsigned int f_count;
3834 lto_input_block ib ((const char *) data + main_offset, header->main_size,
3835 file_data);
3837 data_in
3838 = lto_data_in_create (file_data, (const char *) data + string_offset,
3839 header->string_size, vNULL);
3840 f_count = streamer_read_uhwi (&ib);
3841 for (i = 0; i < f_count; i++)
3843 struct cgraph_node *node;
3844 lto_symtab_encoder_t encoder;
3846 unsigned int index = streamer_read_uhwi (&ib);
3847 encoder = file_data->symtab_node_encoder;
3848 node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
3849 index));
3851 modref_summary *modref_sum = summaries
3852 ? summaries->get_create (node) : NULL;
3853 modref_summary_lto *modref_sum_lto = summaries_lto
3854 ? summaries_lto->get_create (node)
3855 : NULL;
3856 if (optimization_summaries)
3857 modref_sum = optimization_summaries->get_create (node);
3859 if (modref_sum)
3861 modref_sum->writes_errno = false;
3862 modref_sum->side_effects = false;
3863 modref_sum->nondeterministic = false;
3864 modref_sum->calls_interposable = false;
3866 if (modref_sum_lto)
3868 modref_sum_lto->writes_errno = false;
3869 modref_sum_lto->side_effects = false;
3870 modref_sum_lto->nondeterministic = false;
3871 modref_sum_lto->calls_interposable = false;
3874 gcc_assert (!modref_sum || (!modref_sum->loads
3875 && !modref_sum->stores));
3876 gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
3877 && !modref_sum_lto->stores));
3878 unsigned int args = streamer_read_uhwi (&ib);
3879 if (args && modref_sum)
3880 modref_sum->arg_flags.reserve_exact (args);
3881 if (args && modref_sum_lto)
3882 modref_sum_lto->arg_flags.reserve_exact (args);
3883 for (unsigned int i = 0; i < args; i++)
3885 eaf_flags_t flags = streamer_read_uhwi (&ib);
3886 if (modref_sum)
3887 modref_sum->arg_flags.quick_push (flags);
3888 if (modref_sum_lto)
3889 modref_sum_lto->arg_flags.quick_push (flags);
3891 eaf_flags_t flags = streamer_read_uhwi (&ib);
3892 if (modref_sum)
3893 modref_sum->retslot_flags = flags;
3894 if (modref_sum_lto)
3895 modref_sum_lto->retslot_flags = flags;
3897 flags = streamer_read_uhwi (&ib);
3898 if (modref_sum)
3899 modref_sum->static_chain_flags = flags;
3900 if (modref_sum_lto)
3901 modref_sum_lto->static_chain_flags = flags;
3903 read_modref_records (node->decl, &ib, data_in,
3904 modref_sum ? &modref_sum->loads : NULL,
3905 modref_sum_lto ? &modref_sum_lto->loads : NULL);
3906 read_modref_records (node->decl, &ib, data_in,
3907 modref_sum ? &modref_sum->stores : NULL,
3908 modref_sum_lto ? &modref_sum_lto->stores : NULL);
3909 int j = streamer_read_uhwi (&ib);
3910 if (j && modref_sum)
3911 modref_sum->kills.reserve_exact (j);
3912 if (j && modref_sum_lto)
3913 modref_sum_lto->kills.reserve_exact (j);
3914 for (int k = 0; k < j; k++)
3916 modref_access_node a = modref_access_node::stream_in (&ib);
3918 if (modref_sum)
3919 modref_sum->kills.quick_push (a);
3920 if (modref_sum_lto)
3921 modref_sum_lto->kills.quick_push (a);
3923 struct bitpack_d bp = streamer_read_bitpack (&ib);
3924 if (bp_unpack_value (&bp, 1))
3926 if (modref_sum)
3927 modref_sum->writes_errno = true;
3928 if (modref_sum_lto)
3929 modref_sum_lto->writes_errno = true;
3931 if (bp_unpack_value (&bp, 1))
3933 if (modref_sum)
3934 modref_sum->side_effects = true;
3935 if (modref_sum_lto)
3936 modref_sum_lto->side_effects = true;
3938 if (bp_unpack_value (&bp, 1))
3940 if (modref_sum)
3941 modref_sum->nondeterministic = true;
3942 if (modref_sum_lto)
3943 modref_sum_lto->nondeterministic = true;
3945 if (bp_unpack_value (&bp, 1))
3947 if (modref_sum)
3948 modref_sum->calls_interposable = true;
3949 if (modref_sum_lto)
3950 modref_sum_lto->calls_interposable = true;
3952 if (!flag_ltrans)
3954 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
3956 if (bp_unpack_value (&bp, 1))
3958 class fnspec_summary *sum = fnspec_summaries->get_create (e);
3959 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3961 modref_read_escape_summary (&bp, e);
3963 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3965 if (bp_unpack_value (&bp, 1))
3967 class fnspec_summary *sum = fnspec_summaries->get_create (e);
3968 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3970 modref_read_escape_summary (&bp, e);
3973 if (flag_ltrans)
3974 modref_sum->finalize (node->decl);
3975 if (dump_file)
3977 fprintf (dump_file, "Read modref for %s\n",
3978 node->dump_name ());
3979 if (modref_sum)
3980 modref_sum->dump (dump_file);
3981 if (modref_sum_lto)
3982 modref_sum_lto->dump (dump_file);
3983 dump_modref_edge_summaries (dump_file, node, 4);
3987 lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
3988 len);
3989 lto_data_in_delete (data_in);
3992 /* Callback for read_summary. */
3994 static void
3995 modref_read (void)
3997 struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
3998 struct lto_file_decl_data *file_data;
3999 unsigned int j = 0;
4001 gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
4002 if (flag_ltrans)
4003 optimization_summaries = modref_summaries::create_ggc (symtab);
4004 else
4006 if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
4007 summaries_lto = modref_summaries_lto::create_ggc (symtab);
4008 if (!flag_wpa
4009 || (flag_incremental_link == INCREMENTAL_LINK_LTO
4010 && flag_fat_lto_objects))
4011 summaries = modref_summaries::create_ggc (symtab);
4012 if (!fnspec_summaries)
4013 fnspec_summaries = new fnspec_summaries_t (symtab);
4014 if (!escape_summaries)
4015 escape_summaries = new escape_summaries_t (symtab);
4018 while ((file_data = file_data_vec[j++]))
4020 size_t len;
4021 const char *data = lto_get_summary_section_data (file_data,
4022 LTO_section_ipa_modref,
4023 &len);
4024 if (data)
4025 read_section (file_data, data, len);
4026 else
4027 /* Fatal error here. We do not want to support compiling ltrans units
4028 with different version of compiler or different flags than the WPA
4029 unit, so this should never happen. */
4030 fatal_error (input_location,
4031 "IPA modref summary is missing in input file");
4035 /* Recompute arg_flags for param adjustments in INFO. */
4037 static void
4038 remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
4040 auto_vec<eaf_flags_t> old = arg_flags.copy ();
4041 int max = -1;
4042 size_t i;
4043 ipa_adjusted_param *p;
4045 arg_flags.release ();
4047 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4049 int o = info->param_adjustments->get_original_index (i);
4050 if (o >= 0 && (int)old.length () > o && old[o])
4051 max = i;
4053 if (max >= 0)
4054 arg_flags.safe_grow_cleared (max + 1, true);
4055 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4057 int o = info->param_adjustments->get_original_index (i);
4058 if (o >= 0 && (int)old.length () > o && old[o])
4059 arg_flags[i] = old[o];
4063 /* Update kills according to the parm map MAP. */
4065 static void
4066 remap_kills (vec <modref_access_node> &kills, const vec <int> &map)
4068 for (size_t i = 0; i < kills.length ();)
4069 if (kills[i].parm_index >= 0)
4071 if (kills[i].parm_index < (int)map.length ()
4072 && map[kills[i].parm_index] != MODREF_UNKNOWN_PARM)
4074 kills[i].parm_index = map[kills[i].parm_index];
4075 i++;
4077 else
4078 kills.unordered_remove (i);
4080 else
4081 i++;
4084 /* Return true if the V can overlap with KILL. */
4086 static bool
4087 ipcp_argagg_and_kill_overlap_p (const ipa_argagg_value &v,
4088 const modref_access_node &kill)
4090 if (kill.parm_index == v.index)
4092 gcc_assert (kill.parm_offset_known);
4093 gcc_assert (known_eq (kill.max_size, kill.size));
4094 poly_int64 repl_size;
4095 bool ok = poly_int_tree_p (TYPE_SIZE (TREE_TYPE (v.value)),
4096 &repl_size);
4097 gcc_assert (ok);
4098 poly_int64 repl_offset (v.unit_offset);
4099 repl_offset <<= LOG2_BITS_PER_UNIT;
4100 poly_int64 combined_offset
4101 = (kill.parm_offset << LOG2_BITS_PER_UNIT) + kill.offset;
4102 if (ranges_maybe_overlap_p (repl_offset, repl_size,
4103 combined_offset, kill.size))
4104 return true;
4106 return false;
4109 /* If signature changed, update the summary. */
4111 static void
4112 update_signature (struct cgraph_node *node)
4114 modref_summary *r = optimization_summaries
4115 ? optimization_summaries->get (node) : NULL;
4116 modref_summary_lto *r_lto = summaries_lto
4117 ? summaries_lto->get (node) : NULL;
4118 if (!r && !r_lto)
4119 return;
4121 /* Propagating constants in killed memory can lead to eliminated stores in
4122 both callees (because they are considered redundant) and callers, leading
4123 to missing them altogether. */
4124 ipcp_transformation *ipcp_ts = ipcp_get_transformation_summary (node);
4125 if (ipcp_ts)
4127 for (auto &v : ipcp_ts->m_agg_values)
4129 if (!v.by_ref)
4130 continue;
4131 if (r)
4132 for (const modref_access_node &kill : r->kills)
4133 if (ipcp_argagg_and_kill_overlap_p (v, kill))
4135 v.killed = true;
4136 break;
4138 if (!v.killed && r_lto)
4139 for (const modref_access_node &kill : r_lto->kills)
4140 if (ipcp_argagg_and_kill_overlap_p (v, kill))
4142 v.killed = true;
4143 break;
4148 clone_info *info = clone_info::get (node);
4149 if (!info || !info->param_adjustments)
4150 return;
4152 if (dump_file)
4154 fprintf (dump_file, "Updating summary for %s from:\n",
4155 node->dump_name ());
4156 if (r)
4157 r->dump (dump_file);
4158 if (r_lto)
4159 r_lto->dump (dump_file);
4162 size_t i, max = 0;
4163 ipa_adjusted_param *p;
4165 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4167 int idx = info->param_adjustments->get_original_index (i);
4168 if (idx > (int)max)
4169 max = idx;
4172 auto_vec <int, 32> map;
4174 map.reserve (max + 1);
4175 for (i = 0; i <= max; i++)
4176 map.quick_push (MODREF_UNKNOWN_PARM);
4177 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4179 int idx = info->param_adjustments->get_original_index (i);
4180 if (idx >= 0)
4181 map[idx] = i;
4183 if (r)
4185 r->loads->remap_params (&map);
4186 r->stores->remap_params (&map);
4187 remap_kills (r->kills, map);
4188 if (r->arg_flags.length ())
4189 remap_arg_flags (r->arg_flags, info);
4191 if (r_lto)
4193 r_lto->loads->remap_params (&map);
4194 r_lto->stores->remap_params (&map);
4195 remap_kills (r_lto->kills, map);
4196 if (r_lto->arg_flags.length ())
4197 remap_arg_flags (r_lto->arg_flags, info);
4199 if (dump_file)
4201 fprintf (dump_file, "to:\n");
4202 if (r)
4203 r->dump (dump_file);
4204 if (r_lto)
4205 r_lto->dump (dump_file);
4207 if (r)
4208 r->finalize (node->decl);
4209 return;
4212 /* Definition of the modref IPA pass. */
4213 const pass_data pass_data_ipa_modref =
4215 IPA_PASS, /* type */
4216 "modref", /* name */
4217 OPTGROUP_IPA, /* optinfo_flags */
4218 TV_IPA_MODREF, /* tv_id */
4219 0, /* properties_required */
4220 0, /* properties_provided */
4221 0, /* properties_destroyed */
4222 0, /* todo_flags_start */
4223 ( TODO_dump_symtab ), /* todo_flags_finish */
4226 class pass_ipa_modref : public ipa_opt_pass_d
4228 public:
4229 pass_ipa_modref (gcc::context *ctxt)
4230 : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
4231 modref_generate, /* generate_summary */
4232 modref_write, /* write_summary */
4233 modref_read, /* read_summary */
4234 modref_write, /* write_optimization_summary */
4235 modref_read, /* read_optimization_summary */
4236 NULL, /* stmt_fixup */
4237 0, /* function_transform_todo_flags_start */
4238 NULL, /* function_transform */
4239 NULL) /* variable_transform */
4242 /* opt_pass methods: */
4243 opt_pass *clone () final override { return new pass_ipa_modref (m_ctxt); }
4244 bool gate (function *) final override
4246 return true;
4248 unsigned int execute (function *) final override;
4254 unsigned int pass_modref::execute (function *)
4256 if (analyze_function (false))
4257 return execute_fixup_cfg ();
4258 return 0;
4261 gimple_opt_pass *
4262 make_pass_modref (gcc::context *ctxt)
4264 return new pass_modref (ctxt);
4267 ipa_opt_pass_d *
4268 make_pass_ipa_modref (gcc::context *ctxt)
4270 return new pass_ipa_modref (ctxt);
4273 namespace {
4275 /* Skip edges from and to nodes without ipa_pure_const enabled.
4276 Ignore not available symbols. */
4278 static bool
4279 ignore_edge (struct cgraph_edge *e)
4281 /* We merge summaries of inline clones into summaries of functions they
4282 are inlined to. For that reason the complete function bodies must
4283 act as unit. */
4284 if (!e->inline_failed)
4285 return false;
4286 enum availability avail;
4287 cgraph_node *callee = e->callee->ultimate_alias_target
4288 (&avail, e->caller);
4290 return (avail <= AVAIL_INTERPOSABLE
4291 || ((!optimization_summaries || !optimization_summaries->get (callee))
4292 && (!summaries_lto || !summaries_lto->get (callee))));
4295 /* Compute parm_map for CALLEE_EDGE. */
4297 static bool
4298 compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
4300 class ipa_edge_args *args;
4301 if (ipa_node_params_sum
4302 && !callee_edge->call_stmt_cannot_inline_p
4303 && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
4305 int i, count = ipa_get_cs_argument_count (args);
4306 class ipa_node_params *caller_parms_info, *callee_pi;
4307 class ipa_call_summary *es
4308 = ipa_call_summaries->get (callee_edge);
4309 cgraph_node *callee
4310 = callee_edge->callee->ultimate_alias_target
4311 (NULL, callee_edge->caller);
4313 caller_parms_info
4314 = ipa_node_params_sum->get (callee_edge->caller->inlined_to
4315 ? callee_edge->caller->inlined_to
4316 : callee_edge->caller);
4317 callee_pi = ipa_node_params_sum->get (callee);
4319 (*parm_map).safe_grow_cleared (count, true);
4321 for (i = 0; i < count; i++)
4323 if (es && es->param[i].points_to_local_or_readonly_memory)
4325 (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
4326 continue;
4329 struct ipa_jump_func *jf
4330 = ipa_get_ith_jump_func (args, i);
4331 if (jf && callee_pi)
4333 tree cst = ipa_value_from_jfunc (caller_parms_info,
4335 ipa_get_type
4336 (callee_pi, i));
4337 if (cst && points_to_local_or_readonly_memory_p (cst))
4339 (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
4340 continue;
4343 if (jf && jf->type == IPA_JF_PASS_THROUGH)
4345 (*parm_map)[i].parm_index
4346 = ipa_get_jf_pass_through_formal_id (jf);
4347 if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
4349 (*parm_map)[i].parm_offset_known = true;
4350 (*parm_map)[i].parm_offset = 0;
4352 else if (ipa_get_jf_pass_through_operation (jf)
4353 == POINTER_PLUS_EXPR
4354 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
4355 &(*parm_map)[i].parm_offset))
4356 (*parm_map)[i].parm_offset_known = true;
4357 else
4358 (*parm_map)[i].parm_offset_known = false;
4359 continue;
4361 if (jf && jf->type == IPA_JF_ANCESTOR)
4363 (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
4364 (*parm_map)[i].parm_offset_known = true;
4365 gcc_checking_assert
4366 (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
4367 (*parm_map)[i].parm_offset
4368 = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
4370 else
4371 (*parm_map)[i].parm_index = -1;
4373 if (dump_file)
4375 fprintf (dump_file, " Parm map: ");
4376 for (i = 0; i < count; i++)
4377 fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
4378 fprintf (dump_file, "\n");
4380 return true;
4382 return false;
4385 /* Map used to translate escape infos. */
4387 struct escape_map
4389 int parm_index;
4390 bool direct;
4393 /* Update escape map for E. */
4395 static void
4396 update_escape_summary_1 (cgraph_edge *e,
4397 vec <vec <escape_map>> &map,
4398 bool ignore_stores)
4400 escape_summary *sum = escape_summaries->get (e);
4401 if (!sum)
4402 return;
4403 auto_vec <escape_entry> old = sum->esc.copy ();
4404 sum->esc.release ();
4406 unsigned int i;
4407 escape_entry *ee;
4408 FOR_EACH_VEC_ELT (old, i, ee)
4410 unsigned int j;
4411 struct escape_map *em;
4412 /* TODO: We do not have jump functions for return slots, so we
4413 never propagate them to outer function. */
4414 if (ee->parm_index >= (int)map.length ()
4415 || ee->parm_index < 0)
4416 continue;
4417 FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
4419 eaf_flags_t min_flags = ee->min_flags;
4420 if (ee->direct && !em->direct)
4421 min_flags = deref_flags (min_flags, ignore_stores);
4422 struct escape_entry entry = {em->parm_index, ee->arg,
4423 min_flags,
4424 ee->direct && em->direct};
4425 sum->esc.safe_push (entry);
4428 if (!sum->esc.length ())
4429 escape_summaries->remove (e);
4432 /* Update escape map for NODE. */
4434 static void
4435 update_escape_summary (cgraph_node *node,
4436 vec <vec <escape_map>> &map,
4437 bool ignore_stores)
4439 if (!escape_summaries)
4440 return;
4441 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
4442 update_escape_summary_1 (e, map, ignore_stores);
4443 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
4445 if (!e->inline_failed)
4446 update_escape_summary (e->callee, map, ignore_stores);
4447 else
4448 update_escape_summary_1 (e, map, ignore_stores);
4452 /* Get parameter type from DECL. This is only safe for special cases
4453 like builtins we create fnspec for because the type match is checked
4454 at fnspec creation time. */
4456 static tree
4457 get_parm_type (tree decl, unsigned int i)
4459 tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
4461 for (unsigned int p = 0; p < i; p++)
4462 t = TREE_CHAIN (t);
4463 return TREE_VALUE (t);
4466 /* Return access mode for argument I of call E with FNSPEC. */
4468 static modref_access_node
4469 get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
4470 unsigned int i, modref_parm_map &map)
4472 tree size = NULL_TREE;
4473 unsigned int size_arg;
4475 if (!fnspec.arg_specified_p (i))
4477 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
4479 cgraph_node *node = e->caller->inlined_to
4480 ? e->caller->inlined_to : e->caller;
4481 ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
4482 ipa_edge_args *args = ipa_edge_args_sum->get (e);
4483 struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
4485 if (jf)
4486 size = ipa_value_from_jfunc (caller_parms_info, jf,
4487 get_parm_type (e->callee->decl, size_arg));
4489 else if (fnspec.arg_access_size_given_by_type_p (i))
4490 size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
4491 modref_access_node a = {0, -1, -1,
4492 map.parm_offset, map.parm_index,
4493 map.parm_offset_known, 0};
4494 poly_int64 size_hwi;
4495 if (size
4496 && poly_int_tree_p (size, &size_hwi)
4497 && coeffs_in_range_p (size_hwi, 0,
4498 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
4500 a.size = -1;
4501 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
4503 return a;
4506 /* Collapse loads and return true if something changed. */
4507 static bool
4508 collapse_loads (modref_summary *cur_summary,
4509 modref_summary_lto *cur_summary_lto)
4511 bool changed = false;
4513 if (cur_summary && !cur_summary->loads->every_base)
4515 cur_summary->loads->collapse ();
4516 changed = true;
4518 if (cur_summary_lto
4519 && !cur_summary_lto->loads->every_base)
4521 cur_summary_lto->loads->collapse ();
4522 changed = true;
4524 return changed;
4527 /* Collapse loads and return true if something changed. */
4529 static bool
4530 collapse_stores (modref_summary *cur_summary,
4531 modref_summary_lto *cur_summary_lto)
4533 bool changed = false;
4535 if (cur_summary && !cur_summary->stores->every_base)
4537 cur_summary->stores->collapse ();
4538 changed = true;
4540 if (cur_summary_lto
4541 && !cur_summary_lto->stores->every_base)
4543 cur_summary_lto->stores->collapse ();
4544 changed = true;
4546 return changed;
4549 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
4550 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
4552 static bool
4553 propagate_unknown_call (cgraph_node *node,
4554 cgraph_edge *e, int ecf_flags,
4555 modref_summary *cur_summary,
4556 modref_summary_lto *cur_summary_lto,
4557 bool nontrivial_scc)
4559 bool changed = false;
4560 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
4561 auto_vec <modref_parm_map, 32> parm_map;
4562 bool looping;
4564 if (e->callee
4565 && builtin_safe_for_const_function_p (&looping, e->callee->decl))
4567 if (looping && cur_summary && !cur_summary->side_effects)
4569 cur_summary->side_effects = true;
4570 changed = true;
4572 if (looping && cur_summary_lto && !cur_summary_lto->side_effects)
4574 cur_summary_lto->side_effects = true;
4575 changed = true;
4577 return changed;
4580 if (!(ecf_flags & (ECF_CONST | ECF_PURE))
4581 || (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
4582 || nontrivial_scc)
4584 if (cur_summary && !cur_summary->side_effects)
4586 cur_summary->side_effects = true;
4587 changed = true;
4589 if (cur_summary_lto && !cur_summary_lto->side_effects)
4591 cur_summary_lto->side_effects = true;
4592 changed = true;
4594 if (cur_summary && !cur_summary->nondeterministic
4595 && !ignore_nondeterminism_p (node->decl, ecf_flags))
4597 cur_summary->nondeterministic = true;
4598 changed = true;
4600 if (cur_summary_lto && !cur_summary_lto->nondeterministic
4601 && !ignore_nondeterminism_p (node->decl, ecf_flags))
4603 cur_summary_lto->nondeterministic = true;
4604 changed = true;
4607 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
4608 return changed;
4610 if (fnspec_sum
4611 && compute_parm_map (e, &parm_map))
4613 attr_fnspec fnspec (fnspec_sum->fnspec);
4615 gcc_checking_assert (fnspec.known_p ());
4616 if (fnspec.global_memory_read_p ())
4617 collapse_loads (cur_summary, cur_summary_lto);
4618 else
4620 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4621 for (unsigned i = 0; i < parm_map.length () && t;
4622 i++, t = TREE_CHAIN (t))
4623 if (!POINTER_TYPE_P (TREE_VALUE (t)))
4625 else if (!fnspec.arg_specified_p (i)
4626 || fnspec.arg_maybe_read_p (i))
4628 modref_parm_map map = parm_map[i];
4629 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4630 continue;
4631 if (map.parm_index == MODREF_UNKNOWN_PARM)
4633 collapse_loads (cur_summary, cur_summary_lto);
4634 break;
4636 if (cur_summary)
4637 changed |= cur_summary->loads->insert
4638 (node->decl, 0, 0,
4639 get_access_for_fnspec (e, fnspec, i, map), false);
4640 if (cur_summary_lto)
4641 changed |= cur_summary_lto->loads->insert
4642 (node->decl, 0, 0,
4643 get_access_for_fnspec (e, fnspec, i, map), false);
4646 if (ignore_stores_p (node->decl, ecf_flags))
4648 else if (fnspec.global_memory_written_p ())
4649 collapse_stores (cur_summary, cur_summary_lto);
4650 else
4652 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4653 for (unsigned i = 0; i < parm_map.length () && t;
4654 i++, t = TREE_CHAIN (t))
4655 if (!POINTER_TYPE_P (TREE_VALUE (t)))
4657 else if (!fnspec.arg_specified_p (i)
4658 || fnspec.arg_maybe_written_p (i))
4660 modref_parm_map map = parm_map[i];
4661 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4662 continue;
4663 if (map.parm_index == MODREF_UNKNOWN_PARM)
4665 collapse_stores (cur_summary, cur_summary_lto);
4666 break;
4668 if (cur_summary)
4669 changed |= cur_summary->stores->insert
4670 (node->decl, 0, 0,
4671 get_access_for_fnspec (e, fnspec, i, map), false);
4672 if (cur_summary_lto)
4673 changed |= cur_summary_lto->stores->insert
4674 (node->decl, 0, 0,
4675 get_access_for_fnspec (e, fnspec, i, map), false);
4678 if (fnspec.errno_maybe_written_p () && flag_errno_math)
4680 if (cur_summary && !cur_summary->writes_errno)
4682 cur_summary->writes_errno = true;
4683 changed = true;
4685 if (cur_summary_lto && !cur_summary_lto->writes_errno)
4687 cur_summary_lto->writes_errno = true;
4688 changed = true;
4691 return changed;
4693 if (dump_file)
4694 fprintf (dump_file, " collapsing loads\n");
4695 changed |= collapse_loads (cur_summary, cur_summary_lto);
4696 if (!ignore_stores_p (node->decl, ecf_flags))
4698 if (dump_file)
4699 fprintf (dump_file, " collapsing stores\n");
4700 changed |= collapse_stores (cur_summary, cur_summary_lto);
4702 return changed;
4705 /* Maybe remove summaries of NODE pointed to by CUR_SUMMARY_PTR
4706 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
4708 static void
4709 remove_useless_summaries (cgraph_node *node,
4710 modref_summary **cur_summary_ptr,
4711 modref_summary_lto **cur_summary_lto_ptr,
4712 int ecf_flags)
4714 if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
4716 optimization_summaries->remove (node);
4717 *cur_summary_ptr = NULL;
4719 if (*cur_summary_lto_ptr
4720 && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
4722 summaries_lto->remove (node);
4723 *cur_summary_lto_ptr = NULL;
4727 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4728 and propagate loads/stores. */
4730 static bool
4731 modref_propagate_in_scc (cgraph_node *component_node)
4733 bool changed = true;
4734 bool first = true;
4735 int iteration = 0;
4737 while (changed)
4739 bool nontrivial_scc
4740 = ((struct ipa_dfs_info *) component_node->aux)->next_cycle;
4741 changed = false;
4742 for (struct cgraph_node *cur = component_node; cur;
4743 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4745 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
4746 modref_summary *cur_summary = optimization_summaries
4747 ? optimization_summaries->get (node)
4748 : NULL;
4749 modref_summary_lto *cur_summary_lto = summaries_lto
4750 ? summaries_lto->get (node)
4751 : NULL;
4753 if (!cur_summary && !cur_summary_lto)
4754 continue;
4756 int cur_ecf_flags = flags_from_decl_or_type (node->decl);
4758 if (dump_file)
4759 fprintf (dump_file, " Processing %s%s%s\n",
4760 cur->dump_name (),
4761 TREE_READONLY (cur->decl) ? " (const)" : "",
4762 DECL_PURE_P (cur->decl) ? " (pure)" : "");
4764 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
4766 if (dump_file)
4767 fprintf (dump_file, " Indirect call\n");
4768 if (propagate_unknown_call
4769 (node, e, e->indirect_info->ecf_flags,
4770 cur_summary, cur_summary_lto,
4771 nontrivial_scc))
4773 changed = true;
4774 remove_useless_summaries (node, &cur_summary,
4775 &cur_summary_lto,
4776 cur_ecf_flags);
4777 if (!cur_summary && !cur_summary_lto)
4778 break;
4782 if (!cur_summary && !cur_summary_lto)
4783 continue;
4785 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
4786 callee_edge = callee_edge->next_callee)
4788 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
4789 modref_summary *callee_summary = NULL;
4790 modref_summary_lto *callee_summary_lto = NULL;
4791 struct cgraph_node *callee;
4793 if (!callee_edge->inline_failed
4794 || ((flags & ECF_CONST)
4795 && !(flags & ECF_LOOPING_CONST_OR_PURE)))
4796 continue;
4798 /* Get the callee and its summary. */
4799 enum availability avail;
4800 callee = callee_edge->callee->ultimate_alias_target
4801 (&avail, cur);
4803 /* It is not necessary to re-process calls outside of the
4804 SCC component. */
4805 if (iteration > 0
4806 && (!callee->aux
4807 || ((struct ipa_dfs_info *)cur->aux)->scc_no
4808 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
4809 continue;
4811 if (dump_file)
4812 fprintf (dump_file, " Call to %s\n",
4813 callee_edge->callee->dump_name ());
4815 bool ignore_stores = ignore_stores_p (cur->decl, flags);
4817 if (avail <= AVAIL_INTERPOSABLE)
4819 if (dump_file)
4820 fprintf (dump_file, " Call target interposable"
4821 " or not available\n");
4822 changed |= propagate_unknown_call
4823 (node, callee_edge, flags,
4824 cur_summary, cur_summary_lto,
4825 nontrivial_scc);
4826 if (!cur_summary && !cur_summary_lto)
4827 break;
4828 continue;
4831 /* We don't know anything about CALLEE, hence we cannot tell
4832 anything about the entire component. */
4834 if (cur_summary
4835 && !(callee_summary = optimization_summaries->get (callee)))
4837 if (dump_file)
4838 fprintf (dump_file, " No call target summary\n");
4839 changed |= propagate_unknown_call
4840 (node, callee_edge, flags,
4841 cur_summary, NULL,
4842 nontrivial_scc);
4844 if (cur_summary_lto
4845 && !(callee_summary_lto = summaries_lto->get (callee)))
4847 if (dump_file)
4848 fprintf (dump_file, " No call target summary\n");
4849 changed |= propagate_unknown_call
4850 (node, callee_edge, flags,
4851 NULL, cur_summary_lto,
4852 nontrivial_scc);
4855 if (callee_summary && !cur_summary->side_effects
4856 && (callee_summary->side_effects
4857 || callee_edge->recursive_p ()))
4859 cur_summary->side_effects = true;
4860 changed = true;
4862 if (callee_summary_lto && !cur_summary_lto->side_effects
4863 && (callee_summary_lto->side_effects
4864 || callee_edge->recursive_p ()))
4866 cur_summary_lto->side_effects = true;
4867 changed = true;
4869 if (callee_summary && !cur_summary->nondeterministic
4870 && callee_summary->nondeterministic
4871 && !ignore_nondeterminism_p (cur->decl, flags))
4873 cur_summary->nondeterministic = true;
4874 changed = true;
4876 if (callee_summary_lto && !cur_summary_lto->nondeterministic
4877 && callee_summary_lto->nondeterministic
4878 && !ignore_nondeterminism_p (cur->decl, flags))
4880 cur_summary_lto->nondeterministic = true;
4881 changed = true;
4883 if (flags & (ECF_CONST | ECF_NOVOPS))
4884 continue;
4886 /* We can not safely optimize based on summary of callee if it
4887 does not always bind to current def: it is possible that
4888 memory load was optimized out earlier which may not happen in
4889 the interposed variant. */
4890 if (!callee_edge->binds_to_current_def_p ())
4892 if (cur_summary && !cur_summary->calls_interposable)
4894 cur_summary->calls_interposable = true;
4895 changed = true;
4897 if (cur_summary_lto && !cur_summary_lto->calls_interposable)
4899 cur_summary_lto->calls_interposable = true;
4900 changed = true;
4902 if (dump_file)
4903 fprintf (dump_file, " May not bind local;"
4904 " collapsing loads\n");
4908 auto_vec <modref_parm_map, 32> parm_map;
4909 modref_parm_map chain_map;
4910 /* TODO: Once we get jump functions for static chains we could
4911 compute this. */
4912 chain_map.parm_index = MODREF_UNKNOWN_PARM;
4914 compute_parm_map (callee_edge, &parm_map);
4916 /* Merge in callee's information. */
4917 if (callee_summary)
4919 changed |= cur_summary->loads->merge
4920 (node->decl, callee_summary->loads,
4921 &parm_map, &chain_map, !first);
4922 if (!ignore_stores)
4924 changed |= cur_summary->stores->merge
4925 (node->decl, callee_summary->stores,
4926 &parm_map, &chain_map, !first);
4927 if (!cur_summary->writes_errno
4928 && callee_summary->writes_errno)
4930 cur_summary->writes_errno = true;
4931 changed = true;
4935 if (callee_summary_lto)
4937 changed |= cur_summary_lto->loads->merge
4938 (node->decl, callee_summary_lto->loads,
4939 &parm_map, &chain_map, !first);
4940 if (!ignore_stores)
4942 changed |= cur_summary_lto->stores->merge
4943 (node->decl, callee_summary_lto->stores,
4944 &parm_map, &chain_map, !first);
4945 if (!cur_summary_lto->writes_errno
4946 && callee_summary_lto->writes_errno)
4948 cur_summary_lto->writes_errno = true;
4949 changed = true;
4953 if (changed)
4954 remove_useless_summaries (node, &cur_summary,
4955 &cur_summary_lto,
4956 cur_ecf_flags);
4957 if (!cur_summary && !cur_summary_lto)
4958 break;
4959 if (dump_file && changed)
4961 if (cur_summary)
4962 cur_summary->dump (dump_file);
4963 if (cur_summary_lto)
4964 cur_summary_lto->dump (dump_file);
4965 dump_modref_edge_summaries (dump_file, node, 4);
4969 iteration++;
4970 first = false;
4972 if (dump_file)
4973 fprintf (dump_file,
4974 "Propagation finished in %i iterations\n", iteration);
4975 bool pureconst = false;
4976 for (struct cgraph_node *cur = component_node; cur;
4977 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4978 if (!cur->inlined_to && opt_for_fn (cur->decl, flag_ipa_pure_const))
4980 modref_summary *summary = optimization_summaries
4981 ? optimization_summaries->get (cur)
4982 : NULL;
4983 modref_summary_lto *summary_lto = summaries_lto
4984 ? summaries_lto->get (cur)
4985 : NULL;
4986 if (summary && !summary->stores->every_base && !summary->stores->bases
4987 && !summary->nondeterministic)
4989 if (!summary->loads->every_base && !summary->loads->bases
4990 && !summary->calls_interposable)
4991 pureconst |= ipa_make_function_const
4992 (cur, summary->side_effects, false);
4993 else
4994 pureconst |= ipa_make_function_pure
4995 (cur, summary->side_effects, false);
4997 if (summary_lto && !summary_lto->stores->every_base
4998 && !summary_lto->stores->bases && !summary_lto->nondeterministic)
5000 if (!summary_lto->loads->every_base && !summary_lto->loads->bases
5001 && !summary_lto->calls_interposable)
5002 pureconst |= ipa_make_function_const
5003 (cur, summary_lto->side_effects, false);
5004 else
5005 pureconst |= ipa_make_function_pure
5006 (cur, summary_lto->side_effects, false);
5009 return pureconst;
5012 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
5014 static void
5015 modref_propagate_dump_scc (cgraph_node *component_node)
5017 for (struct cgraph_node *cur = component_node; cur;
5018 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5019 if (!cur->inlined_to)
5021 modref_summary *cur_summary = optimization_summaries
5022 ? optimization_summaries->get (cur)
5023 : NULL;
5024 modref_summary_lto *cur_summary_lto = summaries_lto
5025 ? summaries_lto->get (cur)
5026 : NULL;
5028 fprintf (dump_file, "Propagated modref for %s%s%s\n",
5029 cur->dump_name (),
5030 TREE_READONLY (cur->decl) ? " (const)" : "",
5031 DECL_PURE_P (cur->decl) ? " (pure)" : "");
5032 if (optimization_summaries)
5034 if (cur_summary)
5035 cur_summary->dump (dump_file);
5036 else
5037 fprintf (dump_file, " Not tracked\n");
5039 if (summaries_lto)
5041 if (cur_summary_lto)
5042 cur_summary_lto->dump (dump_file);
5043 else
5044 fprintf (dump_file, " Not tracked (lto)\n");
5049 /* Determine EAF flags know for call E with CALLEE_ECF_FLAGS and ARG. */
5052 implicit_eaf_flags_for_edge_and_arg (cgraph_edge *e, int callee_ecf_flags,
5053 bool ignore_stores, int arg)
5055 /* Returning the value is already accounted to at local propagation. */
5056 int implicit_flags = EAF_NOT_RETURNED_DIRECTLY
5057 | EAF_NOT_RETURNED_INDIRECTLY;
5058 if (ignore_stores)
5059 implicit_flags |= ignore_stores_eaf_flags;
5060 if (callee_ecf_flags & ECF_PURE)
5061 implicit_flags |= implicit_pure_eaf_flags;
5062 if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
5063 implicit_flags |= implicit_const_eaf_flags;
5064 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
5065 if (fnspec_sum)
5067 attr_fnspec fnspec (fnspec_sum->fnspec);
5068 implicit_flags |= fnspec.arg_eaf_flags (arg);
5070 return implicit_flags;
5073 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
5074 and SUMMARY_LTO to CUR_SUMMARY_LTO.
5075 Return true if something changed. */
5077 static bool
5078 modref_merge_call_site_flags (escape_summary *sum,
5079 modref_summary *cur_summary,
5080 modref_summary_lto *cur_summary_lto,
5081 modref_summary *summary,
5082 modref_summary_lto *summary_lto,
5083 tree caller,
5084 cgraph_edge *e,
5085 int caller_ecf_flags,
5086 int callee_ecf_flags,
5087 bool binds_to_current_def)
5089 escape_entry *ee;
5090 unsigned int i;
5091 bool changed = false;
5092 bool ignore_stores = ignore_stores_p (caller, callee_ecf_flags);
5094 /* Return early if we have no useful info to propagate. */
5095 if ((!cur_summary
5096 || (!cur_summary->arg_flags.length ()
5097 && !cur_summary->static_chain_flags
5098 && !cur_summary->retslot_flags))
5099 && (!cur_summary_lto
5100 || (!cur_summary_lto->arg_flags.length ()
5101 && !cur_summary_lto->static_chain_flags
5102 && !cur_summary_lto->retslot_flags)))
5103 return false;
5105 FOR_EACH_VEC_ELT (sum->esc, i, ee)
5107 int flags = 0;
5108 int flags_lto = 0;
5109 int implicit_flags = implicit_eaf_flags_for_edge_and_arg
5110 (e, callee_ecf_flags, ignore_stores, ee->arg);
5112 if (summary && ee->arg < summary->arg_flags.length ())
5113 flags = summary->arg_flags[ee->arg];
5114 if (summary_lto
5115 && ee->arg < summary_lto->arg_flags.length ())
5116 flags_lto = summary_lto->arg_flags[ee->arg];
5117 if (!ee->direct)
5119 flags = deref_flags (flags, ignore_stores);
5120 flags_lto = deref_flags (flags_lto, ignore_stores);
5122 if (ignore_stores)
5123 implicit_flags |= ignore_stores_eaf_flags;
5124 if (callee_ecf_flags & ECF_PURE)
5125 implicit_flags |= implicit_pure_eaf_flags;
5126 if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
5127 implicit_flags |= implicit_const_eaf_flags;
5128 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
5129 if (fnspec_sum)
5131 attr_fnspec fnspec (fnspec_sum->fnspec);
5132 implicit_flags |= fnspec.arg_eaf_flags (ee->arg);
5134 if (!ee->direct)
5135 implicit_flags = deref_flags (implicit_flags, ignore_stores);
5136 flags |= implicit_flags;
5137 flags_lto |= implicit_flags;
5138 if (!binds_to_current_def && (flags || flags_lto))
5140 flags = interposable_eaf_flags (flags, implicit_flags);
5141 flags_lto = interposable_eaf_flags (flags_lto, implicit_flags);
5143 if (!(flags & EAF_UNUSED)
5144 && cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ())
5146 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5147 ? cur_summary->retslot_flags
5148 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5149 ? cur_summary->static_chain_flags
5150 : cur_summary->arg_flags[ee->parm_index];
5151 if ((f & flags) != f)
5153 f = remove_useless_eaf_flags
5154 (f & flags, caller_ecf_flags,
5155 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
5156 changed = true;
5159 if (!(flags_lto & EAF_UNUSED)
5160 && cur_summary_lto
5161 && ee->parm_index < (int)cur_summary_lto->arg_flags.length ())
5163 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5164 ? cur_summary_lto->retslot_flags
5165 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5166 ? cur_summary_lto->static_chain_flags
5167 : cur_summary_lto->arg_flags[ee->parm_index];
5168 if ((f & flags_lto) != f)
5170 f = remove_useless_eaf_flags
5171 (f & flags_lto, caller_ecf_flags,
5172 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
5173 changed = true;
5177 return changed;
5180 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
5181 and propagate arg flags. */
5183 static void
5184 modref_propagate_flags_in_scc (cgraph_node *component_node)
5186 bool changed = true;
5187 int iteration = 0;
5189 while (changed)
5191 changed = false;
5192 for (struct cgraph_node *cur = component_node; cur;
5193 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5195 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
5196 modref_summary *cur_summary = optimization_summaries
5197 ? optimization_summaries->get (node)
5198 : NULL;
5199 modref_summary_lto *cur_summary_lto = summaries_lto
5200 ? summaries_lto->get (node)
5201 : NULL;
5203 if (!cur_summary && !cur_summary_lto)
5204 continue;
5205 int caller_ecf_flags = flags_from_decl_or_type (cur->decl);
5207 if (dump_file)
5208 fprintf (dump_file, " Processing %s%s%s\n",
5209 cur->dump_name (),
5210 TREE_READONLY (cur->decl) ? " (const)" : "",
5211 DECL_PURE_P (cur->decl) ? " (pure)" : "");
5213 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
5215 escape_summary *sum = escape_summaries->get (e);
5217 if (!sum || ((e->indirect_info->ecf_flags & ECF_CONST)
5218 && !(e->indirect_info->ecf_flags & ECF_LOOPING_CONST_OR_PURE)))
5219 continue;
5221 changed |= modref_merge_call_site_flags
5222 (sum, cur_summary, cur_summary_lto,
5223 NULL, NULL,
5224 node->decl,
5226 caller_ecf_flags,
5227 e->indirect_info->ecf_flags,
5228 false);
5231 if (!cur_summary && !cur_summary_lto)
5232 continue;
5234 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
5235 callee_edge = callee_edge->next_callee)
5237 int ecf_flags = flags_from_decl_or_type
5238 (callee_edge->callee->decl);
5239 modref_summary *callee_summary = NULL;
5240 modref_summary_lto *callee_summary_lto = NULL;
5241 struct cgraph_node *callee;
5243 if ((ecf_flags & ECF_CONST)
5244 && !(ecf_flags & ECF_LOOPING_CONST_OR_PURE))
5245 continue;
5247 /* Get the callee and its summary. */
5248 enum availability avail;
5249 callee = callee_edge->callee->ultimate_alias_target
5250 (&avail, cur);
5252 /* It is not necessary to re-process calls outside of the
5253 SCC component. */
5254 if (iteration > 0
5255 && (!callee->aux
5256 || ((struct ipa_dfs_info *)cur->aux)->scc_no
5257 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
5258 continue;
5260 escape_summary *sum = escape_summaries->get (callee_edge);
5261 if (!sum)
5262 continue;
5264 if (dump_file)
5265 fprintf (dump_file, " Call to %s\n",
5266 callee_edge->callee->dump_name ());
5268 if (avail <= AVAIL_INTERPOSABLE
5269 || callee_edge->call_stmt_cannot_inline_p)
5271 else
5273 if (cur_summary)
5274 callee_summary = optimization_summaries->get (callee);
5275 if (cur_summary_lto)
5276 callee_summary_lto = summaries_lto->get (callee);
5278 changed |= modref_merge_call_site_flags
5279 (sum, cur_summary, cur_summary_lto,
5280 callee_summary, callee_summary_lto,
5281 node->decl,
5282 callee_edge,
5283 caller_ecf_flags,
5284 ecf_flags,
5285 callee->binds_to_current_def_p ());
5286 if (dump_file && changed)
5288 if (cur_summary)
5289 cur_summary->dump (dump_file);
5290 if (cur_summary_lto)
5291 cur_summary_lto->dump (dump_file);
5295 iteration++;
5297 if (dump_file)
5298 fprintf (dump_file,
5299 "Propagation of flags finished in %i iterations\n", iteration);
5302 } /* ANON namespace. */
5304 /* Call EDGE was inlined; merge summary from callee to the caller. */
5306 void
5307 ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
5309 if (!summaries && !summaries_lto)
5310 return;
5312 struct cgraph_node *to = (edge->caller->inlined_to
5313 ? edge->caller->inlined_to : edge->caller);
5314 class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
5315 class modref_summary_lto *to_info_lto = summaries_lto
5316 ? summaries_lto->get (to) : NULL;
5318 if (!to_info && !to_info_lto)
5320 if (summaries)
5321 summaries->remove (edge->callee);
5322 if (summaries_lto)
5323 summaries_lto->remove (edge->callee);
5324 remove_modref_edge_summaries (edge->callee);
5325 return;
5328 class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
5329 : NULL;
5330 class modref_summary_lto *callee_info_lto
5331 = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
5332 int flags = flags_from_decl_or_type (edge->callee->decl);
5333 /* Combine in outer flags. */
5334 cgraph_node *n;
5335 for (n = edge->caller; n->inlined_to; n = n->callers->caller)
5336 flags |= flags_from_decl_or_type (n->decl);
5337 flags |= flags_from_decl_or_type (n->decl);
5338 bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
5340 if (!callee_info && to_info)
5342 if (!(flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
5343 to_info->loads->collapse ();
5344 if (!ignore_stores)
5345 to_info->stores->collapse ();
5347 if (!callee_info_lto && to_info_lto)
5349 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5350 to_info_lto->loads->collapse ();
5351 if (!ignore_stores)
5352 to_info_lto->stores->collapse ();
5354 /* Merge side effects and non-determinism.
5355 PURE/CONST flags makes functions deterministic and if there is
5356 no LOOPING_CONST_OR_PURE they also have no side effects. */
5357 if (!(flags & (ECF_CONST | ECF_PURE))
5358 || (flags & ECF_LOOPING_CONST_OR_PURE))
5360 if (to_info)
5362 if (!callee_info || callee_info->side_effects)
5363 to_info->side_effects = true;
5364 if ((!callee_info || callee_info->nondeterministic)
5365 && !ignore_nondeterminism_p (edge->caller->decl, flags))
5366 to_info->nondeterministic = true;
5368 if (to_info_lto)
5370 if (!callee_info_lto || callee_info_lto->side_effects)
5371 to_info_lto->side_effects = true;
5372 if ((!callee_info_lto || callee_info_lto->nondeterministic)
5373 && !ignore_nondeterminism_p (edge->caller->decl, flags))
5374 to_info_lto->nondeterministic = true;
5377 if (callee_info || callee_info_lto)
5379 auto_vec <modref_parm_map, 32> parm_map;
5380 modref_parm_map chain_map;
5381 /* TODO: Once we get jump functions for static chains we could
5382 compute parm_index. */
5384 compute_parm_map (edge, &parm_map);
5386 if (!ignore_stores)
5388 if (to_info && callee_info)
5389 to_info->stores->merge (to->decl, callee_info->stores, &parm_map,
5390 &chain_map, false);
5391 if (to_info_lto && callee_info_lto)
5392 to_info_lto->stores->merge (to->decl, callee_info_lto->stores,
5393 &parm_map, &chain_map, false);
5395 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5397 if (to_info && callee_info)
5398 to_info->loads->merge (to->decl, callee_info->loads, &parm_map,
5399 &chain_map, false);
5400 if (to_info_lto && callee_info_lto)
5401 to_info_lto->loads->merge (to->decl, callee_info_lto->loads,
5402 &parm_map, &chain_map, false);
5406 /* Now merge escape summaries.
5407 For every escape to the callee we need to merge callee flags
5408 and remap callee's escapes. */
5409 class escape_summary *sum = escape_summaries->get (edge);
5410 int max_escape = -1;
5411 escape_entry *ee;
5412 unsigned int i;
5414 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
5415 FOR_EACH_VEC_ELT (sum->esc, i, ee)
5416 if ((int)ee->arg > max_escape)
5417 max_escape = ee->arg;
5419 auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
5420 emap.safe_grow (max_escape + 1, true);
5421 for (i = 0; (int)i < max_escape + 1; i++)
5422 emap[i] = vNULL;
5424 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
5425 FOR_EACH_VEC_ELT (sum->esc, i, ee)
5427 bool needed = false;
5428 int implicit_flags = implicit_eaf_flags_for_edge_and_arg
5429 (edge, flags, ignore_stores,
5430 ee->arg);
5431 if (!ee->direct)
5432 implicit_flags = deref_flags (implicit_flags, ignore_stores);
5433 if (to_info && (int)to_info->arg_flags.length () > ee->parm_index)
5435 int flags = callee_info
5436 && callee_info->arg_flags.length () > ee->arg
5437 ? callee_info->arg_flags[ee->arg] : 0;
5438 if (!ee->direct)
5439 flags = deref_flags (flags, ignore_stores);
5440 flags |= ee->min_flags | implicit_flags;
5441 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5442 ? to_info->retslot_flags
5443 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5444 ? to_info->static_chain_flags
5445 : to_info->arg_flags[ee->parm_index];
5446 f &= flags;
5447 if (f)
5448 needed = true;
5450 if (to_info_lto
5451 && (int)to_info_lto->arg_flags.length () > ee->parm_index)
5453 int flags = callee_info_lto
5454 && callee_info_lto->arg_flags.length () > ee->arg
5455 ? callee_info_lto->arg_flags[ee->arg] : 0;
5456 if (!ee->direct)
5457 flags = deref_flags (flags, ignore_stores);
5458 flags |= ee->min_flags | implicit_flags;
5459 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5460 ? to_info_lto->retslot_flags
5461 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5462 ? to_info_lto->static_chain_flags
5463 : to_info_lto->arg_flags[ee->parm_index];
5464 f &= flags;
5465 if (f)
5466 needed = true;
5468 struct escape_map entry = {ee->parm_index, ee->direct};
5469 if (needed)
5470 emap[ee->arg].safe_push (entry);
5472 update_escape_summary (edge->callee, emap, ignore_stores);
5473 for (i = 0; (int)i < max_escape + 1; i++)
5474 emap[i].release ();
5475 if (sum)
5476 escape_summaries->remove (edge);
5478 if (summaries)
5480 if (to_info && !to_info->useful_p (flags))
5482 if (dump_file)
5483 fprintf (dump_file, "Removed mod-ref summary for %s\n",
5484 to->dump_name ());
5485 summaries->remove (to);
5486 to_info = NULL;
5488 else if (to_info && dump_file)
5490 if (dump_file)
5491 fprintf (dump_file, "Updated mod-ref summary for %s\n",
5492 to->dump_name ());
5493 to_info->dump (dump_file);
5495 if (callee_info)
5496 summaries->remove (edge->callee);
5498 if (summaries_lto)
5500 if (to_info_lto && !to_info_lto->useful_p (flags))
5502 if (dump_file)
5503 fprintf (dump_file, "Removed mod-ref summary for %s\n",
5504 to->dump_name ());
5505 summaries_lto->remove (to);
5506 to_info_lto = NULL;
5508 else if (to_info_lto && dump_file)
5510 if (dump_file)
5511 fprintf (dump_file, "Updated mod-ref summary for %s\n",
5512 to->dump_name ());
5513 to_info_lto->dump (dump_file);
5515 if (callee_info_lto)
5516 summaries_lto->remove (edge->callee);
5518 if (!to_info && !to_info_lto)
5519 remove_modref_edge_summaries (to);
5520 return;
5523 /* Run the IPA pass. This will take a function's summaries and calls and
5524 construct new summaries which represent a transitive closure. So that
5525 summary of an analyzed function contains information about the loads and
5526 stores that the function or any function that it calls does. */
5528 unsigned int
5529 pass_ipa_modref::execute (function *)
5531 if (!summaries && !summaries_lto)
5532 return 0;
5533 bool pureconst = false;
5535 if (optimization_summaries)
5536 ggc_delete (optimization_summaries);
5537 optimization_summaries = summaries;
5538 summaries = NULL;
5540 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
5541 symtab->cgraph_count);
5542 int order_pos;
5543 order_pos = ipa_reduced_postorder (order, true, ignore_edge);
5544 int i;
5546 /* Iterate over all strongly connected components in post-order. */
5547 for (i = 0; i < order_pos; i++)
5549 /* Get the component's representative. That's just any node in the
5550 component from which we can traverse the entire component. */
5551 struct cgraph_node *component_node = order[i];
5553 if (dump_file)
5554 fprintf (dump_file, "\n\nStart of SCC component\n");
5556 pureconst |= modref_propagate_in_scc (component_node);
5557 modref_propagate_flags_in_scc (component_node);
5558 if (optimization_summaries)
5559 for (struct cgraph_node *cur = component_node; cur;
5560 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5561 if (modref_summary *sum = optimization_summaries->get (cur))
5562 sum->finalize (cur->decl);
5563 if (dump_file)
5564 modref_propagate_dump_scc (component_node);
5566 cgraph_node *node;
5567 FOR_EACH_FUNCTION (node)
5568 update_signature (node);
5569 if (summaries_lto)
5570 ((modref_summaries_lto *)summaries_lto)->propagated = true;
5571 ipa_free_postorder_info ();
5572 free (order);
5573 delete fnspec_summaries;
5574 fnspec_summaries = NULL;
5575 delete escape_summaries;
5576 escape_summaries = NULL;
5578 /* If we possibly made constructors const/pure we may need to remove
5579 them. */
5580 return pureconst ? TODO_remove_functions : 0;
5583 /* Summaries must stay alive until end of compilation. */
5585 void
5586 ipa_modref_cc_finalize ()
5588 if (optimization_summaries)
5589 ggc_delete (optimization_summaries);
5590 optimization_summaries = NULL;
5591 if (summaries_lto)
5592 ggc_delete (summaries_lto);
5593 summaries_lto = NULL;
5594 if (fnspec_summaries)
5595 delete fnspec_summaries;
5596 fnspec_summaries = NULL;
5597 if (escape_summaries)
5598 delete escape_summaries;
5599 escape_summaries = NULL;
5602 #include "gt-ipa-modref.h"