Daily bump.
[official-gcc.git] / gcc / ipa-modref.c
blob6d49cc1410e87cbab854a848c1db2ee3fe4058c3
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"
90 namespace {
92 /* We record fnspec specifiers for call edges since they depends on actual
93 gimple statements. */
95 class fnspec_summary
97 public:
98 char *fnspec;
100 fnspec_summary ()
101 : fnspec (NULL)
105 ~fnspec_summary ()
107 free (fnspec);
111 /* Summary holding fnspec string for a given call. */
113 class fnspec_summaries_t : public call_summary <fnspec_summary *>
115 public:
116 fnspec_summaries_t (symbol_table *symtab)
117 : call_summary <fnspec_summary *> (symtab) {}
118 /* Hook that is called by summary when an edge is duplicated. */
119 virtual void duplicate (cgraph_edge *,
120 cgraph_edge *,
121 fnspec_summary *src,
122 fnspec_summary *dst)
124 dst->fnspec = xstrdup (src->fnspec);
128 static fnspec_summaries_t *fnspec_summaries = NULL;
130 /* Escape summary holds a vector of param indexes that escape to
131 a given call. */
132 struct escape_entry
134 /* Parameter that escapes at a given call. */
135 unsigned int parm_index;
136 /* Argument it escapes to. */
137 unsigned int arg;
138 /* Minimal flags known about the argument. */
139 eaf_flags_t min_flags;
140 /* Does it escape directly or indirectly? */
141 bool direct;
144 /* Dump EAF flags. */
146 static void
147 dump_eaf_flags (FILE *out, int flags, bool newline = true)
149 if (flags & EAF_DIRECT)
150 fprintf (out, " direct");
151 if (flags & EAF_NOCLOBBER)
152 fprintf (out, " noclobber");
153 if (flags & EAF_NOESCAPE)
154 fprintf (out, " noescape");
155 if (flags & EAF_NODIRECTESCAPE)
156 fprintf (out, " nodirectescape");
157 if (flags & EAF_UNUSED)
158 fprintf (out, " unused");
159 if (flags & EAF_NOT_RETURNED)
160 fprintf (out, " not_returned");
161 if (flags & EAF_NOREAD)
162 fprintf (out, " noread");
163 if (newline)
164 fprintf (out, "\n");
167 struct escape_summary
169 auto_vec <escape_entry> esc;
170 void dump (FILE *out)
172 for (unsigned int i = 0; i < esc.length (); i++)
174 fprintf (out, " parm %i arg %i %s min:",
175 esc[i].parm_index,
176 esc[i].arg,
177 esc[i].direct ? "(direct)" : "(indirect)");
178 dump_eaf_flags (out, esc[i].min_flags, false);
180 fprintf (out, "\n");
184 class escape_summaries_t : public call_summary <escape_summary *>
186 public:
187 escape_summaries_t (symbol_table *symtab)
188 : call_summary <escape_summary *> (symtab) {}
189 /* Hook that is called by summary when an edge is duplicated. */
190 virtual void duplicate (cgraph_edge *,
191 cgraph_edge *,
192 escape_summary *src,
193 escape_summary *dst)
195 dst->esc = src->esc.copy ();
199 static escape_summaries_t *escape_summaries = NULL;
201 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
204 /* Class (from which there is one global instance) that holds modref summaries
205 for all analyzed functions. */
207 class GTY((user)) modref_summaries
208 : public fast_function_summary <modref_summary *, va_gc>
210 public:
211 modref_summaries (symbol_table *symtab)
212 : fast_function_summary <modref_summary *, va_gc> (symtab) {}
213 virtual void insert (cgraph_node *, modref_summary *state);
214 virtual void duplicate (cgraph_node *src_node,
215 cgraph_node *dst_node,
216 modref_summary *src_data,
217 modref_summary *dst_data);
218 static modref_summaries *create_ggc (symbol_table *symtab)
220 return new (ggc_alloc_no_dtor<modref_summaries> ())
221 modref_summaries (symtab);
225 class modref_summary_lto;
227 /* Class (from which there is one global instance) that holds modref summaries
228 for all analyzed functions. */
230 class GTY((user)) modref_summaries_lto
231 : public fast_function_summary <modref_summary_lto *, va_gc>
233 public:
234 modref_summaries_lto (symbol_table *symtab)
235 : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
236 propagated (false) {}
237 virtual void insert (cgraph_node *, modref_summary_lto *state);
238 virtual void duplicate (cgraph_node *src_node,
239 cgraph_node *dst_node,
240 modref_summary_lto *src_data,
241 modref_summary_lto *dst_data);
242 static modref_summaries_lto *create_ggc (symbol_table *symtab)
244 return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
245 modref_summaries_lto (symtab);
247 bool propagated;
250 /* Global variable holding all modref summaries
251 (from analysis to IPA propagation time). */
253 static GTY(()) fast_function_summary <modref_summary *, va_gc>
254 *summaries;
256 /* Global variable holding all modref optimization summaries
257 (from IPA propagation time or used by local optimization pass). */
259 static GTY(()) fast_function_summary <modref_summary *, va_gc>
260 *optimization_summaries;
262 /* LTO summaries hold info from analysis to LTO streaming or from LTO
263 stream-in through propagation to LTO stream-out. */
265 static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
266 *summaries_lto;
268 /* Summary for a single function which this pass produces. */
270 modref_summary::modref_summary ()
271 : loads (NULL), stores (NULL), writes_errno (NULL)
275 modref_summary::~modref_summary ()
277 if (loads)
278 ggc_delete (loads);
279 if (stores)
280 ggc_delete (stores);
283 /* All flags that are implied by the ECF_CONST functions. */
284 const int implicit_const_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
285 | EAF_NODIRECTESCAPE | EAF_NOREAD;
286 /* All flags that are implied by the ECF_PURE function. */
287 const int implicit_pure_eaf_flags = EAF_NOCLOBBER | EAF_NOESCAPE
288 | EAF_NODIRECTESCAPE;
289 /* All flags implied when we know we can ignore stores (i.e. when handling
290 call to noreturn). */
291 const int ignore_stores_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
292 | EAF_NODIRECTESCAPE;
294 /* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
295 useful to track. If returns_void is true moreover clear
296 EAF_NOT_RETURNED. */
297 static int
298 remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
300 if (ecf_flags & ECF_NOVOPS)
301 return 0;
302 if (ecf_flags & ECF_CONST)
303 eaf_flags &= ~implicit_const_eaf_flags;
304 else if (ecf_flags & ECF_PURE)
305 eaf_flags &= ~implicit_pure_eaf_flags;
306 else if ((ecf_flags & ECF_NORETURN) || returns_void)
307 eaf_flags &= ~EAF_NOT_RETURNED;
308 /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
309 in tree-ssa-alias.c). Give up earlier. */
310 if ((eaf_flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
311 return 0;
312 return eaf_flags;
315 /* Return true if FLAGS holds some useful information. */
317 static bool
318 eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags)
320 for (unsigned i = 0; i < flags.length (); i++)
321 if (remove_useless_eaf_flags (flags[i], ecf_flags, false))
322 return true;
323 return false;
326 /* Return true if summary is potentially useful for optimization.
327 If CHECK_FLAGS is false assume that arg_flags are useful. */
329 bool
330 modref_summary::useful_p (int ecf_flags, bool check_flags)
332 if (ecf_flags & ECF_NOVOPS)
333 return false;
334 if (arg_flags.length () && !check_flags)
335 return true;
336 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
337 return true;
338 arg_flags.release ();
339 if (ecf_flags & ECF_CONST)
340 return false;
341 if (loads && !loads->every_base)
342 return true;
343 if (ecf_flags & ECF_PURE)
344 return false;
345 return stores && !stores->every_base;
348 /* Single function summary used for LTO. */
350 typedef modref_tree <tree> modref_records_lto;
351 struct GTY(()) modref_summary_lto
353 /* Load and stores in functions using types rather then alias sets.
355 This is necessary to make the information streamable for LTO but is also
356 more verbose and thus more likely to hit the limits. */
357 modref_records_lto *loads;
358 modref_records_lto *stores;
359 auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
360 bool writes_errno;
362 modref_summary_lto ();
363 ~modref_summary_lto ();
364 void dump (FILE *);
365 bool useful_p (int ecf_flags, bool check_flags = true);
368 /* Summary for a single function which this pass produces. */
370 modref_summary_lto::modref_summary_lto ()
371 : loads (NULL), stores (NULL), writes_errno (NULL)
375 modref_summary_lto::~modref_summary_lto ()
377 if (loads)
378 ggc_delete (loads);
379 if (stores)
380 ggc_delete (stores);
384 /* Return true if lto summary is potentially useful for optimization.
385 If CHECK_FLAGS is false assume that arg_flags are useful. */
387 bool
388 modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
390 if (ecf_flags & ECF_NOVOPS)
391 return false;
392 if (arg_flags.length () && !check_flags)
393 return true;
394 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
395 return true;
396 arg_flags.release ();
397 if (ecf_flags & ECF_CONST)
398 return false;
399 if (loads && !loads->every_base)
400 return true;
401 if (ecf_flags & ECF_PURE)
402 return false;
403 return stores && !stores->every_base;
406 /* Dump A to OUT. */
408 static void
409 dump_access (modref_access_node *a, FILE *out)
411 fprintf (out, " access:");
412 if (a->parm_index != -1)
414 fprintf (out, " Parm %i", a->parm_index);
415 if (a->parm_offset_known)
417 fprintf (out, " param offset:");
418 print_dec ((poly_int64_pod)a->parm_offset, out, SIGNED);
421 if (a->range_info_useful_p ())
423 fprintf (out, " offset:");
424 print_dec ((poly_int64_pod)a->offset, out, SIGNED);
425 fprintf (out, " size:");
426 print_dec ((poly_int64_pod)a->size, out, SIGNED);
427 fprintf (out, " max_size:");
428 print_dec ((poly_int64_pod)a->max_size, out, SIGNED);
429 if (a->adjustments)
430 fprintf (out, " adjusted %i times", a->adjustments);
432 fprintf (out, "\n");
435 /* Dump records TT to OUT. */
437 static void
438 dump_records (modref_records *tt, FILE *out)
440 fprintf (out, " Limits: %i bases, %i refs\n",
441 (int)tt->max_bases, (int)tt->max_refs);
442 if (tt->every_base)
444 fprintf (out, " Every base\n");
445 return;
447 size_t i;
448 modref_base_node <alias_set_type> *n;
449 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
451 fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
452 if (n->every_ref)
454 fprintf (out, " Every ref\n");
455 continue;
457 size_t j;
458 modref_ref_node <alias_set_type> *r;
459 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
461 fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
462 if (r->every_access)
464 fprintf (out, " Every access\n");
465 continue;
467 size_t k;
468 modref_access_node *a;
469 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
470 dump_access (a, out);
475 /* Dump records TT to OUT. */
477 static void
478 dump_lto_records (modref_records_lto *tt, FILE *out)
480 fprintf (out, " Limits: %i bases, %i refs\n",
481 (int)tt->max_bases, (int)tt->max_refs);
482 if (tt->every_base)
484 fprintf (out, " Every base\n");
485 return;
487 size_t i;
488 modref_base_node <tree> *n;
489 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
491 fprintf (out, " Base %i:", (int)i);
492 print_generic_expr (dump_file, n->base);
493 fprintf (out, " (alias set %i)\n",
494 n->base ? get_alias_set (n->base) : 0);
495 if (n->every_ref)
497 fprintf (out, " Every ref\n");
498 continue;
500 size_t j;
501 modref_ref_node <tree> *r;
502 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
504 fprintf (out, " Ref %i:", (int)j);
505 print_generic_expr (dump_file, r->ref);
506 fprintf (out, " (alias set %i)\n",
507 r->ref ? get_alias_set (r->ref) : 0);
508 if (r->every_access)
510 fprintf (out, " Every access\n");
511 continue;
513 size_t k;
514 modref_access_node *a;
515 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
516 dump_access (a, out);
521 /* Dump all escape points of NODE to OUT. */
523 static void
524 dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
526 int i = 0;
527 if (!escape_summaries)
528 return;
529 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
531 class escape_summary *sum = escape_summaries->get (e);
532 if (sum)
534 fprintf (out, "%*sIndirect call %i in %s escapes:",
535 depth, "", i, node->dump_name ());
536 sum->dump (out);
538 i++;
540 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
542 if (!e->inline_failed)
543 dump_modref_edge_summaries (out, e->callee, depth + 1);
544 class escape_summary *sum = escape_summaries->get (e);
545 if (sum)
547 fprintf (out, "%*sCall %s->%s escapes:", depth, "",
548 node->dump_name (), e->callee->dump_name ());
549 sum->dump (out);
551 class fnspec_summary *fsum = fnspec_summaries->get (e);
552 if (fsum)
554 fprintf (out, "%*sCall %s->%s fnspec: %s\n", depth, "",
555 node->dump_name (), e->callee->dump_name (),
556 fsum->fnspec);
561 /* Remove all call edge summaries associated with NODE. */
563 static void
564 remove_modref_edge_summaries (cgraph_node *node)
566 if (!escape_summaries)
567 return;
568 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
569 escape_summaries->remove (e);
570 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
572 if (!e->inline_failed)
573 remove_modref_edge_summaries (e->callee);
574 escape_summaries->remove (e);
575 fnspec_summaries->remove (e);
579 /* Dump summary. */
581 void
582 modref_summary::dump (FILE *out)
584 if (loads)
586 fprintf (out, " loads:\n");
587 dump_records (loads, out);
589 if (stores)
591 fprintf (out, " stores:\n");
592 dump_records (stores, out);
594 if (writes_errno)
595 fprintf (out, " Writes errno\n");
596 if (arg_flags.length ())
598 for (unsigned int i = 0; i < arg_flags.length (); i++)
599 if (arg_flags[i])
601 fprintf (out, " parm %i flags:", i);
602 dump_eaf_flags (out, arg_flags[i]);
607 /* Dump summary. */
609 void
610 modref_summary_lto::dump (FILE *out)
612 fprintf (out, " loads:\n");
613 dump_lto_records (loads, out);
614 fprintf (out, " stores:\n");
615 dump_lto_records (stores, out);
616 if (writes_errno)
617 fprintf (out, " Writes errno\n");
618 if (arg_flags.length ())
620 for (unsigned int i = 0; i < arg_flags.length (); i++)
621 if (arg_flags[i])
623 fprintf (out, " parm %i flags:", i);
624 dump_eaf_flags (out, arg_flags[i]);
629 /* Get function summary for FUNC if it exists, return NULL otherwise. */
631 modref_summary *
632 get_modref_function_summary (cgraph_node *func)
634 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
635 if (!optimization_summaries)
636 return NULL;
638 /* A single function body may be represented by multiple symbols with
639 different visibility. For example, if FUNC is an interposable alias,
640 we don't want to return anything, even if we have summary for the target
641 function. */
642 enum availability avail;
643 func = func->function_or_virtual_thunk_symbol
644 (&avail, current_function_decl ?
645 cgraph_node::get (current_function_decl) : NULL);
646 if (avail <= AVAIL_INTERPOSABLE)
647 return NULL;
649 modref_summary *r = optimization_summaries->get (func);
650 return r;
653 /* Construct modref_access_node from REF. */
654 static modref_access_node
655 get_access (ao_ref *ref)
657 tree base;
659 base = ao_ref_base (ref);
660 modref_access_node a = {ref->offset, ref->size, ref->max_size,
661 0, -1, false, 0};
662 if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
664 tree memref = base;
665 base = TREE_OPERAND (base, 0);
666 if (TREE_CODE (base) == SSA_NAME
667 && SSA_NAME_IS_DEFAULT_DEF (base)
668 && TREE_CODE (SSA_NAME_VAR (base)) == PARM_DECL)
670 a.parm_index = 0;
671 for (tree t = DECL_ARGUMENTS (current_function_decl);
672 t != SSA_NAME_VAR (base); t = DECL_CHAIN (t))
674 if (!t)
676 a.parm_index = -1;
677 break;
679 a.parm_index++;
681 if (TREE_CODE (memref) == MEM_REF)
683 a.parm_offset_known
684 = wi::to_poly_wide (TREE_OPERAND
685 (memref, 1)).to_shwi (&a.parm_offset);
687 else
688 a.parm_offset_known = false;
690 else
691 a.parm_index = -1;
693 else
694 a.parm_index = -1;
695 return a;
698 /* Record access into the modref_records data structure. */
700 static void
701 record_access (modref_records *tt, ao_ref *ref)
703 alias_set_type base_set = !flag_strict_aliasing ? 0
704 : ao_ref_base_alias_set (ref);
705 alias_set_type ref_set = !flag_strict_aliasing ? 0
706 : (ao_ref_alias_set (ref));
707 modref_access_node a = get_access (ref);
708 if (dump_file)
710 fprintf (dump_file, " - Recording base_set=%i ref_set=%i parm=%i\n",
711 base_set, ref_set, a.parm_index);
713 tt->insert (base_set, ref_set, a, false);
716 /* IPA version of record_access_tree. */
718 static void
719 record_access_lto (modref_records_lto *tt, ao_ref *ref)
721 /* get_alias_set sometimes use different type to compute the alias set
722 than TREE_TYPE (base). Do same adjustments. */
723 tree base_type = NULL_TREE, ref_type = NULL_TREE;
724 if (flag_strict_aliasing)
726 tree base;
728 base = ref->ref;
729 while (handled_component_p (base))
730 base = TREE_OPERAND (base, 0);
732 base_type = reference_alias_ptr_type_1 (&base);
734 if (!base_type)
735 base_type = TREE_TYPE (base);
736 else
737 base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
738 ? NULL_TREE : TREE_TYPE (base_type);
740 tree ref_expr = ref->ref;
741 ref_type = reference_alias_ptr_type_1 (&ref_expr);
743 if (!ref_type)
744 ref_type = TREE_TYPE (ref_expr);
745 else
746 ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
747 ? NULL_TREE : TREE_TYPE (ref_type);
749 /* Sanity check that we are in sync with what get_alias_set does. */
750 gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
751 || get_alias_set (base_type)
752 == ao_ref_base_alias_set (ref));
753 gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
754 || get_alias_set (ref_type)
755 == ao_ref_alias_set (ref));
757 /* Do not bother to record types that have no meaningful alias set.
758 Also skip variably modified types since these go to local streams. */
759 if (base_type && (!get_alias_set (base_type)
760 || variably_modified_type_p (base_type, NULL_TREE)))
761 base_type = NULL_TREE;
762 if (ref_type && (!get_alias_set (ref_type)
763 || variably_modified_type_p (ref_type, NULL_TREE)))
764 ref_type = NULL_TREE;
766 modref_access_node a = get_access (ref);
767 if (dump_file)
769 fprintf (dump_file, " - Recording base type:");
770 print_generic_expr (dump_file, base_type);
771 fprintf (dump_file, " (alias set %i) ref type:",
772 base_type ? get_alias_set (base_type) : 0);
773 print_generic_expr (dump_file, ref_type);
774 fprintf (dump_file, " (alias set %i) parm:%i\n",
775 ref_type ? get_alias_set (ref_type) : 0,
776 a.parm_index);
779 tt->insert (base_type, ref_type, a, false);
782 /* Returns true if and only if we should store the access to EXPR.
783 Some accesses, e.g. loads from automatic variables, are not interesting. */
785 static bool
786 record_access_p (tree expr)
788 if (refs_local_or_readonly_memory_p (expr))
790 if (dump_file)
791 fprintf (dump_file, " - Read-only or local, ignoring.\n");
792 return false;
794 return true;
797 /* Return true if ECF flags says that return value can be ignored. */
799 static bool
800 ignore_retval_p (tree caller, int flags)
802 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
803 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
804 return true;
805 return false;
808 /* Return true if ECF flags says that stores can be ignored. */
810 static bool
811 ignore_stores_p (tree caller, int flags)
813 if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
814 return true;
815 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
816 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
817 return true;
818 return false;
821 /* Determine parm_map for argument I of STMT. */
823 modref_parm_map
824 parm_map_for_arg (gimple *stmt, int i)
826 tree op = gimple_call_arg (stmt, i);
827 bool offset_known;
828 poly_int64 offset;
829 struct modref_parm_map parm_map;
831 parm_map.parm_offset_known = false;
832 parm_map.parm_offset = 0;
834 offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
835 if (TREE_CODE (op) == SSA_NAME
836 && SSA_NAME_IS_DEFAULT_DEF (op)
837 && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
839 int index = 0;
840 for (tree t = DECL_ARGUMENTS (current_function_decl);
841 t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
843 if (!t)
845 index = -1;
846 break;
848 index++;
850 parm_map.parm_index = index;
851 parm_map.parm_offset_known = offset_known;
852 parm_map.parm_offset = offset;
854 else if (points_to_local_or_readonly_memory_p (op))
855 parm_map.parm_index = -2;
856 else
857 parm_map.parm_index = -1;
858 return parm_map;
861 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
862 int CUR_SUMMARY. Return true if something changed.
863 If IGNORE_STORES is true, do not merge stores.
864 If RECORD_ADJUSTMENTS is true cap number of adjustments to
865 a given access to make dataflow finite. */
867 bool
868 merge_call_side_effects (modref_summary *cur_summary,
869 gimple *stmt, modref_summary *callee_summary,
870 bool ignore_stores, cgraph_node *callee_node,
871 bool record_adjustments)
873 auto_vec <modref_parm_map, 32> parm_map;
874 bool changed = false;
876 /* We can not safely optimize based on summary of callee if it does
877 not always bind to current def: it is possible that memory load
878 was optimized out earlier which may not happen in the interposed
879 variant. */
880 if (!callee_node->binds_to_current_def_p ())
882 if (dump_file)
883 fprintf (dump_file, " - May be interposed: collapsing loads.\n");
884 cur_summary->loads->collapse ();
887 if (dump_file)
888 fprintf (dump_file, " - Merging side effects of %s with parm map:",
889 callee_node->dump_name ());
891 parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true);
892 for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
894 parm_map[i] = parm_map_for_arg (stmt, i);
895 if (dump_file)
897 fprintf (dump_file, " %i", parm_map[i].parm_index);
898 if (parm_map[i].parm_offset_known)
900 fprintf (dump_file, " offset:");
901 print_dec ((poly_int64_pod)parm_map[i].parm_offset,
902 dump_file, SIGNED);
906 if (dump_file)
907 fprintf (dump_file, "\n");
909 /* Merge with callee's summary. */
910 changed |= cur_summary->loads->merge (callee_summary->loads, &parm_map,
911 record_adjustments);
912 if (!ignore_stores)
914 changed |= cur_summary->stores->merge (callee_summary->stores,
915 &parm_map,
916 record_adjustments);
917 if (!cur_summary->writes_errno
918 && callee_summary->writes_errno)
920 cur_summary->writes_errno = true;
921 changed = true;
924 return changed;
927 /* Return access mode for argument I of call STMT with FNSPEC. */
929 static modref_access_node
930 get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
931 unsigned int i, modref_parm_map &map)
933 tree size = NULL_TREE;
934 unsigned int size_arg;
936 if (!fnspec.arg_specified_p (i))
938 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
939 size = gimple_call_arg (call, size_arg);
940 else if (fnspec.arg_access_size_given_by_type_p (i))
942 tree callee = gimple_call_fndecl (call);
943 tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
945 for (unsigned int p = 0; p < i; p++)
946 t = TREE_CHAIN (t);
947 size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
949 modref_access_node a = {0, -1, -1,
950 map.parm_offset, map.parm_index,
951 map.parm_offset_known, 0};
952 poly_int64 size_hwi;
953 if (size
954 && poly_int_tree_p (size, &size_hwi)
955 && coeffs_in_range_p (size_hwi, 0,
956 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
958 a.size = -1;
959 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
961 return a;
964 /* Collapse loads and return true if something changed. */
966 static bool
967 collapse_loads (modref_summary *cur_summary,
968 modref_summary_lto *cur_summary_lto)
970 bool changed = false;
972 if (cur_summary && !cur_summary->loads->every_base)
974 cur_summary->loads->collapse ();
975 changed = true;
977 if (cur_summary_lto
978 && !cur_summary_lto->loads->every_base)
980 cur_summary_lto->loads->collapse ();
981 changed = true;
983 return changed;
986 /* Collapse loads and return true if something changed. */
988 static bool
989 collapse_stores (modref_summary *cur_summary,
990 modref_summary_lto *cur_summary_lto)
992 bool changed = false;
994 if (cur_summary && !cur_summary->stores->every_base)
996 cur_summary->stores->collapse ();
997 changed = true;
999 if (cur_summary_lto
1000 && !cur_summary_lto->stores->every_base)
1002 cur_summary_lto->stores->collapse ();
1003 changed = true;
1005 return changed;
1009 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1010 If IGNORE_STORES is true ignore them.
1011 Return false if no useful summary can be produced. */
1013 static bool
1014 process_fnspec (modref_summary *cur_summary,
1015 modref_summary_lto *cur_summary_lto,
1016 gcall *call, bool ignore_stores)
1018 attr_fnspec fnspec = gimple_call_fnspec (call);
1019 if (!fnspec.known_p ())
1021 if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
1022 fprintf (dump_file, " Builtin with no fnspec: %s\n",
1023 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
1024 if (ignore_stores)
1026 collapse_loads (cur_summary, cur_summary_lto);
1027 return true;
1029 return false;
1031 if (fnspec.global_memory_read_p ())
1032 collapse_loads (cur_summary, cur_summary_lto);
1033 else
1035 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1036 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1038 else if (!fnspec.arg_specified_p (i)
1039 || fnspec.arg_maybe_read_p (i))
1041 modref_parm_map map = parm_map_for_arg (call, i);
1043 if (map.parm_index == -2)
1044 continue;
1045 if (map.parm_index == -1)
1047 collapse_loads (cur_summary, cur_summary_lto);
1048 break;
1050 if (cur_summary)
1051 cur_summary->loads->insert (0, 0,
1052 get_access_for_fnspec (call,
1053 fnspec, i,
1054 map),
1055 false);
1056 if (cur_summary_lto)
1057 cur_summary_lto->loads->insert (0, 0,
1058 get_access_for_fnspec (call,
1059 fnspec, i,
1060 map),
1061 false);
1064 if (ignore_stores)
1065 return true;
1066 if (fnspec.global_memory_written_p ())
1067 collapse_stores (cur_summary, cur_summary_lto);
1068 else
1070 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1071 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1073 else if (!fnspec.arg_specified_p (i)
1074 || fnspec.arg_maybe_written_p (i))
1076 modref_parm_map map = parm_map_for_arg (call, i);
1078 if (map.parm_index == -2)
1079 continue;
1080 if (map.parm_index == -1)
1082 collapse_stores (cur_summary, cur_summary_lto);
1083 break;
1085 if (cur_summary)
1086 cur_summary->stores->insert (0, 0,
1087 get_access_for_fnspec (call,
1088 fnspec, i,
1089 map),
1090 false);
1091 if (cur_summary_lto)
1092 cur_summary_lto->stores->insert (0, 0,
1093 get_access_for_fnspec (call,
1094 fnspec, i,
1095 map),
1096 false);
1098 if (fnspec.errno_maybe_written_p () && flag_errno_math)
1100 if (cur_summary)
1101 cur_summary->writes_errno = true;
1102 if (cur_summary_lto)
1103 cur_summary_lto->writes_errno = true;
1106 return true;
1109 /* Analyze function call STMT in function F.
1110 Remember recursive calls in RECURSIVE_CALLS. */
1112 static bool
1113 analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto,
1114 gcall *stmt, vec <gimple *> *recursive_calls)
1116 /* Check flags on the function call. In certain cases, analysis can be
1117 simplified. */
1118 int flags = gimple_call_flags (stmt);
1119 if (flags & (ECF_CONST | ECF_NOVOPS))
1121 if (dump_file)
1122 fprintf (dump_file,
1123 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1124 "except for args.\n");
1125 return true;
1128 /* Pure functions do not affect global memory. Stores by functions which are
1129 noreturn and do not throw can safely be ignored. */
1130 bool ignore_stores = ignore_stores_p (current_function_decl, flags);
1132 /* Next, we try to get the callee's function declaration. The goal is to
1133 merge their summary with ours. */
1134 tree callee = gimple_call_fndecl (stmt);
1136 /* Check if this is an indirect call. */
1137 if (!callee)
1139 if (dump_file)
1140 fprintf (dump_file, gimple_call_internal_p (stmt)
1141 ? " - Internal call" : " - Indirect call.\n");
1142 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1144 /* We only need to handle internal calls in IPA mode. */
1145 gcc_checking_assert (!cur_summary_lto);
1147 struct cgraph_node *callee_node = cgraph_node::get_create (callee);
1149 /* If this is a recursive call, the target summary is the same as ours, so
1150 there's nothing to do. */
1151 if (recursive_call_p (current_function_decl, callee))
1153 recursive_calls->safe_push (stmt);
1154 if (dump_file)
1155 fprintf (dump_file, " - Skipping recursive call.\n");
1156 return true;
1159 gcc_assert (callee_node != NULL);
1161 /* Get the function symbol and its availability. */
1162 enum availability avail;
1163 callee_node = callee_node->function_symbol (&avail);
1164 if (avail <= AVAIL_INTERPOSABLE)
1166 if (dump_file)
1167 fprintf (dump_file, " - Function availability <= AVAIL_INTERPOSABLE.\n");
1168 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1171 /* Get callee's modref summary. As above, if there's no summary, we either
1172 have to give up or, if stores are ignored, we can just purge loads. */
1173 modref_summary *callee_summary = optimization_summaries->get (callee_node);
1174 if (!callee_summary)
1176 if (dump_file)
1177 fprintf (dump_file, " - No modref summary available for callee.\n");
1178 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1181 merge_call_side_effects (cur_summary, stmt, callee_summary, ignore_stores,
1182 callee_node, false);
1184 return true;
1187 /* Support analysis in non-lto and lto mode in parallel. */
1189 struct summary_ptrs
1191 struct modref_summary *nolto;
1192 struct modref_summary_lto *lto;
1195 /* Helper for analyze_stmt. */
1197 static bool
1198 analyze_load (gimple *, tree, tree op, void *data)
1200 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1201 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1203 if (dump_file)
1205 fprintf (dump_file, " - Analyzing load: ");
1206 print_generic_expr (dump_file, op);
1207 fprintf (dump_file, "\n");
1210 if (!record_access_p (op))
1211 return false;
1213 ao_ref r;
1214 ao_ref_init (&r, op);
1216 if (summary)
1217 record_access (summary->loads, &r);
1218 if (summary_lto)
1219 record_access_lto (summary_lto->loads, &r);
1220 return false;
1223 /* Helper for analyze_stmt. */
1225 static bool
1226 analyze_store (gimple *, tree, tree op, void *data)
1228 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1229 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1231 if (dump_file)
1233 fprintf (dump_file, " - Analyzing store: ");
1234 print_generic_expr (dump_file, op);
1235 fprintf (dump_file, "\n");
1238 if (!record_access_p (op))
1239 return false;
1241 ao_ref r;
1242 ao_ref_init (&r, op);
1244 if (summary)
1245 record_access (summary->stores, &r);
1246 if (summary_lto)
1247 record_access_lto (summary_lto->stores, &r);
1248 return false;
1251 /* Analyze statement STMT of function F.
1252 If IPA is true do not merge in side effects of calls. */
1254 static bool
1255 analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
1256 gimple *stmt, bool ipa, vec <gimple *> *recursive_calls)
1258 /* In general we can not ignore clobbers because they are barriers for code
1259 motion, however after inlining it is safe to do because local optimization
1260 passes do not consider clobbers from other functions.
1261 Similar logic is in ipa-pure-const.c. */
1262 if ((ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1263 return true;
1265 struct summary_ptrs sums = {summary, summary_lto};
1267 /* Analyze all loads and stores in STMT. */
1268 walk_stmt_load_store_ops (stmt, &sums,
1269 analyze_load, analyze_store);
1271 switch (gimple_code (stmt))
1273 case GIMPLE_ASM:
1274 /* If the ASM statement does not read nor write memory, there's nothing
1275 to do. Otherwise just give up. */
1276 if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1277 return true;
1278 if (dump_file)
1279 fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1280 "which clobbers memory.\n");
1281 return false;
1282 case GIMPLE_CALL:
1283 if (!ipa || gimple_call_internal_p (stmt))
1284 return analyze_call (summary, summary_lto,
1285 as_a <gcall *> (stmt), recursive_calls);
1286 else
1288 attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1290 if (fnspec.known_p ()
1291 && (!fnspec.global_memory_read_p ()
1292 || !fnspec.global_memory_written_p ()))
1294 cgraph_edge *e = cgraph_node::get (current_function_decl)->get_edge (stmt);
1295 if (e->callee)
1297 fnspec_summaries->get_create (e)->fnspec = xstrdup (fnspec.get_str ());
1298 if (dump_file)
1299 fprintf (dump_file, " Recorded fnspec %s\n", fnspec.get_str ());
1303 return true;
1304 default:
1305 /* Nothing to do for other types of statements. */
1306 return true;
1310 /* Remove summary of current function because during the function body
1311 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1312 mode of scan. */
1314 static void
1315 remove_summary (bool lto, bool nolto, bool ipa)
1317 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1318 if (!ipa)
1319 optimization_summaries->remove (fnode);
1320 else
1322 if (nolto)
1323 summaries->remove (fnode);
1324 if (lto)
1325 summaries_lto->remove (fnode);
1326 remove_modref_edge_summaries (fnode);
1328 if (dump_file)
1329 fprintf (dump_file,
1330 " - modref done with result: not tracked.\n");
1333 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1335 bool
1336 memory_access_to (tree op, tree ssa_name)
1338 tree base = get_base_address (op);
1339 if (!base)
1340 return false;
1341 if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1342 return false;
1343 return TREE_OPERAND (base, 0) == ssa_name;
1346 /* Consider statement val = *arg.
1347 return EAF flags of ARG that can be determined from EAF flags of VAL
1348 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1349 all stores to VAL, i.e. when handling noreturn function. */
1351 static int
1352 deref_flags (int flags, bool ignore_stores)
1354 int ret = EAF_NODIRECTESCAPE;
1355 /* If argument is unused just account for
1356 the read involved in dereference. */
1357 if (flags & EAF_UNUSED)
1358 ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOT_RETURNED;
1359 else
1361 if ((flags & EAF_NOCLOBBER) || ignore_stores)
1362 ret |= EAF_NOCLOBBER;
1363 if ((flags & EAF_NOESCAPE) || ignore_stores)
1364 ret |= EAF_NOESCAPE;
1365 /* If the value dereferenced is not used for another load or store
1366 we can still consider ARG as used only directly.
1368 Consider
1371 test (int *a)
1373 return *a!=0;
1377 if ((flags & (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT))
1378 == (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT)
1379 && ((flags & EAF_NOCLOBBER) || ignore_stores))
1380 ret |= EAF_DIRECT;
1381 if (flags & EAF_NOT_RETURNED)
1382 ret |= EAF_NOT_RETURNED;
1384 return ret;
1387 namespace {
1389 /* Description of an escape point. */
1391 struct escape_point
1393 /* Value escapes to this call. */
1394 gcall *call;
1395 /* Argument it escapes to. */
1396 int arg;
1397 /* Flags already known about the argument (this can save us from recording
1398 esape points if local analysis did good job already). */
1399 eaf_flags_t min_flags;
1400 /* Does value escape directly or indiretly? */
1401 bool direct;
1404 class modref_lattice
1406 public:
1407 /* EAF flags of the SSA name. */
1408 eaf_flags_t flags;
1409 /* DFS bookkkeeping: we don't do real dataflow yet. */
1410 bool known;
1411 bool open;
1413 /* When doing IPA analysis we can not merge in callee escape points;
1414 Only remember them and do the merging at IPA propagation time. */
1415 vec <escape_point, va_heap, vl_ptr> escape_points;
1417 void init ();
1418 void release ();
1419 bool merge (const modref_lattice &with);
1420 bool merge (int flags);
1421 bool merge_deref (const modref_lattice &with, bool ignore_stores);
1422 bool merge_direct_load ();
1423 bool merge_direct_store ();
1424 bool add_escape_point (gcall *call, int arg, int min_flags, bool diret);
1425 void dump (FILE *out, int indent = 0) const;
1428 /* Lattices are saved to vectors, so keep them PODs. */
1429 void
1430 modref_lattice::init ()
1432 /* All flags we track. */
1433 int f = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED
1434 | EAF_NODIRECTESCAPE | EAF_NOT_RETURNED | EAF_NOREAD;
1435 flags = f;
1436 /* Check that eaf_flags_t is wide enough to hold all flags. */
1437 gcc_checking_assert (f == flags);
1438 open = true;
1439 known = false;
1442 /* Release memory. */
1443 void
1444 modref_lattice::release ()
1446 escape_points.release ();
1449 /* Dump lattice to OUT; indent with INDENT spaces. */
1451 void
1452 modref_lattice::dump (FILE *out, int indent) const
1454 dump_eaf_flags (out, flags);
1455 if (escape_points.length ())
1457 fprintf (out, "%*sEscapes:\n", indent, "");
1458 for (unsigned int i = 0; i < escape_points.length (); i++)
1460 fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
1461 escape_points[i].arg,
1462 escape_points[i].direct ? "direct" : "indirect");
1463 dump_eaf_flags (out, escape_points[i].min_flags, false);
1464 fprintf (out, " in call ");
1465 print_gimple_stmt (out, escape_points[i].call, 0);
1470 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1471 point exists. */
1473 bool
1474 modref_lattice::add_escape_point (gcall *call, int arg, int min_flags,
1475 bool direct)
1477 escape_point *ep;
1478 unsigned int i;
1480 /* If we already determined flags to be bad enough,
1481 we do not need to record. */
1482 if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
1483 return false;
1485 FOR_EACH_VEC_ELT (escape_points, i, ep)
1486 if (ep->call == call && ep->arg == arg && ep->direct == direct)
1488 if ((ep->min_flags & min_flags) == min_flags)
1489 return false;
1490 ep->min_flags &= min_flags;
1491 return true;
1493 /* Give up if max escape points is met. */
1494 if ((int)escape_points.length () > param_modref_max_escape_points)
1496 if (dump_file)
1497 fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
1498 merge (0);
1499 return true;
1501 escape_point new_ep = {call, arg, min_flags, direct};
1502 escape_points.safe_push (new_ep);
1503 return true;
1506 /* Merge in flags from F. */
1507 bool
1508 modref_lattice::merge (int f)
1510 if (f & EAF_UNUSED)
1511 return false;
1512 /* Noescape implies that value also does not escape directly.
1513 Fnspec machinery does set both so compensate for this. */
1514 if (f & EAF_NOESCAPE)
1515 f |= EAF_NODIRECTESCAPE;
1516 if ((flags & f) != flags)
1518 flags &= f;
1519 /* Prune obvoiusly useless flags;
1520 We do not have ECF_FLAGS handy which is not big problem since
1521 we will do final flags cleanup before producing summary.
1522 Merging should be fast so it can work well with dataflow. */
1523 flags = remove_useless_eaf_flags (flags, 0, false);
1524 if (!flags)
1525 escape_points.release ();
1526 return true;
1528 return false;
1531 /* Merge in WITH. Return true if anyting changed. */
1533 bool
1534 modref_lattice::merge (const modref_lattice &with)
1536 if (!with.known)
1537 return merge (0);
1539 bool changed = merge (with.flags);
1541 if (!flags)
1542 return changed;
1543 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1544 changed |= add_escape_point (with.escape_points[i].call,
1545 with.escape_points[i].arg,
1546 with.escape_points[i].min_flags,
1547 with.escape_points[i].direct);
1548 return changed;
1551 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1552 stores. Return true if anyting changed. */
1554 bool
1555 modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
1557 if (!with.known)
1558 return merge (0);
1560 bool changed = merge (deref_flags (with.flags, ignore_stores));
1562 if (!flags)
1563 return changed;
1564 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1566 int min_flags = with.escape_points[i].min_flags;
1568 if (with.escape_points[i].direct)
1569 min_flags = deref_flags (min_flags, ignore_stores);
1570 else if (ignore_stores)
1571 min_flags |= ignore_stores_eaf_flags;
1572 changed |= add_escape_point (with.escape_points[i].call,
1573 with.escape_points[i].arg,
1574 min_flags,
1575 false);
1577 return changed;
1580 /* Merge in flags for direct load. */
1582 bool
1583 modref_lattice::merge_direct_load ()
1585 return merge (~(EAF_UNUSED | EAF_NOREAD));
1588 /* Merge in flags for direct store. */
1590 bool
1591 modref_lattice::merge_direct_store ()
1593 return merge (~(EAF_UNUSED | EAF_NOCLOBBER));
1596 } /* ANON namespace. */
1598 static void analyze_ssa_name_flags (tree name,
1599 vec<modref_lattice> &lattice,
1600 int depth, bool ipa);
1602 /* Call statements may return their parameters. Consider argument number
1603 ARG of USE_STMT and determine flags that can needs to be cleared
1604 in case pointer possibly indirectly references from ARG I is returned.
1605 LATTICE, DEPTH and ipa are same as in analyze_ssa_name_flags. */
1607 static void
1608 merge_call_lhs_flags (gcall *call, int arg, int index, bool deref,
1609 vec<modref_lattice> &lattice,
1610 int depth, bool ipa)
1612 /* If there is no return value, no flags are affected. */
1613 if (!gimple_call_lhs (call))
1614 return;
1616 /* If we know that function returns given argument and it is not ARG
1617 we can still be happy. */
1618 int flags = gimple_call_return_flags (call);
1619 if ((flags & ERF_RETURNS_ARG)
1620 && (flags & ERF_RETURN_ARG_MASK) != arg)
1621 return;
1623 if (gimple_call_arg_flags (call, arg) & (EAF_NOT_RETURNED | EAF_UNUSED))
1624 return;
1626 /* If return value is SSA name determine its flags. */
1627 if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
1629 tree lhs = gimple_call_lhs (call);
1630 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1631 if (deref)
1632 lattice[index].merge_deref (lattice[SSA_NAME_VERSION (lhs)], false);
1633 else
1634 lattice[index].merge (lattice[SSA_NAME_VERSION (lhs)]);
1636 /* In the case of memory store we can do nothing. */
1637 else
1638 lattice[index].merge (0);
1641 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
1642 LATTICE is an array of modref_lattices.
1643 DEPTH is a recursion depth used to make debug output prettier.
1644 If IPA is true we analyze for IPA propagation (and thus call escape points
1645 are processed later) */
1647 static void
1648 analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
1649 bool ipa)
1651 imm_use_iterator ui;
1652 gimple *use_stmt;
1653 int index = SSA_NAME_VERSION (name);
1655 /* See if value is already computed. */
1656 if (lattice[index].known)
1657 return;
1658 if (lattice[index].open)
1660 if (dump_file)
1661 fprintf (dump_file,
1662 "%*sGiving up on a cycle in SSA graph\n", depth * 4, "");
1663 return;
1665 if (depth == param_modref_max_depth)
1667 if (dump_file)
1668 fprintf (dump_file,
1669 "%*sGiving up on max depth\n", depth * 4, "");
1670 return;
1672 /* Recursion guard. */
1673 lattice[index].init ();
1675 if (dump_file)
1677 fprintf (dump_file,
1678 "%*sAnalyzing flags of ssa name: ", depth * 4, "");
1679 print_generic_expr (dump_file, name);
1680 fprintf (dump_file, "\n");
1683 FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
1685 if (lattice[index].flags == 0)
1686 break;
1687 if (is_gimple_debug (use_stmt))
1688 continue;
1689 if (dump_file)
1691 fprintf (dump_file, "%*s Analyzing stmt: ", depth * 4, "");
1692 print_gimple_stmt (dump_file, use_stmt, 0);
1694 /* If we see a direct non-debug use, clear unused bit.
1695 All dereferneces should be accounted below using deref_flags. */
1696 lattice[index].merge (~EAF_UNUSED);
1698 /* Gimple return may load the return value.
1699 Returning name counts as an use by tree-ssa-structalias.c */
1700 if (greturn *ret = dyn_cast <greturn *> (use_stmt))
1702 if (gimple_return_retval (ret) == name)
1703 lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED));
1704 else if (memory_access_to (gimple_return_retval (ret), name))
1706 lattice[index].merge_direct_load ();
1707 lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED));
1710 /* Account for LHS store, arg loads and flags from callee function. */
1711 else if (gcall *call = dyn_cast <gcall *> (use_stmt))
1713 tree callee = gimple_call_fndecl (call);
1715 /* IPA PTA internally it treats calling a function as "writing" to
1716 the argument space of all functions the function pointer points to
1717 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
1718 is on since that would allow propagation of this from -fno-ipa-pta
1719 to -fipa-pta functions. */
1720 if (gimple_call_fn (use_stmt) == name)
1721 lattice[index].merge (~(EAF_NOCLOBBER | EAF_UNUSED));
1723 /* Recursion would require bit of propagation; give up for now. */
1724 if (callee && !ipa && recursive_call_p (current_function_decl,
1725 callee))
1726 lattice[index].merge (0);
1727 else
1729 int ecf_flags = gimple_call_flags (call);
1730 bool ignore_stores = ignore_stores_p (current_function_decl,
1731 ecf_flags);
1732 bool ignore_retval = ignore_retval_p (current_function_decl,
1733 ecf_flags);
1735 /* Handle *name = func (...). */
1736 if (gimple_call_lhs (call)
1737 && memory_access_to (gimple_call_lhs (call), name))
1739 lattice[index].merge_direct_store ();
1740 /* Return slot optimization passes address of
1741 LHS to callee via hidden parameter and this
1742 may make LHS to escape. See PR 98499. */
1743 if (gimple_call_return_slot_opt_p (call)
1744 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
1745 lattice[index].merge (EAF_NOREAD | EAF_DIRECT);
1748 /* We do not track accesses to the static chain (we could)
1749 so give up. */
1750 if (gimple_call_chain (call)
1751 && (gimple_call_chain (call) == name))
1752 lattice[index].merge (0);
1754 /* Process internal functions and right away. */
1755 bool record_ipa = ipa && !gimple_call_internal_p (call);
1757 /* Handle all function parameters. */
1758 for (unsigned i = 0;
1759 i < gimple_call_num_args (call) && lattice[index].flags; i++)
1760 /* Name is directly passed to the callee. */
1761 if (gimple_call_arg (call, i) == name)
1763 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
1765 int call_flags = gimple_call_arg_flags (call, i)
1766 | EAF_NOT_RETURNED;
1767 if (ignore_stores)
1768 call_flags |= ignore_stores_eaf_flags;
1770 if (!record_ipa)
1771 lattice[index].merge (call_flags);
1772 else
1773 lattice[index].add_escape_point (call, i,
1774 call_flags, true);
1776 if (!ignore_retval)
1777 merge_call_lhs_flags (call, i, index, false,
1778 lattice, depth, ipa);
1780 /* Name is dereferenced and passed to a callee. */
1781 else if (memory_access_to (gimple_call_arg (call, i), name))
1783 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
1784 lattice[index].merge_direct_load ();
1785 else
1787 int call_flags = deref_flags
1788 (gimple_call_arg_flags (call, i)
1789 | EAF_NOT_RETURNED, ignore_stores);
1790 if (!record_ipa)
1791 lattice[index].merge (call_flags);
1792 else
1793 lattice[index].add_escape_point (call, i,
1794 call_flags, false);
1796 if (!ignore_retval)
1797 merge_call_lhs_flags (call, i, index, true,
1798 lattice, depth, ipa);
1802 else if (gimple_assign_load_p (use_stmt))
1804 gassign *assign = as_a <gassign *> (use_stmt);
1805 /* Memory to memory copy. */
1806 if (gimple_store_p (assign))
1808 /* Handle *lhs = *name.
1810 We do not track memory locations, so assume that value
1811 is used arbitrarily. */
1812 if (memory_access_to (gimple_assign_rhs1 (assign), name))
1813 lattice[index].merge (0);
1814 /* Handle *name = *exp. */
1815 else if (memory_access_to (gimple_assign_lhs (assign), name))
1816 lattice[index].merge_direct_store ();
1818 /* Handle lhs = *name. */
1819 else if (memory_access_to (gimple_assign_rhs1 (assign), name))
1821 tree lhs = gimple_assign_lhs (assign);
1822 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1823 lattice[index].merge_deref (lattice[SSA_NAME_VERSION (lhs)],
1824 false);
1827 else if (gimple_store_p (use_stmt))
1829 gassign *assign = dyn_cast <gassign *> (use_stmt);
1831 /* Handle *lhs = name. */
1832 if (assign && gimple_assign_rhs1 (assign) == name)
1834 if (dump_file)
1835 fprintf (dump_file, "%*s ssa name saved to memory\n",
1836 depth * 4, "");
1837 lattice[index].merge (0);
1839 /* Handle *name = exp. */
1840 else if (assign
1841 && memory_access_to (gimple_assign_lhs (assign), name))
1843 /* In general we can not ignore clobbers because they are
1844 barriers for code motion, however after inlining it is safe to
1845 do because local optimization passes do not consider clobbers
1846 from other functions. Similar logic is in ipa-pure-const.c. */
1847 if (!cfun->after_inlining || !gimple_clobber_p (assign))
1848 lattice[index].merge_direct_store ();
1850 /* ASM statements etc. */
1851 else if (!assign)
1853 if (dump_file)
1854 fprintf (dump_file, "%*s Unhandled store\n",
1855 depth * 4, "");
1856 lattice[index].merge (0);
1859 else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
1861 enum tree_code code = gimple_assign_rhs_code (assign);
1863 /* See if operation is a merge as considered by
1864 tree-ssa-structalias.c:find_func_aliases. */
1865 if (!truth_value_p (code)
1866 && code != POINTER_DIFF_EXPR
1867 && (code != POINTER_PLUS_EXPR
1868 || gimple_assign_rhs1 (assign) == name))
1870 tree lhs = gimple_assign_lhs (assign);
1871 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1872 lattice[index].merge (lattice[SSA_NAME_VERSION (lhs)]);
1875 else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
1877 tree result = gimple_phi_result (phi);
1878 analyze_ssa_name_flags (result, lattice, depth + 1, ipa);
1879 lattice[index].merge (lattice[SSA_NAME_VERSION (result)]);
1881 /* Conditions are not considered escape points
1882 by tree-ssa-structalias. */
1883 else if (gimple_code (use_stmt) == GIMPLE_COND)
1885 else
1887 if (dump_file)
1888 fprintf (dump_file, "%*s Unhandled stmt\n", depth * 4, "");
1889 lattice[index].merge (0);
1892 if (dump_file)
1894 fprintf (dump_file, "%*s current flags of ", depth * 4, "");
1895 print_generic_expr (dump_file, name);
1896 lattice[index].dump (dump_file, depth * 4 + 4);
1899 if (dump_file)
1901 fprintf (dump_file, "%*sflags of ssa name ", depth * 4, "");
1902 print_generic_expr (dump_file, name);
1903 lattice[index].dump (dump_file, depth * 4 + 2);
1905 lattice[index].open = false;
1906 lattice[index].known = true;
1909 /* Determine EAF flags for function parameters. */
1911 static void
1912 analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
1913 bool ipa)
1915 unsigned int parm_index = 0;
1916 unsigned int count = 0;
1917 int ecf_flags = flags_from_decl_or_type (current_function_decl);
1919 /* For novops functions we have nothing to gain by EAF flags. */
1920 if (ecf_flags & ECF_NOVOPS)
1921 return;
1923 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
1924 parm = TREE_CHAIN (parm))
1925 count++;
1927 if (!count)
1928 return;
1930 auto_vec<modref_lattice> lattice;
1931 lattice.safe_grow_cleared (num_ssa_names, true);
1933 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
1934 parm = TREE_CHAIN (parm))
1936 tree name = ssa_default_def (cfun, parm);
1937 if (!name || has_zero_uses (name))
1939 /* We do not track non-SSA parameters,
1940 but we want to track unused gimple_regs. */
1941 if (!is_gimple_reg (parm))
1942 continue;
1943 if (summary)
1945 if (parm_index >= summary->arg_flags.length ())
1946 summary->arg_flags.safe_grow_cleared (count, true);
1947 summary->arg_flags[parm_index] = EAF_UNUSED;
1949 else if (summary_lto)
1951 if (parm_index >= summary_lto->arg_flags.length ())
1952 summary_lto->arg_flags.safe_grow_cleared (count, true);
1953 summary_lto->arg_flags[parm_index] = EAF_UNUSED;
1955 continue;
1957 analyze_ssa_name_flags (name, lattice, 0, ipa);
1958 int flags = lattice[SSA_NAME_VERSION (name)].flags;
1960 /* Eliminate useless flags so we do not end up storing unnecessary
1961 summaries. */
1963 flags = remove_useless_eaf_flags
1964 (flags, ecf_flags,
1965 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
1967 if (flags)
1969 if (summary)
1971 if (parm_index >= summary->arg_flags.length ())
1972 summary->arg_flags.safe_grow_cleared (count, true);
1973 summary->arg_flags[parm_index] = flags;
1975 else if (summary_lto)
1977 if (parm_index >= summary_lto->arg_flags.length ())
1978 summary_lto->arg_flags.safe_grow_cleared (count, true);
1979 summary_lto->arg_flags[parm_index] = flags;
1981 if (lattice[SSA_NAME_VERSION (name)].escape_points.length ())
1983 escape_point *ep;
1984 unsigned int ip;
1985 cgraph_node *node = cgraph_node::get (current_function_decl);
1987 gcc_checking_assert (ipa);
1988 FOR_EACH_VEC_ELT
1989 (lattice[SSA_NAME_VERSION (name)].escape_points, ip, ep)
1990 if ((ep->min_flags & flags) != flags)
1992 cgraph_edge *e = node->get_edge (ep->call);
1993 struct escape_entry ee = {parm_index, ep->arg,
1994 ep->min_flags, ep->direct};
1996 escape_summaries->get_create (e)->esc.safe_push (ee);
2001 if (ipa)
2002 for (unsigned int i = 0; i < num_ssa_names; i++)
2003 lattice[i].release ();
2006 /* Analyze function F. IPA indicates whether we're running in local mode
2007 (false) or the IPA mode (true). */
2009 static void
2010 analyze_function (function *f, bool ipa)
2012 if (dump_file)
2013 fprintf (dump_file, "modref analyzing '%s' (ipa=%i)%s%s\n",
2014 function_name (f), ipa,
2015 TREE_READONLY (current_function_decl) ? " (const)" : "",
2016 DECL_PURE_P (current_function_decl) ? " (pure)" : "");
2018 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
2019 if (!flag_ipa_modref)
2020 return;
2022 /* Compute no-LTO summaries when local optimization is going to happen. */
2023 bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
2024 || (in_lto_p && !flag_wpa
2025 && flag_incremental_link != INCREMENTAL_LINK_LTO));
2026 /* Compute LTO when LTO streaming is going to happen. */
2027 bool lto = ipa && ((flag_lto && !in_lto_p)
2028 || flag_wpa
2029 || flag_incremental_link == INCREMENTAL_LINK_LTO);
2030 cgraph_node *fnode = cgraph_node::get (current_function_decl);
2032 modref_summary *summary = NULL;
2033 modref_summary_lto *summary_lto = NULL;
2035 /* Initialize the summary.
2036 If we run in local mode there is possibly pre-existing summary from
2037 IPA pass. Dump it so it is easy to compare if mod-ref info has
2038 improved. */
2039 if (!ipa)
2041 if (!optimization_summaries)
2042 optimization_summaries = modref_summaries::create_ggc (symtab);
2043 else /* Remove existing summary if we are re-running the pass. */
2045 if (dump_file
2046 && (summary
2047 = optimization_summaries->get (cgraph_node::get (f->decl)))
2048 != NULL
2049 && summary->loads)
2051 fprintf (dump_file, "Past summary:\n");
2052 optimization_summaries->get
2053 (cgraph_node::get (f->decl))->dump (dump_file);
2055 optimization_summaries->remove (cgraph_node::get (f->decl));
2057 summary = optimization_summaries->get_create (cgraph_node::get (f->decl));
2058 gcc_checking_assert (nolto && !lto);
2060 /* In IPA mode we analyze every function precisely once. Assert that. */
2061 else
2063 if (nolto)
2065 if (!summaries)
2066 summaries = modref_summaries::create_ggc (symtab);
2067 else
2068 summaries->remove (cgraph_node::get (f->decl));
2069 summary = summaries->get_create (cgraph_node::get (f->decl));
2071 if (lto)
2073 if (!summaries_lto)
2074 summaries_lto = modref_summaries_lto::create_ggc (symtab);
2075 else
2076 summaries_lto->remove (cgraph_node::get (f->decl));
2077 summary_lto = summaries_lto->get_create (cgraph_node::get (f->decl));
2079 if (!fnspec_summaries)
2080 fnspec_summaries = new fnspec_summaries_t (symtab);
2081 if (!escape_summaries)
2082 escape_summaries = new escape_summaries_t (symtab);
2086 /* Create and initialize summary for F.
2087 Note that summaries may be already allocated from previous
2088 run of the pass. */
2089 if (nolto)
2091 gcc_assert (!summary->loads);
2092 summary->loads = modref_records::create_ggc (param_modref_max_bases,
2093 param_modref_max_refs,
2094 param_modref_max_accesses);
2095 gcc_assert (!summary->stores);
2096 summary->stores = modref_records::create_ggc (param_modref_max_bases,
2097 param_modref_max_refs,
2098 param_modref_max_accesses);
2099 summary->writes_errno = false;
2101 if (lto)
2103 gcc_assert (!summary_lto->loads);
2104 summary_lto->loads = modref_records_lto::create_ggc
2105 (param_modref_max_bases,
2106 param_modref_max_refs,
2107 param_modref_max_accesses);
2108 gcc_assert (!summary_lto->stores);
2109 summary_lto->stores = modref_records_lto::create_ggc
2110 (param_modref_max_bases,
2111 param_modref_max_refs,
2112 param_modref_max_accesses);
2113 summary_lto->writes_errno = false;
2116 analyze_parms (summary, summary_lto, ipa);
2118 int ecf_flags = flags_from_decl_or_type (current_function_decl);
2119 auto_vec <gimple *, 32> recursive_calls;
2121 /* Analyze each statement in each basic block of the function. If the
2122 statement cannot be analyzed (for any reason), the entire function cannot
2123 be analyzed by modref. */
2124 basic_block bb;
2125 FOR_EACH_BB_FN (bb, f)
2127 gimple_stmt_iterator si;
2128 for (si = gsi_start_nondebug_after_labels_bb (bb);
2129 !gsi_end_p (si); gsi_next_nondebug (&si))
2131 if (!analyze_stmt (summary, summary_lto,
2132 gsi_stmt (si), ipa, &recursive_calls)
2133 || ((!summary || !summary->useful_p (ecf_flags, false))
2134 && (!summary_lto
2135 || !summary_lto->useful_p (ecf_flags, false))))
2137 collapse_loads (summary, summary_lto);
2138 collapse_stores (summary, summary_lto);
2139 break;
2144 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2145 This needs to be done after all other side effects are computed. */
2146 if (!ipa)
2148 bool changed = true;
2149 bool first = true;
2150 while (changed)
2152 changed = false;
2153 for (unsigned i = 0; i < recursive_calls.length (); i++)
2155 changed |= merge_call_side_effects
2156 (summary, recursive_calls[i], summary,
2157 ignore_stores_p (current_function_decl,
2158 gimple_call_flags
2159 (recursive_calls[i])),
2160 fnode, !first);
2161 if (!summary->useful_p (ecf_flags, false))
2163 remove_summary (lto, nolto, ipa);
2164 return;
2167 first = false;
2170 if (summary && !summary->useful_p (ecf_flags))
2172 if (!ipa)
2173 optimization_summaries->remove (fnode);
2174 else
2175 summaries->remove (fnode);
2176 summary = NULL;
2178 if (summary_lto && !summary_lto->useful_p (ecf_flags))
2180 summaries_lto->remove (fnode);
2181 summary_lto = NULL;
2183 if (ipa && !summary && !summary_lto)
2184 remove_modref_edge_summaries (fnode);
2186 if (dump_file)
2188 fprintf (dump_file, " - modref done with result: tracked.\n");
2189 if (summary)
2190 summary->dump (dump_file);
2191 if (summary_lto)
2192 summary_lto->dump (dump_file);
2193 dump_modref_edge_summaries (dump_file, fnode, 2);
2197 /* Callback for generate_summary. */
2199 static void
2200 modref_generate (void)
2202 struct cgraph_node *node;
2203 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
2205 function *f = DECL_STRUCT_FUNCTION (node->decl);
2206 if (!f)
2207 continue;
2208 push_cfun (f);
2209 analyze_function (f, true);
2210 pop_cfun ();
2214 /* Called when a new function is inserted to callgraph late. */
2216 void
2217 modref_summaries::insert (struct cgraph_node *node, modref_summary *)
2219 /* Local passes ought to be executed by the pass manager. */
2220 if (this == optimization_summaries)
2222 optimization_summaries->remove (node);
2223 return;
2225 if (!DECL_STRUCT_FUNCTION (node->decl)
2226 || !opt_for_fn (node->decl, flag_ipa_modref))
2228 summaries->remove (node);
2229 return;
2231 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2232 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2233 pop_cfun ();
2236 /* Called when a new function is inserted to callgraph late. */
2238 void
2239 modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
2241 /* We do not support adding new function when IPA information is already
2242 propagated. This is done only by SIMD cloning that is not very
2243 critical. */
2244 if (!DECL_STRUCT_FUNCTION (node->decl)
2245 || !opt_for_fn (node->decl, flag_ipa_modref)
2246 || propagated)
2248 summaries_lto->remove (node);
2249 return;
2251 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2252 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2253 pop_cfun ();
2256 /* Called when new clone is inserted to callgraph late. */
2258 void
2259 modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
2260 modref_summary *src_data,
2261 modref_summary *dst_data)
2263 /* Do not duplicate optimization summaries; we do not handle parameter
2264 transforms on them. */
2265 if (this == optimization_summaries)
2267 optimization_summaries->remove (dst);
2268 return;
2270 dst_data->stores = modref_records::create_ggc
2271 (src_data->stores->max_bases,
2272 src_data->stores->max_refs,
2273 src_data->stores->max_accesses);
2274 dst_data->stores->copy_from (src_data->stores);
2275 dst_data->loads = modref_records::create_ggc
2276 (src_data->loads->max_bases,
2277 src_data->loads->max_refs,
2278 src_data->loads->max_accesses);
2279 dst_data->loads->copy_from (src_data->loads);
2280 dst_data->writes_errno = src_data->writes_errno;
2281 if (src_data->arg_flags.length ())
2282 dst_data->arg_flags = src_data->arg_flags.copy ();
2285 /* Called when new clone is inserted to callgraph late. */
2287 void
2288 modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
2289 modref_summary_lto *src_data,
2290 modref_summary_lto *dst_data)
2292 /* Be sure that no further cloning happens after ipa-modref. If it does
2293 we will need to update signatures for possible param changes. */
2294 gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
2295 dst_data->stores = modref_records_lto::create_ggc
2296 (src_data->stores->max_bases,
2297 src_data->stores->max_refs,
2298 src_data->stores->max_accesses);
2299 dst_data->stores->copy_from (src_data->stores);
2300 dst_data->loads = modref_records_lto::create_ggc
2301 (src_data->loads->max_bases,
2302 src_data->loads->max_refs,
2303 src_data->loads->max_accesses);
2304 dst_data->loads->copy_from (src_data->loads);
2305 dst_data->writes_errno = src_data->writes_errno;
2306 if (src_data->arg_flags.length ())
2307 dst_data->arg_flags = src_data->arg_flags.copy ();
2310 namespace
2312 /* Definition of the modref pass on GIMPLE. */
2313 const pass_data pass_data_modref = {
2314 GIMPLE_PASS,
2315 "modref",
2316 OPTGROUP_IPA,
2317 TV_TREE_MODREF,
2318 (PROP_cfg | PROP_ssa),
2325 class pass_modref : public gimple_opt_pass
2327 public:
2328 pass_modref (gcc::context *ctxt)
2329 : gimple_opt_pass (pass_data_modref, ctxt) {}
2331 /* opt_pass methods: */
2332 opt_pass *clone ()
2334 return new pass_modref (m_ctxt);
2336 virtual bool gate (function *)
2338 return flag_ipa_modref;
2340 virtual unsigned int execute (function *);
2343 /* Encode TT to the output block OB using the summary streaming API. */
2345 static void
2346 write_modref_records (modref_records_lto *tt, struct output_block *ob)
2348 streamer_write_uhwi (ob, tt->max_bases);
2349 streamer_write_uhwi (ob, tt->max_refs);
2350 streamer_write_uhwi (ob, tt->max_accesses);
2352 streamer_write_uhwi (ob, tt->every_base);
2353 streamer_write_uhwi (ob, vec_safe_length (tt->bases));
2354 size_t i;
2355 modref_base_node <tree> *base_node;
2356 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, base_node)
2358 stream_write_tree (ob, base_node->base, true);
2360 streamer_write_uhwi (ob, base_node->every_ref);
2361 streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
2363 size_t j;
2364 modref_ref_node <tree> *ref_node;
2365 FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
2367 stream_write_tree (ob, ref_node->ref, true);
2368 streamer_write_uhwi (ob, ref_node->every_access);
2369 streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
2371 size_t k;
2372 modref_access_node *access_node;
2373 FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
2375 streamer_write_hwi (ob, access_node->parm_index);
2376 if (access_node->parm_index != -1)
2378 streamer_write_uhwi (ob, access_node->parm_offset_known);
2379 if (access_node->parm_offset_known)
2381 streamer_write_poly_int64 (ob, access_node->parm_offset);
2382 streamer_write_poly_int64 (ob, access_node->offset);
2383 streamer_write_poly_int64 (ob, access_node->size);
2384 streamer_write_poly_int64 (ob, access_node->max_size);
2392 /* Read a modref_tree from the input block IB using the data from DATA_IN.
2393 This assumes that the tree was encoded using write_modref_tree.
2394 Either nolto_ret or lto_ret is initialized by the tree depending whether
2395 LTO streaming is expected or not. */
2397 void
2398 read_modref_records (lto_input_block *ib, struct data_in *data_in,
2399 modref_records **nolto_ret,
2400 modref_records_lto **lto_ret)
2402 size_t max_bases = streamer_read_uhwi (ib);
2403 size_t max_refs = streamer_read_uhwi (ib);
2404 size_t max_accesses = streamer_read_uhwi (ib);
2406 if (lto_ret)
2407 *lto_ret = modref_records_lto::create_ggc (max_bases, max_refs,
2408 max_accesses);
2409 if (nolto_ret)
2410 *nolto_ret = modref_records::create_ggc (max_bases, max_refs,
2411 max_accesses);
2412 gcc_checking_assert (lto_ret || nolto_ret);
2414 size_t every_base = streamer_read_uhwi (ib);
2415 size_t nbase = streamer_read_uhwi (ib);
2417 gcc_assert (!every_base || nbase == 0);
2418 if (every_base)
2420 if (nolto_ret)
2421 (*nolto_ret)->collapse ();
2422 if (lto_ret)
2423 (*lto_ret)->collapse ();
2425 for (size_t i = 0; i < nbase; i++)
2427 tree base_tree = stream_read_tree (ib, data_in);
2428 modref_base_node <alias_set_type> *nolto_base_node = NULL;
2429 modref_base_node <tree> *lto_base_node = NULL;
2431 /* At stream in time we have LTO alias info. Check if we streamed in
2432 something obviously unnecessary. Do not glob types by alias sets;
2433 it is not 100% clear that ltrans types will get merged same way.
2434 Types may get refined based on ODR type conflicts. */
2435 if (base_tree && !get_alias_set (base_tree))
2437 if (dump_file)
2439 fprintf (dump_file, "Streamed in alias set 0 type ");
2440 print_generic_expr (dump_file, base_tree);
2441 fprintf (dump_file, "\n");
2443 base_tree = NULL;
2446 if (nolto_ret)
2447 nolto_base_node = (*nolto_ret)->insert_base (base_tree
2448 ? get_alias_set (base_tree)
2449 : 0, 0);
2450 if (lto_ret)
2451 lto_base_node = (*lto_ret)->insert_base (base_tree, 0);
2452 size_t every_ref = streamer_read_uhwi (ib);
2453 size_t nref = streamer_read_uhwi (ib);
2455 gcc_assert (!every_ref || nref == 0);
2456 if (every_ref)
2458 if (nolto_base_node)
2459 nolto_base_node->collapse ();
2460 if (lto_base_node)
2461 lto_base_node->collapse ();
2463 for (size_t j = 0; j < nref; j++)
2465 tree ref_tree = stream_read_tree (ib, data_in);
2467 if (ref_tree && !get_alias_set (ref_tree))
2469 if (dump_file)
2471 fprintf (dump_file, "Streamed in alias set 0 type ");
2472 print_generic_expr (dump_file, ref_tree);
2473 fprintf (dump_file, "\n");
2475 ref_tree = NULL;
2478 modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
2479 modref_ref_node <tree> *lto_ref_node = NULL;
2481 if (nolto_base_node)
2482 nolto_ref_node
2483 = nolto_base_node->insert_ref (ref_tree
2484 ? get_alias_set (ref_tree) : 0,
2485 max_refs);
2486 if (lto_base_node)
2487 lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
2489 size_t every_access = streamer_read_uhwi (ib);
2490 size_t naccesses = streamer_read_uhwi (ib);
2492 if (nolto_ref_node)
2493 nolto_ref_node->every_access = every_access;
2494 if (lto_ref_node)
2495 lto_ref_node->every_access = every_access;
2497 for (size_t k = 0; k < naccesses; k++)
2499 int parm_index = streamer_read_hwi (ib);
2500 bool parm_offset_known = false;
2501 poly_int64 parm_offset = 0;
2502 poly_int64 offset = 0;
2503 poly_int64 size = -1;
2504 poly_int64 max_size = -1;
2506 if (parm_index != -1)
2508 parm_offset_known = streamer_read_uhwi (ib);
2509 if (parm_offset_known)
2511 parm_offset = streamer_read_poly_int64 (ib);
2512 offset = streamer_read_poly_int64 (ib);
2513 size = streamer_read_poly_int64 (ib);
2514 max_size = streamer_read_poly_int64 (ib);
2517 modref_access_node a = {offset, size, max_size, parm_offset,
2518 parm_index, parm_offset_known, false};
2519 if (nolto_ref_node)
2520 nolto_ref_node->insert_access (a, max_accesses, false);
2521 if (lto_ref_node)
2522 lto_ref_node->insert_access (a, max_accesses, false);
2526 if (lto_ret)
2527 (*lto_ret)->cleanup ();
2528 if (nolto_ret)
2529 (*nolto_ret)->cleanup ();
2532 /* Write ESUM to BP. */
2534 static void
2535 modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
2537 if (!esum)
2539 bp_pack_var_len_unsigned (bp, 0);
2540 return;
2542 bp_pack_var_len_unsigned (bp, esum->esc.length ());
2543 unsigned int i;
2544 escape_entry *ee;
2545 FOR_EACH_VEC_ELT (esum->esc, i, ee)
2547 bp_pack_var_len_unsigned (bp, ee->parm_index);
2548 bp_pack_var_len_unsigned (bp, ee->arg);
2549 bp_pack_var_len_unsigned (bp, ee->min_flags);
2550 bp_pack_value (bp, ee->direct, 1);
2554 /* Read escape summary for E from BP. */
2556 static void
2557 modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
2559 unsigned int n = bp_unpack_var_len_unsigned (bp);
2560 if (!n)
2561 return;
2562 escape_summary *esum = escape_summaries->get_create (e);
2563 esum->esc.reserve_exact (n);
2564 for (unsigned int i = 0; i < n; i++)
2566 escape_entry ee;
2567 ee.parm_index = bp_unpack_var_len_unsigned (bp);
2568 ee.arg = bp_unpack_var_len_unsigned (bp);
2569 ee.min_flags = bp_unpack_var_len_unsigned (bp);
2570 ee.direct = bp_unpack_value (bp, 1);
2571 esum->esc.quick_push (ee);
2575 /* Callback for write_summary. */
2577 static void
2578 modref_write ()
2580 struct output_block *ob = create_output_block (LTO_section_ipa_modref);
2581 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
2582 unsigned int count = 0;
2583 int i;
2585 if (!summaries_lto)
2587 streamer_write_uhwi (ob, 0);
2588 streamer_write_char_stream (ob->main_stream, 0);
2589 produce_asm (ob, NULL);
2590 destroy_output_block (ob);
2591 return;
2594 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
2596 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
2597 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
2598 modref_summary_lto *r;
2600 if (cnode && cnode->definition && !cnode->alias
2601 && (r = summaries_lto->get (cnode))
2602 && r->useful_p (flags_from_decl_or_type (cnode->decl)))
2603 count++;
2605 streamer_write_uhwi (ob, count);
2607 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
2609 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
2610 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
2612 if (cnode && cnode->definition && !cnode->alias)
2614 modref_summary_lto *r = summaries_lto->get (cnode);
2616 if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
2617 continue;
2619 streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
2621 streamer_write_uhwi (ob, r->arg_flags.length ());
2622 for (unsigned int i = 0; i < r->arg_flags.length (); i++)
2623 streamer_write_uhwi (ob, r->arg_flags[i]);
2625 write_modref_records (r->loads, ob);
2626 write_modref_records (r->stores, ob);
2628 struct bitpack_d bp = bitpack_create (ob->main_stream);
2629 bp_pack_value (&bp, r->writes_errno, 1);
2630 if (!flag_wpa)
2632 for (cgraph_edge *e = cnode->indirect_calls;
2633 e; e = e->next_callee)
2635 class fnspec_summary *sum = fnspec_summaries->get (e);
2636 bp_pack_value (&bp, sum != NULL, 1);
2637 if (sum)
2638 bp_pack_string (ob, &bp, sum->fnspec, true);
2639 class escape_summary *esum = escape_summaries->get (e);
2640 modref_write_escape_summary (&bp,esum);
2642 for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
2644 class fnspec_summary *sum = fnspec_summaries->get (e);
2645 bp_pack_value (&bp, sum != NULL, 1);
2646 if (sum)
2647 bp_pack_string (ob, &bp, sum->fnspec, true);
2648 class escape_summary *esum = escape_summaries->get (e);
2649 modref_write_escape_summary (&bp,esum);
2652 streamer_write_bitpack (&bp);
2655 streamer_write_char_stream (ob->main_stream, 0);
2656 produce_asm (ob, NULL);
2657 destroy_output_block (ob);
2660 static void
2661 read_section (struct lto_file_decl_data *file_data, const char *data,
2662 size_t len)
2664 const struct lto_function_header *header
2665 = (const struct lto_function_header *) data;
2666 const int cfg_offset = sizeof (struct lto_function_header);
2667 const int main_offset = cfg_offset + header->cfg_size;
2668 const int string_offset = main_offset + header->main_size;
2669 struct data_in *data_in;
2670 unsigned int i;
2671 unsigned int f_count;
2673 lto_input_block ib ((const char *) data + main_offset, header->main_size,
2674 file_data->mode_table);
2676 data_in
2677 = lto_data_in_create (file_data, (const char *) data + string_offset,
2678 header->string_size, vNULL);
2679 f_count = streamer_read_uhwi (&ib);
2680 for (i = 0; i < f_count; i++)
2682 struct cgraph_node *node;
2683 lto_symtab_encoder_t encoder;
2685 unsigned int index = streamer_read_uhwi (&ib);
2686 encoder = file_data->symtab_node_encoder;
2687 node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
2688 index));
2690 modref_summary *modref_sum = summaries
2691 ? summaries->get_create (node) : NULL;
2692 modref_summary_lto *modref_sum_lto = summaries_lto
2693 ? summaries_lto->get_create (node)
2694 : NULL;
2695 if (optimization_summaries)
2696 modref_sum = optimization_summaries->get_create (node);
2698 if (modref_sum)
2699 modref_sum->writes_errno = false;
2700 if (modref_sum_lto)
2701 modref_sum_lto->writes_errno = false;
2703 gcc_assert (!modref_sum || (!modref_sum->loads
2704 && !modref_sum->stores));
2705 gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
2706 && !modref_sum_lto->stores));
2707 unsigned int args = streamer_read_uhwi (&ib);
2708 if (args && modref_sum)
2709 modref_sum->arg_flags.reserve_exact (args);
2710 if (args && modref_sum_lto)
2711 modref_sum_lto->arg_flags.reserve_exact (args);
2712 for (unsigned int i = 0; i < args; i++)
2714 eaf_flags_t flags = streamer_read_uhwi (&ib);
2715 if (modref_sum)
2716 modref_sum->arg_flags.quick_push (flags);
2717 if (modref_sum_lto)
2718 modref_sum_lto->arg_flags.quick_push (flags);
2720 read_modref_records (&ib, data_in,
2721 modref_sum ? &modref_sum->loads : NULL,
2722 modref_sum_lto ? &modref_sum_lto->loads : NULL);
2723 read_modref_records (&ib, data_in,
2724 modref_sum ? &modref_sum->stores : NULL,
2725 modref_sum_lto ? &modref_sum_lto->stores : NULL);
2726 struct bitpack_d bp = streamer_read_bitpack (&ib);
2727 if (bp_unpack_value (&bp, 1))
2729 if (modref_sum)
2730 modref_sum->writes_errno = true;
2731 if (modref_sum_lto)
2732 modref_sum_lto->writes_errno = true;
2734 if (!flag_ltrans)
2736 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
2738 if (bp_unpack_value (&bp, 1))
2740 class fnspec_summary *sum = fnspec_summaries->get_create (e);
2741 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
2743 modref_read_escape_summary (&bp, e);
2745 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
2747 if (bp_unpack_value (&bp, 1))
2749 class fnspec_summary *sum = fnspec_summaries->get_create (e);
2750 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
2752 modref_read_escape_summary (&bp, e);
2755 if (dump_file)
2757 fprintf (dump_file, "Read modref for %s\n",
2758 node->dump_name ());
2759 if (modref_sum)
2760 modref_sum->dump (dump_file);
2761 if (modref_sum_lto)
2762 modref_sum_lto->dump (dump_file);
2763 dump_modref_edge_summaries (dump_file, node, 4);
2767 lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
2768 len);
2769 lto_data_in_delete (data_in);
2772 /* Callback for read_summary. */
2774 static void
2775 modref_read (void)
2777 struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
2778 struct lto_file_decl_data *file_data;
2779 unsigned int j = 0;
2781 gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
2782 if (flag_ltrans)
2783 optimization_summaries = modref_summaries::create_ggc (symtab);
2784 else
2786 if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
2787 summaries_lto = modref_summaries_lto::create_ggc (symtab);
2788 if (!flag_wpa
2789 || (flag_incremental_link == INCREMENTAL_LINK_LTO
2790 && flag_fat_lto_objects))
2791 summaries = modref_summaries::create_ggc (symtab);
2792 if (!fnspec_summaries)
2793 fnspec_summaries = new fnspec_summaries_t (symtab);
2794 if (!escape_summaries)
2795 escape_summaries = new escape_summaries_t (symtab);
2798 while ((file_data = file_data_vec[j++]))
2800 size_t len;
2801 const char *data = lto_get_summary_section_data (file_data,
2802 LTO_section_ipa_modref,
2803 &len);
2804 if (data)
2805 read_section (file_data, data, len);
2806 else
2807 /* Fatal error here. We do not want to support compiling ltrans units
2808 with different version of compiler or different flags than the WPA
2809 unit, so this should never happen. */
2810 fatal_error (input_location,
2811 "IPA modref summary is missing in input file");
2815 /* Recompute arg_flags for param adjustments in INFO. */
2817 static void
2818 remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
2820 auto_vec<eaf_flags_t> old = arg_flags.copy ();
2821 int max = -1;
2822 size_t i;
2823 ipa_adjusted_param *p;
2825 arg_flags.release ();
2827 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2829 int o = info->param_adjustments->get_original_index (i);
2830 if (o >= 0 && (int)old.length () > o && old[o])
2831 max = i;
2833 if (max >= 0)
2834 arg_flags.safe_grow_cleared (max + 1, true);
2835 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2837 int o = info->param_adjustments->get_original_index (i);
2838 if (o >= 0 && (int)old.length () > o && old[o])
2839 arg_flags[i] = old[o];
2843 /* If signature changed, update the summary. */
2845 static void
2846 update_signature (struct cgraph_node *node)
2848 clone_info *info = clone_info::get (node);
2849 if (!info || !info->param_adjustments)
2850 return;
2852 modref_summary *r = optimization_summaries
2853 ? optimization_summaries->get (node) : NULL;
2854 modref_summary_lto *r_lto = summaries_lto
2855 ? summaries_lto->get (node) : NULL;
2856 if (!r && !r_lto)
2857 return;
2858 if (dump_file)
2860 fprintf (dump_file, "Updating summary for %s from:\n",
2861 node->dump_name ());
2862 if (r)
2863 r->dump (dump_file);
2864 if (r_lto)
2865 r_lto->dump (dump_file);
2868 size_t i, max = 0;
2869 ipa_adjusted_param *p;
2871 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2873 int idx = info->param_adjustments->get_original_index (i);
2874 if (idx > (int)max)
2875 max = idx;
2878 auto_vec <int, 32> map;
2880 map.reserve (max + 1);
2881 for (i = 0; i <= max; i++)
2882 map.quick_push (-1);
2883 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2885 int idx = info->param_adjustments->get_original_index (i);
2886 if (idx >= 0)
2887 map[idx] = i;
2889 if (r)
2891 r->loads->remap_params (&map);
2892 r->stores->remap_params (&map);
2893 if (r->arg_flags.length ())
2894 remap_arg_flags (r->arg_flags, info);
2896 if (r_lto)
2898 r_lto->loads->remap_params (&map);
2899 r_lto->stores->remap_params (&map);
2900 if (r_lto->arg_flags.length ())
2901 remap_arg_flags (r_lto->arg_flags, info);
2903 if (dump_file)
2905 fprintf (dump_file, "to:\n");
2906 if (r)
2907 r->dump (dump_file);
2908 if (r_lto)
2909 r_lto->dump (dump_file);
2911 return;
2914 /* Definition of the modref IPA pass. */
2915 const pass_data pass_data_ipa_modref =
2917 IPA_PASS, /* type */
2918 "modref", /* name */
2919 OPTGROUP_IPA, /* optinfo_flags */
2920 TV_IPA_MODREF, /* tv_id */
2921 0, /* properties_required */
2922 0, /* properties_provided */
2923 0, /* properties_destroyed */
2924 0, /* todo_flags_start */
2925 ( TODO_dump_symtab ), /* todo_flags_finish */
2928 class pass_ipa_modref : public ipa_opt_pass_d
2930 public:
2931 pass_ipa_modref (gcc::context *ctxt)
2932 : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
2933 modref_generate, /* generate_summary */
2934 modref_write, /* write_summary */
2935 modref_read, /* read_summary */
2936 modref_write, /* write_optimization_summary */
2937 modref_read, /* read_optimization_summary */
2938 NULL, /* stmt_fixup */
2939 0, /* function_transform_todo_flags_start */
2940 NULL, /* function_transform */
2941 NULL) /* variable_transform */
2944 /* opt_pass methods: */
2945 opt_pass *clone () { return new pass_ipa_modref (m_ctxt); }
2946 virtual bool gate (function *)
2948 return true;
2950 virtual unsigned int execute (function *);
2956 unsigned int pass_modref::execute (function *f)
2958 analyze_function (f, false);
2959 return 0;
2962 gimple_opt_pass *
2963 make_pass_modref (gcc::context *ctxt)
2965 return new pass_modref (ctxt);
2968 ipa_opt_pass_d *
2969 make_pass_ipa_modref (gcc::context *ctxt)
2971 return new pass_ipa_modref (ctxt);
2974 /* Skip edges from and to nodes without ipa_pure_const enabled.
2975 Ignore not available symbols. */
2977 static bool
2978 ignore_edge (struct cgraph_edge *e)
2980 /* We merge summaries of inline clones into summaries of functions they
2981 are inlined to. For that reason the complete function bodies must
2982 act as unit. */
2983 if (!e->inline_failed)
2984 return false;
2985 enum availability avail;
2986 cgraph_node *callee = e->callee->function_or_virtual_thunk_symbol
2987 (&avail, e->caller);
2989 return (avail <= AVAIL_INTERPOSABLE
2990 || ((!optimization_summaries || !optimization_summaries->get (callee))
2991 && (!summaries_lto || !summaries_lto->get (callee)))
2992 || flags_from_decl_or_type (e->callee->decl)
2993 & (ECF_CONST | ECF_NOVOPS));
2996 /* Compute parm_map for CALLEE_EDGE. */
2998 static bool
2999 compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
3001 class ipa_edge_args *args;
3002 if (ipa_node_params_sum
3003 && !callee_edge->call_stmt_cannot_inline_p
3004 && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
3006 int i, count = ipa_get_cs_argument_count (args);
3007 class ipa_node_params *caller_parms_info, *callee_pi;
3008 class ipa_call_summary *es
3009 = ipa_call_summaries->get (callee_edge);
3010 cgraph_node *callee
3011 = callee_edge->callee->function_or_virtual_thunk_symbol
3012 (NULL, callee_edge->caller);
3014 caller_parms_info
3015 = ipa_node_params_sum->get (callee_edge->caller->inlined_to
3016 ? callee_edge->caller->inlined_to
3017 : callee_edge->caller);
3018 callee_pi = ipa_node_params_sum->get (callee);
3020 (*parm_map).safe_grow_cleared (count, true);
3022 for (i = 0; i < count; i++)
3024 if (es && es->param[i].points_to_local_or_readonly_memory)
3026 (*parm_map)[i].parm_index = -2;
3027 continue;
3030 struct ipa_jump_func *jf
3031 = ipa_get_ith_jump_func (args, i);
3032 if (jf && callee_pi)
3034 tree cst = ipa_value_from_jfunc (caller_parms_info,
3036 ipa_get_type
3037 (callee_pi, i));
3038 if (cst && points_to_local_or_readonly_memory_p (cst))
3040 (*parm_map)[i].parm_index = -2;
3041 continue;
3044 if (jf && jf->type == IPA_JF_PASS_THROUGH)
3046 (*parm_map)[i].parm_index
3047 = ipa_get_jf_pass_through_formal_id (jf);
3048 if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
3050 (*parm_map)[i].parm_offset_known = true;
3051 (*parm_map)[i].parm_offset = 0;
3053 else if (ipa_get_jf_pass_through_operation (jf)
3054 == POINTER_PLUS_EXPR
3055 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
3056 &(*parm_map)[i].parm_offset))
3057 (*parm_map)[i].parm_offset_known = true;
3058 else
3059 (*parm_map)[i].parm_offset_known = false;
3060 continue;
3062 if (jf && jf->type == IPA_JF_ANCESTOR)
3064 (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
3065 (*parm_map)[i].parm_offset_known = true;
3066 gcc_checking_assert
3067 (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
3068 (*parm_map)[i].parm_offset
3069 = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
3071 else
3072 (*parm_map)[i].parm_index = -1;
3074 if (dump_file)
3076 fprintf (dump_file, " Parm map: ");
3077 for (i = 0; i < count; i++)
3078 fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
3079 fprintf (dump_file, "\n");
3081 return true;
3083 return false;
3086 /* Map used to translate escape infos. */
3088 struct escape_map
3090 int parm_index;
3091 bool direct;
3094 /* Update escape map fo E. */
3096 static void
3097 update_escape_summary_1 (cgraph_edge *e,
3098 vec <vec <escape_map>> &map,
3099 bool ignore_stores)
3101 escape_summary *sum = escape_summaries->get (e);
3102 if (!sum)
3103 return;
3104 auto_vec <escape_entry> old = sum->esc.copy ();
3105 sum->esc.release ();
3107 unsigned int i;
3108 escape_entry *ee;
3109 FOR_EACH_VEC_ELT (old, i, ee)
3111 unsigned int j;
3112 struct escape_map *em;
3113 if (ee->parm_index >= map.length ())
3114 continue;
3115 FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
3117 int min_flags = ee->min_flags;
3118 if (ee->direct && !em->direct)
3119 min_flags = deref_flags (min_flags, ignore_stores);
3120 struct escape_entry entry = {em->parm_index, ee->arg,
3121 ee->min_flags,
3122 ee->direct & em->direct};
3123 sum->esc.safe_push (entry);
3126 if (!sum->esc.length ())
3127 escape_summaries->remove (e);
3130 /* Update escape map fo NODE. */
3132 static void
3133 update_escape_summary (cgraph_node *node,
3134 vec <vec <escape_map>> &map,
3135 bool ignore_stores)
3137 if (!escape_summaries)
3138 return;
3139 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
3140 update_escape_summary_1 (e, map, ignore_stores);
3141 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3143 if (!e->inline_failed)
3144 update_escape_summary (e->callee, map, ignore_stores);
3145 else
3146 update_escape_summary_1 (e, map, ignore_stores);
3150 /* Call EDGE was inlined; merge summary from callee to the caller. */
3152 void
3153 ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
3155 if (!summaries && !summaries_lto)
3156 return;
3158 struct cgraph_node *to = (edge->caller->inlined_to
3159 ? edge->caller->inlined_to : edge->caller);
3160 class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
3161 class modref_summary_lto *to_info_lto = summaries_lto
3162 ? summaries_lto->get (to) : NULL;
3164 if (!to_info && !to_info_lto)
3166 if (summaries)
3167 summaries->remove (edge->callee);
3168 if (summaries_lto)
3169 summaries_lto->remove (edge->callee);
3170 remove_modref_edge_summaries (edge->callee);
3171 return;
3174 class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
3175 : NULL;
3176 class modref_summary_lto *callee_info_lto
3177 = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
3178 int flags = flags_from_decl_or_type (edge->callee->decl);
3179 bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
3181 if (!callee_info && to_info)
3183 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3184 to_info->loads->collapse ();
3185 if (!ignore_stores)
3186 to_info->stores->collapse ();
3188 if (!callee_info_lto && to_info_lto)
3190 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3191 to_info_lto->loads->collapse ();
3192 if (!ignore_stores)
3193 to_info_lto->stores->collapse ();
3195 if (callee_info || callee_info_lto)
3197 auto_vec <modref_parm_map, 32> parm_map;
3199 compute_parm_map (edge, &parm_map);
3201 if (!ignore_stores)
3203 if (to_info && callee_info)
3204 to_info->stores->merge (callee_info->stores, &parm_map, false);
3205 if (to_info_lto && callee_info_lto)
3206 to_info_lto->stores->merge (callee_info_lto->stores, &parm_map,
3207 false);
3209 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3211 if (to_info && callee_info)
3212 to_info->loads->merge (callee_info->loads, &parm_map, false);
3213 if (to_info_lto && callee_info_lto)
3214 to_info_lto->loads->merge (callee_info_lto->loads, &parm_map,
3215 false);
3219 /* Now merge escape summaries.
3220 For every escape to the callee we need to merge calle flags
3221 and remap calees escapes. */
3222 class escape_summary *sum = escape_summaries->get (edge);
3223 int max_escape = -1;
3224 escape_entry *ee;
3225 unsigned int i;
3227 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
3228 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3229 if ((int)ee->arg > max_escape)
3230 max_escape = ee->arg;
3232 auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
3233 emap.safe_grow (max_escape + 1, true);
3234 for (i = 0; (int)i < max_escape + 1; i++)
3235 emap[i] = vNULL;
3237 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
3238 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3240 bool needed = false;
3241 if (to_info && to_info->arg_flags.length () > ee->parm_index)
3243 int flags = callee_info
3244 && callee_info->arg_flags.length () > ee->arg
3245 ? callee_info->arg_flags[ee->arg] : 0;
3246 if (!ee->direct)
3247 flags = deref_flags (flags, ignore_stores);
3248 else if (ignore_stores)
3249 flags |= ignore_stores_eaf_flags;
3250 flags |= ee->min_flags;
3251 to_info->arg_flags[ee->parm_index] &= flags;
3252 if (to_info->arg_flags[ee->parm_index])
3253 needed = true;
3255 if (to_info_lto && to_info_lto->arg_flags.length () > ee->parm_index)
3257 int flags = callee_info_lto
3258 && callee_info_lto->arg_flags.length () > ee->arg
3259 ? callee_info_lto->arg_flags[ee->arg] : 0;
3260 if (!ee->direct)
3261 flags = deref_flags (flags, ignore_stores);
3262 else if (ignore_stores)
3263 flags |= ignore_stores_eaf_flags;
3264 flags |= ee->min_flags;
3265 to_info_lto->arg_flags[ee->parm_index] &= flags;
3266 if (to_info_lto->arg_flags[ee->parm_index])
3267 needed = true;
3269 struct escape_map entry = {ee->parm_index, ee->direct};
3270 if (needed)
3271 emap[ee->arg].safe_push (entry);
3273 update_escape_summary (edge->callee, emap, ignore_stores);
3274 for (i = 0; (int)i < max_escape + 1; i++)
3275 emap[i].release ();
3276 if (sum)
3277 escape_summaries->remove (edge);
3279 if (summaries)
3281 if (to_info && !to_info->useful_p (flags))
3283 if (dump_file)
3284 fprintf (dump_file, "Removed mod-ref summary for %s\n",
3285 to->dump_name ());
3286 summaries->remove (to);
3287 to_info = NULL;
3289 else if (to_info && dump_file)
3291 if (dump_file)
3292 fprintf (dump_file, "Updated mod-ref summary for %s\n",
3293 to->dump_name ());
3294 to_info->dump (dump_file);
3296 if (callee_info)
3297 summaries->remove (edge->callee);
3299 if (summaries_lto)
3301 if (to_info_lto && !to_info_lto->useful_p (flags))
3303 if (dump_file)
3304 fprintf (dump_file, "Removed mod-ref summary for %s\n",
3305 to->dump_name ());
3306 summaries_lto->remove (to);
3308 else if (to_info_lto && dump_file)
3310 if (dump_file)
3311 fprintf (dump_file, "Updated mod-ref summary for %s\n",
3312 to->dump_name ());
3313 to_info_lto->dump (dump_file);
3314 to_info_lto = NULL;
3316 if (callee_info_lto)
3317 summaries_lto->remove (edge->callee);
3319 if (!to_info && !to_info_lto)
3320 remove_modref_edge_summaries (to);
3321 return;
3324 /* Get parameter type from DECL. This is only safe for special cases
3325 like builtins we create fnspec for because the type match is checked
3326 at fnspec creation time. */
3328 static tree
3329 get_parm_type (tree decl, unsigned int i)
3331 tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
3333 for (unsigned int p = 0; p < i; p++)
3334 t = TREE_CHAIN (t);
3335 return TREE_VALUE (t);
3338 /* Return access mode for argument I of call E with FNSPEC. */
3340 static modref_access_node
3341 get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
3342 unsigned int i, modref_parm_map &map)
3344 tree size = NULL_TREE;
3345 unsigned int size_arg;
3347 if (!fnspec.arg_specified_p (i))
3349 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
3351 cgraph_node *node = e->caller->inlined_to
3352 ? e->caller->inlined_to : e->caller;
3353 ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
3354 ipa_edge_args *args = ipa_edge_args_sum->get (e);
3355 struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
3357 if (jf)
3358 size = ipa_value_from_jfunc (caller_parms_info, jf,
3359 get_parm_type (e->callee->decl, size_arg));
3361 else if (fnspec.arg_access_size_given_by_type_p (i))
3362 size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
3363 modref_access_node a = {0, -1, -1,
3364 map.parm_offset, map.parm_index,
3365 map.parm_offset_known, 0};
3366 poly_int64 size_hwi;
3367 if (size
3368 && poly_int_tree_p (size, &size_hwi)
3369 && coeffs_in_range_p (size_hwi, 0,
3370 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
3372 a.size = -1;
3373 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
3375 return a;
3378 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
3379 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
3381 static bool
3382 propagate_unknown_call (cgraph_node *node,
3383 cgraph_edge *e, int ecf_flags,
3384 modref_summary *cur_summary,
3385 modref_summary_lto *cur_summary_lto)
3387 bool changed = false;
3388 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
3389 auto_vec <modref_parm_map, 32> parm_map;
3390 if (fnspec_sum
3391 && compute_parm_map (e, &parm_map))
3393 attr_fnspec fnspec (fnspec_sum->fnspec);
3395 gcc_checking_assert (fnspec.known_p ());
3396 if (fnspec.global_memory_read_p ())
3397 collapse_loads (cur_summary, cur_summary_lto);
3398 else
3400 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
3401 for (unsigned i = 0; i < parm_map.length () && t;
3402 i++, t = TREE_CHAIN (t))
3403 if (!POINTER_TYPE_P (TREE_VALUE (t)))
3405 else if (!fnspec.arg_specified_p (i)
3406 || fnspec.arg_maybe_read_p (i))
3408 modref_parm_map map = parm_map[i];
3409 if (map.parm_index == -2)
3410 continue;
3411 if (map.parm_index == -1)
3413 collapse_loads (cur_summary, cur_summary_lto);
3414 break;
3416 if (cur_summary)
3417 changed |= cur_summary->loads->insert
3418 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
3419 if (cur_summary_lto)
3420 changed |= cur_summary_lto->loads->insert
3421 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
3424 if (ignore_stores_p (node->decl, ecf_flags))
3426 else if (fnspec.global_memory_written_p ())
3427 collapse_stores (cur_summary, cur_summary_lto);
3428 else
3430 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
3431 for (unsigned i = 0; i < parm_map.length () && t;
3432 i++, t = TREE_CHAIN (t))
3433 if (!POINTER_TYPE_P (TREE_VALUE (t)))
3435 else if (!fnspec.arg_specified_p (i)
3436 || fnspec.arg_maybe_written_p (i))
3438 modref_parm_map map = parm_map[i];
3439 if (map.parm_index == -2)
3440 continue;
3441 if (map.parm_index == -1)
3443 collapse_stores (cur_summary, cur_summary_lto);
3444 break;
3446 if (cur_summary)
3447 changed |= cur_summary->stores->insert
3448 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
3449 if (cur_summary_lto)
3450 changed |= cur_summary_lto->stores->insert
3451 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
3454 if (fnspec.errno_maybe_written_p () && flag_errno_math)
3456 if (cur_summary && !cur_summary->writes_errno)
3458 cur_summary->writes_errno = true;
3459 changed = true;
3461 if (cur_summary_lto && !cur_summary_lto->writes_errno)
3463 cur_summary_lto->writes_errno = true;
3464 changed = true;
3467 return changed;
3469 if (dump_file)
3470 fprintf (dump_file, " collapsing loads\n");
3471 changed |= collapse_loads (cur_summary, cur_summary_lto);
3472 if (!ignore_stores_p (node->decl, ecf_flags))
3474 if (dump_file)
3475 fprintf (dump_file, " collapsing stores\n");
3476 changed |= collapse_stores (cur_summary, cur_summary_lto);
3478 return changed;
3481 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
3482 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
3484 static void
3485 remove_useless_summaries (cgraph_node *node,
3486 modref_summary **cur_summary_ptr,
3487 modref_summary_lto **cur_summary_lto_ptr,
3488 int ecf_flags)
3490 if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
3492 optimization_summaries->remove (node);
3493 *cur_summary_ptr = NULL;
3495 if (*cur_summary_lto_ptr
3496 && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
3498 summaries_lto->remove (node);
3499 *cur_summary_lto_ptr = NULL;
3503 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3504 and propagate loads/stores. */
3506 static void
3507 modref_propagate_in_scc (cgraph_node *component_node)
3509 bool changed = true;
3510 bool first = true;
3511 int iteration = 0;
3513 while (changed)
3515 changed = false;
3516 for (struct cgraph_node *cur = component_node; cur;
3517 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3519 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
3520 modref_summary *cur_summary = optimization_summaries
3521 ? optimization_summaries->get (node)
3522 : NULL;
3523 modref_summary_lto *cur_summary_lto = summaries_lto
3524 ? summaries_lto->get (node)
3525 : NULL;
3527 if (!cur_summary && !cur_summary_lto)
3528 continue;
3530 int cur_ecf_flags = flags_from_decl_or_type (node->decl);
3532 if (dump_file)
3533 fprintf (dump_file, " Processing %s%s%s\n",
3534 cur->dump_name (),
3535 TREE_READONLY (cur->decl) ? " (const)" : "",
3536 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3538 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
3540 if (e->indirect_info->ecf_flags & (ECF_CONST | ECF_NOVOPS))
3541 continue;
3542 if (dump_file)
3543 fprintf (dump_file, " Indirect call"
3544 "collapsing loads\n");
3545 if (propagate_unknown_call
3546 (node, e, e->indirect_info->ecf_flags,
3547 cur_summary, cur_summary_lto))
3549 changed = true;
3550 remove_useless_summaries (node, &cur_summary,
3551 &cur_summary_lto,
3552 cur_ecf_flags);
3553 if (!cur_summary && !cur_summary_lto)
3554 break;
3558 if (!cur_summary && !cur_summary_lto)
3559 continue;
3561 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
3562 callee_edge = callee_edge->next_callee)
3564 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
3565 modref_summary *callee_summary = NULL;
3566 modref_summary_lto *callee_summary_lto = NULL;
3567 struct cgraph_node *callee;
3569 if (flags & (ECF_CONST | ECF_NOVOPS)
3570 || !callee_edge->inline_failed)
3571 continue;
3573 /* Get the callee and its summary. */
3574 enum availability avail;
3575 callee = callee_edge->callee->function_or_virtual_thunk_symbol
3576 (&avail, cur);
3578 /* It is not necessary to re-process calls outside of the
3579 SCC component. */
3580 if (iteration > 0
3581 && (!callee->aux
3582 || ((struct ipa_dfs_info *)cur->aux)->scc_no
3583 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
3584 continue;
3586 if (dump_file)
3587 fprintf (dump_file, " Call to %s\n",
3588 callee_edge->callee->dump_name ());
3590 bool ignore_stores = ignore_stores_p (cur->decl, flags);
3592 if (avail <= AVAIL_INTERPOSABLE)
3594 if (dump_file)
3595 fprintf (dump_file, " Call target interposable"
3596 " or not available\n");
3597 changed |= propagate_unknown_call
3598 (node, callee_edge, flags,
3599 cur_summary, cur_summary_lto);
3600 if (!cur_summary && !cur_summary_lto)
3601 break;
3602 continue;
3605 /* We don't know anything about CALLEE, hence we cannot tell
3606 anything about the entire component. */
3608 if (cur_summary
3609 && !(callee_summary = optimization_summaries->get (callee)))
3611 if (dump_file)
3612 fprintf (dump_file, " No call target summary\n");
3613 changed |= propagate_unknown_call
3614 (node, callee_edge, flags,
3615 cur_summary, NULL);
3617 if (cur_summary_lto
3618 && !(callee_summary_lto = summaries_lto->get (callee)))
3620 if (dump_file)
3621 fprintf (dump_file, " No call target summary\n");
3622 changed |= propagate_unknown_call
3623 (node, callee_edge, flags,
3624 NULL, cur_summary_lto);
3627 /* We can not safely optimize based on summary of callee if it
3628 does not always bind to current def: it is possible that
3629 memory load was optimized out earlier which may not happen in
3630 the interposed variant. */
3631 if (!callee_edge->binds_to_current_def_p ())
3633 changed |= collapse_loads (cur_summary, cur_summary_lto);
3634 if (dump_file)
3635 fprintf (dump_file, " May not bind local;"
3636 " collapsing loads\n");
3640 auto_vec <modref_parm_map, 32> parm_map;
3642 compute_parm_map (callee_edge, &parm_map);
3644 /* Merge in callee's information. */
3645 if (callee_summary)
3647 changed |= cur_summary->loads->merge
3648 (callee_summary->loads, &parm_map, !first);
3649 if (!ignore_stores)
3651 changed |= cur_summary->stores->merge
3652 (callee_summary->stores, &parm_map,
3653 !first);
3654 if (!cur_summary->writes_errno
3655 && callee_summary->writes_errno)
3657 cur_summary->writes_errno = true;
3658 changed = true;
3662 if (callee_summary_lto)
3664 changed |= cur_summary_lto->loads->merge
3665 (callee_summary_lto->loads, &parm_map,
3666 !first);
3667 if (!ignore_stores)
3669 changed |= cur_summary_lto->stores->merge
3670 (callee_summary_lto->stores, &parm_map,
3671 !first);
3672 if (!cur_summary_lto->writes_errno
3673 && callee_summary_lto->writes_errno)
3675 cur_summary_lto->writes_errno = true;
3676 changed = true;
3680 if (changed)
3681 remove_useless_summaries (node, &cur_summary,
3682 &cur_summary_lto,
3683 cur_ecf_flags);
3684 if (!cur_summary && !cur_summary_lto)
3685 break;
3686 if (dump_file && changed)
3688 if (cur_summary)
3689 cur_summary->dump (dump_file);
3690 if (cur_summary_lto)
3691 cur_summary_lto->dump (dump_file);
3692 dump_modref_edge_summaries (dump_file, node, 4);
3696 iteration++;
3697 first = false;
3699 if (dump_file)
3700 fprintf (dump_file,
3701 "Propagation finished in %i iterations\n", iteration);
3704 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
3706 static void
3707 modref_propagate_dump_scc (cgraph_node *component_node)
3709 for (struct cgraph_node *cur = component_node; cur;
3710 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3711 if (!cur->inlined_to)
3713 modref_summary *cur_summary = optimization_summaries
3714 ? optimization_summaries->get (cur)
3715 : NULL;
3716 modref_summary_lto *cur_summary_lto = summaries_lto
3717 ? summaries_lto->get (cur)
3718 : NULL;
3720 fprintf (dump_file, "Propagated modref for %s%s%s\n",
3721 cur->dump_name (),
3722 TREE_READONLY (cur->decl) ? " (const)" : "",
3723 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3724 if (optimization_summaries)
3726 if (cur_summary)
3727 cur_summary->dump (dump_file);
3728 else
3729 fprintf (dump_file, " Not tracked\n");
3731 if (summaries_lto)
3733 if (cur_summary_lto)
3734 cur_summary_lto->dump (dump_file);
3735 else
3736 fprintf (dump_file, " Not tracked (lto)\n");
3741 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
3742 and SUMMARY_LTO to CUR_SUMMARY_LTO.
3743 Return true if something changed. */
3745 static bool
3746 modref_merge_call_site_flags (escape_summary *sum,
3747 modref_summary *cur_summary,
3748 modref_summary_lto *cur_summary_lto,
3749 modref_summary *summary,
3750 modref_summary_lto *summary_lto,
3751 tree caller,
3752 int ecf_flags)
3754 escape_entry *ee;
3755 unsigned int i;
3756 bool changed = false;
3757 bool ignore_stores = ignore_stores_p (caller, ecf_flags);
3759 /* If we have no useful info to propagate. */
3760 if ((!cur_summary || !cur_summary->arg_flags.length ())
3761 && (!cur_summary_lto || !cur_summary_lto->arg_flags.length ()))
3762 return false;
3764 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3766 int flags = 0;
3767 int flags_lto = 0;
3769 if (summary && ee->arg < summary->arg_flags.length ())
3770 flags = summary->arg_flags[ee->arg];
3771 if (summary_lto
3772 && ee->arg < summary_lto->arg_flags.length ())
3773 flags_lto = summary_lto->arg_flags[ee->arg];
3774 if (!ee->direct)
3776 flags = deref_flags (flags, ignore_stores);
3777 flags_lto = deref_flags (flags_lto, ignore_stores);
3779 else if (ignore_stores)
3781 flags |= ignore_stores_eaf_flags;
3782 flags_lto |= ignore_stores_eaf_flags;
3784 /* Returning the value is already accounted to at local propagation. */
3785 flags |= ee->min_flags | EAF_NOT_RETURNED;
3786 flags_lto |= ee->min_flags | EAF_NOT_RETURNED;
3787 /* Noescape implies that value also does not escape directly.
3788 Fnspec machinery does set both so compensate for this. */
3789 if (flags & EAF_NOESCAPE)
3790 flags |= EAF_NODIRECTESCAPE;
3791 if (flags_lto & EAF_NOESCAPE)
3792 flags_lto |= EAF_NODIRECTESCAPE;
3793 if (!(flags & EAF_UNUSED)
3794 && cur_summary && ee->parm_index < cur_summary->arg_flags.length ())
3796 int f = cur_summary->arg_flags[ee->parm_index];
3797 if ((f & flags) != f)
3799 f = remove_useless_eaf_flags
3800 (f & flags, ecf_flags,
3801 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
3802 cur_summary->arg_flags[ee->parm_index] = f;
3803 changed = true;
3806 if (!(flags_lto & EAF_UNUSED)
3807 && cur_summary_lto
3808 && ee->parm_index < cur_summary_lto->arg_flags.length ())
3810 int f = cur_summary_lto->arg_flags[ee->parm_index];
3811 if ((f & flags_lto) != f)
3813 f = remove_useless_eaf_flags
3814 (f & flags_lto, ecf_flags,
3815 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
3816 cur_summary_lto->arg_flags[ee->parm_index] = f;
3817 changed = true;
3821 return changed;
3824 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3825 and propagate arg flags. */
3827 static void
3828 modref_propagate_flags_in_scc (cgraph_node *component_node)
3830 bool changed = true;
3831 int iteration = 0;
3833 while (changed)
3835 changed = false;
3836 for (struct cgraph_node *cur = component_node; cur;
3837 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3839 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
3840 modref_summary *cur_summary = optimization_summaries
3841 ? optimization_summaries->get (node)
3842 : NULL;
3843 modref_summary_lto *cur_summary_lto = summaries_lto
3844 ? summaries_lto->get (node)
3845 : NULL;
3847 if (!cur_summary && !cur_summary_lto)
3848 continue;
3850 if (dump_file)
3851 fprintf (dump_file, " Processing %s%s%s\n",
3852 cur->dump_name (),
3853 TREE_READONLY (cur->decl) ? " (const)" : "",
3854 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3856 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
3858 escape_summary *sum = escape_summaries->get (e);
3860 if (!sum || (e->indirect_info->ecf_flags
3861 & (ECF_CONST | ECF_NOVOPS)))
3862 continue;
3864 changed |= modref_merge_call_site_flags
3865 (sum, cur_summary, cur_summary_lto,
3866 NULL, NULL,
3867 node->decl, e->indirect_info->ecf_flags);
3870 if (!cur_summary && !cur_summary_lto)
3871 continue;
3873 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
3874 callee_edge = callee_edge->next_callee)
3876 int ecf_flags = flags_from_decl_or_type
3877 (callee_edge->callee->decl);
3878 modref_summary *callee_summary = NULL;
3879 modref_summary_lto *callee_summary_lto = NULL;
3880 struct cgraph_node *callee;
3882 if (ecf_flags & (ECF_CONST | ECF_NOVOPS)
3883 || !callee_edge->inline_failed)
3884 continue;
3885 /* Get the callee and its summary. */
3886 enum availability avail;
3887 callee = callee_edge->callee->function_or_virtual_thunk_symbol
3888 (&avail, cur);
3890 /* It is not necessary to re-process calls outside of the
3891 SCC component. */
3892 if (iteration > 0
3893 && (!callee->aux
3894 || ((struct ipa_dfs_info *)cur->aux)->scc_no
3895 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
3896 continue;
3898 escape_summary *sum = escape_summaries->get (callee_edge);
3899 if (!sum)
3900 continue;
3902 if (dump_file)
3903 fprintf (dump_file, " Call to %s\n",
3904 callee_edge->callee->dump_name ());
3906 if (avail <= AVAIL_INTERPOSABLE
3907 || callee_edge->call_stmt_cannot_inline_p)
3909 else
3911 if (cur_summary)
3912 callee_summary = optimization_summaries->get (callee);
3913 if (cur_summary_lto)
3914 callee_summary_lto = summaries_lto->get (callee);
3916 changed |= modref_merge_call_site_flags
3917 (sum, cur_summary, cur_summary_lto,
3918 callee_summary, callee_summary_lto,
3919 node->decl, ecf_flags);
3920 if (dump_file && changed)
3922 if (cur_summary)
3923 cur_summary->dump (dump_file);
3924 if (cur_summary_lto)
3925 cur_summary_lto->dump (dump_file);
3929 iteration++;
3931 if (dump_file)
3932 fprintf (dump_file,
3933 "Propagation of flags finished in %i iterations\n", iteration);
3936 /* Run the IPA pass. This will take a function's summaries and calls and
3937 construct new summaries which represent a transitive closure. So that
3938 summary of an analyzed function contains information about the loads and
3939 stores that the function or any function that it calls does. */
3941 unsigned int
3942 pass_ipa_modref::execute (function *)
3944 if (!summaries && !summaries_lto)
3945 return 0;
3947 if (optimization_summaries)
3948 ggc_delete (optimization_summaries);
3949 optimization_summaries = summaries;
3950 summaries = NULL;
3952 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
3953 symtab->cgraph_count);
3954 int order_pos;
3955 order_pos = ipa_reduced_postorder (order, true, ignore_edge);
3956 int i;
3958 /* Iterate over all strongly connected components in post-order. */
3959 for (i = 0; i < order_pos; i++)
3961 /* Get the component's representative. That's just any node in the
3962 component from which we can traverse the entire component. */
3963 struct cgraph_node *component_node = order[i];
3965 if (dump_file)
3966 fprintf (dump_file, "\n\nStart of SCC component\n");
3968 modref_propagate_in_scc (component_node);
3969 modref_propagate_flags_in_scc (component_node);
3970 if (dump_file)
3971 modref_propagate_dump_scc (component_node);
3973 cgraph_node *node;
3974 FOR_EACH_FUNCTION (node)
3975 update_signature (node);
3976 if (summaries_lto)
3977 ((modref_summaries_lto *)summaries_lto)->propagated = true;
3978 ipa_free_postorder_info ();
3979 free (order);
3980 delete fnspec_summaries;
3981 fnspec_summaries = NULL;
3982 delete escape_summaries;
3983 escape_summaries = NULL;
3984 return 0;
3987 /* Summaries must stay alive until end of compilation. */
3989 void
3990 ipa_modref_c_finalize ()
3992 if (optimization_summaries)
3993 ggc_delete (optimization_summaries);
3994 optimization_summaries = NULL;
3995 gcc_checking_assert (!summaries
3996 || flag_incremental_link == INCREMENTAL_LINK_LTO);
3997 if (summaries_lto)
3998 ggc_delete (summaries_lto);
3999 summaries_lto = NULL;
4000 if (fnspec_summaries)
4001 delete fnspec_summaries;
4002 fnspec_summaries = NULL;
4003 if (escape_summaries)
4004 delete escape_summaries;
4005 escape_summaries = NULL;
4008 #include "gt-ipa-modref.h"