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