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