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