]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/ipa-modref.c
x86: Remove "%!" before ret
[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 #include "attribs.h"
89 #include "tree-cfg.h"
90 #include "tree-eh.h"
91
92
93 namespace {
94
95 /* We record fnspec specifiers for call edges since they depends on actual
96 gimple statements. */
97
98 class fnspec_summary
99 {
100 public:
101 char *fnspec;
102
103 fnspec_summary ()
104 : fnspec (NULL)
105 {
106 }
107
108 ~fnspec_summary ()
109 {
110 free (fnspec);
111 }
112 };
113
114 /* Summary holding fnspec string for a given call. */
115
116 class fnspec_summaries_t : public call_summary <fnspec_summary *>
117 {
118 public:
119 fnspec_summaries_t (symbol_table *symtab)
120 : call_summary <fnspec_summary *> (symtab) {}
121 /* Hook that is called by summary when an edge is duplicated. */
122 virtual void duplicate (cgraph_edge *,
123 cgraph_edge *,
124 fnspec_summary *src,
125 fnspec_summary *dst)
126 {
127 dst->fnspec = xstrdup (src->fnspec);
128 }
129 };
130
131 static fnspec_summaries_t *fnspec_summaries = NULL;
132
133 /* Escape summary holds a vector of param indexes that escape to
134 a given call. */
135 struct escape_entry
136 {
137 /* Parameter that escapes at a given call. */
138 int parm_index;
139 /* Argument it escapes to. */
140 unsigned int arg;
141 /* Minimal flags known about the argument. */
142 eaf_flags_t min_flags;
143 /* Does it escape directly or indirectly? */
144 bool direct;
145 };
146
147 /* Dump EAF flags. */
148
149 static void
150 dump_eaf_flags (FILE *out, int flags, bool newline = true)
151 {
152 if (flags & EAF_UNUSED)
153 fprintf (out, " unused");
154 if (flags & EAF_NO_DIRECT_CLOBBER)
155 fprintf (out, " no_direct_clobber");
156 if (flags & EAF_NO_INDIRECT_CLOBBER)
157 fprintf (out, " no_indirect_clobber");
158 if (flags & EAF_NO_DIRECT_ESCAPE)
159 fprintf (out, " no_direct_escape");
160 if (flags & EAF_NO_INDIRECT_ESCAPE)
161 fprintf (out, " no_indirect_escape");
162 if (flags & EAF_NOT_RETURNED_DIRECTLY)
163 fprintf (out, " not_returned_directly");
164 if (flags & EAF_NOT_RETURNED_INDIRECTLY)
165 fprintf (out, " not_returned_indirectly");
166 if (flags & EAF_NO_DIRECT_READ)
167 fprintf (out, " no_direct_read");
168 if (flags & EAF_NO_INDIRECT_READ)
169 fprintf (out, " no_indirect_read");
170 if (newline)
171 fprintf (out, "\n");
172 }
173
174 struct escape_summary
175 {
176 auto_vec <escape_entry> esc;
177 void dump (FILE *out)
178 {
179 for (unsigned int i = 0; i < esc.length (); i++)
180 {
181 fprintf (out, " parm %i arg %i %s min:",
182 esc[i].parm_index,
183 esc[i].arg,
184 esc[i].direct ? "(direct)" : "(indirect)");
185 dump_eaf_flags (out, esc[i].min_flags, false);
186 }
187 fprintf (out, "\n");
188 }
189 };
190
191 class escape_summaries_t : public call_summary <escape_summary *>
192 {
193 public:
194 escape_summaries_t (symbol_table *symtab)
195 : call_summary <escape_summary *> (symtab) {}
196 /* Hook that is called by summary when an edge is duplicated. */
197 virtual void duplicate (cgraph_edge *,
198 cgraph_edge *,
199 escape_summary *src,
200 escape_summary *dst)
201 {
202 dst->esc = src->esc.copy ();
203 }
204 };
205
206 static escape_summaries_t *escape_summaries = NULL;
207
208 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
209
210
211 /* Class (from which there is one global instance) that holds modref summaries
212 for all analyzed functions. */
213
214 class GTY((user)) modref_summaries
215 : public fast_function_summary <modref_summary *, va_gc>
216 {
217 public:
218 modref_summaries (symbol_table *symtab)
219 : fast_function_summary <modref_summary *, va_gc> (symtab) {}
220 virtual void insert (cgraph_node *, modref_summary *state);
221 virtual void duplicate (cgraph_node *src_node,
222 cgraph_node *dst_node,
223 modref_summary *src_data,
224 modref_summary *dst_data);
225 static modref_summaries *create_ggc (symbol_table *symtab)
226 {
227 return new (ggc_alloc_no_dtor<modref_summaries> ())
228 modref_summaries (symtab);
229 }
230 };
231
232 class modref_summary_lto;
233
234 /* Class (from which there is one global instance) that holds modref summaries
235 for all analyzed functions. */
236
237 class GTY((user)) modref_summaries_lto
238 : public fast_function_summary <modref_summary_lto *, va_gc>
239 {
240 public:
241 modref_summaries_lto (symbol_table *symtab)
242 : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
243 propagated (false) {}
244 virtual void insert (cgraph_node *, modref_summary_lto *state);
245 virtual void duplicate (cgraph_node *src_node,
246 cgraph_node *dst_node,
247 modref_summary_lto *src_data,
248 modref_summary_lto *dst_data);
249 static modref_summaries_lto *create_ggc (symbol_table *symtab)
250 {
251 return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
252 modref_summaries_lto (symtab);
253 }
254 bool propagated;
255 };
256
257 /* Global variable holding all modref summaries
258 (from analysis to IPA propagation time). */
259
260 static GTY(()) fast_function_summary <modref_summary *, va_gc>
261 *summaries;
262
263 /* Global variable holding all modref optimization summaries
264 (from IPA propagation time or used by local optimization pass). */
265
266 static GTY(()) fast_function_summary <modref_summary *, va_gc>
267 *optimization_summaries;
268
269 /* LTO summaries hold info from analysis to LTO streaming or from LTO
270 stream-in through propagation to LTO stream-out. */
271
272 static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
273 *summaries_lto;
274
275 /* Summary for a single function which this pass produces. */
276
277 modref_summary::modref_summary ()
278 : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
279 writes_errno (false), side_effects (false), nondeterministic (false),
280 calls_interposable (false), global_memory_read (false),
281 global_memory_written (false), try_dse (false)
282 {
283 }
284
285 modref_summary::~modref_summary ()
286 {
287 if (loads)
288 ggc_delete (loads);
289 if (stores)
290 ggc_delete (stores);
291 }
292
293 /* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
294 useful to track. If returns_void is true moreover clear
295 EAF_NOT_RETURNED. */
296 static int
297 remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
298 {
299 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
300 eaf_flags &= ~implicit_const_eaf_flags;
301 else if (ecf_flags & ECF_PURE)
302 eaf_flags &= ~implicit_pure_eaf_flags;
303 else if ((ecf_flags & ECF_NORETURN) || returns_void)
304 eaf_flags &= ~(EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY);
305 return eaf_flags;
306 }
307
308 /* Return true if FLAGS holds some useful information. */
309
310 static bool
311 eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags)
312 {
313 for (unsigned i = 0; i < flags.length (); i++)
314 if (remove_useless_eaf_flags (flags[i], ecf_flags, false))
315 return true;
316 return false;
317 }
318
319 /* Return true if summary is potentially useful for optimization.
320 If CHECK_FLAGS is false assume that arg_flags are useful. */
321
322 bool
323 modref_summary::useful_p (int ecf_flags, bool check_flags)
324 {
325 if (arg_flags.length () && !check_flags)
326 return true;
327 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
328 return true;
329 arg_flags.release ();
330 if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
331 return true;
332 if (check_flags
333 && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
334 return true;
335 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
336 return ((!side_effects || !nondeterministic)
337 && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
338 if (loads && !loads->every_base)
339 return true;
340 else
341 kills.release ();
342 if (ecf_flags & ECF_PURE)
343 return ((!side_effects || !nondeterministic)
344 && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
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<modref_access_node> GTY((skip)) kills;
360 auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
361 eaf_flags_t retslot_flags;
362 eaf_flags_t static_chain_flags;
363 unsigned writes_errno : 1;
364 unsigned side_effects : 1;
365 unsigned nondeterministic : 1;
366 unsigned calls_interposable : 1;
367
368 modref_summary_lto ();
369 ~modref_summary_lto ();
370 void dump (FILE *);
371 bool useful_p (int ecf_flags, bool check_flags = true);
372 };
373
374 /* Summary for a single function which this pass produces. */
375
376 modref_summary_lto::modref_summary_lto ()
377 : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
378 writes_errno (false), side_effects (false), nondeterministic (false),
379 calls_interposable (false)
380 {
381 }
382
383 modref_summary_lto::~modref_summary_lto ()
384 {
385 if (loads)
386 ggc_delete (loads);
387 if (stores)
388 ggc_delete (stores);
389 }
390
391
392 /* Return true if lto summary is potentially useful for optimization.
393 If CHECK_FLAGS is false assume that arg_flags are useful. */
394
395 bool
396 modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
397 {
398 if (arg_flags.length () && !check_flags)
399 return true;
400 if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
401 return true;
402 arg_flags.release ();
403 if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
404 return true;
405 if (check_flags
406 && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
407 return true;
408 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
409 return ((!side_effects || !nondeterministic)
410 && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
411 if (loads && !loads->every_base)
412 return true;
413 else
414 kills.release ();
415 if (ecf_flags & ECF_PURE)
416 return ((!side_effects || !nondeterministic)
417 && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
418 return stores && !stores->every_base;
419 }
420
421 /* Dump records TT to OUT. */
422
423 static void
424 dump_records (modref_records *tt, FILE *out)
425 {
426 fprintf (out, " Limits: %i bases, %i refs\n",
427 (int)tt->max_bases, (int)tt->max_refs);
428 if (tt->every_base)
429 {
430 fprintf (out, " Every base\n");
431 return;
432 }
433 size_t i;
434 modref_base_node <alias_set_type> *n;
435 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
436 {
437 fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
438 if (n->every_ref)
439 {
440 fprintf (out, " Every ref\n");
441 continue;
442 }
443 size_t j;
444 modref_ref_node <alias_set_type> *r;
445 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
446 {
447 fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
448 if (r->every_access)
449 {
450 fprintf (out, " Every access\n");
451 continue;
452 }
453 size_t k;
454 modref_access_node *a;
455 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
456 {
457 fprintf (out, " access:");
458 a->dump (out);
459 }
460 }
461 }
462 }
463
464 /* Dump records TT to OUT. */
465
466 static void
467 dump_lto_records (modref_records_lto *tt, FILE *out)
468 {
469 fprintf (out, " Limits: %i bases, %i refs\n",
470 (int)tt->max_bases, (int)tt->max_refs);
471 if (tt->every_base)
472 {
473 fprintf (out, " Every base\n");
474 return;
475 }
476 size_t i;
477 modref_base_node <tree> *n;
478 FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
479 {
480 fprintf (out, " Base %i:", (int)i);
481 print_generic_expr (dump_file, n->base);
482 fprintf (out, " (alias set %i)\n",
483 n->base ? get_alias_set (n->base) : 0);
484 if (n->every_ref)
485 {
486 fprintf (out, " Every ref\n");
487 continue;
488 }
489 size_t j;
490 modref_ref_node <tree> *r;
491 FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
492 {
493 fprintf (out, " Ref %i:", (int)j);
494 print_generic_expr (dump_file, r->ref);
495 fprintf (out, " (alias set %i)\n",
496 r->ref ? get_alias_set (r->ref) : 0);
497 if (r->every_access)
498 {
499 fprintf (out, " Every access\n");
500 continue;
501 }
502 size_t k;
503 modref_access_node *a;
504 FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
505 {
506 fprintf (out, " access:");
507 a->dump (out);
508 }
509 }
510 }
511 }
512
513 /* Dump all escape points of NODE to OUT. */
514
515 static void
516 dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
517 {
518 int i = 0;
519 if (!escape_summaries)
520 return;
521 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
522 {
523 class escape_summary *sum = escape_summaries->get (e);
524 if (sum)
525 {
526 fprintf (out, "%*sIndirect call %i in %s escapes:",
527 depth, "", i, node->dump_name ());
528 sum->dump (out);
529 }
530 i++;
531 }
532 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
533 {
534 if (!e->inline_failed)
535 dump_modref_edge_summaries (out, e->callee, depth + 1);
536 class escape_summary *sum = escape_summaries->get (e);
537 if (sum)
538 {
539 fprintf (out, "%*sCall %s->%s escapes:", depth, "",
540 node->dump_name (), e->callee->dump_name ());
541 sum->dump (out);
542 }
543 class fnspec_summary *fsum = fnspec_summaries->get (e);
544 if (fsum)
545 {
546 fprintf (out, "%*sCall %s->%s fnspec: %s\n", depth, "",
547 node->dump_name (), e->callee->dump_name (),
548 fsum->fnspec);
549 }
550 }
551 }
552
553 /* Remove all call edge summaries associated with NODE. */
554
555 static void
556 remove_modref_edge_summaries (cgraph_node *node)
557 {
558 if (!escape_summaries)
559 return;
560 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
561 escape_summaries->remove (e);
562 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
563 {
564 if (!e->inline_failed)
565 remove_modref_edge_summaries (e->callee);
566 escape_summaries->remove (e);
567 fnspec_summaries->remove (e);
568 }
569 }
570
571 /* Dump summary. */
572
573 void
574 modref_summary::dump (FILE *out)
575 {
576 if (loads)
577 {
578 fprintf (out, " loads:\n");
579 dump_records (loads, out);
580 }
581 if (stores)
582 {
583 fprintf (out, " stores:\n");
584 dump_records (stores, out);
585 }
586 if (kills.length ())
587 {
588 fprintf (out, " kills:\n");
589 for (auto kill : kills)
590 {
591 fprintf (out, " ");
592 kill.dump (out);
593 }
594 }
595 if (writes_errno)
596 fprintf (out, " Writes errno\n");
597 if (side_effects)
598 fprintf (out, " Side effects\n");
599 if (nondeterministic)
600 fprintf (out, " Nondeterministic\n");
601 if (calls_interposable)
602 fprintf (out, " Calls interposable\n");
603 if (global_memory_read)
604 fprintf (out, " Global memory read\n");
605 if (global_memory_written)
606 fprintf (out, " Global memory written\n");
607 if (try_dse)
608 fprintf (out, " Try dse\n");
609 if (arg_flags.length ())
610 {
611 for (unsigned int i = 0; i < arg_flags.length (); i++)
612 if (arg_flags[i])
613 {
614 fprintf (out, " parm %i flags:", i);
615 dump_eaf_flags (out, arg_flags[i]);
616 }
617 }
618 if (retslot_flags)
619 {
620 fprintf (out, " Retslot flags:");
621 dump_eaf_flags (out, retslot_flags);
622 }
623 if (static_chain_flags)
624 {
625 fprintf (out, " Static chain flags:");
626 dump_eaf_flags (out, static_chain_flags);
627 }
628 }
629
630 /* Dump summary. */
631
632 void
633 modref_summary_lto::dump (FILE *out)
634 {
635 fprintf (out, " loads:\n");
636 dump_lto_records (loads, out);
637 fprintf (out, " stores:\n");
638 dump_lto_records (stores, out);
639 if (kills.length ())
640 {
641 fprintf (out, " kills:\n");
642 for (auto kill : kills)
643 {
644 fprintf (out, " ");
645 kill.dump (out);
646 }
647 }
648 if (writes_errno)
649 fprintf (out, " Writes errno\n");
650 if (side_effects)
651 fprintf (out, " Side effects\n");
652 if (nondeterministic)
653 fprintf (out, " Nondeterministic\n");
654 if (calls_interposable)
655 fprintf (out, " Calls interposable\n");
656 if (arg_flags.length ())
657 {
658 for (unsigned int i = 0; i < arg_flags.length (); i++)
659 if (arg_flags[i])
660 {
661 fprintf (out, " parm %i flags:", i);
662 dump_eaf_flags (out, arg_flags[i]);
663 }
664 }
665 if (retslot_flags)
666 {
667 fprintf (out, " Retslot flags:");
668 dump_eaf_flags (out, retslot_flags);
669 }
670 if (static_chain_flags)
671 {
672 fprintf (out, " Static chain flags:");
673 dump_eaf_flags (out, static_chain_flags);
674 }
675 }
676
677 /* Called after summary is produced and before it is used by local analysis.
678 Can be called multiple times in case summary needs to update signature.
679 FUN is decl of function summary is attached to. */
680 void
681 modref_summary::finalize (tree fun)
682 {
683 global_memory_read = !loads || loads->global_access_p ();
684 global_memory_written = !stores || stores->global_access_p ();
685
686 /* We can do DSE if we know function has no side effects and
687 we can analyse all stores. Disable dse if there are too many
688 stores to try. */
689 if (side_effects || global_memory_written || writes_errno)
690 try_dse = false;
691 else
692 {
693 try_dse = true;
694 size_t i, j, k;
695 int num_tests = 0, max_tests
696 = opt_for_fn (fun, param_modref_max_tests);
697 modref_base_node <alias_set_type> *base_node;
698 modref_ref_node <alias_set_type> *ref_node;
699 modref_access_node *access_node;
700 FOR_EACH_VEC_SAFE_ELT (stores->bases, i, base_node)
701 {
702 if (base_node->every_ref)
703 {
704 try_dse = false;
705 break;
706 }
707 FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
708 {
709 if (base_node->every_ref)
710 {
711 try_dse = false;
712 break;
713 }
714 FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
715 if (num_tests++ > max_tests
716 || !access_node->parm_offset_known)
717 {
718 try_dse = false;
719 break;
720 }
721 if (!try_dse)
722 break;
723 }
724 if (!try_dse)
725 break;
726 }
727 }
728 }
729
730 /* Get function summary for FUNC if it exists, return NULL otherwise. */
731
732 modref_summary *
733 get_modref_function_summary (cgraph_node *func)
734 {
735 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
736 if (!optimization_summaries)
737 return NULL;
738
739 /* A single function body may be represented by multiple symbols with
740 different visibility. For example, if FUNC is an interposable alias,
741 we don't want to return anything, even if we have summary for the target
742 function. */
743 enum availability avail;
744 func = func->function_or_virtual_thunk_symbol
745 (&avail, current_function_decl ?
746 cgraph_node::get (current_function_decl) : NULL);
747 if (avail <= AVAIL_INTERPOSABLE)
748 return NULL;
749
750 modref_summary *r = optimization_summaries->get (func);
751 return r;
752 }
753
754 /* Get function summary for CALL if it exists, return NULL otherwise.
755 If non-null set interposed to indicate whether function may not
756 bind to current def. In this case sometimes loads from function
757 needs to be ignored. */
758
759 modref_summary *
760 get_modref_function_summary (gcall *call, bool *interposed)
761 {
762 tree callee = gimple_call_fndecl (call);
763 if (!callee)
764 return NULL;
765 struct cgraph_node *node = cgraph_node::get (callee);
766 if (!node)
767 return NULL;
768 modref_summary *r = get_modref_function_summary (node);
769 if (interposed && r)
770 *interposed = r->calls_interposable
771 || !node->binds_to_current_def_p ();
772 return r;
773 }
774
775
776 namespace {
777
778 /* Construct modref_access_node from REF. */
779 static modref_access_node
780 get_access (ao_ref *ref)
781 {
782 tree base;
783
784 base = ao_ref_base (ref);
785 modref_access_node a = {ref->offset, ref->size, ref->max_size,
786 0, MODREF_UNKNOWN_PARM, false, 0};
787 if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
788 {
789 tree memref = base;
790 base = TREE_OPERAND (base, 0);
791
792 if (TREE_CODE (base) == SSA_NAME
793 && SSA_NAME_IS_DEFAULT_DEF (base)
794 && TREE_CODE (SSA_NAME_VAR (base)) == PARM_DECL)
795 {
796 a.parm_index = 0;
797 if (cfun->static_chain_decl
798 && base == ssa_default_def (cfun, cfun->static_chain_decl))
799 a.parm_index = MODREF_STATIC_CHAIN_PARM;
800 else
801 for (tree t = DECL_ARGUMENTS (current_function_decl);
802 t != SSA_NAME_VAR (base); t = DECL_CHAIN (t))
803 a.parm_index++;
804 }
805 else
806 a.parm_index = MODREF_UNKNOWN_PARM;
807
808 if (a.parm_index != MODREF_UNKNOWN_PARM
809 && TREE_CODE (memref) == MEM_REF)
810 {
811 a.parm_offset_known
812 = wi::to_poly_wide (TREE_OPERAND
813 (memref, 1)).to_shwi (&a.parm_offset);
814 }
815 else
816 a.parm_offset_known = false;
817 }
818 else
819 a.parm_index = MODREF_UNKNOWN_PARM;
820 return a;
821 }
822
823 /* Record access into the modref_records data structure. */
824
825 static void
826 record_access (modref_records *tt, ao_ref *ref, modref_access_node &a)
827 {
828 alias_set_type base_set = !flag_strict_aliasing ? 0
829 : ao_ref_base_alias_set (ref);
830 alias_set_type ref_set = !flag_strict_aliasing ? 0
831 : (ao_ref_alias_set (ref));
832 if (dump_file)
833 {
834 fprintf (dump_file, " - Recording base_set=%i ref_set=%i ",
835 base_set, ref_set);
836 a.dump (dump_file);
837 }
838 tt->insert (base_set, ref_set, a, false);
839 }
840
841 /* IPA version of record_access_tree. */
842
843 static void
844 record_access_lto (modref_records_lto *tt, ao_ref *ref, modref_access_node &a)
845 {
846 /* get_alias_set sometimes use different type to compute the alias set
847 than TREE_TYPE (base). Do same adjustments. */
848 tree base_type = NULL_TREE, ref_type = NULL_TREE;
849 if (flag_strict_aliasing)
850 {
851 tree base;
852
853 base = ref->ref;
854 while (handled_component_p (base))
855 base = TREE_OPERAND (base, 0);
856
857 base_type = reference_alias_ptr_type_1 (&base);
858
859 if (!base_type)
860 base_type = TREE_TYPE (base);
861 else
862 base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
863 ? NULL_TREE : TREE_TYPE (base_type);
864
865 tree ref_expr = ref->ref;
866 ref_type = reference_alias_ptr_type_1 (&ref_expr);
867
868 if (!ref_type)
869 ref_type = TREE_TYPE (ref_expr);
870 else
871 ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
872 ? NULL_TREE : TREE_TYPE (ref_type);
873
874 /* Sanity check that we are in sync with what get_alias_set does. */
875 gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
876 || get_alias_set (base_type)
877 == ao_ref_base_alias_set (ref));
878 gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
879 || get_alias_set (ref_type)
880 == ao_ref_alias_set (ref));
881
882 /* Do not bother to record types that have no meaningful alias set.
883 Also skip variably modified types since these go to local streams. */
884 if (base_type && (!get_alias_set (base_type)
885 || variably_modified_type_p (base_type, NULL_TREE)))
886 base_type = NULL_TREE;
887 if (ref_type && (!get_alias_set (ref_type)
888 || variably_modified_type_p (ref_type, NULL_TREE)))
889 ref_type = NULL_TREE;
890 }
891 if (dump_file)
892 {
893 fprintf (dump_file, " - Recording base type:");
894 print_generic_expr (dump_file, base_type);
895 fprintf (dump_file, " (alias set %i) ref type:",
896 base_type ? get_alias_set (base_type) : 0);
897 print_generic_expr (dump_file, ref_type);
898 fprintf (dump_file, " (alias set %i) ",
899 ref_type ? get_alias_set (ref_type) : 0);
900 a.dump (dump_file);
901 }
902
903 tt->insert (base_type, ref_type, a, false);
904 }
905
906 /* Returns true if and only if we should store the access to EXPR.
907 Some accesses, e.g. loads from automatic variables, are not interesting. */
908
909 static bool
910 record_access_p (tree expr)
911 {
912 if (refs_local_or_readonly_memory_p (expr))
913 {
914 if (dump_file)
915 fprintf (dump_file, " - Read-only or local, ignoring.\n");
916 return false;
917 }
918 return true;
919 }
920
921 /* Return true if ECF flags says that nondeterminsm can be ignored. */
922
923 static bool
924 ignore_nondeterminism_p (tree caller, int flags)
925 {
926 if ((flags & (ECF_CONST | ECF_PURE))
927 && !(flags & ECF_LOOPING_CONST_OR_PURE))
928 return true;
929 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
930 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
931 return true;
932 return false;
933 }
934
935 /* Return true if ECF flags says that return value can be ignored. */
936
937 static bool
938 ignore_retval_p (tree caller, int flags)
939 {
940 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
941 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
942 return true;
943 return false;
944 }
945
946 /* Return true if ECF flags says that stores can be ignored. */
947
948 static bool
949 ignore_stores_p (tree caller, int flags)
950 {
951 if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
952 return true;
953 if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
954 || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
955 return true;
956 return false;
957 }
958
959 /* Determine parm_map for argument OP. */
960
961 modref_parm_map
962 parm_map_for_arg (tree op)
963 {
964 bool offset_known;
965 poly_int64 offset;
966 struct modref_parm_map parm_map;
967
968 parm_map.parm_offset_known = false;
969 parm_map.parm_offset = 0;
970
971 offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
972 if (TREE_CODE (op) == SSA_NAME
973 && SSA_NAME_IS_DEFAULT_DEF (op)
974 && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
975 {
976 int index = 0;
977 for (tree t = DECL_ARGUMENTS (current_function_decl);
978 t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
979 {
980 if (!t)
981 {
982 index = MODREF_UNKNOWN_PARM;
983 break;
984 }
985 index++;
986 }
987 parm_map.parm_index = index;
988 parm_map.parm_offset_known = offset_known;
989 parm_map.parm_offset = offset;
990 }
991 else if (points_to_local_or_readonly_memory_p (op))
992 parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM;
993 else
994 parm_map.parm_index = MODREF_UNKNOWN_PARM;
995 return parm_map;
996 }
997
998 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
999 int CUR_SUMMARY. Return true if something changed.
1000 If IGNORE_STORES is true, do not merge stores.
1001 If RECORD_ADJUSTMENTS is true cap number of adjustments to
1002 a given access to make dataflow finite. */
1003
1004 bool
1005 merge_call_side_effects (modref_summary *cur_summary,
1006 gimple *stmt, modref_summary *callee_summary,
1007 bool ignore_stores, cgraph_node *callee_node,
1008 bool record_adjustments, bool always_executed)
1009 {
1010 auto_vec <modref_parm_map, 32> parm_map;
1011 modref_parm_map chain_map;
1012 bool changed = false;
1013 int flags = gimple_call_flags (stmt);
1014
1015 if ((flags & (ECF_CONST | ECF_NOVOPS))
1016 && !(flags & ECF_LOOPING_CONST_OR_PURE))
1017 return changed;
1018
1019 if (!(flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE))
1020 || (flags & ECF_LOOPING_CONST_OR_PURE))
1021 {
1022 if (!cur_summary->side_effects && callee_summary->side_effects)
1023 {
1024 if (dump_file)
1025 fprintf (dump_file, " - merging side effects.\n");
1026 cur_summary->side_effects = true;
1027 changed = true;
1028 }
1029 if (!cur_summary->nondeterministic && callee_summary->nondeterministic
1030 && !ignore_nondeterminism_p (current_function_decl, flags))
1031 {
1032 if (dump_file)
1033 fprintf (dump_file, " - merging nondeterministic.\n");
1034 cur_summary->nondeterministic = true;
1035 changed = true;
1036 }
1037 }
1038
1039 if (flags & (ECF_CONST | ECF_NOVOPS))
1040 return changed;
1041
1042 if (!cur_summary->calls_interposable && callee_summary->calls_interposable)
1043 {
1044 if (dump_file)
1045 fprintf (dump_file, " - merging calls interposable.\n");
1046 cur_summary->calls_interposable = true;
1047 changed = true;
1048 }
1049
1050 /* We can not safely optimize based on summary of callee if it does
1051 not always bind to current def: it is possible that memory load
1052 was optimized out earlier which may not happen in the interposed
1053 variant. */
1054 if (!callee_node->binds_to_current_def_p ()
1055 && !cur_summary->calls_interposable)
1056 {
1057 if (dump_file)
1058 fprintf (dump_file, " - May be interposed.\n");
1059 cur_summary->calls_interposable = true;
1060 changed = true;
1061 }
1062
1063 if (dump_file)
1064 fprintf (dump_file, " - Merging side effects of %s with parm map:",
1065 callee_node->dump_name ());
1066
1067 parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true);
1068 for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
1069 {
1070 parm_map[i] = parm_map_for_arg (gimple_call_arg (stmt, i));
1071 if (dump_file)
1072 {
1073 fprintf (dump_file, " %i", parm_map[i].parm_index);
1074 if (parm_map[i].parm_offset_known)
1075 {
1076 fprintf (dump_file, " offset:");
1077 print_dec ((poly_int64_pod)parm_map[i].parm_offset,
1078 dump_file, SIGNED);
1079 }
1080 }
1081 }
1082 if (gimple_call_chain (stmt))
1083 {
1084 chain_map = parm_map_for_arg (gimple_call_chain (stmt));
1085 if (dump_file)
1086 {
1087 fprintf (dump_file, "static chain %i", chain_map.parm_index);
1088 if (chain_map.parm_offset_known)
1089 {
1090 fprintf (dump_file, " offset:");
1091 print_dec ((poly_int64_pod)chain_map.parm_offset,
1092 dump_file, SIGNED);
1093 }
1094 }
1095 }
1096 if (dump_file)
1097 fprintf (dump_file, "\n");
1098
1099 if (always_executed
1100 && callee_summary->kills.length ()
1101 && (!cfun->can_throw_non_call_exceptions
1102 || !stmt_could_throw_p (cfun, stmt)))
1103 {
1104 /* Watch for self recursive updates. */
1105 auto_vec<modref_access_node, 32> saved_kills;
1106
1107 saved_kills.reserve_exact (callee_summary->kills.length ());
1108 saved_kills.splice (callee_summary->kills);
1109 for (auto kill : saved_kills)
1110 {
1111 if (kill.parm_index >= (int)parm_map.length ())
1112 continue;
1113 modref_parm_map &m
1114 = kill.parm_index == MODREF_STATIC_CHAIN_PARM
1115 ? chain_map
1116 : parm_map[kill.parm_index];
1117 if (m.parm_index == MODREF_LOCAL_MEMORY_PARM
1118 || m.parm_index == MODREF_UNKNOWN_PARM
1119 || m.parm_index == MODREF_RETSLOT_PARM
1120 || !m.parm_offset_known)
1121 continue;
1122 modref_access_node n = kill;
1123 n.parm_index = m.parm_index;
1124 n.parm_offset += m.parm_offset;
1125 if (modref_access_node::insert_kill (cur_summary->kills, n,
1126 record_adjustments))
1127 changed = true;
1128 }
1129 }
1130
1131 /* Merge with callee's summary. */
1132 changed |= cur_summary->loads->merge (callee_summary->loads, &parm_map,
1133 &chain_map, record_adjustments);
1134 if (!ignore_stores)
1135 {
1136 changed |= cur_summary->stores->merge (callee_summary->stores,
1137 &parm_map, &chain_map,
1138 record_adjustments);
1139 if (!cur_summary->writes_errno
1140 && callee_summary->writes_errno)
1141 {
1142 cur_summary->writes_errno = true;
1143 changed = true;
1144 }
1145 }
1146 return changed;
1147 }
1148
1149 /* Return access mode for argument I of call STMT with FNSPEC. */
1150
1151 static modref_access_node
1152 get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
1153 unsigned int i, modref_parm_map &map)
1154 {
1155 tree size = NULL_TREE;
1156 unsigned int size_arg;
1157
1158 if (!fnspec.arg_specified_p (i))
1159 ;
1160 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
1161 size = gimple_call_arg (call, size_arg);
1162 else if (fnspec.arg_access_size_given_by_type_p (i))
1163 {
1164 tree callee = gimple_call_fndecl (call);
1165 tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
1166
1167 for (unsigned int p = 0; p < i; p++)
1168 t = TREE_CHAIN (t);
1169 size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
1170 }
1171 modref_access_node a = {0, -1, -1,
1172 map.parm_offset, map.parm_index,
1173 map.parm_offset_known, 0};
1174 poly_int64 size_hwi;
1175 if (size
1176 && poly_int_tree_p (size, &size_hwi)
1177 && coeffs_in_range_p (size_hwi, 0,
1178 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
1179 {
1180 a.size = -1;
1181 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
1182 }
1183 return a;
1184 }
1185
1186 /* Collapse loads and return true if something changed. */
1187
1188 static bool
1189 collapse_loads (modref_summary *cur_summary,
1190 modref_summary_lto *cur_summary_lto)
1191 {
1192 bool changed = false;
1193
1194 if (cur_summary && !cur_summary->loads->every_base)
1195 {
1196 cur_summary->loads->collapse ();
1197 changed = true;
1198 }
1199 if (cur_summary_lto
1200 && !cur_summary_lto->loads->every_base)
1201 {
1202 cur_summary_lto->loads->collapse ();
1203 changed = true;
1204 }
1205 return changed;
1206 }
1207
1208 /* Collapse loads and return true if something changed. */
1209
1210 static bool
1211 collapse_stores (modref_summary *cur_summary,
1212 modref_summary_lto *cur_summary_lto)
1213 {
1214 bool changed = false;
1215
1216 if (cur_summary && !cur_summary->stores->every_base)
1217 {
1218 cur_summary->stores->collapse ();
1219 changed = true;
1220 }
1221 if (cur_summary_lto
1222 && !cur_summary_lto->stores->every_base)
1223 {
1224 cur_summary_lto->stores->collapse ();
1225 changed = true;
1226 }
1227 return changed;
1228 }
1229
1230
1231 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1232 If IGNORE_STORES is true ignore them.
1233 Return false if no useful summary can be produced. */
1234
1235 static bool
1236 process_fnspec (modref_summary *cur_summary,
1237 modref_summary_lto *cur_summary_lto,
1238 gcall *call, bool ignore_stores)
1239 {
1240 attr_fnspec fnspec = gimple_call_fnspec (call);
1241 int flags = gimple_call_flags (call);
1242
1243 if (!(flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE))
1244 || (flags & ECF_LOOPING_CONST_OR_PURE)
1245 || (cfun->can_throw_non_call_exceptions
1246 && stmt_could_throw_p (cfun, call)))
1247 {
1248 if (cur_summary)
1249 {
1250 cur_summary->side_effects = true;
1251 if (!ignore_nondeterminism_p (current_function_decl, flags))
1252 cur_summary->nondeterministic = true;
1253 }
1254 if (cur_summary_lto)
1255 {
1256 cur_summary_lto->side_effects = true;
1257 if (!ignore_nondeterminism_p (current_function_decl, flags))
1258 cur_summary_lto->nondeterministic = true;
1259 }
1260 }
1261 if (flags & (ECF_CONST | ECF_NOVOPS))
1262 return true;
1263 if (!fnspec.known_p ())
1264 {
1265 if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
1266 fprintf (dump_file, " Builtin with no fnspec: %s\n",
1267 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
1268 if (ignore_stores)
1269 {
1270 collapse_loads (cur_summary, cur_summary_lto);
1271 return true;
1272 }
1273 return false;
1274 }
1275 if (fnspec.global_memory_read_p ())
1276 collapse_loads (cur_summary, cur_summary_lto);
1277 else
1278 {
1279 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1280 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1281 ;
1282 else if (!fnspec.arg_specified_p (i)
1283 || fnspec.arg_maybe_read_p (i))
1284 {
1285 modref_parm_map map = parm_map_for_arg
1286 (gimple_call_arg (call, i));
1287
1288 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
1289 continue;
1290 if (map.parm_index == MODREF_UNKNOWN_PARM)
1291 {
1292 collapse_loads (cur_summary, cur_summary_lto);
1293 break;
1294 }
1295 if (cur_summary)
1296 cur_summary->loads->insert (0, 0,
1297 get_access_for_fnspec (call,
1298 fnspec, i,
1299 map),
1300 false);
1301 if (cur_summary_lto)
1302 cur_summary_lto->loads->insert (0, 0,
1303 get_access_for_fnspec (call,
1304 fnspec, i,
1305 map),
1306 false);
1307 }
1308 }
1309 if (ignore_stores)
1310 return true;
1311 if (fnspec.global_memory_written_p ())
1312 collapse_stores (cur_summary, cur_summary_lto);
1313 else
1314 {
1315 for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1316 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1317 ;
1318 else if (!fnspec.arg_specified_p (i)
1319 || fnspec.arg_maybe_written_p (i))
1320 {
1321 modref_parm_map map = parm_map_for_arg
1322 (gimple_call_arg (call, i));
1323
1324 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
1325 continue;
1326 if (map.parm_index == MODREF_UNKNOWN_PARM)
1327 {
1328 collapse_stores (cur_summary, cur_summary_lto);
1329 break;
1330 }
1331 if (cur_summary)
1332 cur_summary->stores->insert (0, 0,
1333 get_access_for_fnspec (call,
1334 fnspec, i,
1335 map),
1336 false);
1337 if (cur_summary_lto)
1338 cur_summary_lto->stores->insert (0, 0,
1339 get_access_for_fnspec (call,
1340 fnspec, i,
1341 map),
1342 false);
1343 }
1344 if (fnspec.errno_maybe_written_p () && flag_errno_math)
1345 {
1346 if (cur_summary)
1347 cur_summary->writes_errno = true;
1348 if (cur_summary_lto)
1349 cur_summary_lto->writes_errno = true;
1350 }
1351 }
1352 return true;
1353 }
1354
1355 /* Analyze function call STMT in function F.
1356 Remember recursive calls in RECURSIVE_CALLS. */
1357
1358 static bool
1359 analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto,
1360 gcall *stmt, vec <gimple *> *recursive_calls,
1361 bool always_executed)
1362 {
1363 /* Check flags on the function call. In certain cases, analysis can be
1364 simplified. */
1365 int flags = gimple_call_flags (stmt);
1366 if ((flags & (ECF_CONST | ECF_NOVOPS))
1367 && !(flags & ECF_LOOPING_CONST_OR_PURE))
1368 {
1369 if (dump_file)
1370 fprintf (dump_file,
1371 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1372 "except for args.\n");
1373 return true;
1374 }
1375
1376 /* Pure functions do not affect global memory. Stores by functions which are
1377 noreturn and do not throw can safely be ignored. */
1378 bool ignore_stores = ignore_stores_p (current_function_decl, flags);
1379
1380 /* Next, we try to get the callee's function declaration. The goal is to
1381 merge their summary with ours. */
1382 tree callee = gimple_call_fndecl (stmt);
1383
1384 /* Check if this is an indirect call. */
1385 if (!callee)
1386 {
1387 if (dump_file)
1388 fprintf (dump_file, gimple_call_internal_p (stmt)
1389 ? " - Internal call" : " - Indirect call.\n");
1390 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1391 }
1392 /* We only need to handle internal calls in IPA mode. */
1393 gcc_checking_assert (!cur_summary_lto);
1394
1395 struct cgraph_node *callee_node = cgraph_node::get_create (callee);
1396
1397 /* If this is a recursive call, the target summary is the same as ours, so
1398 there's nothing to do. */
1399 if (recursive_call_p (current_function_decl, callee))
1400 {
1401 recursive_calls->safe_push (stmt);
1402 if (cur_summary)
1403 cur_summary->side_effects = true;
1404 if (cur_summary_lto)
1405 cur_summary_lto->side_effects = true;
1406 if (dump_file)
1407 fprintf (dump_file, " - Skipping recursive call.\n");
1408 return true;
1409 }
1410
1411 gcc_assert (callee_node != NULL);
1412
1413 /* Get the function symbol and its availability. */
1414 enum availability avail;
1415 callee_node = callee_node->function_symbol (&avail);
1416 bool looping;
1417 if (builtin_safe_for_const_function_p (&looping, callee))
1418 {
1419 if (looping)
1420 {
1421 if (cur_summary)
1422 cur_summary->side_effects = true;
1423 if (cur_summary_lto)
1424 cur_summary_lto->side_effects = true;
1425 }
1426 if (dump_file)
1427 fprintf (dump_file, " - Bulitin is safe for const.\n");
1428 return true;
1429 }
1430 if (avail <= AVAIL_INTERPOSABLE)
1431 {
1432 if (dump_file)
1433 fprintf (dump_file, " - Function availability <= AVAIL_INTERPOSABLE.\n");
1434 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1435 }
1436
1437 /* Get callee's modref summary. As above, if there's no summary, we either
1438 have to give up or, if stores are ignored, we can just purge loads. */
1439 modref_summary *callee_summary = optimization_summaries->get (callee_node);
1440 if (!callee_summary)
1441 {
1442 if (dump_file)
1443 fprintf (dump_file, " - No modref summary available for callee.\n");
1444 return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores);
1445 }
1446
1447 merge_call_side_effects (cur_summary, stmt, callee_summary, ignore_stores,
1448 callee_node, false, always_executed);
1449
1450 return true;
1451 }
1452
1453 /* Support analysis in non-lto and lto mode in parallel. */
1454
1455 struct summary_ptrs
1456 {
1457 struct modref_summary *nolto;
1458 struct modref_summary_lto *lto;
1459 bool always_executed;
1460 };
1461
1462 /* Helper for analyze_stmt. */
1463
1464 static bool
1465 analyze_load (gimple *, tree, tree op, void *data)
1466 {
1467 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1468 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1469
1470 if (dump_file)
1471 {
1472 fprintf (dump_file, " - Analyzing load: ");
1473 print_generic_expr (dump_file, op);
1474 fprintf (dump_file, "\n");
1475 }
1476
1477 if (TREE_THIS_VOLATILE (op)
1478 || (cfun->can_throw_non_call_exceptions
1479 && tree_could_throw_p (op)))
1480 {
1481 if (dump_file)
1482 fprintf (dump_file, " (volatile or can throw; marking side effects) ");
1483 if (summary)
1484 summary->side_effects = summary->nondeterministic = true;
1485 if (summary_lto)
1486 summary_lto->side_effects = summary_lto->nondeterministic = true;
1487 }
1488
1489 if (!record_access_p (op))
1490 return false;
1491
1492 ao_ref r;
1493 ao_ref_init (&r, op);
1494 modref_access_node a = get_access (&r);
1495
1496 if (summary)
1497 record_access (summary->loads, &r, a);
1498 if (summary_lto)
1499 record_access_lto (summary_lto->loads, &r, a);
1500 return false;
1501 }
1502
1503 /* Helper for analyze_stmt. */
1504
1505 static bool
1506 analyze_store (gimple *stmt, tree, tree op, void *data)
1507 {
1508 modref_summary *summary = ((summary_ptrs *)data)->nolto;
1509 modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto;
1510
1511 if (dump_file)
1512 {
1513 fprintf (dump_file, " - Analyzing store: ");
1514 print_generic_expr (dump_file, op);
1515 fprintf (dump_file, "\n");
1516 }
1517
1518 if (TREE_THIS_VOLATILE (op)
1519 || (cfun->can_throw_non_call_exceptions
1520 && tree_could_throw_p (op)))
1521 {
1522 if (dump_file)
1523 fprintf (dump_file, " (volatile or can throw; marking side effects) ");
1524 if (summary)
1525 summary->side_effects = summary->nondeterministic = true;
1526 if (summary_lto)
1527 summary_lto->side_effects = summary_lto->nondeterministic = true;
1528 }
1529
1530 if (!record_access_p (op))
1531 return false;
1532
1533 ao_ref r;
1534 ao_ref_init (&r, op);
1535 modref_access_node a = get_access (&r);
1536
1537 if (summary)
1538 record_access (summary->stores, &r, a);
1539 if (summary_lto)
1540 record_access_lto (summary_lto->stores, &r, a);
1541 if (((summary_ptrs *)data)->always_executed
1542 && a.useful_for_kill_p ()
1543 && (!cfun->can_throw_non_call_exceptions
1544 || !stmt_could_throw_p (cfun, stmt)))
1545 {
1546 if (dump_file)
1547 fprintf (dump_file, " - Recording kill\n");
1548 if (summary)
1549 modref_access_node::insert_kill (summary->kills, a, false);
1550 if (summary_lto)
1551 modref_access_node::insert_kill (summary_lto->kills, a, false);
1552 }
1553 return false;
1554 }
1555
1556 /* Analyze statement STMT of function F.
1557 If IPA is true do not merge in side effects of calls. */
1558
1559 static bool
1560 analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
1561 gimple *stmt, bool ipa, vec <gimple *> *recursive_calls,
1562 bool always_executed)
1563 {
1564 /* In general we can not ignore clobbers because they are barriers for code
1565 motion, however after inlining it is safe to do because local optimization
1566 passes do not consider clobbers from other functions.
1567 Similar logic is in ipa-pure-const.c. */
1568 if ((ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1569 {
1570 if (always_executed && record_access_p (gimple_assign_lhs (stmt)))
1571 {
1572 ao_ref r;
1573 ao_ref_init (&r, gimple_assign_lhs (stmt));
1574 modref_access_node a = get_access (&r);
1575 if (a.useful_for_kill_p ())
1576 {
1577 if (dump_file)
1578 fprintf (dump_file, " - Recording kill\n");
1579 if (summary)
1580 modref_access_node::insert_kill (summary->kills, a, false);
1581 if (summary_lto)
1582 modref_access_node::insert_kill (summary_lto->kills, a, false);
1583 }
1584 }
1585 return true;
1586 }
1587
1588 struct summary_ptrs sums = {summary, summary_lto, always_executed};
1589
1590 /* Analyze all loads and stores in STMT. */
1591 walk_stmt_load_store_ops (stmt, &sums,
1592 analyze_load, analyze_store);
1593
1594 switch (gimple_code (stmt))
1595 {
1596 case GIMPLE_ASM:
1597 if (gimple_asm_volatile_p (as_a <gasm *> (stmt)))
1598 {
1599 if (summary)
1600 summary->side_effects = summary->nondeterministic = true;
1601 if (summary_lto)
1602 summary_lto->side_effects = summary_lto->nondeterministic = true;
1603 }
1604 if (cfun->can_throw_non_call_exceptions
1605 && stmt_could_throw_p (cfun, stmt))
1606 {
1607 if (summary)
1608 summary->side_effects = true;
1609 if (summary_lto)
1610 summary_lto->side_effects = true;
1611 }
1612 /* If the ASM statement does not read nor write memory, there's nothing
1613 to do. Otherwise just give up. */
1614 if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1615 return true;
1616 if (dump_file)
1617 fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1618 "which clobbers memory.\n");
1619 return false;
1620 case GIMPLE_CALL:
1621 if (!ipa || gimple_call_internal_p (stmt))
1622 return analyze_call (summary, summary_lto,
1623 as_a <gcall *> (stmt), recursive_calls,
1624 always_executed);
1625 else
1626 {
1627 attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1628
1629 if (fnspec.known_p ()
1630 && (!fnspec.global_memory_read_p ()
1631 || !fnspec.global_memory_written_p ()))
1632 {
1633 cgraph_edge *e = cgraph_node::get (current_function_decl)->get_edge (stmt);
1634 if (e->callee)
1635 {
1636 fnspec_summaries->get_create (e)->fnspec = xstrdup (fnspec.get_str ());
1637 if (dump_file)
1638 fprintf (dump_file, " Recorded fnspec %s\n", fnspec.get_str ());
1639 }
1640 }
1641 }
1642 return true;
1643 default:
1644 if (cfun->can_throw_non_call_exceptions
1645 && stmt_could_throw_p (cfun, stmt))
1646 {
1647 if (summary)
1648 summary->side_effects = true;
1649 if (summary_lto)
1650 summary_lto->side_effects = true;
1651 }
1652 return true;
1653 }
1654 }
1655
1656 /* Remove summary of current function because during the function body
1657 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1658 mode of scan. */
1659
1660 static void
1661 remove_summary (bool lto, bool nolto, bool ipa)
1662 {
1663 cgraph_node *fnode = cgraph_node::get (current_function_decl);
1664 if (!ipa)
1665 optimization_summaries->remove (fnode);
1666 else
1667 {
1668 if (nolto)
1669 summaries->remove (fnode);
1670 if (lto)
1671 summaries_lto->remove (fnode);
1672 remove_modref_edge_summaries (fnode);
1673 }
1674 if (dump_file)
1675 fprintf (dump_file,
1676 " - modref done with result: not tracked.\n");
1677 }
1678
1679 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1680
1681 bool
1682 memory_access_to (tree op, tree ssa_name)
1683 {
1684 tree base = get_base_address (op);
1685 if (!base)
1686 return false;
1687 if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1688 return false;
1689 return TREE_OPERAND (base, 0) == ssa_name;
1690 }
1691
1692 /* Consider statement val = *arg.
1693 return EAF flags of ARG that can be determined from EAF flags of VAL
1694 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1695 all stores to VAL, i.e. when handling noreturn function. */
1696
1697 static int
1698 deref_flags (int flags, bool ignore_stores)
1699 {
1700 /* Dereference is also a direct read but dereferenced value does not
1701 yield any other direct use. */
1702 int ret = EAF_NO_DIRECT_CLOBBER | EAF_NO_DIRECT_ESCAPE
1703 | EAF_NOT_RETURNED_DIRECTLY;
1704 /* If argument is unused just account for
1705 the read involved in dereference. */
1706 if (flags & EAF_UNUSED)
1707 ret |= EAF_NO_INDIRECT_READ | EAF_NO_INDIRECT_CLOBBER
1708 | EAF_NO_INDIRECT_ESCAPE;
1709 else
1710 {
1711 /* Direct or indirect accesses leads to indirect accesses. */
1712 if (((flags & EAF_NO_DIRECT_CLOBBER)
1713 && (flags & EAF_NO_INDIRECT_CLOBBER))
1714 || ignore_stores)
1715 ret |= EAF_NO_INDIRECT_CLOBBER;
1716 if (((flags & EAF_NO_DIRECT_ESCAPE)
1717 && (flags & EAF_NO_INDIRECT_ESCAPE))
1718 || ignore_stores)
1719 ret |= EAF_NO_INDIRECT_ESCAPE;
1720 if ((flags & EAF_NO_DIRECT_READ)
1721 && (flags & EAF_NO_INDIRECT_READ))
1722 ret |= EAF_NO_INDIRECT_READ;
1723 if ((flags & EAF_NOT_RETURNED_DIRECTLY)
1724 && (flags & EAF_NOT_RETURNED_INDIRECTLY))
1725 ret |= EAF_NOT_RETURNED_INDIRECTLY;
1726 }
1727 return ret;
1728 }
1729
1730
1731 /* Description of an escape point. */
1732
1733 struct escape_point
1734 {
1735 /* Value escapes to this call. */
1736 gcall *call;
1737 /* Argument it escapes to. */
1738 int arg;
1739 /* Flags already known about the argument (this can save us from recording
1740 esape points if local analysis did good job already). */
1741 eaf_flags_t min_flags;
1742 /* Does value escape directly or indiretly? */
1743 bool direct;
1744 };
1745
1746 class modref_lattice
1747 {
1748 public:
1749 /* EAF flags of the SSA name. */
1750 eaf_flags_t flags;
1751 /* Used during DFS walk to mark names where final value was determined
1752 without need for dataflow. */
1753 bool known;
1754 /* Used during DFS walk to mark open vertices (for cycle detection). */
1755 bool open;
1756 /* Set during DFS walk for names that needs dataflow propagation. */
1757 bool do_dataflow;
1758 /* Used during the iterative dataflow. */
1759 bool changed;
1760
1761 /* When doing IPA analysis we can not merge in callee escape points;
1762 Only remember them and do the merging at IPA propagation time. */
1763 vec <escape_point, va_heap, vl_ptr> escape_points;
1764
1765 /* Representation of a graph for dataaflow. This graph is built on-demand
1766 using modref_eaf_analysis::analyze_ssa and later solved by
1767 modref_eaf_analysis::propagate.
1768 Each edge represents the fact that flags of current lattice should be
1769 propagated to lattice of SSA_NAME. */
1770 struct propagate_edge
1771 {
1772 int ssa_name;
1773 bool deref;
1774 };
1775 vec <propagate_edge, va_heap, vl_ptr> propagate_to;
1776
1777 void init ();
1778 void release ();
1779 bool merge (const modref_lattice &with);
1780 bool merge (int flags);
1781 bool merge_deref (const modref_lattice &with, bool ignore_stores);
1782 bool merge_direct_load ();
1783 bool merge_direct_store ();
1784 bool add_escape_point (gcall *call, int arg, int min_flags, bool diret);
1785 void dump (FILE *out, int indent = 0) const;
1786 };
1787
1788 /* Lattices are saved to vectors, so keep them PODs. */
1789 void
1790 modref_lattice::init ()
1791 {
1792 /* All flags we track. */
1793 int f = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
1794 | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE
1795 | EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ
1796 | EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY
1797 | EAF_UNUSED;
1798 flags = f;
1799 /* Check that eaf_flags_t is wide enough to hold all flags. */
1800 gcc_checking_assert (f == flags);
1801 open = true;
1802 known = false;
1803 }
1804
1805 /* Release memory. */
1806 void
1807 modref_lattice::release ()
1808 {
1809 escape_points.release ();
1810 propagate_to.release ();
1811 }
1812
1813 /* Dump lattice to OUT; indent with INDENT spaces. */
1814
1815 void
1816 modref_lattice::dump (FILE *out, int indent) const
1817 {
1818 dump_eaf_flags (out, flags);
1819 if (escape_points.length ())
1820 {
1821 fprintf (out, "%*sEscapes:\n", indent, "");
1822 for (unsigned int i = 0; i < escape_points.length (); i++)
1823 {
1824 fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
1825 escape_points[i].arg,
1826 escape_points[i].direct ? "direct" : "indirect");
1827 dump_eaf_flags (out, escape_points[i].min_flags, false);
1828 fprintf (out, " in call ");
1829 print_gimple_stmt (out, escape_points[i].call, 0);
1830 }
1831 }
1832 }
1833
1834 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1835 point exists. */
1836
1837 bool
1838 modref_lattice::add_escape_point (gcall *call, int arg, int min_flags,
1839 bool direct)
1840 {
1841 escape_point *ep;
1842 unsigned int i;
1843
1844 /* If we already determined flags to be bad enough,
1845 we do not need to record. */
1846 if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
1847 return false;
1848
1849 FOR_EACH_VEC_ELT (escape_points, i, ep)
1850 if (ep->call == call && ep->arg == arg && ep->direct == direct)
1851 {
1852 if ((ep->min_flags & min_flags) == min_flags)
1853 return false;
1854 ep->min_flags &= min_flags;
1855 return true;
1856 }
1857 /* Give up if max escape points is met. */
1858 if ((int)escape_points.length () > param_modref_max_escape_points)
1859 {
1860 if (dump_file)
1861 fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
1862 merge (0);
1863 return true;
1864 }
1865 escape_point new_ep = {call, arg, min_flags, direct};
1866 escape_points.safe_push (new_ep);
1867 return true;
1868 }
1869
1870 /* Merge in flags from F. */
1871 bool
1872 modref_lattice::merge (int f)
1873 {
1874 if (f & EAF_UNUSED)
1875 return false;
1876 /* Check that flags seems sane: if function does not read the parameter
1877 it can not access it indirectly. */
1878 gcc_checking_assert (!(f & EAF_NO_DIRECT_READ)
1879 || ((f & EAF_NO_INDIRECT_READ)
1880 && (f & EAF_NO_INDIRECT_CLOBBER)
1881 && (f & EAF_NO_INDIRECT_ESCAPE)
1882 && (f & EAF_NOT_RETURNED_INDIRECTLY)));
1883 if ((flags & f) != flags)
1884 {
1885 flags &= f;
1886 /* Prune obvoiusly useless flags;
1887 We do not have ECF_FLAGS handy which is not big problem since
1888 we will do final flags cleanup before producing summary.
1889 Merging should be fast so it can work well with dataflow. */
1890 flags = remove_useless_eaf_flags (flags, 0, false);
1891 if (!flags)
1892 escape_points.release ();
1893 return true;
1894 }
1895 return false;
1896 }
1897
1898 /* Merge in WITH. Return true if anyting changed. */
1899
1900 bool
1901 modref_lattice::merge (const modref_lattice &with)
1902 {
1903 if (!with.known)
1904 do_dataflow = true;
1905
1906 bool changed = merge (with.flags);
1907
1908 if (!flags)
1909 return changed;
1910 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1911 changed |= add_escape_point (with.escape_points[i].call,
1912 with.escape_points[i].arg,
1913 with.escape_points[i].min_flags,
1914 with.escape_points[i].direct);
1915 return changed;
1916 }
1917
1918 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1919 stores. Return true if anyting changed. */
1920
1921 bool
1922 modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
1923 {
1924 if (!with.known)
1925 do_dataflow = true;
1926
1927 bool changed = merge (deref_flags (with.flags, ignore_stores));
1928
1929 if (!flags)
1930 return changed;
1931 for (unsigned int i = 0; i < with.escape_points.length (); i++)
1932 {
1933 int min_flags = with.escape_points[i].min_flags;
1934
1935 if (with.escape_points[i].direct)
1936 min_flags = deref_flags (min_flags, ignore_stores);
1937 else if (ignore_stores)
1938 min_flags |= ignore_stores_eaf_flags;
1939 changed |= add_escape_point (with.escape_points[i].call,
1940 with.escape_points[i].arg,
1941 min_flags,
1942 false);
1943 }
1944 return changed;
1945 }
1946
1947 /* Merge in flags for direct load. */
1948
1949 bool
1950 modref_lattice::merge_direct_load ()
1951 {
1952 return merge (~(EAF_UNUSED | EAF_NO_DIRECT_READ));
1953 }
1954
1955 /* Merge in flags for direct store. */
1956
1957 bool
1958 modref_lattice::merge_direct_store ()
1959 {
1960 return merge (~(EAF_UNUSED | EAF_NO_DIRECT_CLOBBER));
1961 }
1962
1963 /* Analyzer of EAF flags.
1964 This is genrally dataflow problem over the SSA graph, however we only
1965 care about flags of few selected ssa names (arguments, return slot and
1966 static chain). So we first call analyze_ssa_name on all relevant names
1967 and perform a DFS walk to discover SSA names where flags needs to be
1968 determined. For acyclic graphs we try to determine final flags during
1969 this walk. Once cycles or recursin depth is met we enlist SSA names
1970 for dataflow which is done by propagate call.
1971
1972 After propagation the flags can be obtained using get_ssa_name_flags. */
1973
1974 class modref_eaf_analysis
1975 {
1976 public:
1977 /* Mark NAME as relevant for analysis. */
1978 void analyze_ssa_name (tree name);
1979 /* Dataflow slover. */
1980 void propagate ();
1981 /* Return flags computed earlier for NAME. */
1982 int get_ssa_name_flags (tree name)
1983 {
1984 int version = SSA_NAME_VERSION (name);
1985 gcc_checking_assert (m_lattice[version].known);
1986 return m_lattice[version].flags;
1987 }
1988 /* In IPA mode this will record all escape points
1989 determined for NAME to PARM_IDNEX. Flags are minimal
1990 flags known. */
1991 void record_escape_points (tree name, int parm_index, int flags);
1992 modref_eaf_analysis (bool ipa)
1993 {
1994 m_ipa = ipa;
1995 m_depth = 0;
1996 m_lattice.safe_grow_cleared (num_ssa_names, true);
1997 }
1998 ~modref_eaf_analysis ()
1999 {
2000 gcc_checking_assert (!m_depth);
2001 if (m_ipa || m_names_to_propagate.length ())
2002 for (unsigned int i = 0; i < num_ssa_names; i++)
2003 m_lattice[i].release ();
2004 }
2005 private:
2006 /* If true, we produce analysis for IPA mode. In this case escape points ar
2007 collected. */
2008 bool m_ipa;
2009 /* Depth of recursion of analyze_ssa_name. */
2010 int m_depth;
2011 /* Propagation lattice for individual ssa names. */
2012 auto_vec<modref_lattice> m_lattice;
2013 auto_vec<tree> m_deferred_names;
2014 auto_vec<int> m_names_to_propagate;
2015
2016 void merge_with_ssa_name (tree dest, tree src, bool deref);
2017 void merge_call_lhs_flags (gcall *call, int arg, tree name, bool direct,
2018 bool deref);
2019 };
2020
2021
2022 /* Call statements may return tgeir parameters. Consider argument number
2023 ARG of USE_STMT and determine flags that can needs to be cleared
2024 in case pointer possibly indirectly references from ARG I is returned.
2025 If DIRECT is true consider direct returns and if INDIRECT consider
2026 indirect returns.
2027 LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
2028 ARG is set to -1 for static chain. */
2029
2030 void
2031 modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg,
2032 tree name, bool direct,
2033 bool indirect)
2034 {
2035 int index = SSA_NAME_VERSION (name);
2036
2037 /* If value is not returned at all, do nothing. */
2038 if (!direct && !indirect)
2039 return;
2040
2041 /* If there is no return value, no flags are affected. */
2042 if (!gimple_call_lhs (call))
2043 return;
2044
2045 /* If we know that function returns given argument and it is not ARG
2046 we can still be happy. */
2047 if (arg >= 0)
2048 {
2049 int flags = gimple_call_return_flags (call);
2050 if ((flags & ERF_RETURNS_ARG)
2051 && (flags & ERF_RETURN_ARG_MASK) != arg)
2052 return;
2053 }
2054
2055 /* If return value is SSA name determine its flags. */
2056 if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
2057 {
2058 tree lhs = gimple_call_lhs (call);
2059 if (direct)
2060 merge_with_ssa_name (name, lhs, false);
2061 if (indirect)
2062 merge_with_ssa_name (name, lhs, true);
2063 }
2064 /* In the case of memory store we can do nothing. */
2065 else if (!direct)
2066 m_lattice[index].merge (deref_flags (0, false));
2067 else
2068 m_lattice[index].merge (0);
2069 }
2070
2071 /* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
2072 into flags for caller, update LATTICE of corresponding
2073 argument if needed. */
2074
2075 static int
2076 callee_to_caller_flags (int call_flags, bool ignore_stores,
2077 modref_lattice &lattice)
2078 {
2079 /* call_flags is about callee returning a value
2080 that is not the same as caller returning it. */
2081 call_flags |= EAF_NOT_RETURNED_DIRECTLY
2082 | EAF_NOT_RETURNED_INDIRECTLY;
2083 if (!ignore_stores && !(call_flags & EAF_UNUSED))
2084 {
2085 /* If value escapes we are no longer able to track what happens
2086 with it because we can read it from the escaped location
2087 anytime. */
2088 if (!(call_flags & EAF_NO_DIRECT_ESCAPE))
2089 lattice.merge (0);
2090 else if (!(call_flags & EAF_NO_INDIRECT_ESCAPE))
2091 lattice.merge (~(EAF_NOT_RETURNED_INDIRECTLY
2092 | EAF_NO_DIRECT_READ
2093 | EAF_NO_INDIRECT_READ
2094 | EAF_NO_INDIRECT_CLOBBER
2095 | EAF_UNUSED));
2096 }
2097 else
2098 call_flags |= ignore_stores_eaf_flags;
2099 return call_flags;
2100 }
2101
2102 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
2103 LATTICE is an array of modref_lattices.
2104 DEPTH is a recursion depth used to make debug output prettier.
2105 If IPA is true we analyze for IPA propagation (and thus call escape points
2106 are processed later) */
2107
2108 void
2109 modref_eaf_analysis::analyze_ssa_name (tree name)
2110 {
2111 imm_use_iterator ui;
2112 gimple *use_stmt;
2113 int index = SSA_NAME_VERSION (name);
2114
2115 /* See if value is already computed. */
2116 if (m_lattice[index].known || m_lattice[index].do_dataflow)
2117 return;
2118 if (m_lattice[index].open)
2119 {
2120 if (dump_file)
2121 fprintf (dump_file,
2122 "%*sCycle in SSA graph\n",
2123 m_depth * 4, "");
2124 return;
2125 }
2126 /* Recursion guard. */
2127 m_lattice[index].init ();
2128 if (m_depth == param_modref_max_depth)
2129 {
2130 if (dump_file)
2131 fprintf (dump_file,
2132 "%*sMax recursion depth reached; postponing\n",
2133 m_depth * 4, "");
2134 m_deferred_names.safe_push (name);
2135 return;
2136 }
2137
2138 if (dump_file)
2139 {
2140 fprintf (dump_file,
2141 "%*sAnalyzing flags of ssa name: ", m_depth * 4, "");
2142 print_generic_expr (dump_file, name);
2143 fprintf (dump_file, "\n");
2144 }
2145
2146 FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
2147 {
2148 if (m_lattice[index].flags == 0)
2149 break;
2150 if (is_gimple_debug (use_stmt))
2151 continue;
2152 if (dump_file)
2153 {
2154 fprintf (dump_file, "%*s Analyzing stmt: ", m_depth * 4, "");
2155 print_gimple_stmt (dump_file, use_stmt, 0);
2156 }
2157 /* If we see a direct non-debug use, clear unused bit.
2158 All dereferneces should be accounted below using deref_flags. */
2159 m_lattice[index].merge (~EAF_UNUSED);
2160
2161 /* Gimple return may load the return value.
2162 Returning name counts as an use by tree-ssa-structalias.c */
2163 if (greturn *ret = dyn_cast <greturn *> (use_stmt))
2164 {
2165 /* Returning through return slot is seen as memory write earlier. */
2166 if (DECL_RESULT (current_function_decl)
2167 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2168 ;
2169 else if (gimple_return_retval (ret) == name)
2170 m_lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED_DIRECTLY
2171 | EAF_NOT_RETURNED_DIRECTLY));
2172 else if (memory_access_to (gimple_return_retval (ret), name))
2173 {
2174 m_lattice[index].merge_direct_load ();
2175 m_lattice[index].merge (~(EAF_UNUSED
2176 | EAF_NOT_RETURNED_INDIRECTLY));
2177 }
2178 }
2179 /* Account for LHS store, arg loads and flags from callee function. */
2180 else if (gcall *call = dyn_cast <gcall *> (use_stmt))
2181 {
2182 tree callee = gimple_call_fndecl (call);
2183
2184 /* IPA PTA internally it treats calling a function as "writing" to
2185 the argument space of all functions the function pointer points to
2186 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
2187 is on since that would allow propagation of this from -fno-ipa-pta
2188 to -fipa-pta functions. */
2189 if (gimple_call_fn (use_stmt) == name)
2190 m_lattice[index].merge (~(EAF_NO_DIRECT_CLOBBER | EAF_UNUSED));
2191
2192 /* Recursion would require bit of propagation; give up for now. */
2193 if (callee && !m_ipa && recursive_call_p (current_function_decl,
2194 callee))
2195 m_lattice[index].merge (0);
2196 else
2197 {
2198 int ecf_flags = gimple_call_flags (call);
2199 bool ignore_stores = ignore_stores_p (current_function_decl,
2200 ecf_flags);
2201 bool ignore_retval = ignore_retval_p (current_function_decl,
2202 ecf_flags);
2203
2204 /* Handle *name = func (...). */
2205 if (gimple_call_lhs (call)
2206 && memory_access_to (gimple_call_lhs (call), name))
2207 {
2208 m_lattice[index].merge_direct_store ();
2209 /* Return slot optimization passes address of
2210 LHS to callee via hidden parameter and this
2211 may make LHS to escape. See PR 98499. */
2212 if (gimple_call_return_slot_opt_p (call)
2213 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
2214 {
2215 int call_flags = gimple_call_retslot_flags (call);
2216 bool isretslot = false;
2217
2218 if (DECL_RESULT (current_function_decl)
2219 && DECL_BY_REFERENCE
2220 (DECL_RESULT (current_function_decl)))
2221 isretslot = ssa_default_def
2222 (cfun,
2223 DECL_RESULT (current_function_decl))
2224 == name;
2225
2226 /* Passing returnslot to return slot is special because
2227 not_returned and escape has same meaning.
2228 However passing arg to return slot is different. If
2229 the callee's return slot is returned it means that
2230 arg is written to itself which is an escape.
2231 Since we do not track the memory it is written to we
2232 need to give up on analysisng it. */
2233 if (!isretslot)
2234 {
2235 if (!(call_flags & (EAF_NOT_RETURNED_DIRECTLY
2236 | EAF_UNUSED)))
2237 m_lattice[index].merge (0);
2238 else gcc_checking_assert
2239 (call_flags & (EAF_NOT_RETURNED_INDIRECTLY
2240 | EAF_UNUSED));
2241 call_flags = callee_to_caller_flags
2242 (call_flags, false,
2243 m_lattice[index]);
2244 }
2245 m_lattice[index].merge (call_flags);
2246 }
2247 }
2248
2249 if (gimple_call_chain (call)
2250 && (gimple_call_chain (call) == name))
2251 {
2252 int call_flags = gimple_call_static_chain_flags (call);
2253 if (!ignore_retval && !(call_flags & EAF_UNUSED))
2254 merge_call_lhs_flags
2255 (call, -1, name,
2256 !(call_flags & EAF_NOT_RETURNED_DIRECTLY),
2257 !(call_flags & EAF_NOT_RETURNED_INDIRECTLY));
2258 call_flags = callee_to_caller_flags
2259 (call_flags, ignore_stores,
2260 m_lattice[index]);
2261 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2262 m_lattice[index].merge (call_flags);
2263 }
2264
2265 /* Process internal functions and right away. */
2266 bool record_ipa = m_ipa && !gimple_call_internal_p (call);
2267
2268 /* Handle all function parameters. */
2269 for (unsigned i = 0;
2270 i < gimple_call_num_args (call)
2271 && m_lattice[index].flags; i++)
2272 /* Name is directly passed to the callee. */
2273 if (gimple_call_arg (call, i) == name)
2274 {
2275 int call_flags = gimple_call_arg_flags (call, i);
2276 if (!ignore_retval && !(call_flags & EAF_UNUSED))
2277 merge_call_lhs_flags
2278 (call, i, name,
2279 !(call_flags & EAF_NOT_RETURNED_DIRECTLY),
2280 !(call_flags & EAF_NOT_RETURNED_INDIRECTLY));
2281 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2282 {
2283 call_flags = callee_to_caller_flags
2284 (call_flags, ignore_stores,
2285 m_lattice[index]);
2286 if (!record_ipa)
2287 m_lattice[index].merge (call_flags);
2288 else
2289 m_lattice[index].add_escape_point (call, i,
2290 call_flags, true);
2291 }
2292 }
2293 /* Name is dereferenced and passed to a callee. */
2294 else if (memory_access_to (gimple_call_arg (call, i), name))
2295 {
2296 int call_flags = deref_flags
2297 (gimple_call_arg_flags (call, i), ignore_stores);
2298 if (!ignore_retval && !(call_flags & EAF_UNUSED)
2299 && !(call_flags & EAF_NOT_RETURNED_DIRECTLY)
2300 && !(call_flags & EAF_NOT_RETURNED_INDIRECTLY))
2301 merge_call_lhs_flags (call, i, name, false, true);
2302 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
2303 m_lattice[index].merge_direct_load ();
2304 else
2305 {
2306 call_flags = callee_to_caller_flags
2307 (call_flags, ignore_stores,
2308 m_lattice[index]);
2309 if (!record_ipa)
2310 m_lattice[index].merge (call_flags);
2311 else
2312 m_lattice[index].add_escape_point (call, i,
2313 call_flags, false);
2314 }
2315 }
2316 }
2317 }
2318 else if (gimple_assign_load_p (use_stmt))
2319 {
2320 gassign *assign = as_a <gassign *> (use_stmt);
2321 /* Memory to memory copy. */
2322 if (gimple_store_p (assign))
2323 {
2324 /* Handle *lhs = *name.
2325
2326 We do not track memory locations, so assume that value
2327 is used arbitrarily. */
2328 if (memory_access_to (gimple_assign_rhs1 (assign), name))
2329 m_lattice[index].merge (deref_flags (0, false));
2330 /* Handle *name = *exp. */
2331 else if (memory_access_to (gimple_assign_lhs (assign), name))
2332 m_lattice[index].merge_direct_store ();
2333 }
2334 /* Handle lhs = *name. */
2335 else if (memory_access_to (gimple_assign_rhs1 (assign), name))
2336 {
2337 tree lhs = gimple_assign_lhs (assign);
2338 merge_with_ssa_name (name, lhs, true);
2339 }
2340 }
2341 else if (gimple_store_p (use_stmt))
2342 {
2343 gassign *assign = dyn_cast <gassign *> (use_stmt);
2344
2345 /* Handle *lhs = name. */
2346 if (assign && gimple_assign_rhs1 (assign) == name)
2347 {
2348 if (dump_file)
2349 fprintf (dump_file, "%*s ssa name saved to memory\n",
2350 m_depth * 4, "");
2351 m_lattice[index].merge (0);
2352 }
2353 /* Handle *name = exp. */
2354 else if (assign
2355 && memory_access_to (gimple_assign_lhs (assign), name))
2356 {
2357 /* In general we can not ignore clobbers because they are
2358 barriers for code motion, however after inlining it is safe to
2359 do because local optimization passes do not consider clobbers
2360 from other functions.
2361 Similar logic is in ipa-pure-const.c. */
2362 if (!cfun->after_inlining || !gimple_clobber_p (assign))
2363 m_lattice[index].merge_direct_store ();
2364 }
2365 /* ASM statements etc. */
2366 else if (!assign)
2367 {
2368 if (dump_file)
2369 fprintf (dump_file, "%*s Unhandled store\n", m_depth * 4, "");
2370 m_lattice[index].merge (0);
2371 }
2372 }
2373 else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
2374 {
2375 enum tree_code code = gimple_assign_rhs_code (assign);
2376
2377 /* See if operation is a merge as considered by
2378 tree-ssa-structalias.c:find_func_aliases. */
2379 if (!truth_value_p (code)
2380 && code != POINTER_DIFF_EXPR
2381 && (code != POINTER_PLUS_EXPR
2382 || gimple_assign_rhs1 (assign) == name))
2383 {
2384 tree lhs = gimple_assign_lhs (assign);
2385 merge_with_ssa_name (name, lhs, false);
2386 }
2387 }
2388 else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
2389 {
2390 tree result = gimple_phi_result (phi);
2391 merge_with_ssa_name (name, result, false);
2392 }
2393 /* Conditions are not considered escape points
2394 by tree-ssa-structalias. */
2395 else if (gimple_code (use_stmt) == GIMPLE_COND)
2396 ;
2397 else
2398 {
2399 if (dump_file)
2400 fprintf (dump_file, "%*s Unhandled stmt\n", m_depth * 4, "");
2401 m_lattice[index].merge (0);
2402 }
2403
2404 if (dump_file)
2405 {
2406 fprintf (dump_file, "%*s current flags of ", m_depth * 4, "");
2407 print_generic_expr (dump_file, name);
2408 m_lattice[index].dump (dump_file, m_depth * 4 + 4);
2409 }
2410 }
2411 if (dump_file)
2412 {
2413 fprintf (dump_file, "%*sflags of ssa name ", m_depth * 4, "");
2414 print_generic_expr (dump_file, name);
2415 m_lattice[index].dump (dump_file, m_depth * 4 + 2);
2416 }
2417 m_lattice[index].open = false;
2418 if (!m_lattice[index].do_dataflow)
2419 m_lattice[index].known = true;
2420 }
2421
2422 /* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
2423 is dereferenced. */
2424
2425 void
2426 modref_eaf_analysis::merge_with_ssa_name (tree dest, tree src, bool deref)
2427 {
2428 int index = SSA_NAME_VERSION (dest);
2429 int src_index = SSA_NAME_VERSION (src);
2430
2431 /* Merging lattice with itself is a no-op. */
2432 if (!deref && src == dest)
2433 return;
2434
2435 m_depth++;
2436 analyze_ssa_name (src);
2437 m_depth--;
2438 if (deref)
2439 m_lattice[index].merge_deref (m_lattice[src_index], false);
2440 else
2441 m_lattice[index].merge (m_lattice[src_index]);
2442
2443 /* If we failed to produce final solution add an edge to the dataflow
2444 graph. */
2445 if (!m_lattice[src_index].known)
2446 {
2447 modref_lattice::propagate_edge e = {index, deref};
2448
2449 if (!m_lattice[src_index].propagate_to.length ())
2450 m_names_to_propagate.safe_push (src_index);
2451 m_lattice[src_index].propagate_to.safe_push (e);
2452 m_lattice[src_index].changed = true;
2453 m_lattice[src_index].do_dataflow = true;
2454 if (dump_file)
2455 fprintf (dump_file,
2456 "%*sWill propgate from ssa_name %i to %i%s\n",
2457 m_depth * 4 + 4,
2458 "", src_index, index, deref ? " (deref)" : "");
2459 }
2460 }
2461
2462 /* In the case we deferred some SSA names, reprocess them. In the case some
2463 dataflow edges were introduced, do the actual iterative dataflow. */
2464
2465 void
2466 modref_eaf_analysis::propagate ()
2467 {
2468 int iterations = 0;
2469 size_t i;
2470 int index;
2471 bool changed = true;
2472
2473 while (m_deferred_names.length ())
2474 {
2475 tree name = m_deferred_names.pop ();
2476 m_lattice[SSA_NAME_VERSION (name)].open = false;
2477 if (dump_file)
2478 fprintf (dump_file, "Analyzing deferred SSA name\n");
2479 analyze_ssa_name (name);
2480 }
2481
2482 if (!m_names_to_propagate.length ())
2483 return;
2484 if (dump_file)
2485 fprintf (dump_file, "Propagating EAF flags\n");
2486
2487 /* Compute reverse postorder. */
2488 auto_vec <int> rpo;
2489 struct stack_entry
2490 {
2491 int name;
2492 unsigned pos;
2493 };
2494 auto_vec <struct stack_entry> stack;
2495 int pos = m_names_to_propagate.length () - 1;
2496
2497 rpo.safe_grow (m_names_to_propagate.length (), true);
2498 stack.reserve_exact (m_names_to_propagate.length ());
2499
2500 /* We reuse known flag for RPO DFS walk bookeeping. */
2501 if (flag_checking)
2502 FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2503 gcc_assert (!m_lattice[index].known && m_lattice[index].changed);
2504
2505 FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2506 {
2507 if (!m_lattice[index].known)
2508 {
2509 stack_entry e = {index, 0};
2510
2511 stack.quick_push (e);
2512 m_lattice[index].known = true;
2513 }
2514 while (stack.length ())
2515 {
2516 bool found = false;
2517 int index1 = stack.last ().name;
2518
2519 while (stack.last ().pos < m_lattice[index1].propagate_to.length ())
2520 {
2521 int index2 = m_lattice[index1]
2522 .propagate_to[stack.last ().pos].ssa_name;
2523
2524 stack.last ().pos++;
2525 if (!m_lattice[index2].known
2526 && m_lattice[index2].propagate_to.length ())
2527 {
2528 stack_entry e = {index2, 0};
2529
2530 stack.quick_push (e);
2531 m_lattice[index2].known = true;
2532 found = true;
2533 break;
2534 }
2535 }
2536 if (!found
2537 && stack.last ().pos == m_lattice[index1].propagate_to.length ())
2538 {
2539 rpo[pos--] = index1;
2540 stack.pop ();
2541 }
2542 }
2543 }
2544
2545 /* Perform itrative dataflow. */
2546 while (changed)
2547 {
2548 changed = false;
2549 iterations++;
2550 if (dump_file)
2551 fprintf (dump_file, " iteration %i\n", iterations);
2552 FOR_EACH_VEC_ELT (rpo, i, index)
2553 {
2554 if (m_lattice[index].changed)
2555 {
2556 size_t j;
2557
2558 m_lattice[index].changed = false;
2559 if (dump_file)
2560 fprintf (dump_file, " Visiting ssa name %i\n", index);
2561 for (j = 0; j < m_lattice[index].propagate_to.length (); j++)
2562 {
2563 bool ch;
2564 int target = m_lattice[index].propagate_to[j].ssa_name;
2565 bool deref = m_lattice[index].propagate_to[j].deref;
2566
2567 if (dump_file)
2568 fprintf (dump_file, " Propagating flags of ssa name"
2569 " %i to %i%s\n",
2570 index, target, deref ? " (deref)" : "");
2571 m_lattice[target].known = true;
2572 if (!m_lattice[index].propagate_to[j].deref)
2573 ch = m_lattice[target].merge (m_lattice[index]);
2574 else
2575 ch = m_lattice[target].merge_deref (m_lattice[index],
2576 false);
2577 if (!ch)
2578 continue;
2579 if (dump_file)
2580 {
2581 fprintf (dump_file, " New lattice: ");
2582 m_lattice[target].dump (dump_file);
2583 }
2584 changed = true;
2585 m_lattice[target].changed = true;
2586 }
2587 }
2588 }
2589 }
2590 if (dump_file)
2591 fprintf (dump_file, "EAF flags propagated in %i iterations\n", iterations);
2592 }
2593
2594 /* Record escape points of PARM_INDEX according to LATTICE. */
2595
2596 void
2597 modref_eaf_analysis::record_escape_points (tree name, int parm_index, int flags)
2598 {
2599 modref_lattice &lattice = m_lattice[SSA_NAME_VERSION (name)];
2600
2601 if (lattice.escape_points.length ())
2602 {
2603 escape_point *ep;
2604 unsigned int ip;
2605 cgraph_node *node = cgraph_node::get (current_function_decl);
2606
2607 gcc_assert (m_ipa);
2608 FOR_EACH_VEC_ELT (lattice.escape_points, ip, ep)
2609 if ((ep->min_flags & flags) != flags)
2610 {
2611 cgraph_edge *e = node->get_edge (ep->call);
2612 struct escape_entry ee = {parm_index, ep->arg,
2613 ep->min_flags, ep->direct};
2614
2615 escape_summaries->get_create (e)->esc.safe_push (ee);
2616 }
2617 }
2618 }
2619
2620 /* Determine EAF flags for function parameters
2621 and fill in SUMMARY/SUMMARY_LTO. If IPA is true work in IPA mode
2622 where we also collect scape points.
2623 PAST_FLAGS, PAST_RETSLOT_FLAGS, PAST_STATIC_CHAIN_FLAGS can be
2624 used to preserve flags from prevoius (IPA) run for cases where
2625 late optimizations changed code in a way we can no longer analyze
2626 it easily. */
2627
2628 static void
2629 analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
2630 bool ipa, vec<eaf_flags_t> &past_flags,
2631 int past_retslot_flags, int past_static_chain_flags)
2632 {
2633 unsigned int parm_index = 0;
2634 unsigned int count = 0;
2635 int ecf_flags = flags_from_decl_or_type (current_function_decl);
2636 tree retslot = NULL;
2637 tree static_chain = NULL;
2638
2639 /* If there is return slot, look up its SSA name. */
2640 if (DECL_RESULT (current_function_decl)
2641 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2642 retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
2643 if (cfun->static_chain_decl)
2644 static_chain = ssa_default_def (cfun, cfun->static_chain_decl);
2645
2646 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2647 parm = TREE_CHAIN (parm))
2648 count++;
2649
2650 if (!count && !retslot && !static_chain)
2651 return;
2652
2653 modref_eaf_analysis eaf_analysis (ipa);
2654
2655 /* Determine all SSA names we need to know flags for. */
2656 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2657 parm = TREE_CHAIN (parm))
2658 {
2659 tree name = ssa_default_def (cfun, parm);
2660 if (name)
2661 eaf_analysis.analyze_ssa_name (name);
2662 }
2663 if (retslot)
2664 eaf_analysis.analyze_ssa_name (retslot);
2665 if (static_chain)
2666 eaf_analysis.analyze_ssa_name (static_chain);
2667
2668 /* Do the dataflow. */
2669 eaf_analysis.propagate ();
2670
2671 tree attr = lookup_attribute ("fn spec",
2672 TYPE_ATTRIBUTES
2673 (TREE_TYPE (current_function_decl)));
2674 attr_fnspec fnspec (attr
2675 ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)))
2676 : "");
2677
2678
2679 /* Store results to summaries. */
2680 for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
2681 parm = TREE_CHAIN (parm))
2682 {
2683 tree name = ssa_default_def (cfun, parm);
2684 if (!name || has_zero_uses (name))
2685 {
2686 /* We do not track non-SSA parameters,
2687 but we want to track unused gimple_regs. */
2688 if (!is_gimple_reg (parm))
2689 continue;
2690 if (summary)
2691 {
2692 if (parm_index >= summary->arg_flags.length ())
2693 summary->arg_flags.safe_grow_cleared (count, true);
2694 summary->arg_flags[parm_index] = EAF_UNUSED;
2695 }
2696 else if (summary_lto)
2697 {
2698 if (parm_index >= summary_lto->arg_flags.length ())
2699 summary_lto->arg_flags.safe_grow_cleared (count, true);
2700 summary_lto->arg_flags[parm_index] = EAF_UNUSED;
2701 }
2702 continue;
2703 }
2704 int flags = eaf_analysis.get_ssa_name_flags (name);
2705 int attr_flags = fnspec.arg_eaf_flags (parm_index);
2706
2707 if (dump_file && (flags | attr_flags) != flags && !(flags & EAF_UNUSED))
2708 {
2709 fprintf (dump_file,
2710 " Flags for param %i combined with fnspec flags:",
2711 (int)parm_index);
2712 dump_eaf_flags (dump_file, attr_flags, false);
2713 fprintf (dump_file, " determined: ");
2714 dump_eaf_flags (dump_file, flags, true);
2715 }
2716 flags |= attr_flags;
2717
2718 /* Eliminate useless flags so we do not end up storing unnecessary
2719 summaries. */
2720
2721 flags = remove_useless_eaf_flags
2722 (flags, ecf_flags,
2723 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
2724 if (past_flags.length () > parm_index)
2725 {
2726 int past = past_flags[parm_index];
2727 past = remove_useless_eaf_flags
2728 (past, ecf_flags,
2729 VOID_TYPE_P (TREE_TYPE
2730 (TREE_TYPE (current_function_decl))));
2731 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
2732 {
2733 fprintf (dump_file,
2734 " Flags for param %i combined with IPA pass:",
2735 (int)parm_index);
2736 dump_eaf_flags (dump_file, past, false);
2737 fprintf (dump_file, " determined: ");
2738 dump_eaf_flags (dump_file, flags, true);
2739 }
2740 if (!(flags & EAF_UNUSED))
2741 flags |= past;
2742 }
2743
2744 if (flags)
2745 {
2746 if (summary)
2747 {
2748 if (parm_index >= summary->arg_flags.length ())
2749 summary->arg_flags.safe_grow_cleared (count, true);
2750 summary->arg_flags[parm_index] = flags;
2751 }
2752 else if (summary_lto)
2753 {
2754 if (parm_index >= summary_lto->arg_flags.length ())
2755 summary_lto->arg_flags.safe_grow_cleared (count, true);
2756 summary_lto->arg_flags[parm_index] = flags;
2757 }
2758 eaf_analysis.record_escape_points (name, parm_index, flags);
2759 }
2760 }
2761 if (retslot)
2762 {
2763 int flags = eaf_analysis.get_ssa_name_flags (retslot);
2764 int past = past_retslot_flags;
2765
2766 flags = remove_useless_eaf_flags (flags, ecf_flags, false);
2767 past = remove_useless_eaf_flags
2768 (past, ecf_flags,
2769 VOID_TYPE_P (TREE_TYPE
2770 (TREE_TYPE (current_function_decl))));
2771 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
2772 {
2773 fprintf (dump_file,
2774 " Retslot flags combined with IPA pass:");
2775 dump_eaf_flags (dump_file, past, false);
2776 fprintf (dump_file, " determined: ");
2777 dump_eaf_flags (dump_file, flags, true);
2778 }
2779 if (!(flags & EAF_UNUSED))
2780 flags |= past;
2781 if (flags)
2782 {
2783 if (summary)
2784 summary->retslot_flags = flags;
2785 if (summary_lto)
2786 summary_lto->retslot_flags = flags;
2787 eaf_analysis.record_escape_points (retslot,
2788 MODREF_RETSLOT_PARM, flags);
2789 }
2790 }
2791 if (static_chain)
2792 {
2793 int flags = eaf_analysis.get_ssa_name_flags (static_chain);
2794 int past = past_static_chain_flags;
2795
2796 flags = remove_useless_eaf_flags (flags, ecf_flags, false);
2797 past = remove_useless_eaf_flags
2798 (past, ecf_flags,
2799 VOID_TYPE_P (TREE_TYPE
2800 (TREE_TYPE (current_function_decl))));
2801 if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
2802 {
2803 fprintf (dump_file,
2804 " Static chain flags combined with IPA pass:");
2805 dump_eaf_flags (dump_file, past, false);
2806 fprintf (dump_file, " determined: ");
2807 dump_eaf_flags (dump_file, flags, true);
2808 }
2809 if (!(flags & EAF_UNUSED))
2810 flags |= past;
2811 if (flags)
2812 {
2813 if (summary)
2814 summary->static_chain_flags = flags;
2815 if (summary_lto)
2816 summary_lto->static_chain_flags = flags;
2817 eaf_analysis.record_escape_points (static_chain,
2818 MODREF_STATIC_CHAIN_PARM,
2819 flags);
2820 }
2821 }
2822 }
2823
2824 /* Analyze function F. IPA indicates whether we're running in local mode
2825 (false) or the IPA mode (true).
2826 Return true if fixup cfg is needed after the pass. */
2827
2828 static bool
2829 analyze_function (function *f, bool ipa)
2830 {
2831 bool fixup_cfg = false;
2832 if (dump_file)
2833 fprintf (dump_file, "modref analyzing '%s' (ipa=%i)%s%s\n",
2834 function_name (f), ipa,
2835 TREE_READONLY (current_function_decl) ? " (const)" : "",
2836 DECL_PURE_P (current_function_decl) ? " (pure)" : "");
2837
2838 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
2839 if (!flag_ipa_modref
2840 || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
2841 return false;
2842
2843 /* Compute no-LTO summaries when local optimization is going to happen. */
2844 bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
2845 || (in_lto_p && !flag_wpa
2846 && flag_incremental_link != INCREMENTAL_LINK_LTO));
2847 /* Compute LTO when LTO streaming is going to happen. */
2848 bool lto = ipa && ((flag_lto && !in_lto_p)
2849 || flag_wpa
2850 || flag_incremental_link == INCREMENTAL_LINK_LTO);
2851 cgraph_node *fnode = cgraph_node::get (current_function_decl);
2852
2853 modref_summary *summary = NULL;
2854 modref_summary_lto *summary_lto = NULL;
2855
2856 bool past_flags_known = false;
2857 auto_vec <eaf_flags_t> past_flags;
2858 int past_retslot_flags = 0;
2859 int past_static_chain_flags = 0;
2860
2861 /* Initialize the summary.
2862 If we run in local mode there is possibly pre-existing summary from
2863 IPA pass. Dump it so it is easy to compare if mod-ref info has
2864 improved. */
2865 if (!ipa)
2866 {
2867 if (!optimization_summaries)
2868 optimization_summaries = modref_summaries::create_ggc (symtab);
2869 else /* Remove existing summary if we are re-running the pass. */
2870 {
2871 if (dump_file
2872 && (summary
2873 = optimization_summaries->get (cgraph_node::get (f->decl)))
2874 != NULL
2875 && summary->loads)
2876 {
2877 fprintf (dump_file, "Past summary:\n");
2878 optimization_summaries->get
2879 (cgraph_node::get (f->decl))->dump (dump_file);
2880 past_flags.reserve_exact (summary->arg_flags.length ());
2881 past_flags.splice (summary->arg_flags);
2882 past_retslot_flags = summary->retslot_flags;
2883 past_static_chain_flags = summary->static_chain_flags;
2884 past_flags_known = true;
2885 }
2886 optimization_summaries->remove (cgraph_node::get (f->decl));
2887 }
2888 summary = optimization_summaries->get_create (cgraph_node::get (f->decl));
2889 gcc_checking_assert (nolto && !lto);
2890 }
2891 /* In IPA mode we analyze every function precisely once. Assert that. */
2892 else
2893 {
2894 if (nolto)
2895 {
2896 if (!summaries)
2897 summaries = modref_summaries::create_ggc (symtab);
2898 else
2899 summaries->remove (cgraph_node::get (f->decl));
2900 summary = summaries->get_create (cgraph_node::get (f->decl));
2901 }
2902 if (lto)
2903 {
2904 if (!summaries_lto)
2905 summaries_lto = modref_summaries_lto::create_ggc (symtab);
2906 else
2907 summaries_lto->remove (cgraph_node::get (f->decl));
2908 summary_lto = summaries_lto->get_create (cgraph_node::get (f->decl));
2909 }
2910 if (!fnspec_summaries)
2911 fnspec_summaries = new fnspec_summaries_t (symtab);
2912 if (!escape_summaries)
2913 escape_summaries = new escape_summaries_t (symtab);
2914 }
2915
2916
2917 /* Create and initialize summary for F.
2918 Note that summaries may be already allocated from previous
2919 run of the pass. */
2920 if (nolto)
2921 {
2922 gcc_assert (!summary->loads);
2923 summary->loads = modref_records::create_ggc (param_modref_max_bases,
2924 param_modref_max_refs,
2925 param_modref_max_accesses);
2926 gcc_assert (!summary->stores);
2927 summary->stores = modref_records::create_ggc (param_modref_max_bases,
2928 param_modref_max_refs,
2929 param_modref_max_accesses);
2930 summary->writes_errno = false;
2931 summary->side_effects = false;
2932 summary->nondeterministic = false;
2933 summary->calls_interposable = false;
2934 }
2935 if (lto)
2936 {
2937 gcc_assert (!summary_lto->loads);
2938 summary_lto->loads = modref_records_lto::create_ggc
2939 (param_modref_max_bases,
2940 param_modref_max_refs,
2941 param_modref_max_accesses);
2942 gcc_assert (!summary_lto->stores);
2943 summary_lto->stores = modref_records_lto::create_ggc
2944 (param_modref_max_bases,
2945 param_modref_max_refs,
2946 param_modref_max_accesses);
2947 summary_lto->writes_errno = false;
2948 summary_lto->side_effects = false;
2949 summary_lto->nondeterministic = false;
2950 summary_lto->calls_interposable = false;
2951 }
2952
2953 analyze_parms (summary, summary_lto, ipa,
2954 past_flags, past_retslot_flags, past_static_chain_flags);
2955
2956 int ecf_flags = flags_from_decl_or_type (current_function_decl);
2957 auto_vec <gimple *, 32> recursive_calls;
2958
2959 /* Analyze each statement in each basic block of the function. If the
2960 statement cannot be analyzed (for any reason), the entire function cannot
2961 be analyzed by modref. */
2962 basic_block bb;
2963 FOR_EACH_BB_FN (bb, f)
2964 {
2965 gimple_stmt_iterator si;
2966 bool always_executed
2967 = bb == single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))->dest;
2968
2969 for (si = gsi_start_nondebug_after_labels_bb (bb);
2970 !gsi_end_p (si); gsi_next_nondebug (&si))
2971 {
2972 if (!analyze_stmt (summary, summary_lto,
2973 gsi_stmt (si), ipa, &recursive_calls,
2974 always_executed)
2975 || ((!summary || !summary->useful_p (ecf_flags, false))
2976 && (!summary_lto
2977 || !summary_lto->useful_p (ecf_flags, false))))
2978 {
2979 collapse_loads (summary, summary_lto);
2980 collapse_stores (summary, summary_lto);
2981 break;
2982 }
2983 if (always_executed
2984 && stmt_can_throw_external (cfun, gsi_stmt (si)))
2985 always_executed = false;
2986 }
2987 }
2988
2989 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2990 This needs to be done after all other side effects are computed. */
2991 if (!ipa)
2992 {
2993 bool changed = true;
2994 bool first = true;
2995 while (changed)
2996 {
2997 changed = false;
2998 for (unsigned i = 0; i < recursive_calls.length (); i++)
2999 {
3000 changed |= merge_call_side_effects
3001 (summary, recursive_calls[i], summary,
3002 ignore_stores_p (current_function_decl,
3003 gimple_call_flags
3004 (recursive_calls[i])),
3005 fnode, !first, false);
3006 if (!summary->useful_p (ecf_flags, false))
3007 {
3008 remove_summary (lto, nolto, ipa);
3009 return false;
3010 }
3011 }
3012 first = false;
3013 }
3014 }
3015 if (summary && !summary->side_effects && !finite_function_p ())
3016 summary->side_effects = true;
3017 if (summary_lto && !summary_lto->side_effects && !finite_function_p ())
3018 summary_lto->side_effects = true;
3019
3020 if (!ipa && flag_ipa_pure_const)
3021 {
3022 if (!summary->stores->every_base && !summary->stores->bases
3023 && !summary->nondeterministic)
3024 {
3025 if (!summary->loads->every_base && !summary->loads->bases
3026 && !summary->calls_interposable)
3027 fixup_cfg = ipa_make_function_const
3028 (cgraph_node::get (current_function_decl),
3029 summary->side_effects, true);
3030 else
3031 fixup_cfg = ipa_make_function_pure
3032 (cgraph_node::get (current_function_decl),
3033 summary->side_effects, true);
3034 }
3035 }
3036 if (summary && !summary->useful_p (ecf_flags))
3037 {
3038 if (!ipa)
3039 optimization_summaries->remove (fnode);
3040 else
3041 summaries->remove (fnode);
3042 summary = NULL;
3043 }
3044 if (summary)
3045 summary->finalize (current_function_decl);
3046 if (summary_lto && !summary_lto->useful_p (ecf_flags))
3047 {
3048 summaries_lto->remove (fnode);
3049 summary_lto = NULL;
3050 }
3051
3052 if (ipa && !summary && !summary_lto)
3053 remove_modref_edge_summaries (fnode);
3054
3055 if (dump_file)
3056 {
3057 fprintf (dump_file, " - modref done with result: tracked.\n");
3058 if (summary)
3059 summary->dump (dump_file);
3060 if (summary_lto)
3061 summary_lto->dump (dump_file);
3062 dump_modref_edge_summaries (dump_file, fnode, 2);
3063 /* To simplify debugging, compare IPA and local solutions. */
3064 if (past_flags_known && summary)
3065 {
3066 size_t len = summary->arg_flags.length ();
3067
3068 if (past_flags.length () > len)
3069 len = past_flags.length ();
3070 for (size_t i = 0; i < len; i++)
3071 {
3072 int old_flags = i < past_flags.length () ? past_flags[i] : 0;
3073 int new_flags = i < summary->arg_flags.length ()
3074 ? summary->arg_flags[i] : 0;
3075 old_flags = remove_useless_eaf_flags
3076 (old_flags, flags_from_decl_or_type (current_function_decl),
3077 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3078 if (old_flags != new_flags)
3079 {
3080 if ((old_flags & ~new_flags) == 0
3081 || (new_flags & EAF_UNUSED))
3082 fprintf (dump_file, " Flags for param %i improved:",
3083 (int)i);
3084 else
3085 gcc_unreachable ();
3086 dump_eaf_flags (dump_file, old_flags, false);
3087 fprintf (dump_file, " -> ");
3088 dump_eaf_flags (dump_file, new_flags, true);
3089 }
3090 }
3091 past_retslot_flags = remove_useless_eaf_flags
3092 (past_retslot_flags,
3093 flags_from_decl_or_type (current_function_decl),
3094 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3095 if (past_retslot_flags != summary->retslot_flags)
3096 {
3097 if ((past_retslot_flags & ~summary->retslot_flags) == 0
3098 || (summary->retslot_flags & EAF_UNUSED))
3099 fprintf (dump_file, " Flags for retslot improved:");
3100 else
3101 gcc_unreachable ();
3102 dump_eaf_flags (dump_file, past_retslot_flags, false);
3103 fprintf (dump_file, " -> ");
3104 dump_eaf_flags (dump_file, summary->retslot_flags, true);
3105 }
3106 past_static_chain_flags = remove_useless_eaf_flags
3107 (past_static_chain_flags,
3108 flags_from_decl_or_type (current_function_decl),
3109 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3110 if (past_static_chain_flags != summary->static_chain_flags)
3111 {
3112 if ((past_static_chain_flags & ~summary->static_chain_flags) == 0
3113 || (summary->static_chain_flags & EAF_UNUSED))
3114 fprintf (dump_file, " Flags for static chain improved:");
3115 else
3116 gcc_unreachable ();
3117 dump_eaf_flags (dump_file, past_static_chain_flags, false);
3118 fprintf (dump_file, " -> ");
3119 dump_eaf_flags (dump_file, summary->static_chain_flags, true);
3120 }
3121 }
3122 else if (past_flags_known && !summary)
3123 {
3124 for (size_t i = 0; i < past_flags.length (); i++)
3125 {
3126 int old_flags = past_flags[i];
3127 old_flags = remove_useless_eaf_flags
3128 (old_flags, flags_from_decl_or_type (current_function_decl),
3129 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3130 if (old_flags)
3131 {
3132 fprintf (dump_file, " Flags for param %i worsened:",
3133 (int)i);
3134 dump_eaf_flags (dump_file, old_flags, false);
3135 fprintf (dump_file, " -> \n");
3136 }
3137 }
3138 past_retslot_flags = remove_useless_eaf_flags
3139 (past_retslot_flags,
3140 flags_from_decl_or_type (current_function_decl),
3141 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3142 if (past_retslot_flags)
3143 {
3144 fprintf (dump_file, " Flags for retslot worsened:");
3145 dump_eaf_flags (dump_file, past_retslot_flags, false);
3146 fprintf (dump_file, " ->\n");
3147 }
3148 past_static_chain_flags = remove_useless_eaf_flags
3149 (past_static_chain_flags,
3150 flags_from_decl_or_type (current_function_decl),
3151 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3152 if (past_static_chain_flags)
3153 {
3154 fprintf (dump_file, " Flags for static chain worsened:");
3155 dump_eaf_flags (dump_file, past_static_chain_flags, false);
3156 fprintf (dump_file, " ->\n");
3157 }
3158 }
3159 }
3160 return fixup_cfg;
3161 }
3162
3163 /* Callback for generate_summary. */
3164
3165 static void
3166 modref_generate (void)
3167 {
3168 struct cgraph_node *node;
3169 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
3170 {
3171 function *f = DECL_STRUCT_FUNCTION (node->decl);
3172 if (!f)
3173 continue;
3174 push_cfun (f);
3175 analyze_function (f, true);
3176 pop_cfun ();
3177 }
3178 }
3179
3180 } /* ANON namespace. */
3181
3182 /* Debugging helper. */
3183
3184 void
3185 debug_eaf_flags (int flags)
3186 {
3187 dump_eaf_flags (stderr, flags, true);
3188 }
3189
3190 /* Called when a new function is inserted to callgraph late. */
3191
3192 void
3193 modref_summaries::insert (struct cgraph_node *node, modref_summary *)
3194 {
3195 /* Local passes ought to be executed by the pass manager. */
3196 if (this == optimization_summaries)
3197 {
3198 optimization_summaries->remove (node);
3199 return;
3200 }
3201 if (!DECL_STRUCT_FUNCTION (node->decl)
3202 || !opt_for_fn (node->decl, flag_ipa_modref))
3203 {
3204 summaries->remove (node);
3205 return;
3206 }
3207 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
3208 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
3209 pop_cfun ();
3210 }
3211
3212 /* Called when a new function is inserted to callgraph late. */
3213
3214 void
3215 modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
3216 {
3217 /* We do not support adding new function when IPA information is already
3218 propagated. This is done only by SIMD cloning that is not very
3219 critical. */
3220 if (!DECL_STRUCT_FUNCTION (node->decl)
3221 || !opt_for_fn (node->decl, flag_ipa_modref)
3222 || propagated)
3223 {
3224 summaries_lto->remove (node);
3225 return;
3226 }
3227 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
3228 analyze_function (DECL_STRUCT_FUNCTION (node->decl), true);
3229 pop_cfun ();
3230 }
3231
3232 /* Called when new clone is inserted to callgraph late. */
3233
3234 void
3235 modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
3236 modref_summary *src_data,
3237 modref_summary *dst_data)
3238 {
3239 /* Do not duplicate optimization summaries; we do not handle parameter
3240 transforms on them. */
3241 if (this == optimization_summaries)
3242 {
3243 optimization_summaries->remove (dst);
3244 return;
3245 }
3246 dst_data->stores = modref_records::create_ggc
3247 (src_data->stores->max_bases,
3248 src_data->stores->max_refs,
3249 src_data->stores->max_accesses);
3250 dst_data->stores->copy_from (src_data->stores);
3251 dst_data->loads = modref_records::create_ggc
3252 (src_data->loads->max_bases,
3253 src_data->loads->max_refs,
3254 src_data->loads->max_accesses);
3255 dst_data->loads->copy_from (src_data->loads);
3256 dst_data->kills.reserve_exact (src_data->kills.length ());
3257 dst_data->kills.splice (src_data->kills);
3258 dst_data->writes_errno = src_data->writes_errno;
3259 dst_data->side_effects = src_data->side_effects;
3260 dst_data->nondeterministic = src_data->nondeterministic;
3261 dst_data->calls_interposable = src_data->calls_interposable;
3262 if (src_data->arg_flags.length ())
3263 dst_data->arg_flags = src_data->arg_flags.copy ();
3264 dst_data->retslot_flags = src_data->retslot_flags;
3265 dst_data->static_chain_flags = src_data->static_chain_flags;
3266 }
3267
3268 /* Called when new clone is inserted to callgraph late. */
3269
3270 void
3271 modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
3272 modref_summary_lto *src_data,
3273 modref_summary_lto *dst_data)
3274 {
3275 /* Be sure that no further cloning happens after ipa-modref. If it does
3276 we will need to update signatures for possible param changes. */
3277 gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
3278 dst_data->stores = modref_records_lto::create_ggc
3279 (src_data->stores->max_bases,
3280 src_data->stores->max_refs,
3281 src_data->stores->max_accesses);
3282 dst_data->stores->copy_from (src_data->stores);
3283 dst_data->loads = modref_records_lto::create_ggc
3284 (src_data->loads->max_bases,
3285 src_data->loads->max_refs,
3286 src_data->loads->max_accesses);
3287 dst_data->loads->copy_from (src_data->loads);
3288 dst_data->kills.reserve_exact (src_data->kills.length ());
3289 dst_data->kills.splice (src_data->kills);
3290 dst_data->writes_errno = src_data->writes_errno;
3291 dst_data->side_effects = src_data->side_effects;
3292 dst_data->nondeterministic = src_data->nondeterministic;
3293 dst_data->calls_interposable = src_data->calls_interposable;
3294 if (src_data->arg_flags.length ())
3295 dst_data->arg_flags = src_data->arg_flags.copy ();
3296 dst_data->retslot_flags = src_data->retslot_flags;
3297 dst_data->static_chain_flags = src_data->static_chain_flags;
3298 }
3299
3300 namespace
3301 {
3302 /* Definition of the modref pass on GIMPLE. */
3303 const pass_data pass_data_modref = {
3304 GIMPLE_PASS,
3305 "modref",
3306 OPTGROUP_IPA,
3307 TV_TREE_MODREF,
3308 (PROP_cfg | PROP_ssa),
3309 0,
3310 0,
3311 0,
3312 0,
3313 };
3314
3315 class pass_modref : public gimple_opt_pass
3316 {
3317 public:
3318 pass_modref (gcc::context *ctxt)
3319 : gimple_opt_pass (pass_data_modref, ctxt) {}
3320
3321 /* opt_pass methods: */
3322 opt_pass *clone ()
3323 {
3324 return new pass_modref (m_ctxt);
3325 }
3326 virtual bool gate (function *)
3327 {
3328 return flag_ipa_modref;
3329 }
3330 virtual unsigned int execute (function *);
3331 };
3332
3333 /* Encode TT to the output block OB using the summary streaming API. */
3334
3335 static void
3336 write_modref_records (modref_records_lto *tt, struct output_block *ob)
3337 {
3338 streamer_write_uhwi (ob, tt->max_bases);
3339 streamer_write_uhwi (ob, tt->max_refs);
3340 streamer_write_uhwi (ob, tt->max_accesses);
3341
3342 streamer_write_uhwi (ob, tt->every_base);
3343 streamer_write_uhwi (ob, vec_safe_length (tt->bases));
3344 for (auto base_node : tt->bases)
3345 {
3346 stream_write_tree (ob, base_node->base, true);
3347
3348 streamer_write_uhwi (ob, base_node->every_ref);
3349 streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
3350
3351 for (auto ref_node : base_node->refs)
3352 {
3353 stream_write_tree (ob, ref_node->ref, true);
3354 streamer_write_uhwi (ob, ref_node->every_access);
3355 streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
3356
3357 for (auto access_node : ref_node->accesses)
3358 access_node.stream_out (ob);
3359 }
3360 }
3361 }
3362
3363 /* Read a modref_tree from the input block IB using the data from DATA_IN.
3364 This assumes that the tree was encoded using write_modref_tree.
3365 Either nolto_ret or lto_ret is initialized by the tree depending whether
3366 LTO streaming is expected or not. */
3367
3368 static void
3369 read_modref_records (lto_input_block *ib, struct data_in *data_in,
3370 modref_records **nolto_ret,
3371 modref_records_lto **lto_ret)
3372 {
3373 size_t max_bases = streamer_read_uhwi (ib);
3374 size_t max_refs = streamer_read_uhwi (ib);
3375 size_t max_accesses = streamer_read_uhwi (ib);
3376
3377 if (lto_ret)
3378 *lto_ret = modref_records_lto::create_ggc (max_bases, max_refs,
3379 max_accesses);
3380 if (nolto_ret)
3381 *nolto_ret = modref_records::create_ggc (max_bases, max_refs,
3382 max_accesses);
3383 gcc_checking_assert (lto_ret || nolto_ret);
3384
3385 size_t every_base = streamer_read_uhwi (ib);
3386 size_t nbase = streamer_read_uhwi (ib);
3387
3388 gcc_assert (!every_base || nbase == 0);
3389 if (every_base)
3390 {
3391 if (nolto_ret)
3392 (*nolto_ret)->collapse ();
3393 if (lto_ret)
3394 (*lto_ret)->collapse ();
3395 }
3396 for (size_t i = 0; i < nbase; i++)
3397 {
3398 tree base_tree = stream_read_tree (ib, data_in);
3399 modref_base_node <alias_set_type> *nolto_base_node = NULL;
3400 modref_base_node <tree> *lto_base_node = NULL;
3401
3402 /* At stream in time we have LTO alias info. Check if we streamed in
3403 something obviously unnecessary. Do not glob types by alias sets;
3404 it is not 100% clear that ltrans types will get merged same way.
3405 Types may get refined based on ODR type conflicts. */
3406 if (base_tree && !get_alias_set (base_tree))
3407 {
3408 if (dump_file)
3409 {
3410 fprintf (dump_file, "Streamed in alias set 0 type ");
3411 print_generic_expr (dump_file, base_tree);
3412 fprintf (dump_file, "\n");
3413 }
3414 base_tree = NULL;
3415 }
3416
3417 if (nolto_ret)
3418 nolto_base_node = (*nolto_ret)->insert_base (base_tree
3419 ? get_alias_set (base_tree)
3420 : 0, 0);
3421 if (lto_ret)
3422 lto_base_node = (*lto_ret)->insert_base (base_tree, 0);
3423 size_t every_ref = streamer_read_uhwi (ib);
3424 size_t nref = streamer_read_uhwi (ib);
3425
3426 gcc_assert (!every_ref || nref == 0);
3427 if (every_ref)
3428 {
3429 if (nolto_base_node)
3430 nolto_base_node->collapse ();
3431 if (lto_base_node)
3432 lto_base_node->collapse ();
3433 }
3434 for (size_t j = 0; j < nref; j++)
3435 {
3436 tree ref_tree = stream_read_tree (ib, data_in);
3437
3438 if (ref_tree && !get_alias_set (ref_tree))
3439 {
3440 if (dump_file)
3441 {
3442 fprintf (dump_file, "Streamed in alias set 0 type ");
3443 print_generic_expr (dump_file, ref_tree);
3444 fprintf (dump_file, "\n");
3445 }
3446 ref_tree = NULL;
3447 }
3448
3449 modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
3450 modref_ref_node <tree> *lto_ref_node = NULL;
3451
3452 if (nolto_base_node)
3453 nolto_ref_node
3454 = nolto_base_node->insert_ref (ref_tree
3455 ? get_alias_set (ref_tree) : 0,
3456 max_refs);
3457 if (lto_base_node)
3458 lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
3459
3460 size_t every_access = streamer_read_uhwi (ib);
3461 size_t naccesses = streamer_read_uhwi (ib);
3462
3463 if (nolto_ref_node && every_access)
3464 nolto_ref_node->collapse ();
3465 if (lto_ref_node && every_access)
3466 lto_ref_node->collapse ();
3467
3468 for (size_t k = 0; k < naccesses; k++)
3469 {
3470 modref_access_node a = modref_access_node::stream_in (ib);
3471 if (nolto_ref_node)
3472 nolto_ref_node->insert_access (a, max_accesses, false);
3473 if (lto_ref_node)
3474 lto_ref_node->insert_access (a, max_accesses, false);
3475 }
3476 }
3477 }
3478 if (lto_ret)
3479 (*lto_ret)->cleanup ();
3480 if (nolto_ret)
3481 (*nolto_ret)->cleanup ();
3482 }
3483
3484 /* Write ESUM to BP. */
3485
3486 static void
3487 modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
3488 {
3489 if (!esum)
3490 {
3491 bp_pack_var_len_unsigned (bp, 0);
3492 return;
3493 }
3494 bp_pack_var_len_unsigned (bp, esum->esc.length ());
3495 unsigned int i;
3496 escape_entry *ee;
3497 FOR_EACH_VEC_ELT (esum->esc, i, ee)
3498 {
3499 bp_pack_var_len_int (bp, ee->parm_index);
3500 bp_pack_var_len_unsigned (bp, ee->arg);
3501 bp_pack_var_len_unsigned (bp, ee->min_flags);
3502 bp_pack_value (bp, ee->direct, 1);
3503 }
3504 }
3505
3506 /* Read escape summary for E from BP. */
3507
3508 static void
3509 modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
3510 {
3511 unsigned int n = bp_unpack_var_len_unsigned (bp);
3512 if (!n)
3513 return;
3514 escape_summary *esum = escape_summaries->get_create (e);
3515 esum->esc.reserve_exact (n);
3516 for (unsigned int i = 0; i < n; i++)
3517 {
3518 escape_entry ee;
3519 ee.parm_index = bp_unpack_var_len_int (bp);
3520 ee.arg = bp_unpack_var_len_unsigned (bp);
3521 ee.min_flags = bp_unpack_var_len_unsigned (bp);
3522 ee.direct = bp_unpack_value (bp, 1);
3523 esum->esc.quick_push (ee);
3524 }
3525 }
3526
3527 /* Callback for write_summary. */
3528
3529 static void
3530 modref_write ()
3531 {
3532 struct output_block *ob = create_output_block (LTO_section_ipa_modref);
3533 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
3534 unsigned int count = 0;
3535 int i;
3536
3537 if (!summaries_lto)
3538 {
3539 streamer_write_uhwi (ob, 0);
3540 streamer_write_char_stream (ob->main_stream, 0);
3541 produce_asm (ob, NULL);
3542 destroy_output_block (ob);
3543 return;
3544 }
3545
3546 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3547 {
3548 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3549 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3550 modref_summary_lto *r;
3551
3552 if (cnode && cnode->definition && !cnode->alias
3553 && (r = summaries_lto->get (cnode))
3554 && r->useful_p (flags_from_decl_or_type (cnode->decl)))
3555 count++;
3556 }
3557 streamer_write_uhwi (ob, count);
3558
3559 for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3560 {
3561 symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3562 cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3563
3564 if (cnode && cnode->definition && !cnode->alias)
3565 {
3566 modref_summary_lto *r = summaries_lto->get (cnode);
3567
3568 if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
3569 continue;
3570
3571 streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
3572
3573 streamer_write_uhwi (ob, r->arg_flags.length ());
3574 for (unsigned int i = 0; i < r->arg_flags.length (); i++)
3575 streamer_write_uhwi (ob, r->arg_flags[i]);
3576 streamer_write_uhwi (ob, r->retslot_flags);
3577 streamer_write_uhwi (ob, r->static_chain_flags);
3578
3579 write_modref_records (r->loads, ob);
3580 write_modref_records (r->stores, ob);
3581 streamer_write_uhwi (ob, r->kills.length ());
3582 for (auto kill : r->kills)
3583 kill.stream_out (ob);
3584
3585 struct bitpack_d bp = bitpack_create (ob->main_stream);
3586 bp_pack_value (&bp, r->writes_errno, 1);
3587 bp_pack_value (&bp, r->side_effects, 1);
3588 bp_pack_value (&bp, r->nondeterministic, 1);
3589 bp_pack_value (&bp, r->calls_interposable, 1);
3590 if (!flag_wpa)
3591 {
3592 for (cgraph_edge *e = cnode->indirect_calls;
3593 e; e = e->next_callee)
3594 {
3595 class fnspec_summary *sum = fnspec_summaries->get (e);
3596 bp_pack_value (&bp, sum != NULL, 1);
3597 if (sum)
3598 bp_pack_string (ob, &bp, sum->fnspec, true);
3599 class escape_summary *esum = escape_summaries->get (e);
3600 modref_write_escape_summary (&bp,esum);
3601 }
3602 for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
3603 {
3604 class fnspec_summary *sum = fnspec_summaries->get (e);
3605 bp_pack_value (&bp, sum != NULL, 1);
3606 if (sum)
3607 bp_pack_string (ob, &bp, sum->fnspec, true);
3608 class escape_summary *esum = escape_summaries->get (e);
3609 modref_write_escape_summary (&bp,esum);
3610 }
3611 }
3612 streamer_write_bitpack (&bp);
3613 }
3614 }
3615 streamer_write_char_stream (ob->main_stream, 0);
3616 produce_asm (ob, NULL);
3617 destroy_output_block (ob);
3618 }
3619
3620 static void
3621 read_section (struct lto_file_decl_data *file_data, const char *data,
3622 size_t len)
3623 {
3624 const struct lto_function_header *header
3625 = (const struct lto_function_header *) data;
3626 const int cfg_offset = sizeof (struct lto_function_header);
3627 const int main_offset = cfg_offset + header->cfg_size;
3628 const int string_offset = main_offset + header->main_size;
3629 struct data_in *data_in;
3630 unsigned int i;
3631 unsigned int f_count;
3632
3633 lto_input_block ib ((const char *) data + main_offset, header->main_size,
3634 file_data->mode_table);
3635
3636 data_in
3637 = lto_data_in_create (file_data, (const char *) data + string_offset,
3638 header->string_size, vNULL);
3639 f_count = streamer_read_uhwi (&ib);
3640 for (i = 0; i < f_count; i++)
3641 {
3642 struct cgraph_node *node;
3643 lto_symtab_encoder_t encoder;
3644
3645 unsigned int index = streamer_read_uhwi (&ib);
3646 encoder = file_data->symtab_node_encoder;
3647 node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
3648 index));
3649
3650 modref_summary *modref_sum = summaries
3651 ? summaries->get_create (node) : NULL;
3652 modref_summary_lto *modref_sum_lto = summaries_lto
3653 ? summaries_lto->get_create (node)
3654 : NULL;
3655 if (optimization_summaries)
3656 modref_sum = optimization_summaries->get_create (node);
3657
3658 if (modref_sum)
3659 {
3660 modref_sum->writes_errno = false;
3661 modref_sum->side_effects = false;
3662 modref_sum->nondeterministic = false;
3663 modref_sum->calls_interposable = false;
3664 }
3665 if (modref_sum_lto)
3666 {
3667 modref_sum_lto->writes_errno = false;
3668 modref_sum_lto->side_effects = false;
3669 modref_sum_lto->nondeterministic = false;
3670 modref_sum_lto->calls_interposable = false;
3671 }
3672
3673 gcc_assert (!modref_sum || (!modref_sum->loads
3674 && !modref_sum->stores));
3675 gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
3676 && !modref_sum_lto->stores));
3677 unsigned int args = streamer_read_uhwi (&ib);
3678 if (args && modref_sum)
3679 modref_sum->arg_flags.reserve_exact (args);
3680 if (args && modref_sum_lto)
3681 modref_sum_lto->arg_flags.reserve_exact (args);
3682 for (unsigned int i = 0; i < args; i++)
3683 {
3684 eaf_flags_t flags = streamer_read_uhwi (&ib);
3685 if (modref_sum)
3686 modref_sum->arg_flags.quick_push (flags);
3687 if (modref_sum_lto)
3688 modref_sum_lto->arg_flags.quick_push (flags);
3689 }
3690 eaf_flags_t flags = streamer_read_uhwi (&ib);
3691 if (modref_sum)
3692 modref_sum->retslot_flags = flags;
3693 if (modref_sum_lto)
3694 modref_sum_lto->retslot_flags = flags;
3695
3696 flags = streamer_read_uhwi (&ib);
3697 if (modref_sum)
3698 modref_sum->static_chain_flags = flags;
3699 if (modref_sum_lto)
3700 modref_sum_lto->static_chain_flags = flags;
3701
3702 read_modref_records (&ib, data_in,
3703 modref_sum ? &modref_sum->loads : NULL,
3704 modref_sum_lto ? &modref_sum_lto->loads : NULL);
3705 read_modref_records (&ib, data_in,
3706 modref_sum ? &modref_sum->stores : NULL,
3707 modref_sum_lto ? &modref_sum_lto->stores : NULL);
3708 int j = streamer_read_uhwi (&ib);
3709 if (j && modref_sum)
3710 modref_sum->kills.reserve_exact (j);
3711 if (j && modref_sum_lto)
3712 modref_sum_lto->kills.reserve_exact (j);
3713 for (int k = 0; k < j; k++)
3714 {
3715 modref_access_node a = modref_access_node::stream_in (&ib);
3716
3717 if (modref_sum)
3718 modref_sum->kills.quick_push (a);
3719 if (modref_sum_lto)
3720 modref_sum_lto->kills.quick_push (a);
3721 }
3722 struct bitpack_d bp = streamer_read_bitpack (&ib);
3723 if (bp_unpack_value (&bp, 1))
3724 {
3725 if (modref_sum)
3726 modref_sum->writes_errno = true;
3727 if (modref_sum_lto)
3728 modref_sum_lto->writes_errno = true;
3729 }
3730 if (bp_unpack_value (&bp, 1))
3731 {
3732 if (modref_sum)
3733 modref_sum->side_effects = true;
3734 if (modref_sum_lto)
3735 modref_sum_lto->side_effects = true;
3736 }
3737 if (bp_unpack_value (&bp, 1))
3738 {
3739 if (modref_sum)
3740 modref_sum->nondeterministic = true;
3741 if (modref_sum_lto)
3742 modref_sum_lto->nondeterministic = true;
3743 }
3744 if (bp_unpack_value (&bp, 1))
3745 {
3746 if (modref_sum)
3747 modref_sum->calls_interposable = true;
3748 if (modref_sum_lto)
3749 modref_sum_lto->calls_interposable = true;
3750 }
3751 if (!flag_ltrans)
3752 {
3753 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
3754 {
3755 if (bp_unpack_value (&bp, 1))
3756 {
3757 class fnspec_summary *sum = fnspec_summaries->get_create (e);
3758 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3759 }
3760 modref_read_escape_summary (&bp, e);
3761 }
3762 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3763 {
3764 if (bp_unpack_value (&bp, 1))
3765 {
3766 class fnspec_summary *sum = fnspec_summaries->get_create (e);
3767 sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3768 }
3769 modref_read_escape_summary (&bp, e);
3770 }
3771 }
3772 if (flag_ltrans)
3773 modref_sum->finalize (node->decl);
3774 if (dump_file)
3775 {
3776 fprintf (dump_file, "Read modref for %s\n",
3777 node->dump_name ());
3778 if (modref_sum)
3779 modref_sum->dump (dump_file);
3780 if (modref_sum_lto)
3781 modref_sum_lto->dump (dump_file);
3782 dump_modref_edge_summaries (dump_file, node, 4);
3783 }
3784 }
3785
3786 lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
3787 len);
3788 lto_data_in_delete (data_in);
3789 }
3790
3791 /* Callback for read_summary. */
3792
3793 static void
3794 modref_read (void)
3795 {
3796 struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
3797 struct lto_file_decl_data *file_data;
3798 unsigned int j = 0;
3799
3800 gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
3801 if (flag_ltrans)
3802 optimization_summaries = modref_summaries::create_ggc (symtab);
3803 else
3804 {
3805 if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
3806 summaries_lto = modref_summaries_lto::create_ggc (symtab);
3807 if (!flag_wpa
3808 || (flag_incremental_link == INCREMENTAL_LINK_LTO
3809 && flag_fat_lto_objects))
3810 summaries = modref_summaries::create_ggc (symtab);
3811 if (!fnspec_summaries)
3812 fnspec_summaries = new fnspec_summaries_t (symtab);
3813 if (!escape_summaries)
3814 escape_summaries = new escape_summaries_t (symtab);
3815 }
3816
3817 while ((file_data = file_data_vec[j++]))
3818 {
3819 size_t len;
3820 const char *data = lto_get_summary_section_data (file_data,
3821 LTO_section_ipa_modref,
3822 &len);
3823 if (data)
3824 read_section (file_data, data, len);
3825 else
3826 /* Fatal error here. We do not want to support compiling ltrans units
3827 with different version of compiler or different flags than the WPA
3828 unit, so this should never happen. */
3829 fatal_error (input_location,
3830 "IPA modref summary is missing in input file");
3831 }
3832 }
3833
3834 /* Recompute arg_flags for param adjustments in INFO. */
3835
3836 static void
3837 remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
3838 {
3839 auto_vec<eaf_flags_t> old = arg_flags.copy ();
3840 int max = -1;
3841 size_t i;
3842 ipa_adjusted_param *p;
3843
3844 arg_flags.release ();
3845
3846 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
3847 {
3848 int o = info->param_adjustments->get_original_index (i);
3849 if (o >= 0 && (int)old.length () > o && old[o])
3850 max = i;
3851 }
3852 if (max >= 0)
3853 arg_flags.safe_grow_cleared (max + 1, true);
3854 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
3855 {
3856 int o = info->param_adjustments->get_original_index (i);
3857 if (o >= 0 && (int)old.length () > o && old[o])
3858 arg_flags[i] = old[o];
3859 }
3860 }
3861
3862 /* Update kills accrdoing to the parm map MAP. */
3863
3864 static void
3865 remap_kills (vec <modref_access_node> &kills, const vec <int> &map)
3866 {
3867 for (size_t i = 0; i < kills.length ();)
3868 if (kills[i].parm_index >= 0)
3869 {
3870 if (kills[i].parm_index < (int)map.length ()
3871 && map[kills[i].parm_index] != MODREF_UNKNOWN_PARM)
3872 {
3873 kills[i].parm_index = map[kills[i].parm_index];
3874 i++;
3875 }
3876 else
3877 kills.unordered_remove (i);
3878 }
3879 else
3880 i++;
3881 }
3882
3883 /* If signature changed, update the summary. */
3884
3885 static void
3886 update_signature (struct cgraph_node *node)
3887 {
3888 clone_info *info = clone_info::get (node);
3889 if (!info || !info->param_adjustments)
3890 return;
3891
3892 modref_summary *r = optimization_summaries
3893 ? optimization_summaries->get (node) : NULL;
3894 modref_summary_lto *r_lto = summaries_lto
3895 ? summaries_lto->get (node) : NULL;
3896 if (!r && !r_lto)
3897 return;
3898 if (dump_file)
3899 {
3900 fprintf (dump_file, "Updating summary for %s from:\n",
3901 node->dump_name ());
3902 if (r)
3903 r->dump (dump_file);
3904 if (r_lto)
3905 r_lto->dump (dump_file);
3906 }
3907
3908 size_t i, max = 0;
3909 ipa_adjusted_param *p;
3910
3911 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
3912 {
3913 int idx = info->param_adjustments->get_original_index (i);
3914 if (idx > (int)max)
3915 max = idx;
3916 }
3917
3918 auto_vec <int, 32> map;
3919
3920 map.reserve (max + 1);
3921 for (i = 0; i <= max; i++)
3922 map.quick_push (MODREF_UNKNOWN_PARM);
3923 FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
3924 {
3925 int idx = info->param_adjustments->get_original_index (i);
3926 if (idx >= 0)
3927 map[idx] = i;
3928 }
3929 if (r)
3930 {
3931 r->loads->remap_params (&map);
3932 r->stores->remap_params (&map);
3933 remap_kills (r->kills, map);
3934 if (r->arg_flags.length ())
3935 remap_arg_flags (r->arg_flags, info);
3936 }
3937 if (r_lto)
3938 {
3939 r_lto->loads->remap_params (&map);
3940 r_lto->stores->remap_params (&map);
3941 remap_kills (r_lto->kills, map);
3942 if (r_lto->arg_flags.length ())
3943 remap_arg_flags (r_lto->arg_flags, info);
3944 }
3945 if (dump_file)
3946 {
3947 fprintf (dump_file, "to:\n");
3948 if (r)
3949 r->dump (dump_file);
3950 if (r_lto)
3951 r_lto->dump (dump_file);
3952 }
3953 if (r)
3954 r->finalize (node->decl);
3955 return;
3956 }
3957
3958 /* Definition of the modref IPA pass. */
3959 const pass_data pass_data_ipa_modref =
3960 {
3961 IPA_PASS, /* type */
3962 "modref", /* name */
3963 OPTGROUP_IPA, /* optinfo_flags */
3964 TV_IPA_MODREF, /* tv_id */
3965 0, /* properties_required */
3966 0, /* properties_provided */
3967 0, /* properties_destroyed */
3968 0, /* todo_flags_start */
3969 ( TODO_dump_symtab ), /* todo_flags_finish */
3970 };
3971
3972 class pass_ipa_modref : public ipa_opt_pass_d
3973 {
3974 public:
3975 pass_ipa_modref (gcc::context *ctxt)
3976 : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
3977 modref_generate, /* generate_summary */
3978 modref_write, /* write_summary */
3979 modref_read, /* read_summary */
3980 modref_write, /* write_optimization_summary */
3981 modref_read, /* read_optimization_summary */
3982 NULL, /* stmt_fixup */
3983 0, /* function_transform_todo_flags_start */
3984 NULL, /* function_transform */
3985 NULL) /* variable_transform */
3986 {}
3987
3988 /* opt_pass methods: */
3989 opt_pass *clone () { return new pass_ipa_modref (m_ctxt); }
3990 virtual bool gate (function *)
3991 {
3992 return true;
3993 }
3994 virtual unsigned int execute (function *);
3995
3996 };
3997
3998 }
3999
4000 unsigned int pass_modref::execute (function *f)
4001 {
4002 if (analyze_function (f, false))
4003 return execute_fixup_cfg ();
4004 return 0;
4005 }
4006
4007 gimple_opt_pass *
4008 make_pass_modref (gcc::context *ctxt)
4009 {
4010 return new pass_modref (ctxt);
4011 }
4012
4013 ipa_opt_pass_d *
4014 make_pass_ipa_modref (gcc::context *ctxt)
4015 {
4016 return new pass_ipa_modref (ctxt);
4017 }
4018
4019 namespace {
4020
4021 /* Skip edges from and to nodes without ipa_pure_const enabled.
4022 Ignore not available symbols. */
4023
4024 static bool
4025 ignore_edge (struct cgraph_edge *e)
4026 {
4027 /* We merge summaries of inline clones into summaries of functions they
4028 are inlined to. For that reason the complete function bodies must
4029 act as unit. */
4030 if (!e->inline_failed)
4031 return false;
4032 enum availability avail;
4033 cgraph_node *callee = e->callee->function_or_virtual_thunk_symbol
4034 (&avail, e->caller);
4035
4036 return (avail <= AVAIL_INTERPOSABLE
4037 || ((!optimization_summaries || !optimization_summaries->get (callee))
4038 && (!summaries_lto || !summaries_lto->get (callee))));
4039 }
4040
4041 /* Compute parm_map for CALLEE_EDGE. */
4042
4043 static bool
4044 compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
4045 {
4046 class ipa_edge_args *args;
4047 if (ipa_node_params_sum
4048 && !callee_edge->call_stmt_cannot_inline_p
4049 && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
4050 {
4051 int i, count = ipa_get_cs_argument_count (args);
4052 class ipa_node_params *caller_parms_info, *callee_pi;
4053 class ipa_call_summary *es
4054 = ipa_call_summaries->get (callee_edge);
4055 cgraph_node *callee
4056 = callee_edge->callee->function_or_virtual_thunk_symbol
4057 (NULL, callee_edge->caller);
4058
4059 caller_parms_info
4060 = ipa_node_params_sum->get (callee_edge->caller->inlined_to
4061 ? callee_edge->caller->inlined_to
4062 : callee_edge->caller);
4063 callee_pi = ipa_node_params_sum->get (callee);
4064
4065 (*parm_map).safe_grow_cleared (count, true);
4066
4067 for (i = 0; i < count; i++)
4068 {
4069 if (es && es->param[i].points_to_local_or_readonly_memory)
4070 {
4071 (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
4072 continue;
4073 }
4074
4075 struct ipa_jump_func *jf
4076 = ipa_get_ith_jump_func (args, i);
4077 if (jf && callee_pi)
4078 {
4079 tree cst = ipa_value_from_jfunc (caller_parms_info,
4080 jf,
4081 ipa_get_type
4082 (callee_pi, i));
4083 if (cst && points_to_local_or_readonly_memory_p (cst))
4084 {
4085 (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
4086 continue;
4087 }
4088 }
4089 if (jf && jf->type == IPA_JF_PASS_THROUGH)
4090 {
4091 (*parm_map)[i].parm_index
4092 = ipa_get_jf_pass_through_formal_id (jf);
4093 if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
4094 {
4095 (*parm_map)[i].parm_offset_known = true;
4096 (*parm_map)[i].parm_offset = 0;
4097 }
4098 else if (ipa_get_jf_pass_through_operation (jf)
4099 == POINTER_PLUS_EXPR
4100 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
4101 &(*parm_map)[i].parm_offset))
4102 (*parm_map)[i].parm_offset_known = true;
4103 else
4104 (*parm_map)[i].parm_offset_known = false;
4105 continue;
4106 }
4107 if (jf && jf->type == IPA_JF_ANCESTOR)
4108 {
4109 (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
4110 (*parm_map)[i].parm_offset_known = true;
4111 gcc_checking_assert
4112 (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
4113 (*parm_map)[i].parm_offset
4114 = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
4115 }
4116 else
4117 (*parm_map)[i].parm_index = -1;
4118 }
4119 if (dump_file)
4120 {
4121 fprintf (dump_file, " Parm map: ");
4122 for (i = 0; i < count; i++)
4123 fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
4124 fprintf (dump_file, "\n");
4125 }
4126 return true;
4127 }
4128 return false;
4129 }
4130
4131 /* Map used to translate escape infos. */
4132
4133 struct escape_map
4134 {
4135 int parm_index;
4136 bool direct;
4137 };
4138
4139 /* Update escape map for E. */
4140
4141 static void
4142 update_escape_summary_1 (cgraph_edge *e,
4143 vec <vec <escape_map>> &map,
4144 bool ignore_stores)
4145 {
4146 escape_summary *sum = escape_summaries->get (e);
4147 if (!sum)
4148 return;
4149 auto_vec <escape_entry> old = sum->esc.copy ();
4150 sum->esc.release ();
4151
4152 unsigned int i;
4153 escape_entry *ee;
4154 FOR_EACH_VEC_ELT (old, i, ee)
4155 {
4156 unsigned int j;
4157 struct escape_map *em;
4158 /* TODO: We do not have jump functions for return slots, so we
4159 never propagate them to outer function. */
4160 if (ee->parm_index >= (int)map.length ()
4161 || ee->parm_index < 0)
4162 continue;
4163 FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
4164 {
4165 int min_flags = ee->min_flags;
4166 if (ee->direct && !em->direct)
4167 min_flags = deref_flags (min_flags, ignore_stores);
4168 struct escape_entry entry = {em->parm_index, ee->arg,
4169 ee->min_flags,
4170 ee->direct & em->direct};
4171 sum->esc.safe_push (entry);
4172 }
4173 }
4174 if (!sum->esc.length ())
4175 escape_summaries->remove (e);
4176 }
4177
4178 /* Update escape map fo NODE. */
4179
4180 static void
4181 update_escape_summary (cgraph_node *node,
4182 vec <vec <escape_map>> &map,
4183 bool ignore_stores)
4184 {
4185 if (!escape_summaries)
4186 return;
4187 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
4188 update_escape_summary_1 (e, map, ignore_stores);
4189 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
4190 {
4191 if (!e->inline_failed)
4192 update_escape_summary (e->callee, map, ignore_stores);
4193 else
4194 update_escape_summary_1 (e, map, ignore_stores);
4195 }
4196 }
4197
4198 /* Get parameter type from DECL. This is only safe for special cases
4199 like builtins we create fnspec for because the type match is checked
4200 at fnspec creation time. */
4201
4202 static tree
4203 get_parm_type (tree decl, unsigned int i)
4204 {
4205 tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
4206
4207 for (unsigned int p = 0; p < i; p++)
4208 t = TREE_CHAIN (t);
4209 return TREE_VALUE (t);
4210 }
4211
4212 /* Return access mode for argument I of call E with FNSPEC. */
4213
4214 static modref_access_node
4215 get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
4216 unsigned int i, modref_parm_map &map)
4217 {
4218 tree size = NULL_TREE;
4219 unsigned int size_arg;
4220
4221 if (!fnspec.arg_specified_p (i))
4222 ;
4223 else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
4224 {
4225 cgraph_node *node = e->caller->inlined_to
4226 ? e->caller->inlined_to : e->caller;
4227 ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
4228 ipa_edge_args *args = ipa_edge_args_sum->get (e);
4229 struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
4230
4231 if (jf)
4232 size = ipa_value_from_jfunc (caller_parms_info, jf,
4233 get_parm_type (e->callee->decl, size_arg));
4234 }
4235 else if (fnspec.arg_access_size_given_by_type_p (i))
4236 size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
4237 modref_access_node a = {0, -1, -1,
4238 map.parm_offset, map.parm_index,
4239 map.parm_offset_known, 0};
4240 poly_int64 size_hwi;
4241 if (size
4242 && poly_int_tree_p (size, &size_hwi)
4243 && coeffs_in_range_p (size_hwi, 0,
4244 HOST_WIDE_INT_MAX / BITS_PER_UNIT))
4245 {
4246 a.size = -1;
4247 a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
4248 }
4249 return a;
4250 }
4251
4252 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
4253 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
4254
4255 static bool
4256 propagate_unknown_call (cgraph_node *node,
4257 cgraph_edge *e, int ecf_flags,
4258 modref_summary *cur_summary,
4259 modref_summary_lto *cur_summary_lto,
4260 bool nontrivial_scc)
4261 {
4262 bool changed = false;
4263 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
4264 auto_vec <modref_parm_map, 32> parm_map;
4265 bool looping;
4266
4267 if (e->callee
4268 && builtin_safe_for_const_function_p (&looping, e->callee->decl))
4269 {
4270 if (looping && cur_summary && !cur_summary->side_effects)
4271 {
4272 cur_summary->side_effects = true;
4273 changed = true;
4274 }
4275 if (looping && cur_summary_lto && !cur_summary_lto->side_effects)
4276 {
4277 cur_summary_lto->side_effects = true;
4278 changed = true;
4279 }
4280 return changed;
4281 }
4282
4283 if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE))
4284 || (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
4285 || nontrivial_scc)
4286 {
4287 if (cur_summary && !cur_summary->side_effects)
4288 {
4289 cur_summary->side_effects = true;
4290 changed = true;
4291 }
4292 if (cur_summary_lto && !cur_summary_lto->side_effects)
4293 {
4294 cur_summary_lto->side_effects = true;
4295 changed = true;
4296 }
4297 if (cur_summary && !cur_summary->nondeterministic
4298 && !ignore_nondeterminism_p (node->decl, ecf_flags))
4299 {
4300 cur_summary->nondeterministic = true;
4301 changed = true;
4302 }
4303 if (cur_summary_lto && !cur_summary_lto->nondeterministic
4304 && !ignore_nondeterminism_p (node->decl, ecf_flags))
4305 {
4306 cur_summary_lto->nondeterministic = true;
4307 changed = true;
4308 }
4309 }
4310 if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
4311 return changed;
4312
4313 if (fnspec_sum
4314 && compute_parm_map (e, &parm_map))
4315 {
4316 attr_fnspec fnspec (fnspec_sum->fnspec);
4317
4318 gcc_checking_assert (fnspec.known_p ());
4319 if (fnspec.global_memory_read_p ())
4320 collapse_loads (cur_summary, cur_summary_lto);
4321 else
4322 {
4323 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4324 for (unsigned i = 0; i < parm_map.length () && t;
4325 i++, t = TREE_CHAIN (t))
4326 if (!POINTER_TYPE_P (TREE_VALUE (t)))
4327 ;
4328 else if (!fnspec.arg_specified_p (i)
4329 || fnspec.arg_maybe_read_p (i))
4330 {
4331 modref_parm_map map = parm_map[i];
4332 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4333 continue;
4334 if (map.parm_index == MODREF_UNKNOWN_PARM)
4335 {
4336 collapse_loads (cur_summary, cur_summary_lto);
4337 break;
4338 }
4339 if (cur_summary)
4340 changed |= cur_summary->loads->insert
4341 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
4342 if (cur_summary_lto)
4343 changed |= cur_summary_lto->loads->insert
4344 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
4345 }
4346 }
4347 if (ignore_stores_p (node->decl, ecf_flags))
4348 ;
4349 else if (fnspec.global_memory_written_p ())
4350 collapse_stores (cur_summary, cur_summary_lto);
4351 else
4352 {
4353 tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4354 for (unsigned i = 0; i < parm_map.length () && t;
4355 i++, t = TREE_CHAIN (t))
4356 if (!POINTER_TYPE_P (TREE_VALUE (t)))
4357 ;
4358 else if (!fnspec.arg_specified_p (i)
4359 || fnspec.arg_maybe_written_p (i))
4360 {
4361 modref_parm_map map = parm_map[i];
4362 if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4363 continue;
4364 if (map.parm_index == MODREF_UNKNOWN_PARM)
4365 {
4366 collapse_stores (cur_summary, cur_summary_lto);
4367 break;
4368 }
4369 if (cur_summary)
4370 changed |= cur_summary->stores->insert
4371 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
4372 if (cur_summary_lto)
4373 changed |= cur_summary_lto->stores->insert
4374 (0, 0, get_access_for_fnspec (e, fnspec, i, map), false);
4375 }
4376 }
4377 if (fnspec.errno_maybe_written_p () && flag_errno_math)
4378 {
4379 if (cur_summary && !cur_summary->writes_errno)
4380 {
4381 cur_summary->writes_errno = true;
4382 changed = true;
4383 }
4384 if (cur_summary_lto && !cur_summary_lto->writes_errno)
4385 {
4386 cur_summary_lto->writes_errno = true;
4387 changed = true;
4388 }
4389 }
4390 return changed;
4391 }
4392 if (dump_file)
4393 fprintf (dump_file, " collapsing loads\n");
4394 changed |= collapse_loads (cur_summary, cur_summary_lto);
4395 if (!ignore_stores_p (node->decl, ecf_flags))
4396 {
4397 if (dump_file)
4398 fprintf (dump_file, " collapsing stores\n");
4399 changed |= collapse_stores (cur_summary, cur_summary_lto);
4400 }
4401 return changed;
4402 }
4403
4404 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
4405 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
4406
4407 static void
4408 remove_useless_summaries (cgraph_node *node,
4409 modref_summary **cur_summary_ptr,
4410 modref_summary_lto **cur_summary_lto_ptr,
4411 int ecf_flags)
4412 {
4413 if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
4414 {
4415 optimization_summaries->remove (node);
4416 *cur_summary_ptr = NULL;
4417 }
4418 if (*cur_summary_lto_ptr
4419 && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
4420 {
4421 summaries_lto->remove (node);
4422 *cur_summary_lto_ptr = NULL;
4423 }
4424 }
4425
4426 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4427 and propagate loads/stores. */
4428
4429 static bool
4430 modref_propagate_in_scc (cgraph_node *component_node)
4431 {
4432 bool changed = true;
4433 bool first = true;
4434 int iteration = 0;
4435
4436 while (changed)
4437 {
4438 bool nontrivial_scc
4439 = ((struct ipa_dfs_info *) component_node->aux)->next_cycle;
4440 changed = false;
4441 for (struct cgraph_node *cur = component_node; cur;
4442 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4443 {
4444 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
4445 modref_summary *cur_summary = optimization_summaries
4446 ? optimization_summaries->get (node)
4447 : NULL;
4448 modref_summary_lto *cur_summary_lto = summaries_lto
4449 ? summaries_lto->get (node)
4450 : NULL;
4451
4452 if (!cur_summary && !cur_summary_lto)
4453 continue;
4454
4455 int cur_ecf_flags = flags_from_decl_or_type (node->decl);
4456
4457 if (dump_file)
4458 fprintf (dump_file, " Processing %s%s%s\n",
4459 cur->dump_name (),
4460 TREE_READONLY (cur->decl) ? " (const)" : "",
4461 DECL_PURE_P (cur->decl) ? " (pure)" : "");
4462
4463 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
4464 {
4465 if (dump_file)
4466 fprintf (dump_file, " Indirect call\n");
4467 if (propagate_unknown_call
4468 (node, e, e->indirect_info->ecf_flags,
4469 cur_summary, cur_summary_lto,
4470 nontrivial_scc))
4471 {
4472 changed = true;
4473 remove_useless_summaries (node, &cur_summary,
4474 &cur_summary_lto,
4475 cur_ecf_flags);
4476 if (!cur_summary && !cur_summary_lto)
4477 break;
4478 }
4479 }
4480
4481 if (!cur_summary && !cur_summary_lto)
4482 continue;
4483
4484 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
4485 callee_edge = callee_edge->next_callee)
4486 {
4487 int flags = flags_from_decl_or_type (callee_edge->callee->decl);
4488 modref_summary *callee_summary = NULL;
4489 modref_summary_lto *callee_summary_lto = NULL;
4490 struct cgraph_node *callee;
4491
4492 if (!callee_edge->inline_failed
4493 || ((flags & (ECF_CONST | ECF_NOVOPS))
4494 && !(flags & ECF_LOOPING_CONST_OR_PURE)))
4495 continue;
4496
4497 /* Get the callee and its summary. */
4498 enum availability avail;
4499 callee = callee_edge->callee->function_or_virtual_thunk_symbol
4500 (&avail, cur);
4501
4502 /* It is not necessary to re-process calls outside of the
4503 SCC component. */
4504 if (iteration > 0
4505 && (!callee->aux
4506 || ((struct ipa_dfs_info *)cur->aux)->scc_no
4507 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
4508 continue;
4509
4510 if (dump_file)
4511 fprintf (dump_file, " Call to %s\n",
4512 callee_edge->callee->dump_name ());
4513
4514 bool ignore_stores = ignore_stores_p (cur->decl, flags);
4515
4516 if (avail <= AVAIL_INTERPOSABLE)
4517 {
4518 if (dump_file)
4519 fprintf (dump_file, " Call target interposable"
4520 " or not available\n");
4521 changed |= propagate_unknown_call
4522 (node, callee_edge, flags,
4523 cur_summary, cur_summary_lto,
4524 nontrivial_scc);
4525 if (!cur_summary && !cur_summary_lto)
4526 break;
4527 continue;
4528 }
4529
4530 /* We don't know anything about CALLEE, hence we cannot tell
4531 anything about the entire component. */
4532
4533 if (cur_summary
4534 && !(callee_summary = optimization_summaries->get (callee)))
4535 {
4536 if (dump_file)
4537 fprintf (dump_file, " No call target summary\n");
4538 changed |= propagate_unknown_call
4539 (node, callee_edge, flags,
4540 cur_summary, NULL,
4541 nontrivial_scc);
4542 }
4543 if (cur_summary_lto
4544 && !(callee_summary_lto = summaries_lto->get (callee)))
4545 {
4546 if (dump_file)
4547 fprintf (dump_file, " No call target summary\n");
4548 changed |= propagate_unknown_call
4549 (node, callee_edge, flags,
4550 NULL, cur_summary_lto,
4551 nontrivial_scc);
4552 }
4553
4554 if (callee_summary && !cur_summary->side_effects
4555 && (callee_summary->side_effects
4556 || callee_edge->recursive_p ()))
4557 {
4558 cur_summary->side_effects = true;
4559 changed = true;
4560 }
4561 if (callee_summary_lto && !cur_summary_lto->side_effects
4562 && (callee_summary_lto->side_effects
4563 || callee_edge->recursive_p ()))
4564 {
4565 cur_summary_lto->side_effects = true;
4566 changed = true;
4567 }
4568 if (callee_summary && !cur_summary->nondeterministic
4569 && callee_summary->nondeterministic
4570 && !ignore_nondeterminism_p (cur->decl, flags))
4571 {
4572 cur_summary->nondeterministic = true;
4573 changed = true;
4574 }
4575 if (callee_summary_lto && !cur_summary_lto->nondeterministic
4576 && callee_summary_lto->nondeterministic
4577 && !ignore_nondeterminism_p (cur->decl, flags))
4578 {
4579 cur_summary_lto->nondeterministic = true;
4580 changed = true;
4581 }
4582 if (flags & (ECF_CONST | ECF_NOVOPS))
4583 continue;
4584
4585 /* We can not safely optimize based on summary of callee if it
4586 does not always bind to current def: it is possible that
4587 memory load was optimized out earlier which may not happen in
4588 the interposed variant. */
4589 if (!callee_edge->binds_to_current_def_p ())
4590 {
4591 if (cur_summary && !cur_summary->calls_interposable)
4592 {
4593 cur_summary->calls_interposable = true;
4594 changed = true;
4595 }
4596 if (cur_summary_lto && !cur_summary_lto->calls_interposable)
4597 {
4598 cur_summary_lto->calls_interposable = true;
4599 changed = true;
4600 }
4601 if (dump_file)
4602 fprintf (dump_file, " May not bind local;"
4603 " collapsing loads\n");
4604 }
4605
4606
4607 auto_vec <modref_parm_map, 32> parm_map;
4608 modref_parm_map chain_map;
4609 /* TODO: Once we get jump functions for static chains we could
4610 compute this. */
4611 chain_map.parm_index = MODREF_UNKNOWN_PARM;
4612
4613 compute_parm_map (callee_edge, &parm_map);
4614
4615 /* Merge in callee's information. */
4616 if (callee_summary)
4617 {
4618 changed |= cur_summary->loads->merge
4619 (callee_summary->loads, &parm_map,
4620 &chain_map, !first);
4621 if (!ignore_stores)
4622 {
4623 changed |= cur_summary->stores->merge
4624 (callee_summary->stores, &parm_map,
4625 &chain_map, !first);
4626 if (!cur_summary->writes_errno
4627 && callee_summary->writes_errno)
4628 {
4629 cur_summary->writes_errno = true;
4630 changed = true;
4631 }
4632 }
4633 }
4634 if (callee_summary_lto)
4635 {
4636 changed |= cur_summary_lto->loads->merge
4637 (callee_summary_lto->loads, &parm_map,
4638 &chain_map, !first);
4639 if (!ignore_stores)
4640 {
4641 changed |= cur_summary_lto->stores->merge
4642 (callee_summary_lto->stores, &parm_map,
4643 &chain_map, !first);
4644 if (!cur_summary_lto->writes_errno
4645 && callee_summary_lto->writes_errno)
4646 {
4647 cur_summary_lto->writes_errno = true;
4648 changed = true;
4649 }
4650 }
4651 }
4652 if (changed)
4653 remove_useless_summaries (node, &cur_summary,
4654 &cur_summary_lto,
4655 cur_ecf_flags);
4656 if (!cur_summary && !cur_summary_lto)
4657 break;
4658 if (dump_file && changed)
4659 {
4660 if (cur_summary)
4661 cur_summary->dump (dump_file);
4662 if (cur_summary_lto)
4663 cur_summary_lto->dump (dump_file);
4664 dump_modref_edge_summaries (dump_file, node, 4);
4665 }
4666 }
4667 }
4668 iteration++;
4669 first = false;
4670 }
4671 if (dump_file)
4672 fprintf (dump_file,
4673 "Propagation finished in %i iterations\n", iteration);
4674 bool pureconst = false;
4675 for (struct cgraph_node *cur = component_node; cur;
4676 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4677 if (!cur->inlined_to && opt_for_fn (cur->decl, flag_ipa_pure_const))
4678 {
4679 modref_summary *summary = optimization_summaries
4680 ? optimization_summaries->get (cur)
4681 : NULL;
4682 modref_summary_lto *summary_lto = summaries_lto
4683 ? summaries_lto->get (cur)
4684 : NULL;
4685 if (summary && !summary->stores->every_base && !summary->stores->bases
4686 && !summary->nondeterministic)
4687 {
4688 if (!summary->loads->every_base && !summary->loads->bases
4689 && !summary->calls_interposable)
4690 pureconst |= ipa_make_function_const
4691 (cur, summary->side_effects, false);
4692 else
4693 pureconst |= ipa_make_function_pure
4694 (cur, summary->side_effects, false);
4695 }
4696 if (summary_lto && !summary_lto->stores->every_base
4697 && !summary_lto->stores->bases && !summary_lto->nondeterministic)
4698 {
4699 if (!summary_lto->loads->every_base && !summary_lto->loads->bases
4700 && !summary_lto->calls_interposable)
4701 pureconst |= ipa_make_function_const
4702 (cur, summary_lto->side_effects, false);
4703 else
4704 pureconst |= ipa_make_function_pure
4705 (cur, summary_lto->side_effects, false);
4706 }
4707 }
4708 return pureconst;
4709 }
4710
4711 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
4712
4713 static void
4714 modref_propagate_dump_scc (cgraph_node *component_node)
4715 {
4716 for (struct cgraph_node *cur = component_node; cur;
4717 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4718 if (!cur->inlined_to)
4719 {
4720 modref_summary *cur_summary = optimization_summaries
4721 ? optimization_summaries->get (cur)
4722 : NULL;
4723 modref_summary_lto *cur_summary_lto = summaries_lto
4724 ? summaries_lto->get (cur)
4725 : NULL;
4726
4727 fprintf (dump_file, "Propagated modref for %s%s%s\n",
4728 cur->dump_name (),
4729 TREE_READONLY (cur->decl) ? " (const)" : "",
4730 DECL_PURE_P (cur->decl) ? " (pure)" : "");
4731 if (optimization_summaries)
4732 {
4733 if (cur_summary)
4734 cur_summary->dump (dump_file);
4735 else
4736 fprintf (dump_file, " Not tracked\n");
4737 }
4738 if (summaries_lto)
4739 {
4740 if (cur_summary_lto)
4741 cur_summary_lto->dump (dump_file);
4742 else
4743 fprintf (dump_file, " Not tracked (lto)\n");
4744 }
4745 }
4746 }
4747
4748 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
4749 and SUMMARY_LTO to CUR_SUMMARY_LTO.
4750 Return true if something changed. */
4751
4752 static bool
4753 modref_merge_call_site_flags (escape_summary *sum,
4754 modref_summary *cur_summary,
4755 modref_summary_lto *cur_summary_lto,
4756 modref_summary *summary,
4757 modref_summary_lto *summary_lto,
4758 tree caller,
4759 cgraph_edge *e,
4760 int caller_ecf_flags,
4761 int callee_ecf_flags,
4762 bool binds_to_current_def)
4763 {
4764 escape_entry *ee;
4765 unsigned int i;
4766 bool changed = false;
4767 bool ignore_stores = ignore_stores_p (caller, callee_ecf_flags);
4768
4769 /* If we have no useful info to propagate. */
4770 if ((!cur_summary || !cur_summary->arg_flags.length ())
4771 && (!cur_summary_lto || !cur_summary_lto->arg_flags.length ()))
4772 return false;
4773
4774 FOR_EACH_VEC_ELT (sum->esc, i, ee)
4775 {
4776 int flags = 0;
4777 int flags_lto = 0;
4778 /* Returning the value is already accounted to at local propagation. */
4779 int implicit_flags = EAF_NOT_RETURNED_DIRECTLY
4780 | EAF_NOT_RETURNED_INDIRECTLY;
4781
4782 if (summary && ee->arg < summary->arg_flags.length ())
4783 flags = summary->arg_flags[ee->arg];
4784 if (summary_lto
4785 && ee->arg < summary_lto->arg_flags.length ())
4786 flags_lto = summary_lto->arg_flags[ee->arg];
4787 if (!ee->direct)
4788 {
4789 flags = deref_flags (flags, ignore_stores);
4790 flags_lto = deref_flags (flags_lto, ignore_stores);
4791 }
4792 if (ignore_stores)
4793 implicit_flags |= ignore_stores_eaf_flags;
4794 if (callee_ecf_flags & ECF_PURE)
4795 implicit_flags |= implicit_pure_eaf_flags;
4796 if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
4797 implicit_flags |= implicit_const_eaf_flags;
4798 class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
4799 if (fnspec_sum)
4800 {
4801 attr_fnspec fnspec (fnspec_sum->fnspec);
4802 implicit_flags |= fnspec.arg_eaf_flags (ee->arg);
4803 }
4804 if (!ee->direct)
4805 implicit_flags = deref_flags (implicit_flags, ignore_stores);
4806 flags |= implicit_flags;
4807 flags_lto |= implicit_flags;
4808 if (!binds_to_current_def && (flags || flags_lto))
4809 {
4810 flags = interposable_eaf_flags (flags, implicit_flags);
4811 flags_lto = interposable_eaf_flags (flags_lto, implicit_flags);
4812 }
4813 if (!(flags & EAF_UNUSED)
4814 && cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ())
4815 {
4816 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
4817 ? cur_summary->retslot_flags
4818 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
4819 ? cur_summary->static_chain_flags
4820 : cur_summary->arg_flags[ee->parm_index];
4821 if ((f & flags) != f)
4822 {
4823 f = remove_useless_eaf_flags
4824 (f & flags, caller_ecf_flags,
4825 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
4826 changed = true;
4827 }
4828 }
4829 if (!(flags_lto & EAF_UNUSED)
4830 && cur_summary_lto
4831 && ee->parm_index < (int)cur_summary_lto->arg_flags.length ())
4832 {
4833 eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
4834 ? cur_summary_lto->retslot_flags
4835 : ee->parm_index == MODREF_STATIC_CHAIN_PARM
4836 ? cur_summary_lto->static_chain_flags
4837 : cur_summary_lto->arg_flags[ee->parm_index];
4838 if ((f & flags_lto) != f)
4839 {
4840 f = remove_useless_eaf_flags
4841 (f & flags_lto, caller_ecf_flags,
4842 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
4843 changed = true;
4844 }
4845 }
4846 }
4847 return changed;
4848 }
4849
4850 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4851 and propagate arg flags. */
4852
4853 static void
4854 modref_propagate_flags_in_scc (cgraph_node *component_node)
4855 {
4856 bool changed = true;
4857 int iteration = 0;
4858
4859 while (changed)
4860 {
4861 changed = false;
4862 for (struct cgraph_node *cur = component_node; cur;
4863 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4864 {
4865 cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
4866 modref_summary *cur_summary = optimization_summaries
4867 ? optimization_summaries->get (node)
4868 : NULL;
4869 modref_summary_lto *cur_summary_lto = summaries_lto
4870 ? summaries_lto->get (node)
4871 : NULL;
4872
4873 if (!cur_summary && !cur_summary_lto)
4874 continue;
4875 int caller_ecf_flags = flags_from_decl_or_type (cur->decl);
4876
4877 if (dump_file)
4878 fprintf (dump_file, " Processing %s%s%s\n",
4879 cur->dump_name (),
4880 TREE_READONLY (cur->decl) ? " (const)" : "",
4881 DECL_PURE_P (cur->decl) ? " (pure)" : "");
4882
4883 for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
4884 {
4885 escape_summary *sum = escape_summaries->get (e);
4886
4887 if (!sum || (e->indirect_info->ecf_flags
4888 & (ECF_CONST | ECF_NOVOPS)))
4889 continue;
4890
4891 changed |= modref_merge_call_site_flags
4892 (sum, cur_summary, cur_summary_lto,
4893 NULL, NULL,
4894 node->decl,
4895 e,
4896 caller_ecf_flags,
4897 e->indirect_info->ecf_flags,
4898 false);
4899 }
4900
4901 if (!cur_summary && !cur_summary_lto)
4902 continue;
4903
4904 for (cgraph_edge *callee_edge = cur->callees; callee_edge;
4905 callee_edge = callee_edge->next_callee)
4906 {
4907 int ecf_flags = flags_from_decl_or_type
4908 (callee_edge->callee->decl);
4909 modref_summary *callee_summary = NULL;
4910 modref_summary_lto *callee_summary_lto = NULL;
4911 struct cgraph_node *callee;
4912
4913 if (ecf_flags & (ECF_CONST | ECF_NOVOPS)
4914 || !callee_edge->inline_failed)
4915 continue;
4916 /* Get the callee and its summary. */
4917 enum availability avail;
4918 callee = callee_edge->callee->function_or_virtual_thunk_symbol
4919 (&avail, cur);
4920
4921 /* It is not necessary to re-process calls outside of the
4922 SCC component. */
4923 if (iteration > 0
4924 && (!callee->aux
4925 || ((struct ipa_dfs_info *)cur->aux)->scc_no
4926 != ((struct ipa_dfs_info *)callee->aux)->scc_no))
4927 continue;
4928
4929 escape_summary *sum = escape_summaries->get (callee_edge);
4930 if (!sum)
4931 continue;
4932
4933 if (dump_file)
4934 fprintf (dump_file, " Call to %s\n",
4935 callee_edge->callee->dump_name ());
4936
4937 if (avail <= AVAIL_INTERPOSABLE
4938 || callee_edge->call_stmt_cannot_inline_p)
4939 ;
4940 else
4941 {
4942 if (cur_summary)
4943 callee_summary = optimization_summaries->get (callee);
4944 if (cur_summary_lto)
4945 callee_summary_lto = summaries_lto->get (callee);
4946 }
4947 changed |= modref_merge_call_site_flags
4948 (sum, cur_summary, cur_summary_lto,
4949 callee_summary, callee_summary_lto,
4950 node->decl,
4951 callee_edge,
4952 caller_ecf_flags,
4953 ecf_flags,
4954 callee->binds_to_current_def_p ());
4955 if (dump_file && changed)
4956 {
4957 if (cur_summary)
4958 cur_summary->dump (dump_file);
4959 if (cur_summary_lto)
4960 cur_summary_lto->dump (dump_file);
4961 }
4962 }
4963 }
4964 iteration++;
4965 }
4966 if (dump_file)
4967 fprintf (dump_file,
4968 "Propagation of flags finished in %i iterations\n", iteration);
4969 }
4970
4971 } /* ANON namespace. */
4972
4973 /* Call EDGE was inlined; merge summary from callee to the caller. */
4974
4975 void
4976 ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
4977 {
4978 if (!summaries && !summaries_lto)
4979 return;
4980
4981 struct cgraph_node *to = (edge->caller->inlined_to
4982 ? edge->caller->inlined_to : edge->caller);
4983 class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
4984 class modref_summary_lto *to_info_lto = summaries_lto
4985 ? summaries_lto->get (to) : NULL;
4986
4987 if (!to_info && !to_info_lto)
4988 {
4989 if (summaries)
4990 summaries->remove (edge->callee);
4991 if (summaries_lto)
4992 summaries_lto->remove (edge->callee);
4993 remove_modref_edge_summaries (edge->callee);
4994 return;
4995 }
4996
4997 class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
4998 : NULL;
4999 class modref_summary_lto *callee_info_lto
5000 = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
5001 int flags = flags_from_decl_or_type (edge->callee->decl);
5002 bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
5003
5004 if (!callee_info && to_info)
5005 {
5006 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5007 to_info->loads->collapse ();
5008 if (!ignore_stores)
5009 to_info->stores->collapse ();
5010 }
5011 if (!callee_info_lto && to_info_lto)
5012 {
5013 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5014 to_info_lto->loads->collapse ();
5015 if (!ignore_stores)
5016 to_info_lto->stores->collapse ();
5017 }
5018 if (callee_info || callee_info_lto)
5019 {
5020 auto_vec <modref_parm_map, 32> parm_map;
5021 modref_parm_map chain_map;
5022 /* TODO: Once we get jump functions for static chains we could
5023 compute this. */
5024 chain_map.parm_index = MODREF_UNKNOWN_PARM;
5025
5026 compute_parm_map (edge, &parm_map);
5027
5028 if (!ignore_stores)
5029 {
5030 if (to_info && callee_info)
5031 to_info->stores->merge (callee_info->stores, &parm_map,
5032 &chain_map, false);
5033 if (to_info_lto && callee_info_lto)
5034 to_info_lto->stores->merge (callee_info_lto->stores, &parm_map,
5035 &chain_map, false);
5036 }
5037 if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5038 {
5039 if (to_info && callee_info)
5040 to_info->loads->merge (callee_info->loads, &parm_map,
5041 &chain_map, false);
5042 if (to_info_lto && callee_info_lto)
5043 to_info_lto->loads->merge (callee_info_lto->loads, &parm_map,
5044 &chain_map, false);
5045 }
5046 }
5047
5048 /* Now merge escape summaries.
5049 For every escape to the callee we need to merge calle flags
5050 and remap calees escapes. */
5051 class escape_summary *sum = escape_summaries->get (edge);
5052 int max_escape = -1;
5053 escape_entry *ee;
5054 unsigned int i;
5055
5056 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
5057 FOR_EACH_VEC_ELT (sum->esc, i, ee)
5058 if ((int)ee->arg > max_escape)
5059 max_escape = ee->arg;
5060
5061 auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
5062 emap.safe_grow (max_escape + 1, true);
5063 for (i = 0; (int)i < max_escape + 1; i++)
5064 emap[i] = vNULL;
5065
5066 if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
5067 FOR_EACH_VEC_ELT (sum->esc, i, ee)
5068 {
5069 bool needed = false;
5070 /* TODO: We do not have jump functions for return slots, so we
5071 never propagate them to outer function. */
5072 if (ee->parm_index < 0)
5073 continue;
5074 if (to_info && (int)to_info->arg_flags.length () > ee->parm_index)
5075 {
5076 int flags = callee_info
5077 && callee_info->arg_flags.length () > ee->arg
5078 ? callee_info->arg_flags[ee->arg] : 0;
5079 if (!ee->direct)
5080 flags = deref_flags (flags, ignore_stores);
5081 else if (ignore_stores)
5082 flags |= ignore_stores_eaf_flags;
5083 flags |= ee->min_flags;
5084 to_info->arg_flags[ee->parm_index] &= flags;
5085 if (to_info->arg_flags[ee->parm_index])
5086 needed = true;
5087 }
5088 if (to_info_lto
5089 && (int)to_info_lto->arg_flags.length () > ee->parm_index)
5090 {
5091 int flags = callee_info_lto
5092 && callee_info_lto->arg_flags.length () > ee->arg
5093 ? callee_info_lto->arg_flags[ee->arg] : 0;
5094 if (!ee->direct)
5095 flags = deref_flags (flags, ignore_stores);
5096 else if (ignore_stores)
5097 flags |= ignore_stores_eaf_flags;
5098 flags |= ee->min_flags;
5099 to_info_lto->arg_flags[ee->parm_index] &= flags;
5100 if (to_info_lto->arg_flags[ee->parm_index])
5101 needed = true;
5102 }
5103 struct escape_map entry = {ee->parm_index, ee->direct};
5104 if (needed)
5105 emap[ee->arg].safe_push (entry);
5106 }
5107 update_escape_summary (edge->callee, emap, ignore_stores);
5108 for (i = 0; (int)i < max_escape + 1; i++)
5109 emap[i].release ();
5110 if (sum)
5111 escape_summaries->remove (edge);
5112
5113 if (summaries)
5114 {
5115 if (to_info && !to_info->useful_p (flags))
5116 {
5117 if (dump_file)
5118 fprintf (dump_file, "Removed mod-ref summary for %s\n",
5119 to->dump_name ());
5120 summaries->remove (to);
5121 to_info = NULL;
5122 }
5123 else if (to_info && dump_file)
5124 {
5125 if (dump_file)
5126 fprintf (dump_file, "Updated mod-ref summary for %s\n",
5127 to->dump_name ());
5128 to_info->dump (dump_file);
5129 }
5130 if (callee_info)
5131 summaries->remove (edge->callee);
5132 }
5133 if (summaries_lto)
5134 {
5135 if (to_info_lto && !to_info_lto->useful_p (flags))
5136 {
5137 if (dump_file)
5138 fprintf (dump_file, "Removed mod-ref summary for %s\n",
5139 to->dump_name ());
5140 summaries_lto->remove (to);
5141 to_info_lto = NULL;
5142 }
5143 else if (to_info_lto && dump_file)
5144 {
5145 if (dump_file)
5146 fprintf (dump_file, "Updated mod-ref summary for %s\n",
5147 to->dump_name ());
5148 to_info_lto->dump (dump_file);
5149 }
5150 if (callee_info_lto)
5151 summaries_lto->remove (edge->callee);
5152 }
5153 if (!to_info && !to_info_lto)
5154 remove_modref_edge_summaries (to);
5155 return;
5156 }
5157
5158 /* Run the IPA pass. This will take a function's summaries and calls and
5159 construct new summaries which represent a transitive closure. So that
5160 summary of an analyzed function contains information about the loads and
5161 stores that the function or any function that it calls does. */
5162
5163 unsigned int
5164 pass_ipa_modref::execute (function *)
5165 {
5166 if (!summaries && !summaries_lto)
5167 return 0;
5168 bool pureconst = false;
5169
5170 if (optimization_summaries)
5171 ggc_delete (optimization_summaries);
5172 optimization_summaries = summaries;
5173 summaries = NULL;
5174
5175 struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
5176 symtab->cgraph_count);
5177 int order_pos;
5178 order_pos = ipa_reduced_postorder (order, true, ignore_edge);
5179 int i;
5180
5181 /* Iterate over all strongly connected components in post-order. */
5182 for (i = 0; i < order_pos; i++)
5183 {
5184 /* Get the component's representative. That's just any node in the
5185 component from which we can traverse the entire component. */
5186 struct cgraph_node *component_node = order[i];
5187
5188 if (dump_file)
5189 fprintf (dump_file, "\n\nStart of SCC component\n");
5190
5191 pureconst |= modref_propagate_in_scc (component_node);
5192 modref_propagate_flags_in_scc (component_node);
5193 if (optimization_summaries)
5194 for (struct cgraph_node *cur = component_node; cur;
5195 cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5196 if (modref_summary *sum = optimization_summaries->get (cur))
5197 sum->finalize (cur->decl);
5198 if (dump_file)
5199 modref_propagate_dump_scc (component_node);
5200 }
5201 cgraph_node *node;
5202 FOR_EACH_FUNCTION (node)
5203 update_signature (node);
5204 if (summaries_lto)
5205 ((modref_summaries_lto *)summaries_lto)->propagated = true;
5206 ipa_free_postorder_info ();
5207 free (order);
5208 delete fnspec_summaries;
5209 fnspec_summaries = NULL;
5210 delete escape_summaries;
5211 escape_summaries = NULL;
5212
5213 /* If we posibly made constructors const/pure we may need to remove
5214 them. */
5215 return pureconst ? TODO_remove_functions : 0;
5216 }
5217
5218 /* Summaries must stay alive until end of compilation. */
5219
5220 void
5221 ipa_modref_c_finalize ()
5222 {
5223 if (optimization_summaries)
5224 ggc_delete (optimization_summaries);
5225 optimization_summaries = NULL;
5226 if (summaries_lto)
5227 ggc_delete (summaries_lto);
5228 summaries_lto = NULL;
5229 if (fnspec_summaries)
5230 delete fnspec_summaries;
5231 fnspec_summaries = NULL;
5232 if (escape_summaries)
5233 delete escape_summaries;
5234 escape_summaries = NULL;
5235 }
5236
5237 #include "gt-ipa-modref.h"