testsuite: Update scanning symbol sections to support AIX.
[official-gcc.git] / gcc / ipa-modref.c
blob4a43c50aa661c218acd3fa47c562ea89508d8b2a
1 /* Search for references that a functions loads or stores.
2 Copyright (C) 2020 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. The summary has a form of decision tree
24 described in ipa-modref-tree.h.
26 This file contains a tree pass and an IPA pass. Both performs the same
27 analysis however tree pass is executed during early and late optimization
28 passes to propagate info downwards in the compilation order. IPA pass
29 propagates across the callgraph and is able to handle recursion and works on
30 whole program during link-time analysis.
32 LTO mode differs from the local mode by not recording alias sets but types
33 that are translated to alias sets later. This is necessary in order stream
34 the information because the alias sets are rebuild at stream-in time and may
35 not correspond to ones seen during analysis. For this reason part of analysis
36 is duplicated. */
38 #include "config.h"
39 #include "system.h"
40 #include "coretypes.h"
41 #include "backend.h"
42 #include "tree.h"
43 #include "gimple.h"
44 #include "alloc-pool.h"
45 #include "tree-pass.h"
46 #include "gimple-iterator.h"
47 #include "tree-dfa.h"
48 #include "cgraph.h"
49 #include "ipa-utils.h"
50 #include "symbol-summary.h"
51 #include "gimple-pretty-print.h"
52 #include "gimple-walk.h"
53 #include "print-tree.h"
54 #include "tree-streamer.h"
55 #include "alias.h"
56 #include "calls.h"
57 #include "ipa-modref-tree.h"
58 #include "ipa-modref.h"
59 #include "value-range.h"
60 #include "ipa-prop.h"
61 #include "ipa-fnsummary.h"
62 #include "attr-fnspec.h"
63 #include "symtab-clones.h"
64 #include "gimple-ssa.h"
65 #include "tree-phinodes.h"
66 #include "tree-ssa-operands.h"
67 #include "ssa-iterators.h"
68 #include "stringpool.h"
69 #include "tree-ssanames.h"
71 static int analyze_ssa_name_flags (tree name,
72 vec<unsigned char> &known_flags, int depth);
74 /* We record fnspec specifiers for call edges since they depends on actual
75 gimple statements. */
77 class fnspec_summary
79 public:
80 char *fnspec;
82 fnspec_summary ()
83 : fnspec (NULL)
87 ~fnspec_summary ()
89 free (fnspec);
93 /* Summary holding fnspec string for a given call. */
95 class fnspec_summaries_t : public call_summary <fnspec_summary *>
97 public:
98 fnspec_summaries_t (symbol_table *symtab)
99 : call_summary <fnspec_summary *> (symtab) {}
100 /* Hook that is called by summary when an edge is duplicated. */
101 virtual void duplicate (cgraph_edge *,
102 cgraph_edge *,
103 fnspec_summary *src,
104 fnspec_summary *dst)
106 dst->fnspec = xstrdup (src->fnspec);
110 static fnspec_summaries_t *fnspec_summaries = NULL;
112 /* Class (from which there is one global instance) that holds modref summaries
113 for all analyzed functions. */
115 class GTY((user)) modref_summaries
116 : public fast_function_summary <modref_summary *, va_gc>
118 public:
119 modref_summaries (symbol_table *symtab)
120 : fast_function_summary <modref_summary *, va_gc> (symtab) {}
121 virtual void insert (cgraph_node *, modref_summary *state);
122 virtual void duplicate (cgraph_node *src_node,
123 cgraph_node *dst_node,
124 modref_summary *src_data,
125 modref_summary *dst_data);
126 static modref_summaries *create_ggc (symbol_table *symtab)
128 return new (ggc_alloc_no_dtor<modref_summaries> ())
129 modref_summaries (symtab);
133 class modref_summary_lto;
135 /* Class (from which there is one global instance) that holds modref summaries
136 for all analyzed functions. */
138 class GTY((user)) modref_summaries_lto
139 : public fast_function_summary <modref_summary_lto *, va_gc>
141 public:
142 modref_summaries_lto (symbol_table *symtab)
143 : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
144 propagated (false) {}
145 virtual void insert (cgraph_node *, modref_summary_lto *state);
146 virtual void duplicate (cgraph_node *src_node,
147 cgraph_node *dst_node,
148 modref_summary_lto *src_data,
149 modref_summary_lto *dst_data);
150 static modref_summaries_lto *create_ggc (symbol_table *symtab)
152 return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
153 modref_summaries_lto (symtab);
155 bool propagated;
158 /* Global variable holding all modref summaries
159 (from analysis to IPA propagation time). */
161 static GTY(()) fast_function_summary <modref_summary *, va_gc>
162 *summaries;
164 /* Global variable holding all modref optimization summaries
165 (from IPA propagation time or used by local optimization pass). */
167 static GTY(()) fast_function_summary <modref_summary *, va_gc>
168 *optimization_summaries;
170 /* LTO summaries hold info from analysis to LTO streaming or from LTO
171 stream-in through propagation to LTO stream-out. */
173 static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
174 *summaries_lto;
176 /* Summary for a single function which this pass produces. */
178 modref_summary::modref_summary ()
179 : loads (NULL), stores (NULL), writes_errno (NULL)
183 modref_summary::~modref_summary ()
185 if (loads)
186 ggc_delete (loads);
187 if (stores)
188 ggc_delete (stores);
191 /* Return true if summary is potentially useful for optimization. */
193 bool
194 modref_summary::useful_p (int ecf_flags)
196 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
197 return false;
198 if (arg_flags.length ())
199 return true;
200 if (loads && !loads->every_base)
201 return true;
202 if (ecf_flags & ECF_PURE)
203 return false;
204 return stores && !stores->every_base;
207 /* Single function summary used for LTO. */
209 typedef modref_tree <tree> modref_records_lto;
210 struct GTY(()) modref_summary_lto
212 /* Load and stores in functions using types rather then alias sets.
214 This is necessary to make the information streamable for LTO but is also
215 more verbose and thus more likely to hit the limits. */
216 modref_records_lto *loads;
217 modref_records_lto *stores;
218 bool writes_errno;
220 modref_summary_lto ();
221 ~modref_summary_lto ();
222 void dump (FILE *);
223 bool useful_p (int ecf_flags);
226 /* Summary for a single function which this pass produces. */
228 modref_summary_lto::modref_summary_lto ()
229 : loads (NULL), stores (NULL), writes_errno (NULL)
233 modref_summary_lto::~modref_summary_lto ()
235 if (loads)
236 ggc_delete (loads);
237 if (stores)
238 ggc_delete (stores);
242 /* Return true if lto summary is potentially useful for optimization. */
244 bool
245 modref_summary_lto::useful_p (int ecf_flags)
247 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
248 return false;
249 if (loads && !loads->every_base)
250 return true;
251 if (ecf_flags & ECF_PURE)
252 return false;
253 return stores && !stores->every_base;
256 /* Dump A to OUT. */
258 static void
259 dump_access (modref_access_node *a, FILE *out)
261 fprintf (out, " access:");
262 if (a->parm_index != -1)
264 fprintf (out, " Parm %i", a->parm_index);
265 if (a->parm_offset_known)
267 fprintf (out, " param offset:");
268 print_dec ((poly_int64_pod)a->parm_offset, out, SIGNED);
271 if (a->range_info_useful_p ())
273 fprintf (out, " offset:");
274 print_dec ((poly_int64_pod)a->offset, out, SIGNED);
275 fprintf (out, " size:");
276 print_dec ((poly_int64_pod)a->size, out, SIGNED);
277 fprintf (out, " max_size:");
278 print_dec ((poly_int64_pod)a->max_size, out, SIGNED);
280 fprintf (out, "\n");
283 /* Dump records TT to OUT. */
285 static void
286 dump_records (modref_records *tt, FILE *out)
288 fprintf (out, " Limits: %i bases, %i refs\n",
289 (int)tt->max_bases, (int)tt->max_refs);
290 if (tt->every_base)
292 fprintf (out, " Every base\n");
293 return;
295 size_t i;
296 modref_base_node <alias_set_type> *n;
297 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
299 fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
300 if (n->every_ref)
302 fprintf (out, " Every ref\n");
303 continue;
305 size_t j;
306 modref_ref_node <alias_set_type> *r;
307 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
309 fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
310 if (r->every_access)
312 fprintf (out, " Every access\n");
313 continue;
315 size_t k;
316 modref_access_node *a;
317 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
318 dump_access (a, out);
323 /* Dump records TT to OUT. */
325 static void
326 dump_lto_records (modref_records_lto *tt, FILE *out)
328 fprintf (out, " Limits: %i bases, %i refs\n",
329 (int)tt->max_bases, (int)tt->max_refs);
330 if (tt->every_base)
332 fprintf (out, " Every base\n");
333 return;
335 size_t i;
336 modref_base_node <tree> *n;
337 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
339 fprintf (out, " Base %i:", (int)i);
340 print_generic_expr (dump_file, n->base);
341 fprintf (out, " (alias set %i)\n",
342 n->base ? get_alias_set (n->base) : 0);
343 if (n->every_ref)
345 fprintf (out, " Every ref\n");
346 continue;
348 size_t j;
349 modref_ref_node <tree> *r;
350 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
352 fprintf (out, " Ref %i:", (int)j);
353 print_generic_expr (dump_file, r->ref);
354 fprintf (out, " (alias set %i)\n",
355 r->ref ? get_alias_set (r->ref) : 0);
356 if (r->every_access)
358 fprintf (out, " Every access\n");
359 continue;
361 size_t k;
362 modref_access_node *a;
363 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
364 dump_access (a, out);
369 /* Dump EAF flags. */
371 static void
372 dump_eaf_flags (FILE *out, int flags)
374 if (flags & EAF_DIRECT)
375 fprintf (out, " direct");
376 if (flags & EAF_NOCLOBBER)
377 fprintf (out, " noclobber");
378 if (flags & EAF_NOESCAPE)
379 fprintf (out, " noescape");
380 if (flags & EAF_UNUSED)
381 fprintf (out, " unused");
382 fprintf (out, "\n");
385 /* Dump summary. */
387 void
388 modref_summary::dump (FILE *out)
390 if (loads)
392 fprintf (out, " loads:\n");
393 dump_records (loads, out);
395 if (stores)
397 fprintf (out, " stores:\n");
398 dump_records (stores, out);
400 if (writes_errno)
401 fprintf (out, " Writes errno\n");
402 if (arg_flags.length ())
404 for (unsigned int i = 0; i < arg_flags.length (); i++)
405 if (arg_flags[i])
407 fprintf (out, " parm %i flags:", i);
408 dump_eaf_flags (out, arg_flags[i]);
413 /* Dump summary. */
415 void
416 modref_summary_lto::dump (FILE *out)
418 fprintf (out, " loads:\n");
419 dump_lto_records (loads, out);
420 fprintf (out, " stores:\n");
421 dump_lto_records (stores, out);
422 if (writes_errno)
423 fprintf (out, " Writes errno\n");
426 /* Get function summary for FUNC if it exists, return NULL otherwise. */
428 modref_summary *
429 get_modref_function_summary (cgraph_node *func)
431 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
432 if (!optimization_summaries)
433 return NULL;
435 /* A single function body may be represented by multiple symbols with
436 different visibility. For example, if FUNC is an interposable alias,
437 we don't want to return anything, even if we have summary for the target
438 function. */
439 enum availability avail;
440 func = func->function_or_virtual_thunk_symbol
441 (&avail, current_function_decl ?
442 cgraph_node::get (current_function_decl) : NULL);
443 if (avail <= AVAIL_INTERPOSABLE)
444 return NULL;
446 modref_summary *r = optimization_summaries->get (func);
447 return r;
450 /* Construct modref_access_node from REF. */
451 static modref_access_node
452 get_access (ao_ref *ref)
454 tree base;
456 base = ao_ref_base (ref);
457 modref_access_node a = {ref->offset, ref->size, ref->max_size,
458 0, -1, false};
459 if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
461 tree memref = base;
462 base = TREE_OPERAND (base, 0);
463 if (TREE_CODE (base) == SSA_NAME
464 && SSA_NAME_IS_DEFAULT_DEF (base)
465 && TREE_CODE (SSA_NAME_VAR (base)) == PARM_DECL)
467 a.parm_index = 0;
468 for (tree t = DECL_ARGUMENTS (current_function_decl);
469 t != SSA_NAME_VAR (base); t = DECL_CHAIN (t))
471 if (!t)
473 a.parm_index = -1;
474 break;
476 a.parm_index++;
478 if (TREE_CODE (memref) == MEM_REF)
480 a.parm_offset_known
481 = wi::to_poly_wide (TREE_OPERAND
482 (memref, 1)).to_shwi (&a.parm_offset);
484 else
485 a.parm_offset_known = false;
487 else
488 a.parm_index = -1;
490 else
491 a.parm_index = -1;
492 return a;
495 /* Record access into the modref_records data structure. */
497 static void
498 record_access (modref_records *tt, ao_ref *ref)
500 alias_set_type base_set = !flag_strict_aliasing ? 0
501 : ao_ref_base_alias_set (ref);
502 alias_set_type ref_set = !flag_strict_aliasing ? 0
503 : (ao_ref_alias_set (ref));
504 modref_access_node a = get_access (ref);
505 if (dump_file)
507 fprintf (dump_file, " - Recording base_set=%i ref_set=%i parm=%i\n",
508 base_set, ref_set, a.parm_index);
510 tt->insert (base_set, ref_set, a);
513 /* IPA version of record_access_tree. */
515 static void
516 record_access_lto (modref_records_lto *tt, ao_ref *ref)
518 /* get_alias_set sometimes use different type to compute the alias set
519 than TREE_TYPE (base). Do same adjustments. */
520 tree base_type = NULL_TREE, ref_type = NULL_TREE;
521 if (flag_strict_aliasing)
523 tree base;
525 base = ref->ref;
526 while (handled_component_p (base))
527 base = TREE_OPERAND (base, 0);
529 base_type = reference_alias_ptr_type_1 (&base);
531 if (!base_type)
532 base_type = TREE_TYPE (base);
533 else
534 base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
535 ? NULL_TREE : TREE_TYPE (base_type);
537 tree ref_expr = ref->ref;
538 ref_type = reference_alias_ptr_type_1 (&ref_expr);
540 if (!ref_type)
541 ref_type = TREE_TYPE (ref_expr);
542 else
543 ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
544 ? NULL_TREE : TREE_TYPE (ref_type);
546 /* Sanity check that we are in sync with what get_alias_set does. */
547 gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
548 || get_alias_set (base_type)
549 == ao_ref_base_alias_set (ref));
550 gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
551 || get_alias_set (ref_type)
552 == ao_ref_alias_set (ref));
554 /* Do not bother to record types that have no meaningful alias set.
555 Also skip variably modified types since these go to local streams. */
556 if (base_type && (!get_alias_set (base_type)
557 || variably_modified_type_p (base_type, NULL_TREE)))
558 base_type = NULL_TREE;
559 if (ref_type && (!get_alias_set (ref_type)
560 || variably_modified_type_p (ref_type, NULL_TREE)))
561 ref_type = NULL_TREE;
563 modref_access_node a = get_access (ref);
564 if (dump_file)
566 fprintf (dump_file, " - Recording base type:");
567 print_generic_expr (dump_file, base_type);
568 fprintf (dump_file, " (alias set %i) ref type:",
569 base_type ? get_alias_set (base_type) : 0);
570 print_generic_expr (dump_file, ref_type);
571 fprintf (dump_file, " (alias set %i) parm:%i\n",
572 ref_type ? get_alias_set (ref_type) : 0,
573 a.parm_index);
576 tt->insert (base_type, ref_type, a);
579 /* Returns true if and only if we should store the access to EXPR.
580 Some accesses, e.g. loads from automatic variables, are not interesting. */
582 static bool
583 record_access_p (tree expr)
585 if (refs_local_or_readonly_memory_p (expr))
587 if (dump_file)
588 fprintf (dump_file, " - Read-only or local, ignoring.\n");
589 return false;
591 return true;
594 /* Return true if ECF flags says that stores can be ignored. */
596 static bool
597 ignore_stores_p (tree caller, int flags)
599 if (flags & ECF_PURE)
600 return true;
601 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
602 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
603 return true;
604 return false;
607 /* Determine parm_map for argument I of STMT. */
609 modref_parm_map
610 parm_map_for_arg (gimple *stmt, int i)
612 tree op = gimple_call_arg (stmt, i);
613 bool offset_known;
614 poly_int64 offset;
615 struct modref_parm_map parm_map;
617 parm_map.parm_offset_known = false;
618 parm_map.parm_offset = 0;
620 offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
621 if (TREE_CODE (op) == SSA_NAME
622 && SSA_NAME_IS_DEFAULT_DEF (op)
623 && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
625 int index = 0;
626 for (tree t = DECL_ARGUMENTS (current_function_decl);
627 t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
629 if (!t)
631 index = -1;
632 break;
634 index++;
636 parm_map.parm_index = index;
637 parm_map.parm_offset_known = offset_known;
638 parm_map.parm_offset = offset;
640 else if (points_to_local_or_readonly_memory_p (op))
641 parm_map.parm_index = -2;
642 else
643 parm_map.parm_index = -1;
644 return parm_map;
647 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
648 int CUR_SUMMARY. Return true if something changed.
649 If IGNORE_STORES is true, do not merge stores. */
651 bool
652 merge_call_side_effects (modref_summary *cur_summary,
653 gimple *stmt, modref_summary *callee_summary,
654 bool ignore_stores, cgraph_node *callee_node)
656 auto_vec <modref_parm_map, 32> parm_map;
657 bool changed = false;
659 if (dump_file)
660 fprintf (dump_file, " - Merging side effects of %s with parm map:",
661 callee_node->dump_name ());
663 /* We can not safely optimize based on summary of callee if it does
664 not always bind to current def: it is possible that memory load
665 was optimized out earlier which may not happen in the interposed
666 variant. */
667 if (!callee_node->binds_to_current_def_p ())
669 if (dump_file)
670 fprintf (dump_file, " - May be interposed: collapsing loads.\n");
671 cur_summary->loads->collapse ();
674 parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true);
675 for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
677 parm_map[i] = parm_map_for_arg (stmt, i);
678 if (dump_file)
680 fprintf (dump_file, " %i", parm_map[i].parm_index);
681 if (parm_map[i].parm_offset_known)
683 fprintf (dump_file, " offset:");
684 print_dec ((poly_int64_pod)parm_map[i].parm_offset,
685 dump_file, SIGNED);
689 if (dump_file)
690 fprintf (dump_file, "\n");
692 /* Merge with callee's summary. */
693 changed |= cur_summary->loads->merge (callee_summary->loads, &parm_map);
694 if (!ignore_stores)
696 changed |= cur_summary->stores->merge (callee_summary->stores,
697 &parm_map);
698 if (!cur_summary->writes_errno
699 && callee_summary->writes_errno)
701 cur_summary->writes_errno = true;
702 changed = true;
705 return changed;
708 /* Return access mode for argument I of call STMT with FNSPEC. */
710 static modref_access_node
711 get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
712 unsigned int i, modref_parm_map &map)
714 tree size = NULL_TREE;
715 unsigned int size_arg;
717 if (!fnspec.arg_specified_p (i))
719 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
720 size = gimple_call_arg (call, size_arg);
721 else if (fnspec.arg_access_size_given_by_type_p (i))
723 tree callee = gimple_call_fndecl (call);
724 tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
726 for (unsigned int p = 0; p < i; p++)
727 t = TREE_CHAIN (t);
728 size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
730 modref_access_node a = {0, -1, -1,
731 map.parm_offset, map.parm_index,
732 map.parm_offset_known};
733 poly_int64 size_hwi;
734 if (size
735 && poly_int_tree_p (size, &size_hwi)
736 && coeffs_in_range_p (size_hwi, 0,
737 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
739 a.size = -1;
740 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
742 return a;
745 /* Collapse loads and return true if something changed. */
747 static bool
748 collapse_loads (modref_summary *cur_summary,
749 modref_summary_lto *cur_summary_lto)
751 bool changed = false;
753 if (cur_summary && !cur_summary->loads->every_base)
755 cur_summary->loads->collapse ();
756 changed = true;
758 if (cur_summary_lto
759 && !cur_summary_lto->loads->every_base)
761 cur_summary_lto->loads->collapse ();
762 changed = true;
764 return changed;
767 /* Collapse loads and return true if something changed. */
769 static bool
770 collapse_stores (modref_summary *cur_summary,
771 modref_summary_lto *cur_summary_lto)
773 bool changed = false;
775 if (cur_summary && !cur_summary->stores->every_base)
777 cur_summary->stores->collapse ();
778 changed = true;
780 if (cur_summary_lto
781 && !cur_summary_lto->stores->every_base)
783 cur_summary_lto->stores->collapse ();
784 changed = true;
786 return changed;
790 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
791 If IGNORE_STORES is true ignore them.
792 Return false if no useful summary can be produced. */
794 static bool
795 process_fnspec (modref_summary *cur_summary,
796 modref_summary_lto *cur_summary_lto,
797 gcall *call, bool ignore_stores)
799 attr_fnspec fnspec = gimple_call_fnspec (call);
800 if (!fnspec.known_p ())
802 if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
803 fprintf (dump_file, " Builtin with no fnspec: %s\n",
804 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
805 if (ignore_stores)
807 collapse_loads (cur_summary, cur_summary_lto);
808 return true;
810 return false;
812 if (fnspec.global_memory_read_p ())
813 collapse_loads (cur_summary, cur_summary_lto);
814 else
816 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
817 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
819 else if (!fnspec.arg_specified_p (i)
820 || fnspec.arg_maybe_read_p (i))
822 modref_parm_map map = parm_map_for_arg (call, i);
824 if (map.parm_index == -2)
825 continue;
826 if (map.parm_index == -1)
828 collapse_loads (cur_summary, cur_summary_lto);
829 break;
831 if (cur_summary)
832 cur_summary->loads->insert (0, 0,
833 get_access_for_fnspec (call,
834 fnspec, i,
835 map));
836 if (cur_summary_lto)
837 cur_summary_lto->loads->insert (0, 0,
838 get_access_for_fnspec (call,
839 fnspec, i,
840 map));
843 if (ignore_stores)
844 return true;
845 if (fnspec.global_memory_written_p ())
846 collapse_stores (cur_summary, cur_summary_lto);
847 else
849 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
850 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
852 else if (!fnspec.arg_specified_p (i)
853 || fnspec.arg_maybe_written_p (i))
855 modref_parm_map map = parm_map_for_arg (call, i);
857 if (map.parm_index == -2)
858 continue;
859 if (map.parm_index == -1)
861 collapse_stores (cur_summary, cur_summary_lto);
862 break;
864 if (cur_summary)
865 cur_summary->stores->insert (0, 0,
866 get_access_for_fnspec (call,
867 fnspec, i,
868 map));
869 if (cur_summary_lto)
870 cur_summary_lto->stores->insert (0, 0,
871 get_access_for_fnspec (call,
872 fnspec, i,
873 map));
875 if (fnspec.errno_maybe_written_p () && flag_errno_math)
877 if (cur_summary)
878 cur_summary->writes_errno = true;
879 if (cur_summary_lto)
880 cur_summary_lto->writes_errno = true;
883 return true;
886 /* Analyze function call STMT in function F.
887 Remember recursive calls in RECURSIVE_CALLS. */
889 static bool
890 analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto,
891 gcall *stmt, vec <gimple *> *recursive_calls)
893 /* Check flags on the function call. In certain cases, analysis can be
894 simplified. */
895 int flags = gimple_call_flags (stmt);
896 if (flags & (ECF_CONST | ECF_NOVOPS))
898 if (dump_file)
899 fprintf (dump_file,
900 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
901 "except for args.\n");
902 return true;
905 /* Pure functions do not affect global memory. Stores by functions which are
906 noreturn and do not throw can safely be ignored. */
907 bool ignore_stores = ignore_stores_p (current_function_decl, flags);
909 /* Next, we try to get the callee's function declaration. The goal is to
910 merge their summary with ours. */
911 tree callee = gimple_call_fndecl (stmt);
913 /* Check if this is an indirect call. */
914 if (!callee)
916 if (dump_file)
917 fprintf (dump_file, gimple_call_internal_p (stmt)
918 ? " - Internal call" : " - Indirect call.\n");
919 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
921 /* We only need to handle internal calls in IPA mode. */
922 gcc_checking_assert (!cur_summary_lto);
924 struct cgraph_node *callee_node = cgraph_node::get_create (callee);
926 /* If this is a recursive call, the target summary is the same as ours, so
927 there's nothing to do. */
928 if (recursive_call_p (current_function_decl, callee))
930 recursive_calls->safe_push (stmt);
931 if (dump_file)
932 fprintf (dump_file, " - Skipping recursive call.\n");
933 return true;
936 gcc_assert (callee_node != NULL);
938 /* Get the function symbol and its availability. */
939 enum availability avail;
940 callee_node = callee_node->function_symbol (&avail);
941 if (avail <= AVAIL_INTERPOSABLE)
943 if (dump_file)
944 fprintf (dump_file, " - Function availability <= AVAIL_INTERPOSABLE.\n");
945 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
948 /* Get callee's modref summary. As above, if there's no summary, we either
949 have to give up or, if stores are ignored, we can just purge loads. */
950 modref_summary *callee_summary = optimization_summaries->get (callee_node);
951 if (!callee_summary)
953 if (dump_file)
954 fprintf (dump_file, " - No modref summary available for callee.\n");
955 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
958 merge_call_side_effects (cur_summary, stmt, callee_summary, ignore_stores,
959 callee_node);
961 return true;
964 /* Support analysis in non-lto and lto mode in parallel. */
966 struct summary_ptrs
968 struct modref_summary *nolto;
969 struct modref_summary_lto *lto;
972 /* Helper for analyze_stmt. */
974 static bool
975 analyze_load (gimple *, tree, tree op, void *data)
977 modref_summary *summary = ((summary_ptrs *)data)->nolto;
978 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
980 if (dump_file)
982 fprintf (dump_file, " - Analyzing load: ");
983 print_generic_expr (dump_file, op);
984 fprintf (dump_file, "\n");
987 if (!record_access_p (op))
988 return false;
990 ao_ref r;
991 ao_ref_init (&r, op);
993 if (summary)
994 record_access (summary->loads, &r);
995 if (summary_lto)
996 record_access_lto (summary_lto->loads, &r);
997 return false;
1000 /* Helper for analyze_stmt. */
1002 static bool
1003 analyze_store (gimple *, tree, tree op, void *data)
1005 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1006 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1008 if (dump_file)
1010 fprintf (dump_file, " - Analyzing store: ");
1011 print_generic_expr (dump_file, op);
1012 fprintf (dump_file, "\n");
1015 if (!record_access_p (op))
1016 return false;
1018 ao_ref r;
1019 ao_ref_init (&r, op);
1021 if (summary)
1022 record_access (summary->stores, &r);
1023 if (summary_lto)
1024 record_access_lto (summary_lto->stores, &r);
1025 return false;
1028 /* Analyze statement STMT of function F.
1029 If IPA is true do not merge in side effects of calls. */
1031 static bool
1032 analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
1033 gimple *stmt, bool ipa, vec <gimple *> *recursive_calls)
1035 /* In general we can not ignore clobbers because they are barriers for code
1036 motion, however after inlining it is safe to do because local optimization
1037 passes do not consider clobbers from other functions.
1038 Similar logic is in ipa-pure-const.c. */
1039 if ((ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1040 return true;
1042 struct summary_ptrs sums = {summary, summary_lto};
1044 /* Analyze all loads and stores in STMT. */
1045 walk_stmt_load_store_ops (stmt, &sums,
1046 analyze_load, analyze_store);
1048 switch (gimple_code (stmt))
1050 case GIMPLE_ASM:
1051 /* If the ASM statement does not read nor write memory, there's nothing
1052 to do. Otherwise just give up. */
1053 if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1054 return true;
1055 if (dump_file)
1056 fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1057 "which clobbers memory.\n");
1058 return false;
1059 case GIMPLE_CALL:
1060 if (!ipa || gimple_call_internal_p (stmt))
1061 return analyze_call (summary, summary_lto,
1062 as_a <gcall *> (stmt), recursive_calls);
1063 else
1065 attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1067 if (fnspec.known_p ()
1068 && (!fnspec.global_memory_read_p ()
1069 || !fnspec.global_memory_written_p ()))
1071 fnspec_summaries->get_create
1072 (cgraph_node::get (current_function_decl)->get_edge (stmt))
1073 ->fnspec = xstrdup (fnspec.get_str ());
1074 if (dump_file)
1075 fprintf (dump_file, " Recorded fnspec %s\n", fnspec.get_str ());
1078 return true;
1079 default:
1080 /* Nothing to do for other types of statements. */
1081 return true;
1085 /* Remove summary of current function because during the function body
1086 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1087 mode of scan. */
1089 static void
1090 remove_summary (bool lto, bool nolto, bool ipa)
1092 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1093 if (!ipa)
1094 optimization_summaries->remove (fnode);
1095 else
1097 if (nolto)
1098 summaries->remove (fnode);
1099 if (lto)
1100 summaries_lto->remove (fnode);
1102 if (dump_file)
1103 fprintf (dump_file,
1104 " - modref done with result: not tracked.\n");
1107 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1109 bool
1110 memory_access_to (tree op, tree ssa_name)
1112 tree base = get_base_address (op);
1113 if (!base)
1114 return false;
1115 if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1116 return false;
1117 return TREE_OPERAND (base, 0) == ssa_name;
1120 /* Consider statement val = *arg.
1121 return EAF flags of ARG that can be determined from EAF flags of VAL
1122 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1123 all stores to VAL, i.e. when handling noreturn function. */
1125 static int
1126 deref_flags (int flags, bool ignore_stores)
1128 int ret = 0;
1129 if (flags & EAF_UNUSED)
1130 ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE;
1131 else
1133 if ((flags & EAF_NOCLOBBER) || ignore_stores)
1134 ret |= EAF_NOCLOBBER;
1135 if ((flags & EAF_NOESCAPE) || ignore_stores)
1136 ret |= EAF_NOESCAPE;
1138 return ret;
1141 /* Call statements may return their parameters. Consider argument number
1142 ARG of USE_STMT and determine flags that can needs to be cleared
1143 in case pointer possibly indirectly references from ARG I is returned.
1144 KNOWN_FLAGS and DEPTH are same as in analyze_ssa_name_flags. */
1146 static int
1147 call_lhs_flags (gcall *call, int arg,
1148 vec<unsigned char> &known_flags, int depth)
1150 /* If there is no return value, no flags are affected. */
1151 if (!gimple_call_lhs (call))
1152 return EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED;
1154 /* If we know that function returns given argument and it is not ARG
1155 we can still be happy. */
1156 int flags = gimple_call_return_flags (call);
1157 if ((flags & ERF_RETURNS_ARG)
1158 && (flags & ERF_RETURN_ARG_MASK) != arg)
1159 return EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED;
1161 /* If return value is SSA name determine its flags. */
1162 if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
1163 return analyze_ssa_name_flags
1164 (gimple_call_lhs (call), known_flags,
1165 depth + 1);
1166 /* In the case of memory store we can do nothing. */
1167 else
1168 return 0;
1171 /* Analyze EAF flags for SSA name NAME.
1172 KNOWN_FLAGS is a cache for flags we already determined.
1173 DEPTH is a recursion depth used to make debug output prettier. */
1175 static int
1176 analyze_ssa_name_flags (tree name, vec<unsigned char> &known_flags, int depth)
1178 imm_use_iterator ui;
1179 gimple *use_stmt;
1180 int flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED;
1182 /* See if value is already computed. */
1183 if (known_flags[SSA_NAME_VERSION (name)])
1185 /* Punt on cycles for now, so we do not need dataflow. */
1186 if (known_flags[SSA_NAME_VERSION (name)] == 1)
1188 if (dump_file)
1189 fprintf (dump_file,
1190 "%*sGiving up on a cycle in SSA graph\n", depth * 4, "");
1191 return 0;
1193 return known_flags[SSA_NAME_VERSION (name)] - 2;
1195 if (depth == param_modref_max_depth)
1197 if (dump_file)
1198 fprintf (dump_file,
1199 "%*sGiving up on max depth\n", depth * 4, "");
1200 return 0;
1202 /* Recursion guard. */
1203 known_flags[SSA_NAME_VERSION (name)] = 1;
1205 if (dump_file)
1207 fprintf (dump_file,
1208 "%*sAnalyzing flags of ssa name: ", depth * 4, "");
1209 print_generic_expr (dump_file, name);
1210 fprintf (dump_file, "\n");
1213 FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
1215 if (flags == 0)
1217 BREAK_FROM_IMM_USE_STMT (ui);
1219 if (is_gimple_debug (use_stmt))
1220 continue;
1221 if (dump_file)
1223 fprintf (dump_file, "%*s Analyzing stmt:", depth * 4, "");
1224 print_gimple_stmt (dump_file, use_stmt, 0);
1227 /* Gimple return may load the return value.
1228 Returning name counts as an use by tree-ssa-structalias.c */
1229 if (greturn *ret = dyn_cast <greturn *> (use_stmt))
1231 if (memory_access_to (gimple_return_retval (ret), name)
1232 || name == gimple_return_retval (ret))
1233 flags &= ~EAF_UNUSED;
1235 /* Account for LHS store, arg loads and flags from callee function. */
1236 else if (gcall *call = dyn_cast <gcall *> (use_stmt))
1238 tree callee = gimple_call_fndecl (call);
1240 /* Recursion would require bit of propagation; give up for now. */
1241 if (callee && recursive_call_p (current_function_decl, callee))
1242 flags = 0;
1243 else
1245 int ecf_flags = gimple_call_flags (call);
1246 bool ignore_stores = ignore_stores_p (current_function_decl,
1247 ecf_flags);
1249 /* Handle *name = func (...). */
1250 if (gimple_call_lhs (call)
1251 && memory_access_to (gimple_call_lhs (call), name))
1252 flags &= ~(EAF_UNUSED | EAF_NOCLOBBER);
1254 /* We do not track accesses to the static chain (we could)
1255 so give up. */
1256 if (gimple_call_chain (call)
1257 && (gimple_call_chain (call) == name))
1258 flags = 0;
1260 /* Handle all function parameters. */
1261 for (unsigned i = 0; i < gimple_call_num_args (call); i++)
1262 /* Name is directly passed to the callee. */
1263 if (gimple_call_arg (call, i) == name)
1265 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
1266 flags &= ignore_stores
1268 : call_lhs_flags (call, i, known_flags, depth);
1269 else
1271 int call_flags = gimple_call_arg_flags (call, i);
1272 if (ignore_stores)
1273 call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
1274 else
1275 call_flags &= call_lhs_flags (call, i,
1276 known_flags, depth);
1278 flags &= call_flags;
1281 /* Name is dereferenced and passed to a callee. */
1282 else if (memory_access_to (gimple_call_arg (call, i), name))
1284 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
1285 flags &= ~EAF_UNUSED;
1286 else
1287 flags &= deref_flags (gimple_call_arg_flags (call, i),
1288 ignore_stores);
1289 if (!ignore_stores)
1290 flags &= call_lhs_flags (call, i, known_flags, depth);
1293 /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
1294 in tree-ssa-alias.c). Give up earlier. */
1295 if ((flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
1296 flags = 0;
1298 else if (gimple_assign_load_p (use_stmt))
1300 gassign *assign = as_a <gassign *> (use_stmt);
1301 /* Memory to memory copy. */
1302 if (gimple_store_p (assign))
1304 /* Handle *name = *exp. */
1305 if (memory_access_to (gimple_assign_lhs (assign), name))
1306 flags &= ~(EAF_UNUSED | EAF_NOCLOBBER);
1308 /* Handle *lhs = *name.
1310 We do not track memory locations, so assume that value
1311 is used arbitrarily. */
1312 if (memory_access_to (gimple_assign_rhs1 (assign), name))
1313 flags = 0;
1315 /* Handle lhs = *name. */
1316 else if (memory_access_to (gimple_assign_rhs1 (assign), name))
1317 flags &= deref_flags (analyze_ssa_name_flags
1318 (gimple_assign_lhs (assign),
1319 known_flags, depth + 1), false);
1321 else if (gimple_store_p (use_stmt))
1323 gassign *assign = dyn_cast <gassign *> (use_stmt);
1325 /* Handle *lhs = name. */
1326 if (assign && gimple_assign_rhs1 (assign) == name)
1328 if (dump_file)
1329 fprintf (dump_file, "%*s ssa name saved to memory\n",
1330 depth * 4, "");
1331 flags = 0;
1333 /* Handle *name = exp. */
1334 else if (assign
1335 && memory_access_to (gimple_assign_lhs (assign), name))
1336 flags &= ~(EAF_UNUSED | EAF_NOCLOBBER);
1337 /* ASM statements etc. */
1338 else if (!assign)
1340 if (dump_file)
1341 fprintf (dump_file, "%*s Unhandled store\n",
1342 depth * 4, "");
1343 flags = 0;
1346 else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
1348 enum tree_code code = gimple_assign_rhs_code (assign);
1350 /* See if operation is a merge as considered by
1351 tree-ssa-structalias.c:find_func_aliases. */
1352 if (!truth_value_p (code)
1353 && code != POINTER_DIFF_EXPR
1354 && (code != POINTER_PLUS_EXPR
1355 || gimple_assign_rhs1 (assign) == name))
1356 flags &= analyze_ssa_name_flags
1357 (gimple_assign_lhs (assign), known_flags,
1358 depth + 1);
1360 else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
1362 flags &= analyze_ssa_name_flags
1363 (gimple_phi_result (phi), known_flags,
1364 depth + 1);
1366 /* Conditions are not considered escape points
1367 by tree-ssa-structalias. */
1368 else if (gimple_code (use_stmt) == GIMPLE_COND)
1370 else
1372 if (dump_file)
1373 fprintf (dump_file, "%*s Unhandled stmt\n", depth * 4, "");
1374 flags = 0;
1377 if (dump_file)
1379 fprintf (dump_file, "%*s current flags of ", depth * 4, "");
1380 print_generic_expr (dump_file, name);
1381 dump_eaf_flags (dump_file, flags);
1384 if (dump_file)
1386 fprintf (dump_file, "%*sflags of ssa name ", depth * 4, "");
1387 print_generic_expr (dump_file, name);
1388 dump_eaf_flags (dump_file, flags);
1390 known_flags[SSA_NAME_VERSION (name)] = flags + 2;
1391 return flags;
1394 /* Determine EAF flags for function parameters. */
1396 static void
1397 analyze_parms (modref_summary *summary)
1399 unsigned int parm_index = 0;
1400 unsigned int count = 0;
1402 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
1403 parm = TREE_CHAIN (parm))
1404 count++;
1406 if (!count)
1407 return;
1409 auto_vec<unsigned char> known_flags;
1410 known_flags.safe_grow_cleared (num_ssa_names, true);
1412 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
1413 parm = TREE_CHAIN (parm))
1415 tree name = ssa_default_def (cfun, parm);
1416 if (!name)
1417 continue;
1418 int flags = analyze_ssa_name_flags (name, known_flags, 0);
1420 if (flags)
1422 if (parm_index >= summary->arg_flags.length ())
1423 summary->arg_flags.safe_grow_cleared (count, true);
1424 summary->arg_flags[parm_index] = flags;
1429 /* Analyze function F. IPA indicates whether we're running in local mode
1430 (false) or the IPA mode (true). */
1432 static void
1433 analyze_function (function *f, bool ipa)
1435 if (dump_file)
1436 fprintf (dump_file, "modref analyzing '%s' (ipa=%i)%s%s\n",
1437 function_name (f), ipa,
1438 TREE_READONLY (current_function_decl) ? " (const)" : "",
1439 DECL_PURE_P (current_function_decl) ? " (pure)" : "");
1441 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
1442 if (!flag_ipa_modref)
1443 return;
1445 /* Compute no-LTO summaries when local optimization is going to happen. */
1446 bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
1447 || (in_lto_p && !flag_wpa
1448 && flag_incremental_link != INCREMENTAL_LINK_LTO));
1449 /* Compute LTO when LTO streaming is going to happen. */
1450 bool lto = ipa && ((flag_lto && !in_lto_p)
1451 || flag_wpa
1452 || flag_incremental_link == INCREMENTAL_LINK_LTO);
1453 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1455 modref_summary *summary = NULL;
1456 modref_summary_lto *summary_lto = NULL;
1458 /* Initialize the summary.
1459 If we run in local mode there is possibly pre-existing summary from
1460 IPA pass. Dump it so it is easy to compare if mod-ref info has
1461 improved. */
1462 if (!ipa)
1464 if (!optimization_summaries)
1465 optimization_summaries = modref_summaries::create_ggc (symtab);
1466 else /* Remove existing summary if we are re-running the pass. */
1468 if (dump_file
1469 && (summary
1470 = optimization_summaries->get (cgraph_node::get (f->decl)))
1471 != NULL
1472 && summary->loads)
1474 fprintf (dump_file, "Past summary:\n");
1475 optimization_summaries->get
1476 (cgraph_node::get (f->decl))->dump (dump_file);
1478 optimization_summaries->remove (cgraph_node::get (f->decl));
1480 summary = optimization_summaries->get_create (cgraph_node::get (f->decl));
1481 gcc_checking_assert (nolto && !lto);
1483 /* In IPA mode we analyze every function precisely once. Assert that. */
1484 else
1486 if (nolto)
1488 if (!summaries)
1489 summaries = modref_summaries::create_ggc (symtab);
1490 else
1491 summaries->remove (cgraph_node::get (f->decl));
1492 summary = summaries->get_create (cgraph_node::get (f->decl));
1494 if (lto)
1496 if (!summaries_lto)
1497 summaries_lto = modref_summaries_lto::create_ggc (symtab);
1498 else
1499 summaries_lto->remove (cgraph_node::get (f->decl));
1500 summary_lto = summaries_lto->get_create (cgraph_node::get (f->decl));
1502 if (!fnspec_summaries)
1503 fnspec_summaries = new fnspec_summaries_t (symtab);
1507 /* Create and initialize summary for F.
1508 Note that summaries may be already allocated from previous
1509 run of the pass. */
1510 if (nolto)
1512 gcc_assert (!summary->loads);
1513 summary->loads = modref_records::create_ggc (param_modref_max_bases,
1514 param_modref_max_refs,
1515 param_modref_max_accesses);
1516 gcc_assert (!summary->stores);
1517 summary->stores = modref_records::create_ggc (param_modref_max_bases,
1518 param_modref_max_refs,
1519 param_modref_max_accesses);
1520 summary->writes_errno = false;
1522 if (lto)
1524 gcc_assert (!summary_lto->loads);
1525 summary_lto->loads = modref_records_lto::create_ggc
1526 (param_modref_max_bases,
1527 param_modref_max_refs,
1528 param_modref_max_accesses);
1529 gcc_assert (!summary_lto->stores);
1530 summary_lto->stores = modref_records_lto::create_ggc
1531 (param_modref_max_bases,
1532 param_modref_max_refs,
1533 param_modref_max_accesses);
1534 summary_lto->writes_errno = false;
1537 if (!ipa)
1538 analyze_parms (summary);
1540 int ecf_flags = flags_from_decl_or_type (current_function_decl);
1541 auto_vec <gimple *, 32> recursive_calls;
1543 /* Analyze each statement in each basic block of the function. If the
1544 statement cannot be analyzed (for any reason), the entire function cannot
1545 be analyzed by modref. */
1546 basic_block bb;
1547 FOR_EACH_BB_FN (bb, f)
1549 gimple_stmt_iterator si;
1550 for (si = gsi_after_labels (bb); !gsi_end_p (si); gsi_next (&si))
1552 if (!analyze_stmt (summary, summary_lto,
1553 gsi_stmt (si), ipa, &recursive_calls)
1554 || ((!summary || !summary->useful_p (ecf_flags))
1555 && (!summary_lto || !summary_lto->useful_p (ecf_flags))))
1557 collapse_loads (summary, summary_lto);
1558 collapse_stores (summary, summary_lto);
1559 break;
1564 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
1565 This needs to be done after all other side effects are computed. */
1566 if (!ipa)
1568 bool changed = true;
1569 while (changed)
1571 changed = false;
1572 for (unsigned i = 0; i < recursive_calls.length (); i++)
1574 changed |= merge_call_side_effects
1575 (summary, recursive_calls[i], summary,
1576 ignore_stores_p (current_function_decl,
1577 gimple_call_flags
1578 (recursive_calls[i])),
1579 fnode);
1580 if (!summary->useful_p (ecf_flags))
1582 remove_summary (lto, nolto, ipa);
1583 return;
1588 if (summary && !summary->useful_p (ecf_flags))
1590 if (!ipa)
1591 optimization_summaries->remove (fnode);
1592 else
1593 summaries->remove (fnode);
1594 summary = NULL;
1596 if (summary_lto && !summary_lto->useful_p (ecf_flags))
1598 summaries_lto->remove (fnode);
1599 summary_lto = NULL;
1602 if (dump_file)
1604 fprintf (dump_file, " - modref done with result: tracked.\n");
1605 if (summary)
1606 summary->dump (dump_file);
1607 if (summary_lto)
1608 summary_lto->dump (dump_file);
1612 /* Callback for generate_summary. */
1614 static void
1615 modref_generate (void)
1617 struct cgraph_node *node;
1618 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
1620 function *f = DECL_STRUCT_FUNCTION (node->decl);
1621 if (!f)
1622 continue;
1623 push_cfun (f);
1624 analyze_function (f, true);
1625 pop_cfun ();
1629 /* Called when a new function is inserted to callgraph late. */
1631 void
1632 modref_summaries::insert (struct cgraph_node *node, modref_summary *)
1634 /* Local passes ought to be executed by the pass manager. */
1635 if (this == optimization_summaries)
1637 optimization_summaries->remove (node);
1638 return;
1640 if (!DECL_STRUCT_FUNCTION (node->decl)
1641 || !opt_for_fn (node->decl, flag_ipa_modref))
1643 summaries->remove (node);
1644 return;
1646 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
1647 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
1648 pop_cfun ();
1651 /* Called when a new function is inserted to callgraph late. */
1653 void
1654 modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
1656 /* We do not support adding new function when IPA information is already
1657 propagated. This is done only by SIMD cloning that is not very
1658 critical. */
1659 if (!DECL_STRUCT_FUNCTION (node->decl)
1660 || !opt_for_fn (node->decl, flag_ipa_modref)
1661 || propagated)
1663 summaries_lto->remove (node);
1664 return;
1666 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
1667 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
1668 pop_cfun ();
1671 /* Called when new clone is inserted to callgraph late. */
1673 void
1674 modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
1675 modref_summary *src_data,
1676 modref_summary *dst_data)
1678 /* Do not duplicate optimization summaries; we do not handle parameter
1679 transforms on them. */
1680 if (this == optimization_summaries)
1682 optimization_summaries->remove (dst);
1683 return;
1685 dst_data->stores = modref_records::create_ggc
1686 (src_data->stores->max_bases,
1687 src_data->stores->max_refs,
1688 src_data->stores->max_accesses);
1689 dst_data->stores->copy_from (src_data->stores);
1690 dst_data->loads = modref_records::create_ggc
1691 (src_data->loads->max_bases,
1692 src_data->loads->max_refs,
1693 src_data->loads->max_accesses);
1694 dst_data->loads->copy_from (src_data->loads);
1695 dst_data->writes_errno = src_data->writes_errno;
1698 /* Called when new clone is inserted to callgraph late. */
1700 void
1701 modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
1702 modref_summary_lto *src_data,
1703 modref_summary_lto *dst_data)
1705 /* Be sure that no further cloning happens after ipa-modref. If it does
1706 we will need to update signatures for possible param changes. */
1707 gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
1708 dst_data->stores = modref_records_lto::create_ggc
1709 (src_data->stores->max_bases,
1710 src_data->stores->max_refs,
1711 src_data->stores->max_accesses);
1712 dst_data->stores->copy_from (src_data->stores);
1713 dst_data->loads = modref_records_lto::create_ggc
1714 (src_data->loads->max_bases,
1715 src_data->loads->max_refs,
1716 src_data->loads->max_accesses);
1717 dst_data->loads->copy_from (src_data->loads);
1718 dst_data->writes_errno = src_data->writes_errno;
1721 namespace
1723 /* Definition of the modref pass on GIMPLE. */
1724 const pass_data pass_data_modref = {
1725 GIMPLE_PASS,
1726 "modref",
1727 OPTGROUP_IPA,
1728 TV_TREE_MODREF,
1729 (PROP_cfg | PROP_ssa),
1736 class pass_modref : public gimple_opt_pass
1738 public:
1739 pass_modref (gcc::context *ctxt)
1740 : gimple_opt_pass (pass_data_modref, ctxt) {}
1742 /* opt_pass methods: */
1743 opt_pass *clone ()
1745 return new pass_modref (m_ctxt);
1747 virtual bool gate (function *)
1749 return flag_ipa_modref;
1751 virtual unsigned int execute (function *);
1754 /* Encode TT to the output block OB using the summary streaming API. */
1756 static void
1757 write_modref_records (modref_records_lto *tt, struct output_block *ob)
1759 streamer_write_uhwi (ob, tt->max_bases);
1760 streamer_write_uhwi (ob, tt->max_refs);
1761 streamer_write_uhwi (ob, tt->max_accesses);
1763 streamer_write_uhwi (ob, tt->every_base);
1764 streamer_write_uhwi (ob, vec_safe_length (tt->bases));
1765 size_t i;
1766 modref_base_node <tree> *base_node;
1767 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, base_node)
1769 stream_write_tree (ob, base_node->base, true);
1771 streamer_write_uhwi (ob, base_node->every_ref);
1772 streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
1774 size_t j;
1775 modref_ref_node <tree> *ref_node;
1776 FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
1778 stream_write_tree (ob, ref_node->ref, true);
1779 streamer_write_uhwi (ob, ref_node->every_access);
1780 streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
1782 size_t k;
1783 modref_access_node *access_node;
1784 FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
1786 streamer_write_hwi (ob, access_node->parm_index);
1787 if (access_node->parm_index != -1)
1789 streamer_write_uhwi (ob, access_node->parm_offset_known);
1790 if (access_node->parm_offset_known)
1792 streamer_write_poly_int64 (ob, access_node->parm_offset);
1793 streamer_write_poly_int64 (ob, access_node->offset);
1794 streamer_write_poly_int64 (ob, access_node->size);
1795 streamer_write_poly_int64 (ob, access_node->max_size);
1803 /* Read a modref_tree from the input block IB using the data from DATA_IN.
1804 This assumes that the tree was encoded using write_modref_tree.
1805 Either nolto_ret or lto_ret is initialized by the tree depending whether
1806 LTO streaming is expected or not. */
1808 void
1809 read_modref_records (lto_input_block *ib, struct data_in *data_in,
1810 modref_records **nolto_ret,
1811 modref_records_lto **lto_ret)
1813 size_t max_bases = streamer_read_uhwi (ib);
1814 size_t max_refs = streamer_read_uhwi (ib);
1815 size_t max_accesses = streamer_read_uhwi (ib);
1817 if (lto_ret)
1818 *lto_ret = modref_records_lto::create_ggc (max_bases, max_refs,
1819 max_accesses);
1820 if (nolto_ret)
1821 *nolto_ret = modref_records::create_ggc (max_bases, max_refs,
1822 max_accesses);
1823 gcc_checking_assert (lto_ret || nolto_ret);
1825 size_t every_base = streamer_read_uhwi (ib);
1826 size_t nbase = streamer_read_uhwi (ib);
1828 gcc_assert (!every_base || nbase == 0);
1829 if (every_base)
1831 if (nolto_ret)
1832 (*nolto_ret)->collapse ();
1833 if (lto_ret)
1834 (*lto_ret)->collapse ();
1836 for (size_t i = 0; i < nbase; i++)
1838 tree base_tree = stream_read_tree (ib, data_in);
1839 modref_base_node <alias_set_type> *nolto_base_node = NULL;
1840 modref_base_node <tree> *lto_base_node = NULL;
1842 /* At stream in time we have LTO alias info. Check if we streamed in
1843 something obviously unnecessary. Do not glob types by alias sets;
1844 it is not 100% clear that ltrans types will get merged same way.
1845 Types may get refined based on ODR type conflicts. */
1846 if (base_tree && !get_alias_set (base_tree))
1848 if (dump_file)
1850 fprintf (dump_file, "Streamed in alias set 0 type ");
1851 print_generic_expr (dump_file, base_tree);
1852 fprintf (dump_file, "\n");
1854 base_tree = NULL;
1857 if (nolto_ret)
1858 nolto_base_node = (*nolto_ret)->insert_base (base_tree
1859 ? get_alias_set (base_tree)
1860 : 0);
1861 if (lto_ret)
1862 lto_base_node = (*lto_ret)->insert_base (base_tree);
1863 size_t every_ref = streamer_read_uhwi (ib);
1864 size_t nref = streamer_read_uhwi (ib);
1866 gcc_assert (!every_ref || nref == 0);
1867 if (every_ref)
1869 if (nolto_base_node)
1870 nolto_base_node->collapse ();
1871 if (lto_base_node)
1872 lto_base_node->collapse ();
1874 for (size_t j = 0; j < nref; j++)
1876 tree ref_tree = stream_read_tree (ib, data_in);
1878 if (ref_tree && !get_alias_set (ref_tree))
1880 if (dump_file)
1882 fprintf (dump_file, "Streamed in alias set 0 type ");
1883 print_generic_expr (dump_file, ref_tree);
1884 fprintf (dump_file, "\n");
1886 ref_tree = NULL;
1889 modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
1890 modref_ref_node <tree> *lto_ref_node = NULL;
1892 if (nolto_base_node)
1893 nolto_ref_node
1894 = nolto_base_node->insert_ref (ref_tree
1895 ? get_alias_set (ref_tree) : 0,
1896 max_refs);
1897 if (lto_base_node)
1898 lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
1900 size_t every_access = streamer_read_uhwi (ib);
1901 size_t naccesses = streamer_read_uhwi (ib);
1903 if (nolto_ref_node)
1904 nolto_ref_node->every_access = every_access;
1905 if (lto_ref_node)
1906 lto_ref_node->every_access = every_access;
1908 for (size_t k = 0; k < naccesses; k++)
1910 int parm_index = streamer_read_hwi (ib);
1911 bool parm_offset_known = false;
1912 poly_int64 parm_offset = 0;
1913 poly_int64 offset = 0;
1914 poly_int64 size = -1;
1915 poly_int64 max_size = -1;
1917 if (parm_index != -1)
1919 parm_offset_known = streamer_read_uhwi (ib);
1920 if (parm_offset_known)
1922 parm_offset = streamer_read_poly_int64 (ib);
1923 offset = streamer_read_poly_int64 (ib);
1924 size = streamer_read_poly_int64 (ib);
1925 max_size = streamer_read_poly_int64 (ib);
1928 modref_access_node a = {offset, size, max_size, parm_offset,
1929 parm_index, parm_offset_known};
1930 if (nolto_ref_node)
1931 nolto_ref_node->insert_access (a, max_accesses);
1932 if (lto_ref_node)
1933 lto_ref_node->insert_access (a, max_accesses);
1937 if (lto_ret)
1938 (*lto_ret)->cleanup ();
1939 if (nolto_ret)
1940 (*nolto_ret)->cleanup ();
1943 /* Callback for write_summary. */
1945 static void
1946 modref_write ()
1948 struct output_block *ob = create_output_block (LTO_section_ipa_modref);
1949 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
1950 unsigned int count = 0;
1951 int i;
1953 if (!summaries_lto)
1955 streamer_write_uhwi (ob, 0);
1956 streamer_write_char_stream (ob->main_stream, 0);
1957 produce_asm (ob, NULL);
1958 destroy_output_block (ob);
1959 return;
1962 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
1964 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
1965 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
1966 modref_summary_lto *r;
1968 if (cnode && cnode->definition && !cnode->alias
1969 && (r = summaries_lto->get (cnode))
1970 && r->useful_p (flags_from_decl_or_type (cnode->decl)))
1971 count++;
1973 streamer_write_uhwi (ob, count);
1975 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
1977 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
1978 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
1980 if (cnode && cnode->definition && !cnode->alias)
1982 modref_summary_lto *r = summaries_lto->get (cnode);
1984 if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
1985 continue;
1987 streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
1989 write_modref_records (r->loads, ob);
1990 write_modref_records (r->stores, ob);
1992 struct bitpack_d bp = bitpack_create (ob->main_stream);
1993 bp_pack_value (&bp, r->writes_errno, 1);
1994 if (!flag_wpa)
1996 for (cgraph_edge *e = cnode->indirect_calls;
1997 e; e = e->next_callee)
1999 class fnspec_summary *sum = fnspec_summaries->get (e);
2000 bp_pack_value (&bp, sum != NULL, 1);
2001 if (sum)
2002 bp_pack_string (ob, &bp, sum->fnspec, true);
2004 for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
2006 class fnspec_summary *sum = fnspec_summaries->get (e);
2007 bp_pack_value (&bp, sum != NULL, 1);
2008 if (sum)
2009 bp_pack_string (ob, &bp, sum->fnspec, true);
2012 streamer_write_bitpack (&bp);
2015 streamer_write_char_stream (ob->main_stream, 0);
2016 produce_asm (ob, NULL);
2017 destroy_output_block (ob);
2020 static void
2021 read_section (struct lto_file_decl_data *file_data, const char *data,
2022 size_t len)
2024 const struct lto_function_header *header
2025 = (const struct lto_function_header *) data;
2026 const int cfg_offset = sizeof (struct lto_function_header);
2027 const int main_offset = cfg_offset + header->cfg_size;
2028 const int string_offset = main_offset + header->main_size;
2029 struct data_in *data_in;
2030 unsigned int i;
2031 unsigned int f_count;
2033 lto_input_block ib ((const char *) data + main_offset, header->main_size,
2034 file_data->mode_table);
2036 data_in
2037 = lto_data_in_create (file_data, (const char *) data + string_offset,
2038 header->string_size, vNULL);
2039 f_count = streamer_read_uhwi (&ib);
2040 for (i = 0; i < f_count; i++)
2042 struct cgraph_node *node;
2043 lto_symtab_encoder_t encoder;
2045 unsigned int index = streamer_read_uhwi (&ib);
2046 encoder = file_data->symtab_node_encoder;
2047 node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
2048 index));
2050 modref_summary *modref_sum = summaries
2051 ? summaries->get_create (node) : NULL;
2052 modref_summary_lto *modref_sum_lto = summaries_lto
2053 ? summaries_lto->get_create (node)
2054 : NULL;
2055 if (optimization_summaries)
2056 modref_sum = optimization_summaries->get_create (node);
2058 if (modref_sum)
2059 modref_sum->writes_errno = false;
2060 if (modref_sum_lto)
2061 modref_sum_lto->writes_errno = false;
2063 gcc_assert (!modref_sum || (!modref_sum->loads
2064 && !modref_sum->stores));
2065 gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
2066 && !modref_sum_lto->stores));
2067 read_modref_records (&ib, data_in,
2068 modref_sum ? &modref_sum->loads : NULL,
2069 modref_sum_lto ? &modref_sum_lto->loads : NULL);
2070 read_modref_records (&ib, data_in,
2071 modref_sum ? &modref_sum->stores : NULL,
2072 modref_sum_lto ? &modref_sum_lto->stores : NULL);
2073 struct bitpack_d bp = streamer_read_bitpack (&ib);
2074 if (bp_unpack_value (&bp, 1))
2076 if (modref_sum)
2077 modref_sum->writes_errno = true;
2078 if (modref_sum_lto)
2079 modref_sum_lto->writes_errno = true;
2081 if (!flag_ltrans)
2083 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
2085 if (bp_unpack_value (&bp, 1))
2087 class fnspec_summary *sum = fnspec_summaries->get_create (e);
2088 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
2091 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
2093 if (bp_unpack_value (&bp, 1))
2095 class fnspec_summary *sum = fnspec_summaries->get_create (e);
2096 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
2100 if (dump_file)
2102 fprintf (dump_file, "Read modref for %s\n",
2103 node->dump_name ());
2104 if (modref_sum)
2105 modref_sum->dump (dump_file);
2106 if (modref_sum_lto)
2107 modref_sum_lto->dump (dump_file);
2111 lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
2112 len);
2113 lto_data_in_delete (data_in);
2116 /* Callback for read_summary. */
2118 static void
2119 modref_read (void)
2121 struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
2122 struct lto_file_decl_data *file_data;
2123 unsigned int j = 0;
2125 gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
2126 if (flag_ltrans)
2127 optimization_summaries = modref_summaries::create_ggc (symtab);
2128 else
2130 if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
2131 summaries_lto = modref_summaries_lto::create_ggc (symtab);
2132 if (!flag_wpa
2133 || (flag_incremental_link == INCREMENTAL_LINK_LTO
2134 && flag_fat_lto_objects))
2135 summaries = modref_summaries::create_ggc (symtab);
2136 if (!fnspec_summaries)
2137 fnspec_summaries = new fnspec_summaries_t (symtab);
2140 while ((file_data = file_data_vec[j++]))
2142 size_t len;
2143 const char *data = lto_get_summary_section_data (file_data,
2144 LTO_section_ipa_modref,
2145 &len);
2146 if (data)
2147 read_section (file_data, data, len);
2148 else
2149 /* Fatal error here. We do not want to support compiling ltrans units
2150 with different version of compiler or different flags than the WPA
2151 unit, so this should never happen. */
2152 fatal_error (input_location,
2153 "IPA modref summary is missing in input file");
2157 /* If signature changed, update the summary. */
2159 static void
2160 update_signature (struct cgraph_node *node)
2162 clone_info *info = clone_info::get (node);
2163 if (!info || !info->param_adjustments)
2164 return;
2166 modref_summary *r = optimization_summaries
2167 ? optimization_summaries->get (node) : NULL;
2168 modref_summary_lto *r_lto = summaries_lto
2169 ? summaries_lto->get (node) : NULL;
2170 if (!r && !r_lto)
2171 return;
2172 if (dump_file)
2174 fprintf (dump_file, "Updating summary for %s from:\n",
2175 node->dump_name ());
2176 r->dump (dump_file);
2179 size_t i, max = 0;
2180 ipa_adjusted_param *p;
2182 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2184 int idx = info->param_adjustments->get_original_index (i);
2185 if (idx > (int)max)
2186 max = idx;
2189 auto_vec <int, 32> map;
2191 map.reserve (max + 1);
2192 for (i = 0; i <= max; i++)
2193 map.quick_push (-1);
2194 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2196 int idx = info->param_adjustments->get_original_index (i);
2197 if (idx >= 0)
2198 map[idx] = i;
2200 if (r)
2202 r->loads->remap_params (&map);
2203 r->stores->remap_params (&map);
2205 if (r_lto)
2207 r_lto->loads->remap_params (&map);
2208 r_lto->stores->remap_params (&map);
2210 if (dump_file)
2212 fprintf (dump_file, "to:\n");
2213 if (r)
2214 r->dump (dump_file);
2215 if (r_lto)
2216 r_lto->dump (dump_file);
2218 return;
2221 /* Definition of the modref IPA pass. */
2222 const pass_data pass_data_ipa_modref =
2224 IPA_PASS, /* type */
2225 "modref", /* name */
2226 OPTGROUP_IPA, /* optinfo_flags */
2227 TV_IPA_MODREF, /* tv_id */
2228 0, /* properties_required */
2229 0, /* properties_provided */
2230 0, /* properties_destroyed */
2231 0, /* todo_flags_start */
2232 ( TODO_dump_symtab ), /* todo_flags_finish */
2235 class pass_ipa_modref : public ipa_opt_pass_d
2237 public:
2238 pass_ipa_modref (gcc::context *ctxt)
2239 : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
2240 modref_generate, /* generate_summary */
2241 modref_write, /* write_summary */
2242 modref_read, /* read_summary */
2243 modref_write, /* write_optimization_summary */
2244 modref_read, /* read_optimization_summary */
2245 NULL, /* stmt_fixup */
2246 0, /* function_transform_todo_flags_start */
2247 NULL, /* function_transform */
2248 NULL) /* variable_transform */
2251 /* opt_pass methods: */
2252 opt_pass *clone () { return new pass_ipa_modref (m_ctxt); }
2253 virtual bool gate (function *)
2255 return true;
2257 virtual unsigned int execute (function *);
2263 unsigned int pass_modref::execute (function *f)
2265 analyze_function (f, false);
2266 return 0;
2269 gimple_opt_pass *
2270 make_pass_modref (gcc::context *ctxt)
2272 return new pass_modref (ctxt);
2275 ipa_opt_pass_d *
2276 make_pass_ipa_modref (gcc::context *ctxt)
2278 return new pass_ipa_modref (ctxt);
2281 /* Skip edges from and to nodes without ipa_pure_const enabled.
2282 Ignore not available symbols. */
2284 static bool
2285 ignore_edge (struct cgraph_edge *e)
2287 /* We merge summaries of inline clones into summaries of functions they
2288 are inlined to. For that reason the complete function bodies must
2289 act as unit. */
2290 if (!e->inline_failed)
2291 return false;
2292 enum availability avail;
2293 cgraph_node *callee = e->callee->function_or_virtual_thunk_symbol
2294 (&avail, e->caller);
2296 return (avail <= AVAIL_INTERPOSABLE
2297 || ((!optimization_summaries || !optimization_summaries->get (callee))
2298 && (!summaries_lto || !summaries_lto->get (callee)))
2299 || flags_from_decl_or_type (e->callee->decl)
2300 & (ECF_CONST | ECF_NOVOPS));
2303 /* Compute parm_map for CALLEE_EDGE. */
2305 static bool
2306 compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
2308 class ipa_edge_args *args;
2309 if (ipa_node_params_sum
2310 && !callee_edge->call_stmt_cannot_inline_p
2311 && (args = IPA_EDGE_REF (callee_edge)) != NULL)
2313 int i, count = ipa_get_cs_argument_count (args);
2314 class ipa_node_params *caller_parms_info, *callee_pi;
2315 class ipa_call_summary *es
2316 = ipa_call_summaries->get (callee_edge);
2317 cgraph_node *callee
2318 = callee_edge->callee->function_or_virtual_thunk_symbol
2319 (NULL, callee_edge->caller);
2321 caller_parms_info = IPA_NODE_REF (callee_edge->caller->inlined_to
2322 ? callee_edge->caller->inlined_to
2323 : callee_edge->caller);
2324 callee_pi = IPA_NODE_REF (callee);
2326 (*parm_map).safe_grow_cleared (count, true);
2328 for (i = 0; i < count; i++)
2330 if (es && es->param[i].points_to_local_or_readonly_memory)
2332 (*parm_map)[i].parm_index = -2;
2333 continue;
2336 struct ipa_jump_func *jf
2337 = ipa_get_ith_jump_func (args, i);
2338 if (jf && callee_pi)
2340 tree cst = ipa_value_from_jfunc (caller_parms_info,
2342 ipa_get_type
2343 (callee_pi, i));
2344 if (cst && points_to_local_or_readonly_memory_p (cst))
2346 (*parm_map)[i].parm_index = -2;
2347 continue;
2350 if (jf && jf->type == IPA_JF_PASS_THROUGH)
2352 (*parm_map)[i].parm_index
2353 = ipa_get_jf_pass_through_formal_id (jf);
2354 if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
2356 (*parm_map)[i].parm_offset_known = true;
2357 (*parm_map)[i].parm_offset = 0;
2359 else if (ipa_get_jf_pass_through_operation (jf)
2360 == POINTER_PLUS_EXPR
2361 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
2362 &(*parm_map)[i].parm_offset))
2363 (*parm_map)[i].parm_offset_known = true;
2364 else
2365 (*parm_map)[i].parm_offset_known = false;
2366 continue;
2368 if (jf && jf->type == IPA_JF_ANCESTOR)
2370 (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
2371 (*parm_map)[i].parm_offset_known = true;
2372 gcc_checking_assert
2373 (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
2374 (*parm_map)[i].parm_offset
2375 = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
2377 else
2378 (*parm_map)[i].parm_index = -1;
2380 if (dump_file)
2382 fprintf (dump_file, " Parm map: ");
2383 for (i = 0; i < count; i++)
2384 fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
2385 fprintf (dump_file, "\n");
2387 return true;
2389 return false;
2392 /* Call EDGE was inlined; merge summary from callee to the caller. */
2394 void
2395 ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
2397 if (!summaries && !summaries_lto)
2398 return;
2400 struct cgraph_node *to = (edge->caller->inlined_to
2401 ? edge->caller->inlined_to : edge->caller);
2402 class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
2403 class modref_summary_lto *to_info_lto = summaries_lto
2404 ? summaries_lto->get (to) : NULL;
2406 if (!to_info && !to_info_lto)
2408 if (summaries)
2409 summaries->remove (edge->callee);
2410 if (summaries_lto)
2411 summaries_lto->remove (edge->callee);
2412 return;
2415 class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
2416 : NULL;
2417 class modref_summary_lto *callee_info_lto
2418 = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
2419 int flags = flags_from_decl_or_type (edge->callee->decl);
2421 if (!callee_info && to_info)
2423 if (ignore_stores_p (edge->caller->decl, flags))
2424 to_info->loads->collapse ();
2425 else
2427 summaries->remove (to);
2428 to_info = NULL;
2431 if (!callee_info_lto && to_info_lto)
2433 if (ignore_stores_p (edge->caller->decl, flags))
2434 to_info_lto->loads->collapse ();
2435 else
2437 summaries_lto->remove (to);
2438 to_info_lto = NULL;
2441 if (callee_info || callee_info_lto)
2443 auto_vec <modref_parm_map, 32> parm_map;
2445 compute_parm_map (edge, &parm_map);
2447 if (!ignore_stores_p (edge->caller->decl, flags))
2449 if (to_info && callee_info)
2450 to_info->stores->merge (callee_info->stores, &parm_map);
2451 if (to_info_lto && callee_info_lto)
2452 to_info_lto->stores->merge (callee_info_lto->stores, &parm_map);
2454 if (to_info && callee_info)
2455 to_info->loads->merge (callee_info->loads, &parm_map);
2456 if (to_info_lto && callee_info_lto)
2457 to_info_lto->loads->merge (callee_info_lto->loads, &parm_map);
2459 if (summaries)
2461 if (to_info && !to_info->useful_p (flags))
2463 if (dump_file)
2464 fprintf (dump_file, "Removed mod-ref summary for %s\n",
2465 to->dump_name ());
2466 summaries->remove (to);
2468 else if (to_info && dump_file)
2470 if (dump_file)
2471 fprintf (dump_file, "Updated mod-ref summary for %s\n",
2472 to->dump_name ());
2473 to_info->dump (dump_file);
2475 if (callee_info)
2476 summaries->remove (edge->callee);
2478 if (summaries_lto)
2480 if (to_info_lto && !to_info_lto->useful_p (flags))
2482 if (dump_file)
2483 fprintf (dump_file, "Removed mod-ref summary for %s\n",
2484 to->dump_name ());
2485 summaries_lto->remove (to);
2487 else if (to_info_lto && dump_file)
2489 if (dump_file)
2490 fprintf (dump_file, "Updated mod-ref summary for %s\n",
2491 to->dump_name ());
2492 to_info_lto->dump (dump_file);
2494 if (callee_info_lto)
2495 summaries_lto->remove (edge->callee);
2497 return;
2500 /* Get parameter type from DECL. This is only safe for special cases
2501 like builtins we create fnspec for because the type match is checked
2502 at fnspec creation time. */
2504 static tree
2505 get_parm_type (tree decl, unsigned int i)
2507 tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
2509 for (unsigned int p = 0; p < i; p++)
2510 t = TREE_CHAIN (t);
2511 return TREE_VALUE (t);
2514 /* Return access mode for argument I of call E with FNSPEC. */
2516 static modref_access_node
2517 get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
2518 unsigned int i, modref_parm_map &map)
2520 tree size = NULL_TREE;
2521 unsigned int size_arg;
2523 if (!fnspec.arg_specified_p (i))
2525 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
2527 cgraph_node *node = e->caller->inlined_to
2528 ? e->caller->inlined_to : e->caller;
2529 class ipa_node_params *caller_parms_info = IPA_NODE_REF (node);
2530 class ipa_edge_args *args = IPA_EDGE_REF (e);
2531 struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
2533 if (jf)
2534 size = ipa_value_from_jfunc (caller_parms_info, jf,
2535 get_parm_type (e->callee->decl, size_arg));
2537 else if (fnspec.arg_access_size_given_by_type_p (i))
2538 size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
2539 modref_access_node a = {0, -1, -1,
2540 map.parm_offset, map.parm_index,
2541 map.parm_offset_known};
2542 poly_int64 size_hwi;
2543 if (size
2544 && poly_int_tree_p (size, &size_hwi)
2545 && coeffs_in_range_p (size_hwi, 0,
2546 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
2548 a.size = -1;
2549 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
2551 return a;
2554 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
2555 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
2557 static bool
2558 propagate_unknown_call (cgraph_node *node,
2559 cgraph_edge *e, int ecf_flags,
2560 modref_summary **cur_summary_ptr,
2561 modref_summary_lto **cur_summary_lto_ptr)
2563 bool changed = false;
2564 modref_summary *cur_summary = cur_summary_ptr ? *cur_summary_ptr : NULL;
2565 modref_summary_lto *cur_summary_lto = cur_summary_lto_ptr
2566 ? *cur_summary_lto_ptr : NULL;
2567 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
2568 auto_vec <modref_parm_map, 32> parm_map;
2569 if (fnspec_sum
2570 && compute_parm_map (e, &parm_map))
2572 attr_fnspec fnspec (fnspec_sum->fnspec);
2574 gcc_checking_assert (fnspec.known_p ());
2575 if (fnspec.global_memory_read_p ())
2576 collapse_loads (cur_summary, cur_summary_lto);
2577 else
2579 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
2580 for (unsigned i = 0; i < parm_map.length () && t;
2581 i++, t = TREE_CHAIN (t))
2582 if (!POINTER_TYPE_P (TREE_VALUE (t)))
2584 else if (!fnspec.arg_specified_p (i)
2585 || fnspec.arg_maybe_read_p (i))
2587 modref_parm_map map = parm_map[i];
2588 if (map.parm_index == -2)
2589 continue;
2590 if (map.parm_index == -1)
2592 collapse_loads (cur_summary, cur_summary_lto);
2593 break;
2595 if (cur_summary)
2596 changed |= cur_summary->loads->insert
2597 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
2598 if (cur_summary_lto)
2599 changed |= cur_summary_lto->loads->insert
2600 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
2603 if (ignore_stores_p (node->decl, ecf_flags))
2605 else if (fnspec.global_memory_written_p ())
2606 collapse_stores (cur_summary, cur_summary_lto);
2607 else
2609 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
2610 for (unsigned i = 0; i < parm_map.length () && t;
2611 i++, t = TREE_CHAIN (t))
2612 if (!POINTER_TYPE_P (TREE_VALUE (t)))
2614 else if (!fnspec.arg_specified_p (i)
2615 || fnspec.arg_maybe_written_p (i))
2617 modref_parm_map map = parm_map[i];
2618 if (map.parm_index == -2)
2619 continue;
2620 if (map.parm_index == -1)
2622 collapse_stores (cur_summary, cur_summary_lto);
2623 break;
2625 if (cur_summary)
2626 changed |= cur_summary->stores->insert
2627 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
2628 if (cur_summary_lto)
2629 changed |= cur_summary_lto->stores->insert
2630 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
2633 if (fnspec.errno_maybe_written_p () && flag_errno_math)
2635 if (cur_summary && !cur_summary->writes_errno)
2637 cur_summary->writes_errno = true;
2638 changed = true;
2640 if (cur_summary_lto && !cur_summary_lto->writes_errno)
2642 cur_summary_lto->writes_errno = true;
2643 changed = true;
2646 return changed;
2648 if (ignore_stores_p (node->decl, ecf_flags))
2650 if (dump_file)
2651 fprintf (dump_file, " collapsing loads\n");
2652 return collapse_loads (cur_summary, cur_summary_lto);
2654 if (optimization_summaries)
2655 optimization_summaries->remove (node);
2656 if (summaries_lto)
2657 summaries_lto->remove (node);
2658 if (cur_summary_ptr)
2659 *cur_summary_ptr = NULL;
2660 if (cur_summary_lto_ptr)
2661 *cur_summary_lto_ptr = NULL;
2662 if (dump_file)
2663 fprintf (dump_file, " Giving up\n");
2664 return true;
2667 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE. */
2669 static void
2670 modref_propagate_in_scc (cgraph_node *component_node)
2672 bool changed = true;
2673 int iteration = 0;
2675 while (changed)
2677 changed = false;
2678 for (struct cgraph_node *cur = component_node; cur;
2679 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
2681 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
2682 modref_summary *cur_summary = optimization_summaries
2683 ? optimization_summaries->get (node)
2684 : NULL;
2685 modref_summary_lto *cur_summary_lto = summaries_lto
2686 ? summaries_lto->get (node)
2687 : NULL;
2689 if (!cur_summary && !cur_summary_lto)
2690 continue;
2692 if (dump_file)
2693 fprintf (dump_file, " Processing %s%s%s\n",
2694 cur->dump_name (),
2695 TREE_READONLY (cur->decl) ? " (const)" : "",
2696 DECL_PURE_P (cur->decl) ? " (pure)" : "");
2698 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
2700 if (e->indirect_info->ecf_flags & (ECF_CONST | ECF_NOVOPS))
2701 continue;
2702 if (dump_file)
2703 fprintf (dump_file, " Indirect call"
2704 "collapsing loads\n");
2705 changed |= propagate_unknown_call
2706 (node, e, e->indirect_info->ecf_flags,
2707 &cur_summary, &cur_summary_lto);
2708 if (!cur_summary && !cur_summary_lto)
2709 break;
2712 if (!cur_summary && !cur_summary_lto)
2713 continue;
2715 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
2716 callee_edge = callee_edge->next_callee)
2718 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
2719 modref_summary *callee_summary = NULL;
2720 modref_summary_lto *callee_summary_lto = NULL;
2721 struct cgraph_node *callee;
2723 if (flags & (ECF_CONST | ECF_NOVOPS)
2724 || !callee_edge->inline_failed)
2725 continue;
2727 /* Get the callee and its summary. */
2728 enum availability avail;
2729 callee = callee_edge->callee->function_or_virtual_thunk_symbol
2730 (&avail, cur);
2732 /* It is not necessary to re-process calls outside of the
2733 SCC component. */
2734 if (iteration > 0
2735 && (!callee->aux
2736 || ((struct ipa_dfs_info *)cur->aux)->scc_no
2737 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
2738 continue;
2740 if (dump_file)
2741 fprintf (dump_file, " Call to %s\n",
2742 callee_edge->callee->dump_name ());
2744 bool ignore_stores = ignore_stores_p (cur->decl, flags);
2746 if (avail <= AVAIL_INTERPOSABLE)
2748 if (dump_file)
2749 fprintf (dump_file, " Call target interposable"
2750 " or not available\n");
2751 changed |= propagate_unknown_call
2752 (node, callee_edge, flags,
2753 &cur_summary, &cur_summary_lto);
2754 if (!cur_summary && !cur_summary_lto)
2755 break;
2756 continue;
2759 /* We don't know anything about CALLEE, hence we cannot tell
2760 anything about the entire component. */
2762 if (cur_summary
2763 && !(callee_summary = optimization_summaries->get (callee)))
2765 if (dump_file)
2766 fprintf (dump_file, " No call target summary\n");
2767 changed |= propagate_unknown_call
2768 (node, callee_edge, flags,
2769 &cur_summary, NULL);
2770 if (!cur_summary && !cur_summary_lto)
2771 break;
2773 if (cur_summary_lto
2774 && !(callee_summary_lto = summaries_lto->get (callee)))
2776 if (dump_file)
2777 fprintf (dump_file, " No call target summary\n");
2778 changed |= propagate_unknown_call
2779 (node, callee_edge, flags,
2780 NULL, &cur_summary_lto);
2781 if (!cur_summary && !cur_summary_lto)
2782 break;
2785 /* We can not safely optimize based on summary of callee if it
2786 does not always bind to current def: it is possible that
2787 memory load was optimized out earlier which may not happen in
2788 the interposed variant. */
2789 if (!callee_edge->binds_to_current_def_p ())
2791 changed |= collapse_loads (cur_summary, cur_summary_lto);
2792 if (dump_file)
2793 fprintf (dump_file, " May not bind local;"
2794 " collapsing loads\n");
2798 auto_vec <modref_parm_map, 32> parm_map;
2800 compute_parm_map (callee_edge, &parm_map);
2802 /* Merge in callee's information. */
2803 if (callee_summary)
2805 changed |= cur_summary->loads->merge
2806 (callee_summary->loads, &parm_map);
2807 if (!ignore_stores)
2809 changed |= cur_summary->stores->merge
2810 (callee_summary->stores, &parm_map);
2811 if (!cur_summary->writes_errno
2812 && callee_summary->writes_errno)
2814 cur_summary->writes_errno = true;
2815 changed = true;
2819 if (callee_summary_lto)
2821 changed |= cur_summary_lto->loads->merge
2822 (callee_summary_lto->loads, &parm_map);
2823 if (!ignore_stores)
2825 changed |= cur_summary_lto->stores->merge
2826 (callee_summary_lto->stores, &parm_map);
2827 if (!cur_summary_lto->writes_errno
2828 && callee_summary_lto->writes_errno)
2830 cur_summary_lto->writes_errno = true;
2831 changed = true;
2835 if (dump_file && changed)
2837 if (cur_summary)
2838 cur_summary->dump (dump_file);
2839 if (cur_summary_lto)
2840 cur_summary_lto->dump (dump_file);
2844 iteration++;
2846 if (dump_file)
2848 fprintf (dump_file,
2849 "Propagation finished in %i iterations\n", iteration);
2850 for (struct cgraph_node *cur = component_node; cur;
2851 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
2852 if (!cur->inlined_to)
2854 modref_summary *cur_summary = optimization_summaries
2855 ? optimization_summaries->get (cur)
2856 : NULL;
2857 modref_summary_lto *cur_summary_lto = summaries_lto
2858 ? summaries_lto->get (cur)
2859 : NULL;
2861 fprintf (dump_file, "Propagated modref for %s%s%s\n",
2862 cur->dump_name (),
2863 TREE_READONLY (cur->decl) ? " (const)" : "",
2864 DECL_PURE_P (cur->decl) ? " (pure)" : "");
2865 if (optimization_summaries)
2867 if (cur_summary)
2868 cur_summary->dump (dump_file);
2869 else
2870 fprintf (dump_file, " Not tracked\n");
2872 if (summaries_lto)
2874 if (cur_summary_lto)
2875 cur_summary_lto->dump (dump_file);
2876 else
2877 fprintf (dump_file, " Not tracked (lto)\n");
2883 /* Run the IPA pass. This will take a function's summaries and calls and
2884 construct new summaries which represent a transitive closure. So that
2885 summary of an analyzed function contains information about the loads and
2886 stores that the function or any function that it calls does. */
2888 unsigned int
2889 pass_ipa_modref::execute (function *)
2891 if (!summaries && !summaries_lto)
2892 return 0;
2894 if (optimization_summaries)
2895 ggc_delete (optimization_summaries);
2896 optimization_summaries = summaries;
2897 summaries = NULL;
2899 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
2900 symtab->cgraph_count);
2901 int order_pos;
2902 order_pos = ipa_reduced_postorder (order, true, ignore_edge);
2903 int i;
2905 /* Iterate over all strongly connected components in post-order. */
2906 for (i = 0; i < order_pos; i++)
2908 /* Get the component's representative. That's just any node in the
2909 component from which we can traverse the entire component. */
2910 struct cgraph_node *component_node = order[i];
2912 if (dump_file)
2913 fprintf (dump_file, "\n\nStart of SCC component\n");
2915 modref_propagate_in_scc (component_node);
2917 cgraph_node *node;
2918 FOR_EACH_FUNCTION (node)
2919 update_signature (node);
2920 if (summaries_lto)
2921 ((modref_summaries_lto *)summaries_lto)->propagated = true;
2922 ipa_free_postorder_info ();
2923 free (order);
2924 delete fnspec_summaries;
2925 fnspec_summaries = NULL;
2926 return 0;
2929 /* Summaries must stay alive until end of compilation. */
2931 void
2932 ipa_modref_c_finalize ()
2934 if (optimization_summaries)
2935 ggc_delete (optimization_summaries);
2936 optimization_summaries = NULL;
2937 gcc_checking_assert (!summaries);
2938 if (summaries_lto)
2940 ggc_delete (summaries_lto);
2941 summaries_lto = NULL;
2943 if (fnspec_summaries)
2944 delete fnspec_summaries;
2945 fnspec_summaries = NULL;
2948 #include "gt-ipa-modref.h"