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