Branch data Line data Source code
1 : : /* Search for references that a functions loads or stores.
2 : : Copyright (C) 2020-2025 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 : 924435 : fnspec_summary ()
106 : 924435 : : fnspec (NULL)
107 : : {
108 : : }
109 : :
110 : 924435 : ~fnspec_summary ()
111 : : {
112 : 924435 : free (fnspec);
113 : 924435 : }
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 : 150809 : fnspec_summaries_t (symbol_table *symtab)
122 : 301618 : : call_summary <fnspec_summary *> (symtab) {}
123 : : /* Hook that is called by summary when an edge is duplicated. */
124 : 359510 : void duplicate (cgraph_edge *,
125 : : cgraph_edge *,
126 : : fnspec_summary *src,
127 : : fnspec_summary *dst) final override
128 : : {
129 : 359510 : dst->fnspec = xstrdup (src->fnspec);
130 : 359510 : }
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 : 3592 : dump_eaf_flags (FILE *out, int flags, bool newline = true)
153 : : {
154 : 3592 : if (flags & EAF_UNUSED)
155 : 286 : fprintf (out, " unused");
156 : 3592 : if (flags & EAF_NO_DIRECT_CLOBBER)
157 : 2271 : fprintf (out, " no_direct_clobber");
158 : 3592 : if (flags & EAF_NO_INDIRECT_CLOBBER)
159 : 2174 : fprintf (out, " no_indirect_clobber");
160 : 3592 : if (flags & EAF_NO_DIRECT_ESCAPE)
161 : 2797 : fprintf (out, " no_direct_escape");
162 : 3592 : if (flags & EAF_NO_INDIRECT_ESCAPE)
163 : 2433 : fprintf (out, " no_indirect_escape");
164 : 3592 : if (flags & EAF_NOT_RETURNED_DIRECTLY)
165 : 2496 : fprintf (out, " not_returned_directly");
166 : 3592 : if (flags & EAF_NOT_RETURNED_INDIRECTLY)
167 : 2372 : fprintf (out, " not_returned_indirectly");
168 : 3592 : if (flags & EAF_NO_DIRECT_READ)
169 : 2093 : fprintf (out, " no_direct_read");
170 : 3592 : if (flags & EAF_NO_INDIRECT_READ)
171 : 2239 : fprintf (out, " no_indirect_read");
172 : 3592 : if (newline)
173 : 3516 : fprintf (out, "\n");
174 : 3592 : }
175 : :
176 : 722536 : 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 : 150809 : escape_summaries_t (symbol_table *symtab)
197 : 301618 : : call_summary <escape_summary *> (symtab) {}
198 : : /* Hook that is called by summary when an edge is duplicated. */
199 : 139483 : void duplicate (cgraph_edge *,
200 : : cgraph_edge *,
201 : : escape_summary *src,
202 : : escape_summary *dst) final override
203 : : {
204 : 139483 : dst->esc = src->esc.copy ();
205 : 139483 : }
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 : 280509 : modref_summaries (symbol_table *symtab)
221 : 561018 : : 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 : 280509 : static modref_summaries *create_ggc (symbol_table *symtab)
228 : : {
229 : 280509 : return new (ggc_alloc_no_dtor<modref_summaries> ())
230 : 280509 : 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 : 27436 : modref_summaries_lto (symbol_table *symtab)
244 : 27436 : : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
245 : 54872 : 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 : 27436 : static modref_summaries_lto *create_ggc (symbol_table *symtab)
252 : : {
253 : 27436 : return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
254 : 27436 : 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 : 7014036 : modref_summary::modref_summary ()
280 : 7014036 : : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
281 : 7014036 : writes_errno (false), side_effects (false), nondeterministic (false),
282 : 7014036 : calls_interposable (false), global_memory_read (false),
283 : 7014036 : global_memory_written (false), try_dse (false)
284 : : {
285 : 7014036 : }
286 : :
287 : 7013374 : modref_summary::~modref_summary ()
288 : : {
289 : 7013374 : if (loads)
290 : 5109516 : ggc_delete (loads);
291 : 7013374 : if (stores)
292 : 5109516 : ggc_delete (stores);
293 : 7013374 : }
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 : 15760485 : remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
300 : : {
301 : 15760485 : if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
302 : 1468618 : eaf_flags &= ~implicit_const_eaf_flags;
303 : 14291867 : else if (ecf_flags & ECF_PURE)
304 : 2195028 : eaf_flags &= ~implicit_pure_eaf_flags;
305 : 12096839 : else if ((ecf_flags & ECF_NORETURN) || returns_void)
306 : 2838242 : eaf_flags &= ~(EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY);
307 : 15760485 : return eaf_flags;
308 : : }
309 : :
310 : : /* Return true if FLAGS holds some useful information. */
311 : :
312 : : static bool
313 : 5463003 : eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags)
314 : : {
315 : 6150526 : for (unsigned i = 0; i < flags.length (); i++)
316 : 3792571 : 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 : 71932885 : modref_summary::useful_p (int ecf_flags, bool check_flags)
326 : : {
327 : 71932885 : if (arg_flags.length () && !check_flags)
328 : : return true;
329 : 28355017 : if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
330 : : return true;
331 : 25448261 : arg_flags.release ();
332 : 25448261 : if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
333 : : return true;
334 : 25434726 : if (check_flags
335 : 25434726 : && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
336 : : return true;
337 : 25392341 : if (ecf_flags & ECF_CONST)
338 : 1105859 : return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
339 : 24828609 : if (loads && !loads->every_base)
340 : : return true;
341 : : else
342 : 5532201 : kills.release ();
343 : 5532201 : if (ecf_flags & ECF_PURE)
344 : 163353 : return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
345 : 5418088 : 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 : 161067 : modref_summary_lto::modref_summary_lto ()
377 : 161067 : : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
378 : 161067 : writes_errno (false), side_effects (false), nondeterministic (false),
379 : 161067 : calls_interposable (false)
380 : : {
381 : 161067 : }
382 : :
383 : 161061 : modref_summary_lto::~modref_summary_lto ()
384 : : {
385 : 161061 : if (loads)
386 : 160468 : ggc_delete (loads);
387 : 161061 : if (stores)
388 : 160468 : ggc_delete (stores);
389 : 161061 : }
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 : 908899 : modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
397 : : {
398 : 908899 : if (arg_flags.length () && !check_flags)
399 : : return true;
400 : 602524 : if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
401 : : return true;
402 : 404232 : arg_flags.release ();
403 : 404232 : if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
404 : : return true;
405 : 403530 : if (check_flags
406 : 403530 : && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
407 : : return true;
408 : 403133 : if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
409 : 30112 : return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
410 : 387765 : if (loads && !loads->every_base)
411 : : return true;
412 : : else
413 : 74438 : kills.release ();
414 : 74438 : if (ecf_flags & ECF_PURE)
415 : 8177 : return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
416 : 69846 : return stores && !stores->every_base;
417 : : }
418 : :
419 : : /* Dump records TT to OUT. */
420 : :
421 : : static void
422 : 1284 : dump_records (modref_records *tt, FILE *out)
423 : : {
424 : 1284 : if (tt->every_base)
425 : : {
426 : 155 : fprintf (out, " Every base\n");
427 : 155 : return;
428 : : }
429 : : size_t i;
430 : : modref_base_node <alias_set_type> *n;
431 : 1860 : FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
432 : : {
433 : 731 : fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
434 : 731 : 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 : 2264 : FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
442 : : {
443 : 802 : fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
444 : 802 : if (r->every_access)
445 : : {
446 : 578 : fprintf (out, " Every access\n");
447 : 578 : continue;
448 : : }
449 : : size_t k;
450 : : modref_access_node *a;
451 : 1272 : FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
452 : : {
453 : 246 : fprintf (out, " access:");
454 : 246 : 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 : 179 : dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
511 : : {
512 : 179 : int i = 0;
513 : 179 : if (!escape_summaries)
514 : : return;
515 : 120 : 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 : 194 : for (cgraph_edge *e = node->callees; e; e = e->next_callee)
527 : : {
528 : 100 : if (!e->inline_failed)
529 : 0 : dump_modref_edge_summaries (out, e->callee, depth + 1);
530 : 100 : class escape_summary *sum = escape_summaries->get (e);
531 : 100 : 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 : 100 : class fnspec_summary *fsum = fnspec_summaries->get (e);
538 : 100 : 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 : 392744 : remove_modref_edge_summaries (cgraph_node *node)
551 : : {
552 : 392744 : if (!escape_summaries)
553 : : return;
554 : 435090 : for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
555 : 42346 : escape_summaries->remove (e);
556 : 2109031 : for (cgraph_edge *e = node->callees; e; e = e->next_callee)
557 : : {
558 : 1716287 : if (!e->inline_failed)
559 : 135761 : remove_modref_edge_summaries (e->callee);
560 : 1716287 : escape_summaries->remove (e);
561 : 1716287 : fnspec_summaries->remove (e);
562 : : }
563 : : }
564 : :
565 : : /* Dump summary. */
566 : :
567 : : void
568 : 642 : modref_summary::dump (FILE *out) const
569 : : {
570 : 642 : if (loads)
571 : : {
572 : 642 : fprintf (out, " loads:\n");
573 : 642 : dump_records (loads, out);
574 : : }
575 : 642 : if (stores)
576 : : {
577 : 642 : fprintf (out, " stores:\n");
578 : 642 : dump_records (stores, out);
579 : : }
580 : 642 : if (kills.length ())
581 : : {
582 : 41 : fprintf (out, " kills:\n");
583 : 175 : for (auto kill : kills)
584 : : {
585 : 52 : fprintf (out, " ");
586 : 52 : kill.dump (out);
587 : : }
588 : : }
589 : 642 : if (writes_errno)
590 : 0 : fprintf (out, " Writes errno\n");
591 : 642 : if (side_effects)
592 : 108 : fprintf (out, " Side effects\n");
593 : 642 : if (nondeterministic)
594 : 483 : fprintf (out, " Nondeterministic\n");
595 : 642 : if (calls_interposable)
596 : 0 : fprintf (out, " Calls interposable\n");
597 : 642 : if (global_memory_read)
598 : 146 : fprintf (out, " Global memory read\n");
599 : 642 : if (global_memory_written)
600 : 113 : fprintf (out, " Global memory written\n");
601 : 642 : if (try_dse)
602 : 450 : fprintf (out, " Try dse\n");
603 : 642 : if (arg_flags.length ())
604 : : {
605 : 1306 : for (unsigned int i = 0; i < arg_flags.length (); i++)
606 : 924 : if (arg_flags[i])
607 : : {
608 : 816 : fprintf (out, " parm %i flags:", i);
609 : 816 : dump_eaf_flags (out, arg_flags[i]);
610 : : }
611 : : }
612 : 642 : if (retslot_flags)
613 : : {
614 : 4 : fprintf (out, " Retslot flags:");
615 : 4 : dump_eaf_flags (out, retslot_flags);
616 : : }
617 : 642 : if (static_chain_flags)
618 : : {
619 : 4 : fprintf (out, " Static chain flags:");
620 : 4 : dump_eaf_flags (out, static_chain_flags);
621 : : }
622 : 642 : }
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 : 4087119 : modref_summary::finalize (tree fun)
676 : : {
677 : 4087119 : global_memory_read = !loads || loads->global_access_p ();
678 : 4087119 : 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 : 4087119 : if (side_effects || global_memory_written || writes_errno)
684 : 2108119 : try_dse = false;
685 : : else
686 : : {
687 : 1979000 : try_dse = true;
688 : 1979000 : size_t i, j, k;
689 : 1979000 : int num_tests = 0, max_tests
690 : 1979000 : = opt_for_fn (fun, param_modref_max_tests);
691 : 1979000 : modref_base_node <alias_set_type> *base_node;
692 : 1979000 : modref_ref_node <alias_set_type> *ref_node;
693 : 1979000 : modref_access_node *access_node;
694 : 2539936 : FOR_EACH_VEC_SAFE_ELT (stores->bases, i, base_node)
695 : : {
696 : 603310 : if (base_node->every_ref)
697 : : {
698 : 0 : try_dse = false;
699 : 0 : break;
700 : : }
701 : 1439295 : FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
702 : : {
703 : 878359 : if (base_node->every_ref)
704 : : {
705 : : try_dse = false;
706 : : break;
707 : : }
708 : 1794524 : FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
709 : 958539 : if (num_tests++ > max_tests
710 : 958539 : || !access_node->parm_offset_known)
711 : : {
712 : 42374 : try_dse = false;
713 : 42374 : break;
714 : : }
715 : 878359 : if (!try_dse)
716 : : break;
717 : : }
718 : 603310 : if (!try_dse)
719 : : break;
720 : : }
721 : : }
722 : 4087119 : if (loads->every_base)
723 : 1188372 : load_accesses = 1;
724 : : else
725 : : {
726 : 2898747 : load_accesses = 0;
727 : 8266419 : for (auto base_node : loads->bases)
728 : : {
729 : 2201872 : if (base_node->every_ref)
730 : 5983 : load_accesses++;
731 : : else
732 : 9051313 : for (auto ref_node : base_node->refs)
733 : 2463646 : if (ref_node->every_access)
734 : 875853 : load_accesses++;
735 : : else
736 : 1587793 : load_accesses += ref_node->accesses->length ();
737 : : }
738 : : }
739 : 4087119 : }
740 : :
741 : : /* Get function summary for FUNC if it exists, return NULL otherwise. */
742 : :
743 : : modref_summary *
744 : 473259610 : get_modref_function_summary (cgraph_node *func)
745 : : {
746 : : /* Avoid creation of the summary too early (e.g. when front-end calls us). */
747 : 473259610 : 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 : 460901801 : enum availability avail;
755 : 460901801 : func = func->ultimate_alias_target
756 : 921624926 : (&avail, current_function_decl ?
757 : 460723125 : cgraph_node::get (current_function_decl) : NULL);
758 : 460901801 : if (avail <= AVAIL_INTERPOSABLE)
759 : : return NULL;
760 : :
761 : 115883879 : modref_summary *r = optimization_summaries->get (func);
762 : 115883879 : 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 : 35938477 : get_modref_function_summary (gcall *call, bool *interposed)
772 : : {
773 : 35938477 : tree callee = gimple_call_fndecl (call);
774 : 35938477 : if (!callee)
775 : : return NULL;
776 : 34311156 : struct cgraph_node *node = cgraph_node::get (callee);
777 : 34311156 : if (!node)
778 : : return NULL;
779 : 34231398 : modref_summary *r = get_modref_function_summary (node);
780 : 34231398 : if (interposed && r)
781 : 5917255 : *interposed = r->calls_interposable
782 : 5917255 : || !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 : 7836660 : ignore_nondeterminism_p (tree caller, int flags, tree callee_fntype)
793 : : {
794 : 7836660 : int caller_flags = flags_from_decl_or_type (caller);
795 : 7836660 : if ((flags | caller_flags) & (ECF_CONST | ECF_PURE))
796 : : return true;
797 : 7532858 : if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
798 : 7532858 : || (!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 : 6941152 : if (lookup_attribute ("unsequenced", TYPE_ATTRIBUTES (TREE_TYPE (caller)))
803 : 13882304 : || lookup_attribute ("reproducible",
804 : 6941152 : TYPE_ATTRIBUTES (TREE_TYPE (caller))))
805 : 0 : return true;
806 : 6941152 : if (callee_fntype
807 : 6941152 : && (lookup_attribute ("unsequenced", TYPE_ATTRIBUTES (callee_fntype))
808 : 5647823 : || lookup_attribute ("reproducible",
809 : 5647823 : 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 : 5485396 : ignore_retval_p (tree caller, int flags)
818 : : {
819 : 5485396 : if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
820 : 5485396 : || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
821 : 42019 : return true;
822 : : return false;
823 : : }
824 : :
825 : : /* Return true if ECF flags says that stores can be ignored. */
826 : :
827 : : static bool
828 : 26053851 : ignore_stores_p (tree caller, int flags)
829 : : {
830 : 26053851 : if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
831 : : return true;
832 : 23056905 : if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
833 : 23056905 : || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
834 : 1588026 : 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 : 14775444 : parm_map_for_ptr (tree op)
842 : : {
843 : 14775444 : bool offset_known;
844 : 14775444 : poly_int64 offset;
845 : 14775444 : struct modref_parm_map parm_map;
846 : 14775444 : gcall *call;
847 : :
848 : 14775444 : parm_map.parm_offset_known = false;
849 : 14775444 : parm_map.parm_offset = 0;
850 : :
851 : 14775444 : offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
852 : 14775444 : if (TREE_CODE (op) == SSA_NAME
853 : 9812007 : && SSA_NAME_IS_DEFAULT_DEF (op)
854 : 22665960 : && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
855 : : {
856 : 7877443 : int index = 0;
857 : :
858 : 7877443 : if (cfun->static_chain_decl
859 : 7877443 : && op == ssa_default_def (cfun, cfun->static_chain_decl))
860 : : index = MODREF_STATIC_CHAIN_PARM;
861 : : else
862 : 7798674 : for (tree t = DECL_ARGUMENTS (current_function_decl);
863 : 12774521 : t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
864 : 4975847 : index++;
865 : 7877443 : parm_map.parm_index = index;
866 : 7877443 : parm_map.parm_offset_known = offset_known;
867 : 7877443 : parm_map.parm_offset = offset;
868 : : }
869 : 6898001 : 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 : 6177971 : else if (TREE_CODE (op) == SSA_NAME
874 : 1815700 : && (call = dyn_cast<gcall *>(SSA_NAME_DEF_STMT (op))) != NULL
875 : 6858081 : && 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 : 14775444 : 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 : 10599212 : verify_arg (tree arg, int flags, bool load)
887 : : {
888 : 10599212 : if (flags & EAF_UNUSED)
889 : : return true;
890 : 10357194 : if (load && (flags & EAF_NO_DIRECT_READ))
891 : : return true;
892 : : if (!load
893 : 4470181 : && (flags & (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER))
894 : : == (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER))
895 : : return true;
896 : 9447195 : if (is_gimple_constant (arg))
897 : : return true;
898 : 7315940 : if (DECL_P (arg) && TREE_READONLY (arg))
899 : : return true;
900 : 7315833 : if (TREE_CODE (arg) == ADDR_EXPR)
901 : : {
902 : 3149601 : tree t = get_base_address (TREE_OPERAND (arg, 0));
903 : 7015734 : if (is_gimple_constant (t))
904 : : return true;
905 : 2225406 : if (DECL_P (t)
906 : 2225406 : && (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 : 8631252 : may_access_nonescaping_parm_p (gcall *call, int callee_ecf_flags, bool load)
919 : : {
920 : 8631252 : int implicit_flags = 0;
921 : :
922 : 8631252 : if (ignore_stores_p (current_function_decl, callee_ecf_flags))
923 : 632130 : implicit_flags |= ignore_stores_eaf_flags;
924 : 8631252 : if (callee_ecf_flags & ECF_PURE)
925 : 239111 : implicit_flags |= implicit_pure_eaf_flags;
926 : 8631252 : if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
927 : 0 : implicit_flags |= implicit_const_eaf_flags;
928 : 8631252 : if (gimple_call_chain (call)
929 : 8670399 : && !verify_arg (gimple_call_chain (call),
930 : 39147 : gimple_call_static_chain_flags (call) | implicit_flags,
931 : : load))
932 : : return true;
933 : 13382433 : for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
934 : 10560065 : if (!verify_arg (gimple_call_arg (call, i),
935 : 10560065 : 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 : 8989952 : class modref_access_analysis
947 : : {
948 : : public:
949 : 4494976 : modref_access_analysis (bool ipa, modref_summary *summary,
950 : : modref_summary_lto *summary_lto)
951 : 4494976 : : 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 : 6656965 : modref_access_analysis::set_side_effects ()
999 : : {
1000 : 6656965 : bool changed = false;
1001 : :
1002 : 6656965 : if (m_summary && !m_summary->side_effects)
1003 : : {
1004 : 1512786 : m_summary->side_effects = true;
1005 : 1512786 : changed = true;
1006 : : }
1007 : 6656965 : if (m_summary_lto && !m_summary_lto->side_effects)
1008 : : {
1009 : 1492 : m_summary_lto->side_effects = true;
1010 : 1492 : changed = true;
1011 : : }
1012 : 6656965 : return changed;
1013 : : }
1014 : :
1015 : : /* Set nondeterministic flag and return if something changed. */
1016 : :
1017 : : bool
1018 : 4106750 : modref_access_analysis::set_nondeterministic ()
1019 : : {
1020 : 4106750 : bool changed = false;
1021 : :
1022 : 4106750 : if (m_summary && !m_summary->nondeterministic)
1023 : : {
1024 : 1317525 : m_summary->side_effects = m_summary->nondeterministic = true;
1025 : 1317525 : changed = true;
1026 : : }
1027 : 4106750 : if (m_summary_lto && !m_summary_lto->nondeterministic)
1028 : : {
1029 : 5888 : m_summary_lto->side_effects = m_summary_lto->nondeterministic = true;
1030 : 5888 : changed = true;
1031 : : }
1032 : 4106750 : return changed;
1033 : : }
1034 : :
1035 : : /* Construct modref_access_node from REF. */
1036 : :
1037 : : modref_access_node
1038 : 12753898 : modref_access_analysis::get_access (ao_ref *ref)
1039 : : {
1040 : 12753898 : tree base;
1041 : :
1042 : 12753898 : base = ao_ref_base (ref);
1043 : 12753898 : modref_access_node a = {ref->offset, ref->size, ref->max_size,
1044 : 12753898 : 0, MODREF_UNKNOWN_PARM, false, 0};
1045 : 12753898 : if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
1046 : : {
1047 : 10325564 : tree memref = base;
1048 : 10325564 : modref_parm_map m = parm_map_for_ptr (TREE_OPERAND (base, 0));
1049 : :
1050 : 10325564 : a.parm_index = m.parm_index;
1051 : 10325564 : if (a.parm_index != MODREF_UNKNOWN_PARM && TREE_CODE (memref) == MEM_REF)
1052 : : {
1053 : 6847698 : a.parm_offset_known
1054 : 6847698 : = wi::to_poly_wide (TREE_OPERAND
1055 : 6847698 : (memref, 1)).to_shwi (&a.parm_offset);
1056 : 6847698 : if (a.parm_offset_known && m.parm_offset_known)
1057 : 10325564 : a.parm_offset += m.parm_offset;
1058 : : else
1059 : 502495 : a.parm_offset_known = false;
1060 : : }
1061 : : }
1062 : : else
1063 : : a.parm_index = MODREF_UNKNOWN_PARM;
1064 : 12753898 : return a;
1065 : : }
1066 : :
1067 : : /* Record access into the modref_records data structure. */
1068 : :
1069 : : void
1070 : 12386496 : modref_access_analysis::record_access (modref_records *tt,
1071 : : ao_ref *ref,
1072 : : modref_access_node &a)
1073 : : {
1074 : 12386496 : alias_set_type base_set = !flag_strict_aliasing
1075 : 12386496 : || !flag_ipa_strict_aliasing ? 0
1076 : 9864608 : : ao_ref_base_alias_set (ref);
1077 : 12386496 : alias_set_type ref_set = !flag_strict_aliasing
1078 : 12386496 : || !flag_ipa_strict_aliasing ? 0
1079 : 9864608 : : (ao_ref_alias_set (ref));
1080 : 12386496 : if (dump_file)
1081 : : {
1082 : 247 : fprintf (dump_file, " - Recording base_set=%i ref_set=%i ",
1083 : : base_set, ref_set);
1084 : 247 : a.dump (dump_file);
1085 : : }
1086 : 12386496 : tt->insert (current_function_decl, base_set, ref_set, a, false);
1087 : 12386496 : }
1088 : :
1089 : : /* IPA version of record_access_tree. */
1090 : :
1091 : : void
1092 : 163652 : 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 : 163652 : tree base_type = NULL_TREE, ref_type = NULL_TREE;
1098 : 163652 : if (flag_strict_aliasing && flag_ipa_strict_aliasing)
1099 : : {
1100 : 163178 : tree base;
1101 : :
1102 : 163178 : base = ref->ref;
1103 : 220501 : while (handled_component_p (base))
1104 : 57323 : base = TREE_OPERAND (base, 0);
1105 : :
1106 : 163178 : base_type = reference_alias_ptr_type_1 (&base);
1107 : :
1108 : 163178 : if (!base_type)
1109 : 161791 : base_type = TREE_TYPE (base);
1110 : : else
1111 : 1387 : base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
1112 : 1387 : ? NULL_TREE : TREE_TYPE (base_type);
1113 : :
1114 : 163178 : tree ref_expr = ref->ref;
1115 : 163178 : ref_type = reference_alias_ptr_type_1 (&ref_expr);
1116 : :
1117 : 163178 : if (!ref_type)
1118 : 161885 : ref_type = TREE_TYPE (ref_expr);
1119 : : else
1120 : 1293 : ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
1121 : 1293 : ? NULL_TREE : TREE_TYPE (ref_type);
1122 : :
1123 : : /* Sanity check that we are in sync with what get_alias_set does. */
1124 : 163178 : 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 : 163178 : 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 : 163178 : if (base_type && (!get_alias_set (base_type)
1134 : 152628 : || variably_modified_type_p (base_type, NULL_TREE)))
1135 : : base_type = NULL_TREE;
1136 : 163178 : if (ref_type && (!get_alias_set (ref_type)
1137 : 154485 : || variably_modified_type_p (ref_type, NULL_TREE)))
1138 : : ref_type = NULL_TREE;
1139 : : }
1140 : 163652 : 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 : 163652 : tt->insert (current_function_decl, base_type, ref_type, a, false);
1153 : 163652 : }
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 : 25579534 : modref_access_analysis::record_access_p (tree expr)
1160 : : {
1161 : 25579534 : if (TREE_THIS_VOLATILE (expr)
1162 : 25579534 : && !ignore_nondeterminism_p (current_function_decl, 0, NULL))
1163 : : {
1164 : 900791 : if (dump_file)
1165 : 0 : fprintf (dump_file, " (volatile; marking nondeterministic) ");
1166 : 900791 : set_nondeterministic ();
1167 : : }
1168 : 25579534 : if (cfun->can_throw_non_call_exceptions
1169 : 25579534 : && tree_could_throw_p (expr))
1170 : : {
1171 : 1579890 : if (dump_file)
1172 : 0 : fprintf (dump_file, " (can throw; marking side effects) ");
1173 : 1579890 : set_side_effects ();
1174 : : }
1175 : :
1176 : 25579534 : if (refs_local_or_readonly_memory_p (expr))
1177 : : {
1178 : 12825636 : if (dump_file)
1179 : 57 : fprintf (dump_file, " - Read-only or local, ignoring.\n");
1180 : 12825636 : return false;
1181 : : }
1182 : : return true;
1183 : : }
1184 : :
1185 : : /* Collapse loads and return true if something changed. */
1186 : :
1187 : : bool
1188 : 2354370 : modref_access_analysis::record_unknown_load ()
1189 : : {
1190 : 2354370 : bool changed = false;
1191 : :
1192 : 2354370 : if (m_summary && !m_summary->loads->every_base)
1193 : : {
1194 : 917532 : m_summary->loads->collapse ();
1195 : 917532 : changed = true;
1196 : : }
1197 : 2354370 : if (m_summary_lto && !m_summary_lto->loads->every_base)
1198 : : {
1199 : 1777 : m_summary_lto->loads->collapse ();
1200 : 1777 : changed = true;
1201 : : }
1202 : 2354370 : return changed;
1203 : : }
1204 : :
1205 : : /* Collapse loads and return true if something changed. */
1206 : :
1207 : : bool
1208 : 2084555 : modref_access_analysis::record_unknown_store ()
1209 : : {
1210 : 2084555 : bool changed = false;
1211 : :
1212 : 2084555 : if (m_summary && !m_summary->stores->every_base)
1213 : : {
1214 : 970964 : m_summary->stores->collapse ();
1215 : 970964 : changed = true;
1216 : : }
1217 : 2084555 : if (m_summary_lto && !m_summary_lto->stores->every_base)
1218 : : {
1219 : 1691 : m_summary_lto->stores->collapse ();
1220 : 1691 : changed = true;
1221 : : }
1222 : 2084555 : return changed;
1223 : : }
1224 : :
1225 : : /* Record unknown load from global memory. */
1226 : :
1227 : : bool
1228 : 1142922 : modref_access_analysis::record_global_memory_load ()
1229 : : {
1230 : 1142922 : bool changed = false;
1231 : 1142922 : modref_access_node a = {0, -1, -1,
1232 : : 0, MODREF_GLOBAL_MEMORY_PARM, false, 0};
1233 : :
1234 : 1142922 : if (m_summary && !m_summary->loads->every_base)
1235 : 791861 : changed |= m_summary->loads->insert (current_function_decl, 0, 0, a, false);
1236 : 1142922 : if (m_summary_lto && !m_summary_lto->loads->every_base)
1237 : 465 : changed |= m_summary_lto->loads->insert (current_function_decl,
1238 : : 0, 0, a, false);
1239 : 1142922 : return changed;
1240 : : }
1241 : :
1242 : : /* Record unknown store from global memory. */
1243 : :
1244 : : bool
1245 : 766671 : modref_access_analysis::record_global_memory_store ()
1246 : : {
1247 : 766671 : bool changed = false;
1248 : 766671 : modref_access_node a = {0, -1, -1,
1249 : : 0, MODREF_GLOBAL_MEMORY_PARM, false, 0};
1250 : :
1251 : 766671 : if (m_summary && !m_summary->stores->every_base)
1252 : 568782 : changed |= m_summary->stores->insert (current_function_decl,
1253 : : 0, 0, a, false);
1254 : 766671 : if (m_summary_lto && !m_summary_lto->stores->every_base)
1255 : 338 : changed |= m_summary_lto->stores->insert (current_function_decl,
1256 : : 0, 0, a, false);
1257 : 766671 : 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 : 1436046 : modref_access_analysis::merge_call_side_effects
1268 : : (gimple *stmt, modref_summary *callee_summary,
1269 : : cgraph_node *callee_node, bool record_adjustments)
1270 : : {
1271 : 1436046 : gcall *call = as_a <gcall *> (stmt);
1272 : 1436046 : int flags = gimple_call_flags (call);
1273 : :
1274 : : /* Nothing to do for non-looping cont functions. */
1275 : 1436046 : if ((flags & ECF_CONST)
1276 : : && !(flags & ECF_LOOPING_CONST_OR_PURE))
1277 : : return false;
1278 : :
1279 : 1436046 : bool changed = false;
1280 : :
1281 : 1436046 : 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 : 1436046 : if (!(flags & (ECF_CONST | ECF_PURE))
1289 : 128342 : || (flags & ECF_LOOPING_CONST_OR_PURE))
1290 : : {
1291 : 1351774 : if (!m_summary->side_effects && callee_summary->side_effects)
1292 : : {
1293 : 351145 : if (dump_file)
1294 : 0 : fprintf (dump_file, " - merging side effects.\n");
1295 : 351145 : m_summary->side_effects = true;
1296 : 351145 : changed = true;
1297 : : }
1298 : 883608 : if (!m_summary->nondeterministic && callee_summary->nondeterministic
1299 : 1694186 : && !ignore_nondeterminism_p (current_function_decl, flags,
1300 : : gimple_call_fntype (call)))
1301 : : {
1302 : 340876 : if (dump_file)
1303 : 0 : fprintf (dump_file, " - merging nondeterministic.\n");
1304 : 340876 : m_summary->nondeterministic = true;
1305 : 340876 : changed = true;
1306 : : }
1307 : : }
1308 : :
1309 : : /* For const functions we are done. */
1310 : 1436046 : if (flags & (ECF_CONST | ECF_NOVOPS))
1311 : : return changed;
1312 : :
1313 : : /* Merge calls_interposable flags. */
1314 : 1435581 : if (!m_summary->calls_interposable && callee_summary->calls_interposable)
1315 : : {
1316 : 161451 : if (dump_file)
1317 : 0 : fprintf (dump_file, " - merging calls interposable.\n");
1318 : 161451 : m_summary->calls_interposable = true;
1319 : 161451 : changed = true;
1320 : : }
1321 : :
1322 : 1435581 : if (!callee_node->binds_to_current_def_p () && !m_summary->calls_interposable)
1323 : : {
1324 : 143048 : if (dump_file)
1325 : 0 : fprintf (dump_file, " - May be interposed.\n");
1326 : 143048 : m_summary->calls_interposable = true;
1327 : 143048 : 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 : 1435581 : if (dump_file)
1333 : 13 : fprintf (dump_file, " Parm map:");
1334 : :
1335 : 1435581 : auto_vec <modref_parm_map, 32> parm_map;
1336 : 1435581 : parm_map.safe_grow_cleared (gimple_call_num_args (call), true);
1337 : 5053374 : for (unsigned i = 0; i < gimple_call_num_args (call); i++)
1338 : : {
1339 : 3617793 : parm_map[i] = parm_map_for_ptr (gimple_call_arg (call, i));
1340 : 3617793 : 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 : 1435581 : modref_parm_map chain_map;
1353 : 1435581 : if (gimple_call_chain (call))
1354 : : {
1355 : 2470 : chain_map = parm_map_for_ptr (gimple_call_chain (call));
1356 : 2470 : 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 : 1435581 : 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 : 1435581 : if (m_always_executed
1373 : 588027 : && callee_summary->kills.length ()
1374 : 1506459 : && (!cfun->can_throw_non_call_exceptions
1375 : 75 : || !stmt_could_throw_p (cfun, call)))
1376 : : {
1377 : : /* Watch for self recursive updates. */
1378 : 70840 : auto_vec<modref_access_node, 32> saved_kills;
1379 : :
1380 : 141680 : saved_kills.reserve_exact (callee_summary->kills.length ());
1381 : 70840 : saved_kills.splice (callee_summary->kills);
1382 : 294477 : for (auto kill : saved_kills)
1383 : : {
1384 : 163914 : if (kill.parm_index >= (int)parm_map.length ())
1385 : 34811 : continue;
1386 : 81957 : modref_parm_map &m
1387 : : = kill.parm_index == MODREF_STATIC_CHAIN_PARM
1388 : 81957 : ? chain_map
1389 : 81525 : : parm_map[kill.parm_index];
1390 : 116768 : if (m.parm_index == MODREF_LOCAL_MEMORY_PARM
1391 : 81957 : || m.parm_index == MODREF_UNKNOWN_PARM
1392 : : || m.parm_index == MODREF_RETSLOT_PARM
1393 : 47174 : || !m.parm_offset_known)
1394 : 34811 : continue;
1395 : 47146 : modref_access_node n = kill;
1396 : 47146 : n.parm_index = m.parm_index;
1397 : 47146 : n.parm_offset += m.parm_offset;
1398 : 47146 : if (modref_access_node::insert_kill (m_summary->kills, n,
1399 : : record_adjustments))
1400 : 28062 : changed = true;
1401 : : }
1402 : 70840 : }
1403 : :
1404 : : /* Merge in loads. */
1405 : 4306743 : changed |= m_summary->loads->merge (current_function_decl,
1406 : : callee_summary->loads,
1407 : : &parm_map, &chain_map,
1408 : : record_adjustments,
1409 : 1435581 : !may_access_nonescaping_parm_p
1410 : 1435581 : (call, flags, true));
1411 : : /* Merge in stores. */
1412 : 1435581 : if (!ignore_stores_p (current_function_decl, flags))
1413 : : {
1414 : 3921864 : changed |= m_summary->stores->merge (current_function_decl,
1415 : : callee_summary->stores,
1416 : : &parm_map, &chain_map,
1417 : : record_adjustments,
1418 : 1307288 : !may_access_nonescaping_parm_p
1419 : 1307288 : (call, flags, false));
1420 : 1307288 : if (!m_summary->writes_errno
1421 : 1134973 : && callee_summary->writes_errno)
1422 : : {
1423 : 101825 : m_summary->writes_errno = true;
1424 : 101825 : changed = true;
1425 : : }
1426 : : }
1427 : 1435581 : return changed;
1428 : 1435581 : }
1429 : :
1430 : : /* Return access mode for argument I of call STMT with FNSPEC. */
1431 : :
1432 : : modref_access_node
1433 : 279501 : modref_access_analysis::get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
1434 : : unsigned int i,
1435 : : modref_parm_map &map)
1436 : : {
1437 : 279501 : tree size = NULL_TREE;
1438 : 279501 : unsigned int size_arg;
1439 : :
1440 : 279501 : if (!fnspec.arg_specified_p (i))
1441 : : ;
1442 : 279501 : else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
1443 : 60300 : size = gimple_call_arg (call, size_arg);
1444 : 219201 : else if (fnspec.arg_access_size_given_by_type_p (i))
1445 : : {
1446 : 33 : tree callee = gimple_call_fndecl (call);
1447 : 33 : tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
1448 : :
1449 : 82 : for (unsigned int p = 0; p < i; p++)
1450 : 49 : t = TREE_CHAIN (t);
1451 : 33 : size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
1452 : : }
1453 : 279501 : modref_access_node a = {0, -1, -1,
1454 : 279501 : map.parm_offset, map.parm_index,
1455 : 279501 : map.parm_offset_known, 0};
1456 : 279501 : poly_int64 size_hwi;
1457 : 279501 : if (size
1458 : 60333 : && poly_int_tree_p (size, &size_hwi)
1459 : 296742 : && coeffs_in_range_p (size_hwi, 0,
1460 : : HOST_WIDE_INT_MAX / BITS_PER_UNIT))
1461 : : {
1462 : 17019 : a.size = -1;
1463 : 17019 : a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
1464 : : }
1465 : 279501 : 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 : 3864166 : modref_access_analysis::process_fnspec (gcall *call)
1474 : : {
1475 : 3864166 : 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 : 3864166 : if (!(flags & (ECF_CONST | ECF_PURE))
1480 : 370488 : || (flags & ECF_LOOPING_CONST_OR_PURE)
1481 : 4222405 : || (cfun->can_throw_non_call_exceptions
1482 : 36066 : && stmt_could_throw_p (cfun, call)))
1483 : : {
1484 : 3506559 : set_side_effects ();
1485 : 6845562 : if (!ignore_nondeterminism_p (current_function_decl, flags,
1486 : : gimple_call_fntype (call)))
1487 : 3090268 : set_nondeterministic ();
1488 : : }
1489 : :
1490 : : /* For const functions we are done. */
1491 : 3864166 : if (flags & (ECF_CONST | ECF_NOVOPS))
1492 : 3367972 : return;
1493 : :
1494 : 3857396 : attr_fnspec fnspec = gimple_call_fnspec (call);
1495 : : /* If there is no fnpec we know nothing about loads & stores. */
1496 : 3857396 : if (!fnspec.known_p ())
1497 : : {
1498 : 3028893 : 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 : 3028893 : if (!ignore_stores_p (current_function_decl, flags))
1502 : : {
1503 : 2599555 : if (!may_access_nonescaping_parm_p (call, flags, false))
1504 : 738831 : record_global_memory_store ();
1505 : : else
1506 : 1860724 : record_unknown_store ();
1507 : 2599555 : if (!may_access_nonescaping_parm_p (call, flags, true))
1508 : 738831 : record_global_memory_load ();
1509 : : else
1510 : 1860724 : record_unknown_load ();
1511 : : }
1512 : : else
1513 : : {
1514 : 429338 : if (!may_access_nonescaping_parm_p (call, flags, true))
1515 : 350873 : record_global_memory_load ();
1516 : : else
1517 : 78465 : record_unknown_load ();
1518 : : }
1519 : 3028893 : return;
1520 : : }
1521 : : /* Process fnspec. */
1522 : 828503 : if (fnspec.global_memory_read_p ())
1523 : : {
1524 : 167217 : if (may_access_nonescaping_parm_p (call, flags, true))
1525 : 113999 : record_unknown_load ();
1526 : : else
1527 : 53218 : record_global_memory_load ();
1528 : : }
1529 : : else
1530 : : {
1531 : 1540626 : for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1532 : 1168655 : if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1533 : : ;
1534 : 825024 : else if (!fnspec.arg_specified_p (i)
1535 : 825024 : || fnspec.arg_maybe_read_p (i))
1536 : : {
1537 : 536941 : modref_parm_map map = parm_map_for_ptr
1538 : 536941 : (gimple_call_arg (call, i));
1539 : :
1540 : 536941 : if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
1541 : 35023 : continue;
1542 : 501918 : if (map.parm_index == MODREF_UNKNOWN_PARM)
1543 : : {
1544 : 289315 : record_unknown_load ();
1545 : 289315 : break;
1546 : : }
1547 : 212603 : modref_access_node a = get_access_for_fnspec (call, fnspec, i, map);
1548 : 212603 : if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1549 : 0 : continue;
1550 : 212603 : if (m_summary)
1551 : 212603 : m_summary->loads->insert (current_function_decl, 0, 0, a, false);
1552 : 212603 : if (m_summary_lto)
1553 : 0 : m_summary_lto->loads->insert (current_function_decl, 0, 0, a,
1554 : : false);
1555 : : }
1556 : : }
1557 : 828503 : if (ignore_stores_p (current_function_decl, flags))
1558 : : return;
1559 : 496194 : if (fnspec.global_memory_written_p ())
1560 : : {
1561 : 92718 : if (may_access_nonescaping_parm_p (call, flags, false))
1562 : 64878 : record_unknown_store ();
1563 : : else
1564 : 27840 : record_global_memory_store ();
1565 : : }
1566 : : else
1567 : : {
1568 : 861019 : for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1569 : 604629 : if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1570 : : ;
1571 : 350488 : else if (!fnspec.arg_specified_p (i)
1572 : 350488 : || fnspec.arg_maybe_written_p (i))
1573 : : {
1574 : 292676 : modref_parm_map map = parm_map_for_ptr
1575 : 292676 : (gimple_call_arg (call, i));
1576 : :
1577 : 292676 : if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
1578 : 78692 : continue;
1579 : 213984 : if (map.parm_index == MODREF_UNKNOWN_PARM)
1580 : : {
1581 : 147086 : record_unknown_store ();
1582 : 147086 : break;
1583 : : }
1584 : 66898 : modref_access_node a = get_access_for_fnspec (call, fnspec, i, map);
1585 : 66898 : if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1586 : 0 : continue;
1587 : 66898 : if (m_summary)
1588 : 66898 : m_summary->stores->insert (current_function_decl, 0, 0, a, false);
1589 : 66898 : if (m_summary_lto)
1590 : 0 : m_summary_lto->stores->insert (current_function_decl,
1591 : : 0, 0, a, false);
1592 : : }
1593 : 403476 : if (fnspec.errno_maybe_written_p () && flag_errno_math)
1594 : : {
1595 : 64294 : if (m_summary)
1596 : 64294 : m_summary->writes_errno = true;
1597 : 64294 : 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 : 6041392 : modref_access_analysis::analyze_call (gcall *stmt)
1608 : : {
1609 : : /* Check flags on the function call. In certain cases, analysis can be
1610 : : simplified. */
1611 : 6041392 : int flags = gimple_call_flags (stmt);
1612 : :
1613 : 6041392 : if (dump_file)
1614 : : {
1615 : 33 : fprintf (dump_file, " - Analyzing call:");
1616 : 33 : print_gimple_stmt (dump_file, stmt, 0);
1617 : : }
1618 : :
1619 : 6041392 : if ((flags & ECF_CONST)
1620 : : && !(flags & ECF_LOOPING_CONST_OR_PURE))
1621 : : {
1622 : 593574 : if (dump_file)
1623 : 0 : fprintf (dump_file,
1624 : : " - ECF_CONST, ignoring all stores and all loads "
1625 : : "except for args.\n");
1626 : 593574 : 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 : 5447818 : tree callee = gimple_call_fndecl (stmt);
1632 : :
1633 : : /* Check if this is an indirect call. */
1634 : 5447818 : if (!callee)
1635 : : {
1636 : 367642 : if (dump_file)
1637 : 52 : fprintf (dump_file, gimple_call_internal_p (stmt)
1638 : : ? " - Internal call" : " - Indirect call.\n");
1639 : 367642 : process_fnspec (stmt);
1640 : 367642 : return;
1641 : : }
1642 : : /* We only need to handle internal calls in IPA mode. */
1643 : 5080176 : gcc_checking_assert (!m_summary_lto && !m_ipa);
1644 : :
1645 : 5080176 : 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 : 5080176 : if (recursive_call_p (current_function_decl, callee))
1650 : : {
1651 : 10730 : m_recursive_calls.safe_push (stmt);
1652 : 10730 : set_side_effects ();
1653 : 10730 : if (dump_file)
1654 : 1 : fprintf (dump_file, " - Skipping recursive call.\n");
1655 : 10730 : return;
1656 : : }
1657 : :
1658 : 5069446 : gcc_assert (callee_node != NULL);
1659 : :
1660 : : /* Get the function symbol and its availability. */
1661 : 5069446 : enum availability avail;
1662 : 5069446 : callee_node = callee_node->function_symbol (&avail);
1663 : 5069446 : bool looping;
1664 : 5069446 : if (builtin_safe_for_const_function_p (&looping, callee))
1665 : : {
1666 : 147945 : if (looping)
1667 : 2711 : set_side_effects ();
1668 : 147945 : if (dump_file)
1669 : 0 : fprintf (dump_file, " - Builtin is safe for const.\n");
1670 : 147945 : return;
1671 : : }
1672 : 4921501 : if (avail <= AVAIL_INTERPOSABLE)
1673 : : {
1674 : 3091742 : if (dump_file)
1675 : 3 : fprintf (dump_file,
1676 : : " - Function availability <= AVAIL_INTERPOSABLE.\n");
1677 : 3091742 : process_fnspec (stmt);
1678 : 3091742 : 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 : 1829759 : modref_summary *callee_summary = optimization_summaries->get (callee_node);
1684 : 1829759 : if (!callee_summary)
1685 : : {
1686 : 404782 : if (dump_file)
1687 : 0 : fprintf (dump_file, " - No modref summary available for callee.\n");
1688 : 404782 : process_fnspec (stmt);
1689 : 404782 : return;
1690 : : }
1691 : :
1692 : 1424977 : merge_call_side_effects (stmt, callee_summary, callee_node, false);
1693 : :
1694 : 1424977 : return;
1695 : : }
1696 : :
1697 : : /* Helper for analyze_stmt. */
1698 : :
1699 : : bool
1700 : 12884297 : modref_access_analysis::analyze_load (gimple *, tree, tree op, void *data)
1701 : : {
1702 : 12884297 : modref_access_analysis *t = (modref_access_analysis *)data;
1703 : :
1704 : 12884297 : 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 : 12884297 : if (!t->record_access_p (op))
1712 : : return false;
1713 : :
1714 : 8378935 : ao_ref r;
1715 : 8378935 : ao_ref_init (&r, op);
1716 : 8378935 : modref_access_node a = get_access (&r);
1717 : 8378935 : if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1718 : : return false;
1719 : :
1720 : 8352156 : if (t->m_summary)
1721 : 8314640 : t->record_access (t->m_summary->loads, &r, a);
1722 : 8352156 : if (t->m_summary_lto)
1723 : 108016 : 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 : 12148769 : modref_access_analysis::analyze_store (gimple *stmt, tree, tree op, void *data)
1731 : : {
1732 : 12148769 : modref_access_analysis *t = (modref_access_analysis *)data;
1733 : :
1734 : 12148769 : if (dump_file)
1735 : : {
1736 : 100 : fprintf (dump_file, " - Analyzing store: ");
1737 : 100 : print_generic_expr (dump_file, op);
1738 : 100 : fprintf (dump_file, "\n");
1739 : : }
1740 : :
1741 : 12148769 : if (!t->record_access_p (op))
1742 : : return false;
1743 : :
1744 : 4252420 : ao_ref r;
1745 : 4252420 : ao_ref_init (&r, op);
1746 : 4252420 : modref_access_node a = get_access (&r);
1747 : 4252420 : if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1748 : : return false;
1749 : :
1750 : 4095169 : if (t->m_summary)
1751 : 4071856 : t->record_access (t->m_summary->stores, &r, a);
1752 : 4095169 : if (t->m_summary_lto)
1753 : 55636 : t->record_access_lto (t->m_summary_lto->stores, &r, a);
1754 : 4095169 : if (t->m_always_executed
1755 : 1886401 : && a.useful_for_kill_p ()
1756 : 5423051 : && !stmt_could_throw_p (cfun, stmt))
1757 : : {
1758 : 1322102 : if (dump_file)
1759 : 21 : fprintf (dump_file, " - Recording kill\n");
1760 : 1322102 : if (t->m_summary)
1761 : 1319615 : modref_access_node::insert_kill (t->m_summary->kills, a, false);
1762 : 1322102 : if (t->m_summary_lto)
1763 : 5364 : 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 : 64442802 : modref_access_analysis::analyze_stmt (gimple *stmt, bool always_executed)
1773 : : {
1774 : 64442802 : 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 : 64442802 : if ((m_ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1780 : : {
1781 : 1735207 : if (always_executed && record_access_p (gimple_assign_lhs (stmt)))
1782 : : {
1783 : 122543 : ao_ref r;
1784 : 122543 : ao_ref_init (&r, gimple_assign_lhs (stmt));
1785 : 122543 : modref_access_node a = get_access (&r);
1786 : 122543 : if (a.useful_for_kill_p ())
1787 : : {
1788 : 115067 : if (dump_file)
1789 : 0 : fprintf (dump_file, " - Recording kill\n");
1790 : 115067 : if (m_summary)
1791 : 114626 : modref_access_node::insert_kill (m_summary->kills, a, false);
1792 : 115067 : if (m_summary_lto)
1793 : 797 : modref_access_node::insert_kill (m_summary_lto->kills,
1794 : : a, false);
1795 : : }
1796 : : }
1797 : 1735207 : return;
1798 : : }
1799 : :
1800 : : /* Analyze all loads and stores in STMT. */
1801 : 62707595 : walk_stmt_load_store_ops (stmt, this,
1802 : : analyze_load, analyze_store);
1803 : :
1804 : 62707595 : switch (gimple_code (stmt))
1805 : : {
1806 : 134692 : case GIMPLE_ASM:
1807 : 134692 : if (gimple_asm_volatile_p (as_a <gasm *> (stmt))
1808 : 134692 : && !ignore_nondeterminism_p (current_function_decl, 0, NULL))
1809 : 115691 : set_nondeterministic ();
1810 : 134692 : if (cfun->can_throw_non_call_exceptions
1811 : 134692 : && 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 : 134692 : if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1816 : : return;
1817 : 11867 : if (dump_file)
1818 : 1 : fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1819 : : "which clobbers memory.\n");
1820 : 11867 : record_unknown_load ();
1821 : 11867 : record_unknown_store ();
1822 : 11867 : return;
1823 : 10446378 : case GIMPLE_CALL:
1824 : 10446378 : if (!m_ipa || gimple_call_internal_p (stmt))
1825 : 6041392 : analyze_call (as_a <gcall *> (stmt));
1826 : : else
1827 : : {
1828 : 4404986 : attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1829 : :
1830 : 4404986 : if (fnspec.known_p ()
1831 : 4404986 : && (!fnspec.global_memory_read_p ()
1832 : 295062 : || !fnspec.global_memory_written_p ()))
1833 : : {
1834 : 493652 : cgraph_edge *e = cgraph_node::get
1835 : 493652 : (current_function_decl)->get_edge (stmt);
1836 : 493652 : if (e->callee)
1837 : : {
1838 : 493648 : fnspec_summaries->get_create (e)->fnspec
1839 : 493648 : = xstrdup (fnspec.get_str ());
1840 : 493648 : if (dump_file)
1841 : 2 : fprintf (dump_file, " Recorded fnspec %s\n",
1842 : : fnspec.get_str ());
1843 : : }
1844 : : }
1845 : : }
1846 : : return;
1847 : 52126525 : default:
1848 : 52126525 : if (cfun->can_throw_non_call_exceptions
1849 : 52126525 : && stmt_could_throw_p (cfun, stmt))
1850 : 1556656 : set_side_effects ();
1851 : : return;
1852 : : }
1853 : : }
1854 : :
1855 : : /* Propagate load/stores across recursive calls. */
1856 : :
1857 : : void
1858 : 2239283 : modref_access_analysis::propagate ()
1859 : : {
1860 : 2239283 : if (m_ipa && m_summary)
1861 : : return;
1862 : :
1863 : 2239283 : bool changed = true;
1864 : 2239283 : bool first = true;
1865 : 2239283 : cgraph_node *fnode = cgraph_node::get (current_function_decl);
1866 : :
1867 : 2239283 : m_always_executed = false;
1868 : 4479988 : while (changed && m_summary->useful_p (m_ecf_flags, false))
1869 : : {
1870 : : changed = false;
1871 : 6731546 : for (unsigned i = 0; i < m_recursive_calls.length (); i++)
1872 : : {
1873 : 11069 : changed |= merge_call_side_effects (m_recursive_calls[i], m_summary,
1874 : 11069 : fnode, !first);
1875 : : }
1876 : : first = false;
1877 : : }
1878 : : }
1879 : :
1880 : : /* Analyze function. */
1881 : :
1882 : : void
1883 : 4494976 : modref_access_analysis::analyze ()
1884 : : {
1885 : 4494976 : m_ecf_flags = flags_from_decl_or_type (current_function_decl);
1886 : 4494976 : 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 : 4494976 : basic_block bb;
1892 : 4494976 : bitmap always_executed_bbs = find_always_executed_bbs (cfun, true);
1893 : 26355615 : FOR_EACH_BB_FN (bb, cfun)
1894 : : {
1895 : 22991522 : gimple_stmt_iterator si;
1896 : 22991522 : bool always_executed = bitmap_bit_p (always_executed_bbs, bb->index);
1897 : :
1898 : 22991522 : for (si = gsi_start_nondebug_after_labels_bb (bb);
1899 : 86303441 : !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 : 64444597 : if (infer_nonnull_range_by_dereference (gsi_stmt (si),
1906 : : null_pointer_node))
1907 : : {
1908 : 1795 : if (dump_file)
1909 : 0 : fprintf (dump_file, " - NULL memory access; terminating BB\n");
1910 : 1795 : if (flag_non_call_exceptions)
1911 : 268 : set_side_effects ();
1912 : : break;
1913 : : }
1914 : 64442802 : analyze_stmt (gsi_stmt (si), always_executed);
1915 : :
1916 : : /* Avoid doing useless work. */
1917 : 64028404 : if ((!m_summary || !m_summary->useful_p (m_ecf_flags, false))
1918 : 65569603 : && (!m_summary_lto
1919 : 419014 : || !m_summary_lto->useful_p (m_ecf_flags, false)))
1920 : : {
1921 : : summary_useful = false;
1922 : : break;
1923 : : }
1924 : 63311919 : if (always_executed
1925 : 63311919 : && stmt_can_throw_external (cfun, gsi_stmt (si)))
1926 : : always_executed = false;
1927 : : }
1928 : 22991522 : 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 : 4494976 : if (summary_useful)
1934 : : {
1935 : 3364093 : if (!m_ipa)
1936 : 2239283 : propagate ();
1937 : 3364093 : if (m_summary && !m_summary->side_effects && !finite_function_p ())
1938 : 49059 : m_summary->side_effects = true;
1939 : 81414 : if (m_summary_lto && !m_summary_lto->side_effects
1940 : 3440511 : && !finite_function_p ())
1941 : 2986 : m_summary_lto->side_effects = true;
1942 : : }
1943 : 4494976 : BITMAP_FREE (always_executed_bbs);
1944 : 4494976 : }
1945 : :
1946 : : /* Return true if OP accesses memory pointed to by SSA_NAME. */
1947 : :
1948 : : bool
1949 : 21420283 : memory_access_to (tree op, tree ssa_name)
1950 : : {
1951 : 21420283 : tree base = get_base_address (op);
1952 : 21420283 : if (!base)
1953 : : return false;
1954 : 21420283 : if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1955 : : return false;
1956 : 8396823 : 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 : 7662711 : 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 : 7969815 : 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 : 7662711 : 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 : 7624635 : if (((flags & EAF_NO_DIRECT_CLOBBER)
1980 : : && (flags & EAF_NO_INDIRECT_CLOBBER))
1981 : 3874030 : || ignore_stores)
1982 : 3776954 : ret |= EAF_NO_INDIRECT_CLOBBER;
1983 : 7624635 : if (((flags & EAF_NO_DIRECT_ESCAPE)
1984 : : && (flags & EAF_NO_INDIRECT_ESCAPE))
1985 : 3471258 : || ignore_stores)
1986 : 4179724 : ret |= EAF_NO_INDIRECT_ESCAPE;
1987 : 7624635 : if ((flags & EAF_NO_DIRECT_READ)
1988 : : && (flags & EAF_NO_INDIRECT_READ))
1989 : 3431925 : ret |= EAF_NO_INDIRECT_READ;
1990 : 7624635 : if ((flags & EAF_NOT_RETURNED_DIRECTLY)
1991 : : && (flags & EAF_NOT_RETURNED_INDIRECTLY))
1992 : 2667821 : ret |= EAF_NOT_RETURNED_INDIRECTLY;
1993 : : }
1994 : 7662711 : 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 : 21567076 : modref_lattice::init ()
2064 : : {
2065 : : /* All flags we track. */
2066 : 21567076 : 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 : 21567076 : flags = f;
2072 : : /* Check that eaf_flags_t is wide enough to hold all flags. */
2073 : 21567076 : gcc_checking_assert (f == flags);
2074 : 21567076 : open = true;
2075 : 21567076 : known = false;
2076 : 0 : }
2077 : :
2078 : : /* Release memory. */
2079 : : void
2080 : 39856955 : modref_lattice::release ()
2081 : : {
2082 : 0 : escape_points.release ();
2083 : 39856955 : propagate_to.release ();
2084 : 0 : }
2085 : :
2086 : : /* Dump lattice to OUT; indent with INDENT spaces. */
2087 : :
2088 : : void
2089 : 2620 : modref_lattice::dump (FILE *out, int indent) const
2090 : : {
2091 : 2620 : dump_eaf_flags (out, flags);
2092 : 2620 : 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 : 2620 : }
2106 : :
2107 : : /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
2108 : : point exists. */
2109 : :
2110 : : bool
2111 : 1884547 : modref_lattice::add_escape_point (gcall *call, unsigned arg,
2112 : : eaf_flags_t min_flags, bool direct)
2113 : : {
2114 : 1884547 : escape_point *ep;
2115 : 1884547 : unsigned int i;
2116 : :
2117 : : /* If we already determined flags to be bad enough,
2118 : : we do not need to record. */
2119 : 1884547 : if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
2120 : : return false;
2121 : :
2122 : 4028564 : FOR_EACH_VEC_ELT (escape_points, i, ep)
2123 : 3412836 : if (ep->call == call && ep->arg == arg && ep->direct == direct)
2124 : : {
2125 : 55186 : 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 : 768457 : 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 : 615728 : escape_point new_ep = {call, arg, min_flags, direct};
2139 : 615728 : escape_points.safe_push (new_ep);
2140 : 615728 : return true;
2141 : : }
2142 : :
2143 : : /* Merge in flags from F. */
2144 : : bool
2145 : 66104649 : modref_lattice::merge (int f)
2146 : : {
2147 : 66104649 : 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 : 66095442 : 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 : 66095442 : if ((flags & f) != flags)
2157 : : {
2158 : 41579183 : 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 : 41579183 : flags = remove_useless_eaf_flags (flags, 0, false);
2164 : 41579183 : if (!flags)
2165 : 7880121 : escape_points.release ();
2166 : 41579183 : return true;
2167 : : }
2168 : : return false;
2169 : : }
2170 : :
2171 : : /* Merge in WITH. Return true if anything changed. */
2172 : :
2173 : : bool
2174 : 14532372 : modref_lattice::merge (const modref_lattice &with)
2175 : : {
2176 : 14532372 : if (!with.known)
2177 : 2241395 : do_dataflow = true;
2178 : :
2179 : 14532372 : bool changed = merge (with.flags);
2180 : :
2181 : 14532372 : if (!flags)
2182 : : return changed;
2183 : 11080119 : for (unsigned int i = 0; i < with.escape_points.length (); i++)
2184 : 242343 : changed |= add_escape_point (with.escape_points[i].call,
2185 : 242343 : with.escape_points[i].arg,
2186 : 242343 : with.escape_points[i].min_flags,
2187 : 242343 : 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 : 7375231 : modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
2196 : : {
2197 : 7375231 : if (!with.known)
2198 : 338376 : do_dataflow = true;
2199 : :
2200 : 7375231 : bool changed = merge (deref_flags (with.flags, ignore_stores));
2201 : :
2202 : 7375231 : if (!flags)
2203 : : return changed;
2204 : 7146883 : for (unsigned int i = 0; i < with.escape_points.length (); i++)
2205 : : {
2206 : 138849 : int min_flags = with.escape_points[i].min_flags;
2207 : :
2208 : 138849 : if (with.escape_points[i].direct)
2209 : 116511 : min_flags = deref_flags (min_flags, ignore_stores);
2210 : 22338 : else if (ignore_stores)
2211 : 0 : min_flags |= ignore_stores_eaf_flags;
2212 : 138849 : changed |= add_escape_point (with.escape_points[i].call,
2213 : 138849 : 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 : 152 : 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 : 2680229 : 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 : 6445495 : int get_ssa_name_flags (tree name)
2256 : : {
2257 : 6445495 : int version = SSA_NAME_VERSION (name);
2258 : 6445495 : gcc_checking_assert (m_lattice[version].known);
2259 : 6445495 : 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 : 3810425 : modref_eaf_analysis (bool ipa)
2266 : 3810425 : {
2267 : 3810425 : m_ipa = ipa;
2268 : 3810425 : m_depth = 0;
2269 : 7620850 : m_lattice.safe_grow_cleared (num_ssa_names, true);
2270 : 3810425 : }
2271 : 3810425 : ~modref_eaf_analysis ()
2272 : : {
2273 : 3810425 : gcc_checking_assert (!m_depth);
2274 : 3810425 : if (m_ipa || m_names_to_propagate.length ())
2275 : 41014257 : for (unsigned int i = 0; i < num_ssa_names; i++)
2276 : 79713910 : m_lattice[i].release ();
2277 : 3810425 : }
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 : 5370148 : modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg,
2305 : : tree name, bool direct,
2306 : : bool indirect)
2307 : : {
2308 : 5370148 : int index = SSA_NAME_VERSION (name);
2309 : 5370148 : bool returned_directly = false;
2310 : :
2311 : : /* If there is no return value, no flags are affected. */
2312 : 5370148 : 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 : 2923836 : if (arg >= 0)
2318 : : {
2319 : 2916490 : int flags = gimple_call_return_flags (call);
2320 : 2916490 : if (flags & ERF_RETURNS_ARG)
2321 : : {
2322 : 19079 : 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 : 2904757 : else if (!direct && !indirect)
2336 : : return;
2337 : :
2338 : : /* If return value is SSA name determine its flags. */
2339 : 2703761 : if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
2340 : : {
2341 : 2364855 : tree lhs = gimple_call_lhs (call);
2342 : 2364855 : if (direct)
2343 : 2225664 : merge_with_ssa_name (name, lhs, false);
2344 : 2364855 : if (indirect)
2345 : 1920985 : merge_with_ssa_name (name, lhs, true);
2346 : : }
2347 : : /* In the case of memory store we can do nothing. */
2348 : 338906 : else if (!direct)
2349 : 104998 : m_lattice[index].merge (deref_flags (0, false));
2350 : : else
2351 : 233908 : 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 : 4753633 : 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 : 4753633 : call_flags |= EAF_NOT_RETURNED_DIRECTLY
2365 : : | EAF_NOT_RETURNED_INDIRECTLY;
2366 : 4753633 : 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 : 4075570 : if (!(call_flags & EAF_NO_DIRECT_ESCAPE))
2372 : 3068159 : lattice.merge (0);
2373 : 1007411 : else if (!(call_flags & EAF_NO_INDIRECT_ESCAPE))
2374 : 466682 : 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 : 678063 : call_flags |= ignore_stores_eaf_flags;
2382 : 4753633 : 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 : 25981529 : modref_eaf_analysis::analyze_ssa_name (tree name, bool deferred)
2393 : : {
2394 : 25981529 : imm_use_iterator ui;
2395 : 25981529 : gimple *use_stmt;
2396 : 25981529 : int index = SSA_NAME_VERSION (name);
2397 : :
2398 : 25981529 : if (!deferred)
2399 : : {
2400 : : /* See if value is already computed. */
2401 : 25978777 : if (m_lattice[index].known || m_lattice[index].do_dataflow)
2402 : 4414453 : return;
2403 : 21937998 : if (m_lattice[index].open)
2404 : : {
2405 : 370922 : if (dump_file)
2406 : 41 : fprintf (dump_file,
2407 : : "%*sCycle in SSA graph\n",
2408 : 41 : m_depth * 4, "");
2409 : 370922 : return;
2410 : : }
2411 : : /* Recursion guard. */
2412 : 21567076 : m_lattice[index].init ();
2413 : 21567076 : if (m_depth == param_modref_max_depth)
2414 : : {
2415 : 2752 : if (dump_file)
2416 : 0 : fprintf (dump_file,
2417 : : "%*sMax recursion depth reached; postponing\n",
2418 : : m_depth * 4, "");
2419 : 2752 : m_deferred_names.safe_push (name);
2420 : 2752 : return;
2421 : : }
2422 : : }
2423 : :
2424 : 21567076 : 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 : 58599049 : FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
2433 : : {
2434 : 39896816 : if (m_lattice[index].flags == 0)
2435 : : break;
2436 : 37031973 : if (is_gimple_debug (use_stmt))
2437 : 5826083 : continue;
2438 : 31205890 : if (dump_file)
2439 : : {
2440 : 1477 : fprintf (dump_file, "%*s Analyzing stmt: ", m_depth * 4, "");
2441 : 1477 : 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 : 31205890 : 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 : 31205890 : if (greturn *ret = dyn_cast <greturn *> (use_stmt))
2450 : : {
2451 : : /* Returning through return slot is seen as memory write earlier. */
2452 : 1216125 : if (DECL_RESULT (current_function_decl)
2453 : 1216125 : && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2454 : : ;
2455 : 1171978 : else if (gimple_return_retval (ret) == name)
2456 : 1171978 : 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 : 29989765 : else if (gcall *call = dyn_cast <gcall *> (use_stmt))
2467 : : {
2468 : 5498202 : 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 : 5498202 : if (gimple_call_fn (use_stmt) == name)
2476 : 54079 : m_lattice[index].merge (~(EAF_NO_DIRECT_CLOBBER | EAF_UNUSED));
2477 : :
2478 : : /* Recursion would require bit of propagation; give up for now. */
2479 : 5498202 : if (callee && !m_ipa && recursive_call_p (current_function_decl,
2480 : : callee))
2481 : 12806 : m_lattice[index].merge (0);
2482 : : else
2483 : : {
2484 : 5485396 : int ecf_flags = gimple_call_flags (call);
2485 : 5485396 : bool ignore_stores = ignore_stores_p (current_function_decl,
2486 : : ecf_flags);
2487 : 5485396 : bool ignore_retval = ignore_retval_p (current_function_decl,
2488 : : ecf_flags);
2489 : :
2490 : : /* Handle *name = func (...). */
2491 : 5485396 : if (gimple_call_lhs (call)
2492 : 5485396 : && memory_access_to (gimple_call_lhs (call), name))
2493 : : {
2494 : 16321 : 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 : 16321 : if (gimple_call_return_slot_opt_p (call)
2499 : 16321 : && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
2500 : : {
2501 : 12613 : int call_flags = gimple_call_retslot_flags (call);
2502 : 12613 : bool isretslot = false;
2503 : :
2504 : 12613 : if (DECL_RESULT (current_function_decl)
2505 : 12613 : && DECL_BY_REFERENCE
2506 : : (DECL_RESULT (current_function_decl)))
2507 : 23976 : isretslot = ssa_default_def
2508 : 11988 : (cfun,
2509 : 11988 : 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 : 11988 : if (!isretslot)
2520 : : {
2521 : 625 : if (!(call_flags & (EAF_NOT_RETURNED_DIRECTLY
2522 : : | EAF_UNUSED)))
2523 : 455 : m_lattice[index].merge (0);
2524 : 170 : else gcc_checking_assert
2525 : : (call_flags & (EAF_NOT_RETURNED_INDIRECTLY
2526 : : | EAF_UNUSED));
2527 : 625 : call_flags = callee_to_caller_flags
2528 : 625 : (call_flags, false,
2529 : : m_lattice[index]);
2530 : : }
2531 : 12613 : m_lattice[index].merge (call_flags);
2532 : : }
2533 : : }
2534 : :
2535 : 5485396 : if (gimple_call_chain (call)
2536 : 5485396 : && (gimple_call_chain (call) == name))
2537 : : {
2538 : 27680 : int call_flags = gimple_call_static_chain_flags (call);
2539 : 27680 : if (!ignore_retval && !(call_flags & EAF_UNUSED))
2540 : 27680 : merge_call_lhs_flags
2541 : 27680 : (call, -1, name,
2542 : 27680 : !(call_flags & EAF_NOT_RETURNED_DIRECTLY),
2543 : 27680 : !(call_flags & EAF_NOT_RETURNED_INDIRECTLY));
2544 : 27680 : call_flags = callee_to_caller_flags
2545 : 27680 : (call_flags, ignore_stores,
2546 : : m_lattice[index]);
2547 : 27680 : if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2548 : 27680 : m_lattice[index].merge (call_flags);
2549 : : }
2550 : :
2551 : : /* Process internal functions and right away. */
2552 : 5485396 : bool record_ipa = m_ipa && !gimple_call_internal_p (call);
2553 : :
2554 : : /* Handle all function parameters. */
2555 : 20761749 : for (unsigned i = 0;
2556 : 20761749 : i < gimple_call_num_args (call)
2557 : 20761749 : && m_lattice[index].flags; i++)
2558 : : /* Name is directly passed to the callee. */
2559 : 15276353 : if (gimple_call_arg (call, i) == name)
2560 : : {
2561 : 5324394 : int call_flags = gimple_call_arg_flags (call, i);
2562 : 5324394 : if (!ignore_retval)
2563 : 5282374 : merge_call_lhs_flags
2564 : 5282374 : (call, i, name,
2565 : 5282374 : !(call_flags & (EAF_NOT_RETURNED_DIRECTLY
2566 : : | EAF_UNUSED)),
2567 : 5282374 : !(call_flags & (EAF_NOT_RETURNED_INDIRECTLY
2568 : : | EAF_UNUSED)));
2569 : 5324394 : if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2570 : : {
2571 : 4665364 : call_flags = callee_to_caller_flags
2572 : 4665364 : (call_flags, ignore_stores,
2573 : : m_lattice[index]);
2574 : 4665364 : if (!record_ipa)
2575 : 3183055 : m_lattice[index].merge (call_flags);
2576 : : else
2577 : 1482309 : m_lattice[index].add_escape_point (call, i,
2578 : : call_flags, true);
2579 : : }
2580 : : }
2581 : : /* Name is dereferenced and passed to a callee. */
2582 : 9951959 : else if (memory_access_to (gimple_call_arg (call, i), name))
2583 : : {
2584 : 60116 : int call_flags = deref_flags
2585 : 60116 : (gimple_call_arg_flags (call, i), ignore_stores);
2586 : 60116 : if (!ignore_retval && !(call_flags & EAF_UNUSED)
2587 : 60094 : && (call_flags & (EAF_NOT_RETURNED_DIRECTLY
2588 : : | EAF_NOT_RETURNED_INDIRECTLY))
2589 : : != (EAF_NOT_RETURNED_DIRECTLY
2590 : : | EAF_NOT_RETURNED_INDIRECTLY))
2591 : 60094 : merge_call_lhs_flags (call, i, name, false, true);
2592 : 60116 : if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
2593 : 152 : m_lattice[index].merge_direct_load ();
2594 : : else
2595 : : {
2596 : 59964 : call_flags = callee_to_caller_flags
2597 : 59964 : (call_flags, ignore_stores,
2598 : : m_lattice[index]);
2599 : 59964 : if (!record_ipa)
2600 : 38918 : m_lattice[index].merge (call_flags);
2601 : : else
2602 : 21046 : m_lattice[index].add_escape_point (call, i,
2603 : : call_flags, false);
2604 : : }
2605 : : }
2606 : : }
2607 : : }
2608 : 24491563 : else if (gimple_assign_load_p (use_stmt))
2609 : : {
2610 : 5536414 : gassign *assign = as_a <gassign *> (use_stmt);
2611 : : /* Memory to memory copy. */
2612 : 5536414 : 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 : 296659 : if (memory_access_to (gimple_assign_rhs1 (assign), name))
2619 : 202106 : m_lattice[index].merge (deref_flags (0, false));
2620 : :
2621 : : /* Handle *name = *exp. */
2622 : 296659 : if (memory_access_to (gimple_assign_lhs (assign), name))
2623 : 93736 : m_lattice[index].merge_direct_store ();
2624 : : }
2625 : : /* Handle lhs = *name. */
2626 : 5239755 : else if (memory_access_to (gimple_assign_rhs1 (assign), name))
2627 : : {
2628 : 5104895 : tree lhs = gimple_assign_lhs (assign);
2629 : 5104895 : merge_with_ssa_name (name, lhs, true);
2630 : : }
2631 : : }
2632 : 18955149 : else if (gimple_store_p (use_stmt))
2633 : : {
2634 : 4343661 : gassign *assign = dyn_cast <gassign *> (use_stmt);
2635 : :
2636 : : /* Handle *lhs = name. */
2637 : 4343661 : if (assign && gimple_assign_rhs1 (assign) == name)
2638 : : {
2639 : 1667065 : if (dump_file)
2640 : 63 : fprintf (dump_file, "%*s ssa name saved to memory\n",
2641 : 63 : m_depth * 4, "");
2642 : 1667065 : m_lattice[index].merge (0);
2643 : : }
2644 : : /* Handle *name = exp. */
2645 : 2676596 : else if (assign
2646 : 2676596 : && 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 : 2616180 : if (!cfun->after_inlining || !gimple_clobber_p (assign))
2654 : 2570172 : m_lattice[index].merge_direct_store ();
2655 : : }
2656 : : /* ASM statements etc. */
2657 : 60416 : 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 : 14611488 : else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
2665 : : {
2666 : 9311396 : 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 : 9311396 : if (!truth_value_p (code)
2671 : 8777224 : && code != POINTER_DIFF_EXPR
2672 : 17884168 : && (code != POINTER_PLUS_EXPR
2673 : 1240624 : || gimple_assign_rhs1 (assign) == name))
2674 : : {
2675 : 8141140 : tree lhs = gimple_assign_lhs (assign);
2676 : 8141140 : merge_with_ssa_name (name, lhs, false);
2677 : : }
2678 : : }
2679 : 5300092 : else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
2680 : : {
2681 : 1893529 : tree result = gimple_phi_result (phi);
2682 : 1893529 : merge_with_ssa_name (name, result, false);
2683 : : }
2684 : : /* Conditions are not considered escape points
2685 : : by tree-ssa-structalias. */
2686 : 3406563 : else if (gimple_code (use_stmt) == GIMPLE_COND)
2687 : : ;
2688 : : else
2689 : : {
2690 : 66273 : if (dump_file)
2691 : 6 : fprintf (dump_file, "%*s Unhandled stmt\n", m_depth * 4, "");
2692 : 66273 : m_lattice[index].merge (0);
2693 : : }
2694 : :
2695 : 31205890 : if (dump_file)
2696 : : {
2697 : 1477 : fprintf (dump_file, "%*s current flags of ", m_depth * 4, "");
2698 : 1477 : print_generic_expr (dump_file, name);
2699 : 1477 : m_lattice[index].dump (dump_file, m_depth * 4 + 4);
2700 : : }
2701 : 21567076 : }
2702 : 21567076 : 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 : 21567076 : m_lattice[index].open = false;
2709 : 21567076 : if (!m_lattice[index].do_dataflow)
2710 : 19478969 : 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 : 19286213 : modref_eaf_analysis::merge_with_ssa_name (tree dest, tree src, bool deref)
2718 : : {
2719 : 19286213 : int index = SSA_NAME_VERSION (dest);
2720 : 19286213 : int src_index = SSA_NAME_VERSION (src);
2721 : :
2722 : : /* Merging lattice with itself is a no-op. */
2723 : 19286213 : if (!deref && src == dest)
2724 : 26 : return;
2725 : :
2726 : 19286187 : m_depth++;
2727 : 19286187 : analyze_ssa_name (src);
2728 : 19286187 : m_depth--;
2729 : 19286187 : if (deref)
2730 : 7025880 : m_lattice[index].merge_deref (m_lattice[src_index], false);
2731 : : else
2732 : 12260307 : 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 : 19286187 : if (!m_lattice[src_index].known)
2737 : : {
2738 : 2579771 : modref_lattice::propagate_edge e = {index, deref};
2739 : :
2740 : 2579771 : if (!m_lattice[src_index].propagate_to.length ())
2741 : 1859417 : m_names_to_propagate.safe_push (src_index);
2742 : 2579771 : m_lattice[src_index].propagate_to.safe_push (e);
2743 : 2579771 : m_lattice[src_index].changed = true;
2744 : 2579771 : m_lattice[src_index].do_dataflow = true;
2745 : 2579771 : 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 : 3810425 : modref_eaf_analysis::propagate ()
2758 : : {
2759 : 3810425 : int iterations = 0;
2760 : 3810425 : size_t i;
2761 : 3810425 : int index;
2762 : 3810425 : bool changed = true;
2763 : :
2764 : 3813177 : while (m_deferred_names.length ())
2765 : : {
2766 : 2752 : tree name = m_deferred_names.pop ();
2767 : 2752 : if (dump_file)
2768 : 0 : fprintf (dump_file, "Analyzing deferred SSA name\n");
2769 : 2752 : analyze_ssa_name (name, true);
2770 : : }
2771 : :
2772 : 3810425 : if (!m_names_to_propagate.length ())
2773 : 3645055 : return;
2774 : 165370 : if (dump_file)
2775 : 41 : fprintf (dump_file, "Propagating EAF flags\n");
2776 : :
2777 : : /* Compute reverse postorder. */
2778 : 165370 : auto_vec <int> rpo;
2779 : 165370 : struct stack_entry
2780 : : {
2781 : : int name;
2782 : : unsigned pos;
2783 : : };
2784 : 165370 : auto_vec <struct stack_entry> stack;
2785 : 165370 : int pos = m_names_to_propagate.length () - 1;
2786 : :
2787 : 165370 : rpo.safe_grow (m_names_to_propagate.length (), true);
2788 : 330740 : stack.reserve_exact (m_names_to_propagate.length ());
2789 : :
2790 : : /* We reuse known flag for RPO DFS walk bookkeeping. */
2791 : 165370 : if (flag_checking)
2792 : 2024697 : FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2793 : 1859342 : gcc_assert (!m_lattice[index].known && m_lattice[index].changed);
2794 : :
2795 : 2024787 : FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2796 : : {
2797 : 1859417 : if (!m_lattice[index].known)
2798 : : {
2799 : 326936 : stack_entry e = {index, 0};
2800 : :
2801 : 326936 : stack.quick_push (e);
2802 : 326936 : m_lattice[index].known = true;
2803 : : }
2804 : 5251315 : while (stack.length ())
2805 : : {
2806 : 3391898 : bool found = false;
2807 : 3391898 : int index1 = stack.last ().name;
2808 : :
2809 : 4439188 : while (stack.last ().pos < m_lattice[index1].propagate_to.length ())
2810 : : {
2811 : 2579771 : int index2 = m_lattice[index1]
2812 : 2579771 : .propagate_to[stack.last ().pos].ssa_name;
2813 : :
2814 : 2579771 : stack.last ().pos++;
2815 : 2579771 : if (!m_lattice[index2].known
2816 : 3627061 : && m_lattice[index2].propagate_to.length ())
2817 : : {
2818 : 1532481 : stack_entry e = {index2, 0};
2819 : :
2820 : 1532481 : stack.quick_push (e);
2821 : 1532481 : m_lattice[index2].known = true;
2822 : 1532481 : found = true;
2823 : 1532481 : break;
2824 : : }
2825 : : }
2826 : 1532481 : if (!found
2827 : 3718834 : && stack.last ().pos == m_lattice[index1].propagate_to.length ())
2828 : : {
2829 : 1859417 : rpo[pos--] = index1;
2830 : 1859417 : stack.pop ();
2831 : : }
2832 : : }
2833 : : }
2834 : :
2835 : : /* Perform iterative dataflow. */
2836 : 420414 : while (changed)
2837 : : {
2838 : 255044 : changed = false;
2839 : 255044 : iterations++;
2840 : 255044 : if (dump_file)
2841 : 43 : fprintf (dump_file, " iteration %i\n", iterations);
2842 : 3830121 : FOR_EACH_VEC_ELT (rpo, i, index)
2843 : : {
2844 : 3154663 : if (m_lattice[index].changed)
2845 : : {
2846 : 1886757 : size_t j;
2847 : :
2848 : 1886757 : m_lattice[index].changed = false;
2849 : 1886757 : if (dump_file)
2850 : 96 : fprintf (dump_file, " Visiting ssa name %i\n", index);
2851 : 5776079 : for (j = 0; j < m_lattice[index].propagate_to.length (); j++)
2852 : : {
2853 : 2621416 : bool ch;
2854 : 2621416 : int target = m_lattice[index].propagate_to[j].ssa_name;
2855 : 2621416 : bool deref = m_lattice[index].propagate_to[j].deref;
2856 : :
2857 : 2621416 : 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 : 2621416 : m_lattice[target].known = true;
2862 : 2621416 : if (!m_lattice[index].propagate_to[j].deref)
2863 : 2272065 : ch = m_lattice[target].merge (m_lattice[index]);
2864 : : else
2865 : 349351 : ch = m_lattice[target].merge_deref (m_lattice[index],
2866 : : false);
2867 : 2621416 : if (!ch)
2868 : 2331171 : continue;
2869 : 290245 : if (dump_file)
2870 : : {
2871 : 4 : fprintf (dump_file, " New lattice: ");
2872 : 4 : m_lattice[target].dump (dump_file);
2873 : : }
2874 : 290245 : changed = true;
2875 : 290245 : m_lattice[target].changed = true;
2876 : : }
2877 : : }
2878 : : }
2879 : : }
2880 : 165370 : if (dump_file)
2881 : 41 : fprintf (dump_file, "EAF flags propagated in %i iterations\n", iterations);
2882 : 165370 : }
2883 : :
2884 : : /* Record escape points of PARM_INDEX according to LATTICE. */
2885 : :
2886 : : void
2887 : 3160805 : modref_eaf_analysis::record_escape_points (tree name, int parm_index, int flags)
2888 : : {
2889 : 3160805 : modref_lattice &lattice = m_lattice[SSA_NAME_VERSION (name)];
2890 : :
2891 : 3160805 : if (lattice.escape_points.length ())
2892 : : {
2893 : 170841 : escape_point *ep;
2894 : 170841 : unsigned int ip;
2895 : 170841 : cgraph_node *node = cgraph_node::get (current_function_decl);
2896 : :
2897 : 170841 : gcc_assert (m_ipa);
2898 : 440445 : FOR_EACH_VEC_ELT (lattice.escape_points, ip, ep)
2899 : 269604 : if ((ep->min_flags & flags) != flags)
2900 : : {
2901 : 235251 : cgraph_edge *e = node->get_edge (ep->call);
2902 : 235251 : struct escape_entry ee = {parm_index, ep->arg,
2903 : 235251 : ep->min_flags, ep->direct};
2904 : :
2905 : 235251 : escape_summaries->get_create (e)->esc.safe_push (ee);
2906 : : }
2907 : : }
2908 : 3160805 : }
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 : 4494976 : 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 : 4494976 : unsigned int parm_index = 0;
2924 : 4494976 : unsigned int count = 0;
2925 : 4494976 : int ecf_flags = flags_from_decl_or_type (current_function_decl);
2926 : 4494976 : tree retslot = NULL;
2927 : 4494976 : tree static_chain = NULL;
2928 : :
2929 : : /* If there is return slot, look up its SSA name. */
2930 : 4494976 : if (DECL_RESULT (current_function_decl)
2931 : 4494976 : && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2932 : 57020 : retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
2933 : 4494976 : if (cfun->static_chain_decl)
2934 : 48721 : static_chain = ssa_default_def (cfun, cfun->static_chain_decl);
2935 : :
2936 : 14226294 : for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2937 : 9731318 : parm = TREE_CHAIN (parm))
2938 : 9731318 : count++;
2939 : :
2940 : 4494976 : if (!count && !retslot && !static_chain)
2941 : 684551 : return;
2942 : :
2943 : 3810425 : modref_eaf_analysis eaf_analysis (ipa);
2944 : :
2945 : : /* Determine all SSA names we need to know flags for. */
2946 : 13541743 : for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2947 : 9731318 : parm = TREE_CHAIN (parm))
2948 : : {
2949 : 9731318 : tree name = ssa_default_def (cfun, parm);
2950 : 9731318 : if (name)
2951 : 6587240 : eaf_analysis.analyze_ssa_name (name);
2952 : : }
2953 : 3810425 : if (retslot)
2954 : 56833 : eaf_analysis.analyze_ssa_name (retslot);
2955 : 3810425 : if (static_chain)
2956 : 48517 : eaf_analysis.analyze_ssa_name (static_chain);
2957 : :
2958 : : /* Do the dataflow. */
2959 : 3810425 : eaf_analysis.propagate ();
2960 : :
2961 : 3810425 : tree attr = lookup_attribute ("fn spec",
2962 : 3810425 : TYPE_ATTRIBUTES
2963 : : (TREE_TYPE (current_function_decl)));
2964 : 3810425 : attr_fnspec fnspec (attr
2965 : 102148 : ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)))
2966 : 3912573 : : "");
2967 : :
2968 : :
2969 : : /* Store results to summaries. */
2970 : 13541743 : for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
2971 : 9731318 : parm = TREE_CHAIN (parm))
2972 : : {
2973 : 9731318 : tree name = ssa_default_def (cfun, parm);
2974 : 9731318 : 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 : 3391173 : if (!is_gimple_reg (parm))
2979 : 619402 : continue;
2980 : 2771771 : if (summary)
2981 : : {
2982 : 2663449 : if (parm_index >= summary->arg_flags.length ())
2983 : 605371 : summary->arg_flags.safe_grow_cleared (count, true);
2984 : 2663449 : summary->arg_flags[parm_index] = EAF_UNUSED;
2985 : : }
2986 : 2771771 : if (summary_lto)
2987 : : {
2988 : 217872 : if (parm_index >= summary_lto->arg_flags.length ())
2989 : 9653 : summary_lto->arg_flags.safe_grow_cleared (count, true);
2990 : 217872 : summary_lto->arg_flags[parm_index] = EAF_UNUSED;
2991 : : }
2992 : 2771771 : continue;
2993 : : }
2994 : 6340145 : int flags = eaf_analysis.get_ssa_name_flags (name);
2995 : 6340145 : int attr_flags = fnspec.arg_eaf_flags (parm_index);
2996 : :
2997 : 6340145 : 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 : 6340145 : flags |= attr_flags;
3007 : :
3008 : : /* Eliminate useless flags so we do not end up storing unnecessary
3009 : : summaries. */
3010 : :
3011 : 6340145 : flags = remove_useless_eaf_flags
3012 : 6340145 : (flags, ecf_flags,
3013 : 6340145 : VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3014 : 6340145 : if (past_flags.length () > parm_index)
3015 : : {
3016 : 665080 : int past = past_flags[parm_index];
3017 : 665080 : past = remove_useless_eaf_flags
3018 : 665080 : (past, ecf_flags,
3019 : 665080 : 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 : 665080 : past &= ~(EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ);
3024 : 665080 : 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 : 665080 : if (!(flags & EAF_UNUSED))
3034 : 665080 : flags |= past;
3035 : : }
3036 : :
3037 : 6340145 : if (flags)
3038 : : {
3039 : 3074397 : if (summary)
3040 : : {
3041 : 3047631 : if (parm_index >= summary->arg_flags.length ())
3042 : 1919385 : summary->arg_flags.safe_grow_cleared (count, true);
3043 : 3047631 : summary->arg_flags[parm_index] = flags;
3044 : : }
3045 : 3074397 : if (summary_lto)
3046 : : {
3047 : 60785 : if (parm_index >= summary_lto->arg_flags.length ())
3048 : 42855 : summary_lto->arg_flags.safe_grow_cleared (count, true);
3049 : 60785 : summary_lto->arg_flags[parm_index] = flags;
3050 : : }
3051 : 3074397 : eaf_analysis.record_escape_points (name, parm_index, flags);
3052 : : }
3053 : : }
3054 : 3810425 : if (retslot)
3055 : : {
3056 : 56833 : int flags = eaf_analysis.get_ssa_name_flags (retslot);
3057 : 56833 : int past = past_retslot_flags;
3058 : :
3059 : 56833 : flags = remove_useless_eaf_flags (flags, ecf_flags, false);
3060 : 56833 : past = remove_useless_eaf_flags
3061 : 56833 : (past, ecf_flags,
3062 : 56833 : VOID_TYPE_P (TREE_TYPE
3063 : : (TREE_TYPE (current_function_decl))));
3064 : 56833 : 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 : 56833 : if (!(flags & EAF_UNUSED))
3073 : 56750 : flags |= past;
3074 : 56750 : if (flags)
3075 : : {
3076 : 39453 : if (summary)
3077 : 39311 : summary->retslot_flags = flags;
3078 : 39453 : if (summary_lto)
3079 : 284 : summary_lto->retslot_flags = flags;
3080 : 39453 : eaf_analysis.record_escape_points (retslot,
3081 : : MODREF_RETSLOT_PARM, flags);
3082 : : }
3083 : : }
3084 : 3810425 : if (static_chain)
3085 : : {
3086 : 48517 : int flags = eaf_analysis.get_ssa_name_flags (static_chain);
3087 : 48517 : int past = past_static_chain_flags;
3088 : :
3089 : 48517 : flags = remove_useless_eaf_flags (flags, ecf_flags, false);
3090 : 48517 : past = remove_useless_eaf_flags
3091 : 48517 : (past, ecf_flags,
3092 : 48517 : VOID_TYPE_P (TREE_TYPE
3093 : : (TREE_TYPE (current_function_decl))));
3094 : 48517 : 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 : 48517 : if (!(flags & EAF_UNUSED))
3103 : 48433 : flags |= past;
3104 : 48433 : if (flags)
3105 : : {
3106 : 46955 : if (summary)
3107 : 46880 : summary->static_chain_flags = flags;
3108 : 46955 : if (summary_lto)
3109 : 153 : summary_lto->static_chain_flags = flags;
3110 : 46955 : eaf_analysis.record_escape_points (static_chain,
3111 : : MODREF_STATIC_CHAIN_PARM,
3112 : : flags);
3113 : : }
3114 : : }
3115 : 3810425 : }
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 : 4974584 : analyze_function (bool ipa)
3123 : : {
3124 : 4974584 : bool fixup_cfg = false;
3125 : 4974584 : if (dump_file)
3126 : 188 : fprintf (dump_file, "\n\nmodref analyzing '%s' (ipa=%i)%s%s\n",
3127 : 188 : cgraph_node::get (current_function_decl)->dump_name (), ipa,
3128 : 188 : TREE_READONLY (current_function_decl) ? " (const)" : "",
3129 : 188 : DECL_PURE_P (current_function_decl) ? " (pure)" : "");
3130 : :
3131 : : /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
3132 : 4974584 : if (!flag_ipa_modref
3133 : 4974584 : || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
3134 : 479608 : return false;
3135 : :
3136 : : /* Compute no-LTO summaries when local optimization is going to happen. */
3137 : 1271803 : bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
3138 : 4535461 : || (in_lto_p && !flag_wpa
3139 : 883 : && flag_incremental_link != INCREMENTAL_LINK_LTO));
3140 : : /* Compute LTO when LTO streaming is going to happen. */
3141 : 1271803 : bool lto = ipa && ((flag_lto && !in_lto_p)
3142 : 1181764 : || flag_wpa
3143 : 1181691 : || flag_incremental_link == INCREMENTAL_LINK_LTO);
3144 : 4494976 : cgraph_node *fnode = cgraph_node::get (current_function_decl);
3145 : :
3146 : 4494976 : modref_summary *summary = NULL;
3147 : 4494976 : modref_summary_lto *summary_lto = NULL;
3148 : :
3149 : 4494976 : bool past_flags_known = false;
3150 : 4494976 : auto_vec <eaf_flags_t> past_flags;
3151 : 4494976 : int past_retslot_flags = 0;
3152 : 4494976 : 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 : 4494976 : if (!ipa)
3159 : : {
3160 : 3223173 : if (!optimization_summaries)
3161 : 137934 : optimization_summaries = modref_summaries::create_ggc (symtab);
3162 : : else /* Remove existing summary if we are re-running the pass. */
3163 : : {
3164 : 3085239 : summary = optimization_summaries->get (fnode);
3165 : 3085239 : if (summary != NULL
3166 : 709649 : && summary->loads)
3167 : : {
3168 : 709649 : if (dump_file)
3169 : : {
3170 : 23 : fprintf (dump_file, "Past summary:\n");
3171 : 23 : optimization_summaries->get (fnode)->dump (dump_file);
3172 : : }
3173 : 1138920 : past_flags.reserve_exact (summary->arg_flags.length ());
3174 : 709649 : past_flags.splice (summary->arg_flags);
3175 : 709649 : past_retslot_flags = summary->retslot_flags;
3176 : 709649 : past_static_chain_flags = summary->static_chain_flags;
3177 : 709649 : past_flags_known = true;
3178 : : }
3179 : 3085239 : optimization_summaries->remove (fnode);
3180 : : }
3181 : 3223173 : summary = optimization_summaries->get_create (fnode);
3182 : 3223173 : gcc_checking_assert (nolto && !lto);
3183 : : }
3184 : : /* In IPA mode we analyze every function precisely once. Assert that. */
3185 : : else
3186 : : {
3187 : 1271803 : if (nolto)
3188 : : {
3189 : 1232201 : if (!summaries)
3190 : 129253 : summaries = modref_summaries::create_ggc (symtab);
3191 : : else
3192 : 1102948 : summaries->remove (fnode);
3193 : 1232201 : summary = summaries->get_create (fnode);
3194 : : }
3195 : 1271803 : if (lto)
3196 : : {
3197 : 90112 : if (!summaries_lto)
3198 : 18656 : summaries_lto = modref_summaries_lto::create_ggc (symtab);
3199 : : else
3200 : 71456 : summaries_lto->remove (fnode);
3201 : 90112 : summary_lto = summaries_lto->get_create (fnode);
3202 : : }
3203 : 1271803 : if (!fnspec_summaries)
3204 : 137844 : fnspec_summaries = new fnspec_summaries_t (symtab);
3205 : 1271803 : if (!escape_summaries)
3206 : 137844 : 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 : 1271803 : if (nolto)
3214 : : {
3215 : 4455374 : gcc_assert (!summary->loads);
3216 : 4455374 : summary->loads = modref_records::create_ggc ();
3217 : 4455374 : gcc_assert (!summary->stores);
3218 : 4455374 : summary->stores = modref_records::create_ggc ();
3219 : 4455374 : summary->writes_errno = false;
3220 : 4455374 : summary->side_effects = false;
3221 : 4455374 : summary->nondeterministic = false;
3222 : 4455374 : summary->calls_interposable = false;
3223 : : }
3224 : 4494976 : if (lto)
3225 : : {
3226 : 90112 : gcc_assert (!summary_lto->loads);
3227 : 90112 : summary_lto->loads = modref_records_lto::create_ggc ();
3228 : 90112 : gcc_assert (!summary_lto->stores);
3229 : 90112 : summary_lto->stores = modref_records_lto::create_ggc ();
3230 : 90112 : summary_lto->writes_errno = false;
3231 : 90112 : summary_lto->side_effects = false;
3232 : 90112 : summary_lto->nondeterministic = false;
3233 : 90112 : summary_lto->calls_interposable = false;
3234 : : }
3235 : :
3236 : 4494976 : analyze_parms (summary, summary_lto, ipa,
3237 : : past_flags, past_retslot_flags, past_static_chain_flags);
3238 : :
3239 : 4494976 : {
3240 : 4494976 : modref_access_analysis analyzer (ipa, summary, summary_lto);
3241 : 4494976 : analyzer.analyze ();
3242 : 4494976 : }
3243 : :
3244 : 4494976 : if (!ipa && flag_ipa_pure_const)
3245 : : {
3246 : 3223038 : if (!summary->stores->every_base && !summary->stores->bases
3247 : 1067350 : && !summary->nondeterministic)
3248 : : {
3249 : 1038387 : if (!summary->loads->every_base && !summary->loads->bases
3250 : 644829 : && !summary->calls_interposable)
3251 : 642389 : fixup_cfg = ipa_make_function_const (fnode,
3252 : : summary->side_effects, true);
3253 : : else
3254 : 395998 : fixup_cfg = ipa_make_function_pure (fnode,
3255 : : summary->side_effects, true);
3256 : : }
3257 : : }
3258 : 4494976 : int ecf_flags = flags_from_decl_or_type (current_function_decl);
3259 : 4494976 : if (summary && !summary->useful_p (ecf_flags))
3260 : : {
3261 : 1095136 : if (!ipa)
3262 : 957141 : optimization_summaries->remove (fnode);
3263 : : else
3264 : 137995 : summaries->remove (fnode);
3265 : : summary = NULL;
3266 : : }
3267 : 3399840 : if (summary)
3268 : 3360238 : summary->finalize (current_function_decl);
3269 : 4494976 : if (summary_lto && !summary_lto->useful_p (ecf_flags))
3270 : : {
3271 : 8842 : summaries_lto->remove (fnode);
3272 : 8842 : summary_lto = NULL;
3273 : : }
3274 : :
3275 : 4494976 : if (ipa && !summary && !summary_lto)
3276 : 142148 : remove_modref_edge_summaries (fnode);
3277 : :
3278 : 4494976 : if (dump_file)
3279 : : {
3280 : 153 : fprintf (dump_file, " - modref done with result: tracked.\n");
3281 : 153 : if (summary)
3282 : 127 : summary->dump (dump_file);
3283 : 153 : if (summary_lto)
3284 : 14 : summary_lto->dump (dump_file);
3285 : 153 : dump_modref_edge_summaries (dump_file, fnode, 2);
3286 : : /* To simplify debugging, compare IPA and local solutions. */
3287 : 153 : 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 : 130 : 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 : 4494976 : return fixup_cfg;
3385 : 4494976 : }
3386 : :
3387 : : /* Callback for generate_summary. */
3388 : :
3389 : : static void
3390 : 227164 : modref_generate (void)
3391 : : {
3392 : 227164 : struct cgraph_node *node;
3393 : 1926002 : FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
3394 : : {
3395 : 1698838 : function *f = DECL_STRUCT_FUNCTION (node->decl);
3396 : 1698838 : if (!f)
3397 : 0 : continue;
3398 : 1698838 : push_cfun (f);
3399 : 1698838 : analyze_function (true);
3400 : 1698838 : pop_cfun ();
3401 : : }
3402 : 227164 : }
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 : 82046 : modref_summaries::insert (struct cgraph_node *node, modref_summary *)
3418 : : {
3419 : : /* Local passes ought to be executed by the pass manager. */
3420 : 82046 : if (this == optimization_summaries)
3421 : : {
3422 : 64187 : optimization_summaries->remove (node);
3423 : 64187 : return;
3424 : : }
3425 : 17859 : if (!DECL_STRUCT_FUNCTION (node->decl)
3426 : 17859 : || !opt_for_fn (node->decl, flag_ipa_modref))
3427 : : {
3428 : 0 : summaries->remove (node);
3429 : 0 : return;
3430 : : }
3431 : 17859 : push_cfun (DECL_STRUCT_FUNCTION (node->decl));
3432 : 17859 : analyze_function (true);
3433 : 17859 : pop_cfun ();
3434 : : }
3435 : :
3436 : : /* Called when a new function is inserted to callgraph late. */
3437 : :
3438 : : void
3439 : 1507 : 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 : 1507 : if (!DECL_STRUCT_FUNCTION (node->decl)
3445 : 1507 : || !opt_for_fn (node->decl, flag_ipa_modref)
3446 : 3013 : || propagated)
3447 : : {
3448 : 373 : summaries_lto->remove (node);
3449 : 373 : return;
3450 : : }
3451 : 1134 : push_cfun (DECL_STRUCT_FUNCTION (node->decl));
3452 : 1134 : analyze_function (true);
3453 : 1134 : pop_cfun ();
3454 : : }
3455 : :
3456 : : /* Called when new clone is inserted to callgraph late. */
3457 : :
3458 : : void
3459 : 2433053 : 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 : 2433053 : if (this == optimization_summaries)
3466 : : {
3467 : 1822065 : optimization_summaries->remove (dst);
3468 : 1822065 : return;
3469 : : }
3470 : 610988 : dst_data->stores = modref_records::create_ggc ();
3471 : 610988 : dst_data->stores->copy_from (src_data->stores);
3472 : 610988 : dst_data->loads = modref_records::create_ggc ();
3473 : 610988 : dst_data->loads->copy_from (src_data->loads);
3474 : 718523 : dst_data->kills.reserve_exact (src_data->kills.length ());
3475 : 610988 : dst_data->kills.splice (src_data->kills);
3476 : 610988 : dst_data->writes_errno = src_data->writes_errno;
3477 : 610988 : dst_data->side_effects = src_data->side_effects;
3478 : 610988 : dst_data->nondeterministic = src_data->nondeterministic;
3479 : 610988 : dst_data->calls_interposable = src_data->calls_interposable;
3480 : 610988 : if (src_data->arg_flags.length ())
3481 : 380770 : dst_data->arg_flags = src_data->arg_flags.copy ();
3482 : 610988 : dst_data->retslot_flags = src_data->retslot_flags;
3483 : 610988 : 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 : 32013 : 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 : 32013 : gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
3496 : 32013 : dst_data->stores = modref_records_lto::create_ggc ();
3497 : 32013 : dst_data->stores->copy_from (src_data->stores);
3498 : 32013 : dst_data->loads = modref_records_lto::create_ggc ();
3499 : 32013 : dst_data->loads->copy_from (src_data->loads);
3500 : 32663 : dst_data->kills.reserve_exact (src_data->kills.length ());
3501 : 32013 : dst_data->kills.splice (src_data->kills);
3502 : 32013 : dst_data->writes_errno = src_data->writes_errno;
3503 : 32013 : dst_data->side_effects = src_data->side_effects;
3504 : 32013 : dst_data->nondeterministic = src_data->nondeterministic;
3505 : 32013 : dst_data->calls_interposable = src_data->calls_interposable;
3506 : 32013 : if (src_data->arg_flags.length ())
3507 : 29803 : dst_data->arg_flags = src_data->arg_flags.copy ();
3508 : 32013 : dst_data->retslot_flags = src_data->retslot_flags;
3509 : 32013 : dst_data->static_chain_flags = src_data->static_chain_flags;
3510 : 32013 : }
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 : 565906 : pass_modref (gcc::context *ctxt)
3531 : 1131812 : : gimple_opt_pass (pass_data_modref, ctxt) {}
3532 : :
3533 : : /* opt_pass methods: */
3534 : 282953 : opt_pass *clone () final override
3535 : : {
3536 : 282953 : return new pass_modref (m_ctxt);
3537 : : }
3538 : 3260387 : bool gate (function *) final override
3539 : : {
3540 : 3260387 : 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 : 188104 : write_modref_records (modref_records_lto *tt, struct output_block *ob)
3549 : : {
3550 : 188104 : streamer_write_uhwi (ob, tt->every_base);
3551 : 249182 : streamer_write_uhwi (ob, vec_safe_length (tt->bases));
3552 : 386484 : for (auto base_node : tt->bases)
3553 : : {
3554 : 76224 : stream_write_tree (ob, base_node->base, true);
3555 : :
3556 : 76224 : streamer_write_uhwi (ob, base_node->every_ref);
3557 : 152221 : streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
3558 : :
3559 : 307111 : for (auto ref_node : base_node->refs)
3560 : : {
3561 : 78893 : stream_write_tree (ob, ref_node->ref, true);
3562 : 78893 : streamer_write_uhwi (ob, ref_node->every_access);
3563 : 99764 : streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
3564 : :
3565 : 143126 : for (auto access_node : ref_node->accesses)
3566 : 22491 : access_node.stream_out (ob);
3567 : : }
3568 : : }
3569 : 188104 : }
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 : 164236 : 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 : 164236 : size_t max_bases = opt_for_fn (decl, param_modref_max_bases);
3583 : 164236 : size_t max_refs = opt_for_fn (decl, param_modref_max_refs);
3584 : 164236 : size_t max_accesses = opt_for_fn (decl, param_modref_max_accesses);
3585 : :
3586 : 164236 : if (lto_ret)
3587 : 76698 : *lto_ret = modref_records_lto::create_ggc ();
3588 : 164236 : if (nolto_ret)
3589 : 87632 : *nolto_ret = modref_records::create_ggc ();
3590 : 164236 : gcc_checking_assert (lto_ret || nolto_ret);
3591 : :
3592 : 164236 : size_t every_base = streamer_read_uhwi (ib);
3593 : 164236 : size_t nbase = streamer_read_uhwi (ib);
3594 : :
3595 : 164236 : gcc_assert (!every_base || nbase == 0);
3596 : 164236 : if (every_base)
3597 : : {
3598 : 11218 : if (nolto_ret)
3599 : 9766 : (*nolto_ret)->collapse ();
3600 : 11218 : if (lto_ret)
3601 : 1452 : (*lto_ret)->collapse ();
3602 : : }
3603 : 227643 : for (size_t i = 0; i < nbase; i++)
3604 : : {
3605 : 63407 : tree base_tree = stream_read_tree (ib, data_in);
3606 : 63407 : modref_base_node <alias_set_type> *nolto_base_node = NULL;
3607 : 63407 : 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 : 63407 : if (base_tree && !get_alias_set (base_tree))
3614 : : {
3615 : 7 : 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 : 63407 : if (nolto_ret)
3625 : 71691 : nolto_base_node = (*nolto_ret)->insert_base (base_tree
3626 : 35291 : ? get_alias_set (base_tree)
3627 : : : 0, 0, INT_MAX);
3628 : 63407 : if (lto_ret)
3629 : 27043 : lto_base_node = (*lto_ret)->insert_base (base_tree, 0, max_bases);
3630 : 63407 : size_t every_ref = streamer_read_uhwi (ib);
3631 : 63407 : size_t nref = streamer_read_uhwi (ib);
3632 : :
3633 : 63407 : gcc_assert (!every_ref || nref == 0);
3634 : 63407 : if (every_ref)
3635 : : {
3636 : 100 : if (nolto_base_node)
3637 : 46 : nolto_base_node->collapse ();
3638 : 100 : if (lto_base_node)
3639 : 54 : lto_base_node->collapse ();
3640 : : }
3641 : 128897 : for (size_t j = 0; j < nref; j++)
3642 : : {
3643 : 65490 : tree ref_tree = stream_read_tree (ib, data_in);
3644 : :
3645 : 65490 : if (ref_tree && !get_alias_set (ref_tree))
3646 : : {
3647 : 29 : 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 : 65490 : modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
3657 : 65490 : modref_ref_node <tree> *lto_ref_node = NULL;
3658 : :
3659 : 65490 : if (nolto_base_node)
3660 : 37426 : nolto_ref_node
3661 : 74088 : = nolto_base_node->insert_ref (ref_tree
3662 : 36662 : ? get_alias_set (ref_tree) : 0,
3663 : : max_refs);
3664 : 65490 : if (lto_base_node)
3665 : 28100 : lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
3666 : :
3667 : 65490 : size_t every_access = streamer_read_uhwi (ib);
3668 : 65490 : size_t naccesses = streamer_read_uhwi (ib);
3669 : :
3670 : 65490 : if (nolto_ref_node && every_access)
3671 : 29497 : nolto_ref_node->collapse ();
3672 : 65490 : if (lto_ref_node && every_access)
3673 : 20339 : lto_ref_node->collapse ();
3674 : :
3675 : 81972 : for (size_t k = 0; k < naccesses; k++)
3676 : : {
3677 : 16482 : modref_access_node a = modref_access_node::stream_in (ib);
3678 : 16482 : if (nolto_ref_node)
3679 : 8299 : nolto_ref_node->insert_access (a, max_accesses, false);
3680 : 16482 : if (lto_ref_node)
3681 : 8203 : lto_ref_node->insert_access (a, max_accesses, false);
3682 : : }
3683 : : }
3684 : : }
3685 : 164236 : if (lto_ret)
3686 : 76698 : (*lto_ret)->cleanup ();
3687 : 164236 : if (nolto_ret)
3688 : 87632 : (*nolto_ret)->cleanup ();
3689 : 164236 : }
3690 : :
3691 : : /* Write ESUM to BP. */
3692 : :
3693 : : static void
3694 : 325499 : modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
3695 : : {
3696 : 325499 : if (!esum)
3697 : : {
3698 : 302314 : bp_pack_var_len_unsigned (bp, 0);
3699 : 302314 : return;
3700 : : }
3701 : 23185 : bp_pack_var_len_unsigned (bp, esum->esc.length ());
3702 : 23185 : unsigned int i;
3703 : 23185 : escape_entry *ee;
3704 : 70006 : FOR_EACH_VEC_ELT (esum->esc, i, ee)
3705 : : {
3706 : 23636 : bp_pack_var_len_int (bp, ee->parm_index);
3707 : 23636 : bp_pack_var_len_unsigned (bp, ee->arg);
3708 : 23636 : bp_pack_var_len_unsigned (bp, ee->min_flags);
3709 : 23636 : bp_pack_value (bp, ee->direct, 1);
3710 : : }
3711 : : }
3712 : :
3713 : : /* Read escape summary for E from BP. */
3714 : :
3715 : : static void
3716 : 307087 : modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
3717 : : {
3718 : 307087 : unsigned int n = bp_unpack_var_len_unsigned (bp);
3719 : 307087 : if (!n)
3720 : : return;
3721 : 22712 : escape_summary *esum = escape_summaries->get_create (e);
3722 : 22712 : esum->esc.reserve_exact (n);
3723 : 45822 : for (unsigned int i = 0; i < n; i++)
3724 : : {
3725 : 23110 : escape_entry ee;
3726 : 23110 : ee.parm_index = bp_unpack_var_len_int (bp);
3727 : 23110 : ee.arg = bp_unpack_var_len_unsigned (bp);
3728 : 23110 : ee.min_flags = bp_unpack_var_len_unsigned (bp);
3729 : 23110 : ee.direct = bp_unpack_value (bp, 1);
3730 : 23110 : esum->esc.quick_push (ee);
3731 : : }
3732 : : }
3733 : :
3734 : : /* Callback for write_summary. */
3735 : :
3736 : : static void
3737 : 33014 : modref_write ()
3738 : : {
3739 : 33014 : struct output_block *ob = create_output_block (LTO_section_ipa_modref);
3740 : 33014 : lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
3741 : 33014 : unsigned int count = 0;
3742 : 33014 : int i;
3743 : :
3744 : 33014 : if (!summaries_lto)
3745 : : {
3746 : 5221 : streamer_write_uhwi (ob, 0);
3747 : 5221 : streamer_write_char_stream (ob->main_stream, 0);
3748 : 5221 : produce_asm (ob);
3749 : 5221 : destroy_output_block (ob);
3750 : 5221 : return;
3751 : : }
3752 : :
3753 : 617143 : for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3754 : : {
3755 : 280783 : symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3756 : 561566 : cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3757 : 201188 : modref_summary_lto *r;
3758 : :
3759 : 201188 : if (cnode && cnode->definition && !cnode->alias
3760 : 144510 : && (r = summaries_lto->get (cnode))
3761 : 97658 : && r->useful_p (flags_from_decl_or_type (cnode->decl)))
3762 : 94052 : count++;
3763 : : }
3764 : 27793 : streamer_write_uhwi (ob, count);
3765 : :
3766 : 617143 : for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3767 : : {
3768 : 280783 : symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3769 : 561566 : cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3770 : :
3771 : 201188 : if (cnode && cnode->definition && !cnode->alias)
3772 : : {
3773 : 144510 : modref_summary_lto *r = summaries_lto->get (cnode);
3774 : :
3775 : 144510 : if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
3776 : 50458 : continue;
3777 : :
3778 : 94052 : streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
3779 : :
3780 : 94052 : streamer_write_uhwi (ob, r->arg_flags.length ());
3781 : 391953 : for (unsigned int i = 0; i < r->arg_flags.length (); i++)
3782 : 297901 : streamer_write_uhwi (ob, r->arg_flags[i]);
3783 : 94052 : streamer_write_uhwi (ob, r->retslot_flags);
3784 : 94052 : streamer_write_uhwi (ob, r->static_chain_flags);
3785 : :
3786 : 94052 : write_modref_records (r->loads, ob);
3787 : 94052 : write_modref_records (r->stores, ob);
3788 : 98509 : streamer_write_uhwi (ob, r->kills.length ());
3789 : 108235 : for (auto kill : r->kills)
3790 : 5269 : kill.stream_out (ob);
3791 : :
3792 : 94052 : struct bitpack_d bp = bitpack_create (ob->main_stream);
3793 : 94052 : bp_pack_value (&bp, r->writes_errno, 1);
3794 : 94052 : bp_pack_value (&bp, r->side_effects, 1);
3795 : 94052 : bp_pack_value (&bp, r->nondeterministic, 1);
3796 : 94052 : bp_pack_value (&bp, r->calls_interposable, 1);
3797 : 94052 : if (!flag_wpa)
3798 : : {
3799 : 79433 : for (cgraph_edge *e = cnode->indirect_calls;
3800 : 81145 : e; e = e->next_callee)
3801 : : {
3802 : 1712 : class fnspec_summary *sum = fnspec_summaries->get (e);
3803 : 1712 : bp_pack_value (&bp, sum != NULL, 1);
3804 : 1712 : if (sum)
3805 : 0 : bp_pack_string (ob, &bp, sum->fnspec, true);
3806 : 1712 : class escape_summary *esum = escape_summaries->get (e);
3807 : 1712 : modref_write_escape_summary (&bp,esum);
3808 : : }
3809 : 403220 : for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
3810 : : {
3811 : 323787 : class fnspec_summary *sum = fnspec_summaries->get (e);
3812 : 323787 : bp_pack_value (&bp, sum != NULL, 1);
3813 : 323787 : if (sum)
3814 : 73838 : bp_pack_string (ob, &bp, sum->fnspec, true);
3815 : 323787 : class escape_summary *esum = escape_summaries->get (e);
3816 : 323787 : modref_write_escape_summary (&bp,esum);
3817 : : }
3818 : : }
3819 : 94052 : streamer_write_bitpack (&bp);
3820 : : }
3821 : : }
3822 : 27793 : streamer_write_char_stream (ob->main_stream, 0);
3823 : 27793 : produce_asm (ob);
3824 : 27793 : destroy_output_block (ob);
3825 : : }
3826 : :
3827 : : static void
3828 : 23094 : read_section (struct lto_file_decl_data *file_data, const char *data,
3829 : : size_t len)
3830 : : {
3831 : 23094 : const struct lto_function_header *header
3832 : : = (const struct lto_function_header *) data;
3833 : 23094 : const int cfg_offset = sizeof (struct lto_function_header);
3834 : 23094 : const int main_offset = cfg_offset + header->cfg_size;
3835 : 23094 : const int string_offset = main_offset + header->main_size;
3836 : 23094 : struct data_in *data_in;
3837 : 23094 : unsigned int i;
3838 : 23094 : unsigned int f_count;
3839 : :
3840 : 23094 : lto_input_block ib ((const char *) data + main_offset, header->main_size,
3841 : 23094 : file_data);
3842 : :
3843 : 23094 : data_in
3844 : 46188 : = lto_data_in_create (file_data, (const char *) data + string_offset,
3845 : 23094 : header->string_size, vNULL);
3846 : 23094 : f_count = streamer_read_uhwi (&ib);
3847 : 105212 : for (i = 0; i < f_count; i++)
3848 : : {
3849 : 82118 : struct cgraph_node *node;
3850 : 82118 : lto_symtab_encoder_t encoder;
3851 : :
3852 : 82118 : unsigned int index = streamer_read_uhwi (&ib);
3853 : 82118 : encoder = file_data->symtab_node_encoder;
3854 : 82118 : node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
3855 : : index));
3856 : :
3857 : 82118 : modref_summary *modref_sum = summaries
3858 : 82118 : ? summaries->get_create (node) : NULL;
3859 : 82118 : modref_summary_lto *modref_sum_lto = summaries_lto
3860 : 82118 : ? summaries_lto->get_create (node)
3861 : 82118 : : NULL;
3862 : 82118 : if (optimization_summaries)
3863 : 14619 : modref_sum = optimization_summaries->get_create (node);
3864 : :
3865 : 82118 : if (modref_sum)
3866 : : {
3867 : 43816 : modref_sum->writes_errno = false;
3868 : 43816 : modref_sum->side_effects = false;
3869 : 43816 : modref_sum->nondeterministic = false;
3870 : 43816 : modref_sum->calls_interposable = false;
3871 : : }
3872 : 82118 : if (modref_sum_lto)
3873 : : {
3874 : 38349 : modref_sum_lto->writes_errno = false;
3875 : 38349 : modref_sum_lto->side_effects = false;
3876 : 38349 : modref_sum_lto->nondeterministic = false;
3877 : 38349 : modref_sum_lto->calls_interposable = false;
3878 : : }
3879 : :
3880 : 82118 : gcc_assert (!modref_sum || (!modref_sum->loads
3881 : : && !modref_sum->stores));
3882 : 82118 : gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
3883 : : && !modref_sum_lto->stores));
3884 : 82118 : unsigned int args = streamer_read_uhwi (&ib);
3885 : 82118 : if (args && modref_sum)
3886 : 29775 : modref_sum->arg_flags.reserve_exact (args);
3887 : 82118 : if (args && modref_sum_lto)
3888 : 23955 : modref_sum_lto->arg_flags.reserve_exact (args);
3889 : 161738 : for (unsigned int i = 0; i < args; i++)
3890 : : {
3891 : 79620 : eaf_flags_t flags = streamer_read_uhwi (&ib);
3892 : 79620 : if (modref_sum)
3893 : 44226 : modref_sum->arg_flags.quick_push (flags);
3894 : 79620 : if (modref_sum_lto)
3895 : 35446 : modref_sum_lto->arg_flags.quick_push (flags);
3896 : : }
3897 : 82118 : eaf_flags_t flags = streamer_read_uhwi (&ib);
3898 : 82118 : if (modref_sum)
3899 : 43816 : modref_sum->retslot_flags = flags;
3900 : 82118 : if (modref_sum_lto)
3901 : 38349 : modref_sum_lto->retslot_flags = flags;
3902 : :
3903 : 82118 : flags = streamer_read_uhwi (&ib);
3904 : 82118 : if (modref_sum)
3905 : 43816 : modref_sum->static_chain_flags = flags;
3906 : 82118 : if (modref_sum_lto)
3907 : 38349 : modref_sum_lto->static_chain_flags = flags;
3908 : :
3909 : 82118 : 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 : 82118 : 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 : 82118 : int j = streamer_read_uhwi (&ib);
3916 : 82118 : if (j && modref_sum)
3917 : 1846 : modref_sum->kills.reserve_exact (j);
3918 : 82118 : if (j && modref_sum_lto)
3919 : 1453 : modref_sum_lto->kills.reserve_exact (j);
3920 : 86149 : for (int k = 0; k < j; k++)
3921 : : {
3922 : 4031 : modref_access_node a = modref_access_node::stream_in (&ib);
3923 : :
3924 : 4031 : if (modref_sum)
3925 : 2223 : modref_sum->kills.quick_push (a);
3926 : 4031 : if (modref_sum_lto)
3927 : 1815 : modref_sum_lto->kills.quick_push (a);
3928 : : }
3929 : 82118 : struct bitpack_d bp = streamer_read_bitpack (&ib);
3930 : 82118 : if (bp_unpack_value (&bp, 1))
3931 : : {
3932 : 96 : if (modref_sum)
3933 : 96 : modref_sum->writes_errno = true;
3934 : 96 : if (modref_sum_lto)
3935 : 0 : modref_sum_lto->writes_errno = true;
3936 : : }
3937 : 82118 : if (bp_unpack_value (&bp, 1))
3938 : : {
3939 : 13333 : if (modref_sum)
3940 : 9838 : modref_sum->side_effects = true;
3941 : 13333 : if (modref_sum_lto)
3942 : 3496 : modref_sum_lto->side_effects = true;
3943 : : }
3944 : 82118 : if (bp_unpack_value (&bp, 1))
3945 : : {
3946 : 7024 : if (modref_sum)
3947 : 4397 : modref_sum->nondeterministic = true;
3948 : 7024 : if (modref_sum_lto)
3949 : 2627 : modref_sum_lto->nondeterministic = true;
3950 : : }
3951 : 82118 : 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 : 82118 : if (!flag_ltrans)
3959 : : {
3960 : 68805 : for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
3961 : : {
3962 : 1306 : 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 : 1306 : modref_read_escape_summary (&bp, e);
3968 : : }
3969 : 373280 : for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3970 : : {
3971 : 305781 : if (bp_unpack_value (&bp, 1))
3972 : : {
3973 : 71277 : class fnspec_summary *sum = fnspec_summaries->get_create (e);
3974 : 71277 : sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3975 : : }
3976 : 305781 : modref_read_escape_summary (&bp, e);
3977 : : }
3978 : : }
3979 : 82118 : if (flag_ltrans)
3980 : 14619 : modref_sum->finalize (node->decl);
3981 : 82118 : 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 : 23094 : lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
3994 : : len);
3995 : 23094 : lto_data_in_delete (data_in);
3996 : 23094 : }
3997 : :
3998 : : /* Callback for read_summary. */
3999 : :
4000 : : static void
4001 : 22069 : modref_read (void)
4002 : : {
4003 : 22069 : struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
4004 : 22069 : struct lto_file_decl_data *file_data;
4005 : 22069 : unsigned int j = 0;
4006 : :
4007 : 22069 : gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
4008 : 22069 : if (flag_ltrans)
4009 : 9104 : optimization_summaries = modref_summaries::create_ggc (symtab);
4010 : : else
4011 : : {
4012 : 12965 : if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
4013 : 8780 : summaries_lto = modref_summaries_lto::create_ggc (symtab);
4014 : 12965 : if (!flag_wpa
4015 : 8747 : || (flag_incremental_link == INCREMENTAL_LINK_LTO
4016 : 0 : && flag_fat_lto_objects))
4017 : 4218 : summaries = modref_summaries::create_ggc (symtab);
4018 : 12965 : if (!fnspec_summaries)
4019 : 12965 : fnspec_summaries = new fnspec_summaries_t (symtab);
4020 : 12965 : if (!escape_summaries)
4021 : 12965 : escape_summaries = new escape_summaries_t (symtab);
4022 : : }
4023 : :
4024 : 45163 : while ((file_data = file_data_vec[j++]))
4025 : : {
4026 : 23094 : size_t len;
4027 : 23094 : const char *data = lto_get_summary_section_data (file_data,
4028 : : LTO_section_ipa_modref,
4029 : : &len);
4030 : 23094 : if (data)
4031 : 23094 : 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 : 22069 : }
4040 : :
4041 : : /* Recompute arg_flags for param adjustments in INFO. */
4042 : :
4043 : : static void
4044 : 17695 : remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
4045 : : {
4046 : 17695 : auto_vec<eaf_flags_t> old = arg_flags.copy ();
4047 : 17695 : int max = -1;
4048 : 17695 : size_t i;
4049 : 17695 : ipa_adjusted_param *p;
4050 : :
4051 : 17695 : arg_flags.release ();
4052 : :
4053 : 57509 : FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4054 : : {
4055 : 39814 : int o = info->param_adjustments->get_original_index (i);
4056 : 69623 : if (o >= 0 && (int)old.length () > o && old[o])
4057 : : max = i;
4058 : : }
4059 : 17695 : if (max >= 0)
4060 : 11261 : arg_flags.safe_grow_cleared (max + 1, true);
4061 : 73657 : FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4062 : : {
4063 : 39814 : int o = info->param_adjustments->get_original_index (i);
4064 : 29809 : if (o >= 0 && (int)old.length () > o && old[o])
4065 : 16181 : arg_flags[i] = old[o];
4066 : : }
4067 : 17695 : }
4068 : :
4069 : : /* Update kills according to the parm map MAP. */
4070 : :
4071 : : static void
4072 : 19649 : remap_kills (vec <modref_access_node> &kills, const vec <int> &map)
4073 : : {
4074 : 21345 : for (size_t i = 0; i < kills.length ();)
4075 : 1696 : if (kills[i].parm_index >= 0)
4076 : : {
4077 : 1594 : if (kills[i].parm_index < (int)map.length ()
4078 : 1594 : && map[kills[i].parm_index] != MODREF_UNKNOWN_PARM)
4079 : : {
4080 : 1477 : kills[i].parm_index = map[kills[i].parm_index];
4081 : 1477 : i++;
4082 : : }
4083 : : else
4084 : 117 : kills.unordered_remove (i);
4085 : : }
4086 : : else
4087 : 102 : i++;
4088 : 19649 : }
4089 : :
4090 : : /* Return true if the V can overlap with KILL. */
4091 : :
4092 : : static bool
4093 : 6761 : ipcp_argagg_and_kill_overlap_p (const ipa_argagg_value &v,
4094 : : const modref_access_node &kill)
4095 : : {
4096 : 6761 : if (kill.parm_index == v.index)
4097 : : {
4098 : 433 : gcc_assert (kill.parm_offset_known);
4099 : 433 : gcc_assert (known_eq (kill.max_size, kill.size));
4100 : 433 : poly_int64 repl_size;
4101 : 433 : bool ok = poly_int_tree_p (TYPE_SIZE (TREE_TYPE (v.value)),
4102 : : &repl_size);
4103 : 433 : gcc_assert (ok);
4104 : 433 : poly_int64 repl_offset (v.unit_offset);
4105 : 433 : repl_offset <<= LOG2_BITS_PER_UNIT;
4106 : 433 : poly_int64 combined_offset
4107 : 433 : = (kill.parm_offset << LOG2_BITS_PER_UNIT) + kill.offset;
4108 : 433 : if (ranges_maybe_overlap_p (repl_offset, repl_size,
4109 : 433 : combined_offset, kill.size))
4110 : 387 : return true;
4111 : : }
4112 : : return false;
4113 : : }
4114 : :
4115 : : /* If signature changed, update the summary. */
4116 : :
4117 : : static void
4118 : 3063173 : update_signature (struct cgraph_node *node)
4119 : : {
4120 : 6126346 : modref_summary *r = optimization_summaries
4121 : 3063173 : ? optimization_summaries->get (node) : NULL;
4122 : 6126346 : modref_summary_lto *r_lto = summaries_lto
4123 : 3063173 : ? summaries_lto->get (node) : NULL;
4124 : 3063173 : 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 : 826714 : ipcp_transformation *ipcp_ts = ipcp_get_transformation_summary (node);
4131 : 826714 : if (ipcp_ts)
4132 : : {
4133 : 61453 : for (auto &v : ipcp_ts->m_agg_values)
4134 : : {
4135 : 15668 : if (!v.by_ref)
4136 : 2332 : continue;
4137 : 13336 : if (r)
4138 : 22936 : for (const modref_access_node &kill : r->kills)
4139 : 6713 : if (ipcp_argagg_and_kill_overlap_p (v, kill))
4140 : : {
4141 : 368 : v.killed = true;
4142 : 368 : break;
4143 : : }
4144 : 13336 : if (!v.killed && r_lto)
4145 : 1135 : for (const modref_access_node &kill : r_lto->kills)
4146 : 48 : if (ipcp_argagg_and_kill_overlap_p (v, kill))
4147 : : {
4148 : 19 : v.killed = true;
4149 : 19 : break;
4150 : : }
4151 : : }
4152 : : }
4153 : :
4154 : 826714 : clone_info *info = clone_info::get (node);
4155 : 826714 : if (!info || !info->param_adjustments)
4156 : : return;
4157 : :
4158 : 19506 : 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 : 62284 : FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4172 : : {
4173 : 42778 : int idx = info->param_adjustments->get_original_index (i);
4174 : 42778 : if (idx > (int)max)
4175 : 21805 : max = idx;
4176 : : }
4177 : :
4178 : 19506 : auto_vec <int, 32> map;
4179 : :
4180 : 19506 : map.reserve (max + 1);
4181 : 83167 : for (i = 0; i <= max; i++)
4182 : 44155 : map.quick_push (MODREF_UNKNOWN_PARM);
4183 : 62284 : FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4184 : : {
4185 : 42778 : int idx = info->param_adjustments->get_original_index (i);
4186 : 42778 : if (idx >= 0)
4187 : 32101 : map[idx] = i;
4188 : : }
4189 : 19506 : if (r)
4190 : : {
4191 : 18178 : r->loads->remap_params (&map);
4192 : 18178 : r->stores->remap_params (&map);
4193 : 18178 : remap_kills (r->kills, map);
4194 : 18178 : if (r->arg_flags.length ())
4195 : 16515 : remap_arg_flags (r->arg_flags, info);
4196 : : }
4197 : 19506 : if (r_lto)
4198 : : {
4199 : 1471 : r_lto->loads->remap_params (&map);
4200 : 1471 : r_lto->stores->remap_params (&map);
4201 : 1471 : remap_kills (r_lto->kills, map);
4202 : 1471 : if (r_lto->arg_flags.length ())
4203 : 1180 : remap_arg_flags (r_lto->arg_flags, info);
4204 : : }
4205 : 19506 : 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 : 19506 : if (r)
4214 : 18178 : r->finalize (node->decl);
4215 : 19506 : return;
4216 : 19506 : }
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 : 282953 : 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 : 282953 : NULL) /* variable_transform */
4246 : 282953 : {}
4247 : :
4248 : : /* opt_pass methods: */
4249 : 0 : opt_pass *clone () final override { return new pass_ipa_modref (m_ctxt); }
4250 : 592078 : bool gate (function *) final override
4251 : : {
4252 : 592078 : return true;
4253 : : }
4254 : : unsigned int execute (function *) final override;
4255 : :
4256 : : };
4257 : :
4258 : : }
4259 : :
4260 : 3256753 : unsigned int pass_modref::execute (function *)
4261 : : {
4262 : 3256753 : if (analyze_function (false))
4263 : 7307 : return execute_fixup_cfg ();
4264 : : return 0;
4265 : : }
4266 : :
4267 : : gimple_opt_pass *
4268 : 282953 : make_pass_modref (gcc::context *ctxt)
4269 : : {
4270 : 282953 : return new pass_modref (ctxt);
4271 : : }
4272 : :
4273 : : ipa_opt_pass_d *
4274 : 282953 : make_pass_ipa_modref (gcc::context *ctxt)
4275 : : {
4276 : 282953 : 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 : 6699664 : 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 : 6699664 : if (!e->inline_failed)
4291 : : return false;
4292 : 5554429 : enum availability avail;
4293 : 5554429 : cgraph_node *callee = e->callee->ultimate_alias_target
4294 : 5554429 : (&avail, e->caller);
4295 : :
4296 : 5554429 : return (avail <= AVAIL_INTERPOSABLE
4297 : 5554429 : || ((!optimization_summaries || !optimization_summaries->get (callee))
4298 : 199023 : && (!summaries_lto || !summaries_lto->get (callee))));
4299 : : }
4300 : :
4301 : : /* Compute parm_map for CALLEE_EDGE. */
4302 : :
4303 : : static bool
4304 : 1916634 : compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
4305 : : {
4306 : 1916634 : class ipa_edge_args *args;
4307 : 1916634 : if (ipa_node_params_sum
4308 : 1916634 : && !callee_edge->call_stmt_cannot_inline_p
4309 : 3833267 : && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
4310 : : {
4311 : 1882086 : int i, count = ipa_get_cs_argument_count (args);
4312 : 1882086 : class ipa_node_params *caller_parms_info, *callee_pi;
4313 : 1882086 : class ipa_call_summary *es
4314 : 1882086 : = ipa_call_summaries->get (callee_edge);
4315 : 1882086 : cgraph_node *callee
4316 : 1882086 : = callee_edge->callee->ultimate_alias_target
4317 : 1882086 : (NULL, callee_edge->caller);
4318 : :
4319 : 1882086 : caller_parms_info
4320 : 1882086 : = ipa_node_params_sum->get (callee_edge->caller->inlined_to
4321 : : ? callee_edge->caller->inlined_to
4322 : : : callee_edge->caller);
4323 : 1882086 : callee_pi = ipa_node_params_sum->get (callee);
4324 : :
4325 : 1882086 : (*parm_map).safe_grow_cleared (count, true);
4326 : :
4327 : 6099782 : for (i = 0; i < count; i++)
4328 : : {
4329 : 4217696 : if (es && es->param[i].points_to_local_or_readonly_memory)
4330 : : {
4331 : 736659 : (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
4332 : 736659 : continue;
4333 : : }
4334 : :
4335 : 3481037 : struct ipa_jump_func *jf
4336 : 3481037 : = ipa_get_ith_jump_func (args, i);
4337 : 3481037 : if (jf && callee_pi)
4338 : : {
4339 : 2588819 : tree cst = ipa_value_from_jfunc (caller_parms_info,
4340 : : jf,
4341 : : ipa_get_type
4342 : : (callee_pi, i));
4343 : 2588819 : if (cst && points_to_local_or_readonly_memory_p (cst))
4344 : : {
4345 : 541 : (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
4346 : 541 : continue;
4347 : : }
4348 : : }
4349 : 3480496 : if (jf && jf->type == IPA_JF_PASS_THROUGH)
4350 : : {
4351 : 714033 : (*parm_map)[i].parm_index
4352 : 714033 : = ipa_get_jf_pass_through_formal_id (jf);
4353 : 714033 : if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
4354 : : {
4355 : 702586 : (*parm_map)[i].parm_offset_known = true;
4356 : 702586 : (*parm_map)[i].parm_offset = 0;
4357 : : }
4358 : 11447 : else if (ipa_get_jf_pass_through_operation (jf)
4359 : : == POINTER_PLUS_EXPR
4360 : 13868 : && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
4361 : 2421 : &(*parm_map)[i].parm_offset))
4362 : 2421 : (*parm_map)[i].parm_offset_known = true;
4363 : : else
4364 : 9026 : (*parm_map)[i].parm_offset_known = false;
4365 : 714033 : continue;
4366 : : }
4367 : 2766463 : if (jf && jf->type == IPA_JF_ANCESTOR)
4368 : : {
4369 : 104083 : (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
4370 : 104083 : (*parm_map)[i].parm_offset_known = true;
4371 : 104083 : gcc_checking_assert
4372 : : (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
4373 : 208166 : (*parm_map)[i].parm_offset
4374 : 104083 : = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
4375 : : }
4376 : : else
4377 : 2662380 : (*parm_map)[i].parm_index = -1;
4378 : : }
4379 : 1882086 : if (dump_file)
4380 : : {
4381 : 439 : fprintf (dump_file, " Parm map: ");
4382 : 1458 : for (i = 0; i < count; i++)
4383 : 580 : fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
4384 : 439 : fprintf (dump_file, "\n");
4385 : : }
4386 : 1882086 : 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 : 1912991 : update_escape_summary_1 (cgraph_edge *e,
4403 : : vec <vec <escape_map>> &map,
4404 : : bool ignore_stores)
4405 : : {
4406 : 1912991 : escape_summary *sum = escape_summaries->get (e);
4407 : 1912991 : if (!sum)
4408 : 1801574 : return;
4409 : 111417 : auto_vec <escape_entry> old = sum->esc.copy ();
4410 : 111417 : sum->esc.release ();
4411 : :
4412 : 111417 : unsigned int i;
4413 : 111417 : escape_entry *ee;
4414 : 242106 : FOR_EACH_VEC_ELT (old, i, ee)
4415 : : {
4416 : 130689 : unsigned int j;
4417 : 130689 : 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 : 130689 : if (ee->parm_index >= (int)map.length ()
4421 : 130689 : || ee->parm_index < 0)
4422 : 99964 : continue;
4423 : 182600 : FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
4424 : : {
4425 : 26020 : eaf_flags_t min_flags = ee->min_flags;
4426 : 26020 : if (ee->direct && !em->direct)
4427 : 3933 : min_flags = deref_flags (min_flags, ignore_stores);
4428 : 26020 : struct escape_entry entry = {em->parm_index, ee->arg,
4429 : : min_flags,
4430 : 26020 : ee->direct && em->direct};
4431 : 26020 : sum->esc.safe_push (entry);
4432 : : }
4433 : : }
4434 : 111417 : if (!sum->esc.length ())
4435 : 89658 : escape_summaries->remove (e);
4436 : 111417 : }
4437 : :
4438 : : /* Update escape map for NODE. */
4439 : :
4440 : : static void
4441 : 1173752 : update_escape_summary (cgraph_node *node,
4442 : : vec <vec <escape_map>> &map,
4443 : : bool ignore_stores)
4444 : : {
4445 : 1173752 : if (!escape_summaries)
4446 : : return;
4447 : 1233054 : for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
4448 : 59302 : update_escape_summary_1 (e, map, ignore_stores);
4449 : 3496108 : for (cgraph_edge *e = node->callees; e; e = e->next_callee)
4450 : : {
4451 : 2322356 : if (!e->inline_failed)
4452 : 468667 : update_escape_summary (e->callee, map, ignore_stores);
4453 : : else
4454 : 1853689 : 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 : 19704 : get_parm_type (tree decl, unsigned int i)
4464 : : {
4465 : 19704 : tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
4466 : :
4467 : 59011 : for (unsigned int p = 0; p < i; p++)
4468 : 39307 : t = TREE_CHAIN (t);
4469 : 19704 : 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 : 244325 : get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
4476 : : unsigned int i, modref_parm_map &map)
4477 : : {
4478 : 244325 : tree size = NULL_TREE;
4479 : 244325 : unsigned int size_arg;
4480 : :
4481 : 244325 : if (!fnspec.arg_specified_p (i))
4482 : : ;
4483 : 244325 : else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
4484 : : {
4485 : 39402 : cgraph_node *node = e->caller->inlined_to
4486 : 19701 : ? e->caller->inlined_to : e->caller;
4487 : 19701 : ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
4488 : 19701 : ipa_edge_args *args = ipa_edge_args_sum->get (e);
4489 : 19701 : struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
4490 : :
4491 : 19701 : if (jf)
4492 : 19701 : size = ipa_value_from_jfunc (caller_parms_info, jf,
4493 : 19701 : get_parm_type (e->callee->decl, size_arg));
4494 : : }
4495 : 224624 : 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 : 244325 : modref_access_node a = {0, -1, -1,
4498 : 244325 : map.parm_offset, map.parm_index,
4499 : 244325 : map.parm_offset_known, 0};
4500 : 244325 : poly_int64 size_hwi;
4501 : 244325 : if (size
4502 : 8855 : && poly_int_tree_p (size, &size_hwi)
4503 : 253044 : && coeffs_in_range_p (size_hwi, 0,
4504 : : HOST_WIDE_INT_MAX / BITS_PER_UNIT))
4505 : : {
4506 : 8552 : a.size = -1;
4507 : 8552 : a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
4508 : : }
4509 : 244325 : return a;
4510 : : }
4511 : :
4512 : : /* Collapse loads and return true if something changed. */
4513 : : static bool
4514 : 2287780 : collapse_loads (modref_summary *cur_summary,
4515 : : modref_summary_lto *cur_summary_lto)
4516 : : {
4517 : 2287780 : bool changed = false;
4518 : :
4519 : 2287780 : if (cur_summary && !cur_summary->loads->every_base)
4520 : : {
4521 : 417657 : cur_summary->loads->collapse ();
4522 : 417657 : changed = true;
4523 : : }
4524 : 2287780 : if (cur_summary_lto
4525 : 177072 : && !cur_summary_lto->loads->every_base)
4526 : : {
4527 : 23849 : cur_summary_lto->loads->collapse ();
4528 : 23849 : changed = true;
4529 : : }
4530 : 2287780 : return changed;
4531 : : }
4532 : :
4533 : : /* Collapse loads and return true if something changed. */
4534 : :
4535 : : static bool
4536 : 1756902 : collapse_stores (modref_summary *cur_summary,
4537 : : modref_summary_lto *cur_summary_lto)
4538 : : {
4539 : 1756902 : bool changed = false;
4540 : :
4541 : 1756902 : if (cur_summary && !cur_summary->stores->every_base)
4542 : : {
4543 : 414554 : cur_summary->stores->collapse ();
4544 : 414554 : changed = true;
4545 : : }
4546 : 1756902 : if (cur_summary_lto
4547 : 43242 : && !cur_summary_lto->stores->every_base)
4548 : : {
4549 : 9604 : cur_summary_lto->stores->collapse ();
4550 : 9604 : changed = true;
4551 : : }
4552 : 1756902 : 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 : 2758603 : 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 : 2758603 : bool changed = false;
4566 : 2758603 : class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
4567 : 2758603 : auto_vec <modref_parm_map, 32> parm_map;
4568 : 2758603 : bool looping;
4569 : :
4570 : 2758603 : if (e->callee
4571 : 2758603 : && builtin_safe_for_const_function_p (&looping, e->callee->decl))
4572 : : {
4573 : 246871 : if (looping && cur_summary && !cur_summary->side_effects)
4574 : : {
4575 : 265 : cur_summary->side_effects = true;
4576 : 265 : changed = true;
4577 : : }
4578 : 246871 : 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 : 246871 : return changed;
4584 : : }
4585 : :
4586 : 2511732 : if (!(ecf_flags & (ECF_CONST | ECF_PURE))
4587 : 268600 : || (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
4588 : 265263 : || nontrivial_scc)
4589 : : {
4590 : 2246572 : if (cur_summary && !cur_summary->side_effects)
4591 : : {
4592 : 385408 : cur_summary->side_effects = true;
4593 : 385408 : changed = true;
4594 : : }
4595 : 2246572 : if (cur_summary_lto && !cur_summary_lto->side_effects)
4596 : : {
4597 : 19900 : cur_summary_lto->side_effects = true;
4598 : 19900 : changed = true;
4599 : : }
4600 : 2246572 : if (!ignore_nondeterminism_p (node->decl, ecf_flags,
4601 : 2246572 : e->callee ? TREE_TYPE (e->callee->decl)
4602 : : : NULL_TREE))
4603 : : {
4604 : 1841758 : if (cur_summary && !cur_summary->nondeterministic)
4605 : : {
4606 : 350202 : cur_summary->nondeterministic = true;
4607 : 350202 : changed = true;
4608 : : }
4609 : 1841758 : if (cur_summary_lto && !cur_summary_lto->nondeterministic)
4610 : : {
4611 : 5946 : cur_summary_lto->nondeterministic = true;
4612 : 5946 : changed = true;
4613 : : }
4614 : : }
4615 : : }
4616 : 2511732 : if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
4617 : : return changed;
4618 : :
4619 : 2511375 : if (fnspec_sum
4620 : 2511375 : && compute_parm_map (e, &parm_map))
4621 : : {
4622 : 482361 : attr_fnspec fnspec (fnspec_sum->fnspec);
4623 : :
4624 : 482361 : gcc_checking_assert (fnspec.known_p ());
4625 : 482361 : if (fnspec.global_memory_read_p ())
4626 : 0 : collapse_loads (cur_summary, cur_summary_lto);
4627 : : else
4628 : : {
4629 : 482361 : tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4630 : 1069923 : for (unsigned i = 0; i < parm_map.length () && t;
4631 : 587562 : i++, t = TREE_CHAIN (t))
4632 : 846328 : if (!POINTER_TYPE_P (TREE_VALUE (t)))
4633 : : ;
4634 : 646108 : else if (!fnspec.arg_specified_p (i)
4635 : 646108 : || fnspec.arg_maybe_read_p (i))
4636 : : {
4637 : 453605 : modref_parm_map map = parm_map[i];
4638 : 453605 : if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4639 : 29039 : continue;
4640 : 424566 : if (map.parm_index == MODREF_UNKNOWN_PARM)
4641 : : {
4642 : 258766 : collapse_loads (cur_summary, cur_summary_lto);
4643 : 258766 : break;
4644 : : }
4645 : 165800 : if (cur_summary)
4646 : 278040 : changed |= cur_summary->loads->insert
4647 : 139020 : (node->decl, 0, 0,
4648 : 278040 : get_access_for_fnspec (e, fnspec, i, map), false);
4649 : 165800 : if (cur_summary_lto)
4650 : 178190 : changed |= cur_summary_lto->loads->insert
4651 : 89095 : (node->decl, 0, 0,
4652 : 178190 : get_access_for_fnspec (e, fnspec, i, map), false);
4653 : : }
4654 : : }
4655 : 482361 : if (ignore_stores_p (node->decl, ecf_flags))
4656 : : ;
4657 : 254989 : else if (fnspec.global_memory_written_p ())
4658 : 0 : collapse_stores (cur_summary, cur_summary_lto);
4659 : : else
4660 : : {
4661 : 254989 : tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4662 : 430475 : for (unsigned i = 0; i < parm_map.length () && t;
4663 : 175486 : i++, t = TREE_CHAIN (t))
4664 : 319792 : if (!POINTER_TYPE_P (TREE_VALUE (t)))
4665 : : ;
4666 : 217796 : else if (!fnspec.arg_specified_p (i)
4667 : 217796 : || fnspec.arg_maybe_written_p (i))
4668 : : {
4669 : 196752 : modref_parm_map map = parm_map[i];
4670 : 196752 : if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4671 : 36593 : continue;
4672 : 160159 : if (map.parm_index == MODREF_UNKNOWN_PARM)
4673 : : {
4674 : 144306 : collapse_stores (cur_summary, cur_summary_lto);
4675 : 144306 : break;
4676 : : }
4677 : 15853 : if (cur_summary)
4678 : 31584 : changed |= cur_summary->stores->insert
4679 : 15792 : (node->decl, 0, 0,
4680 : 31584 : get_access_for_fnspec (e, fnspec, i, map), false);
4681 : 15853 : if (cur_summary_lto)
4682 : 836 : changed |= cur_summary_lto->stores->insert
4683 : 418 : (node->decl, 0, 0,
4684 : 836 : get_access_for_fnspec (e, fnspec, i, map), false);
4685 : : }
4686 : : }
4687 : 482361 : if (fnspec.errno_maybe_written_p () && flag_errno_math)
4688 : : {
4689 : 32822 : if (cur_summary && !cur_summary->writes_errno)
4690 : : {
4691 : 17139 : cur_summary->writes_errno = true;
4692 : 17139 : changed = true;
4693 : : }
4694 : 32822 : if (cur_summary_lto && !cur_summary_lto->writes_errno)
4695 : : {
4696 : 362 : cur_summary_lto->writes_errno = true;
4697 : 362 : changed = true;
4698 : : }
4699 : : }
4700 : 482361 : return changed;
4701 : : }
4702 : 2029014 : if (dump_file)
4703 : 50 : fprintf (dump_file, " collapsing loads\n");
4704 : 2029014 : changed |= collapse_loads (cur_summary, cur_summary_lto);
4705 : 2029014 : if (!ignore_stores_p (node->decl, ecf_flags))
4706 : : {
4707 : 1612596 : if (dump_file)
4708 : 48 : fprintf (dump_file, " collapsing stores\n");
4709 : 1612596 : changed |= collapse_stores (cur_summary, cur_summary_lto);
4710 : : }
4711 : : return changed;
4712 : 2758603 : }
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 : 597782 : 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 : 597782 : if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
4724 : : {
4725 : 122197 : optimization_summaries->remove (node);
4726 : 122197 : *cur_summary_ptr = NULL;
4727 : : }
4728 : 597782 : if (*cur_summary_lto_ptr
4729 : 597782 : && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
4730 : : {
4731 : 3906 : summaries_lto->remove (node);
4732 : 3906 : *cur_summary_lto_ptr = NULL;
4733 : : }
4734 : 597782 : }
4735 : :
4736 : : /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4737 : : and propagate loads/stores. */
4738 : :
4739 : : static bool
4740 : 2166468 : modref_propagate_in_scc (cgraph_node *component_node)
4741 : : {
4742 : 2166468 : bool changed = true;
4743 : 2166468 : bool first = true;
4744 : 2166468 : int iteration = 0;
4745 : :
4746 : 5002424 : while (changed)
4747 : : {
4748 : 2835956 : bool nontrivial_scc
4749 : 2835956 : = ((struct ipa_dfs_info *) component_node->aux)->next_cycle;
4750 : 2835956 : changed = false;
4751 : 5705781 : for (struct cgraph_node *cur = component_node; cur;
4752 : 2869825 : cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4753 : : {
4754 : 2869825 : cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
4755 : 5739650 : modref_summary *cur_summary = optimization_summaries
4756 : 2869825 : ? optimization_summaries->get (node)
4757 : : : NULL;
4758 : 5739650 : modref_summary_lto *cur_summary_lto = summaries_lto
4759 : 2869825 : ? summaries_lto->get (node)
4760 : : : NULL;
4761 : :
4762 : 2869825 : if (!cur_summary && !cur_summary_lto)
4763 : 723037 : continue;
4764 : :
4765 : 2173686 : int cur_ecf_flags = flags_from_decl_or_type (node->decl);
4766 : :
4767 : 2173686 : 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 : 2259850 : for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
4774 : : {
4775 : 113062 : if (dump_file)
4776 : 48 : fprintf (dump_file, " Indirect call\n");
4777 : 113062 : if (propagate_unknown_call
4778 : 113062 : (node, e, e->indirect_info->ecf_flags,
4779 : : cur_summary, cur_summary_lto,
4780 : : nontrivial_scc))
4781 : : {
4782 : 45255 : changed = true;
4783 : 45255 : remove_useless_summaries (node, &cur_summary,
4784 : : &cur_summary_lto,
4785 : : cur_ecf_flags);
4786 : 45255 : if (!cur_summary && !cur_summary_lto)
4787 : : break;
4788 : : }
4789 : : }
4790 : :
4791 : 2173686 : if (!cur_summary && !cur_summary_lto)
4792 : 26898 : continue;
4793 : :
4794 : 8601038 : for (cgraph_edge *callee_edge = cur->callees; callee_edge;
4795 : 6454250 : callee_edge = callee_edge->next_callee)
4796 : : {
4797 : 6551398 : int flags = flags_from_decl_or_type (callee_edge->callee->decl);
4798 : 6551398 : modref_summary *callee_summary = NULL;
4799 : 6551398 : modref_summary_lto *callee_summary_lto = NULL;
4800 : 6551398 : struct cgraph_node *callee;
4801 : :
4802 : 6551398 : if (!callee_edge->inline_failed
4803 : 5693096 : || ((flags & ECF_CONST)
4804 : : && !(flags & ECF_LOOPING_CONST_OR_PURE)))
4805 : 6989728 : continue;
4806 : :
4807 : : /* Get the callee and its summary. */
4808 : 5375092 : enum availability avail;
4809 : 5375092 : callee = callee_edge->callee->ultimate_alias_target
4810 : 5375092 : (&avail, cur);
4811 : :
4812 : : /* It is not necessary to re-process calls outside of the
4813 : : SCC component. */
4814 : 5375092 : if (iteration > 0
4815 : 2078435 : && (!callee->aux
4816 : 501838 : || ((struct ipa_dfs_info *)cur->aux)->scc_no
4817 : 501838 : != ((struct ipa_dfs_info *)callee->aux)->scc_no))
4818 : 2068350 : continue;
4819 : :
4820 : 3306742 : if (dump_file)
4821 : 15 : fprintf (dump_file, " Call to %s\n",
4822 : 15 : callee_edge->callee->dump_name ());
4823 : :
4824 : 3306742 : bool ignore_stores = ignore_stores_p (cur->decl, flags);
4825 : :
4826 : 3306742 : if (avail <= AVAIL_INTERPOSABLE)
4827 : : {
4828 : 2566303 : if (dump_file)
4829 : 5 : fprintf (dump_file, " Call target interposable"
4830 : : " or not available\n");
4831 : 5132606 : changed |= propagate_unknown_call
4832 : 2566303 : (node, callee_edge, flags,
4833 : : cur_summary, cur_summary_lto,
4834 : : nontrivial_scc);
4835 : 2566303 : if (!cur_summary && !cur_summary_lto)
4836 : : break;
4837 : 2566303 : continue;
4838 : : }
4839 : :
4840 : : /* We don't know anything about CALLEE, hence we cannot tell
4841 : : anything about the entire component. */
4842 : :
4843 : 740439 : if (cur_summary
4844 : 740439 : && !(callee_summary = optimization_summaries->get (callee)))
4845 : : {
4846 : 77956 : if (dump_file)
4847 : 0 : fprintf (dump_file, " No call target summary\n");
4848 : 77956 : changed |= propagate_unknown_call
4849 : 77956 : (node, callee_edge, flags,
4850 : : cur_summary, NULL,
4851 : : nontrivial_scc);
4852 : : }
4853 : 740439 : if (cur_summary_lto
4854 : 740439 : && !(callee_summary_lto = summaries_lto->get (callee)))
4855 : : {
4856 : 1282 : if (dump_file)
4857 : 0 : fprintf (dump_file, " No call target summary\n");
4858 : 1282 : changed |= propagate_unknown_call
4859 : 1282 : (node, callee_edge, flags,
4860 : : NULL, cur_summary_lto,
4861 : : nontrivial_scc);
4862 : : }
4863 : :
4864 : 576612 : if (callee_summary && !cur_summary->side_effects
4865 : 848825 : && (callee_summary->side_effects
4866 : 62513 : || callee_edge->recursive_p ()))
4867 : : {
4868 : 46823 : cur_summary->side_effects = true;
4869 : 46823 : changed = true;
4870 : : }
4871 : 183906 : if (callee_summary_lto && !cur_summary_lto->side_effects
4872 : 763399 : && (callee_summary_lto->side_effects
4873 : 20802 : || callee_edge->recursive_p ()))
4874 : : {
4875 : 2216 : cur_summary_lto->side_effects = true;
4876 : 2216 : changed = true;
4877 : : }
4878 : 576612 : if (callee_summary && !cur_summary->nondeterministic
4879 : 179549 : && callee_summary->nondeterministic
4880 : 780493 : && !ignore_nondeterminism_p
4881 : 40054 : (cur->decl, flags,
4882 : 40054 : TREE_TYPE (callee_edge->callee->decl)))
4883 : : {
4884 : 38619 : cur_summary->nondeterministic = true;
4885 : 38619 : changed = true;
4886 : : }
4887 : 183906 : if (callee_summary_lto && !cur_summary_lto->nondeterministic
4888 : 62393 : && callee_summary_lto->nondeterministic
4889 : 742849 : && !ignore_nondeterminism_p
4890 : 2410 : (cur->decl, flags,
4891 : 2410 : TREE_TYPE (callee_edge->callee->decl)))
4892 : : {
4893 : 2054 : cur_summary_lto->nondeterministic = true;
4894 : 2054 : changed = true;
4895 : : }
4896 : 740439 : if (flags & (ECF_CONST | ECF_NOVOPS))
4897 : 2463 : 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 : 737976 : if (!callee_edge->binds_to_current_def_p ())
4904 : : {
4905 : 121930 : if (cur_summary && !cur_summary->calls_interposable)
4906 : : {
4907 : 37810 : cur_summary->calls_interposable = true;
4908 : 37810 : changed = true;
4909 : : }
4910 : 121930 : if (cur_summary_lto && !cur_summary_lto->calls_interposable)
4911 : : {
4912 : 54 : cur_summary_lto->calls_interposable = true;
4913 : 54 : changed = true;
4914 : : }
4915 : 121930 : if (dump_file)
4916 : 0 : fprintf (dump_file, " May not bind local;"
4917 : : " collapsing loads\n");
4918 : : }
4919 : :
4920 : :
4921 : 737976 : auto_vec <modref_parm_map, 32> parm_map;
4922 : 737976 : modref_parm_map chain_map;
4923 : : /* TODO: Once we get jump functions for static chains we could
4924 : : compute this. */
4925 : 737976 : chain_map.parm_index = MODREF_UNKNOWN_PARM;
4926 : :
4927 : 737976 : compute_parm_map (callee_edge, &parm_map);
4928 : :
4929 : : /* Merge in callee's information. */
4930 : 737976 : if (callee_summary)
4931 : : {
4932 : 1148546 : changed |= cur_summary->loads->merge
4933 : 574273 : (node->decl, callee_summary->loads,
4934 : 574273 : &parm_map, &chain_map, !first);
4935 : 574273 : if (!ignore_stores)
4936 : : {
4937 : 1065452 : changed |= cur_summary->stores->merge
4938 : 532726 : (node->decl, callee_summary->stores,
4939 : : &parm_map, &chain_map, !first);
4940 : 532726 : if (!cur_summary->writes_errno
4941 : 453680 : && callee_summary->writes_errno)
4942 : : {
4943 : 12901 : cur_summary->writes_errno = true;
4944 : 12901 : changed = true;
4945 : : }
4946 : : }
4947 : : }
4948 : 737976 : if (callee_summary_lto)
4949 : : {
4950 : 367536 : changed |= cur_summary_lto->loads->merge
4951 : 183768 : (node->decl, callee_summary_lto->loads,
4952 : 183768 : &parm_map, &chain_map, !first);
4953 : 183768 : if (!ignore_stores)
4954 : : {
4955 : 354978 : changed |= cur_summary_lto->stores->merge
4956 : 177489 : (node->decl, callee_summary_lto->stores,
4957 : : &parm_map, &chain_map, !first);
4958 : 177489 : if (!cur_summary_lto->writes_errno
4959 : 177444 : && callee_summary_lto->writes_errno)
4960 : : {
4961 : 87 : cur_summary_lto->writes_errno = true;
4962 : 87 : changed = true;
4963 : : }
4964 : : }
4965 : : }
4966 : 737976 : if (changed)
4967 : 552527 : remove_useless_summaries (node, &cur_summary,
4968 : : &cur_summary_lto,
4969 : : cur_ecf_flags);
4970 : 737976 : if (!cur_summary && !cur_summary_lto)
4971 : : break;
4972 : 640828 : 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 : 737976 : }
4981 : : }
4982 : 2835956 : iteration++;
4983 : 2835956 : first = false;
4984 : : }
4985 : 2166468 : if (dump_file)
4986 : 58 : fprintf (dump_file,
4987 : : "Propagation finished in %i iterations\n", iteration);
4988 : : bool pureconst = false;
4989 : 4351480 : for (struct cgraph_node *cur = component_node; cur;
4990 : 2185012 : cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4991 : 2185012 : if (!cur->inlined_to && opt_for_fn (cur->decl, flag_ipa_pure_const))
4992 : : {
4993 : 2057310 : modref_summary *summary = optimization_summaries
4994 : 1028655 : ? optimization_summaries->get (cur)
4995 : : : NULL;
4996 : 2057310 : modref_summary_lto *summary_lto = summaries_lto
4997 : 1028655 : ? summaries_lto->get (cur)
4998 : : : NULL;
4999 : 1028655 : if (summary && !summary->stores->every_base && !summary->stores->bases
5000 : 154862 : && !summary->nondeterministic)
5001 : : {
5002 : 143560 : if (!summary->loads->every_base && !summary->loads->bases
5003 : 67018 : && !summary->calls_interposable)
5004 : 66636 : pureconst |= ipa_make_function_const
5005 : 66636 : (cur, summary->side_effects, false);
5006 : : else
5007 : 76924 : pureconst |= ipa_make_function_pure
5008 : 76924 : (cur, summary->side_effects, false);
5009 : : }
5010 : 1028655 : if (summary_lto && !summary_lto->stores->every_base
5011 : 47848 : && !summary_lto->stores->bases && !summary_lto->nondeterministic)
5012 : : {
5013 : 12725 : if (!summary_lto->loads->every_base && !summary_lto->loads->bases
5014 : 3137 : && !summary_lto->calls_interposable)
5015 : 3135 : pureconst |= ipa_make_function_const
5016 : 3135 : (cur, summary_lto->side_effects, false);
5017 : : else
5018 : 9590 : pureconst |= ipa_make_function_pure
5019 : 9590 : (cur, summary_lto->side_effects, false);
5020 : : }
5021 : : }
5022 : 2166468 : 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 : 94 : modref_summary *cur_summary = optimization_summaries
5035 : 47 : ? optimization_summaries->get (cur)
5036 : : : NULL;
5037 : 94 : 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 : 214862 : 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 : 214862 : int implicit_flags = EAF_NOT_RETURNED_DIRECTLY
5070 : : | EAF_NOT_RETURNED_INDIRECTLY;
5071 : 214862 : if (ignore_stores)
5072 : 99821 : implicit_flags |= ignore_stores_eaf_flags;
5073 : 214862 : if (callee_ecf_flags & ECF_PURE)
5074 : 95186 : implicit_flags |= implicit_pure_eaf_flags;
5075 : 214862 : if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
5076 : 482 : implicit_flags |= implicit_const_eaf_flags;
5077 : 214862 : class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
5078 : 214862 : if (fnspec_sum)
5079 : : {
5080 : 86890 : attr_fnspec fnspec (fnspec_sum->fnspec);
5081 : 86890 : implicit_flags |= fnspec.arg_eaf_flags (arg);
5082 : : }
5083 : 214862 : 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 : 121024 : 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 : 121024 : escape_entry *ee;
5103 : 121024 : unsigned int i;
5104 : 121024 : bool changed = false;
5105 : 121024 : bool ignore_stores = ignore_stores_p (caller, callee_ecf_flags);
5106 : :
5107 : : /* Return early if we have no useful info to propagate. */
5108 : 121024 : if ((!cur_summary
5109 : 99607 : || (!cur_summary->arg_flags.length ()
5110 : : && !cur_summary->static_chain_flags
5111 : 550 : && !cur_summary->retslot_flags))
5112 : 121030 : && (!cur_summary_lto
5113 : 21417 : || (!cur_summary_lto->arg_flags.length ()
5114 : : && !cur_summary_lto->static_chain_flags
5115 : 29 : && !cur_summary_lto->retslot_flags)))
5116 : : return false;
5117 : :
5118 : 255741 : FOR_EACH_VEC_ELT (sum->esc, i, ee)
5119 : : {
5120 : 134723 : int flags = 0;
5121 : 134723 : int flags_lto = 0;
5122 : 134723 : int implicit_flags = implicit_eaf_flags_for_edge_and_arg
5123 : 134723 : (e, callee_ecf_flags, ignore_stores, ee->arg);
5124 : :
5125 : 134723 : if (summary && ee->arg < summary->arg_flags.length ())
5126 : 29689 : flags = summary->arg_flags[ee->arg];
5127 : 134723 : if (summary_lto
5128 : 134723 : && ee->arg < summary_lto->arg_flags.length ())
5129 : 801 : flags_lto = summary_lto->arg_flags[ee->arg];
5130 : 134723 : if (!ee->direct)
5131 : : {
5132 : 26252 : flags = deref_flags (flags, ignore_stores);
5133 : 26252 : flags_lto = deref_flags (flags_lto, ignore_stores);
5134 : : }
5135 : 134723 : if (ignore_stores)
5136 : 87669 : implicit_flags |= ignore_stores_eaf_flags;
5137 : 134723 : if (callee_ecf_flags & ECF_PURE)
5138 : 83328 : implicit_flags |= implicit_pure_eaf_flags;
5139 : 134723 : if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
5140 : 482 : implicit_flags |= implicit_const_eaf_flags;
5141 : 134723 : class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
5142 : 134723 : if (fnspec_sum)
5143 : : {
5144 : 86890 : attr_fnspec fnspec (fnspec_sum->fnspec);
5145 : 86890 : implicit_flags |= fnspec.arg_eaf_flags (ee->arg);
5146 : : }
5147 : 134723 : if (!ee->direct)
5148 : 26252 : implicit_flags = deref_flags (implicit_flags, ignore_stores);
5149 : 134723 : flags |= implicit_flags;
5150 : 134723 : flags_lto |= implicit_flags;
5151 : 134723 : if (!binds_to_current_def && (flags || flags_lto))
5152 : : {
5153 : 112898 : flags = interposable_eaf_flags (flags, implicit_flags);
5154 : 112898 : flags_lto = interposable_eaf_flags (flags_lto, implicit_flags);
5155 : : }
5156 : 134723 : if (!(flags & EAF_UNUSED)
5157 : 246238 : && cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ())
5158 : : {
5159 : 112065 : eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5160 : 112065 : ? cur_summary->retslot_flags
5161 : : : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5162 : : ? cur_summary->static_chain_flags
5163 : 111171 : : cur_summary->arg_flags[ee->parm_index];
5164 : 112065 : if ((f & flags) != f)
5165 : : {
5166 : 97038 : f = remove_useless_eaf_flags
5167 : 48519 : (f & flags, caller_ecf_flags,
5168 : 48519 : VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
5169 : 48519 : changed = true;
5170 : : }
5171 : : }
5172 : 134723 : if (!(flags_lto & EAF_UNUSED)
5173 : 134723 : && cur_summary_lto
5174 : 221499 : && ee->parm_index < (int)cur_summary_lto->arg_flags.length ())
5175 : : {
5176 : 43419 : eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5177 : 43419 : ? cur_summary_lto->retslot_flags
5178 : : : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5179 : : ? cur_summary_lto->static_chain_flags
5180 : 43315 : : cur_summary_lto->arg_flags[ee->parm_index];
5181 : 43419 : 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 : 2166468 : modref_propagate_flags_in_scc (cgraph_node *component_node)
5198 : : {
5199 : 2166468 : bool changed = true;
5200 : 2166468 : int iteration = 0;
5201 : :
5202 : 4371150 : while (changed)
5203 : : {
5204 : : changed = false;
5205 : 4428361 : for (struct cgraph_node *cur = component_node; cur;
5206 : 2223679 : cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5207 : : {
5208 : 2223679 : cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
5209 : 4447358 : modref_summary *cur_summary = optimization_summaries
5210 : 2223679 : ? optimization_summaries->get (node)
5211 : : : NULL;
5212 : 4447358 : modref_summary_lto *cur_summary_lto = summaries_lto
5213 : 2223679 : ? summaries_lto->get (node)
5214 : : : NULL;
5215 : :
5216 : 2223679 : if (!cur_summary && !cur_summary_lto)
5217 : 694572 : continue;
5218 : 1529107 : int caller_ecf_flags = flags_from_decl_or_type (cur->decl);
5219 : :
5220 : 1529107 : 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 : 1589907 : for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
5227 : : {
5228 : 60800 : escape_summary *sum = escape_summaries->get (e);
5229 : :
5230 : 60800 : if (!sum || ((e->indirect_info->ecf_flags & ECF_CONST)
5231 : 220 : && !(e->indirect_info->ecf_flags & ECF_LOOPING_CONST_OR_PURE)))
5232 : 60580 : continue;
5233 : :
5234 : 220 : changed |= modref_merge_call_site_flags
5235 : 220 : (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 : 1529107 : if (!cur_summary && !cur_summary_lto)
5245 : : continue;
5246 : :
5247 : 5961882 : for (cgraph_edge *callee_edge = cur->callees; callee_edge;
5248 : 4432775 : callee_edge = callee_edge->next_callee)
5249 : : {
5250 : 4432775 : int ecf_flags = flags_from_decl_or_type
5251 : 4432775 : (callee_edge->callee->decl);
5252 : 4432775 : modref_summary *callee_summary = NULL;
5253 : 4432775 : modref_summary_lto *callee_summary_lto = NULL;
5254 : 4432775 : struct cgraph_node *callee;
5255 : :
5256 : 4432775 : if ((ecf_flags & ECF_CONST)
5257 : : && !(ecf_flags & ECF_LOOPING_CONST_OR_PURE))
5258 : 4311971 : continue;
5259 : :
5260 : : /* Get the callee and its summary. */
5261 : 4213487 : enum availability avail;
5262 : 4213487 : callee = callee_edge->callee->ultimate_alias_target
5263 : 4213487 : (&avail, cur);
5264 : :
5265 : : /* It is not necessary to re-process calls outside of the
5266 : : SCC component. */
5267 : 4213487 : if (iteration > 0
5268 : 381216 : && (!callee->aux
5269 : 234211 : || ((struct ipa_dfs_info *)cur->aux)->scc_no
5270 : 234211 : != ((struct ipa_dfs_info *)callee->aux)->scc_no))
5271 : 379761 : continue;
5272 : :
5273 : 3833726 : escape_summary *sum = escape_summaries->get (callee_edge);
5274 : 3833726 : if (!sum)
5275 : 3712922 : continue;
5276 : :
5277 : 120804 : if (dump_file)
5278 : 3 : fprintf (dump_file, " Call to %s\n",
5279 : 3 : callee_edge->callee->dump_name ());
5280 : :
5281 : 120804 : if (avail <= AVAIL_INTERPOSABLE
5282 : 24432 : || callee_edge->call_stmt_cannot_inline_p)
5283 : : ;
5284 : : else
5285 : : {
5286 : 24432 : if (cur_summary)
5287 : 24162 : callee_summary = optimization_summaries->get (callee);
5288 : 24432 : if (cur_summary_lto)
5289 : 590 : callee_summary_lto = summaries_lto->get (callee);
5290 : : }
5291 : 241608 : changed |= modref_merge_call_site_flags
5292 : 120804 : (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 : 120804 : callee->binds_to_current_def_p ());
5299 : 120804 : 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 : 2204682 : iteration++;
5309 : : }
5310 : 2166468 : if (dump_file)
5311 : 58 : fprintf (dump_file,
5312 : : "Propagation of flags finished in %i iterations\n", iteration);
5313 : 2166468 : }
5314 : :
5315 : : } /* ANON namespace. */
5316 : :
5317 : : /* Call EDGE was inlined; merge summary from callee to the caller. */
5318 : :
5319 : : void
5320 : 3449925 : ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
5321 : : {
5322 : 3449925 : if (!summaries && !summaries_lto)
5323 : : return;
5324 : :
5325 : 1610552 : struct cgraph_node *to = (edge->caller->inlined_to
5326 : 805276 : ? edge->caller->inlined_to : edge->caller);
5327 : 805276 : class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
5328 : 1610552 : class modref_summary_lto *to_info_lto = summaries_lto
5329 : 805276 : ? summaries_lto->get (to) : NULL;
5330 : :
5331 : 805276 : if (!to_info && !to_info_lto)
5332 : : {
5333 : 100191 : if (summaries)
5334 : 99719 : summaries->remove (edge->callee);
5335 : 100191 : if (summaries_lto)
5336 : 889 : summaries_lto->remove (edge->callee);
5337 : 100191 : remove_modref_edge_summaries (edge->callee);
5338 : 100191 : return;
5339 : : }
5340 : :
5341 : 705085 : class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
5342 : : : NULL;
5343 : 1410170 : class modref_summary_lto *callee_info_lto
5344 : 705085 : = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
5345 : 705085 : int flags = flags_from_decl_or_type (edge->callee->decl);
5346 : : /* Combine in outer flags. */
5347 : 705085 : cgraph_node *n;
5348 : 1086780 : for (n = edge->caller; n->inlined_to; n = n->callers->caller)
5349 : 381695 : flags |= flags_from_decl_or_type (n->decl);
5350 : 705085 : flags |= flags_from_decl_or_type (n->decl);
5351 : 705085 : bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
5352 : :
5353 : 705085 : if (!callee_info && to_info)
5354 : : {
5355 : 9254 : if (!(flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
5356 : 6910 : to_info->loads->collapse ();
5357 : 9254 : if (!ignore_stores)
5358 : 6803 : to_info->stores->collapse ();
5359 : : }
5360 : 705085 : if (!callee_info_lto && to_info_lto)
5361 : : {
5362 : 246 : if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5363 : 133 : to_info_lto->loads->collapse ();
5364 : 246 : if (!ignore_stores)
5365 : 105 : 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 : 705085 : if (!(flags & (ECF_CONST | ECF_PURE))
5371 : 86828 : || (flags & ECF_LOOPING_CONST_OR_PURE))
5372 : : {
5373 : 640637 : bool set_nondeterministic
5374 : : = !ignore_nondeterminism_p
5375 : 640637 : (edge->caller->decl, flags,
5376 : 640637 : TREE_TYPE (edge->callee->decl));
5377 : 640637 : if (to_info)
5378 : : {
5379 : 626973 : if (!callee_info || callee_info->side_effects)
5380 : 52518 : to_info->side_effects = true;
5381 : 626973 : if (set_nondeterministic)
5382 : 598151 : to_info->nondeterministic = true;
5383 : : }
5384 : 640637 : if (to_info_lto)
5385 : : {
5386 : 28339 : if (!callee_info_lto || callee_info_lto->side_effects)
5387 : 20948 : to_info_lto->side_effects = true;
5388 : 28339 : if (set_nondeterministic)
5389 : 26892 : to_info_lto->nondeterministic = true;
5390 : : }
5391 : : }
5392 : 705085 : if (callee_info || callee_info_lto)
5393 : : {
5394 : 695672 : auto_vec <modref_parm_map, 32> parm_map;
5395 : 695672 : modref_parm_map chain_map;
5396 : : /* TODO: Once we get jump functions for static chains we could
5397 : : compute parm_index. */
5398 : :
5399 : 695672 : compute_parm_map (edge, &parm_map);
5400 : :
5401 : 695672 : if (!ignore_stores)
5402 : : {
5403 : 604238 : if (to_info && callee_info)
5404 : 591348 : to_info->stores->merge (to->decl, callee_info->stores, &parm_map,
5405 : : &chain_map, false);
5406 : 604238 : if (to_info_lto && callee_info_lto)
5407 : 26787 : to_info_lto->stores->merge (to->decl, callee_info_lto->stores,
5408 : : &parm_map, &chain_map, false);
5409 : : }
5410 : 695672 : if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5411 : : {
5412 : 686372 : if (to_info && callee_info)
5413 : 671831 : to_info->loads->merge (to->decl, callee_info->loads, &parm_map,
5414 : : &chain_map, false);
5415 : 686372 : if (to_info_lto && callee_info_lto)
5416 : 30657 : to_info_lto->loads->merge (to->decl, callee_info_lto->loads,
5417 : : &parm_map, &chain_map, false);
5418 : : }
5419 : 695672 : }
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 : 705085 : class escape_summary *sum = escape_summaries->get (edge);
5425 : 705085 : int max_escape = -1;
5426 : 705085 : escape_entry *ee;
5427 : 705085 : unsigned int i;
5428 : :
5429 : 705085 : if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
5430 : 144978 : FOR_EACH_VEC_ELT (sum->esc, i, ee)
5431 : 80139 : if ((int)ee->arg > max_escape)
5432 : : max_escape = ee->arg;
5433 : :
5434 : 705085 : auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
5435 : 705085 : emap.safe_grow (max_escape + 1, true);
5436 : 1526422 : for (i = 0; (int)i < max_escape + 1; i++)
5437 : 116252 : emap[i] = vNULL;
5438 : :
5439 : 705085 : if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
5440 : 144978 : FOR_EACH_VEC_ELT (sum->esc, i, ee)
5441 : : {
5442 : 80139 : bool needed = false;
5443 : 80139 : int implicit_flags = implicit_eaf_flags_for_edge_and_arg
5444 : 160278 : (edge, flags, ignore_stores,
5445 : 80139 : ee->arg);
5446 : 80139 : if (!ee->direct)
5447 : 14064 : implicit_flags = deref_flags (implicit_flags, ignore_stores);
5448 : 159697 : if (to_info && (int)to_info->arg_flags.length () > ee->parm_index)
5449 : : {
5450 : 79684 : int flags = callee_info
5451 : 79612 : && callee_info->arg_flags.length () > ee->arg
5452 : 150523 : ? callee_info->arg_flags[ee->arg] : 0;
5453 : 79684 : if (!ee->direct)
5454 : 14045 : flags = deref_flags (flags, ignore_stores);
5455 : 79684 : flags |= ee->min_flags | implicit_flags;
5456 : 79684 : eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5457 : 79684 : ? to_info->retslot_flags
5458 : : : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5459 : : ? to_info->static_chain_flags
5460 : 78986 : : to_info->arg_flags[ee->parm_index];
5461 : 79684 : f &= flags;
5462 : 79684 : if (f)
5463 : 80139 : needed = true;
5464 : : }
5465 : 80139 : if (to_info_lto
5466 : 80915 : && (int)to_info_lto->arg_flags.length () > ee->parm_index)
5467 : : {
5468 : 778 : int flags = callee_info_lto
5469 : 778 : && callee_info_lto->arg_flags.length () > ee->arg
5470 : 1539 : ? callee_info_lto->arg_flags[ee->arg] : 0;
5471 : 778 : if (!ee->direct)
5472 : 55 : flags = deref_flags (flags, ignore_stores);
5473 : 778 : flags |= ee->min_flags | implicit_flags;
5474 : 778 : eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5475 : 778 : ? to_info_lto->retslot_flags
5476 : : : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5477 : : ? to_info_lto->static_chain_flags
5478 : 766 : : to_info_lto->arg_flags[ee->parm_index];
5479 : 778 : f &= flags;
5480 : 778 : if (f)
5481 : 80139 : needed = true;
5482 : : }
5483 : 80139 : struct escape_map entry = {ee->parm_index, ee->direct};
5484 : 80139 : if (needed)
5485 : 79677 : emap[ee->arg].safe_push (entry);
5486 : : }
5487 : 705085 : update_escape_summary (edge->callee, emap, ignore_stores);
5488 : 1526422 : for (i = 0; (int)i < max_escape + 1; i++)
5489 : 116252 : emap[i].release ();
5490 : 705085 : if (sum)
5491 : 64841 : escape_summaries->remove (edge);
5492 : :
5493 : 705085 : if (summaries)
5494 : : {
5495 : 690192 : if (to_info && !to_info->useful_p (flags))
5496 : : {
5497 : 14307 : if (dump_file)
5498 : 11 : fprintf (dump_file, "Removed mod-ref summary for %s\n",
5499 : : to->dump_name ());
5500 : 14307 : summaries->remove (to);
5501 : 14307 : to_info = NULL;
5502 : : }
5503 : 675885 : else if (to_info && dump_file)
5504 : : {
5505 : 436 : if (dump_file)
5506 : 436 : fprintf (dump_file, "Updated mod-ref summary for %s\n",
5507 : : to->dump_name ());
5508 : 436 : to_info->dump (dump_file);
5509 : : }
5510 : 690192 : if (callee_info)
5511 : 680938 : summaries->remove (edge->callee);
5512 : : }
5513 : 705085 : if (summaries_lto)
5514 : : {
5515 : 32009 : if (to_info_lto && !to_info_lto->useful_p (flags))
5516 : : {
5517 : 571 : if (dump_file)
5518 : 1 : fprintf (dump_file, "Removed mod-ref summary for %s\n",
5519 : : to->dump_name ());
5520 : 571 : summaries_lto->remove (to);
5521 : 571 : to_info_lto = NULL;
5522 : : }
5523 : 31438 : 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 : 32009 : if (callee_info_lto)
5531 : 31763 : summaries_lto->remove (edge->callee);
5532 : : }
5533 : 705085 : if (!to_info && !to_info_lto)
5534 : 14644 : remove_modref_edge_summaries (to);
5535 : 705085 : return;
5536 : 705085 : }
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 : 226752 : pass_ipa_modref::execute (function *)
5545 : : {
5546 : 226752 : if (!summaries && !summaries_lto)
5547 : : return 0;
5548 : 142185 : bool pureconst = false;
5549 : :
5550 : 142185 : if (optimization_summaries)
5551 : 129213 : ggc_delete (optimization_summaries);
5552 : 142185 : optimization_summaries = summaries;
5553 : 142185 : summaries = NULL;
5554 : :
5555 : 142185 : struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
5556 : : symtab->cgraph_count);
5557 : 142185 : int order_pos;
5558 : 142185 : order_pos = ipa_reduced_postorder (order, true, ignore_edge);
5559 : 142185 : int i;
5560 : :
5561 : : /* Iterate over all strongly connected components in post-order. */
5562 : 2308653 : 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 : 2166468 : struct cgraph_node *component_node = order[i];
5567 : :
5568 : 2166468 : if (dump_file)
5569 : 58 : fprintf (dump_file, "\n\nStart of SCC component\n");
5570 : :
5571 : 2166468 : pureconst |= modref_propagate_in_scc (component_node);
5572 : 2166468 : modref_propagate_flags_in_scc (component_node);
5573 : 2166468 : if (optimization_summaries)
5574 : 4222865 : for (struct cgraph_node *cur = component_node; cur;
5575 : 2120668 : cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5576 : 2120668 : if (modref_summary *sum = optimization_summaries->get (cur))
5577 : 694084 : sum->finalize (cur->decl);
5578 : 2166468 : if (dump_file)
5579 : 58 : modref_propagate_dump_scc (component_node);
5580 : : }
5581 : 142185 : cgraph_node *node;
5582 : 6410716 : FOR_EACH_FUNCTION (node)
5583 : 3063173 : update_signature (node);
5584 : 142185 : if (summaries_lto)
5585 : 18812 : ((modref_summaries_lto *)summaries_lto)->propagated = true;
5586 : 142185 : ipa_free_postorder_info ();
5587 : 142185 : free (order);
5588 : 142185 : delete fnspec_summaries;
5589 : 142185 : fnspec_summaries = NULL;
5590 : 142185 : delete escape_summaries;
5591 : 142185 : escape_summaries = NULL;
5592 : :
5593 : : /* If we possibly made constructors const/pure we may need to remove
5594 : : them. */
5595 : 142185 : return pureconst ? TODO_remove_functions : 0;
5596 : : }
5597 : :
5598 : : /* Summaries must stay alive until end of compilation. */
5599 : :
5600 : : void
5601 : 255038 : ipa_modref_cc_finalize ()
5602 : : {
5603 : 255038 : if (optimization_summaries)
5604 : 151038 : ggc_delete (optimization_summaries);
5605 : 255038 : optimization_summaries = NULL;
5606 : 255038 : if (summaries_lto)
5607 : 27426 : ggc_delete (summaries_lto);
5608 : 255038 : summaries_lto = NULL;
5609 : 255038 : if (fnspec_summaries)
5610 : 8623 : delete fnspec_summaries;
5611 : 255038 : fnspec_summaries = NULL;
5612 : 255038 : if (escape_summaries)
5613 : 8623 : delete escape_summaries;
5614 : 255038 : escape_summaries = NULL;
5615 : 255038 : }
5616 : :
5617 : : /* Return true if call is known to perform no memory reads. */
5618 : :
5619 : : bool
5620 : 30791223 : ipa_modref_callee_reads_no_memory_p (gcall *call)
5621 : : {
5622 : 30791223 : if (gimple_call_flags (call) & ECF_CONST)
5623 : : return true;
5624 : 30770525 : attr_fnspec fnspec = gimple_call_fnspec (call);
5625 : 30770525 : if (fnspec.known_p ()
5626 : 30770525 : && !fnspec.global_memory_read_p ())
5627 : : {
5628 : : bool found = false;
5629 : 7095032 : for (unsigned int i = 0; i < gimple_call_num_args (call) && !found; i++)
5630 : 4023020 : if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
5631 : : ;
5632 : 3019700 : else if (!fnspec.arg_specified_p (i)
5633 : 3019700 : || fnspec.arg_maybe_read_p (i))
5634 : : found = true;
5635 : 3072012 : 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 : 29780607 : bool interposed;
5643 : 29780607 : modref_summary *sum = get_modref_function_summary (call, &interposed);
5644 : 29780607 : if (sum && !interposed && !sum->global_memory_read && !sum->loads)
5645 : : return true;
5646 : : return false;
5647 : : }
5648 : :
5649 : : #include "gt-ipa-modref.h"
|