]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/ipa-modref.c
ipa: Get rid of IPA_NODE_REF and IPA_EDGE_REF
[thirdparty/gcc.git] / gcc / ipa-modref.c
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
4
5 This file is part of GCC.
6
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.
11
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.
16
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/>. */
20
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.
24
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.
30
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.
36
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.
43
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). */
55
56 #include "config.h"
57 #include "system.h"
58 #include "coretypes.h"
59 #include "backend.h"
60 #include "tree.h"
61 #include "gimple.h"
62 #include "alloc-pool.h"
63 #include "tree-pass.h"
64 #include "gimple-iterator.h"
65 #include "tree-dfa.h"
66 #include "cgraph.h"
67 #include "ipa-utils.h"
68 #include "symbol-summary.h"
69 #include "gimple-pretty-print.h"
70 #include "gimple-walk.h"
71 #include "print-tree.h"
72 #include "tree-streamer.h"
73 #include "alias.h"
74 #include "calls.h"
75 #include "ipa-modref-tree.h"
76 #include "ipa-modref.h"
77 #include "value-range.h"
78 #include "ipa-prop.h"
79 #include "ipa-fnsummary.h"
80 #include "attr-fnspec.h"
81 #include "symtab-clones.h"
82 #include "gimple-ssa.h"
83 #include "tree-phinodes.h"
84 #include "tree-ssa-operands.h"
85 #include "ssa-iterators.h"
86 #include "stringpool.h"
87 #include "tree-ssanames.h"
88
89 namespace {
90
91 /* We record fnspec specifiers for call edges since they depends on actual
92 gimple statements. */
93
94 class fnspec_summary
95 {
96 public:
97 char *fnspec;
98
99 fnspec_summary ()
100 : fnspec (NULL)
101 {
102 }
103
104 ~fnspec_summary ()
105 {
106 free (fnspec);
107 }
108 };
109
110 /* Summary holding fnspec string for a given call. */
111
112 class fnspec_summaries_t : public call_summary <fnspec_summary *>
113 {
114 public:
115 fnspec_summaries_t (symbol_table *symtab)
116 : call_summary <fnspec_summary *> (symtab) {}
117 /* Hook that is called by summary when an edge is duplicated. */
118 virtual void duplicate (cgraph_edge *,
119 cgraph_edge *,
120 fnspec_summary *src,
121 fnspec_summary *dst)
122 {
123 dst->fnspec = xstrdup (src->fnspec);
124 }
125 };
126
127 static fnspec_summaries_t *fnspec_summaries = NULL;
128
129 /* Escape summary holds a vector of param indexes that escape to
130 a given call. */
131 struct escape_entry
132 {
133 /* Parameter that escapes at a given call. */
134 unsigned int parm_index;
135 /* Argument it escapes to. */
136 unsigned int arg;
137 /* Minimal flags known about the argument. */
138 char min_flags;
139 /* Does it escape directly or indirectly? */
140 bool direct;
141 };
142
143 /* Dump EAF flags. */
144
145 static void
146 dump_eaf_flags (FILE *out, int flags, bool newline = true)
147 {
148 if (flags & EAF_DIRECT)
149 fprintf (out, " direct");
150 if (flags & EAF_NOCLOBBER)
151 fprintf (out, " noclobber");
152 if (flags & EAF_NOESCAPE)
153 fprintf (out, " noescape");
154 if (flags & EAF_NODIRECTESCAPE)
155 fprintf (out, " nodirectescape");
156 if (flags & EAF_UNUSED)
157 fprintf (out, " unused");
158 if (newline)
159 fprintf (out, "\n");
160 }
161
162 struct escape_summary
163 {
164 auto_vec <escape_entry> esc;
165 void dump (FILE *out)
166 {
167 for (unsigned int i = 0; i < esc.length (); i++)
168 {
169 fprintf (out, " parm %i arg %i %s min:",
170 esc[i].parm_index,
171 esc[i].arg,
172 esc[i].direct ? "(direct)" : "(indirect)");
173 dump_eaf_flags (out, esc[i].min_flags, false);
174 }
175 fprintf (out, "\n");
176 }
177 };
178
179 class escape_summaries_t : public call_summary <escape_summary *>
180 {
181 public:
182 escape_summaries_t (symbol_table *symtab)
183 : call_summary <escape_summary *> (symtab) {}
184 /* Hook that is called by summary when an edge is duplicated. */
185 virtual void duplicate (cgraph_edge *,
186 cgraph_edge *,
187 escape_summary *src,
188 escape_summary *dst)
189 {
190 dst->esc = src->esc.copy ();
191 }
192 };
193
194 static escape_summaries_t *escape_summaries = NULL;
195
196 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
197
198
199 /* Class (from which there is one global instance) that holds modref summaries
200 for all analyzed functions. */
201
202 class GTY((user)) modref_summaries
203 : public fast_function_summary <modref_summary *, va_gc>
204 {
205 public:
206 modref_summaries (symbol_table *symtab)
207 : fast_function_summary <modref_summary *, va_gc> (symtab) {}
208 virtual void insert (cgraph_node *, modref_summary *state);
209 virtual void duplicate (cgraph_node *src_node,
210 cgraph_node *dst_node,
211 modref_summary *src_data,
212 modref_summary *dst_data);
213 static modref_summaries *create_ggc (symbol_table *symtab)
214 {
215 return new (ggc_alloc_no_dtor<modref_summaries> ())
216 modref_summaries (symtab);
217 }
218 };
219
220 class modref_summary_lto;
221
222 /* Class (from which there is one global instance) that holds modref summaries
223 for all analyzed functions. */
224
225 class GTY((user)) modref_summaries_lto
226 : public fast_function_summary <modref_summary_lto *, va_gc>
227 {
228 public:
229 modref_summaries_lto (symbol_table *symtab)
230 : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
231 propagated (false) {}
232 virtual void insert (cgraph_node *, modref_summary_lto *state);
233 virtual void duplicate (cgraph_node *src_node,
234 cgraph_node *dst_node,
235 modref_summary_lto *src_data,
236 modref_summary_lto *dst_data);
237 static modref_summaries_lto *create_ggc (symbol_table *symtab)
238 {
239 return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
240 modref_summaries_lto (symtab);
241 }
242 bool propagated;
243 };
244
245 /* Global variable holding all modref summaries
246 (from analysis to IPA propagation time). */
247
248 static GTY(()) fast_function_summary <modref_summary *, va_gc>
249 *summaries;
250
251 /* Global variable holding all modref optimization summaries
252 (from IPA propagation time or used by local optimization pass). */
253
254 static GTY(()) fast_function_summary <modref_summary *, va_gc>
255 *optimization_summaries;
256
257 /* LTO summaries hold info from analysis to LTO streaming or from LTO
258 stream-in through propagation to LTO stream-out. */
259
260 static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
261 *summaries_lto;
262
263 /* Summary for a single function which this pass produces. */
264
265 modref_summary::modref_summary ()
266 : loads (NULL), stores (NULL), writes_errno (NULL)
267 {
268 }
269
270 modref_summary::~modref_summary ()
271 {
272 if (loads)
273 ggc_delete (loads);
274 if (stores)
275 ggc_delete (stores);
276 }
277
278 /* Return true if FLAGS holds some useful information. */
279
280 static bool
281 eaf_flags_useful_p (vec <unsigned char> &flags, int ecf_flags)
282 {
283 for (unsigned i = 0; i < flags.length (); i++)
284 if (ecf_flags & ECF_PURE)
285 {
286 if (flags[i] & (EAF_UNUSED | EAF_DIRECT))
287 return true;
288 }
289 else
290 {
291 if (flags[i])
292 return true;
293 }
294 return false;
295 }
296
297 /* Return true if summary is potentially useful for optimization.
298 If CHECK_FLAGS is false assume that arg_flags are useful. */
299
300 bool
301 modref_summary::useful_p (int ecf_flags, bool check_flags)
302 {
303 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
304 return false;
305 if (arg_flags.length () && !check_flags)
306 return true;
307 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
308 return true;
309 arg_flags.release ();
310 if (loads && !loads->every_base)
311 return true;
312 if (ecf_flags & ECF_PURE)
313 return false;
314 return stores && !stores->every_base;
315 }
316
317 /* Single function summary used for LTO. */
318
319 typedef modref_tree <tree> modref_records_lto;
320 struct GTY(()) modref_summary_lto
321 {
322 /* Load and stores in functions using types rather then alias sets.
323
324 This is necessary to make the information streamable for LTO but is also
325 more verbose and thus more likely to hit the limits. */
326 modref_records_lto *loads;
327 modref_records_lto *stores;
328 auto_vec<unsigned char> GTY((skip)) arg_flags;
329 bool writes_errno;
330
331 modref_summary_lto ();
332 ~modref_summary_lto ();
333 void dump (FILE *);
334 bool useful_p (int ecf_flags, bool check_flags = true);
335 };
336
337 /* Summary for a single function which this pass produces. */
338
339 modref_summary_lto::modref_summary_lto ()
340 : loads (NULL), stores (NULL), writes_errno (NULL)
341 {
342 }
343
344 modref_summary_lto::~modref_summary_lto ()
345 {
346 if (loads)
347 ggc_delete (loads);
348 if (stores)
349 ggc_delete (stores);
350 }
351
352
353 /* Return true if lto summary is potentially useful for optimization.
354 If CHECK_FLAGS is false assume that arg_flags are useful. */
355
356 bool
357 modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
358 {
359 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
360 return false;
361 if (arg_flags.length () && !check_flags)
362 return true;
363 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
364 return true;
365 arg_flags.release ();
366 if (loads && !loads->every_base)
367 return true;
368 if (ecf_flags & ECF_PURE)
369 return false;
370 return stores && !stores->every_base;
371 }
372
373 /* Dump A to OUT. */
374
375 static void
376 dump_access (modref_access_node *a, FILE *out)
377 {
378 fprintf (out, " access:");
379 if (a->parm_index != -1)
380 {
381 fprintf (out, " Parm %i", a->parm_index);
382 if (a->parm_offset_known)
383 {
384 fprintf (out, " param offset:");
385 print_dec ((poly_int64_pod)a->parm_offset, out, SIGNED);
386 }
387 }
388 if (a->range_info_useful_p ())
389 {
390 fprintf (out, " offset:");
391 print_dec ((poly_int64_pod)a->offset, out, SIGNED);
392 fprintf (out, " size:");
393 print_dec ((poly_int64_pod)a->size, out, SIGNED);
394 fprintf (out, " max_size:");
395 print_dec ((poly_int64_pod)a->max_size, out, SIGNED);
396 }
397 fprintf (out, "\n");
398 }
399
400 /* Dump records TT to OUT. */
401
402 static void
403 dump_records (modref_records *tt, FILE *out)
404 {
405 fprintf (out, " Limits: %i bases, %i refs\n",
406 (int)tt->max_bases, (int)tt->max_refs);
407 if (tt->every_base)
408 {
409 fprintf (out, " Every base\n");
410 return;
411 }
412 size_t i;
413 modref_base_node <alias_set_type> *n;
414 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
415 {
416 fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
417 if (n->every_ref)
418 {
419 fprintf (out, " Every ref\n");
420 continue;
421 }
422 size_t j;
423 modref_ref_node <alias_set_type> *r;
424 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
425 {
426 fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
427 if (r->every_access)
428 {
429 fprintf (out, " Every access\n");
430 continue;
431 }
432 size_t k;
433 modref_access_node *a;
434 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
435 dump_access (a, out);
436 }
437 }
438 }
439
440 /* Dump records TT to OUT. */
441
442 static void
443 dump_lto_records (modref_records_lto *tt, FILE *out)
444 {
445 fprintf (out, " Limits: %i bases, %i refs\n",
446 (int)tt->max_bases, (int)tt->max_refs);
447 if (tt->every_base)
448 {
449 fprintf (out, " Every base\n");
450 return;
451 }
452 size_t i;
453 modref_base_node <tree> *n;
454 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
455 {
456 fprintf (out, " Base %i:", (int)i);
457 print_generic_expr (dump_file, n->base);
458 fprintf (out, " (alias set %i)\n",
459 n->base ? get_alias_set (n->base) : 0);
460 if (n->every_ref)
461 {
462 fprintf (out, " Every ref\n");
463 continue;
464 }
465 size_t j;
466 modref_ref_node <tree> *r;
467 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
468 {
469 fprintf (out, " Ref %i:", (int)j);
470 print_generic_expr (dump_file, r->ref);
471 fprintf (out, " (alias set %i)\n",
472 r->ref ? get_alias_set (r->ref) : 0);
473 if (r->every_access)
474 {
475 fprintf (out, " Every access\n");
476 continue;
477 }
478 size_t k;
479 modref_access_node *a;
480 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
481 dump_access (a, out);
482 }
483 }
484 }
485
486 /* Dump all escape points of NODE to OUT. */
487
488 static void
489 dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
490 {
491 int i = 0;
492 if (!escape_summaries)
493 return;
494 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
495 {
496 class escape_summary *sum = escape_summaries->get (e);
497 if (sum)
498 {
499 fprintf (out, "%*sIndirect call %i in %s escapes:",
500 depth, "", i, node->dump_name ());
501 sum->dump (out);
502 }
503 i++;
504 }
505 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
506 {
507 if (!e->inline_failed)
508 dump_modref_edge_summaries (out, e->callee, depth + 1);
509 class escape_summary *sum = escape_summaries->get (e);
510 if (sum)
511 {
512 fprintf (out, "%*sCall %s->%s escapes:", depth, "",
513 node->dump_name (), e->callee->dump_name ());
514 sum->dump (out);
515 }
516 class fnspec_summary *fsum = fnspec_summaries->get (e);
517 if (fsum)
518 {
519 fprintf (out, "%*sCall %s->%s fnspec: %s\n", depth, "",
520 node->dump_name (), e->callee->dump_name (),
521 fsum->fnspec);
522 }
523 }
524 }
525
526 /* Remove all call edge summaries associated with NODE. */
527
528 static void
529 remove_modref_edge_summaries (cgraph_node *node)
530 {
531 if (!escape_summaries)
532 return;
533 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
534 escape_summaries->remove (e);
535 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
536 {
537 if (!e->inline_failed)
538 remove_modref_edge_summaries (e->callee);
539 escape_summaries->remove (e);
540 fnspec_summaries->remove (e);
541 }
542 }
543
544 /* Dump summary. */
545
546 void
547 modref_summary::dump (FILE *out)
548 {
549 if (loads)
550 {
551 fprintf (out, " loads:\n");
552 dump_records (loads, out);
553 }
554 if (stores)
555 {
556 fprintf (out, " stores:\n");
557 dump_records (stores, out);
558 }
559 if (writes_errno)
560 fprintf (out, " Writes errno\n");
561 if (arg_flags.length ())
562 {
563 for (unsigned int i = 0; i < arg_flags.length (); i++)
564 if (arg_flags[i])
565 {
566 fprintf (out, " parm %i flags:", i);
567 dump_eaf_flags (out, arg_flags[i]);
568 }
569 }
570 }
571
572 /* Dump summary. */
573
574 void
575 modref_summary_lto::dump (FILE *out)
576 {
577 fprintf (out, " loads:\n");
578 dump_lto_records (loads, out);
579 fprintf (out, " stores:\n");
580 dump_lto_records (stores, out);
581 if (writes_errno)
582 fprintf (out, " Writes errno\n");
583 if (arg_flags.length ())
584 {
585 for (unsigned int i = 0; i < arg_flags.length (); i++)
586 if (arg_flags[i])
587 {
588 fprintf (out, " parm %i flags:", i);
589 dump_eaf_flags (out, arg_flags[i]);
590 }
591 }
592 }
593
594 /* Get function summary for FUNC if it exists, return NULL otherwise. */
595
596 modref_summary *
597 get_modref_function_summary (cgraph_node *func)
598 {
599 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
600 if (!optimization_summaries)
601 return NULL;
602
603 /* A single function body may be represented by multiple symbols with
604 different visibility. For example, if FUNC is an interposable alias,
605 we don't want to return anything, even if we have summary for the target
606 function. */
607 enum availability avail;
608 func = func->function_or_virtual_thunk_symbol
609 (&avail, current_function_decl ?
610 cgraph_node::get (current_function_decl) : NULL);
611 if (avail <= AVAIL_INTERPOSABLE)
612 return NULL;
613
614 modref_summary *r = optimization_summaries->get (func);
615 return r;
616 }
617
618 /* Construct modref_access_node from REF. */
619 static modref_access_node
620 get_access (ao_ref *ref)
621 {
622 tree base;
623
624 base = ao_ref_base (ref);
625 modref_access_node a = {ref->offset, ref->size, ref->max_size,
626 0, -1, false};
627 if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
628 {
629 tree memref = base;
630 base = TREE_OPERAND (base, 0);
631 if (TREE_CODE (base) == SSA_NAME
632 && SSA_NAME_IS_DEFAULT_DEF (base)
633 && TREE_CODE (SSA_NAME_VAR (base)) == PARM_DECL)
634 {
635 a.parm_index = 0;
636 for (tree t = DECL_ARGUMENTS (current_function_decl);
637 t != SSA_NAME_VAR (base); t = DECL_CHAIN (t))
638 {
639 if (!t)
640 {
641 a.parm_index = -1;
642 break;
643 }
644 a.parm_index++;
645 }
646 if (TREE_CODE (memref) == MEM_REF)
647 {
648 a.parm_offset_known
649 = wi::to_poly_wide (TREE_OPERAND
650 (memref, 1)).to_shwi (&a.parm_offset);
651 }
652 else
653 a.parm_offset_known = false;
654 }
655 else
656 a.parm_index = -1;
657 }
658 else
659 a.parm_index = -1;
660 return a;
661 }
662
663 /* Record access into the modref_records data structure. */
664
665 static void
666 record_access (modref_records *tt, ao_ref *ref)
667 {
668 alias_set_type base_set = !flag_strict_aliasing ? 0
669 : ao_ref_base_alias_set (ref);
670 alias_set_type ref_set = !flag_strict_aliasing ? 0
671 : (ao_ref_alias_set (ref));
672 modref_access_node a = get_access (ref);
673 if (dump_file)
674 {
675 fprintf (dump_file, " - Recording base_set=%i ref_set=%i parm=%i\n",
676 base_set, ref_set, a.parm_index);
677 }
678 tt->insert (base_set, ref_set, a);
679 }
680
681 /* IPA version of record_access_tree. */
682
683 static void
684 record_access_lto (modref_records_lto *tt, ao_ref *ref)
685 {
686 /* get_alias_set sometimes use different type to compute the alias set
687 than TREE_TYPE (base). Do same adjustments. */
688 tree base_type = NULL_TREE, ref_type = NULL_TREE;
689 if (flag_strict_aliasing)
690 {
691 tree base;
692
693 base = ref->ref;
694 while (handled_component_p (base))
695 base = TREE_OPERAND (base, 0);
696
697 base_type = reference_alias_ptr_type_1 (&base);
698
699 if (!base_type)
700 base_type = TREE_TYPE (base);
701 else
702 base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
703 ? NULL_TREE : TREE_TYPE (base_type);
704
705 tree ref_expr = ref->ref;
706 ref_type = reference_alias_ptr_type_1 (&ref_expr);
707
708 if (!ref_type)
709 ref_type = TREE_TYPE (ref_expr);
710 else
711 ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
712 ? NULL_TREE : TREE_TYPE (ref_type);
713
714 /* Sanity check that we are in sync with what get_alias_set does. */
715 gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
716 || get_alias_set (base_type)
717 == ao_ref_base_alias_set (ref));
718 gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
719 || get_alias_set (ref_type)
720 == ao_ref_alias_set (ref));
721
722 /* Do not bother to record types that have no meaningful alias set.
723 Also skip variably modified types since these go to local streams. */
724 if (base_type && (!get_alias_set (base_type)
725 || variably_modified_type_p (base_type, NULL_TREE)))
726 base_type = NULL_TREE;
727 if (ref_type && (!get_alias_set (ref_type)
728 || variably_modified_type_p (ref_type, NULL_TREE)))
729 ref_type = NULL_TREE;
730 }
731 modref_access_node a = get_access (ref);
732 if (dump_file)
733 {
734 fprintf (dump_file, " - Recording base type:");
735 print_generic_expr (dump_file, base_type);
736 fprintf (dump_file, " (alias set %i) ref type:",
737 base_type ? get_alias_set (base_type) : 0);
738 print_generic_expr (dump_file, ref_type);
739 fprintf (dump_file, " (alias set %i) parm:%i\n",
740 ref_type ? get_alias_set (ref_type) : 0,
741 a.parm_index);
742 }
743
744 tt->insert (base_type, ref_type, a);
745 }
746
747 /* Returns true if and only if we should store the access to EXPR.
748 Some accesses, e.g. loads from automatic variables, are not interesting. */
749
750 static bool
751 record_access_p (tree expr)
752 {
753 if (refs_local_or_readonly_memory_p (expr))
754 {
755 if (dump_file)
756 fprintf (dump_file, " - Read-only or local, ignoring.\n");
757 return false;
758 }
759 return true;
760 }
761
762 /* Return true if ECF flags says that return value can be ignored. */
763
764 static bool
765 ignore_retval_p (tree caller, int flags)
766 {
767 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
768 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
769 return true;
770 return false;
771 }
772
773 /* Return true if ECF flags says that stores can be ignored. */
774
775 static bool
776 ignore_stores_p (tree caller, int flags)
777 {
778 if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
779 return true;
780 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
781 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
782 return true;
783 return false;
784 }
785
786 /* Determine parm_map for argument I of STMT. */
787
788 modref_parm_map
789 parm_map_for_arg (gimple *stmt, int i)
790 {
791 tree op = gimple_call_arg (stmt, i);
792 bool offset_known;
793 poly_int64 offset;
794 struct modref_parm_map parm_map;
795
796 parm_map.parm_offset_known = false;
797 parm_map.parm_offset = 0;
798
799 offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
800 if (TREE_CODE (op) == SSA_NAME
801 && SSA_NAME_IS_DEFAULT_DEF (op)
802 && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
803 {
804 int index = 0;
805 for (tree t = DECL_ARGUMENTS (current_function_decl);
806 t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
807 {
808 if (!t)
809 {
810 index = -1;
811 break;
812 }
813 index++;
814 }
815 parm_map.parm_index = index;
816 parm_map.parm_offset_known = offset_known;
817 parm_map.parm_offset = offset;
818 }
819 else if (points_to_local_or_readonly_memory_p (op))
820 parm_map.parm_index = -2;
821 else
822 parm_map.parm_index = -1;
823 return parm_map;
824 }
825
826 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
827 int CUR_SUMMARY. Return true if something changed.
828 If IGNORE_STORES is true, do not merge stores. */
829
830 bool
831 merge_call_side_effects (modref_summary *cur_summary,
832 gimple *stmt, modref_summary *callee_summary,
833 bool ignore_stores, cgraph_node *callee_node)
834 {
835 auto_vec <modref_parm_map, 32> parm_map;
836 bool changed = false;
837
838 /* We can not safely optimize based on summary of callee if it does
839 not always bind to current def: it is possible that memory load
840 was optimized out earlier which may not happen in the interposed
841 variant. */
842 if (!callee_node->binds_to_current_def_p ())
843 {
844 if (dump_file)
845 fprintf (dump_file, " - May be interposed: collapsing loads.\n");
846 cur_summary->loads->collapse ();
847 }
848
849 if (dump_file)
850 fprintf (dump_file, " - Merging side effects of %s with parm map:",
851 callee_node->dump_name ());
852
853 parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true);
854 for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
855 {
856 parm_map[i] = parm_map_for_arg (stmt, i);
857 if (dump_file)
858 {
859 fprintf (dump_file, " %i", parm_map[i].parm_index);
860 if (parm_map[i].parm_offset_known)
861 {
862 fprintf (dump_file, " offset:");
863 print_dec ((poly_int64_pod)parm_map[i].parm_offset,
864 dump_file, SIGNED);
865 }
866 }
867 }
868 if (dump_file)
869 fprintf (dump_file, "\n");
870
871 /* Merge with callee's summary. */
872 changed |= cur_summary->loads->merge (callee_summary->loads, &parm_map);
873 if (!ignore_stores)
874 {
875 changed |= cur_summary->stores->merge (callee_summary->stores,
876 &parm_map);
877 if (!cur_summary->writes_errno
878 && callee_summary->writes_errno)
879 {
880 cur_summary->writes_errno = true;
881 changed = true;
882 }
883 }
884 return changed;
885 }
886
887 /* Return access mode for argument I of call STMT with FNSPEC. */
888
889 static modref_access_node
890 get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
891 unsigned int i, modref_parm_map &map)
892 {
893 tree size = NULL_TREE;
894 unsigned int size_arg;
895
896 if (!fnspec.arg_specified_p (i))
897 ;
898 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
899 size = gimple_call_arg (call, size_arg);
900 else if (fnspec.arg_access_size_given_by_type_p (i))
901 {
902 tree callee = gimple_call_fndecl (call);
903 tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
904
905 for (unsigned int p = 0; p < i; p++)
906 t = TREE_CHAIN (t);
907 size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
908 }
909 modref_access_node a = {0, -1, -1,
910 map.parm_offset, map.parm_index,
911 map.parm_offset_known};
912 poly_int64 size_hwi;
913 if (size
914 && poly_int_tree_p (size, &size_hwi)
915 && coeffs_in_range_p (size_hwi, 0,
916 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
917 {
918 a.size = -1;
919 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
920 }
921 return a;
922 }
923
924 /* Collapse loads and return true if something changed. */
925
926 static bool
927 collapse_loads (modref_summary *cur_summary,
928 modref_summary_lto *cur_summary_lto)
929 {
930 bool changed = false;
931
932 if (cur_summary && !cur_summary->loads->every_base)
933 {
934 cur_summary->loads->collapse ();
935 changed = true;
936 }
937 if (cur_summary_lto
938 && !cur_summary_lto->loads->every_base)
939 {
940 cur_summary_lto->loads->collapse ();
941 changed = true;
942 }
943 return changed;
944 }
945
946 /* Collapse loads and return true if something changed. */
947
948 static bool
949 collapse_stores (modref_summary *cur_summary,
950 modref_summary_lto *cur_summary_lto)
951 {
952 bool changed = false;
953
954 if (cur_summary && !cur_summary->stores->every_base)
955 {
956 cur_summary->stores->collapse ();
957 changed = true;
958 }
959 if (cur_summary_lto
960 && !cur_summary_lto->stores->every_base)
961 {
962 cur_summary_lto->stores->collapse ();
963 changed = true;
964 }
965 return changed;
966 }
967
968
969 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
970 If IGNORE_STORES is true ignore them.
971 Return false if no useful summary can be produced. */
972
973 static bool
974 process_fnspec (modref_summary *cur_summary,
975 modref_summary_lto *cur_summary_lto,
976 gcall *call, bool ignore_stores)
977 {
978 attr_fnspec fnspec = gimple_call_fnspec (call);
979 if (!fnspec.known_p ())
980 {
981 if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
982 fprintf (dump_file, " Builtin with no fnspec: %s\n",
983 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
984 if (ignore_stores)
985 {
986 collapse_loads (cur_summary, cur_summary_lto);
987 return true;
988 }
989 return false;
990 }
991 if (fnspec.global_memory_read_p ())
992 collapse_loads (cur_summary, cur_summary_lto);
993 else
994 {
995 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
996 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
997 ;
998 else if (!fnspec.arg_specified_p (i)
999 || fnspec.arg_maybe_read_p (i))
1000 {
1001 modref_parm_map map = parm_map_for_arg (call, i);
1002
1003 if (map.parm_index == -2)
1004 continue;
1005 if (map.parm_index == -1)
1006 {
1007 collapse_loads (cur_summary, cur_summary_lto);
1008 break;
1009 }
1010 if (cur_summary)
1011 cur_summary->loads->insert (0, 0,
1012 get_access_for_fnspec (call,
1013 fnspec, i,
1014 map));
1015 if (cur_summary_lto)
1016 cur_summary_lto->loads->insert (0, 0,
1017 get_access_for_fnspec (call,
1018 fnspec, i,
1019 map));
1020 }
1021 }
1022 if (ignore_stores)
1023 return true;
1024 if (fnspec.global_memory_written_p ())
1025 collapse_stores (cur_summary, cur_summary_lto);
1026 else
1027 {
1028 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1029 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1030 ;
1031 else if (!fnspec.arg_specified_p (i)
1032 || fnspec.arg_maybe_written_p (i))
1033 {
1034 modref_parm_map map = parm_map_for_arg (call, i);
1035
1036 if (map.parm_index == -2)
1037 continue;
1038 if (map.parm_index == -1)
1039 {
1040 collapse_stores (cur_summary, cur_summary_lto);
1041 break;
1042 }
1043 if (cur_summary)
1044 cur_summary->stores->insert (0, 0,
1045 get_access_for_fnspec (call,
1046 fnspec, i,
1047 map));
1048 if (cur_summary_lto)
1049 cur_summary_lto->stores->insert (0, 0,
1050 get_access_for_fnspec (call,
1051 fnspec, i,
1052 map));
1053 }
1054 if (fnspec.errno_maybe_written_p () && flag_errno_math)
1055 {
1056 if (cur_summary)
1057 cur_summary->writes_errno = true;
1058 if (cur_summary_lto)
1059 cur_summary_lto->writes_errno = true;
1060 }
1061 }
1062 return true;
1063 }
1064
1065 /* Analyze function call STMT in function F.
1066 Remember recursive calls in RECURSIVE_CALLS. */
1067
1068 static bool
1069 analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto,
1070 gcall *stmt, vec <gimple *> *recursive_calls)
1071 {
1072 /* Check flags on the function call. In certain cases, analysis can be
1073 simplified. */
1074 int flags = gimple_call_flags (stmt);
1075 if (flags & (ECF_CONST | ECF_NOVOPS))
1076 {
1077 if (dump_file)
1078 fprintf (dump_file,
1079 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1080 "except for args.\n");
1081 return true;
1082 }
1083
1084 /* Pure functions do not affect global memory. Stores by functions which are
1085 noreturn and do not throw can safely be ignored. */
1086 bool ignore_stores = ignore_stores_p (current_function_decl, flags);
1087
1088 /* Next, we try to get the callee's function declaration. The goal is to
1089 merge their summary with ours. */
1090 tree callee = gimple_call_fndecl (stmt);
1091
1092 /* Check if this is an indirect call. */
1093 if (!callee)
1094 {
1095 if (dump_file)
1096 fprintf (dump_file, gimple_call_internal_p (stmt)
1097 ? " - Internal call" : " - Indirect call.\n");
1098 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1099 }
1100 /* We only need to handle internal calls in IPA mode. */
1101 gcc_checking_assert (!cur_summary_lto);
1102
1103 struct cgraph_node *callee_node = cgraph_node::get_create (callee);
1104
1105 /* If this is a recursive call, the target summary is the same as ours, so
1106 there's nothing to do. */
1107 if (recursive_call_p (current_function_decl, callee))
1108 {
1109 recursive_calls->safe_push (stmt);
1110 if (dump_file)
1111 fprintf (dump_file, " - Skipping recursive call.\n");
1112 return true;
1113 }
1114
1115 gcc_assert (callee_node != NULL);
1116
1117 /* Get the function symbol and its availability. */
1118 enum availability avail;
1119 callee_node = callee_node->function_symbol (&avail);
1120 if (avail <= AVAIL_INTERPOSABLE)
1121 {
1122 if (dump_file)
1123 fprintf (dump_file, " - Function availability <= AVAIL_INTERPOSABLE.\n");
1124 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1125 }
1126
1127 /* Get callee's modref summary. As above, if there's no summary, we either
1128 have to give up or, if stores are ignored, we can just purge loads. */
1129 modref_summary *callee_summary = optimization_summaries->get (callee_node);
1130 if (!callee_summary)
1131 {
1132 if (dump_file)
1133 fprintf (dump_file, " - No modref summary available for callee.\n");
1134 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1135 }
1136
1137 merge_call_side_effects (cur_summary, stmt, callee_summary, ignore_stores,
1138 callee_node);
1139
1140 return true;
1141 }
1142
1143 /* Support analysis in non-lto and lto mode in parallel. */
1144
1145 struct summary_ptrs
1146 {
1147 struct modref_summary *nolto;
1148 struct modref_summary_lto *lto;
1149 };
1150
1151 /* Helper for analyze_stmt. */
1152
1153 static bool
1154 analyze_load (gimple *, tree, tree op, void *data)
1155 {
1156 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1157 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1158
1159 if (dump_file)
1160 {
1161 fprintf (dump_file, " - Analyzing load: ");
1162 print_generic_expr (dump_file, op);
1163 fprintf (dump_file, "\n");
1164 }
1165
1166 if (!record_access_p (op))
1167 return false;
1168
1169 ao_ref r;
1170 ao_ref_init (&r, op);
1171
1172 if (summary)
1173 record_access (summary->loads, &r);
1174 if (summary_lto)
1175 record_access_lto (summary_lto->loads, &r);
1176 return false;
1177 }
1178
1179 /* Helper for analyze_stmt. */
1180
1181 static bool
1182 analyze_store (gimple *, tree, tree op, void *data)
1183 {
1184 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1185 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1186
1187 if (dump_file)
1188 {
1189 fprintf (dump_file, " - Analyzing store: ");
1190 print_generic_expr (dump_file, op);
1191 fprintf (dump_file, "\n");
1192 }
1193
1194 if (!record_access_p (op))
1195 return false;
1196
1197 ao_ref r;
1198 ao_ref_init (&r, op);
1199
1200 if (summary)
1201 record_access (summary->stores, &r);
1202 if (summary_lto)
1203 record_access_lto (summary_lto->stores, &r);
1204 return false;
1205 }
1206
1207 /* Analyze statement STMT of function F.
1208 If IPA is true do not merge in side effects of calls. */
1209
1210 static bool
1211 analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
1212 gimple *stmt, bool ipa, vec <gimple *> *recursive_calls)
1213 {
1214 /* In general we can not ignore clobbers because they are barriers for code
1215 motion, however after inlining it is safe to do because local optimization
1216 passes do not consider clobbers from other functions.
1217 Similar logic is in ipa-pure-const.c. */
1218 if ((ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1219 return true;
1220
1221 struct summary_ptrs sums = {summary, summary_lto};
1222
1223 /* Analyze all loads and stores in STMT. */
1224 walk_stmt_load_store_ops (stmt, &sums,
1225 analyze_load, analyze_store);
1226
1227 switch (gimple_code (stmt))
1228 {
1229 case GIMPLE_ASM:
1230 /* If the ASM statement does not read nor write memory, there's nothing
1231 to do. Otherwise just give up. */
1232 if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1233 return true;
1234 if (dump_file)
1235 fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1236 "which clobbers memory.\n");
1237 return false;
1238 case GIMPLE_CALL:
1239 if (!ipa || gimple_call_internal_p (stmt))
1240 return analyze_call (summary, summary_lto,
1241 as_a <gcall *> (stmt), recursive_calls);
1242 else
1243 {
1244 attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1245
1246 if (fnspec.known_p ()
1247 && (!fnspec.global_memory_read_p ()
1248 || !fnspec.global_memory_written_p ()))
1249 {
1250 cgraph_edge *e = cgraph_node::get (current_function_decl)->get_edge (stmt);
1251 if (e->callee)
1252 {
1253 fnspec_summaries->get_create (e)->fnspec = xstrdup (fnspec.get_str ());
1254 if (dump_file)
1255 fprintf (dump_file, " Recorded fnspec %s\n", fnspec.get_str ());
1256 }
1257 }
1258 }
1259 return true;
1260 default:
1261 /* Nothing to do for other types of statements. */
1262 return true;
1263 }
1264 }
1265
1266 /* Remove summary of current function because during the function body
1267 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1268 mode of scan. */
1269
1270 static void
1271 remove_summary (bool lto, bool nolto, bool ipa)
1272 {
1273 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1274 if (!ipa)
1275 optimization_summaries->remove (fnode);
1276 else
1277 {
1278 if (nolto)
1279 summaries->remove (fnode);
1280 if (lto)
1281 summaries_lto->remove (fnode);
1282 remove_modref_edge_summaries (fnode);
1283 }
1284 if (dump_file)
1285 fprintf (dump_file,
1286 " - modref done with result: not tracked.\n");
1287 }
1288
1289 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1290
1291 bool
1292 memory_access_to (tree op, tree ssa_name)
1293 {
1294 tree base = get_base_address (op);
1295 if (!base)
1296 return false;
1297 if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1298 return false;
1299 return TREE_OPERAND (base, 0) == ssa_name;
1300 }
1301
1302 /* Consider statement val = *arg.
1303 return EAF flags of ARG that can be determined from EAF flags of VAL
1304 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1305 all stores to VAL, i.e. when handling noreturn function. */
1306
1307 static int
1308 deref_flags (int flags, bool ignore_stores)
1309 {
1310 int ret = EAF_NODIRECTESCAPE;
1311 if (flags & EAF_UNUSED)
1312 ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE;
1313 else
1314 {
1315 if ((flags & EAF_NOCLOBBER) || ignore_stores)
1316 ret |= EAF_NOCLOBBER;
1317 if ((flags & EAF_NOESCAPE) || ignore_stores)
1318 ret |= EAF_NOESCAPE;
1319 }
1320 return ret;
1321 }
1322
1323 namespace {
1324
1325 /* Description of an escape point. */
1326
1327 struct escape_point
1328 {
1329 /* Value escapes to this call. */
1330 gcall *call;
1331 /* Argument it escapes to. */
1332 int arg;
1333 /* Flags already known about the argument (this can save us from recording
1334 esape points if local analysis did good job already). */
1335 char min_flags;
1336 /* Does value escape directly or indiretly? */
1337 bool direct;
1338 };
1339
1340 class modref_lattice
1341 {
1342 public:
1343 /* EAF flags of the SSA name. */
1344 int flags;
1345 /* DFS bookkkeeping: we don't do real dataflow yet. */
1346 bool known;
1347 bool open;
1348
1349 /* When doing IPA analysis we can not merge in callee escape points;
1350 Only remember them and do the merging at IPA propagation time. */
1351 vec <escape_point, va_heap, vl_ptr> escape_points;
1352
1353 void init ();
1354 void release ();
1355 bool merge (const modref_lattice &with);
1356 bool merge (int flags);
1357 bool merge_deref (const modref_lattice &with, bool ignore_stores);
1358 bool merge_direct_load ();
1359 bool merge_direct_store ();
1360 bool add_escape_point (gcall *call, int arg, int min_flags, bool diret);
1361 void dump (FILE *out, int indent = 0) const;
1362 };
1363
1364 /* Lattices are saved to vectors, so keep them PODs. */
1365 void
1366 modref_lattice::init ()
1367 {
1368 flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED
1369 | EAF_NODIRECTESCAPE;
1370 open = true;
1371 known = false;
1372 }
1373
1374 /* Release memory. */
1375 void
1376 modref_lattice::release ()
1377 {
1378 escape_points.release ();
1379 }
1380
1381 /* Dump lattice to OUT; indent with INDENT spaces. */
1382
1383 void
1384 modref_lattice::dump (FILE *out, int indent) const
1385 {
1386 dump_eaf_flags (out, flags);
1387 if (escape_points.length ())
1388 {
1389 fprintf (out, "%*sEscapes:\n", indent, "");
1390 for (unsigned int i = 0; i < escape_points.length (); i++)
1391 {
1392 fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
1393 escape_points[i].arg,
1394 escape_points[i].direct ? "direct" : "indirect");
1395 dump_eaf_flags (out, flags, false);
1396 fprintf (out, " in call ");
1397 print_gimple_stmt (out, escape_points[i].call, 0);
1398 }
1399 }
1400 }
1401
1402 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1403 point exists. */
1404
1405 bool
1406 modref_lattice::add_escape_point (gcall *call, int arg, int min_flags,
1407 bool direct)
1408 {
1409 escape_point *ep;
1410 unsigned int i;
1411
1412 /* If we already determined flags to be bad enough,
1413 * we do not need to record. */
1414 if ((flags & min_flags) == flags)
1415 return false;
1416
1417 FOR_EACH_VEC_ELT (escape_points, i, ep)
1418 if (ep->call == call && ep->arg == arg && ep->direct == direct)
1419 {
1420 if ((ep->min_flags & min_flags) == min_flags)
1421 return false;
1422 ep->min_flags &= min_flags;
1423 return true;
1424 }
1425 /* Give up if max escape points is met. */
1426 if ((int)escape_points.length () > param_modref_max_escape_points)
1427 {
1428 if (dump_file)
1429 fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
1430 merge (0);
1431 return true;
1432 }
1433 escape_point new_ep = {call, arg, min_flags, direct};
1434 escape_points.safe_push (new_ep);
1435 return true;
1436 }
1437
1438 /* Merge in flags from F. */
1439 bool
1440 modref_lattice::merge (int f)
1441 {
1442 if (f & EAF_UNUSED)
1443 return false;
1444 if ((flags & f) != flags)
1445 {
1446 flags &= f;
1447 /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
1448 in tree-ssa-alias.c). Give up earlier. */
1449 if ((flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
1450 flags = 0;
1451 if (!flags)
1452 escape_points.release ();
1453 return true;
1454 }
1455 return false;
1456 }
1457
1458 /* Merge in WITH. Return true if anyting changed. */
1459
1460 bool
1461 modref_lattice::merge (const modref_lattice &with)
1462 {
1463 if (!with.known)
1464 return merge (0);
1465
1466 bool changed = merge (with.flags);
1467
1468 if (!flags)
1469 return changed;
1470 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1471 changed |= add_escape_point (with.escape_points[i].call,
1472 with.escape_points[i].arg,
1473 with.escape_points[i].min_flags,
1474 with.escape_points[i].direct);
1475 return changed;
1476 }
1477
1478 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1479 stores. Return true if anyting changed. */
1480
1481 bool
1482 modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
1483 {
1484 if (!with.known)
1485 return merge (0);
1486
1487 bool changed = merge (deref_flags (with.flags, ignore_stores));
1488
1489 if (!flags)
1490 return changed;
1491 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1492 changed |= add_escape_point (with.escape_points[i].call,
1493 with.escape_points[i].arg,
1494 with.escape_points[i].min_flags,
1495 false);
1496 return changed;
1497 }
1498
1499 /* Merge in flags for direct load. */
1500
1501 bool
1502 modref_lattice::merge_direct_load ()
1503 {
1504 return merge (~EAF_UNUSED);
1505 }
1506
1507 /* Merge in flags for direct store. */
1508
1509 bool
1510 modref_lattice::merge_direct_store ()
1511 {
1512 return merge (~(EAF_UNUSED | EAF_NOCLOBBER));
1513 }
1514
1515 } /* ANON namespace. */
1516
1517 static void analyze_ssa_name_flags (tree name,
1518 vec<modref_lattice> &lattice,
1519 int depth, bool ipa);
1520
1521 /* Call statements may return their parameters. Consider argument number
1522 ARG of USE_STMT and determine flags that can needs to be cleared
1523 in case pointer possibly indirectly references from ARG I is returned.
1524 LATTICE, DEPTH and ipa are same as in analyze_ssa_name_flags. */
1525
1526 static void
1527 merge_call_lhs_flags (gcall *call, int arg, int index, bool deref,
1528 vec<modref_lattice> &lattice,
1529 int depth, bool ipa)
1530 {
1531 /* If there is no return value, no flags are affected. */
1532 if (!gimple_call_lhs (call))
1533 return;
1534
1535 /* If we know that function returns given argument and it is not ARG
1536 we can still be happy. */
1537 int flags = gimple_call_return_flags (call);
1538 if ((flags & ERF_RETURNS_ARG)
1539 && (flags & ERF_RETURN_ARG_MASK) != arg)
1540 return;
1541
1542 /* If return value is SSA name determine its flags. */
1543 if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
1544 {
1545 tree lhs = gimple_call_lhs (call);
1546 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1547 if (deref)
1548 lattice[index].merge_deref (lattice[SSA_NAME_VERSION (lhs)], false);
1549 else
1550 lattice[index].merge (lattice[SSA_NAME_VERSION (lhs)]);
1551 }
1552 /* In the case of memory store we can do nothing. */
1553 else
1554 lattice[index].merge (0);
1555 }
1556
1557 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
1558 LATTICE is an array of modref_lattices.
1559 DEPTH is a recursion depth used to make debug output prettier.
1560 If IPA is true we analyze for IPA propagation (and thus call escape points
1561 are processed later) */
1562
1563 static void
1564 analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
1565 bool ipa)
1566 {
1567 imm_use_iterator ui;
1568 gimple *use_stmt;
1569 int index = SSA_NAME_VERSION (name);
1570
1571 /* See if value is already computed. */
1572 if (lattice[index].known)
1573 return;
1574 if (lattice[index].open)
1575 {
1576 if (dump_file)
1577 fprintf (dump_file,
1578 "%*sGiving up on a cycle in SSA graph\n", depth * 4, "");
1579 return;
1580 }
1581 if (depth == param_modref_max_depth)
1582 {
1583 if (dump_file)
1584 fprintf (dump_file,
1585 "%*sGiving up on max depth\n", depth * 4, "");
1586 return;
1587 }
1588 /* Recursion guard. */
1589 lattice[index].init ();
1590
1591 if (dump_file)
1592 {
1593 fprintf (dump_file,
1594 "%*sAnalyzing flags of ssa name: ", depth * 4, "");
1595 print_generic_expr (dump_file, name);
1596 fprintf (dump_file, "\n");
1597 }
1598
1599 FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
1600 {
1601 if (lattice[index].flags == 0)
1602 break;
1603 if (is_gimple_debug (use_stmt))
1604 continue;
1605 if (dump_file)
1606 {
1607 fprintf (dump_file, "%*s Analyzing stmt: ", depth * 4, "");
1608 print_gimple_stmt (dump_file, use_stmt, 0);
1609 }
1610
1611 /* Gimple return may load the return value.
1612 Returning name counts as an use by tree-ssa-structalias.c */
1613 if (greturn *ret = dyn_cast <greturn *> (use_stmt))
1614 {
1615 if (gimple_return_retval (ret) == name)
1616 lattice[index].merge (~EAF_UNUSED);
1617 else if (memory_access_to (gimple_return_retval (ret), name))
1618 lattice[index].merge_direct_load ();
1619 }
1620 /* Account for LHS store, arg loads and flags from callee function. */
1621 else if (gcall *call = dyn_cast <gcall *> (use_stmt))
1622 {
1623 tree callee = gimple_call_fndecl (call);
1624 /* Return slot optimization would require bit of propagation;
1625 give up for now. */
1626 if (gimple_call_return_slot_opt_p (call)
1627 && gimple_call_lhs (call) != NULL_TREE
1628 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
1629 {
1630 if (dump_file)
1631 fprintf (dump_file, "%*s Unhandled return slot opt\n",
1632 depth * 4, "");
1633 lattice[index].merge (0);
1634 }
1635 /* Recursion would require bit of propagation; give up for now. */
1636 else if (callee && !ipa && recursive_call_p (current_function_decl,
1637 callee))
1638 lattice[index].merge (0);
1639 else
1640 {
1641 int ecf_flags = gimple_call_flags (call);
1642 bool ignore_stores = ignore_stores_p (current_function_decl,
1643 ecf_flags);
1644 bool ignore_retval = ignore_retval_p (current_function_decl,
1645 ecf_flags);
1646
1647 /* Handle *name = func (...). */
1648 if (gimple_call_lhs (call)
1649 && memory_access_to (gimple_call_lhs (call), name))
1650 lattice[index].merge_direct_store ();
1651
1652 /* We do not track accesses to the static chain (we could)
1653 so give up. */
1654 if (gimple_call_chain (call)
1655 && (gimple_call_chain (call) == name))
1656 lattice[index].merge (0);
1657
1658 /* Process internal functions and right away. */
1659 bool record_ipa = ipa && !gimple_call_internal_p (call);
1660
1661 /* Handle all function parameters. */
1662 for (unsigned i = 0;
1663 i < gimple_call_num_args (call) && lattice[index].flags; i++)
1664 /* Name is directly passed to the callee. */
1665 if (gimple_call_arg (call, i) == name)
1666 {
1667 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
1668 {
1669 int call_flags = gimple_call_arg_flags (call, i);
1670 if (ignore_stores)
1671 call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE
1672 | EAF_NODIRECTESCAPE;
1673
1674 if (!record_ipa)
1675 lattice[index].merge (call_flags);
1676 else
1677 lattice[index].add_escape_point (call, i,
1678 call_flags, true);
1679 }
1680 if (!ignore_retval)
1681 merge_call_lhs_flags (call, i, index, false,
1682 lattice, depth, ipa);
1683 }
1684 /* Name is dereferenced and passed to a callee. */
1685 else if (memory_access_to (gimple_call_arg (call, i), name))
1686 {
1687 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
1688 lattice[index].merge_direct_load ();
1689 else
1690 {
1691 int call_flags = deref_flags
1692 (gimple_call_arg_flags (call, i), ignore_stores);
1693 if (!record_ipa)
1694 lattice[index].merge (call_flags);
1695 else
1696 lattice[index].add_escape_point (call, i,
1697 call_flags, false);
1698 }
1699 if (!ignore_retval)
1700 merge_call_lhs_flags (call, i, index, true,
1701 lattice, depth, ipa);
1702 }
1703 }
1704 }
1705 else if (gimple_assign_load_p (use_stmt))
1706 {
1707 gassign *assign = as_a <gassign *> (use_stmt);
1708 /* Memory to memory copy. */
1709 if (gimple_store_p (assign))
1710 {
1711 /* Handle *lhs = *name.
1712
1713 We do not track memory locations, so assume that value
1714 is used arbitrarily. */
1715 if (memory_access_to (gimple_assign_rhs1 (assign), name))
1716 lattice[index].merge (0);
1717 /* Handle *name = *exp. */
1718 else if (memory_access_to (gimple_assign_lhs (assign), name))
1719 lattice[index].merge_direct_store ();
1720 }
1721 /* Handle lhs = *name. */
1722 else if (memory_access_to (gimple_assign_rhs1 (assign), name))
1723 {
1724 tree lhs = gimple_assign_lhs (assign);
1725 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1726 lattice[index].merge_deref (lattice[SSA_NAME_VERSION (lhs)],
1727 false);
1728 }
1729 }
1730 else if (gimple_store_p (use_stmt))
1731 {
1732 gassign *assign = dyn_cast <gassign *> (use_stmt);
1733
1734 /* Handle *lhs = name. */
1735 if (assign && gimple_assign_rhs1 (assign) == name)
1736 {
1737 if (dump_file)
1738 fprintf (dump_file, "%*s ssa name saved to memory\n",
1739 depth * 4, "");
1740 lattice[index].merge (0);
1741 }
1742 /* Handle *name = exp. */
1743 else if (assign
1744 && memory_access_to (gimple_assign_lhs (assign), name))
1745 {
1746 /* In general we can not ignore clobbers because they are
1747 barriers for code motion, however after inlining it is safe to
1748 do because local optimization passes do not consider clobbers
1749 from other functions. Similar logic is in ipa-pure-const.c. */
1750 if (!cfun->after_inlining || !gimple_clobber_p (assign))
1751 lattice[index].merge_direct_store ();
1752 }
1753 /* ASM statements etc. */
1754 else if (!assign)
1755 {
1756 if (dump_file)
1757 fprintf (dump_file, "%*s Unhandled store\n",
1758 depth * 4, "");
1759 lattice[index].merge (0);
1760 }
1761 }
1762 else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
1763 {
1764 enum tree_code code = gimple_assign_rhs_code (assign);
1765
1766 /* See if operation is a merge as considered by
1767 tree-ssa-structalias.c:find_func_aliases. */
1768 if (!truth_value_p (code)
1769 && code != POINTER_DIFF_EXPR
1770 && (code != POINTER_PLUS_EXPR
1771 || gimple_assign_rhs1 (assign) == name))
1772 {
1773 tree lhs = gimple_assign_lhs (assign);
1774 analyze_ssa_name_flags (lhs, lattice, depth + 1, ipa);
1775 lattice[index].merge (lattice[SSA_NAME_VERSION (lhs)]);
1776 }
1777 }
1778 else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
1779 {
1780 tree result = gimple_phi_result (phi);
1781 analyze_ssa_name_flags (result, lattice, depth + 1, ipa);
1782 lattice[index].merge (lattice[SSA_NAME_VERSION (result)]);
1783 }
1784 /* Conditions are not considered escape points
1785 by tree-ssa-structalias. */
1786 else if (gimple_code (use_stmt) == GIMPLE_COND)
1787 ;
1788 else
1789 {
1790 if (dump_file)
1791 fprintf (dump_file, "%*s Unhandled stmt\n", depth * 4, "");
1792 lattice[index].merge (0);
1793 }
1794
1795 if (dump_file)
1796 {
1797 fprintf (dump_file, "%*s current flags of ", depth * 4, "");
1798 print_generic_expr (dump_file, name);
1799 lattice[index].dump (dump_file, depth * 4 + 4);
1800 }
1801 }
1802 if (dump_file)
1803 {
1804 fprintf (dump_file, "%*sflags of ssa name ", depth * 4, "");
1805 print_generic_expr (dump_file, name);
1806 lattice[index].dump (dump_file, depth * 4 + 2);
1807 }
1808 lattice[index].open = false;
1809 lattice[index].known = true;
1810 }
1811
1812 /* Determine EAF flags for function parameters. */
1813
1814 static void
1815 analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
1816 bool ipa)
1817 {
1818 unsigned int parm_index = 0;
1819 unsigned int count = 0;
1820 int ecf_flags = flags_from_decl_or_type (current_function_decl);
1821
1822 /* For const functions we have nothing to gain by EAF flags. */
1823 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
1824 return;
1825
1826 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
1827 parm = TREE_CHAIN (parm))
1828 count++;
1829
1830 if (!count)
1831 return;
1832
1833 auto_vec<modref_lattice> lattice;
1834 lattice.safe_grow_cleared (num_ssa_names, true);
1835
1836 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
1837 parm = TREE_CHAIN (parm))
1838 {
1839 tree name = ssa_default_def (cfun, parm);
1840 if (!name || has_zero_uses (name))
1841 {
1842 /* We do not track non-SSA parameters,
1843 but we want to track unused gimple_regs. */
1844 if (!is_gimple_reg (parm))
1845 continue;
1846 if (summary)
1847 {
1848 if (parm_index >= summary->arg_flags.length ())
1849 summary->arg_flags.safe_grow_cleared (count, true);
1850 summary->arg_flags[parm_index] = EAF_UNUSED;
1851 }
1852 else if (summary_lto)
1853 {
1854 if (parm_index >= summary_lto->arg_flags.length ())
1855 summary_lto->arg_flags.safe_grow_cleared (count, true);
1856 summary_lto->arg_flags[parm_index] = EAF_UNUSED;
1857 }
1858 continue;
1859 }
1860 analyze_ssa_name_flags (name, lattice, 0, ipa);
1861 int flags = lattice[SSA_NAME_VERSION (name)].flags;
1862
1863 /* For pure functions we have implicit NOCLOBBER
1864 and NOESCAPE. */
1865 if (ecf_flags & ECF_PURE)
1866 flags &= ~(EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE);
1867
1868 if (flags)
1869 {
1870 if (summary)
1871 {
1872 if (parm_index >= summary->arg_flags.length ())
1873 summary->arg_flags.safe_grow_cleared (count, true);
1874 summary->arg_flags[parm_index] = flags;
1875 }
1876 else if (summary_lto)
1877 {
1878 if (parm_index >= summary_lto->arg_flags.length ())
1879 summary_lto->arg_flags.safe_grow_cleared (count, true);
1880 summary_lto->arg_flags[parm_index] = flags;
1881 }
1882 if (lattice[SSA_NAME_VERSION (name)].escape_points.length ())
1883 {
1884 escape_point *ep;
1885 unsigned int ip;
1886 cgraph_node *node = cgraph_node::get (current_function_decl);
1887
1888 gcc_checking_assert (ipa);
1889 FOR_EACH_VEC_ELT
1890 (lattice[SSA_NAME_VERSION (name)].escape_points, ip, ep)
1891 if ((ep->min_flags & flags) != flags)
1892 {
1893 cgraph_edge *e = node->get_edge (ep->call);
1894 struct escape_entry ee = {parm_index, ep->arg,
1895 ep->min_flags, ep->direct};
1896
1897 escape_summaries->get_create (e)->esc.safe_push (ee);
1898 }
1899 }
1900 }
1901 }
1902 if (ipa)
1903 for (unsigned int i = 0; i < num_ssa_names; i++)
1904 lattice[i].release ();
1905 }
1906
1907 /* Analyze function F. IPA indicates whether we're running in local mode
1908 (false) or the IPA mode (true). */
1909
1910 static void
1911 analyze_function (function *f, bool ipa)
1912 {
1913 if (dump_file)
1914 fprintf (dump_file, "modref analyzing '%s' (ipa=%i)%s%s\n",
1915 function_name (f), ipa,
1916 TREE_READONLY (current_function_decl) ? " (const)" : "",
1917 DECL_PURE_P (current_function_decl) ? " (pure)" : "");
1918
1919 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
1920 if (!flag_ipa_modref)
1921 return;
1922
1923 /* Compute no-LTO summaries when local optimization is going to happen. */
1924 bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
1925 || (in_lto_p && !flag_wpa
1926 && flag_incremental_link != INCREMENTAL_LINK_LTO));
1927 /* Compute LTO when LTO streaming is going to happen. */
1928 bool lto = ipa && ((flag_lto && !in_lto_p)
1929 || flag_wpa
1930 || flag_incremental_link == INCREMENTAL_LINK_LTO);
1931 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1932
1933 modref_summary *summary = NULL;
1934 modref_summary_lto *summary_lto = NULL;
1935
1936 /* Initialize the summary.
1937 If we run in local mode there is possibly pre-existing summary from
1938 IPA pass. Dump it so it is easy to compare if mod-ref info has
1939 improved. */
1940 if (!ipa)
1941 {
1942 if (!optimization_summaries)
1943 optimization_summaries = modref_summaries::create_ggc (symtab);
1944 else /* Remove existing summary if we are re-running the pass. */
1945 {
1946 if (dump_file
1947 && (summary
1948 = optimization_summaries->get (cgraph_node::get (f->decl)))
1949 != NULL
1950 && summary->loads)
1951 {
1952 fprintf (dump_file, "Past summary:\n");
1953 optimization_summaries->get
1954 (cgraph_node::get (f->decl))->dump (dump_file);
1955 }
1956 optimization_summaries->remove (cgraph_node::get (f->decl));
1957 }
1958 summary = optimization_summaries->get_create (cgraph_node::get (f->decl));
1959 gcc_checking_assert (nolto && !lto);
1960 }
1961 /* In IPA mode we analyze every function precisely once. Assert that. */
1962 else
1963 {
1964 if (nolto)
1965 {
1966 if (!summaries)
1967 summaries = modref_summaries::create_ggc (symtab);
1968 else
1969 summaries->remove (cgraph_node::get (f->decl));
1970 summary = summaries->get_create (cgraph_node::get (f->decl));
1971 }
1972 if (lto)
1973 {
1974 if (!summaries_lto)
1975 summaries_lto = modref_summaries_lto::create_ggc (symtab);
1976 else
1977 summaries_lto->remove (cgraph_node::get (f->decl));
1978 summary_lto = summaries_lto->get_create (cgraph_node::get (f->decl));
1979 }
1980 if (!fnspec_summaries)
1981 fnspec_summaries = new fnspec_summaries_t (symtab);
1982 if (!escape_summaries)
1983 escape_summaries = new escape_summaries_t (symtab);
1984 }
1985
1986
1987 /* Create and initialize summary for F.
1988 Note that summaries may be already allocated from previous
1989 run of the pass. */
1990 if (nolto)
1991 {
1992 gcc_assert (!summary->loads);
1993 summary->loads = modref_records::create_ggc (param_modref_max_bases,
1994 param_modref_max_refs,
1995 param_modref_max_accesses);
1996 gcc_assert (!summary->stores);
1997 summary->stores = modref_records::create_ggc (param_modref_max_bases,
1998 param_modref_max_refs,
1999 param_modref_max_accesses);
2000 summary->writes_errno = false;
2001 }
2002 if (lto)
2003 {
2004 gcc_assert (!summary_lto->loads);
2005 summary_lto->loads = modref_records_lto::create_ggc
2006 (param_modref_max_bases,
2007 param_modref_max_refs,
2008 param_modref_max_accesses);
2009 gcc_assert (!summary_lto->stores);
2010 summary_lto->stores = modref_records_lto::create_ggc
2011 (param_modref_max_bases,
2012 param_modref_max_refs,
2013 param_modref_max_accesses);
2014 summary_lto->writes_errno = false;
2015 }
2016
2017 analyze_parms (summary, summary_lto, ipa);
2018
2019 int ecf_flags = flags_from_decl_or_type (current_function_decl);
2020 auto_vec <gimple *, 32> recursive_calls;
2021
2022 /* Analyze each statement in each basic block of the function. If the
2023 statement cannot be analyzed (for any reason), the entire function cannot
2024 be analyzed by modref. */
2025 basic_block bb;
2026 FOR_EACH_BB_FN (bb, f)
2027 {
2028 gimple_stmt_iterator si;
2029 for (si = gsi_after_labels (bb); !gsi_end_p (si); gsi_next (&si))
2030 {
2031 if (!analyze_stmt (summary, summary_lto,
2032 gsi_stmt (si), ipa, &recursive_calls)
2033 || ((!summary || !summary->useful_p (ecf_flags, false))
2034 && (!summary_lto
2035 || !summary_lto->useful_p (ecf_flags, false))))
2036 {
2037 collapse_loads (summary, summary_lto);
2038 collapse_stores (summary, summary_lto);
2039 break;
2040 }
2041 }
2042 }
2043
2044 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2045 This needs to be done after all other side effects are computed. */
2046 if (!ipa)
2047 {
2048 bool changed = true;
2049 while (changed)
2050 {
2051 changed = false;
2052 for (unsigned i = 0; i < recursive_calls.length (); i++)
2053 {
2054 changed |= merge_call_side_effects
2055 (summary, recursive_calls[i], summary,
2056 ignore_stores_p (current_function_decl,
2057 gimple_call_flags
2058 (recursive_calls[i])),
2059 fnode);
2060 if (!summary->useful_p (ecf_flags, false))
2061 {
2062 remove_summary (lto, nolto, ipa);
2063 return;
2064 }
2065 }
2066 }
2067 }
2068 if (summary && !summary->useful_p (ecf_flags))
2069 {
2070 if (!ipa)
2071 optimization_summaries->remove (fnode);
2072 else
2073 summaries->remove (fnode);
2074 summary = NULL;
2075 }
2076 if (summary_lto && !summary_lto->useful_p (ecf_flags))
2077 {
2078 summaries_lto->remove (fnode);
2079 summary_lto = NULL;
2080 }
2081 if (ipa && !summary && !summary_lto)
2082 remove_modref_edge_summaries (fnode);
2083
2084 if (dump_file)
2085 {
2086 fprintf (dump_file, " - modref done with result: tracked.\n");
2087 if (summary)
2088 summary->dump (dump_file);
2089 if (summary_lto)
2090 summary_lto->dump (dump_file);
2091 dump_modref_edge_summaries (dump_file, fnode, 2);
2092 }
2093 }
2094
2095 /* Callback for generate_summary. */
2096
2097 static void
2098 modref_generate (void)
2099 {
2100 struct cgraph_node *node;
2101 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
2102 {
2103 function *f = DECL_STRUCT_FUNCTION (node->decl);
2104 if (!f)
2105 continue;
2106 push_cfun (f);
2107 analyze_function (f, true);
2108 pop_cfun ();
2109 }
2110 }
2111
2112 /* Called when a new function is inserted to callgraph late. */
2113
2114 void
2115 modref_summaries::insert (struct cgraph_node *node, modref_summary *)
2116 {
2117 /* Local passes ought to be executed by the pass manager. */
2118 if (this == optimization_summaries)
2119 {
2120 optimization_summaries->remove (node);
2121 return;
2122 }
2123 if (!DECL_STRUCT_FUNCTION (node->decl)
2124 || !opt_for_fn (node->decl, flag_ipa_modref))
2125 {
2126 summaries->remove (node);
2127 return;
2128 }
2129 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2130 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2131 pop_cfun ();
2132 }
2133
2134 /* Called when a new function is inserted to callgraph late. */
2135
2136 void
2137 modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
2138 {
2139 /* We do not support adding new function when IPA information is already
2140 propagated. This is done only by SIMD cloning that is not very
2141 critical. */
2142 if (!DECL_STRUCT_FUNCTION (node->decl)
2143 || !opt_for_fn (node->decl, flag_ipa_modref)
2144 || propagated)
2145 {
2146 summaries_lto->remove (node);
2147 return;
2148 }
2149 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2150 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
2151 pop_cfun ();
2152 }
2153
2154 /* Called when new clone is inserted to callgraph late. */
2155
2156 void
2157 modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
2158 modref_summary *src_data,
2159 modref_summary *dst_data)
2160 {
2161 /* Do not duplicate optimization summaries; we do not handle parameter
2162 transforms on them. */
2163 if (this == optimization_summaries)
2164 {
2165 optimization_summaries->remove (dst);
2166 return;
2167 }
2168 dst_data->stores = modref_records::create_ggc
2169 (src_data->stores->max_bases,
2170 src_data->stores->max_refs,
2171 src_data->stores->max_accesses);
2172 dst_data->stores->copy_from (src_data->stores);
2173 dst_data->loads = modref_records::create_ggc
2174 (src_data->loads->max_bases,
2175 src_data->loads->max_refs,
2176 src_data->loads->max_accesses);
2177 dst_data->loads->copy_from (src_data->loads);
2178 dst_data->writes_errno = src_data->writes_errno;
2179 if (src_data->arg_flags.length ())
2180 dst_data->arg_flags = src_data->arg_flags.copy ();
2181 }
2182
2183 /* Called when new clone is inserted to callgraph late. */
2184
2185 void
2186 modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
2187 modref_summary_lto *src_data,
2188 modref_summary_lto *dst_data)
2189 {
2190 /* Be sure that no further cloning happens after ipa-modref. If it does
2191 we will need to update signatures for possible param changes. */
2192 gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
2193 dst_data->stores = modref_records_lto::create_ggc
2194 (src_data->stores->max_bases,
2195 src_data->stores->max_refs,
2196 src_data->stores->max_accesses);
2197 dst_data->stores->copy_from (src_data->stores);
2198 dst_data->loads = modref_records_lto::create_ggc
2199 (src_data->loads->max_bases,
2200 src_data->loads->max_refs,
2201 src_data->loads->max_accesses);
2202 dst_data->loads->copy_from (src_data->loads);
2203 dst_data->writes_errno = src_data->writes_errno;
2204 if (src_data->arg_flags.length ())
2205 dst_data->arg_flags = src_data->arg_flags.copy ();
2206 }
2207
2208 namespace
2209 {
2210 /* Definition of the modref pass on GIMPLE. */
2211 const pass_data pass_data_modref = {
2212 GIMPLE_PASS,
2213 "modref",
2214 OPTGROUP_IPA,
2215 TV_TREE_MODREF,
2216 (PROP_cfg | PROP_ssa),
2217 0,
2218 0,
2219 0,
2220 0,
2221 };
2222
2223 class pass_modref : public gimple_opt_pass
2224 {
2225 public:
2226 pass_modref (gcc::context *ctxt)
2227 : gimple_opt_pass (pass_data_modref, ctxt) {}
2228
2229 /* opt_pass methods: */
2230 opt_pass *clone ()
2231 {
2232 return new pass_modref (m_ctxt);
2233 }
2234 virtual bool gate (function *)
2235 {
2236 return flag_ipa_modref;
2237 }
2238 virtual unsigned int execute (function *);
2239 };
2240
2241 /* Encode TT to the output block OB using the summary streaming API. */
2242
2243 static void
2244 write_modref_records (modref_records_lto *tt, struct output_block *ob)
2245 {
2246 streamer_write_uhwi (ob, tt->max_bases);
2247 streamer_write_uhwi (ob, tt->max_refs);
2248 streamer_write_uhwi (ob, tt->max_accesses);
2249
2250 streamer_write_uhwi (ob, tt->every_base);
2251 streamer_write_uhwi (ob, vec_safe_length (tt->bases));
2252 size_t i;
2253 modref_base_node <tree> *base_node;
2254 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, base_node)
2255 {
2256 stream_write_tree (ob, base_node->base, true);
2257
2258 streamer_write_uhwi (ob, base_node->every_ref);
2259 streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
2260
2261 size_t j;
2262 modref_ref_node <tree> *ref_node;
2263 FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
2264 {
2265 stream_write_tree (ob, ref_node->ref, true);
2266 streamer_write_uhwi (ob, ref_node->every_access);
2267 streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
2268
2269 size_t k;
2270 modref_access_node *access_node;
2271 FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
2272 {
2273 streamer_write_hwi (ob, access_node->parm_index);
2274 if (access_node->parm_index != -1)
2275 {
2276 streamer_write_uhwi (ob, access_node->parm_offset_known);
2277 if (access_node->parm_offset_known)
2278 {
2279 streamer_write_poly_int64 (ob, access_node->parm_offset);
2280 streamer_write_poly_int64 (ob, access_node->offset);
2281 streamer_write_poly_int64 (ob, access_node->size);
2282 streamer_write_poly_int64 (ob, access_node->max_size);
2283 }
2284 }
2285 }
2286 }
2287 }
2288 }
2289
2290 /* Read a modref_tree from the input block IB using the data from DATA_IN.
2291 This assumes that the tree was encoded using write_modref_tree.
2292 Either nolto_ret or lto_ret is initialized by the tree depending whether
2293 LTO streaming is expected or not. */
2294
2295 void
2296 read_modref_records (lto_input_block *ib, struct data_in *data_in,
2297 modref_records **nolto_ret,
2298 modref_records_lto **lto_ret)
2299 {
2300 size_t max_bases = streamer_read_uhwi (ib);
2301 size_t max_refs = streamer_read_uhwi (ib);
2302 size_t max_accesses = streamer_read_uhwi (ib);
2303
2304 if (lto_ret)
2305 *lto_ret = modref_records_lto::create_ggc (max_bases, max_refs,
2306 max_accesses);
2307 if (nolto_ret)
2308 *nolto_ret = modref_records::create_ggc (max_bases, max_refs,
2309 max_accesses);
2310 gcc_checking_assert (lto_ret || nolto_ret);
2311
2312 size_t every_base = streamer_read_uhwi (ib);
2313 size_t nbase = streamer_read_uhwi (ib);
2314
2315 gcc_assert (!every_base || nbase == 0);
2316 if (every_base)
2317 {
2318 if (nolto_ret)
2319 (*nolto_ret)->collapse ();
2320 if (lto_ret)
2321 (*lto_ret)->collapse ();
2322 }
2323 for (size_t i = 0; i < nbase; i++)
2324 {
2325 tree base_tree = stream_read_tree (ib, data_in);
2326 modref_base_node <alias_set_type> *nolto_base_node = NULL;
2327 modref_base_node <tree> *lto_base_node = NULL;
2328
2329 /* At stream in time we have LTO alias info. Check if we streamed in
2330 something obviously unnecessary. Do not glob types by alias sets;
2331 it is not 100% clear that ltrans types will get merged same way.
2332 Types may get refined based on ODR type conflicts. */
2333 if (base_tree && !get_alias_set (base_tree))
2334 {
2335 if (dump_file)
2336 {
2337 fprintf (dump_file, "Streamed in alias set 0 type ");
2338 print_generic_expr (dump_file, base_tree);
2339 fprintf (dump_file, "\n");
2340 }
2341 base_tree = NULL;
2342 }
2343
2344 if (nolto_ret)
2345 nolto_base_node = (*nolto_ret)->insert_base (base_tree
2346 ? get_alias_set (base_tree)
2347 : 0);
2348 if (lto_ret)
2349 lto_base_node = (*lto_ret)->insert_base (base_tree);
2350 size_t every_ref = streamer_read_uhwi (ib);
2351 size_t nref = streamer_read_uhwi (ib);
2352
2353 gcc_assert (!every_ref || nref == 0);
2354 if (every_ref)
2355 {
2356 if (nolto_base_node)
2357 nolto_base_node->collapse ();
2358 if (lto_base_node)
2359 lto_base_node->collapse ();
2360 }
2361 for (size_t j = 0; j < nref; j++)
2362 {
2363 tree ref_tree = stream_read_tree (ib, data_in);
2364
2365 if (ref_tree && !get_alias_set (ref_tree))
2366 {
2367 if (dump_file)
2368 {
2369 fprintf (dump_file, "Streamed in alias set 0 type ");
2370 print_generic_expr (dump_file, ref_tree);
2371 fprintf (dump_file, "\n");
2372 }
2373 ref_tree = NULL;
2374 }
2375
2376 modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
2377 modref_ref_node <tree> *lto_ref_node = NULL;
2378
2379 if (nolto_base_node)
2380 nolto_ref_node
2381 = nolto_base_node->insert_ref (ref_tree
2382 ? get_alias_set (ref_tree) : 0,
2383 max_refs);
2384 if (lto_base_node)
2385 lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
2386
2387 size_t every_access = streamer_read_uhwi (ib);
2388 size_t naccesses = streamer_read_uhwi (ib);
2389
2390 if (nolto_ref_node)
2391 nolto_ref_node->every_access = every_access;
2392 if (lto_ref_node)
2393 lto_ref_node->every_access = every_access;
2394
2395 for (size_t k = 0; k < naccesses; k++)
2396 {
2397 int parm_index = streamer_read_hwi (ib);
2398 bool parm_offset_known = false;
2399 poly_int64 parm_offset = 0;
2400 poly_int64 offset = 0;
2401 poly_int64 size = -1;
2402 poly_int64 max_size = -1;
2403
2404 if (parm_index != -1)
2405 {
2406 parm_offset_known = streamer_read_uhwi (ib);
2407 if (parm_offset_known)
2408 {
2409 parm_offset = streamer_read_poly_int64 (ib);
2410 offset = streamer_read_poly_int64 (ib);
2411 size = streamer_read_poly_int64 (ib);
2412 max_size = streamer_read_poly_int64 (ib);
2413 }
2414 }
2415 modref_access_node a = {offset, size, max_size, parm_offset,
2416 parm_index, parm_offset_known};
2417 if (nolto_ref_node)
2418 nolto_ref_node->insert_access (a, max_accesses);
2419 if (lto_ref_node)
2420 lto_ref_node->insert_access (a, max_accesses);
2421 }
2422 }
2423 }
2424 if (lto_ret)
2425 (*lto_ret)->cleanup ();
2426 if (nolto_ret)
2427 (*nolto_ret)->cleanup ();
2428 }
2429
2430 /* Write ESUM to BP. */
2431
2432 static void
2433 modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
2434 {
2435 if (!esum)
2436 {
2437 bp_pack_var_len_unsigned (bp, 0);
2438 return;
2439 }
2440 bp_pack_var_len_unsigned (bp, esum->esc.length ());
2441 unsigned int i;
2442 escape_entry *ee;
2443 FOR_EACH_VEC_ELT (esum->esc, i, ee)
2444 {
2445 bp_pack_var_len_unsigned (bp, ee->parm_index);
2446 bp_pack_var_len_unsigned (bp, ee->arg);
2447 bp_pack_var_len_unsigned (bp, ee->min_flags);
2448 bp_pack_value (bp, ee->direct, 1);
2449 }
2450 }
2451
2452 /* Read escape summary for E from BP. */
2453
2454 static void
2455 modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
2456 {
2457 unsigned int n = bp_unpack_var_len_unsigned (bp);
2458 if (!n)
2459 return;
2460 escape_summary *esum = escape_summaries->get_create (e);
2461 esum->esc.reserve_exact (n);
2462 for (unsigned int i = 0; i < n; i++)
2463 {
2464 escape_entry ee;
2465 ee.parm_index = bp_unpack_var_len_unsigned (bp);
2466 ee.arg = bp_unpack_var_len_unsigned (bp);
2467 ee.min_flags = bp_unpack_var_len_unsigned (bp);
2468 ee.direct = bp_unpack_value (bp, 1);
2469 esum->esc.quick_push (ee);
2470 }
2471 }
2472
2473 /* Callback for write_summary. */
2474
2475 static void
2476 modref_write ()
2477 {
2478 struct output_block *ob = create_output_block (LTO_section_ipa_modref);
2479 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
2480 unsigned int count = 0;
2481 int i;
2482
2483 if (!summaries_lto)
2484 {
2485 streamer_write_uhwi (ob, 0);
2486 streamer_write_char_stream (ob->main_stream, 0);
2487 produce_asm (ob, NULL);
2488 destroy_output_block (ob);
2489 return;
2490 }
2491
2492 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
2493 {
2494 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
2495 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
2496 modref_summary_lto *r;
2497
2498 if (cnode && cnode->definition && !cnode->alias
2499 && (r = summaries_lto->get (cnode))
2500 && r->useful_p (flags_from_decl_or_type (cnode->decl)))
2501 count++;
2502 }
2503 streamer_write_uhwi (ob, count);
2504
2505 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
2506 {
2507 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
2508 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
2509
2510 if (cnode && cnode->definition && !cnode->alias)
2511 {
2512 modref_summary_lto *r = summaries_lto->get (cnode);
2513
2514 if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
2515 continue;
2516
2517 streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
2518
2519 streamer_write_uhwi (ob, r->arg_flags.length ());
2520 for (unsigned int i = 0; i < r->arg_flags.length (); i++)
2521 streamer_write_char_stream (ob->main_stream, r->arg_flags[i]);
2522
2523 write_modref_records (r->loads, ob);
2524 write_modref_records (r->stores, ob);
2525
2526 struct bitpack_d bp = bitpack_create (ob->main_stream);
2527 bp_pack_value (&bp, r->writes_errno, 1);
2528 if (!flag_wpa)
2529 {
2530 for (cgraph_edge *e = cnode->indirect_calls;
2531 e; e = e->next_callee)
2532 {
2533 class fnspec_summary *sum = fnspec_summaries->get (e);
2534 bp_pack_value (&bp, sum != NULL, 1);
2535 if (sum)
2536 bp_pack_string (ob, &bp, sum->fnspec, true);
2537 class escape_summary *esum = escape_summaries->get (e);
2538 modref_write_escape_summary (&bp,esum);
2539 }
2540 for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
2541 {
2542 class fnspec_summary *sum = fnspec_summaries->get (e);
2543 bp_pack_value (&bp, sum != NULL, 1);
2544 if (sum)
2545 bp_pack_string (ob, &bp, sum->fnspec, true);
2546 class escape_summary *esum = escape_summaries->get (e);
2547 modref_write_escape_summary (&bp,esum);
2548 }
2549 }
2550 streamer_write_bitpack (&bp);
2551 }
2552 }
2553 streamer_write_char_stream (ob->main_stream, 0);
2554 produce_asm (ob, NULL);
2555 destroy_output_block (ob);
2556 }
2557
2558 static void
2559 read_section (struct lto_file_decl_data *file_data, const char *data,
2560 size_t len)
2561 {
2562 const struct lto_function_header *header
2563 = (const struct lto_function_header *) data;
2564 const int cfg_offset = sizeof (struct lto_function_header);
2565 const int main_offset = cfg_offset + header->cfg_size;
2566 const int string_offset = main_offset + header->main_size;
2567 struct data_in *data_in;
2568 unsigned int i;
2569 unsigned int f_count;
2570
2571 lto_input_block ib ((const char *) data + main_offset, header->main_size,
2572 file_data->mode_table);
2573
2574 data_in
2575 = lto_data_in_create (file_data, (const char *) data + string_offset,
2576 header->string_size, vNULL);
2577 f_count = streamer_read_uhwi (&ib);
2578 for (i = 0; i < f_count; i++)
2579 {
2580 struct cgraph_node *node;
2581 lto_symtab_encoder_t encoder;
2582
2583 unsigned int index = streamer_read_uhwi (&ib);
2584 encoder = file_data->symtab_node_encoder;
2585 node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
2586 index));
2587
2588 modref_summary *modref_sum = summaries
2589 ? summaries->get_create (node) : NULL;
2590 modref_summary_lto *modref_sum_lto = summaries_lto
2591 ? summaries_lto->get_create (node)
2592 : NULL;
2593 if (optimization_summaries)
2594 modref_sum = optimization_summaries->get_create (node);
2595
2596 if (modref_sum)
2597 modref_sum->writes_errno = false;
2598 if (modref_sum_lto)
2599 modref_sum_lto->writes_errno = false;
2600
2601 gcc_assert (!modref_sum || (!modref_sum->loads
2602 && !modref_sum->stores));
2603 gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
2604 && !modref_sum_lto->stores));
2605 unsigned int args = streamer_read_uhwi (&ib);
2606 if (args && modref_sum)
2607 modref_sum->arg_flags.reserve_exact (args);
2608 if (args && modref_sum_lto)
2609 modref_sum_lto->arg_flags.reserve_exact (args);
2610 for (unsigned int i = 0; i < args; i++)
2611 {
2612 unsigned char flags = streamer_read_uchar (&ib);
2613 if (modref_sum)
2614 modref_sum->arg_flags.quick_push (flags);
2615 if (modref_sum_lto)
2616 modref_sum_lto->arg_flags.quick_push (flags);
2617 }
2618 read_modref_records (&ib, data_in,
2619 modref_sum ? &modref_sum->loads : NULL,
2620 modref_sum_lto ? &modref_sum_lto->loads : NULL);
2621 read_modref_records (&ib, data_in,
2622 modref_sum ? &modref_sum->stores : NULL,
2623 modref_sum_lto ? &modref_sum_lto->stores : NULL);
2624 struct bitpack_d bp = streamer_read_bitpack (&ib);
2625 if (bp_unpack_value (&bp, 1))
2626 {
2627 if (modref_sum)
2628 modref_sum->writes_errno = true;
2629 if (modref_sum_lto)
2630 modref_sum_lto->writes_errno = true;
2631 }
2632 if (!flag_ltrans)
2633 {
2634 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
2635 {
2636 if (bp_unpack_value (&bp, 1))
2637 {
2638 class fnspec_summary *sum = fnspec_summaries->get_create (e);
2639 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
2640 }
2641 modref_read_escape_summary (&bp, e);
2642 }
2643 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
2644 {
2645 if (bp_unpack_value (&bp, 1))
2646 {
2647 class fnspec_summary *sum = fnspec_summaries->get_create (e);
2648 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
2649 }
2650 modref_read_escape_summary (&bp, e);
2651 }
2652 }
2653 if (dump_file)
2654 {
2655 fprintf (dump_file, "Read modref for %s\n",
2656 node->dump_name ());
2657 if (modref_sum)
2658 modref_sum->dump (dump_file);
2659 if (modref_sum_lto)
2660 modref_sum_lto->dump (dump_file);
2661 dump_modref_edge_summaries (dump_file, node, 4);
2662 }
2663 }
2664
2665 lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
2666 len);
2667 lto_data_in_delete (data_in);
2668 }
2669
2670 /* Callback for read_summary. */
2671
2672 static void
2673 modref_read (void)
2674 {
2675 struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
2676 struct lto_file_decl_data *file_data;
2677 unsigned int j = 0;
2678
2679 gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
2680 if (flag_ltrans)
2681 optimization_summaries = modref_summaries::create_ggc (symtab);
2682 else
2683 {
2684 if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
2685 summaries_lto = modref_summaries_lto::create_ggc (symtab);
2686 if (!flag_wpa
2687 || (flag_incremental_link == INCREMENTAL_LINK_LTO
2688 && flag_fat_lto_objects))
2689 summaries = modref_summaries::create_ggc (symtab);
2690 if (!fnspec_summaries)
2691 fnspec_summaries = new fnspec_summaries_t (symtab);
2692 if (!escape_summaries)
2693 escape_summaries = new escape_summaries_t (symtab);
2694 }
2695
2696 while ((file_data = file_data_vec[j++]))
2697 {
2698 size_t len;
2699 const char *data = lto_get_summary_section_data (file_data,
2700 LTO_section_ipa_modref,
2701 &len);
2702 if (data)
2703 read_section (file_data, data, len);
2704 else
2705 /* Fatal error here. We do not want to support compiling ltrans units
2706 with different version of compiler or different flags than the WPA
2707 unit, so this should never happen. */
2708 fatal_error (input_location,
2709 "IPA modref summary is missing in input file");
2710 }
2711 }
2712
2713 /* Recompute arg_flags for param adjustments in INFO. */
2714
2715 static void
2716 remap_arg_flags (auto_vec <unsigned char> &arg_flags, clone_info *info)
2717 {
2718 auto_vec<unsigned char> old = arg_flags.copy ();
2719 int max = -1;
2720 size_t i;
2721 ipa_adjusted_param *p;
2722
2723 arg_flags.release ();
2724
2725 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2726 {
2727 int o = info->param_adjustments->get_original_index (i);
2728 if (o >= 0 && (int)old.length () > o && old[o])
2729 max = i;
2730 }
2731 if (max >= 0)
2732 arg_flags.safe_grow_cleared (max + 1, true);
2733 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2734 {
2735 int o = info->param_adjustments->get_original_index (i);
2736 if (o >= 0 && (int)old.length () > o && old[o])
2737 arg_flags[i] = old[o];
2738 }
2739 }
2740
2741 /* If signature changed, update the summary. */
2742
2743 static void
2744 update_signature (struct cgraph_node *node)
2745 {
2746 clone_info *info = clone_info::get (node);
2747 if (!info || !info->param_adjustments)
2748 return;
2749
2750 modref_summary *r = optimization_summaries
2751 ? optimization_summaries->get (node) : NULL;
2752 modref_summary_lto *r_lto = summaries_lto
2753 ? summaries_lto->get (node) : NULL;
2754 if (!r && !r_lto)
2755 return;
2756 if (dump_file)
2757 {
2758 fprintf (dump_file, "Updating summary for %s from:\n",
2759 node->dump_name ());
2760 if (r)
2761 r->dump (dump_file);
2762 if (r_lto)
2763 r_lto->dump (dump_file);
2764 }
2765
2766 size_t i, max = 0;
2767 ipa_adjusted_param *p;
2768
2769 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2770 {
2771 int idx = info->param_adjustments->get_original_index (i);
2772 if (idx > (int)max)
2773 max = idx;
2774 }
2775
2776 auto_vec <int, 32> map;
2777
2778 map.reserve (max + 1);
2779 for (i = 0; i <= max; i++)
2780 map.quick_push (-1);
2781 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
2782 {
2783 int idx = info->param_adjustments->get_original_index (i);
2784 if (idx >= 0)
2785 map[idx] = i;
2786 }
2787 if (r)
2788 {
2789 r->loads->remap_params (&map);
2790 r->stores->remap_params (&map);
2791 if (r->arg_flags.length ())
2792 remap_arg_flags (r->arg_flags, info);
2793 }
2794 if (r_lto)
2795 {
2796 r_lto->loads->remap_params (&map);
2797 r_lto->stores->remap_params (&map);
2798 if (r_lto->arg_flags.length ())
2799 remap_arg_flags (r_lto->arg_flags, info);
2800 }
2801 if (dump_file)
2802 {
2803 fprintf (dump_file, "to:\n");
2804 if (r)
2805 r->dump (dump_file);
2806 if (r_lto)
2807 r_lto->dump (dump_file);
2808 }
2809 return;
2810 }
2811
2812 /* Definition of the modref IPA pass. */
2813 const pass_data pass_data_ipa_modref =
2814 {
2815 IPA_PASS, /* type */
2816 "modref", /* name */
2817 OPTGROUP_IPA, /* optinfo_flags */
2818 TV_IPA_MODREF, /* tv_id */
2819 0, /* properties_required */
2820 0, /* properties_provided */
2821 0, /* properties_destroyed */
2822 0, /* todo_flags_start */
2823 ( TODO_dump_symtab ), /* todo_flags_finish */
2824 };
2825
2826 class pass_ipa_modref : public ipa_opt_pass_d
2827 {
2828 public:
2829 pass_ipa_modref (gcc::context *ctxt)
2830 : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
2831 modref_generate, /* generate_summary */
2832 modref_write, /* write_summary */
2833 modref_read, /* read_summary */
2834 modref_write, /* write_optimization_summary */
2835 modref_read, /* read_optimization_summary */
2836 NULL, /* stmt_fixup */
2837 0, /* function_transform_todo_flags_start */
2838 NULL, /* function_transform */
2839 NULL) /* variable_transform */
2840 {}
2841
2842 /* opt_pass methods: */
2843 opt_pass *clone () { return new pass_ipa_modref (m_ctxt); }
2844 virtual bool gate (function *)
2845 {
2846 return true;
2847 }
2848 virtual unsigned int execute (function *);
2849
2850 };
2851
2852 }
2853
2854 unsigned int pass_modref::execute (function *f)
2855 {
2856 analyze_function (f, false);
2857 return 0;
2858 }
2859
2860 gimple_opt_pass *
2861 make_pass_modref (gcc::context *ctxt)
2862 {
2863 return new pass_modref (ctxt);
2864 }
2865
2866 ipa_opt_pass_d *
2867 make_pass_ipa_modref (gcc::context *ctxt)
2868 {
2869 return new pass_ipa_modref (ctxt);
2870 }
2871
2872 /* Skip edges from and to nodes without ipa_pure_const enabled.
2873 Ignore not available symbols. */
2874
2875 static bool
2876 ignore_edge (struct cgraph_edge *e)
2877 {
2878 /* We merge summaries of inline clones into summaries of functions they
2879 are inlined to. For that reason the complete function bodies must
2880 act as unit. */
2881 if (!e->inline_failed)
2882 return false;
2883 enum availability avail;
2884 cgraph_node *callee = e->callee->function_or_virtual_thunk_symbol
2885 (&avail, e->caller);
2886
2887 return (avail <= AVAIL_INTERPOSABLE
2888 || ((!optimization_summaries || !optimization_summaries->get (callee))
2889 && (!summaries_lto || !summaries_lto->get (callee)))
2890 || flags_from_decl_or_type (e->callee->decl)
2891 & (ECF_CONST | ECF_NOVOPS));
2892 }
2893
2894 /* Compute parm_map for CALLEE_EDGE. */
2895
2896 static bool
2897 compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
2898 {
2899 class ipa_edge_args *args;
2900 if (ipa_node_params_sum
2901 && !callee_edge->call_stmt_cannot_inline_p
2902 && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
2903 {
2904 int i, count = ipa_get_cs_argument_count (args);
2905 class ipa_node_params *caller_parms_info, *callee_pi;
2906 class ipa_call_summary *es
2907 = ipa_call_summaries->get (callee_edge);
2908 cgraph_node *callee
2909 = callee_edge->callee->function_or_virtual_thunk_symbol
2910 (NULL, callee_edge->caller);
2911
2912 caller_parms_info
2913 = ipa_node_params_sum->get (callee_edge->caller->inlined_to
2914 ? callee_edge->caller->inlined_to
2915 : callee_edge->caller);
2916 callee_pi = ipa_node_params_sum->get (callee);
2917
2918 (*parm_map).safe_grow_cleared (count, true);
2919
2920 for (i = 0; i < count; i++)
2921 {
2922 if (es && es->param[i].points_to_local_or_readonly_memory)
2923 {
2924 (*parm_map)[i].parm_index = -2;
2925 continue;
2926 }
2927
2928 struct ipa_jump_func *jf
2929 = ipa_get_ith_jump_func (args, i);
2930 if (jf && callee_pi)
2931 {
2932 tree cst = ipa_value_from_jfunc (caller_parms_info,
2933 jf,
2934 ipa_get_type
2935 (callee_pi, i));
2936 if (cst && points_to_local_or_readonly_memory_p (cst))
2937 {
2938 (*parm_map)[i].parm_index = -2;
2939 continue;
2940 }
2941 }
2942 if (jf && jf->type == IPA_JF_PASS_THROUGH)
2943 {
2944 (*parm_map)[i].parm_index
2945 = ipa_get_jf_pass_through_formal_id (jf);
2946 if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
2947 {
2948 (*parm_map)[i].parm_offset_known = true;
2949 (*parm_map)[i].parm_offset = 0;
2950 }
2951 else if (ipa_get_jf_pass_through_operation (jf)
2952 == POINTER_PLUS_EXPR
2953 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
2954 &(*parm_map)[i].parm_offset))
2955 (*parm_map)[i].parm_offset_known = true;
2956 else
2957 (*parm_map)[i].parm_offset_known = false;
2958 continue;
2959 }
2960 if (jf && jf->type == IPA_JF_ANCESTOR)
2961 {
2962 (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
2963 (*parm_map)[i].parm_offset_known = true;
2964 gcc_checking_assert
2965 (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
2966 (*parm_map)[i].parm_offset
2967 = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
2968 }
2969 else
2970 (*parm_map)[i].parm_index = -1;
2971 }
2972 if (dump_file)
2973 {
2974 fprintf (dump_file, " Parm map: ");
2975 for (i = 0; i < count; i++)
2976 fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
2977 fprintf (dump_file, "\n");
2978 }
2979 return true;
2980 }
2981 return false;
2982 }
2983
2984 /* Map used to translate escape infos. */
2985
2986 struct escape_map
2987 {
2988 int parm_index;
2989 bool direct;
2990 };
2991
2992 /* Update escape map fo E. */
2993
2994 static void
2995 update_escape_summary_1 (cgraph_edge *e,
2996 vec <vec <escape_map>> &map)
2997 {
2998 escape_summary *sum = escape_summaries->get (e);
2999 if (!sum)
3000 return;
3001 auto_vec <escape_entry> old = sum->esc.copy ();
3002 sum->esc.release ();
3003
3004 unsigned int i;
3005 escape_entry *ee;
3006 FOR_EACH_VEC_ELT (old, i, ee)
3007 {
3008 unsigned int j;
3009 struct escape_map *em;
3010 if (ee->parm_index >= map.length ())
3011 continue;
3012 FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
3013 {
3014 struct escape_entry entry = {em->parm_index, ee->arg,
3015 ee->min_flags,
3016 ee->direct & em->direct};
3017 sum->esc.safe_push (entry);
3018 }
3019 }
3020 if (!sum->esc.length ())
3021 escape_summaries->remove (e);
3022 }
3023
3024 /* Update escape map fo NODE. */
3025
3026 static void
3027 update_escape_summary (cgraph_node *node,
3028 vec <vec <escape_map>> &map)
3029 {
3030 if (!escape_summaries)
3031 return;
3032 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
3033 update_escape_summary_1 (e, map);
3034 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3035 {
3036 if (!e->inline_failed)
3037 update_escape_summary (e->callee, map);
3038 else
3039 update_escape_summary_1 (e, map);
3040 }
3041 }
3042
3043 /* Call EDGE was inlined; merge summary from callee to the caller. */
3044
3045 void
3046 ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
3047 {
3048 if (!summaries && !summaries_lto)
3049 return;
3050
3051 struct cgraph_node *to = (edge->caller->inlined_to
3052 ? edge->caller->inlined_to : edge->caller);
3053 class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
3054 class modref_summary_lto *to_info_lto = summaries_lto
3055 ? summaries_lto->get (to) : NULL;
3056
3057 if (!to_info && !to_info_lto)
3058 {
3059 if (summaries)
3060 summaries->remove (edge->callee);
3061 if (summaries_lto)
3062 summaries_lto->remove (edge->callee);
3063 remove_modref_edge_summaries (edge->callee);
3064 return;
3065 }
3066
3067 class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
3068 : NULL;
3069 class modref_summary_lto *callee_info_lto
3070 = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
3071 int flags = flags_from_decl_or_type (edge->callee->decl);
3072 bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
3073
3074 if (!callee_info && to_info)
3075 {
3076 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3077 to_info->loads->collapse ();
3078 if (!ignore_stores)
3079 to_info->stores->collapse ();
3080 }
3081 if (!callee_info_lto && to_info_lto)
3082 {
3083 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3084 to_info_lto->loads->collapse ();
3085 if (!ignore_stores)
3086 to_info_lto->stores->collapse ();
3087 }
3088 if (callee_info || callee_info_lto)
3089 {
3090 auto_vec <modref_parm_map, 32> parm_map;
3091
3092 compute_parm_map (edge, &parm_map);
3093
3094 if (!ignore_stores)
3095 {
3096 if (to_info && callee_info)
3097 to_info->stores->merge (callee_info->stores, &parm_map);
3098 if (to_info_lto && callee_info_lto)
3099 to_info_lto->stores->merge (callee_info_lto->stores, &parm_map);
3100 }
3101 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
3102 {
3103 if (to_info && callee_info)
3104 to_info->loads->merge (callee_info->loads, &parm_map);
3105 if (to_info_lto && callee_info_lto)
3106 to_info_lto->loads->merge (callee_info_lto->loads, &parm_map);
3107 }
3108 }
3109
3110 /* Now merge escape summaries.
3111 For every escape to the callee we need to merge calle flags
3112 and remap calees escapes. */
3113 class escape_summary *sum = escape_summaries->get (edge);
3114 int max_escape = -1;
3115 escape_entry *ee;
3116 unsigned int i;
3117
3118 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
3119 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3120 if ((int)ee->arg > max_escape)
3121 max_escape = ee->arg;
3122
3123 auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
3124 emap.safe_grow (max_escape + 1, true);
3125 for (i = 0; (int)i < max_escape + 1; i++)
3126 emap[i] = vNULL;
3127
3128 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
3129 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3130 {
3131 bool needed = false;
3132 if (to_info && to_info->arg_flags.length () > ee->parm_index)
3133 {
3134 int flags = callee_info
3135 && callee_info->arg_flags.length () > ee->arg
3136 ? callee_info->arg_flags[ee->arg] : 0;
3137 if (!ee->direct)
3138 flags = deref_flags (flags, ignore_stores);
3139 else if (ignore_stores)
3140 flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE;
3141 flags |= ee->min_flags;
3142 to_info->arg_flags[ee->parm_index] &= flags;
3143 if (to_info->arg_flags[ee->parm_index])
3144 needed = true;
3145 }
3146 if (to_info_lto && to_info_lto->arg_flags.length () > ee->parm_index)
3147 {
3148 int flags = callee_info_lto
3149 && callee_info_lto->arg_flags.length () > ee->arg
3150 ? callee_info_lto->arg_flags[ee->arg] : 0;
3151 if (!ee->direct)
3152 flags = deref_flags (flags, ignore_stores);
3153 else if (ignore_stores)
3154 flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE;
3155 flags |= ee->min_flags;
3156 to_info_lto->arg_flags[ee->parm_index] &= flags;
3157 if (to_info_lto->arg_flags[ee->parm_index])
3158 needed = true;
3159 }
3160 struct escape_map entry = {ee->parm_index, ee->direct};
3161 if (needed)
3162 emap[ee->arg].safe_push (entry);
3163 }
3164 update_escape_summary (edge->callee, emap);
3165 for (i = 0; (int)i < max_escape + 1; i++)
3166 emap[i].release ();
3167 if (sum)
3168 escape_summaries->remove (edge);
3169
3170 if (summaries)
3171 {
3172 if (to_info && !to_info->useful_p (flags))
3173 {
3174 if (dump_file)
3175 fprintf (dump_file, "Removed mod-ref summary for %s\n",
3176 to->dump_name ());
3177 summaries->remove (to);
3178 to_info = NULL;
3179 }
3180 else if (to_info && dump_file)
3181 {
3182 if (dump_file)
3183 fprintf (dump_file, "Updated mod-ref summary for %s\n",
3184 to->dump_name ());
3185 to_info->dump (dump_file);
3186 }
3187 if (callee_info)
3188 summaries->remove (edge->callee);
3189 }
3190 if (summaries_lto)
3191 {
3192 if (to_info_lto && !to_info_lto->useful_p (flags))
3193 {
3194 if (dump_file)
3195 fprintf (dump_file, "Removed mod-ref summary for %s\n",
3196 to->dump_name ());
3197 summaries_lto->remove (to);
3198 }
3199 else if (to_info_lto && dump_file)
3200 {
3201 if (dump_file)
3202 fprintf (dump_file, "Updated mod-ref summary for %s\n",
3203 to->dump_name ());
3204 to_info_lto->dump (dump_file);
3205 to_info_lto = NULL;
3206 }
3207 if (callee_info_lto)
3208 summaries_lto->remove (edge->callee);
3209 }
3210 if (!to_info && !to_info_lto)
3211 remove_modref_edge_summaries (to);
3212 return;
3213 }
3214
3215 /* Get parameter type from DECL. This is only safe for special cases
3216 like builtins we create fnspec for because the type match is checked
3217 at fnspec creation time. */
3218
3219 static tree
3220 get_parm_type (tree decl, unsigned int i)
3221 {
3222 tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
3223
3224 for (unsigned int p = 0; p < i; p++)
3225 t = TREE_CHAIN (t);
3226 return TREE_VALUE (t);
3227 }
3228
3229 /* Return access mode for argument I of call E with FNSPEC. */
3230
3231 static modref_access_node
3232 get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
3233 unsigned int i, modref_parm_map &map)
3234 {
3235 tree size = NULL_TREE;
3236 unsigned int size_arg;
3237
3238 if (!fnspec.arg_specified_p (i))
3239 ;
3240 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
3241 {
3242 cgraph_node *node = e->caller->inlined_to
3243 ? e->caller->inlined_to : e->caller;
3244 ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
3245 ipa_edge_args *args = ipa_edge_args_sum->get (e);
3246 struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
3247
3248 if (jf)
3249 size = ipa_value_from_jfunc (caller_parms_info, jf,
3250 get_parm_type (e->callee->decl, size_arg));
3251 }
3252 else if (fnspec.arg_access_size_given_by_type_p (i))
3253 size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
3254 modref_access_node a = {0, -1, -1,
3255 map.parm_offset, map.parm_index,
3256 map.parm_offset_known};
3257 poly_int64 size_hwi;
3258 if (size
3259 && poly_int_tree_p (size, &size_hwi)
3260 && coeffs_in_range_p (size_hwi, 0,
3261 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
3262 {
3263 a.size = -1;
3264 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
3265 }
3266 return a;
3267 }
3268
3269 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
3270 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
3271
3272 static bool
3273 propagate_unknown_call (cgraph_node *node,
3274 cgraph_edge *e, int ecf_flags,
3275 modref_summary *cur_summary,
3276 modref_summary_lto *cur_summary_lto)
3277 {
3278 bool changed = false;
3279 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
3280 auto_vec <modref_parm_map, 32> parm_map;
3281 if (fnspec_sum
3282 && compute_parm_map (e, &parm_map))
3283 {
3284 attr_fnspec fnspec (fnspec_sum->fnspec);
3285
3286 gcc_checking_assert (fnspec.known_p ());
3287 if (fnspec.global_memory_read_p ())
3288 collapse_loads (cur_summary, cur_summary_lto);
3289 else
3290 {
3291 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
3292 for (unsigned i = 0; i < parm_map.length () && t;
3293 i++, t = TREE_CHAIN (t))
3294 if (!POINTER_TYPE_P (TREE_VALUE (t)))
3295 ;
3296 else if (!fnspec.arg_specified_p (i)
3297 || fnspec.arg_maybe_read_p (i))
3298 {
3299 modref_parm_map map = parm_map[i];
3300 if (map.parm_index == -2)
3301 continue;
3302 if (map.parm_index == -1)
3303 {
3304 collapse_loads (cur_summary, cur_summary_lto);
3305 break;
3306 }
3307 if (cur_summary)
3308 changed |= cur_summary->loads->insert
3309 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
3310 if (cur_summary_lto)
3311 changed |= cur_summary_lto->loads->insert
3312 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
3313 }
3314 }
3315 if (ignore_stores_p (node->decl, ecf_flags))
3316 ;
3317 else if (fnspec.global_memory_written_p ())
3318 collapse_stores (cur_summary, cur_summary_lto);
3319 else
3320 {
3321 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
3322 for (unsigned i = 0; i < parm_map.length () && t;
3323 i++, t = TREE_CHAIN (t))
3324 if (!POINTER_TYPE_P (TREE_VALUE (t)))
3325 ;
3326 else if (!fnspec.arg_specified_p (i)
3327 || fnspec.arg_maybe_written_p (i))
3328 {
3329 modref_parm_map map = parm_map[i];
3330 if (map.parm_index == -2)
3331 continue;
3332 if (map.parm_index == -1)
3333 {
3334 collapse_stores (cur_summary, cur_summary_lto);
3335 break;
3336 }
3337 if (cur_summary)
3338 changed |= cur_summary->stores->insert
3339 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
3340 if (cur_summary_lto)
3341 changed |= cur_summary_lto->stores->insert
3342 (0, 0, get_access_for_fnspec (e, fnspec, i, map));
3343 }
3344 }
3345 if (fnspec.errno_maybe_written_p () && flag_errno_math)
3346 {
3347 if (cur_summary && !cur_summary->writes_errno)
3348 {
3349 cur_summary->writes_errno = true;
3350 changed = true;
3351 }
3352 if (cur_summary_lto && !cur_summary_lto->writes_errno)
3353 {
3354 cur_summary_lto->writes_errno = true;
3355 changed = true;
3356 }
3357 }
3358 return changed;
3359 }
3360 if (dump_file)
3361 fprintf (dump_file, " collapsing loads\n");
3362 changed |= collapse_loads (cur_summary, cur_summary_lto);
3363 if (!ignore_stores_p (node->decl, ecf_flags))
3364 {
3365 if (dump_file)
3366 fprintf (dump_file, " collapsing stores\n");
3367 changed |= collapse_stores (cur_summary, cur_summary_lto);
3368 }
3369 return changed;
3370 }
3371
3372 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
3373 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
3374
3375 static void
3376 remove_useless_summaries (cgraph_node *node,
3377 modref_summary **cur_summary_ptr,
3378 modref_summary_lto **cur_summary_lto_ptr,
3379 int ecf_flags)
3380 {
3381 if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
3382 {
3383 optimization_summaries->remove (node);
3384 *cur_summary_ptr = NULL;
3385 }
3386 if (*cur_summary_lto_ptr
3387 && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
3388 {
3389 summaries_lto->remove (node);
3390 *cur_summary_lto_ptr = NULL;
3391 }
3392 }
3393
3394 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3395 and propagate loads/stores. */
3396
3397 static void
3398 modref_propagate_in_scc (cgraph_node *component_node)
3399 {
3400 bool changed = true;
3401 int iteration = 0;
3402
3403 while (changed)
3404 {
3405 changed = false;
3406 for (struct cgraph_node *cur = component_node; cur;
3407 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3408 {
3409 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
3410 modref_summary *cur_summary = optimization_summaries
3411 ? optimization_summaries->get (node)
3412 : NULL;
3413 modref_summary_lto *cur_summary_lto = summaries_lto
3414 ? summaries_lto->get (node)
3415 : NULL;
3416
3417 if (!cur_summary && !cur_summary_lto)
3418 continue;
3419
3420 int cur_ecf_flags = flags_from_decl_or_type (node->decl);
3421
3422 if (dump_file)
3423 fprintf (dump_file, " Processing %s%s%s\n",
3424 cur->dump_name (),
3425 TREE_READONLY (cur->decl) ? " (const)" : "",
3426 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3427
3428 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
3429 {
3430 if (e->indirect_info->ecf_flags & (ECF_CONST | ECF_NOVOPS))
3431 continue;
3432 if (dump_file)
3433 fprintf (dump_file, " Indirect call"
3434 "collapsing loads\n");
3435 if (propagate_unknown_call
3436 (node, e, e->indirect_info->ecf_flags,
3437 cur_summary, cur_summary_lto))
3438 {
3439 changed = true;
3440 remove_useless_summaries (node, &cur_summary,
3441 &cur_summary_lto,
3442 cur_ecf_flags);
3443 if (!cur_summary && !cur_summary_lto)
3444 break;
3445 }
3446 }
3447
3448 if (!cur_summary && !cur_summary_lto)
3449 continue;
3450
3451 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
3452 callee_edge = callee_edge->next_callee)
3453 {
3454 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
3455 modref_summary *callee_summary = NULL;
3456 modref_summary_lto *callee_summary_lto = NULL;
3457 struct cgraph_node *callee;
3458
3459 if (flags & (ECF_CONST | ECF_NOVOPS)
3460 || !callee_edge->inline_failed)
3461 continue;
3462
3463 /* Get the callee and its summary. */
3464 enum availability avail;
3465 callee = callee_edge->callee->function_or_virtual_thunk_symbol
3466 (&avail, cur);
3467
3468 /* It is not necessary to re-process calls outside of the
3469 SCC component. */
3470 if (iteration > 0
3471 && (!callee->aux
3472 || ((struct ipa_dfs_info *)cur->aux)->scc_no
3473 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
3474 continue;
3475
3476 if (dump_file)
3477 fprintf (dump_file, " Call to %s\n",
3478 callee_edge->callee->dump_name ());
3479
3480 bool ignore_stores = ignore_stores_p (cur->decl, flags);
3481
3482 if (avail <= AVAIL_INTERPOSABLE)
3483 {
3484 if (dump_file)
3485 fprintf (dump_file, " Call target interposable"
3486 " or not available\n");
3487 changed |= propagate_unknown_call
3488 (node, callee_edge, flags,
3489 cur_summary, cur_summary_lto);
3490 if (!cur_summary && !cur_summary_lto)
3491 break;
3492 continue;
3493 }
3494
3495 /* We don't know anything about CALLEE, hence we cannot tell
3496 anything about the entire component. */
3497
3498 if (cur_summary
3499 && !(callee_summary = optimization_summaries->get (callee)))
3500 {
3501 if (dump_file)
3502 fprintf (dump_file, " No call target summary\n");
3503 changed |= propagate_unknown_call
3504 (node, callee_edge, flags,
3505 cur_summary, NULL);
3506 }
3507 if (cur_summary_lto
3508 && !(callee_summary_lto = summaries_lto->get (callee)))
3509 {
3510 if (dump_file)
3511 fprintf (dump_file, " No call target summary\n");
3512 changed |= propagate_unknown_call
3513 (node, callee_edge, flags,
3514 NULL, cur_summary_lto);
3515 }
3516
3517 /* We can not safely optimize based on summary of callee if it
3518 does not always bind to current def: it is possible that
3519 memory load was optimized out earlier which may not happen in
3520 the interposed variant. */
3521 if (!callee_edge->binds_to_current_def_p ())
3522 {
3523 changed |= collapse_loads (cur_summary, cur_summary_lto);
3524 if (dump_file)
3525 fprintf (dump_file, " May not bind local;"
3526 " collapsing loads\n");
3527 }
3528
3529
3530 auto_vec <modref_parm_map, 32> parm_map;
3531
3532 compute_parm_map (callee_edge, &parm_map);
3533
3534 /* Merge in callee's information. */
3535 if (callee_summary)
3536 {
3537 changed |= cur_summary->loads->merge
3538 (callee_summary->loads, &parm_map);
3539 if (!ignore_stores)
3540 {
3541 changed |= cur_summary->stores->merge
3542 (callee_summary->stores, &parm_map);
3543 if (!cur_summary->writes_errno
3544 && callee_summary->writes_errno)
3545 {
3546 cur_summary->writes_errno = true;
3547 changed = true;
3548 }
3549 }
3550 }
3551 if (callee_summary_lto)
3552 {
3553 changed |= cur_summary_lto->loads->merge
3554 (callee_summary_lto->loads, &parm_map);
3555 if (!ignore_stores)
3556 {
3557 changed |= cur_summary_lto->stores->merge
3558 (callee_summary_lto->stores, &parm_map);
3559 if (!cur_summary_lto->writes_errno
3560 && callee_summary_lto->writes_errno)
3561 {
3562 cur_summary_lto->writes_errno = true;
3563 changed = true;
3564 }
3565 }
3566 }
3567 if (changed)
3568 remove_useless_summaries (node, &cur_summary,
3569 &cur_summary_lto,
3570 cur_ecf_flags);
3571 if (!cur_summary && !cur_summary_lto)
3572 break;
3573 if (dump_file && changed)
3574 {
3575 if (cur_summary)
3576 cur_summary->dump (dump_file);
3577 if (cur_summary_lto)
3578 cur_summary_lto->dump (dump_file);
3579 dump_modref_edge_summaries (dump_file, node, 4);
3580 }
3581 }
3582 }
3583 iteration++;
3584 }
3585 if (dump_file)
3586 fprintf (dump_file,
3587 "Propagation finished in %i iterations\n", iteration);
3588 }
3589
3590 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
3591
3592 static void
3593 modref_propagate_dump_scc (cgraph_node *component_node)
3594 {
3595 for (struct cgraph_node *cur = component_node; cur;
3596 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3597 if (!cur->inlined_to)
3598 {
3599 modref_summary *cur_summary = optimization_summaries
3600 ? optimization_summaries->get (cur)
3601 : NULL;
3602 modref_summary_lto *cur_summary_lto = summaries_lto
3603 ? summaries_lto->get (cur)
3604 : NULL;
3605
3606 fprintf (dump_file, "Propagated modref for %s%s%s\n",
3607 cur->dump_name (),
3608 TREE_READONLY (cur->decl) ? " (const)" : "",
3609 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3610 if (optimization_summaries)
3611 {
3612 if (cur_summary)
3613 cur_summary->dump (dump_file);
3614 else
3615 fprintf (dump_file, " Not tracked\n");
3616 }
3617 if (summaries_lto)
3618 {
3619 if (cur_summary_lto)
3620 cur_summary_lto->dump (dump_file);
3621 else
3622 fprintf (dump_file, " Not tracked (lto)\n");
3623 }
3624 }
3625 }
3626
3627 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
3628 and SUMMARY_LTO to CUR_SUMMARY_LTO.
3629 Return true if something changed. */
3630
3631 static bool
3632 modref_merge_call_site_flags (escape_summary *sum,
3633 modref_summary *cur_summary,
3634 modref_summary_lto *cur_summary_lto,
3635 modref_summary *summary,
3636 modref_summary_lto *summary_lto,
3637 bool ignore_stores)
3638 {
3639 escape_entry *ee;
3640 unsigned int i;
3641 bool changed = false;
3642
3643 /* If we have no useful info to propagate. */
3644 if ((!cur_summary || !cur_summary->arg_flags.length ())
3645 && (!cur_summary_lto || !cur_summary_lto->arg_flags.length ()))
3646 return false;
3647
3648 FOR_EACH_VEC_ELT (sum->esc, i, ee)
3649 {
3650 int flags = 0;
3651 int flags_lto = 0;
3652
3653 if (summary && ee->arg < summary->arg_flags.length ())
3654 flags = summary->arg_flags[ee->arg];
3655 if (summary_lto
3656 && ee->arg < summary_lto->arg_flags.length ())
3657 flags_lto = summary_lto->arg_flags[ee->arg];
3658 if (!ee->direct)
3659 {
3660 flags = deref_flags (flags, ignore_stores);
3661 flags_lto = deref_flags (flags_lto, ignore_stores);
3662 }
3663 else if (ignore_stores)
3664 {
3665 flags |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE;
3666 flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE;
3667 }
3668 flags |= ee->min_flags;
3669 flags_lto |= ee->min_flags;
3670 if (!(flags & EAF_UNUSED)
3671 && cur_summary && ee->parm_index < cur_summary->arg_flags.length ())
3672 {
3673 int f = cur_summary->arg_flags[ee->parm_index];
3674 if ((f & flags) != f)
3675 {
3676 f = f & flags;
3677 if ((f & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
3678 f = 0;
3679 cur_summary->arg_flags[ee->parm_index] = f;
3680 changed = true;
3681 }
3682 }
3683 if (!(flags_lto & EAF_UNUSED)
3684 && cur_summary_lto
3685 && ee->parm_index < cur_summary_lto->arg_flags.length ())
3686 {
3687 int f = cur_summary_lto->arg_flags[ee->parm_index];
3688 if ((f & flags_lto) != f)
3689 {
3690 f = f & flags;
3691 if ((f & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
3692 f = 0;
3693 cur_summary_lto->arg_flags[ee->parm_index] = f;
3694 changed = true;
3695 }
3696 }
3697 }
3698 return changed;
3699 }
3700
3701 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3702 and propagate arg flags. */
3703
3704 static void
3705 modref_propagate_flags_in_scc (cgraph_node *component_node)
3706 {
3707 bool changed = true;
3708 int iteration = 0;
3709
3710 while (changed)
3711 {
3712 changed = false;
3713 for (struct cgraph_node *cur = component_node; cur;
3714 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
3715 {
3716 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
3717 modref_summary *cur_summary = optimization_summaries
3718 ? optimization_summaries->get (node)
3719 : NULL;
3720 modref_summary_lto *cur_summary_lto = summaries_lto
3721 ? summaries_lto->get (node)
3722 : NULL;
3723
3724 if (!cur_summary && !cur_summary_lto)
3725 continue;
3726
3727 if (dump_file)
3728 fprintf (dump_file, " Processing %s%s%s\n",
3729 cur->dump_name (),
3730 TREE_READONLY (cur->decl) ? " (const)" : "",
3731 DECL_PURE_P (cur->decl) ? " (pure)" : "");
3732
3733 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
3734 {
3735 escape_summary *sum = escape_summaries->get (e);
3736
3737 if (!sum || (e->indirect_info->ecf_flags
3738 & (ECF_CONST | ECF_NOVOPS)))
3739 continue;
3740
3741 changed |= modref_merge_call_site_flags
3742 (sum, cur_summary, cur_summary_lto,
3743 NULL, NULL, ignore_stores_p (node->decl,
3744 e->indirect_info->ecf_flags));
3745 }
3746
3747 if (!cur_summary && !cur_summary_lto)
3748 continue;
3749
3750 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
3751 callee_edge = callee_edge->next_callee)
3752 {
3753 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
3754 modref_summary *callee_summary = NULL;
3755 modref_summary_lto *callee_summary_lto = NULL;
3756 struct cgraph_node *callee;
3757
3758 if (flags & (ECF_CONST | ECF_NOVOPS)
3759 || !callee_edge->inline_failed)
3760 continue;
3761 /* Get the callee and its summary. */
3762 enum availability avail;
3763 callee = callee_edge->callee->function_or_virtual_thunk_symbol
3764 (&avail, cur);
3765
3766 /* It is not necessary to re-process calls outside of the
3767 SCC component. */
3768 if (iteration > 0
3769 && (!callee->aux
3770 || ((struct ipa_dfs_info *)cur->aux)->scc_no
3771 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
3772 continue;
3773
3774 escape_summary *sum = escape_summaries->get (callee_edge);
3775 if (!sum)
3776 continue;
3777
3778 if (dump_file)
3779 fprintf (dump_file, " Call to %s\n",
3780 callee_edge->callee->dump_name ());
3781
3782 if (avail <= AVAIL_INTERPOSABLE
3783 || callee_edge->call_stmt_cannot_inline_p)
3784 ;
3785 else
3786 {
3787 if (cur_summary)
3788 callee_summary = optimization_summaries->get (callee);
3789 if (cur_summary_lto)
3790 callee_summary_lto = summaries_lto->get (callee);
3791 }
3792 changed |= modref_merge_call_site_flags
3793 (sum, cur_summary, cur_summary_lto,
3794 callee_summary, callee_summary_lto,
3795 ignore_stores_p (node->decl, flags));
3796 if (dump_file && changed)
3797 {
3798 if (cur_summary)
3799 cur_summary->dump (dump_file);
3800 if (cur_summary_lto)
3801 cur_summary_lto->dump (dump_file);
3802 }
3803 }
3804 }
3805 iteration++;
3806 }
3807 if (dump_file)
3808 fprintf (dump_file,
3809 "Propagation of flags finished in %i iterations\n", iteration);
3810 }
3811
3812 /* Run the IPA pass. This will take a function's summaries and calls and
3813 construct new summaries which represent a transitive closure. So that
3814 summary of an analyzed function contains information about the loads and
3815 stores that the function or any function that it calls does. */
3816
3817 unsigned int
3818 pass_ipa_modref::execute (function *)
3819 {
3820 if (!summaries && !summaries_lto)
3821 return 0;
3822
3823 if (optimization_summaries)
3824 ggc_delete (optimization_summaries);
3825 optimization_summaries = summaries;
3826 summaries = NULL;
3827
3828 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
3829 symtab->cgraph_count);
3830 int order_pos;
3831 order_pos = ipa_reduced_postorder (order, true, ignore_edge);
3832 int i;
3833
3834 /* Iterate over all strongly connected components in post-order. */
3835 for (i = 0; i < order_pos; i++)
3836 {
3837 /* Get the component's representative. That's just any node in the
3838 component from which we can traverse the entire component. */
3839 struct cgraph_node *component_node = order[i];
3840
3841 if (dump_file)
3842 fprintf (dump_file, "\n\nStart of SCC component\n");
3843
3844 modref_propagate_in_scc (component_node);
3845 modref_propagate_flags_in_scc (component_node);
3846 if (dump_file)
3847 modref_propagate_dump_scc (component_node);
3848 }
3849 cgraph_node *node;
3850 FOR_EACH_FUNCTION (node)
3851 update_signature (node);
3852 if (summaries_lto)
3853 ((modref_summaries_lto *)summaries_lto)->propagated = true;
3854 ipa_free_postorder_info ();
3855 free (order);
3856 delete fnspec_summaries;
3857 fnspec_summaries = NULL;
3858 delete escape_summaries;
3859 escape_summaries = NULL;
3860 return 0;
3861 }
3862
3863 /* Summaries must stay alive until end of compilation. */
3864
3865 void
3866 ipa_modref_c_finalize ()
3867 {
3868 if (optimization_summaries)
3869 ggc_delete (optimization_summaries);
3870 optimization_summaries = NULL;
3871 gcc_checking_assert (!summaries
3872 || flag_incremental_link == INCREMENTAL_LINK_LTO);
3873 if (summaries_lto)
3874 ggc_delete (summaries_lto);
3875 summaries_lto = NULL;
3876 if (fnspec_summaries)
3877 delete fnspec_summaries;
3878 fnspec_summaries = NULL;
3879 if (escape_summaries)
3880 delete escape_summaries;
3881 escape_summaries = NULL;
3882 }
3883
3884 #include "gt-ipa-modref.h"