Daily bump.
[official-gcc.git] / gcc / ipa-modref.c
blob72006251f29fb6b1818332c0e26723f6fffe9bcc
1 /* Search for references that a functions loads or stores.
2 Copyright (C) 2020-2021 Free Software Foundation, Inc.
3 Contributed by David Cepelik and Jan Hubicka
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 /* Mod/ref pass records summary about loads and stores performed by the
22 function. This is later used by alias analysis to disambiguate memory
23 accesses across function calls.
25 This file contains a tree pass and an IPA pass. Both performs the same
26 analysis however tree pass is executed during early and late optimization
27 passes to propagate info downwards in the compilation order. IPA pass
28 propagates across the callgraph and is able to handle recursion and works on
29 whole program during link-time analysis.
31 LTO mode differs from the local mode by not recording alias sets but types
32 that are translated to alias sets later. This is necessary in order stream
33 the information because the alias sets are rebuild at stream-in time and may
34 not correspond to ones seen during analysis. For this reason part of
35 analysis is duplicated.
37 The following information is computed
38 1) load/store access tree described in ipa-modref-tree.h
39 This is used by tree-ssa-alias to disambiguate load/stores
40 2) EAF flags used by points-to analysis (in tree-ssa-structlias).
41 and defined in tree-core.h.
42 and stored to optimization_summaries.
44 There are multiple summaries computed and used during the propagation:
45 - summaries holds summaries from analysis to IPA propagation
46 time.
47 - summaries_lto is same as summaries but holds them in a format
48 that can be streamed (as described above).
49 - fnspec_summary holds fnspec strings for call. This is
50 necessary because gimple_call_fnspec performs additional
51 analysis except for looking callee fndecl.
52 - escape_summary holds escape points for given call edge.
53 That is a vector recording what function parmaeters
54 may escape to a function call (and with what parameter index). */
56 #include "config.h"
57 #include "system.h"
58 #include "coretypes.h"
59 #include "backend.h"
60 #include "tree.h"
61 #include "gimple.h"
62 #include "alloc-pool.h"
63 #include "tree-pass.h"
64 #include "gimple-iterator.h"
65 #include "tree-dfa.h"
66 #include "cgraph.h"
67 #include "ipa-utils.h"
68 #include "symbol-summary.h"
69 #include "gimple-pretty-print.h"
70 #include "gimple-walk.h"
71 #include "print-tree.h"
72 #include "tree-streamer.h"
73 #include "alias.h"
74 #include "calls.h"
75 #include "ipa-modref-tree.h"
76 #include "ipa-modref.h"
77 #include "value-range.h"
78 #include "ipa-prop.h"
79 #include "ipa-fnsummary.h"
80 #include "attr-fnspec.h"
81 #include "symtab-clones.h"
82 #include "gimple-ssa.h"
83 #include "tree-phinodes.h"
84 #include "tree-ssa-operands.h"
85 #include "ssa-iterators.h"
86 #include "stringpool.h"
87 #include "tree-ssanames.h"
88 #include "attribs.h"
89 #include "tree-cfg.h"
90 #include "tree-eh.h"
93 namespace {
95 /* We record fnspec specifiers for call edges since they depends on actual
96 gimple statements. */
98 class fnspec_summary
100 public:
101 char *fnspec;
103 fnspec_summary ()
104 : fnspec (NULL)
108 ~fnspec_summary ()
110 free (fnspec);
114 /* Summary holding fnspec string for a given call. */
116 class fnspec_summaries_t : public call_summary <fnspec_summary *>
118 public:
119 fnspec_summaries_t (symbol_table *symtab)
120 : call_summary <fnspec_summary *> (symtab) {}
121 /* Hook that is called by summary when an edge is duplicated. */
122 virtual void duplicate (cgraph_edge *,
123 cgraph_edge *,
124 fnspec_summary *src,
125 fnspec_summary *dst)
127 dst->fnspec = xstrdup (src->fnspec);
131 static fnspec_summaries_t *fnspec_summaries = NULL;
133 /* Escape summary holds a vector of param indexes that escape to
134 a given call. */
135 struct escape_entry
137 /* Parameter that escapes at a given call. */
138 int parm_index;
139 /* Argument it escapes to. */
140 unsigned int arg;
141 /* Minimal flags known about the argument. */
142 eaf_flags_t min_flags;
143 /* Does it escape directly or indirectly? */
144 bool direct;
147 /* Dump EAF flags. */
149 static void
150 dump_eaf_flags (FILE *out, int flags, bool newline = true)
152 if (flags & EAF_UNUSED)
153 fprintf (out, " unused");
154 if (flags & EAF_NO_DIRECT_CLOBBER)
155 fprintf (out, " no_direct_clobber");
156 if (flags & EAF_NO_INDIRECT_CLOBBER)
157 fprintf (out, " no_indirect_clobber");
158 if (flags & EAF_NO_DIRECT_ESCAPE)
159 fprintf (out, " no_direct_escape");
160 if (flags & EAF_NO_INDIRECT_ESCAPE)
161 fprintf (out, " no_indirect_escape");
162 if (flags & EAF_NOT_RETURNED_DIRECTLY)
163 fprintf (out, " not_returned_directly");
164 if (flags & EAF_NOT_RETURNED_INDIRECTLY)
165 fprintf (out, " not_returned_indirectly");
166 if (flags & EAF_NO_DIRECT_READ)
167 fprintf (out, " no_direct_read");
168 if (flags & EAF_NO_INDIRECT_READ)
169 fprintf (out, " no_indirect_read");
170 if (newline)
171 fprintf (out, "\n");
174 struct escape_summary
176 auto_vec <escape_entry> esc;
177 void dump (FILE *out)
179 for (unsigned int i = 0; i < esc.length (); i++)
181 fprintf (out, " parm %i arg %i %s min:",
182 esc[i].parm_index,
183 esc[i].arg,
184 esc[i].direct ? "(direct)" : "(indirect)");
185 dump_eaf_flags (out, esc[i].min_flags, false);
187 fprintf (out, "\n");
191 class escape_summaries_t : public call_summary <escape_summary *>
193 public:
194 escape_summaries_t (symbol_table *symtab)
195 : call_summary <escape_summary *> (symtab) {}
196 /* Hook that is called by summary when an edge is duplicated. */
197 virtual void duplicate (cgraph_edge *,
198 cgraph_edge *,
199 escape_summary *src,
200 escape_summary *dst)
202 dst->esc = src->esc.copy ();
206 static escape_summaries_t *escape_summaries = NULL;
208 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
211 /* Class (from which there is one global instance) that holds modref summaries
212 for all analyzed functions. */
214 class GTY((user)) modref_summaries
215 : public fast_function_summary <modref_summary *, va_gc>
217 public:
218 modref_summaries (symbol_table *symtab)
219 : fast_function_summary <modref_summary *, va_gc> (symtab) {}
220 virtual void insert (cgraph_node *, modref_summary *state);
221 virtual void duplicate (cgraph_node *src_node,
222 cgraph_node *dst_node,
223 modref_summary *src_data,
224 modref_summary *dst_data);
225 static modref_summaries *create_ggc (symbol_table *symtab)
227 return new (ggc_alloc_no_dtor<modref_summaries> ())
228 modref_summaries (symtab);
232 class modref_summary_lto;
234 /* Class (from which there is one global instance) that holds modref summaries
235 for all analyzed functions. */
237 class GTY((user)) modref_summaries_lto
238 : public fast_function_summary <modref_summary_lto *, va_gc>
240 public:
241 modref_summaries_lto (symbol_table *symtab)
242 : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
243 propagated (false) {}
244 virtual void insert (cgraph_node *, modref_summary_lto *state);
245 virtual void duplicate (cgraph_node *src_node,
246 cgraph_node *dst_node,
247 modref_summary_lto *src_data,
248 modref_summary_lto *dst_data);
249 static modref_summaries_lto *create_ggc (symbol_table *symtab)
251 return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
252 modref_summaries_lto (symtab);
254 bool propagated;
257 /* Global variable holding all modref summaries
258 (from analysis to IPA propagation time). */
260 static GTY(()) fast_function_summary <modref_summary *, va_gc>
261 *summaries;
263 /* Global variable holding all modref optimization summaries
264 (from IPA propagation time or used by local optimization pass). */
266 static GTY(()) fast_function_summary <modref_summary *, va_gc>
267 *optimization_summaries;
269 /* LTO summaries hold info from analysis to LTO streaming or from LTO
270 stream-in through propagation to LTO stream-out. */
272 static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
273 *summaries_lto;
275 /* Summary for a single function which this pass produces. */
277 modref_summary::modref_summary ()
278 : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
279 writes_errno (false), side_effects (false)
283 modref_summary::~modref_summary ()
285 if (loads)
286 ggc_delete (loads);
287 if (stores)
288 ggc_delete (stores);
291 /* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
292 useful to track. If returns_void is true moreover clear
293 EAF_NOT_RETURNED. */
294 static int
295 remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
297 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
298 eaf_flags &= ~implicit_const_eaf_flags;
299 else if (ecf_flags & ECF_PURE)
300 eaf_flags &= ~implicit_pure_eaf_flags;
301 else if ((ecf_flags & ECF_NORETURN) || returns_void)
302 eaf_flags &= ~(EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY);
303 return eaf_flags;
306 /* Return true if FLAGS holds some useful information. */
308 static bool
309 eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags)
311 for (unsigned i = 0; i < flags.length (); i++)
312 if (remove_useless_eaf_flags (flags[i], ecf_flags, false))
313 return true;
314 return false;
317 /* Return true if summary is potentially useful for optimization.
318 If CHECK_FLAGS is false assume that arg_flags are useful. */
320 bool
321 modref_summary::useful_p (int ecf_flags, bool check_flags)
323 if (arg_flags.length () && !check_flags)
324 return true;
325 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
326 return true;
327 arg_flags.release ();
328 if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
329 return true;
330 if (check_flags
331 && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
332 return true;
333 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
334 return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
335 if (loads && !loads->every_base)
336 return true;
337 if (ecf_flags & ECF_PURE)
338 return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
339 return stores && !stores->every_base;
342 /* Return true if global memory is read
343 (that is loads summary contains global memory access). */
344 bool
345 modref_summary::global_memory_read_p ()
347 if (!loads)
348 return true;
349 return loads->global_access_p ();
352 /* Return true if global memory is written. */
353 bool
354 modref_summary::global_memory_written_p ()
356 if (!stores)
357 return true;
358 return stores->global_access_p ();
362 /* Single function summary used for LTO. */
364 typedef modref_tree <tree> modref_records_lto;
365 struct GTY(()) modref_summary_lto
367 /* Load and stores in functions using types rather then alias sets.
369 This is necessary to make the information streamable for LTO but is also
370 more verbose and thus more likely to hit the limits. */
371 modref_records_lto *loads;
372 modref_records_lto *stores;
373 auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
374 eaf_flags_t retslot_flags;
375 eaf_flags_t static_chain_flags;
376 bool writes_errno;
377 bool side_effects;
379 modref_summary_lto ();
380 ~modref_summary_lto ();
381 void dump (FILE *);
382 bool useful_p (int ecf_flags, bool check_flags = true);
385 /* Summary for a single function which this pass produces. */
387 modref_summary_lto::modref_summary_lto ()
388 : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
389 writes_errno (false), side_effects (false)
393 modref_summary_lto::~modref_summary_lto ()
395 if (loads)
396 ggc_delete (loads);
397 if (stores)
398 ggc_delete (stores);
402 /* Return true if lto summary is potentially useful for optimization.
403 If CHECK_FLAGS is false assume that arg_flags are useful. */
405 bool
406 modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
408 if (arg_flags.length () && !check_flags)
409 return true;
410 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
411 return true;
412 arg_flags.release ();
413 if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
414 return true;
415 if (check_flags
416 && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
417 return true;
418 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
419 return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
420 if (loads && !loads->every_base)
421 return true;
422 if (ecf_flags & ECF_PURE)
423 return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
424 return stores && !stores->every_base;
427 /* Dump A to OUT. */
429 static void
430 dump_access (modref_access_node *a, FILE *out)
432 fprintf (out, " access:");
433 if (a->parm_index != MODREF_UNKNOWN_PARM)
435 if (a->parm_index >= 0)
436 fprintf (out, " Parm %i", a->parm_index);
437 else if (a->parm_index == MODREF_STATIC_CHAIN_PARM)
438 fprintf (out, " Static chain");
439 else
440 gcc_unreachable ();
441 if (a->parm_offset_known)
443 fprintf (out, " param offset:");
444 print_dec ((poly_int64_pod)a->parm_offset, out, SIGNED);
447 if (a->range_info_useful_p ())
449 fprintf (out, " offset:");
450 print_dec ((poly_int64_pod)a->offset, out, SIGNED);
451 fprintf (out, " size:");
452 print_dec ((poly_int64_pod)a->size, out, SIGNED);
453 fprintf (out, " max_size:");
454 print_dec ((poly_int64_pod)a->max_size, out, SIGNED);
455 if (a->adjustments)
456 fprintf (out, " adjusted %i times", a->adjustments);
458 fprintf (out, "\n");
461 /* Dump records TT to OUT. */
463 static void
464 dump_records (modref_records *tt, FILE *out)
466 fprintf (out, " Limits: %i bases, %i refs\n",
467 (int)tt->max_bases, (int)tt->max_refs);
468 if (tt->every_base)
470 fprintf (out, " Every base\n");
471 return;
473 size_t i;
474 modref_base_node <alias_set_type> *n;
475 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
477 fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
478 if (n->every_ref)
480 fprintf (out, " Every ref\n");
481 continue;
483 size_t j;
484 modref_ref_node <alias_set_type> *r;
485 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
487 fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
488 if (r->every_access)
490 fprintf (out, " Every access\n");
491 continue;
493 size_t k;
494 modref_access_node *a;
495 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
496 dump_access (a, out);
501 /* Dump records TT to OUT. */
503 static void
504 dump_lto_records (modref_records_lto *tt, FILE *out)
506 fprintf (out, " Limits: %i bases, %i refs\n",
507 (int)tt->max_bases, (int)tt->max_refs);
508 if (tt->every_base)
510 fprintf (out, " Every base\n");
511 return;
513 size_t i;
514 modref_base_node <tree> *n;
515 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
517 fprintf (out, " Base %i:", (int)i);
518 print_generic_expr (dump_file, n->base);
519 fprintf (out, " (alias set %i)\n",
520 n->base ? get_alias_set (n->base) : 0);
521 if (n->every_ref)
523 fprintf (out, " Every ref\n");
524 continue;
526 size_t j;
527 modref_ref_node <tree> *r;
528 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
530 fprintf (out, " Ref %i:", (int)j);
531 print_generic_expr (dump_file, r->ref);
532 fprintf (out, " (alias set %i)\n",
533 r->ref ? get_alias_set (r->ref) : 0);
534 if (r->every_access)
536 fprintf (out, " Every access\n");
537 continue;
539 size_t k;
540 modref_access_node *a;
541 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
542 dump_access (a, out);
547 /* Dump all escape points of NODE to OUT. */
549 static void
550 dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
552 int i = 0;
553 if (!escape_summaries)
554 return;
555 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
557 class escape_summary *sum = escape_summaries->get (e);
558 if (sum)
560 fprintf (out, "%*sIndirect call %i in %s escapes:",
561 depth, "", i, node->dump_name ());
562 sum->dump (out);
564 i++;
566 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
568 if (!e->inline_failed)
569 dump_modref_edge_summaries (out, e->callee, depth + 1);
570 class escape_summary *sum = escape_summaries->get (e);
571 if (sum)
573 fprintf (out, "%*sCall %s->%s escapes:", depth, "",
574 node->dump_name (), e->callee->dump_name ());
575 sum->dump (out);
577 class fnspec_summary *fsum = fnspec_summaries->get (e);
578 if (fsum)
580 fprintf (out, "%*sCall %s->%s fnspec: %s\n", depth, "",
581 node->dump_name (), e->callee->dump_name (),
582 fsum->fnspec);
587 /* Remove all call edge summaries associated with NODE. */
589 static void
590 remove_modref_edge_summaries (cgraph_node *node)
592 if (!escape_summaries)
593 return;
594 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
595 escape_summaries->remove (e);
596 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
598 if (!e->inline_failed)
599 remove_modref_edge_summaries (e->callee);
600 escape_summaries->remove (e);
601 fnspec_summaries->remove (e);
605 /* Dump summary. */
607 void
608 modref_summary::dump (FILE *out)
610 if (loads)
612 fprintf (out, " loads:\n");
613 dump_records (loads, out);
615 if (stores)
617 fprintf (out, " stores:\n");
618 dump_records (stores, out);
620 if (writes_errno)
621 fprintf (out, " Writes errno\n");
622 if (side_effects)
623 fprintf (out, " Side effects\n");
624 if (arg_flags.length ())
626 for (unsigned int i = 0; i < arg_flags.length (); i++)
627 if (arg_flags[i])
629 fprintf (out, " parm %i flags:", i);
630 dump_eaf_flags (out, arg_flags[i]);
633 if (retslot_flags)
635 fprintf (out, " Retslot flags:");
636 dump_eaf_flags (out, retslot_flags);
638 if (static_chain_flags)
640 fprintf (out, " Static chain flags:");
641 dump_eaf_flags (out, static_chain_flags);
645 /* Dump summary. */
647 void
648 modref_summary_lto::dump (FILE *out)
650 fprintf (out, " loads:\n");
651 dump_lto_records (loads, out);
652 fprintf (out, " stores:\n");
653 dump_lto_records (stores, out);
654 if (writes_errno)
655 fprintf (out, " Writes errno\n");
656 if (side_effects)
657 fprintf (out, " Side effects\n");
658 if (arg_flags.length ())
660 for (unsigned int i = 0; i < arg_flags.length (); i++)
661 if (arg_flags[i])
663 fprintf (out, " parm %i flags:", i);
664 dump_eaf_flags (out, arg_flags[i]);
667 if (retslot_flags)
669 fprintf (out, " Retslot flags:");
670 dump_eaf_flags (out, retslot_flags);
672 if (static_chain_flags)
674 fprintf (out, " Static chain flags:");
675 dump_eaf_flags (out, static_chain_flags);
679 /* Get function summary for FUNC if it exists, return NULL otherwise. */
681 modref_summary *
682 get_modref_function_summary (cgraph_node *func)
684 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
685 if (!optimization_summaries)
686 return NULL;
688 /* A single function body may be represented by multiple symbols with
689 different visibility. For example, if FUNC is an interposable alias,
690 we don't want to return anything, even if we have summary for the target
691 function. */
692 enum availability avail;
693 func = func->function_or_virtual_thunk_symbol
694 (&avail, current_function_decl ?
695 cgraph_node::get (current_function_decl) : NULL);
696 if (avail <= AVAIL_INTERPOSABLE)
697 return NULL;
699 modref_summary *r = optimization_summaries->get (func);
700 return r;
703 namespace {
705 /* Construct modref_access_node from REF. */
706 static modref_access_node
707 get_access (ao_ref *ref)
709 tree base;
711 base = ao_ref_base (ref);
712 modref_access_node a = {ref->offset, ref->size, ref->max_size,
713 0, MODREF_UNKNOWN_PARM, false, 0};
714 if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
716 tree memref = base;
717 base = TREE_OPERAND (base, 0);
719 if (TREE_CODE (base) == SSA_NAME
720 && SSA_NAME_IS_DEFAULT_DEF (base)
721 && TREE_CODE (SSA_NAME_VAR (base)) == PARM_DECL)
723 a.parm_index = 0;
724 if (cfun->static_chain_decl
725 && base == ssa_default_def (cfun, cfun->static_chain_decl))
726 a.parm_index = MODREF_STATIC_CHAIN_PARM;
727 else
728 for (tree t = DECL_ARGUMENTS (current_function_decl);
729 t != SSA_NAME_VAR (base); t = DECL_CHAIN (t))
730 a.parm_index++;
732 else
733 a.parm_index = MODREF_UNKNOWN_PARM;
735 if (a.parm_index != MODREF_UNKNOWN_PARM
736 && TREE_CODE (memref) == MEM_REF)
738 a.parm_offset_known
739 = wi::to_poly_wide (TREE_OPERAND
740 (memref, 1)).to_shwi (&a.parm_offset);
742 else
743 a.parm_offset_known = false;
745 else
746 a.parm_index = MODREF_UNKNOWN_PARM;
747 return a;
750 /* Record access into the modref_records data structure. */
752 static void
753 record_access (modref_records *tt, ao_ref *ref)
755 alias_set_type base_set = !flag_strict_aliasing ? 0
756 : ao_ref_base_alias_set (ref);
757 alias_set_type ref_set = !flag_strict_aliasing ? 0
758 : (ao_ref_alias_set (ref));
759 modref_access_node a = get_access (ref);
760 if (dump_file)
762 fprintf (dump_file, " - Recording base_set=%i ref_set=%i ",
763 base_set, ref_set);
764 dump_access (&a, dump_file);
766 tt->insert (base_set, ref_set, a, false);
769 /* IPA version of record_access_tree. */
771 static void
772 record_access_lto (modref_records_lto *tt, ao_ref *ref)
774 /* get_alias_set sometimes use different type to compute the alias set
775 than TREE_TYPE (base). Do same adjustments. */
776 tree base_type = NULL_TREE, ref_type = NULL_TREE;
777 if (flag_strict_aliasing)
779 tree base;
781 base = ref->ref;
782 while (handled_component_p (base))
783 base = TREE_OPERAND (base, 0);
785 base_type = reference_alias_ptr_type_1 (&base);
787 if (!base_type)
788 base_type = TREE_TYPE (base);
789 else
790 base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
791 ? NULL_TREE : TREE_TYPE (base_type);
793 tree ref_expr = ref->ref;
794 ref_type = reference_alias_ptr_type_1 (&ref_expr);
796 if (!ref_type)
797 ref_type = TREE_TYPE (ref_expr);
798 else
799 ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
800 ? NULL_TREE : TREE_TYPE (ref_type);
802 /* Sanity check that we are in sync with what get_alias_set does. */
803 gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
804 || get_alias_set (base_type)
805 == ao_ref_base_alias_set (ref));
806 gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
807 || get_alias_set (ref_type)
808 == ao_ref_alias_set (ref));
810 /* Do not bother to record types that have no meaningful alias set.
811 Also skip variably modified types since these go to local streams. */
812 if (base_type && (!get_alias_set (base_type)
813 || variably_modified_type_p (base_type, NULL_TREE)))
814 base_type = NULL_TREE;
815 if (ref_type && (!get_alias_set (ref_type)
816 || variably_modified_type_p (ref_type, NULL_TREE)))
817 ref_type = NULL_TREE;
819 modref_access_node a = get_access (ref);
820 if (dump_file)
822 fprintf (dump_file, " - Recording base type:");
823 print_generic_expr (dump_file, base_type);
824 fprintf (dump_file, " (alias set %i) ref type:",
825 base_type ? get_alias_set (base_type) : 0);
826 print_generic_expr (dump_file, ref_type);
827 fprintf (dump_file, " (alias set %i) ",
828 ref_type ? get_alias_set (ref_type) : 0);
829 dump_access (&a, dump_file);
832 tt->insert (base_type, ref_type, a, false);
835 /* Returns true if and only if we should store the access to EXPR.
836 Some accesses, e.g. loads from automatic variables, are not interesting. */
838 static bool
839 record_access_p (tree expr)
841 if (refs_local_or_readonly_memory_p (expr))
843 if (dump_file)
844 fprintf (dump_file, " - Read-only or local, ignoring.\n");
845 return false;
847 return true;
850 /* Return true if ECF flags says that return value can be ignored. */
852 static bool
853 ignore_retval_p (tree caller, int flags)
855 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
856 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
857 return true;
858 return false;
861 /* Return true if ECF flags says that stores can be ignored. */
863 static bool
864 ignore_stores_p (tree caller, int flags)
866 if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
867 return true;
868 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
869 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
870 return true;
871 return false;
874 /* Determine parm_map for argument OP. */
876 modref_parm_map
877 parm_map_for_arg (tree op)
879 bool offset_known;
880 poly_int64 offset;
881 struct modref_parm_map parm_map;
883 parm_map.parm_offset_known = false;
884 parm_map.parm_offset = 0;
886 offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
887 if (TREE_CODE (op) == SSA_NAME
888 && SSA_NAME_IS_DEFAULT_DEF (op)
889 && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
891 int index = 0;
892 for (tree t = DECL_ARGUMENTS (current_function_decl);
893 t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
895 if (!t)
897 index = MODREF_UNKNOWN_PARM;
898 break;
900 index++;
902 parm_map.parm_index = index;
903 parm_map.parm_offset_known = offset_known;
904 parm_map.parm_offset = offset;
906 else if (points_to_local_or_readonly_memory_p (op))
907 parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM;
908 else
909 parm_map.parm_index = MODREF_UNKNOWN_PARM;
910 return parm_map;
913 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
914 int CUR_SUMMARY. Return true if something changed.
915 If IGNORE_STORES is true, do not merge stores.
916 If RECORD_ADJUSTMENTS is true cap number of adjustments to
917 a given access to make dataflow finite. */
919 bool
920 merge_call_side_effects (modref_summary *cur_summary,
921 gimple *stmt, modref_summary *callee_summary,
922 bool ignore_stores, cgraph_node *callee_node,
923 bool record_adjustments)
925 auto_vec <modref_parm_map, 32> parm_map;
926 modref_parm_map chain_map;
927 bool changed = false;
928 int flags = gimple_call_flags (stmt);
930 if (!cur_summary->side_effects && callee_summary->side_effects)
932 if (dump_file)
933 fprintf (dump_file, " - merging side effects.\n");
934 cur_summary->side_effects = true;
935 changed = true;
938 if (flags & (ECF_CONST | ECF_NOVOPS))
939 return changed;
941 /* We can not safely optimize based on summary of callee if it does
942 not always bind to current def: it is possible that memory load
943 was optimized out earlier which may not happen in the interposed
944 variant. */
945 if (!callee_node->binds_to_current_def_p ())
947 if (dump_file)
948 fprintf (dump_file, " - May be interposed: collapsing loads.\n");
949 cur_summary->loads->collapse ();
952 if (dump_file)
953 fprintf (dump_file, " - Merging side effects of %s with parm map:",
954 callee_node->dump_name ());
956 parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true);
957 for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
959 parm_map[i] = parm_map_for_arg (gimple_call_arg (stmt, i));
960 if (dump_file)
962 fprintf (dump_file, " %i", parm_map[i].parm_index);
963 if (parm_map[i].parm_offset_known)
965 fprintf (dump_file, " offset:");
966 print_dec ((poly_int64_pod)parm_map[i].parm_offset,
967 dump_file, SIGNED);
971 if (gimple_call_chain (stmt))
973 chain_map = parm_map_for_arg (gimple_call_chain (stmt));
974 if (dump_file)
976 fprintf (dump_file, "static chain %i", chain_map.parm_index);
977 if (chain_map.parm_offset_known)
979 fprintf (dump_file, " offset:");
980 print_dec ((poly_int64_pod)chain_map.parm_offset,
981 dump_file, SIGNED);
985 if (dump_file)
986 fprintf (dump_file, "\n");
988 /* Merge with callee's summary. */
989 changed |= cur_summary->loads->merge (callee_summary->loads, &parm_map,
990 &chain_map, record_adjustments);
991 if (!ignore_stores)
993 changed |= cur_summary->stores->merge (callee_summary->stores,
994 &parm_map, &chain_map,
995 record_adjustments);
996 if (!cur_summary->writes_errno
997 && callee_summary->writes_errno)
999 cur_summary->writes_errno = true;
1000 changed = true;
1003 return changed;
1006 /* Return access mode for argument I of call STMT with FNSPEC. */
1008 static modref_access_node
1009 get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
1010 unsigned int i, modref_parm_map &map)
1012 tree size = NULL_TREE;
1013 unsigned int size_arg;
1015 if (!fnspec.arg_specified_p (i))
1017 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
1018 size = gimple_call_arg (call, size_arg);
1019 else if (fnspec.arg_access_size_given_by_type_p (i))
1021 tree callee = gimple_call_fndecl (call);
1022 tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
1024 for (unsigned int p = 0; p < i; p++)
1025 t = TREE_CHAIN (t);
1026 size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
1028 modref_access_node a = {0, -1, -1,
1029 map.parm_offset, map.parm_index,
1030 map.parm_offset_known, 0};
1031 poly_int64 size_hwi;
1032 if (size
1033 && poly_int_tree_p (size, &size_hwi)
1034 && coeffs_in_range_p (size_hwi, 0,
1035 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
1037 a.size = -1;
1038 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
1040 return a;
1043 /* Collapse loads and return true if something changed. */
1045 static bool
1046 collapse_loads (modref_summary *cur_summary,
1047 modref_summary_lto *cur_summary_lto)
1049 bool changed = false;
1051 if (cur_summary && !cur_summary->loads->every_base)
1053 cur_summary->loads->collapse ();
1054 changed = true;
1056 if (cur_summary_lto
1057 && !cur_summary_lto->loads->every_base)
1059 cur_summary_lto->loads->collapse ();
1060 changed = true;
1062 return changed;
1065 /* Collapse loads and return true if something changed. */
1067 static bool
1068 collapse_stores (modref_summary *cur_summary,
1069 modref_summary_lto *cur_summary_lto)
1071 bool changed = false;
1073 if (cur_summary && !cur_summary->stores->every_base)
1075 cur_summary->stores->collapse ();
1076 changed = true;
1078 if (cur_summary_lto
1079 && !cur_summary_lto->stores->every_base)
1081 cur_summary_lto->stores->collapse ();
1082 changed = true;
1084 return changed;
1088 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1089 If IGNORE_STORES is true ignore them.
1090 Return false if no useful summary can be produced. */
1092 static bool
1093 process_fnspec (modref_summary *cur_summary,
1094 modref_summary_lto *cur_summary_lto,
1095 gcall *call, bool ignore_stores)
1097 attr_fnspec fnspec = gimple_call_fnspec (call);
1098 int flags = gimple_call_flags (call);
1100 if (!(flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE))
1101 || (flags & ECF_LOOPING_CONST_OR_PURE)
1102 || (cfun->can_throw_non_call_exceptions
1103 && stmt_could_throw_p (cfun, call)))
1105 if (cur_summary)
1106 cur_summary->side_effects = true;
1107 if (cur_summary_lto)
1108 cur_summary_lto->side_effects = true;
1110 if (flags & (ECF_CONST | ECF_NOVOPS))
1111 return true;
1112 if (!fnspec.known_p ())
1114 if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
1115 fprintf (dump_file, " Builtin with no fnspec: %s\n",
1116 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
1117 if (ignore_stores)
1119 collapse_loads (cur_summary, cur_summary_lto);
1120 return true;
1122 return false;
1124 if (fnspec.global_memory_read_p ())
1125 collapse_loads (cur_summary, cur_summary_lto);
1126 else
1128 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1129 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1131 else if (!fnspec.arg_specified_p (i)
1132 || fnspec.arg_maybe_read_p (i))
1134 modref_parm_map map = parm_map_for_arg
1135 (gimple_call_arg (call, i));
1137 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
1138 continue;
1139 if (map.parm_index == MODREF_UNKNOWN_PARM)
1141 collapse_loads (cur_summary, cur_summary_lto);
1142 break;
1144 if (cur_summary)
1145 cur_summary->loads->insert (0, 0,
1146 get_access_for_fnspec (call,
1147 fnspec, i,
1148 map),
1149 false);
1150 if (cur_summary_lto)
1151 cur_summary_lto->loads->insert (0, 0,
1152 get_access_for_fnspec (call,
1153 fnspec, i,
1154 map),
1155 false);
1158 if (ignore_stores)
1159 return true;
1160 if (fnspec.global_memory_written_p ())
1161 collapse_stores (cur_summary, cur_summary_lto);
1162 else
1164 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1165 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1167 else if (!fnspec.arg_specified_p (i)
1168 || fnspec.arg_maybe_written_p (i))
1170 modref_parm_map map = parm_map_for_arg
1171 (gimple_call_arg (call, i));
1173 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
1174 continue;
1175 if (map.parm_index == MODREF_UNKNOWN_PARM)
1177 collapse_stores (cur_summary, cur_summary_lto);
1178 break;
1180 if (cur_summary)
1181 cur_summary->stores->insert (0, 0,
1182 get_access_for_fnspec (call,
1183 fnspec, i,
1184 map),
1185 false);
1186 if (cur_summary_lto)
1187 cur_summary_lto->stores->insert (0, 0,
1188 get_access_for_fnspec (call,
1189 fnspec, i,
1190 map),
1191 false);
1193 if (fnspec.errno_maybe_written_p () && flag_errno_math)
1195 if (cur_summary)
1196 cur_summary->writes_errno = true;
1197 if (cur_summary_lto)
1198 cur_summary_lto->writes_errno = true;
1201 return true;
1204 /* Analyze function call STMT in function F.
1205 Remember recursive calls in RECURSIVE_CALLS. */
1207 static bool
1208 analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto,
1209 gcall *stmt, vec <gimple *> *recursive_calls)
1211 /* Check flags on the function call. In certain cases, analysis can be
1212 simplified. */
1213 int flags = gimple_call_flags (stmt);
1214 if ((flags & (ECF_CONST | ECF_NOVOPS))
1215 && !(flags & ECF_LOOPING_CONST_OR_PURE))
1217 if (dump_file)
1218 fprintf (dump_file,
1219 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1220 "except for args.\n");
1221 return true;
1224 /* Pure functions do not affect global memory. Stores by functions which are
1225 noreturn and do not throw can safely be ignored. */
1226 bool ignore_stores = ignore_stores_p (current_function_decl, flags);
1228 /* Next, we try to get the callee's function declaration. The goal is to
1229 merge their summary with ours. */
1230 tree callee = gimple_call_fndecl (stmt);
1232 /* Check if this is an indirect call. */
1233 if (!callee)
1235 if (dump_file)
1236 fprintf (dump_file, gimple_call_internal_p (stmt)
1237 ? " - Internal call" : " - Indirect call.\n");
1238 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1240 /* We only need to handle internal calls in IPA mode. */
1241 gcc_checking_assert (!cur_summary_lto);
1243 struct cgraph_node *callee_node = cgraph_node::get_create (callee);
1245 /* If this is a recursive call, the target summary is the same as ours, so
1246 there's nothing to do. */
1247 if (recursive_call_p (current_function_decl, callee))
1249 recursive_calls->safe_push (stmt);
1250 if (cur_summary)
1251 cur_summary->side_effects = true;
1252 if (cur_summary_lto)
1253 cur_summary_lto->side_effects = true;
1254 if (dump_file)
1255 fprintf (dump_file, " - Skipping recursive call.\n");
1256 return true;
1259 gcc_assert (callee_node != NULL);
1261 /* Get the function symbol and its availability. */
1262 enum availability avail;
1263 callee_node = callee_node->function_symbol (&avail);
1264 bool looping;
1265 if (builtin_safe_for_const_function_p (&looping, callee))
1267 if (looping)
1269 if (cur_summary)
1270 cur_summary->side_effects = true;
1271 if (cur_summary_lto)
1272 cur_summary_lto->side_effects = true;
1274 if (dump_file)
1275 fprintf (dump_file, " - Bulitin is safe for const.\n");
1276 return true;
1278 if (avail <= AVAIL_INTERPOSABLE)
1280 if (dump_file)
1281 fprintf (dump_file, " - Function availability <= AVAIL_INTERPOSABLE.\n");
1282 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1285 /* Get callee's modref summary. As above, if there's no summary, we either
1286 have to give up or, if stores are ignored, we can just purge loads. */
1287 modref_summary *callee_summary = optimization_summaries->get (callee_node);
1288 if (!callee_summary)
1290 if (dump_file)
1291 fprintf (dump_file, " - No modref summary available for callee.\n");
1292 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1295 merge_call_side_effects (cur_summary, stmt, callee_summary, ignore_stores,
1296 callee_node, false);
1298 return true;
1301 /* Support analysis in non-lto and lto mode in parallel. */
1303 struct summary_ptrs
1305 struct modref_summary *nolto;
1306 struct modref_summary_lto *lto;
1309 /* Helper for analyze_stmt. */
1311 static bool
1312 analyze_load (gimple *, tree, tree op, void *data)
1314 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1315 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1317 if (dump_file)
1319 fprintf (dump_file, " - Analyzing load: ");
1320 print_generic_expr (dump_file, op);
1321 fprintf (dump_file, "\n");
1324 if (TREE_THIS_VOLATILE (op)
1325 || (cfun->can_throw_non_call_exceptions
1326 && tree_could_throw_p (op)))
1328 if (dump_file)
1329 fprintf (dump_file, " (volatile or can throw; marking side effects) ");
1330 if (summary)
1331 summary->side_effects = true;
1332 if (summary_lto)
1333 summary_lto->side_effects = true;
1336 if (!record_access_p (op))
1337 return false;
1339 ao_ref r;
1340 ao_ref_init (&r, op);
1342 if (summary)
1343 record_access (summary->loads, &r);
1344 if (summary_lto)
1345 record_access_lto (summary_lto->loads, &r);
1346 return false;
1349 /* Helper for analyze_stmt. */
1351 static bool
1352 analyze_store (gimple *, tree, tree op, void *data)
1354 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1355 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1357 if (dump_file)
1359 fprintf (dump_file, " - Analyzing store: ");
1360 print_generic_expr (dump_file, op);
1361 fprintf (dump_file, "\n");
1364 if (TREE_THIS_VOLATILE (op)
1365 || (cfun->can_throw_non_call_exceptions
1366 && tree_could_throw_p (op)))
1368 if (dump_file)
1369 fprintf (dump_file, " (volatile or can throw; marking side effects) ");
1370 if (summary)
1371 summary->side_effects = true;
1372 if (summary_lto)
1373 summary_lto->side_effects = true;
1376 if (!record_access_p (op))
1377 return false;
1379 ao_ref r;
1380 ao_ref_init (&r, op);
1382 if (summary)
1383 record_access (summary->stores, &r);
1384 if (summary_lto)
1385 record_access_lto (summary_lto->stores, &r);
1386 return false;
1389 /* Analyze statement STMT of function F.
1390 If IPA is true do not merge in side effects of calls. */
1392 static bool
1393 analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
1394 gimple *stmt, bool ipa, vec <gimple *> *recursive_calls)
1396 /* In general we can not ignore clobbers because they are barriers for code
1397 motion, however after inlining it is safe to do because local optimization
1398 passes do not consider clobbers from other functions.
1399 Similar logic is in ipa-pure-const.c. */
1400 if ((ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1401 return true;
1403 struct summary_ptrs sums = {summary, summary_lto};
1405 /* Analyze all loads and stores in STMT. */
1406 walk_stmt_load_store_ops (stmt, &sums,
1407 analyze_load, analyze_store);
1409 switch (gimple_code (stmt))
1411 case GIMPLE_ASM:
1412 if (gimple_asm_volatile_p (as_a <gasm *> (stmt))
1413 || (cfun->can_throw_non_call_exceptions
1414 && stmt_could_throw_p (cfun, stmt)))
1416 if (summary)
1417 summary->side_effects = true;
1418 if (summary_lto)
1419 summary_lto->side_effects = true;
1421 /* If the ASM statement does not read nor write memory, there's nothing
1422 to do. Otherwise just give up. */
1423 if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1424 return true;
1425 if (dump_file)
1426 fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1427 "which clobbers memory.\n");
1428 return false;
1429 case GIMPLE_CALL:
1430 if (!ipa || gimple_call_internal_p (stmt))
1431 return analyze_call (summary, summary_lto,
1432 as_a <gcall *> (stmt), recursive_calls);
1433 else
1435 attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1437 if (fnspec.known_p ()
1438 && (!fnspec.global_memory_read_p ()
1439 || !fnspec.global_memory_written_p ()))
1441 cgraph_edge *e = cgraph_node::get (current_function_decl)->get_edge (stmt);
1442 if (e->callee)
1444 fnspec_summaries->get_create (e)->fnspec = xstrdup (fnspec.get_str ());
1445 if (dump_file)
1446 fprintf (dump_file, " Recorded fnspec %s\n", fnspec.get_str ());
1450 return true;
1451 default:
1452 if (cfun->can_throw_non_call_exceptions
1453 && stmt_could_throw_p (cfun, stmt))
1455 if (summary)
1456 summary->side_effects = true;
1457 if (summary_lto)
1458 summary_lto->side_effects = true;
1460 return true;
1464 /* Remove summary of current function because during the function body
1465 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1466 mode of scan. */
1468 static void
1469 remove_summary (bool lto, bool nolto, bool ipa)
1471 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1472 if (!ipa)
1473 optimization_summaries->remove (fnode);
1474 else
1476 if (nolto)
1477 summaries->remove (fnode);
1478 if (lto)
1479 summaries_lto->remove (fnode);
1480 remove_modref_edge_summaries (fnode);
1482 if (dump_file)
1483 fprintf (dump_file,
1484 " - modref done with result: not tracked.\n");
1487 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1489 bool
1490 memory_access_to (tree op, tree ssa_name)
1492 tree base = get_base_address (op);
1493 if (!base)
1494 return false;
1495 if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1496 return false;
1497 return TREE_OPERAND (base, 0) == ssa_name;
1500 /* Consider statement val = *arg.
1501 return EAF flags of ARG that can be determined from EAF flags of VAL
1502 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1503 all stores to VAL, i.e. when handling noreturn function. */
1505 static int
1506 deref_flags (int flags, bool ignore_stores)
1508 /* Dereference is also a direct read but dereferenced value does not
1509 yield any other direct use. */
1510 int ret = EAF_NO_DIRECT_CLOBBER | EAF_NO_DIRECT_ESCAPE
1511 | EAF_NOT_RETURNED_DIRECTLY;
1512 /* If argument is unused just account for
1513 the read involved in dereference. */
1514 if (flags & EAF_UNUSED)
1515 ret |= EAF_NO_INDIRECT_READ | EAF_NO_INDIRECT_CLOBBER
1516 | EAF_NO_INDIRECT_ESCAPE;
1517 else
1519 /* Direct or indirect accesses leads to indirect accesses. */
1520 if (((flags & EAF_NO_DIRECT_CLOBBER)
1521 && (flags & EAF_NO_INDIRECT_CLOBBER))
1522 || ignore_stores)
1523 ret |= EAF_NO_INDIRECT_CLOBBER;
1524 if (((flags & EAF_NO_DIRECT_ESCAPE)
1525 && (flags & EAF_NO_INDIRECT_ESCAPE))
1526 || ignore_stores)
1527 ret |= EAF_NO_INDIRECT_ESCAPE;
1528 if ((flags & EAF_NO_DIRECT_READ)
1529 && (flags & EAF_NO_INDIRECT_READ))
1530 ret |= EAF_NO_INDIRECT_READ;
1531 if ((flags & EAF_NOT_RETURNED_DIRECTLY)
1532 && (flags & EAF_NOT_RETURNED_INDIRECTLY))
1533 ret |= EAF_NOT_RETURNED_INDIRECTLY;
1535 return ret;
1539 /* Description of an escape point. */
1541 struct escape_point
1543 /* Value escapes to this call. */
1544 gcall *call;
1545 /* Argument it escapes to. */
1546 int arg;
1547 /* Flags already known about the argument (this can save us from recording
1548 esape points if local analysis did good job already). */
1549 eaf_flags_t min_flags;
1550 /* Does value escape directly or indiretly? */
1551 bool direct;
1554 class modref_lattice
1556 public:
1557 /* EAF flags of the SSA name. */
1558 eaf_flags_t flags;
1559 /* Used during DFS walk to mark names where final value was determined
1560 without need for dataflow. */
1561 bool known;
1562 /* Used during DFS walk to mark open vertices (for cycle detection). */
1563 bool open;
1564 /* Set during DFS walk for names that needs dataflow propagation. */
1565 bool do_dataflow;
1566 /* Used during the iterative dataflow. */
1567 bool changed;
1569 /* When doing IPA analysis we can not merge in callee escape points;
1570 Only remember them and do the merging at IPA propagation time. */
1571 vec <escape_point, va_heap, vl_ptr> escape_points;
1573 /* Representation of a graph for dataaflow. This graph is built on-demand
1574 using modref_eaf_analysis::analyze_ssa and later solved by
1575 modref_eaf_analysis::propagate.
1576 Each edge represents the fact that flags of current lattice should be
1577 propagated to lattice of SSA_NAME. */
1578 struct propagate_edge
1580 int ssa_name;
1581 bool deref;
1583 vec <propagate_edge, va_heap, vl_ptr> propagate_to;
1585 void init ();
1586 void release ();
1587 bool merge (const modref_lattice &with);
1588 bool merge (int flags);
1589 bool merge_deref (const modref_lattice &with, bool ignore_stores);
1590 bool merge_direct_load ();
1591 bool merge_direct_store ();
1592 bool add_escape_point (gcall *call, int arg, int min_flags, bool diret);
1593 void dump (FILE *out, int indent = 0) const;
1596 /* Lattices are saved to vectors, so keep them PODs. */
1597 void
1598 modref_lattice::init ()
1600 /* All flags we track. */
1601 int f = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
1602 | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE
1603 | EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ
1604 | EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY
1605 | EAF_UNUSED;
1606 flags = f;
1607 /* Check that eaf_flags_t is wide enough to hold all flags. */
1608 gcc_checking_assert (f == flags);
1609 open = true;
1610 known = false;
1613 /* Release memory. */
1614 void
1615 modref_lattice::release ()
1617 escape_points.release ();
1618 propagate_to.release ();
1621 /* Dump lattice to OUT; indent with INDENT spaces. */
1623 void
1624 modref_lattice::dump (FILE *out, int indent) const
1626 dump_eaf_flags (out, flags);
1627 if (escape_points.length ())
1629 fprintf (out, "%*sEscapes:\n", indent, "");
1630 for (unsigned int i = 0; i < escape_points.length (); i++)
1632 fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
1633 escape_points[i].arg,
1634 escape_points[i].direct ? "direct" : "indirect");
1635 dump_eaf_flags (out, escape_points[i].min_flags, false);
1636 fprintf (out, " in call ");
1637 print_gimple_stmt (out, escape_points[i].call, 0);
1642 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1643 point exists. */
1645 bool
1646 modref_lattice::add_escape_point (gcall *call, int arg, int min_flags,
1647 bool direct)
1649 escape_point *ep;
1650 unsigned int i;
1652 /* If we already determined flags to be bad enough,
1653 we do not need to record. */
1654 if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
1655 return false;
1657 FOR_EACH_VEC_ELT (escape_points, i, ep)
1658 if (ep->call == call && ep->arg == arg && ep->direct == direct)
1660 if ((ep->min_flags & min_flags) == min_flags)
1661 return false;
1662 ep->min_flags &= min_flags;
1663 return true;
1665 /* Give up if max escape points is met. */
1666 if ((int)escape_points.length () > param_modref_max_escape_points)
1668 if (dump_file)
1669 fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
1670 merge (0);
1671 return true;
1673 escape_point new_ep = {call, arg, min_flags, direct};
1674 escape_points.safe_push (new_ep);
1675 return true;
1678 /* Merge in flags from F. */
1679 bool
1680 modref_lattice::merge (int f)
1682 if (f & EAF_UNUSED)
1683 return false;
1684 if ((flags & f) != flags)
1686 flags &= f;
1687 /* Prune obvoiusly useless flags;
1688 We do not have ECF_FLAGS handy which is not big problem since
1689 we will do final flags cleanup before producing summary.
1690 Merging should be fast so it can work well with dataflow. */
1691 flags = remove_useless_eaf_flags (flags, 0, false);
1692 if (!flags)
1693 escape_points.release ();
1694 return true;
1696 return false;
1699 /* Merge in WITH. Return true if anyting changed. */
1701 bool
1702 modref_lattice::merge (const modref_lattice &with)
1704 if (!with.known)
1705 do_dataflow = true;
1707 bool changed = merge (with.flags);
1709 if (!flags)
1710 return changed;
1711 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1712 changed |= add_escape_point (with.escape_points[i].call,
1713 with.escape_points[i].arg,
1714 with.escape_points[i].min_flags,
1715 with.escape_points[i].direct);
1716 return changed;
1719 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1720 stores. Return true if anyting changed. */
1722 bool
1723 modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
1725 if (!with.known)
1726 do_dataflow = true;
1728 bool changed = merge (deref_flags (with.flags, ignore_stores));
1730 if (!flags)
1731 return changed;
1732 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1734 int min_flags = with.escape_points[i].min_flags;
1736 if (with.escape_points[i].direct)
1737 min_flags = deref_flags (min_flags, ignore_stores);
1738 else if (ignore_stores)
1739 min_flags |= ignore_stores_eaf_flags;
1740 changed |= add_escape_point (with.escape_points[i].call,
1741 with.escape_points[i].arg,
1742 min_flags,
1743 false);
1745 return changed;
1748 /* Merge in flags for direct load. */
1750 bool
1751 modref_lattice::merge_direct_load ()
1753 return merge (~(EAF_UNUSED | EAF_NO_DIRECT_READ));
1756 /* Merge in flags for direct store. */
1758 bool
1759 modref_lattice::merge_direct_store ()
1761 return merge (~(EAF_UNUSED | EAF_NO_DIRECT_CLOBBER));
1764 /* Analyzer of EAF flags.
1765 This is genrally dataflow problem over the SSA graph, however we only
1766 care about flags of few selected ssa names (arguments, return slot and
1767 static chain). So we first call analyze_ssa_name on all relevant names
1768 and perform a DFS walk to discover SSA names where flags needs to be
1769 determined. For acyclic graphs we try to determine final flags during
1770 this walk. Once cycles or recursin depth is met we enlist SSA names
1771 for dataflow which is done by propagate call.
1773 After propagation the flags can be obtained using get_ssa_name_flags. */
1775 class modref_eaf_analysis
1777 public:
1778 /* Mark NAME as relevant for analysis. */
1779 void analyze_ssa_name (tree name);
1780 /* Dataflow slover. */
1781 void propagate ();
1782 /* Return flags computed earlier for NAME. */
1783 int get_ssa_name_flags (tree name)
1785 int version = SSA_NAME_VERSION (name);
1786 gcc_checking_assert (m_lattice[version].known);
1787 return m_lattice[version].flags;
1789 /* In IPA mode this will record all escape points
1790 determined for NAME to PARM_IDNEX. Flags are minimal
1791 flags known. */
1792 void record_escape_points (tree name, int parm_index, int flags);
1793 modref_eaf_analysis (bool ipa)
1795 m_ipa = ipa;
1796 m_depth = 0;
1797 m_lattice.safe_grow_cleared (num_ssa_names, true);
1799 ~modref_eaf_analysis ()
1801 gcc_checking_assert (!m_depth);
1802 if (m_ipa || m_names_to_propagate.length ())
1803 for (unsigned int i = 0; i < num_ssa_names; i++)
1804 m_lattice[i].release ();
1806 private:
1807 /* If true, we produce analysis for IPA mode. In this case escape points ar
1808 collected. */
1809 bool m_ipa;
1810 /* Depth of recursion of analyze_ssa_name. */
1811 int m_depth;
1812 /* Propagation lattice for individual ssa names. */
1813 auto_vec<modref_lattice> m_lattice;
1814 auto_vec<tree> m_deferred_names;
1815 auto_vec<int> m_names_to_propagate;
1817 void merge_with_ssa_name (tree dest, tree src, bool deref);
1818 void merge_call_lhs_flags (gcall *call, int arg, tree name, bool direct,
1819 bool deref);
1823 /* Call statements may return tgeir parameters. Consider argument number
1824 ARG of USE_STMT and determine flags that can needs to be cleared
1825 in case pointer possibly indirectly references from ARG I is returned.
1826 If DIRECT is true consider direct returns and if INDIRECT consider
1827 indirect returns.
1828 LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
1829 ARG is set to -1 for static chain. */
1831 void
1832 modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg,
1833 tree name, bool direct,
1834 bool indirect)
1836 int index = SSA_NAME_VERSION (name);
1838 /* If value is not returned at all, do nothing. */
1839 if (!direct && !indirect)
1840 return;
1842 /* If there is no return value, no flags are affected. */
1843 if (!gimple_call_lhs (call))
1844 return;
1846 /* If we know that function returns given argument and it is not ARG
1847 we can still be happy. */
1848 if (arg >= 0)
1850 int flags = gimple_call_return_flags (call);
1851 if ((flags & ERF_RETURNS_ARG)
1852 && (flags & ERF_RETURN_ARG_MASK) != arg)
1853 return;
1856 /* If return value is SSA name determine its flags. */
1857 if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
1859 tree lhs = gimple_call_lhs (call);
1860 if (direct)
1861 merge_with_ssa_name (name, lhs, false);
1862 if (indirect)
1863 merge_with_ssa_name (name, lhs, true);
1865 /* In the case of memory store we can do nothing. */
1866 else if (!direct)
1867 m_lattice[index].merge (deref_flags (0, false));
1868 else
1869 m_lattice[index].merge (0);
1872 /* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
1873 into flags for caller, update LATTICE of corresponding
1874 argument if needed. */
1876 static int
1877 callee_to_caller_flags (int call_flags, bool ignore_stores,
1878 modref_lattice &lattice)
1880 /* call_flags is about callee returning a value
1881 that is not the same as caller returning it. */
1882 call_flags |= EAF_NOT_RETURNED_DIRECTLY
1883 | EAF_NOT_RETURNED_INDIRECTLY;
1884 /* TODO: We miss return value propagation.
1885 Be conservative and if value escapes to memory
1886 also mark it as escaping. */
1887 if (!ignore_stores && !(call_flags & EAF_UNUSED))
1889 if (!(call_flags & EAF_NO_DIRECT_ESCAPE))
1890 lattice.merge (~(EAF_NOT_RETURNED_DIRECTLY
1891 | EAF_NOT_RETURNED_INDIRECTLY
1892 | EAF_UNUSED));
1893 if (!(call_flags & EAF_NO_INDIRECT_ESCAPE))
1894 lattice.merge (~(EAF_NOT_RETURNED_INDIRECTLY
1895 | EAF_UNUSED));
1897 else
1898 call_flags |= ignore_stores_eaf_flags;
1899 return call_flags;
1902 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
1903 LATTICE is an array of modref_lattices.
1904 DEPTH is a recursion depth used to make debug output prettier.
1905 If IPA is true we analyze for IPA propagation (and thus call escape points
1906 are processed later) */
1908 void
1909 modref_eaf_analysis::analyze_ssa_name (tree name)
1911 imm_use_iterator ui;
1912 gimple *use_stmt;
1913 int index = SSA_NAME_VERSION (name);
1915 /* See if value is already computed. */
1916 if (m_lattice[index].known || m_lattice[index].do_dataflow)
1917 return;
1918 if (m_lattice[index].open)
1920 if (dump_file)
1921 fprintf (dump_file,
1922 "%*sCycle in SSA graph\n",
1923 m_depth * 4, "");
1924 return;
1926 /* Recursion guard. */
1927 m_lattice[index].init ();
1928 if (m_depth == param_modref_max_depth)
1930 if (dump_file)
1931 fprintf (dump_file,
1932 "%*sMax recursion depth reached; postponing\n",
1933 m_depth * 4, "");
1934 m_deferred_names.safe_push (name);
1935 return;
1938 if (dump_file)
1940 fprintf (dump_file,
1941 "%*sAnalyzing flags of ssa name: ", m_depth * 4, "");
1942 print_generic_expr (dump_file, name);
1943 fprintf (dump_file, "\n");
1946 FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
1948 if (m_lattice[index].flags == 0)
1949 break;
1950 if (is_gimple_debug (use_stmt))
1951 continue;
1952 if (dump_file)
1954 fprintf (dump_file, "%*s Analyzing stmt: ", m_depth * 4, "");
1955 print_gimple_stmt (dump_file, use_stmt, 0);
1957 /* If we see a direct non-debug use, clear unused bit.
1958 All dereferneces should be accounted below using deref_flags. */
1959 m_lattice[index].merge (~EAF_UNUSED);
1961 /* Gimple return may load the return value.
1962 Returning name counts as an use by tree-ssa-structalias.c */
1963 if (greturn *ret = dyn_cast <greturn *> (use_stmt))
1965 /* Returning through return slot is seen as memory write earlier. */
1966 if (DECL_RESULT (current_function_decl)
1967 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
1969 else if (gimple_return_retval (ret) == name)
1970 m_lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED_DIRECTLY
1971 | EAF_NOT_RETURNED_DIRECTLY));
1972 else if (memory_access_to (gimple_return_retval (ret), name))
1974 m_lattice[index].merge_direct_load ();
1975 m_lattice[index].merge (~(EAF_UNUSED
1976 | EAF_NOT_RETURNED_INDIRECTLY));
1979 /* Account for LHS store, arg loads and flags from callee function. */
1980 else if (gcall *call = dyn_cast <gcall *> (use_stmt))
1982 tree callee = gimple_call_fndecl (call);
1984 /* IPA PTA internally it treats calling a function as "writing" to
1985 the argument space of all functions the function pointer points to
1986 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
1987 is on since that would allow propagation of this from -fno-ipa-pta
1988 to -fipa-pta functions. */
1989 if (gimple_call_fn (use_stmt) == name)
1990 m_lattice[index].merge (~(EAF_NO_DIRECT_CLOBBER | EAF_UNUSED));
1992 /* Recursion would require bit of propagation; give up for now. */
1993 if (callee && !m_ipa && recursive_call_p (current_function_decl,
1994 callee))
1995 m_lattice[index].merge (0);
1996 else
1998 int ecf_flags = gimple_call_flags (call);
1999 bool ignore_stores = ignore_stores_p (current_function_decl,
2000 ecf_flags);
2001 bool ignore_retval = ignore_retval_p (current_function_decl,
2002 ecf_flags);
2004 /* Handle *name = func (...). */
2005 if (gimple_call_lhs (call)
2006 && memory_access_to (gimple_call_lhs (call), name))
2008 m_lattice[index].merge_direct_store ();
2009 /* Return slot optimization passes address of
2010 LHS to callee via hidden parameter and this
2011 may make LHS to escape. See PR 98499. */
2012 if (gimple_call_return_slot_opt_p (call)
2013 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
2015 int call_flags = gimple_call_retslot_flags (call);
2016 bool isretslot = false;
2018 if (DECL_RESULT (current_function_decl)
2019 && DECL_BY_REFERENCE
2020 (DECL_RESULT (current_function_decl)))
2021 isretslot = ssa_default_def
2022 (cfun,
2023 DECL_RESULT (current_function_decl))
2024 == name;
2026 /* Passing returnslot to return slot is special because
2027 not_returned and escape has same meaning.
2028 However passing arg to return slot is different. If
2029 the callee's return slot is returned it means that
2030 arg is written to itself which is an escape. */
2031 if (!isretslot)
2033 if (!(call_flags & (EAF_NOT_RETURNED_DIRECTLY
2034 | EAF_UNUSED)))
2035 m_lattice[index].merge (~(EAF_NO_DIRECT_ESCAPE
2036 | EAF_NO_INDIRECT_ESCAPE
2037 | EAF_UNUSED));
2038 if (!(call_flags & (EAF_NOT_RETURNED_INDIRECTLY
2039 | EAF_UNUSED)))
2040 m_lattice[index].merge (~(EAF_NO_INDIRECT_ESCAPE
2041 | EAF_UNUSED));
2042 call_flags = callee_to_caller_flags
2043 (call_flags, false,
2044 m_lattice[index]);
2046 m_lattice[index].merge (call_flags);
2050 if (gimple_call_chain (call)
2051 && (gimple_call_chain (call) == name))
2053 int call_flags = gimple_call_static_chain_flags (call);
2054 if (!ignore_retval && !(call_flags & EAF_UNUSED))
2055 merge_call_lhs_flags
2056 (call, -1, name,
2057 !(call_flags & EAF_NOT_RETURNED_DIRECTLY),
2058 !(call_flags & EAF_NOT_RETURNED_INDIRECTLY));
2059 call_flags = callee_to_caller_flags
2060 (call_flags, ignore_stores,
2061 m_lattice[index]);
2062 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2063 m_lattice[index].merge (call_flags);
2066 /* Process internal functions and right away. */
2067 bool record_ipa = m_ipa && !gimple_call_internal_p (call);
2069 /* Handle all function parameters. */
2070 for (unsigned i = 0;
2071 i < gimple_call_num_args (call)
2072 && m_lattice[index].flags; i++)
2073 /* Name is directly passed to the callee. */
2074 if (gimple_call_arg (call, i) == name)
2076 int call_flags = gimple_call_arg_flags (call, i);
2077 if (!ignore_retval && !(call_flags & EAF_UNUSED))
2078 merge_call_lhs_flags
2079 (call, i, name,
2080 !(call_flags & EAF_NOT_RETURNED_DIRECTLY),
2081 !(call_flags & EAF_NOT_RETURNED_INDIRECTLY));
2082 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2084 call_flags = callee_to_caller_flags
2085 (call_flags, ignore_stores,
2086 m_lattice[index]);
2087 if (!record_ipa)
2088 m_lattice[index].merge (call_flags);
2089 else
2090 m_lattice[index].add_escape_point (call, i,
2091 call_flags, true);
2094 /* Name is dereferenced and passed to a callee. */
2095 else if (memory_access_to (gimple_call_arg (call, i), name))
2097 int call_flags = deref_flags
2098 (gimple_call_arg_flags (call, i), ignore_stores);
2099 if (!ignore_retval && !(call_flags & EAF_UNUSED)
2100 && !(call_flags & EAF_NOT_RETURNED_DIRECTLY)
2101 && !(call_flags & EAF_NOT_RETURNED_INDIRECTLY))
2102 merge_call_lhs_flags (call, i, name, false, true);
2103 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
2104 m_lattice[index].merge_direct_load ();
2105 else
2107 call_flags = callee_to_caller_flags
2108 (call_flags, ignore_stores,
2109 m_lattice[index]);
2110 if (!record_ipa)
2111 m_lattice[index].merge (call_flags);
2112 else
2113 m_lattice[index].add_escape_point (call, i,
2114 call_flags, false);
2119 else if (gimple_assign_load_p (use_stmt))
2121 gassign *assign = as_a <gassign *> (use_stmt);
2122 /* Memory to memory copy. */
2123 if (gimple_store_p (assign))
2125 /* Handle *lhs = *name.
2127 We do not track memory locations, so assume that value
2128 is used arbitrarily. */
2129 if (memory_access_to (gimple_assign_rhs1 (assign), name))
2130 m_lattice[index].merge (deref_flags (0, false));
2131 /* Handle *name = *exp. */
2132 else if (memory_access_to (gimple_assign_lhs (assign), name))
2133 m_lattice[index].merge_direct_store ();
2135 /* Handle lhs = *name. */
2136 else if (memory_access_to (gimple_assign_rhs1 (assign), name))
2138 tree lhs = gimple_assign_lhs (assign);
2139 merge_with_ssa_name (name, lhs, true);
2142 else if (gimple_store_p (use_stmt))
2144 gassign *assign = dyn_cast <gassign *> (use_stmt);
2146 /* Handle *lhs = name. */
2147 if (assign && gimple_assign_rhs1 (assign) == name)
2149 if (dump_file)
2150 fprintf (dump_file, "%*s ssa name saved to memory\n",
2151 m_depth * 4, "");
2152 m_lattice[index].merge (0);
2154 /* Handle *name = exp. */
2155 else if (assign
2156 && memory_access_to (gimple_assign_lhs (assign), name))
2158 /* In general we can not ignore clobbers because they are
2159 barriers for code motion, however after inlining it is safe to
2160 do because local optimization passes do not consider clobbers
2161 from other functions.
2162 Similar logic is in ipa-pure-const.c. */
2163 if (!cfun->after_inlining || !gimple_clobber_p (assign))
2164 m_lattice[index].merge_direct_store ();
2166 /* ASM statements etc. */
2167 else if (!assign)
2169 if (dump_file)
2170 fprintf (dump_file, "%*s Unhandled store\n", m_depth * 4, "");
2171 m_lattice[index].merge (0);
2174 else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
2176 enum tree_code code = gimple_assign_rhs_code (assign);
2178 /* See if operation is a merge as considered by
2179 tree-ssa-structalias.c:find_func_aliases. */
2180 if (!truth_value_p (code)
2181 && code != POINTER_DIFF_EXPR
2182 && (code != POINTER_PLUS_EXPR
2183 || gimple_assign_rhs1 (assign) == name))
2185 tree lhs = gimple_assign_lhs (assign);
2186 merge_with_ssa_name (name, lhs, false);
2189 else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
2191 tree result = gimple_phi_result (phi);
2192 merge_with_ssa_name (name, result, false);
2194 /* Conditions are not considered escape points
2195 by tree-ssa-structalias. */
2196 else if (gimple_code (use_stmt) == GIMPLE_COND)
2198 else
2200 if (dump_file)
2201 fprintf (dump_file, "%*s Unhandled stmt\n", m_depth * 4, "");
2202 m_lattice[index].merge (0);
2205 if (dump_file)
2207 fprintf (dump_file, "%*s current flags of ", m_depth * 4, "");
2208 print_generic_expr (dump_file, name);
2209 m_lattice[index].dump (dump_file, m_depth * 4 + 4);
2212 if (dump_file)
2214 fprintf (dump_file, "%*sflags of ssa name ", m_depth * 4, "");
2215 print_generic_expr (dump_file, name);
2216 m_lattice[index].dump (dump_file, m_depth * 4 + 2);
2218 m_lattice[index].open = false;
2219 if (!m_lattice[index].do_dataflow)
2220 m_lattice[index].known = true;
2223 /* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
2224 is dereferenced. */
2226 void
2227 modref_eaf_analysis::merge_with_ssa_name (tree dest, tree src, bool deref)
2229 int index = SSA_NAME_VERSION (dest);
2230 int src_index = SSA_NAME_VERSION (src);
2232 /* Merging lattice with itself is a no-op. */
2233 if (!deref && src == dest)
2234 return;
2236 m_depth++;
2237 analyze_ssa_name (src);
2238 m_depth--;
2239 if (deref)
2240 m_lattice[index].merge_deref (m_lattice[src_index], false);
2241 else
2242 m_lattice[index].merge (m_lattice[src_index]);
2244 /* If we failed to produce final solution add an edge to the dataflow
2245 graph. */
2246 if (!m_lattice[src_index].known)
2248 modref_lattice::propagate_edge e = {index, deref};
2250 if (!m_lattice[src_index].propagate_to.length ())
2251 m_names_to_propagate.safe_push (src_index);
2252 m_lattice[src_index].propagate_to.safe_push (e);
2253 m_lattice[src_index].changed = true;
2254 m_lattice[src_index].do_dataflow = true;
2255 if (dump_file)
2256 fprintf (dump_file,
2257 "%*sWill propgate from ssa_name %i to %i%s\n",
2258 m_depth * 4 + 4,
2259 "", src_index, index, deref ? " (deref)" : "");
2263 /* In the case we deferred some SSA names, reprocess them. In the case some
2264 dataflow edges were introduced, do the actual iterative dataflow. */
2266 void
2267 modref_eaf_analysis::propagate ()
2269 int iterations = 0;
2270 size_t i;
2271 int index;
2272 bool changed = true;
2274 while (m_deferred_names.length ())
2276 tree name = m_deferred_names.pop ();
2277 m_lattice[SSA_NAME_VERSION (name)].open = false;
2278 if (dump_file)
2279 fprintf (dump_file, "Analyzing deferred SSA name\n");
2280 analyze_ssa_name (name);
2283 if (!m_names_to_propagate.length ())
2284 return;
2285 if (dump_file)
2286 fprintf (dump_file, "Propagating EAF flags\n");
2288 /* Compute reverse postorder. */
2289 auto_vec <int> rpo;
2290 struct stack_entry
2292 int name;
2293 unsigned pos;
2295 auto_vec <struct stack_entry> stack;
2296 int pos = m_names_to_propagate.length () - 1;
2298 rpo.safe_grow (m_names_to_propagate.length (), true);
2299 stack.reserve_exact (m_names_to_propagate.length ());
2301 /* We reuse known flag for RPO DFS walk bookeeping. */
2302 if (flag_checking)
2303 FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2304 gcc_assert (!m_lattice[index].known && m_lattice[index].changed);
2306 FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2308 if (!m_lattice[index].known)
2310 stack_entry e = {index, 0};
2312 stack.quick_push (e);
2313 m_lattice[index].known = true;
2315 while (stack.length ())
2317 bool found = false;
2318 int index1 = stack.last ().name;
2320 while (stack.last ().pos < m_lattice[index1].propagate_to.length ())
2322 int index2 = m_lattice[index1]
2323 .propagate_to[stack.last ().pos].ssa_name;
2325 stack.last ().pos++;
2326 if (!m_lattice[index2].known
2327 && m_lattice[index2].propagate_to.length ())
2329 stack_entry e = {index2, 0};
2331 stack.quick_push (e);
2332 m_lattice[index2].known = true;
2333 found = true;
2334 break;
2337 if (!found
2338 && stack.last ().pos == m_lattice[index1].propagate_to.length ())
2340 rpo[pos--] = index1;
2341 stack.pop ();
2346 /* Perform itrative dataflow. */
2347 while (changed)
2349 changed = false;
2350 iterations++;
2351 if (dump_file)
2352 fprintf (dump_file, " iteration %i\n", iterations);
2353 FOR_EACH_VEC_ELT (rpo, i, index)
2355 if (m_lattice[index].changed)
2357 size_t j;
2359 m_lattice[index].changed = false;
2360 if (dump_file)
2361 fprintf (dump_file, " Visiting ssa name %i\n", index);
2362 for (j = 0; j < m_lattice[index].propagate_to.length (); j++)
2364 bool ch;
2365 int target = m_lattice[index].propagate_to[j].ssa_name;
2366 bool deref = m_lattice[index].propagate_to[j].deref;
2368 if (dump_file)
2369 fprintf (dump_file, " Propagating flags of ssa name"
2370 " %i to %i%s\n",
2371 index, target, deref ? " (deref)" : "");
2372 m_lattice[target].known = true;
2373 if (!m_lattice[index].propagate_to[j].deref)
2374 ch = m_lattice[target].merge (m_lattice[index]);
2375 else
2376 ch = m_lattice[target].merge_deref (m_lattice[index],
2377 false);
2378 if (!ch)
2379 continue;
2380 if (dump_file)
2382 fprintf (dump_file, " New lattice: ");
2383 m_lattice[target].dump (dump_file);
2385 changed = true;
2386 m_lattice[target].changed = true;
2391 if (dump_file)
2392 fprintf (dump_file, "EAF flags propagated in %i iterations\n", iterations);
2395 /* Record escape points of PARM_INDEX according to LATTICE. */
2397 void
2398 modref_eaf_analysis::record_escape_points (tree name, int parm_index, int flags)
2400 modref_lattice &lattice = m_lattice[SSA_NAME_VERSION (name)];
2402 if (lattice.escape_points.length ())
2404 escape_point *ep;
2405 unsigned int ip;
2406 cgraph_node *node = cgraph_node::get (current_function_decl);
2408 gcc_assert (m_ipa);
2409 FOR_EACH_VEC_ELT (lattice.escape_points, ip, ep)
2410 if ((ep->min_flags & flags) != flags)
2412 cgraph_edge *e = node->get_edge (ep->call);
2413 struct escape_entry ee = {parm_index, ep->arg,
2414 ep->min_flags, ep->direct};
2416 escape_summaries->get_create (e)->esc.safe_push (ee);
2421 /* Determine EAF flags for function parameters
2422 and fill in SUMMARY/SUMMARY_LTO. If IPA is true work in IPA mode
2423 where we also collect scape points.
2424 PAST_FLAGS, PAST_RETSLOT_FLAGS, PAST_STATIC_CHAIN_FLAGS can be
2425 used to preserve flags from prevoius (IPA) run for cases where
2426 late optimizations changed code in a way we can no longer analyze
2427 it easily. */
2429 static void
2430 analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
2431 bool ipa, vec<eaf_flags_t> &past_flags,
2432 int past_retslot_flags, int past_static_chain_flags)
2434 unsigned int parm_index = 0;
2435 unsigned int count = 0;
2436 int ecf_flags = flags_from_decl_or_type (current_function_decl);
2437 tree retslot = NULL;
2438 tree static_chain = NULL;
2440 /* If there is return slot, look up its SSA name. */
2441 if (DECL_RESULT (current_function_decl)
2442 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2443 retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
2444 if (cfun->static_chain_decl)
2445 static_chain = ssa_default_def (cfun, cfun->static_chain_decl);
2447 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2448 parm = TREE_CHAIN (parm))
2449 count++;
2451 if (!count && !retslot && !static_chain)
2452 return;
2454 modref_eaf_analysis eaf_analysis (ipa);
2456 /* Determine all SSA names we need to know flags for. */
2457 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2458 parm = TREE_CHAIN (parm))
2460 tree name = ssa_default_def (cfun, parm);
2461 if (name)
2462 eaf_analysis.analyze_ssa_name (name);
2464 if (retslot)
2465 eaf_analysis.analyze_ssa_name (retslot);
2466 if (static_chain)
2467 eaf_analysis.analyze_ssa_name (static_chain);
2469 /* Do the dataflow. */
2470 eaf_analysis.propagate ();
2472 /* Store results to summaries. */
2473 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
2474 parm = TREE_CHAIN (parm))
2476 tree name = ssa_default_def (cfun, parm);
2477 if (!name || has_zero_uses (name))
2479 /* We do not track non-SSA parameters,
2480 but we want to track unused gimple_regs. */
2481 if (!is_gimple_reg (parm))
2482 continue;
2483 if (summary)
2485 if (parm_index >= summary->arg_flags.length ())
2486 summary->arg_flags.safe_grow_cleared (count, true);
2487 summary->arg_flags[parm_index] = EAF_UNUSED;
2489 else if (summary_lto)
2491 if (parm_index >= summary_lto->arg_flags.length ())
2492 summary_lto->arg_flags.safe_grow_cleared (count, true);
2493 summary_lto->arg_flags[parm_index] = EAF_UNUSED;
2495 continue;
2497 int flags = eaf_analysis.get_ssa_name_flags (name);
2499 /* Eliminate useless flags so we do not end up storing unnecessary
2500 summaries. */
2502 flags = remove_useless_eaf_flags
2503 (flags, ecf_flags,
2504 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
2505 if (past_flags.length () > parm_index)
2507 int past = past_flags[parm_index];
2508 past = remove_useless_eaf_flags
2509 (past, ecf_flags,
2510 VOID_TYPE_P (TREE_TYPE
2511 (TREE_TYPE (current_function_decl))));
2512 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
2514 fprintf (dump_file,
2515 " Flags for param %i combined with IPA pass:",
2516 (int)parm_index);
2517 dump_eaf_flags (dump_file, past, false);
2518 fprintf (dump_file, " local ");
2519 dump_eaf_flags (dump_file, flags | past, true);
2521 if (!(flags & EAF_UNUSED))
2522 flags |= past;
2525 if (flags)
2527 if (summary)
2529 if (parm_index >= summary->arg_flags.length ())
2530 summary->arg_flags.safe_grow_cleared (count, true);
2531 summary->arg_flags[parm_index] = flags;
2533 else if (summary_lto)
2535 if (parm_index >= summary_lto->arg_flags.length ())
2536 summary_lto->arg_flags.safe_grow_cleared (count, true);
2537 summary_lto->arg_flags[parm_index] = flags;
2539 eaf_analysis.record_escape_points (name, parm_index, flags);
2542 if (retslot)
2544 int flags = eaf_analysis.get_ssa_name_flags (retslot);
2545 int past = past_retslot_flags;
2547 flags = remove_useless_eaf_flags (flags, ecf_flags, false);
2548 past = remove_useless_eaf_flags
2549 (past, ecf_flags,
2550 VOID_TYPE_P (TREE_TYPE
2551 (TREE_TYPE (current_function_decl))));
2552 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
2554 fprintf (dump_file,
2555 " Retslot flags combined with IPA pass:");
2556 dump_eaf_flags (dump_file, past, false);
2557 fprintf (dump_file, " local ");
2558 dump_eaf_flags (dump_file, flags, true);
2560 if (!(flags & EAF_UNUSED))
2561 flags |= past;
2562 if (flags)
2564 if (summary)
2565 summary->retslot_flags = flags;
2566 if (summary_lto)
2567 summary_lto->retslot_flags = flags;
2568 eaf_analysis.record_escape_points (retslot,
2569 MODREF_RETSLOT_PARM, flags);
2572 if (static_chain)
2574 int flags = eaf_analysis.get_ssa_name_flags (static_chain);
2575 int past = past_static_chain_flags;
2577 flags = remove_useless_eaf_flags (flags, ecf_flags, false);
2578 past = remove_useless_eaf_flags
2579 (past, ecf_flags,
2580 VOID_TYPE_P (TREE_TYPE
2581 (TREE_TYPE (current_function_decl))));
2582 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
2584 fprintf (dump_file,
2585 " Static chain flags combined with IPA pass:");
2586 dump_eaf_flags (dump_file, past, false);
2587 fprintf (dump_file, " local ");
2588 dump_eaf_flags (dump_file, flags, true);
2590 if (!(flags & EAF_UNUSED))
2591 flags |= past;
2592 if (flags)
2594 if (summary)
2595 summary->static_chain_flags = flags;
2596 if (summary_lto)
2597 summary_lto->static_chain_flags = flags;
2598 eaf_analysis.record_escape_points (static_chain,
2599 MODREF_STATIC_CHAIN_PARM,
2600 flags);
2605 /* Analyze function F. IPA indicates whether we're running in local mode
2606 (false) or the IPA mode (true).
2607 Return true if fixup cfg is needed after the pass. */
2609 static bool
2610 analyze_function (function *f, bool ipa)
2612 bool fixup_cfg = false;
2613 if (dump_file)
2614 fprintf (dump_file, "modref analyzing '%s' (ipa=%i)%s%s\n",
2615 function_name (f), ipa,
2616 TREE_READONLY (current_function_decl) ? " (const)" : "",
2617 DECL_PURE_P (current_function_decl) ? " (pure)" : "");
2619 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
2620 if (!flag_ipa_modref
2621 || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
2622 return false;
2624 /* Compute no-LTO summaries when local optimization is going to happen. */
2625 bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
2626 || (in_lto_p && !flag_wpa
2627 && flag_incremental_link != INCREMENTAL_LINK_LTO));
2628 /* Compute LTO when LTO streaming is going to happen. */
2629 bool lto = ipa && ((flag_lto && !in_lto_p)
2630 || flag_wpa
2631 || flag_incremental_link == INCREMENTAL_LINK_LTO);
2632 cgraph_node *fnode = cgraph_node::get (current_function_decl);
2634 modref_summary *summary = NULL;
2635 modref_summary_lto *summary_lto = NULL;
2637 bool past_flags_known = false;
2638 auto_vec <eaf_flags_t> past_flags;
2639 int past_retslot_flags = 0;
2640 int past_static_chain_flags = 0;
2642 /* Initialize the summary.
2643 If we run in local mode there is possibly pre-existing summary from
2644 IPA pass. Dump it so it is easy to compare if mod-ref info has
2645 improved. */
2646 if (!ipa)
2648 if (!optimization_summaries)
2649 optimization_summaries = modref_summaries::create_ggc (symtab);
2650 else /* Remove existing summary if we are re-running the pass. */
2652 if (dump_file
2653 && (summary
2654 = optimization_summaries->get (cgraph_node::get (f->decl)))
2655 != NULL
2656 && summary->loads)
2658 fprintf (dump_file, "Past summary:\n");
2659 optimization_summaries->get
2660 (cgraph_node::get (f->decl))->dump (dump_file);
2661 past_flags.reserve_exact (summary->arg_flags.length ());
2662 past_flags.splice (summary->arg_flags);
2663 past_retslot_flags = summary->retslot_flags;
2664 past_static_chain_flags = summary->static_chain_flags;
2665 past_flags_known = true;
2667 optimization_summaries->remove (cgraph_node::get (f->decl));
2669 summary = optimization_summaries->get_create (cgraph_node::get (f->decl));
2670 gcc_checking_assert (nolto && !lto);
2672 /* In IPA mode we analyze every function precisely once. Assert that. */
2673 else
2675 if (nolto)
2677 if (!summaries)
2678 summaries = modref_summaries::create_ggc (symtab);
2679 else
2680 summaries->remove (cgraph_node::get (f->decl));
2681 summary = summaries->get_create (cgraph_node::get (f->decl));
2683 if (lto)
2685 if (!summaries_lto)
2686 summaries_lto = modref_summaries_lto::create_ggc (symtab);
2687 else
2688 summaries_lto->remove (cgraph_node::get (f->decl));
2689 summary_lto = summaries_lto->get_create (cgraph_node::get (f->decl));
2691 if (!fnspec_summaries)
2692 fnspec_summaries = new fnspec_summaries_t (symtab);
2693 if (!escape_summaries)
2694 escape_summaries = new escape_summaries_t (symtab);
2698 /* Create and initialize summary for F.
2699 Note that summaries may be already allocated from previous
2700 run of the pass. */
2701 if (nolto)
2703 gcc_assert (!summary->loads);
2704 summary->loads = modref_records::create_ggc (param_modref_max_bases,
2705 param_modref_max_refs,
2706 param_modref_max_accesses);
2707 gcc_assert (!summary->stores);
2708 summary->stores = modref_records::create_ggc (param_modref_max_bases,
2709 param_modref_max_refs,
2710 param_modref_max_accesses);
2711 summary->writes_errno = false;
2712 summary->side_effects = false;
2714 if (lto)
2716 gcc_assert (!summary_lto->loads);
2717 summary_lto->loads = modref_records_lto::create_ggc
2718 (param_modref_max_bases,
2719 param_modref_max_refs,
2720 param_modref_max_accesses);
2721 gcc_assert (!summary_lto->stores);
2722 summary_lto->stores = modref_records_lto::create_ggc
2723 (param_modref_max_bases,
2724 param_modref_max_refs,
2725 param_modref_max_accesses);
2726 summary_lto->writes_errno = false;
2727 summary_lto->side_effects = false;
2730 analyze_parms (summary, summary_lto, ipa,
2731 past_flags, past_retslot_flags, past_static_chain_flags);
2733 int ecf_flags = flags_from_decl_or_type (current_function_decl);
2734 auto_vec <gimple *, 32> recursive_calls;
2736 /* Analyze each statement in each basic block of the function. If the
2737 statement cannot be analyzed (for any reason), the entire function cannot
2738 be analyzed by modref. */
2739 basic_block bb;
2740 FOR_EACH_BB_FN (bb, f)
2742 gimple_stmt_iterator si;
2743 for (si = gsi_start_nondebug_after_labels_bb (bb);
2744 !gsi_end_p (si); gsi_next_nondebug (&si))
2746 if (!analyze_stmt (summary, summary_lto,
2747 gsi_stmt (si), ipa, &recursive_calls)
2748 || ((!summary || !summary->useful_p (ecf_flags, false))
2749 && (!summary_lto
2750 || !summary_lto->useful_p (ecf_flags, false))))
2752 collapse_loads (summary, summary_lto);
2753 collapse_stores (summary, summary_lto);
2754 break;
2759 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2760 This needs to be done after all other side effects are computed. */
2761 if (!ipa)
2763 bool changed = true;
2764 bool first = true;
2765 while (changed)
2767 changed = false;
2768 for (unsigned i = 0; i < recursive_calls.length (); i++)
2770 changed |= merge_call_side_effects
2771 (summary, recursive_calls[i], summary,
2772 ignore_stores_p (current_function_decl,
2773 gimple_call_flags
2774 (recursive_calls[i])),
2775 fnode, !first);
2776 if (!summary->useful_p (ecf_flags, false))
2778 remove_summary (lto, nolto, ipa);
2779 return false;
2782 first = false;
2785 if (summary && !summary->global_memory_written_p () && !summary->side_effects
2786 && !finite_function_p ())
2787 summary->side_effects = true;
2788 if (summary_lto && !summary_lto->side_effects && !finite_function_p ())
2789 summary_lto->side_effects = true;
2791 if (!ipa && flag_ipa_pure_const)
2793 if (!summary->stores->every_base && !summary->stores->bases)
2795 if (!summary->loads->every_base && !summary->loads->bases)
2796 fixup_cfg = ipa_make_function_const
2797 (cgraph_node::get (current_function_decl),
2798 summary->side_effects, true);
2799 else
2800 fixup_cfg = ipa_make_function_pure
2801 (cgraph_node::get (current_function_decl),
2802 summary->side_effects, true);
2805 if (summary && !summary->useful_p (ecf_flags))
2807 if (!ipa)
2808 optimization_summaries->remove (fnode);
2809 else
2810 summaries->remove (fnode);
2811 summary = NULL;
2813 if (summary_lto && !summary_lto->useful_p (ecf_flags))
2815 summaries_lto->remove (fnode);
2816 summary_lto = NULL;
2819 if (ipa && !summary && !summary_lto)
2820 remove_modref_edge_summaries (fnode);
2822 if (dump_file)
2824 fprintf (dump_file, " - modref done with result: tracked.\n");
2825 if (summary)
2826 summary->dump (dump_file);
2827 if (summary_lto)
2828 summary_lto->dump (dump_file);
2829 dump_modref_edge_summaries (dump_file, fnode, 2);
2830 /* To simplify debugging, compare IPA and local solutions. */
2831 if (past_flags_known && summary)
2833 size_t len = summary->arg_flags.length ();
2835 if (past_flags.length () > len)
2836 len = past_flags.length ();
2837 for (size_t i = 0; i < len; i++)
2839 int old_flags = i < past_flags.length () ? past_flags[i] : 0;
2840 int new_flags = i < summary->arg_flags.length ()
2841 ? summary->arg_flags[i] : 0;
2842 old_flags = remove_useless_eaf_flags
2843 (old_flags, flags_from_decl_or_type (current_function_decl),
2844 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
2845 if (old_flags != new_flags)
2847 if ((old_flags & ~new_flags) == 0
2848 || (new_flags & EAF_UNUSED))
2849 fprintf (dump_file, " Flags for param %i improved:",
2850 (int)i);
2851 else
2852 gcc_unreachable ();
2853 dump_eaf_flags (dump_file, old_flags, false);
2854 fprintf (dump_file, " -> ");
2855 dump_eaf_flags (dump_file, new_flags, true);
2858 past_retslot_flags = remove_useless_eaf_flags
2859 (past_retslot_flags,
2860 flags_from_decl_or_type (current_function_decl),
2861 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
2862 if (past_retslot_flags != summary->retslot_flags)
2864 if ((past_retslot_flags & ~summary->retslot_flags) == 0
2865 || (summary->retslot_flags & EAF_UNUSED))
2866 fprintf (dump_file, " Flags for retslot improved:");
2867 else
2868 gcc_unreachable ();
2869 dump_eaf_flags (dump_file, past_retslot_flags, false);
2870 fprintf (dump_file, " -> ");
2871 dump_eaf_flags (dump_file, summary->retslot_flags, true);
2873 past_static_chain_flags = remove_useless_eaf_flags
2874 (past_static_chain_flags,
2875 flags_from_decl_or_type (current_function_decl),
2876 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
2877 if (past_static_chain_flags != summary->static_chain_flags)
2879 if ((past_static_chain_flags & ~summary->static_chain_flags) == 0
2880 || (summary->static_chain_flags & EAF_UNUSED))
2881 fprintf (dump_file, " Flags for static chain improved:");
2882 else
2883 gcc_unreachable ();
2884 dump_eaf_flags (dump_file, past_static_chain_flags, false);
2885 fprintf (dump_file, " -> ");
2886 dump_eaf_flags (dump_file, summary->static_chain_flags, true);
2889 else if (past_flags_known && !summary)
2891 for (size_t i = 0; i < past_flags.length (); i++)
2893 int old_flags = past_flags[i];
2894 old_flags = remove_useless_eaf_flags
2895 (old_flags, flags_from_decl_or_type (current_function_decl),
2896 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
2897 if (old_flags)
2899 fprintf (dump_file, " Flags for param %i worsened:",
2900 (int)i);
2901 dump_eaf_flags (dump_file, old_flags, false);
2902 fprintf (dump_file, " -> \n");
2905 past_retslot_flags = remove_useless_eaf_flags
2906 (past_retslot_flags,
2907 flags_from_decl_or_type (current_function_decl),
2908 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
2909 if (past_retslot_flags)
2911 fprintf (dump_file, " Flags for retslot worsened:");
2912 dump_eaf_flags (dump_file, past_retslot_flags, false);
2913 fprintf (dump_file, " ->\n");
2915 past_static_chain_flags = remove_useless_eaf_flags
2916 (past_static_chain_flags,
2917 flags_from_decl_or_type (current_function_decl),
2918 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
2919 if (past_static_chain_flags)
2921 fprintf (dump_file, " Flags for static chain worsened:");
2922 dump_eaf_flags (dump_file, past_static_chain_flags, false);
2923 fprintf (dump_file, " ->\n");
2927 return fixup_cfg;
2930 /* Callback for generate_summary. */
2932 static void
2933 modref_generate (void)
2935 struct cgraph_node *node;
2936 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
2938 function *f = DECL_STRUCT_FUNCTION (node->decl);
2939 if (!f)
2940 continue;
2941 push_cfun (f);
2942 analyze_function (f, true);
2943 pop_cfun ();
2947 } /* ANON namespace. */
2949 /* Debugging helper. */
2951 void
2952 debug_eaf_flags (int flags)
2954 dump_eaf_flags (stderr, flags, true);
2957 /* Called when a new function is inserted to callgraph late. */
2959 void
2960 modref_summaries::insert (struct cgraph_node *node, modref_summary *)
2962 /* Local passes ought to be executed by the pass manager. */
2963 if (this == optimization_summaries)
2965 optimization_summaries->remove (node);
2966 return;
2968 if (!DECL_STRUCT_FUNCTION (node->decl)
2969 || !opt_for_fn (node->decl, flag_ipa_modref))
2971 summaries->remove (node);
2972 return;
2974 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2975 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2976 pop_cfun ();
2979 /* Called when a new function is inserted to callgraph late. */
2981 void
2982 modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
2984 /* We do not support adding new function when IPA information is already
2985 propagated. This is done only by SIMD cloning that is not very
2986 critical. */
2987 if (!DECL_STRUCT_FUNCTION (node->decl)
2988 || !opt_for_fn (node->decl, flag_ipa_modref)
2989 || propagated)
2991 summaries_lto->remove (node);
2992 return;
2994 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2995 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2996 pop_cfun ();
2999 /* Called when new clone is inserted to callgraph late. */
3001 void
3002 modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
3003 modref_summary *src_data,
3004 modref_summary *dst_data)
3006 /* Do not duplicate optimization summaries; we do not handle parameter
3007 transforms on them. */
3008 if (this == optimization_summaries)
3010 optimization_summaries->remove (dst);
3011 return;
3013 dst_data->stores = modref_records::create_ggc
3014 (src_data->stores->max_bases,
3015 src_data->stores->max_refs,
3016 src_data->stores->max_accesses);
3017 dst_data->stores->copy_from (src_data->stores);
3018 dst_data->loads = modref_records::create_ggc
3019 (src_data->loads->max_bases,
3020 src_data->loads->max_refs,
3021 src_data->loads->max_accesses);
3022 dst_data->loads->copy_from (src_data->loads);
3023 dst_data->writes_errno = src_data->writes_errno;
3024 dst_data->side_effects = src_data->side_effects;
3025 if (src_data->arg_flags.length ())
3026 dst_data->arg_flags = src_data->arg_flags.copy ();
3027 dst_data->retslot_flags = src_data->retslot_flags;
3028 dst_data->static_chain_flags = src_data->static_chain_flags;
3031 /* Called when new clone is inserted to callgraph late. */
3033 void
3034 modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
3035 modref_summary_lto *src_data,
3036 modref_summary_lto *dst_data)
3038 /* Be sure that no further cloning happens after ipa-modref. If it does
3039 we will need to update signatures for possible param changes. */
3040 gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
3041 dst_data->stores = modref_records_lto::create_ggc
3042 (src_data->stores->max_bases,
3043 src_data->stores->max_refs,
3044 src_data->stores->max_accesses);
3045 dst_data->stores->copy_from (src_data->stores);
3046 dst_data->loads = modref_records_lto::create_ggc
3047 (src_data->loads->max_bases,
3048 src_data->loads->max_refs,
3049 src_data->loads->max_accesses);
3050 dst_data->loads->copy_from (src_data->loads);
3051 dst_data->writes_errno = src_data->writes_errno;
3052 dst_data->side_effects = src_data->side_effects;
3053 if (src_data->arg_flags.length ())
3054 dst_data->arg_flags = src_data->arg_flags.copy ();
3055 dst_data->retslot_flags = src_data->retslot_flags;
3056 dst_data->static_chain_flags = src_data->static_chain_flags;
3059 namespace
3061 /* Definition of the modref pass on GIMPLE. */
3062 const pass_data pass_data_modref = {
3063 GIMPLE_PASS,
3064 "modref",
3065 OPTGROUP_IPA,
3066 TV_TREE_MODREF,
3067 (PROP_cfg | PROP_ssa),
3074 class pass_modref : public gimple_opt_pass
3076 public:
3077 pass_modref (gcc::context *ctxt)
3078 : gimple_opt_pass (pass_data_modref, ctxt) {}
3080 /* opt_pass methods: */
3081 opt_pass *clone ()
3083 return new pass_modref (m_ctxt);
3085 virtual bool gate (function *)
3087 return flag_ipa_modref;
3089 virtual unsigned int execute (function *);
3092 /* Encode TT to the output block OB using the summary streaming API. */
3094 static void
3095 write_modref_records (modref_records_lto *tt, struct output_block *ob)
3097 streamer_write_uhwi (ob, tt->max_bases);
3098 streamer_write_uhwi (ob, tt->max_refs);
3099 streamer_write_uhwi (ob, tt->max_accesses);
3101 streamer_write_uhwi (ob, tt->every_base);
3102 streamer_write_uhwi (ob, vec_safe_length (tt->bases));
3103 size_t i;
3104 modref_base_node <tree> *base_node;
3105 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, base_node)
3107 stream_write_tree (ob, base_node->base, true);
3109 streamer_write_uhwi (ob, base_node->every_ref);
3110 streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
3112 size_t j;
3113 modref_ref_node <tree> *ref_node;
3114 FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
3116 stream_write_tree (ob, ref_node->ref, true);
3117 streamer_write_uhwi (ob, ref_node->every_access);
3118 streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
3120 size_t k;
3121 modref_access_node *access_node;
3122 FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
3124 streamer_write_hwi (ob, access_node->parm_index);
3125 if (access_node->parm_index != -1)
3127 streamer_write_uhwi (ob, access_node->parm_offset_known);
3128 if (access_node->parm_offset_known)
3130 streamer_write_poly_int64 (ob, access_node->parm_offset);
3131 streamer_write_poly_int64 (ob, access_node->offset);
3132 streamer_write_poly_int64 (ob, access_node->size);
3133 streamer_write_poly_int64 (ob, access_node->max_size);
3141 /* Read a modref_tree from the input block IB using the data from DATA_IN.
3142 This assumes that the tree was encoded using write_modref_tree.
3143 Either nolto_ret or lto_ret is initialized by the tree depending whether
3144 LTO streaming is expected or not. */
3146 static void
3147 read_modref_records (lto_input_block *ib, struct data_in *data_in,
3148 modref_records **nolto_ret,
3149 modref_records_lto **lto_ret)
3151 size_t max_bases = streamer_read_uhwi (ib);
3152 size_t max_refs = streamer_read_uhwi (ib);
3153 size_t max_accesses = streamer_read_uhwi (ib);
3155 if (lto_ret)
3156 *lto_ret = modref_records_lto::create_ggc (max_bases, max_refs,
3157 max_accesses);
3158 if (nolto_ret)
3159 *nolto_ret = modref_records::create_ggc (max_bases, max_refs,
3160 max_accesses);
3161 gcc_checking_assert (lto_ret || nolto_ret);
3163 size_t every_base = streamer_read_uhwi (ib);
3164 size_t nbase = streamer_read_uhwi (ib);
3166 gcc_assert (!every_base || nbase == 0);
3167 if (every_base)
3169 if (nolto_ret)
3170 (*nolto_ret)->collapse ();
3171 if (lto_ret)
3172 (*lto_ret)->collapse ();
3174 for (size_t i = 0; i < nbase; i++)
3176 tree base_tree = stream_read_tree (ib, data_in);
3177 modref_base_node <alias_set_type> *nolto_base_node = NULL;
3178 modref_base_node <tree> *lto_base_node = NULL;
3180 /* At stream in time we have LTO alias info. Check if we streamed in
3181 something obviously unnecessary. Do not glob types by alias sets;
3182 it is not 100% clear that ltrans types will get merged same way.
3183 Types may get refined based on ODR type conflicts. */
3184 if (base_tree && !get_alias_set (base_tree))
3186 if (dump_file)
3188 fprintf (dump_file, "Streamed in alias set 0 type ");
3189 print_generic_expr (dump_file, base_tree);
3190 fprintf (dump_file, "\n");
3192 base_tree = NULL;
3195 if (nolto_ret)
3196 nolto_base_node = (*nolto_ret)->insert_base (base_tree
3197 ? get_alias_set (base_tree)
3198 : 0, 0);
3199 if (lto_ret)
3200 lto_base_node = (*lto_ret)->insert_base (base_tree, 0);
3201 size_t every_ref = streamer_read_uhwi (ib);
3202 size_t nref = streamer_read_uhwi (ib);
3204 gcc_assert (!every_ref || nref == 0);
3205 if (every_ref)
3207 if (nolto_base_node)
3208 nolto_base_node->collapse ();
3209 if (lto_base_node)
3210 lto_base_node->collapse ();
3212 for (size_t j = 0; j < nref; j++)
3214 tree ref_tree = stream_read_tree (ib, data_in);
3216 if (ref_tree && !get_alias_set (ref_tree))
3218 if (dump_file)
3220 fprintf (dump_file, "Streamed in alias set 0 type ");
3221 print_generic_expr (dump_file, ref_tree);
3222 fprintf (dump_file, "\n");
3224 ref_tree = NULL;
3227 modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
3228 modref_ref_node <tree> *lto_ref_node = NULL;
3230 if (nolto_base_node)
3231 nolto_ref_node
3232 = nolto_base_node->insert_ref (ref_tree
3233 ? get_alias_set (ref_tree) : 0,
3234 max_refs);
3235 if (lto_base_node)
3236 lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
3238 size_t every_access = streamer_read_uhwi (ib);
3239 size_t naccesses = streamer_read_uhwi (ib);
3241 if (nolto_ref_node)
3242 nolto_ref_node->every_access = every_access;
3243 if (lto_ref_node)
3244 lto_ref_node->every_access = every_access;
3246 for (size_t k = 0; k < naccesses; k++)
3248 int parm_index = streamer_read_hwi (ib);
3249 bool parm_offset_known = false;
3250 poly_int64 parm_offset = 0;
3251 poly_int64 offset = 0;
3252 poly_int64 size = -1;
3253 poly_int64 max_size = -1;
3255 if (parm_index != -1)
3257 parm_offset_known = streamer_read_uhwi (ib);
3258 if (parm_offset_known)
3260 parm_offset = streamer_read_poly_int64 (ib);
3261 offset = streamer_read_poly_int64 (ib);
3262 size = streamer_read_poly_int64 (ib);
3263 max_size = streamer_read_poly_int64 (ib);
3266 modref_access_node a = {offset, size, max_size, parm_offset,
3267 parm_index, parm_offset_known, false};
3268 if (nolto_ref_node)
3269 nolto_ref_node->insert_access (a, max_accesses, false);
3270 if (lto_ref_node)
3271 lto_ref_node->insert_access (a, max_accesses, false);
3275 if (lto_ret)
3276 (*lto_ret)->cleanup ();
3277 if (nolto_ret)
3278 (*nolto_ret)->cleanup ();
3281 /* Write ESUM to BP. */
3283 static void
3284 modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
3286 if (!esum)
3288 bp_pack_var_len_unsigned (bp, 0);
3289 return;
3291 bp_pack_var_len_unsigned (bp, esum->esc.length ());
3292 unsigned int i;
3293 escape_entry *ee;
3294 FOR_EACH_VEC_ELT (esum->esc, i, ee)
3296 bp_pack_var_len_int (bp, ee->parm_index);
3297 bp_pack_var_len_unsigned (bp, ee->arg);
3298 bp_pack_var_len_unsigned (bp, ee->min_flags);
3299 bp_pack_value (bp, ee->direct, 1);
3303 /* Read escape summary for E from BP. */
3305 static void
3306 modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
3308 unsigned int n = bp_unpack_var_len_unsigned (bp);
3309 if (!n)
3310 return;
3311 escape_summary *esum = escape_summaries->get_create (e);
3312 esum->esc.reserve_exact (n);
3313 for (unsigned int i = 0; i < n; i++)
3315 escape_entry ee;
3316 ee.parm_index = bp_unpack_var_len_int (bp);
3317 ee.arg = bp_unpack_var_len_unsigned (bp);
3318 ee.min_flags = bp_unpack_var_len_unsigned (bp);
3319 ee.direct = bp_unpack_value (bp, 1);
3320 esum->esc.quick_push (ee);
3324 /* Callback for write_summary. */
3326 static void
3327 modref_write ()
3329 struct output_block *ob = create_output_block (LTO_section_ipa_modref);
3330 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
3331 unsigned int count = 0;
3332 int i;
3334 if (!summaries_lto)
3336 streamer_write_uhwi (ob, 0);
3337 streamer_write_char_stream (ob->main_stream, 0);
3338 produce_asm (ob, NULL);
3339 destroy_output_block (ob);
3340 return;
3343 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3345 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3346 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3347 modref_summary_lto *r;
3349 if (cnode && cnode->definition && !cnode->alias
3350 && (r = summaries_lto->get (cnode))
3351 && r->useful_p (flags_from_decl_or_type (cnode->decl)))
3352 count++;
3354 streamer_write_uhwi (ob, count);
3356 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3358 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3359 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3361 if (cnode && cnode->definition && !cnode->alias)
3363 modref_summary_lto *r = summaries_lto->get (cnode);
3365 if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
3366 continue;
3368 streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
3370 streamer_write_uhwi (ob, r->arg_flags.length ());
3371 for (unsigned int i = 0; i < r->arg_flags.length (); i++)
3372 streamer_write_uhwi (ob, r->arg_flags[i]);
3373 streamer_write_uhwi (ob, r->retslot_flags);
3374 streamer_write_uhwi (ob, r->static_chain_flags);
3376 write_modref_records (r->loads, ob);
3377 write_modref_records (r->stores, ob);
3379 struct bitpack_d bp = bitpack_create (ob->main_stream);
3380 bp_pack_value (&bp, r->writes_errno, 1);
3381 bp_pack_value (&bp, r->side_effects, 1);
3382 if (!flag_wpa)
3384 for (cgraph_edge *e = cnode->indirect_calls;
3385 e; e = e->next_callee)
3387 class fnspec_summary *sum = fnspec_summaries->get (e);
3388 bp_pack_value (&bp, sum != NULL, 1);
3389 if (sum)
3390 bp_pack_string (ob, &bp, sum->fnspec, true);
3391 class escape_summary *esum = escape_summaries->get (e);
3392 modref_write_escape_summary (&bp,esum);
3394 for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
3396 class fnspec_summary *sum = fnspec_summaries->get (e);
3397 bp_pack_value (&bp, sum != NULL, 1);
3398 if (sum)
3399 bp_pack_string (ob, &bp, sum->fnspec, true);
3400 class escape_summary *esum = escape_summaries->get (e);
3401 modref_write_escape_summary (&bp,esum);
3404 streamer_write_bitpack (&bp);
3407 streamer_write_char_stream (ob->main_stream, 0);
3408 produce_asm (ob, NULL);
3409 destroy_output_block (ob);
3412 static void
3413 read_section (struct lto_file_decl_data *file_data, const char *data,
3414 size_t len)
3416 const struct lto_function_header *header
3417 = (const struct lto_function_header *) data;
3418 const int cfg_offset = sizeof (struct lto_function_header);
3419 const int main_offset = cfg_offset + header->cfg_size;
3420 const int string_offset = main_offset + header->main_size;
3421 struct data_in *data_in;
3422 unsigned int i;
3423 unsigned int f_count;
3425 lto_input_block ib ((const char *) data + main_offset, header->main_size,
3426 file_data->mode_table);
3428 data_in
3429 = lto_data_in_create (file_data, (const char *) data + string_offset,
3430 header->string_size, vNULL);
3431 f_count = streamer_read_uhwi (&ib);
3432 for (i = 0; i < f_count; i++)
3434 struct cgraph_node *node;
3435 lto_symtab_encoder_t encoder;
3437 unsigned int index = streamer_read_uhwi (&ib);
3438 encoder = file_data->symtab_node_encoder;
3439 node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
3440 index));
3442 modref_summary *modref_sum = summaries
3443 ? summaries->get_create (node) : NULL;
3444 modref_summary_lto *modref_sum_lto = summaries_lto
3445 ? summaries_lto->get_create (node)
3446 : NULL;
3447 if (optimization_summaries)
3448 modref_sum = optimization_summaries->get_create (node);
3450 if (modref_sum)
3452 modref_sum->writes_errno = false;
3453 modref_sum->side_effects = false;
3455 if (modref_sum_lto)
3457 modref_sum_lto->writes_errno = false;
3458 modref_sum_lto->side_effects = false;
3461 gcc_assert (!modref_sum || (!modref_sum->loads
3462 && !modref_sum->stores));
3463 gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
3464 && !modref_sum_lto->stores));
3465 unsigned int args = streamer_read_uhwi (&ib);
3466 if (args && modref_sum)
3467 modref_sum->arg_flags.reserve_exact (args);
3468 if (args && modref_sum_lto)
3469 modref_sum_lto->arg_flags.reserve_exact (args);
3470 for (unsigned int i = 0; i < args; i++)
3472 eaf_flags_t flags = streamer_read_uhwi (&ib);
3473 if (modref_sum)
3474 modref_sum->arg_flags.quick_push (flags);
3475 if (modref_sum_lto)
3476 modref_sum_lto->arg_flags.quick_push (flags);
3478 eaf_flags_t flags = streamer_read_uhwi (&ib);
3479 if (modref_sum)
3480 modref_sum->retslot_flags = flags;
3481 if (modref_sum_lto)
3482 modref_sum_lto->retslot_flags = flags;
3484 flags = streamer_read_uhwi (&ib);
3485 if (modref_sum)
3486 modref_sum->static_chain_flags = flags;
3487 if (modref_sum_lto)
3488 modref_sum_lto->static_chain_flags = flags;
3490 read_modref_records (&ib, data_in,
3491 modref_sum ? &modref_sum->loads : NULL,
3492 modref_sum_lto ? &modref_sum_lto->loads : NULL);
3493 read_modref_records (&ib, data_in,
3494 modref_sum ? &modref_sum->stores : NULL,
3495 modref_sum_lto ? &modref_sum_lto->stores : NULL);
3496 struct bitpack_d bp = streamer_read_bitpack (&ib);
3497 if (bp_unpack_value (&bp, 1))
3499 if (modref_sum)
3500 modref_sum->writes_errno = true;
3501 if (modref_sum_lto)
3502 modref_sum_lto->writes_errno = true;
3504 if (bp_unpack_value (&bp, 1))
3506 if (modref_sum)
3507 modref_sum->side_effects = true;
3508 if (modref_sum_lto)
3509 modref_sum_lto->side_effects = true;
3511 if (!flag_ltrans)
3513 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
3515 if (bp_unpack_value (&bp, 1))
3517 class fnspec_summary *sum = fnspec_summaries->get_create (e);
3518 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3520 modref_read_escape_summary (&bp, e);
3522 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3524 if (bp_unpack_value (&bp, 1))
3526 class fnspec_summary *sum = fnspec_summaries->get_create (e);
3527 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3529 modref_read_escape_summary (&bp, e);
3532 if (dump_file)
3534 fprintf (dump_file, "Read modref for %s\n",
3535 node->dump_name ());
3536 if (modref_sum)
3537 modref_sum->dump (dump_file);
3538 if (modref_sum_lto)
3539 modref_sum_lto->dump (dump_file);
3540 dump_modref_edge_summaries (dump_file, node, 4);
3544 lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
3545 len);
3546 lto_data_in_delete (data_in);
3549 /* Callback for read_summary. */
3551 static void
3552 modref_read (void)
3554 struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
3555 struct lto_file_decl_data *file_data;
3556 unsigned int j = 0;
3558 gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
3559 if (flag_ltrans)
3560 optimization_summaries = modref_summaries::create_ggc (symtab);
3561 else
3563 if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
3564 summaries_lto = modref_summaries_lto::create_ggc (symtab);
3565 if (!flag_wpa
3566 || (flag_incremental_link == INCREMENTAL_LINK_LTO
3567 && flag_fat_lto_objects))
3568 summaries = modref_summaries::create_ggc (symtab);
3569 if (!fnspec_summaries)
3570 fnspec_summaries = new fnspec_summaries_t (symtab);
3571 if (!escape_summaries)
3572 escape_summaries = new escape_summaries_t (symtab);
3575 while ((file_data = file_data_vec[j++]))
3577 size_t len;
3578 const char *data = lto_get_summary_section_data (file_data,
3579 LTO_section_ipa_modref,
3580 &len);
3581 if (data)
3582 read_section (file_data, data, len);
3583 else
3584 /* Fatal error here. We do not want to support compiling ltrans units
3585 with different version of compiler or different flags than the WPA
3586 unit, so this should never happen. */
3587 fatal_error (input_location,
3588 "IPA modref summary is missing in input file");
3592 /* Recompute arg_flags for param adjustments in INFO. */
3594 static void
3595 remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
3597 auto_vec<eaf_flags_t> old = arg_flags.copy ();
3598 int max = -1;
3599 size_t i;
3600 ipa_adjusted_param *p;
3602 arg_flags.release ();
3604 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
3606 int o = info->param_adjustments->get_original_index (i);
3607 if (o >= 0 && (int)old.length () > o && old[o])
3608 max = i;
3610 if (max >= 0)
3611 arg_flags.safe_grow_cleared (max + 1, true);
3612 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
3614 int o = info->param_adjustments->get_original_index (i);
3615 if (o >= 0 && (int)old.length () > o && old[o])
3616 arg_flags[i] = old[o];
3620 /* If signature changed, update the summary. */
3622 static void
3623 update_signature (struct cgraph_node *node)
3625 clone_info *info = clone_info::get (node);
3626 if (!info || !info->param_adjustments)
3627 return;
3629 modref_summary *r = optimization_summaries
3630 ? optimization_summaries->get (node) : NULL;
3631 modref_summary_lto *r_lto = summaries_lto
3632 ? summaries_lto->get (node) : NULL;
3633 if (!r && !r_lto)
3634 return;
3635 if (dump_file)
3637 fprintf (dump_file, "Updating summary for %s from:\n",
3638 node->dump_name ());
3639 if (r)
3640 r->dump (dump_file);
3641 if (r_lto)
3642 r_lto->dump (dump_file);
3645 size_t i, max = 0;
3646 ipa_adjusted_param *p;
3648 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
3650 int idx = info->param_adjustments->get_original_index (i);
3651 if (idx > (int)max)
3652 max = idx;
3655 auto_vec <int, 32> map;
3657 map.reserve (max + 1);
3658 for (i = 0; i <= max; i++)
3659 map.quick_push (MODREF_UNKNOWN_PARM);
3660 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
3662 int idx = info->param_adjustments->get_original_index (i);
3663 if (idx >= 0)
3664 map[idx] = i;
3666 if (r)
3668 r->loads->remap_params (&map);
3669 r->stores->remap_params (&map);
3670 if (r->arg_flags.length ())
3671 remap_arg_flags (r->arg_flags, info);
3673 if (r_lto)
3675 r_lto->loads->remap_params (&map);
3676 r_lto->stores->remap_params (&map);
3677 if (r_lto->arg_flags.length ())
3678 remap_arg_flags (r_lto->arg_flags, info);
3680 if (dump_file)
3682 fprintf (dump_file, "to:\n");
3683 if (r)
3684 r->dump (dump_file);
3685 if (r_lto)
3686 r_lto->dump (dump_file);
3688 return;
3691 /* Definition of the modref IPA pass. */
3692 const pass_data pass_data_ipa_modref =
3694 IPA_PASS, /* type */
3695 "modref", /* name */
3696 OPTGROUP_IPA, /* optinfo_flags */
3697 TV_IPA_MODREF, /* tv_id */
3698 0, /* properties_required */
3699 0, /* properties_provided */
3700 0, /* properties_destroyed */
3701 0, /* todo_flags_start */
3702 ( TODO_dump_symtab ), /* todo_flags_finish */
3705 class pass_ipa_modref : public ipa_opt_pass_d
3707 public:
3708 pass_ipa_modref (gcc::context *ctxt)
3709 : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
3710 modref_generate, /* generate_summary */
3711 modref_write, /* write_summary */
3712 modref_read, /* read_summary */
3713 modref_write, /* write_optimization_summary */
3714 modref_read, /* read_optimization_summary */
3715 NULL, /* stmt_fixup */
3716 0, /* function_transform_todo_flags_start */
3717 NULL, /* function_transform */
3718 NULL) /* variable_transform */
3721 /* opt_pass methods: */
3722 opt_pass *clone () { return new pass_ipa_modref (m_ctxt); }
3723 virtual bool gate (function *)
3725 return true;
3727 virtual unsigned int execute (function *);
3733 unsigned int pass_modref::execute (function *f)
3735 if (analyze_function (f, false))
3736 return execute_fixup_cfg ();
3737 return 0;
3740 gimple_opt_pass *
3741 make_pass_modref (gcc::context *ctxt)
3743 return new pass_modref (ctxt);
3746 ipa_opt_pass_d *
3747 make_pass_ipa_modref (gcc::context *ctxt)
3749 return new pass_ipa_modref (ctxt);
3752 namespace {
3754 /* Skip edges from and to nodes without ipa_pure_const enabled.
3755 Ignore not available symbols. */
3757 static bool
3758 ignore_edge (struct cgraph_edge *e)
3760 /* We merge summaries of inline clones into summaries of functions they
3761 are inlined to. For that reason the complete function bodies must
3762 act as unit. */
3763 if (!e->inline_failed)
3764 return false;
3765 enum availability avail;
3766 cgraph_node *callee = e->callee->function_or_virtual_thunk_symbol
3767 (&avail, e->caller);
3769 return (avail <= AVAIL_INTERPOSABLE
3770 || ((!optimization_summaries || !optimization_summaries->get (callee))
3771 && (!summaries_lto || !summaries_lto->get (callee))));
3774 /* Compute parm_map for CALLEE_EDGE. */
3776 static bool
3777 compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
3779 class ipa_edge_args *args;
3780 if (ipa_node_params_sum
3781 && !callee_edge->call_stmt_cannot_inline_p
3782 && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
3784 int i, count = ipa_get_cs_argument_count (args);
3785 class ipa_node_params *caller_parms_info, *callee_pi;
3786 class ipa_call_summary *es
3787 = ipa_call_summaries->get (callee_edge);
3788 cgraph_node *callee
3789 = callee_edge->callee->function_or_virtual_thunk_symbol
3790 (NULL, callee_edge->caller);
3792 caller_parms_info
3793 = ipa_node_params_sum->get (callee_edge->caller->inlined_to
3794 ? callee_edge->caller->inlined_to
3795 : callee_edge->caller);
3796 callee_pi = ipa_node_params_sum->get (callee);
3798 (*parm_map).safe_grow_cleared (count, true);
3800 for (i = 0; i < count; i++)
3802 if (es && es->param[i].points_to_local_or_readonly_memory)
3804 (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
3805 continue;
3808 struct ipa_jump_func *jf
3809 = ipa_get_ith_jump_func (args, i);
3810 if (jf && callee_pi)
3812 tree cst = ipa_value_from_jfunc (caller_parms_info,
3814 ipa_get_type
3815 (callee_pi, i));
3816 if (cst && points_to_local_or_readonly_memory_p (cst))
3818 (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
3819 continue;
3822 if (jf && jf->type == IPA_JF_PASS_THROUGH)
3824 (*parm_map)[i].parm_index
3825 = ipa_get_jf_pass_through_formal_id (jf);
3826 if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
3828 (*parm_map)[i].parm_offset_known = true;
3829 (*parm_map)[i].parm_offset = 0;
3831 else if (ipa_get_jf_pass_through_operation (jf)
3832 == POINTER_PLUS_EXPR
3833 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
3834 &(*parm_map)[i].parm_offset))
3835 (*parm_map)[i].parm_offset_known = true;
3836 else
3837 (*parm_map)[i].parm_offset_known = false;
3838 continue;
3840 if (jf && jf->type == IPA_JF_ANCESTOR)
3842 (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
3843 (*parm_map)[i].parm_offset_known = true;
3844 gcc_checking_assert
3845 (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
3846 (*parm_map)[i].parm_offset
3847 = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
3849 else
3850 (*parm_map)[i].parm_index = -1;
3852 if (dump_file)
3854 fprintf (dump_file, " Parm map: ");
3855 for (i = 0; i < count; i++)
3856 fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
3857 fprintf (dump_file, "\n");
3859 return true;
3861 return false;
3864 /* Map used to translate escape infos. */
3866 struct escape_map
3868 int parm_index;
3869 bool direct;
3872 /* Update escape map for E. */
3874 static void
3875 update_escape_summary_1 (cgraph_edge *e,
3876 vec <vec <escape_map>> &map,
3877 bool ignore_stores)
3879 escape_summary *sum = escape_summaries->get (e);
3880 if (!sum)
3881 return;
3882 auto_vec <escape_entry> old = sum->esc.copy ();
3883 sum->esc.release ();
3885 unsigned int i;
3886 escape_entry *ee;
3887 FOR_EACH_VEC_ELT (old, i, ee)
3889 unsigned int j;
3890 struct escape_map *em;
3891 /* TODO: We do not have jump functions for return slots, so we
3892 never propagate them to outer function. */
3893 if (ee->parm_index >= (int)map.length ()
3894 || ee->parm_index < 0)
3895 continue;
3896 FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
3898 int min_flags = ee->min_flags;
3899 if (ee->direct && !em->direct)
3900 min_flags = deref_flags (min_flags, ignore_stores);
3901 struct escape_entry entry = {em->parm_index, ee->arg,
3902 ee->min_flags,
3903 ee->direct & em->direct};
3904 sum->esc.safe_push (entry);
3907 if (!sum->esc.length ())
3908 escape_summaries->remove (e);
3911 /* Update escape map fo NODE. */
3913 static void
3914 update_escape_summary (cgraph_node *node,
3915 vec <vec <escape_map>> &map,
3916 bool ignore_stores)
3918 if (!escape_summaries)
3919 return;
3920 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
3921 update_escape_summary_1 (e, map, ignore_stores);
3922 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3924 if (!e->inline_failed)
3925 update_escape_summary (e->callee, map, ignore_stores);
3926 else
3927 update_escape_summary_1 (e, map, ignore_stores);
3931 /* Get parameter type from DECL. This is only safe for special cases
3932 like builtins we create fnspec for because the type match is checked
3933 at fnspec creation time. */
3935 static tree
3936 get_parm_type (tree decl, unsigned int i)
3938 tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
3940 for (unsigned int p = 0; p < i; p++)
3941 t = TREE_CHAIN (t);
3942 return TREE_VALUE (t);
3945 /* Return access mode for argument I of call E with FNSPEC. */
3947 static modref_access_node
3948 get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
3949 unsigned int i, modref_parm_map &map)
3951 tree size = NULL_TREE;
3952 unsigned int size_arg;
3954 if (!fnspec.arg_specified_p (i))
3956 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
3958 cgraph_node *node = e->caller->inlined_to
3959 ? e->caller->inlined_to : e->caller;
3960 ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
3961 ipa_edge_args *args = ipa_edge_args_sum->get (e);
3962 struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
3964 if (jf)
3965 size = ipa_value_from_jfunc (caller_parms_info, jf,
3966 get_parm_type (e->callee->decl, size_arg));
3968 else if (fnspec.arg_access_size_given_by_type_p (i))
3969 size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
3970 modref_access_node a = {0, -1, -1,
3971 map.parm_offset, map.parm_index,
3972 map.parm_offset_known, 0};
3973 poly_int64 size_hwi;
3974 if (size
3975 && poly_int_tree_p (size, &size_hwi)
3976 && coeffs_in_range_p (size_hwi, 0,
3977 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
3979 a.size = -1;
3980 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
3982 return a;
3985 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
3986 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
3988 static bool
3989 propagate_unknown_call (cgraph_node *node,
3990 cgraph_edge *e, int ecf_flags,
3991 modref_summary *cur_summary,
3992 modref_summary_lto *cur_summary_lto,
3993 bool nontrivial_scc)
3995 bool changed = false;
3996 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
3997 auto_vec <modref_parm_map, 32> parm_map;
3998 bool looping;
4000 if (e->callee
4001 && builtin_safe_for_const_function_p (&looping, e->callee->decl))
4003 if (looping && cur_summary && !cur_summary->side_effects)
4005 cur_summary->side_effects = true;
4006 changed = true;
4008 if (looping && cur_summary_lto && !cur_summary_lto->side_effects)
4010 cur_summary_lto->side_effects = true;
4011 changed = true;
4013 return changed;
4016 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE))
4017 || (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
4018 || nontrivial_scc)
4020 if (cur_summary && !cur_summary->side_effects)
4022 cur_summary->side_effects = true;
4023 changed = true;
4025 if (cur_summary_lto && !cur_summary_lto->side_effects)
4027 cur_summary_lto->side_effects = true;
4028 changed = true;
4031 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
4032 return changed;
4034 if (fnspec_sum
4035 && compute_parm_map (e, &parm_map))
4037 attr_fnspec fnspec (fnspec_sum->fnspec);
4039 gcc_checking_assert (fnspec.known_p ());
4040 if (fnspec.global_memory_read_p ())
4041 collapse_loads (cur_summary, cur_summary_lto);
4042 else
4044 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4045 for (unsigned i = 0; i < parm_map.length () && t;
4046 i++, t = TREE_CHAIN (t))
4047 if (!POINTER_TYPE_P (TREE_VALUE (t)))
4049 else if (!fnspec.arg_specified_p (i)
4050 || fnspec.arg_maybe_read_p (i))
4052 modref_parm_map map = parm_map[i];
4053 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4054 continue;
4055 if (map.parm_index == MODREF_UNKNOWN_PARM)
4057 collapse_loads (cur_summary, cur_summary_lto);
4058 break;
4060 if (cur_summary)
4061 changed |= cur_summary->loads->insert
4062 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
4063 if (cur_summary_lto)
4064 changed |= cur_summary_lto->loads->insert
4065 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
4068 if (ignore_stores_p (node->decl, ecf_flags))
4070 else if (fnspec.global_memory_written_p ())
4071 collapse_stores (cur_summary, cur_summary_lto);
4072 else
4074 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4075 for (unsigned i = 0; i < parm_map.length () && t;
4076 i++, t = TREE_CHAIN (t))
4077 if (!POINTER_TYPE_P (TREE_VALUE (t)))
4079 else if (!fnspec.arg_specified_p (i)
4080 || fnspec.arg_maybe_written_p (i))
4082 modref_parm_map map = parm_map[i];
4083 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4084 continue;
4085 if (map.parm_index == MODREF_UNKNOWN_PARM)
4087 collapse_stores (cur_summary, cur_summary_lto);
4088 break;
4090 if (cur_summary)
4091 changed |= cur_summary->stores->insert
4092 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
4093 if (cur_summary_lto)
4094 changed |= cur_summary_lto->stores->insert
4095 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
4098 if (fnspec.errno_maybe_written_p () && flag_errno_math)
4100 if (cur_summary && !cur_summary->writes_errno)
4102 cur_summary->writes_errno = true;
4103 changed = true;
4105 if (cur_summary_lto && !cur_summary_lto->writes_errno)
4107 cur_summary_lto->writes_errno = true;
4108 changed = true;
4111 return changed;
4113 if (dump_file)
4114 fprintf (dump_file, " collapsing loads\n");
4115 changed |= collapse_loads (cur_summary, cur_summary_lto);
4116 if (!ignore_stores_p (node->decl, ecf_flags))
4118 if (dump_file)
4119 fprintf (dump_file, " collapsing stores\n");
4120 changed |= collapse_stores (cur_summary, cur_summary_lto);
4122 return changed;
4125 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
4126 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
4128 static void
4129 remove_useless_summaries (cgraph_node *node,
4130 modref_summary **cur_summary_ptr,
4131 modref_summary_lto **cur_summary_lto_ptr,
4132 int ecf_flags)
4134 if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
4136 optimization_summaries->remove (node);
4137 *cur_summary_ptr = NULL;
4139 if (*cur_summary_lto_ptr
4140 && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
4142 summaries_lto->remove (node);
4143 *cur_summary_lto_ptr = NULL;
4147 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4148 and propagate loads/stores. */
4150 static bool
4151 modref_propagate_in_scc (cgraph_node *component_node)
4153 bool changed = true;
4154 bool first = true;
4155 int iteration = 0;
4157 while (changed)
4159 bool nontrivial_scc
4160 = ((struct ipa_dfs_info *) component_node->aux)->next_cycle;
4161 changed = false;
4162 for (struct cgraph_node *cur = component_node; cur;
4163 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4165 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
4166 modref_summary *cur_summary = optimization_summaries
4167 ? optimization_summaries->get (node)
4168 : NULL;
4169 modref_summary_lto *cur_summary_lto = summaries_lto
4170 ? summaries_lto->get (node)
4171 : NULL;
4173 if (!cur_summary && !cur_summary_lto)
4174 continue;
4176 int cur_ecf_flags = flags_from_decl_or_type (node->decl);
4178 if (dump_file)
4179 fprintf (dump_file, " Processing %s%s%s\n",
4180 cur->dump_name (),
4181 TREE_READONLY (cur->decl) ? " (const)" : "",
4182 DECL_PURE_P (cur->decl) ? " (pure)" : "");
4184 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
4186 if (dump_file)
4187 fprintf (dump_file, " Indirect call\n");
4188 if (propagate_unknown_call
4189 (node, e, e->indirect_info->ecf_flags,
4190 cur_summary, cur_summary_lto,
4191 nontrivial_scc))
4193 changed = true;
4194 remove_useless_summaries (node, &cur_summary,
4195 &cur_summary_lto,
4196 cur_ecf_flags);
4197 if (!cur_summary && !cur_summary_lto)
4198 break;
4202 if (!cur_summary && !cur_summary_lto)
4203 continue;
4205 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
4206 callee_edge = callee_edge->next_callee)
4208 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
4209 modref_summary *callee_summary = NULL;
4210 modref_summary_lto *callee_summary_lto = NULL;
4211 struct cgraph_node *callee;
4213 if (!callee_edge->inline_failed
4214 || ((flags & (ECF_CONST | ECF_NOVOPS))
4215 && !(flags & ECF_LOOPING_CONST_OR_PURE)))
4216 continue;
4218 /* Get the callee and its summary. */
4219 enum availability avail;
4220 callee = callee_edge->callee->function_or_virtual_thunk_symbol
4221 (&avail, cur);
4223 /* It is not necessary to re-process calls outside of the
4224 SCC component. */
4225 if (iteration > 0
4226 && (!callee->aux
4227 || ((struct ipa_dfs_info *)cur->aux)->scc_no
4228 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
4229 continue;
4231 if (dump_file)
4232 fprintf (dump_file, " Call to %s\n",
4233 callee_edge->callee->dump_name ());
4235 bool ignore_stores = ignore_stores_p (cur->decl, flags);
4237 if (avail <= AVAIL_INTERPOSABLE)
4239 if (dump_file)
4240 fprintf (dump_file, " Call target interposable"
4241 " or not available\n");
4242 changed |= propagate_unknown_call
4243 (node, callee_edge, flags,
4244 cur_summary, cur_summary_lto,
4245 nontrivial_scc);
4246 if (!cur_summary && !cur_summary_lto)
4247 break;
4248 continue;
4251 /* We don't know anything about CALLEE, hence we cannot tell
4252 anything about the entire component. */
4254 if (cur_summary
4255 && !(callee_summary = optimization_summaries->get (callee)))
4257 if (dump_file)
4258 fprintf (dump_file, " No call target summary\n");
4259 changed |= propagate_unknown_call
4260 (node, callee_edge, flags,
4261 cur_summary, NULL,
4262 nontrivial_scc);
4264 if (cur_summary_lto
4265 && !(callee_summary_lto = summaries_lto->get (callee)))
4267 if (dump_file)
4268 fprintf (dump_file, " No call target summary\n");
4269 changed |= propagate_unknown_call
4270 (node, callee_edge, flags,
4271 NULL, cur_summary_lto,
4272 nontrivial_scc);
4275 if (callee_summary && !cur_summary->side_effects
4276 && (callee_summary->side_effects
4277 || callee_edge->recursive_p ()))
4279 cur_summary->side_effects = true;
4280 changed = true;
4282 if (callee_summary_lto && !cur_summary_lto->side_effects
4283 && (callee_summary_lto->side_effects
4284 || callee_edge->recursive_p ()))
4286 cur_summary_lto->side_effects = true;
4287 changed = true;
4289 if (flags & (ECF_CONST | ECF_NOVOPS))
4290 continue;
4292 /* We can not safely optimize based on summary of callee if it
4293 does not always bind to current def: it is possible that
4294 memory load was optimized out earlier which may not happen in
4295 the interposed variant. */
4296 if (!callee_edge->binds_to_current_def_p ())
4298 changed |= collapse_loads (cur_summary, cur_summary_lto);
4299 if (dump_file)
4300 fprintf (dump_file, " May not bind local;"
4301 " collapsing loads\n");
4305 auto_vec <modref_parm_map, 32> parm_map;
4306 modref_parm_map chain_map;
4307 /* TODO: Once we get jump functions for static chains we could
4308 compute this. */
4309 chain_map.parm_index = MODREF_UNKNOWN_PARM;
4311 compute_parm_map (callee_edge, &parm_map);
4313 /* Merge in callee's information. */
4314 if (callee_summary)
4316 changed |= cur_summary->loads->merge
4317 (callee_summary->loads, &parm_map,
4318 &chain_map, !first);
4319 if (!ignore_stores)
4321 changed |= cur_summary->stores->merge
4322 (callee_summary->stores, &parm_map,
4323 &chain_map, !first);
4324 if (!cur_summary->writes_errno
4325 && callee_summary->writes_errno)
4327 cur_summary->writes_errno = true;
4328 changed = true;
4332 if (callee_summary_lto)
4334 changed |= cur_summary_lto->loads->merge
4335 (callee_summary_lto->loads, &parm_map,
4336 &chain_map, !first);
4337 if (!ignore_stores)
4339 changed |= cur_summary_lto->stores->merge
4340 (callee_summary_lto->stores, &parm_map,
4341 &chain_map, !first);
4342 if (!cur_summary_lto->writes_errno
4343 && callee_summary_lto->writes_errno)
4345 cur_summary_lto->writes_errno = true;
4346 changed = true;
4350 if (changed)
4351 remove_useless_summaries (node, &cur_summary,
4352 &cur_summary_lto,
4353 cur_ecf_flags);
4354 if (!cur_summary && !cur_summary_lto)
4355 break;
4356 if (dump_file && changed)
4358 if (cur_summary)
4359 cur_summary->dump (dump_file);
4360 if (cur_summary_lto)
4361 cur_summary_lto->dump (dump_file);
4362 dump_modref_edge_summaries (dump_file, node, 4);
4366 iteration++;
4367 first = false;
4369 if (dump_file)
4370 fprintf (dump_file,
4371 "Propagation finished in %i iterations\n", iteration);
4372 bool pureconst = false;
4373 for (struct cgraph_node *cur = component_node; cur;
4374 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4375 if (!cur->inlined_to && opt_for_fn (cur->decl, flag_ipa_pure_const))
4377 modref_summary *summary = optimization_summaries
4378 ? optimization_summaries->get (cur)
4379 : NULL;
4380 modref_summary_lto *summary_lto = summaries_lto
4381 ? summaries_lto->get (cur)
4382 : NULL;
4383 if (summary && !summary->stores->every_base && !summary->stores->bases)
4385 if (!summary->loads->every_base && !summary->loads->bases)
4386 pureconst |= ipa_make_function_const
4387 (cur, summary->side_effects, false);
4388 else
4389 pureconst |= ipa_make_function_pure
4390 (cur, summary->side_effects, false);
4392 if (summary_lto && !summary_lto->stores->every_base
4393 && !summary_lto->stores->bases)
4395 if (!summary_lto->loads->every_base && !summary_lto->loads->bases)
4396 pureconst |= ipa_make_function_const
4397 (cur, summary_lto->side_effects, false);
4398 else
4399 pureconst |= ipa_make_function_pure
4400 (cur, summary_lto->side_effects, false);
4403 return pureconst;
4406 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
4408 static void
4409 modref_propagate_dump_scc (cgraph_node *component_node)
4411 for (struct cgraph_node *cur = component_node; cur;
4412 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4413 if (!cur->inlined_to)
4415 modref_summary *cur_summary = optimization_summaries
4416 ? optimization_summaries->get (cur)
4417 : NULL;
4418 modref_summary_lto *cur_summary_lto = summaries_lto
4419 ? summaries_lto->get (cur)
4420 : NULL;
4422 fprintf (dump_file, "Propagated modref for %s%s%s\n",
4423 cur->dump_name (),
4424 TREE_READONLY (cur->decl) ? " (const)" : "",
4425 DECL_PURE_P (cur->decl) ? " (pure)" : "");
4426 if (optimization_summaries)
4428 if (cur_summary)
4429 cur_summary->dump (dump_file);
4430 else
4431 fprintf (dump_file, " Not tracked\n");
4433 if (summaries_lto)
4435 if (cur_summary_lto)
4436 cur_summary_lto->dump (dump_file);
4437 else
4438 fprintf (dump_file, " Not tracked (lto)\n");
4443 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
4444 and SUMMARY_LTO to CUR_SUMMARY_LTO.
4445 Return true if something changed. */
4447 static bool
4448 modref_merge_call_site_flags (escape_summary *sum,
4449 modref_summary *cur_summary,
4450 modref_summary_lto *cur_summary_lto,
4451 modref_summary *summary,
4452 modref_summary_lto *summary_lto,
4453 tree caller,
4454 cgraph_edge *e,
4455 int caller_ecf_flags,
4456 int callee_ecf_flags,
4457 bool binds_to_current_def)
4459 escape_entry *ee;
4460 unsigned int i;
4461 bool changed = false;
4462 bool ignore_stores = ignore_stores_p (caller, callee_ecf_flags);
4464 /* If we have no useful info to propagate. */
4465 if ((!cur_summary || !cur_summary->arg_flags.length ())
4466 && (!cur_summary_lto || !cur_summary_lto->arg_flags.length ()))
4467 return false;
4469 FOR_EACH_VEC_ELT (sum->esc, i, ee)
4471 int flags = 0;
4472 int flags_lto = 0;
4473 /* Returning the value is already accounted to at local propagation. */
4474 int implicit_flags = EAF_NOT_RETURNED_DIRECTLY
4475 | EAF_NOT_RETURNED_INDIRECTLY;
4477 if (summary && ee->arg < summary->arg_flags.length ())
4478 flags = summary->arg_flags[ee->arg];
4479 if (summary_lto
4480 && ee->arg < summary_lto->arg_flags.length ())
4481 flags_lto = summary_lto->arg_flags[ee->arg];
4482 if (!ee->direct)
4484 flags = deref_flags (flags, ignore_stores);
4485 flags_lto = deref_flags (flags_lto, ignore_stores);
4487 if (ignore_stores)
4488 implicit_flags |= ignore_stores_eaf_flags;
4489 if (callee_ecf_flags & ECF_PURE)
4490 implicit_flags |= implicit_pure_eaf_flags;
4491 if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
4492 implicit_flags |= implicit_const_eaf_flags;
4493 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
4494 if (fnspec_sum)
4496 attr_fnspec fnspec (fnspec_sum->fnspec);
4497 int fnspec_flags = 0;
4499 if (fnspec.arg_specified_p (ee->arg))
4501 if (!fnspec.arg_used_p (ee->arg))
4502 fnspec_flags = EAF_UNUSED;
4503 else
4505 if (fnspec.arg_direct_p (ee->arg))
4506 fnspec_flags |= EAF_NO_INDIRECT_READ
4507 | EAF_NO_INDIRECT_ESCAPE
4508 | EAF_NOT_RETURNED_INDIRECTLY
4509 | EAF_NO_INDIRECT_CLOBBER;
4510 if (fnspec.arg_noescape_p (ee->arg))
4511 fnspec_flags |= EAF_NO_DIRECT_ESCAPE
4512 | EAF_NO_INDIRECT_ESCAPE;
4513 if (fnspec.arg_readonly_p (ee->arg))
4514 flags |= EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER;
4517 implicit_flags |= fnspec_flags;
4519 if (!ee->direct)
4520 implicit_flags = deref_flags (implicit_flags, ignore_stores);
4521 flags |= implicit_flags;
4522 flags_lto |= implicit_flags;
4523 if (!binds_to_current_def && (flags || flags_lto))
4525 flags = interposable_eaf_flags (flags, implicit_flags);
4526 flags_lto = interposable_eaf_flags (flags_lto, implicit_flags);
4528 if (!(flags & EAF_UNUSED)
4529 && cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ())
4531 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
4532 ? cur_summary->retslot_flags
4533 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
4534 ? cur_summary->static_chain_flags
4535 : cur_summary->arg_flags[ee->parm_index];
4536 if ((f & flags) != f)
4538 f = remove_useless_eaf_flags
4539 (f & flags, caller_ecf_flags,
4540 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
4541 changed = true;
4544 if (!(flags_lto & EAF_UNUSED)
4545 && cur_summary_lto
4546 && ee->parm_index < (int)cur_summary_lto->arg_flags.length ())
4548 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
4549 ? cur_summary_lto->retslot_flags
4550 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
4551 ? cur_summary_lto->static_chain_flags
4552 : cur_summary_lto->arg_flags[ee->parm_index];
4553 if ((f & flags_lto) != f)
4555 f = remove_useless_eaf_flags
4556 (f & flags_lto, caller_ecf_flags,
4557 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
4558 changed = true;
4562 return changed;
4565 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4566 and propagate arg flags. */
4568 static void
4569 modref_propagate_flags_in_scc (cgraph_node *component_node)
4571 bool changed = true;
4572 int iteration = 0;
4574 while (changed)
4576 changed = false;
4577 for (struct cgraph_node *cur = component_node; cur;
4578 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4580 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
4581 modref_summary *cur_summary = optimization_summaries
4582 ? optimization_summaries->get (node)
4583 : NULL;
4584 modref_summary_lto *cur_summary_lto = summaries_lto
4585 ? summaries_lto->get (node)
4586 : NULL;
4588 if (!cur_summary && !cur_summary_lto)
4589 continue;
4590 int caller_ecf_flags = flags_from_decl_or_type (cur->decl);
4592 if (dump_file)
4593 fprintf (dump_file, " Processing %s%s%s\n",
4594 cur->dump_name (),
4595 TREE_READONLY (cur->decl) ? " (const)" : "",
4596 DECL_PURE_P (cur->decl) ? " (pure)" : "");
4598 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
4600 escape_summary *sum = escape_summaries->get (e);
4602 if (!sum || (e->indirect_info->ecf_flags
4603 & (ECF_CONST | ECF_NOVOPS)))
4604 continue;
4606 changed |= modref_merge_call_site_flags
4607 (sum, cur_summary, cur_summary_lto,
4608 NULL, NULL,
4609 node->decl,
4611 caller_ecf_flags,
4612 e->indirect_info->ecf_flags,
4613 false);
4616 if (!cur_summary && !cur_summary_lto)
4617 continue;
4619 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
4620 callee_edge = callee_edge->next_callee)
4622 int ecf_flags = flags_from_decl_or_type
4623 (callee_edge->callee->decl);
4624 modref_summary *callee_summary = NULL;
4625 modref_summary_lto *callee_summary_lto = NULL;
4626 struct cgraph_node *callee;
4628 if (ecf_flags & (ECF_CONST | ECF_NOVOPS)
4629 || !callee_edge->inline_failed)
4630 continue;
4631 /* Get the callee and its summary. */
4632 enum availability avail;
4633 callee = callee_edge->callee->function_or_virtual_thunk_symbol
4634 (&avail, cur);
4636 /* It is not necessary to re-process calls outside of the
4637 SCC component. */
4638 if (iteration > 0
4639 && (!callee->aux
4640 || ((struct ipa_dfs_info *)cur->aux)->scc_no
4641 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
4642 continue;
4644 escape_summary *sum = escape_summaries->get (callee_edge);
4645 if (!sum)
4646 continue;
4648 if (dump_file)
4649 fprintf (dump_file, " Call to %s\n",
4650 callee_edge->callee->dump_name ());
4652 if (avail <= AVAIL_INTERPOSABLE
4653 || callee_edge->call_stmt_cannot_inline_p)
4655 else
4657 if (cur_summary)
4658 callee_summary = optimization_summaries->get (callee);
4659 if (cur_summary_lto)
4660 callee_summary_lto = summaries_lto->get (callee);
4662 changed |= modref_merge_call_site_flags
4663 (sum, cur_summary, cur_summary_lto,
4664 callee_summary, callee_summary_lto,
4665 node->decl,
4666 callee_edge,
4667 caller_ecf_flags,
4668 ecf_flags,
4669 callee->binds_to_current_def_p ());
4670 if (dump_file && changed)
4672 if (cur_summary)
4673 cur_summary->dump (dump_file);
4674 if (cur_summary_lto)
4675 cur_summary_lto->dump (dump_file);
4679 iteration++;
4681 if (dump_file)
4682 fprintf (dump_file,
4683 "Propagation of flags finished in %i iterations\n", iteration);
4686 } /* ANON namespace. */
4688 /* Call EDGE was inlined; merge summary from callee to the caller. */
4690 void
4691 ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
4693 if (!summaries && !summaries_lto)
4694 return;
4696 struct cgraph_node *to = (edge->caller->inlined_to
4697 ? edge->caller->inlined_to : edge->caller);
4698 class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
4699 class modref_summary_lto *to_info_lto = summaries_lto
4700 ? summaries_lto->get (to) : NULL;
4702 if (!to_info && !to_info_lto)
4704 if (summaries)
4705 summaries->remove (edge->callee);
4706 if (summaries_lto)
4707 summaries_lto->remove (edge->callee);
4708 remove_modref_edge_summaries (edge->callee);
4709 return;
4712 class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
4713 : NULL;
4714 class modref_summary_lto *callee_info_lto
4715 = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
4716 int flags = flags_from_decl_or_type (edge->callee->decl);
4717 bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
4719 if (!callee_info && to_info)
4721 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
4722 to_info->loads->collapse ();
4723 if (!ignore_stores)
4724 to_info->stores->collapse ();
4726 if (!callee_info_lto && to_info_lto)
4728 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
4729 to_info_lto->loads->collapse ();
4730 if (!ignore_stores)
4731 to_info_lto->stores->collapse ();
4733 if (callee_info || callee_info_lto)
4735 auto_vec <modref_parm_map, 32> parm_map;
4736 modref_parm_map chain_map;
4737 /* TODO: Once we get jump functions for static chains we could
4738 compute this. */
4739 chain_map.parm_index = MODREF_UNKNOWN_PARM;
4741 compute_parm_map (edge, &parm_map);
4743 if (!ignore_stores)
4745 if (to_info && callee_info)
4746 to_info->stores->merge (callee_info->stores, &parm_map,
4747 &chain_map, false);
4748 if (to_info_lto && callee_info_lto)
4749 to_info_lto->stores->merge (callee_info_lto->stores, &parm_map,
4750 &chain_map, false);
4752 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
4754 if (to_info && callee_info)
4755 to_info->loads->merge (callee_info->loads, &parm_map,
4756 &chain_map, false);
4757 if (to_info_lto && callee_info_lto)
4758 to_info_lto->loads->merge (callee_info_lto->loads, &parm_map,
4759 &chain_map, false);
4763 /* Now merge escape summaries.
4764 For every escape to the callee we need to merge calle flags
4765 and remap calees escapes. */
4766 class escape_summary *sum = escape_summaries->get (edge);
4767 int max_escape = -1;
4768 escape_entry *ee;
4769 unsigned int i;
4771 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
4772 FOR_EACH_VEC_ELT (sum->esc, i, ee)
4773 if ((int)ee->arg > max_escape)
4774 max_escape = ee->arg;
4776 auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
4777 emap.safe_grow (max_escape + 1, true);
4778 for (i = 0; (int)i < max_escape + 1; i++)
4779 emap[i] = vNULL;
4781 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
4782 FOR_EACH_VEC_ELT (sum->esc, i, ee)
4784 bool needed = false;
4785 /* TODO: We do not have jump functions for return slots, so we
4786 never propagate them to outer function. */
4787 if (ee->parm_index < 0)
4788 continue;
4789 if (to_info && (int)to_info->arg_flags.length () > ee->parm_index)
4791 int flags = callee_info
4792 && callee_info->arg_flags.length () > ee->arg
4793 ? callee_info->arg_flags[ee->arg] : 0;
4794 if (!ee->direct)
4795 flags = deref_flags (flags, ignore_stores);
4796 else if (ignore_stores)
4797 flags |= ignore_stores_eaf_flags;
4798 flags |= ee->min_flags;
4799 to_info->arg_flags[ee->parm_index] &= flags;
4800 if (to_info->arg_flags[ee->parm_index])
4801 needed = true;
4803 if (to_info_lto
4804 && (int)to_info_lto->arg_flags.length () > ee->parm_index)
4806 int flags = callee_info_lto
4807 && callee_info_lto->arg_flags.length () > ee->arg
4808 ? callee_info_lto->arg_flags[ee->arg] : 0;
4809 if (!ee->direct)
4810 flags = deref_flags (flags, ignore_stores);
4811 else if (ignore_stores)
4812 flags |= ignore_stores_eaf_flags;
4813 flags |= ee->min_flags;
4814 to_info_lto->arg_flags[ee->parm_index] &= flags;
4815 if (to_info_lto->arg_flags[ee->parm_index])
4816 needed = true;
4818 struct escape_map entry = {ee->parm_index, ee->direct};
4819 if (needed)
4820 emap[ee->arg].safe_push (entry);
4822 update_escape_summary (edge->callee, emap, ignore_stores);
4823 for (i = 0; (int)i < max_escape + 1; i++)
4824 emap[i].release ();
4825 if (sum)
4826 escape_summaries->remove (edge);
4828 if (summaries)
4830 if (to_info && !to_info->useful_p (flags))
4832 if (dump_file)
4833 fprintf (dump_file, "Removed mod-ref summary for %s\n",
4834 to->dump_name ());
4835 summaries->remove (to);
4836 to_info = NULL;
4838 else if (to_info && dump_file)
4840 if (dump_file)
4841 fprintf (dump_file, "Updated mod-ref summary for %s\n",
4842 to->dump_name ());
4843 to_info->dump (dump_file);
4845 if (callee_info)
4846 summaries->remove (edge->callee);
4848 if (summaries_lto)
4850 if (to_info_lto && !to_info_lto->useful_p (flags))
4852 if (dump_file)
4853 fprintf (dump_file, "Removed mod-ref summary for %s\n",
4854 to->dump_name ());
4855 summaries_lto->remove (to);
4857 else if (to_info_lto && dump_file)
4859 if (dump_file)
4860 fprintf (dump_file, "Updated mod-ref summary for %s\n",
4861 to->dump_name ());
4862 to_info_lto->dump (dump_file);
4863 to_info_lto = NULL;
4865 if (callee_info_lto)
4866 summaries_lto->remove (edge->callee);
4868 if (!to_info && !to_info_lto)
4869 remove_modref_edge_summaries (to);
4870 return;
4873 /* Run the IPA pass. This will take a function's summaries and calls and
4874 construct new summaries which represent a transitive closure. So that
4875 summary of an analyzed function contains information about the loads and
4876 stores that the function or any function that it calls does. */
4878 unsigned int
4879 pass_ipa_modref::execute (function *)
4881 if (!summaries && !summaries_lto)
4882 return 0;
4883 bool pureconst = false;
4885 if (optimization_summaries)
4886 ggc_delete (optimization_summaries);
4887 optimization_summaries = summaries;
4888 summaries = NULL;
4890 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
4891 symtab->cgraph_count);
4892 int order_pos;
4893 order_pos = ipa_reduced_postorder (order, true, ignore_edge);
4894 int i;
4896 /* Iterate over all strongly connected components in post-order. */
4897 for (i = 0; i < order_pos; i++)
4899 /* Get the component's representative. That's just any node in the
4900 component from which we can traverse the entire component. */
4901 struct cgraph_node *component_node = order[i];
4903 if (dump_file)
4904 fprintf (dump_file, "\n\nStart of SCC component\n");
4906 pureconst |= modref_propagate_in_scc (component_node);
4907 modref_propagate_flags_in_scc (component_node);
4908 if (dump_file)
4909 modref_propagate_dump_scc (component_node);
4911 cgraph_node *node;
4912 FOR_EACH_FUNCTION (node)
4913 update_signature (node);
4914 if (summaries_lto)
4915 ((modref_summaries_lto *)summaries_lto)->propagated = true;
4916 ipa_free_postorder_info ();
4917 free (order);
4918 delete fnspec_summaries;
4919 fnspec_summaries = NULL;
4920 delete escape_summaries;
4921 escape_summaries = NULL;
4923 /* If we posibly made constructors const/pure we may need to remove
4924 them. */
4925 return pureconst ? TODO_remove_functions : 0;
4928 /* Summaries must stay alive until end of compilation. */
4930 void
4931 ipa_modref_c_finalize ()
4933 if (optimization_summaries)
4934 ggc_delete (optimization_summaries);
4935 optimization_summaries = NULL;
4936 if (summaries_lto)
4937 ggc_delete (summaries_lto);
4938 summaries_lto = NULL;
4939 if (fnspec_summaries)
4940 delete fnspec_summaries;
4941 fnspec_summaries = NULL;
4942 if (escape_summaries)
4943 delete escape_summaries;
4944 escape_summaries = NULL;
4947 #include "gt-ipa-modref.h"