Branch data Line data Source code
1 : : /* Search for references that a functions loads or stores.
2 : : Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 : : Contributed by David Cepelik and Jan Hubicka
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it under
8 : : the terms of the GNU General Public License as published by the Free
9 : : Software Foundation; either version 3, or (at your option) any later
10 : : version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : : for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : : /* Mod/ref pass records summary about loads and stores performed by the
22 : : function. This is later used by alias analysis to disambiguate memory
23 : : accesses across function calls.
24 : :
25 : : This file contains a tree pass and an IPA pass. Both performs the same
26 : : analysis however tree pass is executed during early and late optimization
27 : : passes to propagate info downwards in the compilation order. IPA pass
28 : : propagates across the callgraph and is able to handle recursion and works on
29 : : whole program during link-time analysis.
30 : :
31 : : LTO mode differs from the local mode by not recording alias sets but types
32 : : that are translated to alias sets later. This is necessary in order stream
33 : : the information because the alias sets are rebuild at stream-in time and may
34 : : not correspond to ones seen during analysis. For this reason part of
35 : : analysis is duplicated.
36 : :
37 : : The following information is computed
38 : : 1) load/store access tree described in ipa-modref-tree.h
39 : : This is used by tree-ssa-alias to disambiguate load/stores
40 : : 2) EAF flags used by points-to analysis (in tree-ssa-structalias).
41 : : and defined in tree-core.h.
42 : : and stored to optimization_summaries.
43 : :
44 : : There are multiple summaries computed and used during the propagation:
45 : : - summaries holds summaries from analysis to IPA propagation
46 : : time.
47 : : - summaries_lto is same as summaries but holds them in a format
48 : : that can be streamed (as described above).
49 : : - fnspec_summary holds fnspec strings for call. This is
50 : : necessary because gimple_call_fnspec performs additional
51 : : analysis except for looking callee fndecl.
52 : : - escape_summary holds escape points for given call edge.
53 : : That is a vector recording what function parameters
54 : : may escape to a function call (and with what parameter index). */
55 : :
56 : : #include "config.h"
57 : : #include "system.h"
58 : : #include "coretypes.h"
59 : : #include "backend.h"
60 : : #include "tree.h"
61 : : #include "gimple.h"
62 : : #include "alloc-pool.h"
63 : : #include "tree-pass.h"
64 : : #include "gimple-iterator.h"
65 : : #include "tree-dfa.h"
66 : : #include "cgraph.h"
67 : : #include "ipa-utils.h"
68 : : #include "symbol-summary.h"
69 : : #include "gimple-pretty-print.h"
70 : : #include "gimple-walk.h"
71 : : #include "print-tree.h"
72 : : #include "tree-streamer.h"
73 : : #include "alias.h"
74 : : #include "calls.h"
75 : : #include "ipa-modref-tree.h"
76 : : #include "ipa-modref.h"
77 : : #include "value-range.h"
78 : : #include "sreal.h"
79 : : #include "ipa-cp.h"
80 : : #include "ipa-prop.h"
81 : : #include "ipa-fnsummary.h"
82 : : #include "attr-fnspec.h"
83 : : #include "symtab-clones.h"
84 : : #include "gimple-ssa.h"
85 : : #include "tree-phinodes.h"
86 : : #include "tree-ssa-operands.h"
87 : : #include "ssa-iterators.h"
88 : : #include "stringpool.h"
89 : : #include "tree-ssanames.h"
90 : : #include "attribs.h"
91 : : #include "tree-cfg.h"
92 : : #include "tree-eh.h"
93 : :
94 : :
95 : : namespace {
96 : :
97 : : /* We record fnspec specifiers for call edges since they depends on actual
98 : : gimple statements. */
99 : :
100 : : class fnspec_summary
101 : : {
102 : : public:
103 : : char *fnspec;
104 : :
105 : 921742 : fnspec_summary ()
106 : 921742 : : fnspec (NULL)
107 : : {
108 : : }
109 : :
110 : 921742 : ~fnspec_summary ()
111 : : {
112 : 921742 : free (fnspec);
113 : 921742 : }
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 : 150125 : fnspec_summaries_t (symbol_table *symtab)
122 : 300250 : : call_summary <fnspec_summary *> (symtab) {}
123 : : /* Hook that is called by summary when an edge is duplicated. */
124 : 359018 : void duplicate (cgraph_edge *,
125 : : cgraph_edge *,
126 : : fnspec_summary *src,
127 : : fnspec_summary *dst) final override
128 : : {
129 : 359018 : dst->fnspec = xstrdup (src->fnspec);
130 : 359018 : }
131 : : };
132 : :
133 : : static fnspec_summaries_t *fnspec_summaries = NULL;
134 : :
135 : : /* Escape summary holds a vector of param indexes that escape to
136 : : a given call. */
137 : : struct escape_entry
138 : : {
139 : : /* Parameter that escapes at a given call. */
140 : : int parm_index;
141 : : /* Argument it escapes to. */
142 : : unsigned int arg;
143 : : /* Minimal flags known about the argument. */
144 : : eaf_flags_t min_flags;
145 : : /* Does it escape directly or indirectly? */
146 : : bool direct;
147 : : };
148 : :
149 : : /* Dump EAF flags. */
150 : :
151 : : static void
152 : 3592 : dump_eaf_flags (FILE *out, int flags, bool newline = true)
153 : : {
154 : 3592 : if (flags & EAF_UNUSED)
155 : 286 : fprintf (out, " unused");
156 : 3592 : if (flags & EAF_NO_DIRECT_CLOBBER)
157 : 2271 : fprintf (out, " no_direct_clobber");
158 : 3592 : if (flags & EAF_NO_INDIRECT_CLOBBER)
159 : 2174 : fprintf (out, " no_indirect_clobber");
160 : 3592 : if (flags & EAF_NO_DIRECT_ESCAPE)
161 : 2797 : fprintf (out, " no_direct_escape");
162 : 3592 : if (flags & EAF_NO_INDIRECT_ESCAPE)
163 : 2433 : fprintf (out, " no_indirect_escape");
164 : 3592 : if (flags & EAF_NOT_RETURNED_DIRECTLY)
165 : 2496 : fprintf (out, " not_returned_directly");
166 : 3592 : if (flags & EAF_NOT_RETURNED_INDIRECTLY)
167 : 2372 : fprintf (out, " not_returned_indirectly");
168 : 3592 : if (flags & EAF_NO_DIRECT_READ)
169 : 2093 : fprintf (out, " no_direct_read");
170 : 3592 : if (flags & EAF_NO_INDIRECT_READ)
171 : 2239 : fprintf (out, " no_indirect_read");
172 : 3592 : if (newline)
173 : 3516 : fprintf (out, "\n");
174 : 3592 : }
175 : :
176 : 720884 : struct escape_summary
177 : : {
178 : : auto_vec <escape_entry> esc;
179 : 11 : void dump (FILE *out)
180 : : {
181 : 24 : for (unsigned int i = 0; i < esc.length (); i++)
182 : : {
183 : 39 : fprintf (out, " parm %i arg %i %s min:",
184 : 13 : esc[i].parm_index,
185 : 13 : esc[i].arg,
186 : 13 : esc[i].direct ? "(direct)" : "(indirect)");
187 : 13 : dump_eaf_flags (out, esc[i].min_flags, false);
188 : : }
189 : 11 : fprintf (out, "\n");
190 : 11 : }
191 : : };
192 : :
193 : : class escape_summaries_t : public call_summary <escape_summary *>
194 : : {
195 : : public:
196 : 150125 : escape_summaries_t (symbol_table *symtab)
197 : 300250 : : call_summary <escape_summary *> (symtab) {}
198 : : /* Hook that is called by summary when an edge is duplicated. */
199 : 139240 : void duplicate (cgraph_edge *,
200 : : cgraph_edge *,
201 : : escape_summary *src,
202 : : escape_summary *dst) final override
203 : : {
204 : 139240 : dst->esc = src->esc.copy ();
205 : 139240 : }
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 : 279321 : modref_summaries (symbol_table *symtab)
221 : 558642 : : 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 : 279321 : static modref_summaries *create_ggc (symbol_table *symtab)
228 : : {
229 : 279321 : return new (ggc_alloc_no_dtor<modref_summaries> ())
230 : 279321 : 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 : 27232 : modref_summaries_lto (symbol_table *symtab)
244 : 27232 : : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
245 : 54464 : 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 : 27232 : static modref_summaries_lto *create_ggc (symbol_table *symtab)
252 : : {
253 : 27232 : return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
254 : 27232 : 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 : 6983191 : modref_summary::modref_summary ()
280 : 6983191 : : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
281 : 6983191 : writes_errno (false), side_effects (false), nondeterministic (false),
282 : 6983191 : calls_interposable (false), global_memory_read (false),
283 : 6983191 : global_memory_written (false), try_dse (false)
284 : : {
285 : 6983191 : }
286 : :
287 : 6982529 : modref_summary::~modref_summary ()
288 : : {
289 : 6982529 : if (loads)
290 : 5097084 : ggc_delete (loads);
291 : 6982529 : if (stores)
292 : 5097084 : ggc_delete (stores);
293 : 6982529 : }
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 : 15729395 : remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
300 : : {
301 : 15729395 : if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
302 : 1466078 : eaf_flags &= ~implicit_const_eaf_flags;
303 : 14263317 : else if (ecf_flags & ECF_PURE)
304 : 2185155 : eaf_flags &= ~implicit_pure_eaf_flags;
305 : 12078162 : else if ((ecf_flags & ECF_NORETURN) || returns_void)
306 : 2832624 : eaf_flags &= ~(EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY);
307 : 15729395 : return eaf_flags;
308 : : }
309 : :
310 : : /* Return true if FLAGS holds some useful information. */
311 : :
312 : : static bool
313 : 5449595 : eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags)
314 : : {
315 : 6135849 : for (unsigned i = 0; i < flags.length (); i++)
316 : 3782616 : 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 : 71740476 : modref_summary::useful_p (int ecf_flags, bool check_flags)
326 : : {
327 : 71740476 : if (arg_flags.length () && !check_flags)
328 : : return true;
329 : 28214542 : if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
330 : : return true;
331 : 25316213 : arg_flags.release ();
332 : 25316213 : if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
333 : : return true;
334 : 25302697 : if (check_flags
335 : 25302697 : && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
336 : : return true;
337 : 25260312 : if (ecf_flags & ECF_CONST)
338 : 1104960 : return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
339 : 24696665 : if (loads && !loads->every_base)
340 : : return true;
341 : : else
342 : 5529986 : kills.release ();
343 : 5529986 : if (ecf_flags & ECF_PURE)
344 : 162388 : return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
345 : 5416496 : return stores && !stores->every_base;
346 : : }
347 : :
348 : : /* Single function summary used for LTO. */
349 : :
350 : : typedef modref_tree <tree> modref_records_lto;
351 : : struct GTY(()) modref_summary_lto
352 : : {
353 : : /* Load and stores in functions using types rather then alias sets.
354 : :
355 : : This is necessary to make the information streamable for LTO but is also
356 : : more verbose and thus more likely to hit the limits. */
357 : : modref_records_lto *loads;
358 : : modref_records_lto *stores;
359 : : auto_vec<modref_access_node> GTY((skip)) kills;
360 : : auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
361 : : eaf_flags_t retslot_flags;
362 : : eaf_flags_t static_chain_flags;
363 : : unsigned writes_errno : 1;
364 : : unsigned side_effects : 1;
365 : : unsigned nondeterministic : 1;
366 : : unsigned calls_interposable : 1;
367 : :
368 : : modref_summary_lto ();
369 : : ~modref_summary_lto ();
370 : : void dump (FILE *);
371 : : bool useful_p (int ecf_flags, bool check_flags = true);
372 : : };
373 : :
374 : : /* Summary for a single function which this pass produces. */
375 : :
376 : 160837 : modref_summary_lto::modref_summary_lto ()
377 : 160837 : : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
378 : 160837 : writes_errno (false), side_effects (false), nondeterministic (false),
379 : 160837 : calls_interposable (false)
380 : : {
381 : 160837 : }
382 : :
383 : 160831 : modref_summary_lto::~modref_summary_lto ()
384 : : {
385 : 160831 : if (loads)
386 : 160238 : ggc_delete (loads);
387 : 160831 : if (stores)
388 : 160238 : ggc_delete (stores);
389 : 160831 : }
390 : :
391 : :
392 : : /* Return true if lto summary is potentially useful for optimization.
393 : : If CHECK_FLAGS is false assume that arg_flags are useful. */
394 : :
395 : : bool
396 : 907442 : modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
397 : : {
398 : 907442 : if (arg_flags.length () && !check_flags)
399 : : return true;
400 : 601656 : if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
401 : : return true;
402 : 403623 : arg_flags.release ();
403 : 403623 : if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
404 : : return true;
405 : 402921 : if (check_flags
406 : 402921 : && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
407 : : return true;
408 : 402524 : if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
409 : 30084 : return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
410 : 387170 : if (loads && !loads->every_base)
411 : : return true;
412 : : else
413 : 74396 : kills.release ();
414 : 74396 : if (ecf_flags & ECF_PURE)
415 : 8169 : return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
416 : 69808 : return stores && !stores->every_base;
417 : : }
418 : :
419 : : /* Dump records TT to OUT. */
420 : :
421 : : static void
422 : 1284 : dump_records (modref_records *tt, FILE *out)
423 : : {
424 : 1284 : if (tt->every_base)
425 : : {
426 : 155 : fprintf (out, " Every base\n");
427 : 155 : return;
428 : : }
429 : : size_t i;
430 : : modref_base_node <alias_set_type> *n;
431 : 1860 : FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
432 : : {
433 : 731 : fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
434 : 731 : if (n->every_ref)
435 : : {
436 : 0 : fprintf (out, " Every ref\n");
437 : 0 : continue;
438 : : }
439 : : size_t j;
440 : : modref_ref_node <alias_set_type> *r;
441 : 2264 : FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
442 : : {
443 : 802 : fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
444 : 802 : if (r->every_access)
445 : : {
446 : 578 : fprintf (out, " Every access\n");
447 : 578 : continue;
448 : : }
449 : : size_t k;
450 : : modref_access_node *a;
451 : 1272 : FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
452 : : {
453 : 246 : fprintf (out, " access:");
454 : 246 : a->dump (out);
455 : : }
456 : : }
457 : : }
458 : : }
459 : :
460 : : /* Dump records TT to OUT. */
461 : :
462 : : static void
463 : 74 : dump_lto_records (modref_records_lto *tt, FILE *out)
464 : : {
465 : 74 : if (tt->every_base)
466 : : {
467 : 10 : fprintf (out, " Every base\n");
468 : 10 : return;
469 : : }
470 : : size_t i;
471 : : modref_base_node <tree> *n;
472 : 124 : FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
473 : : {
474 : 60 : fprintf (out, " Base %i:", (int)i);
475 : 60 : print_generic_expr (out, n->base);
476 : 60 : fprintf (out, " (alias set %i)\n",
477 : 60 : n->base ? get_alias_set (n->base) : 0);
478 : 60 : if (n->every_ref)
479 : : {
480 : 0 : fprintf (out, " Every ref\n");
481 : 0 : continue;
482 : : }
483 : : size_t j;
484 : : modref_ref_node <tree> *r;
485 : 180 : FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
486 : : {
487 : 60 : fprintf (out, " Ref %i:", (int)j);
488 : 60 : print_generic_expr (out, r->ref);
489 : 60 : fprintf (out, " (alias set %i)\n",
490 : 60 : r->ref ? get_alias_set (r->ref) : 0);
491 : 60 : if (r->every_access)
492 : : {
493 : 36 : fprintf (out, " Every access\n");
494 : 36 : continue;
495 : : }
496 : : size_t k;
497 : : modref_access_node *a;
498 : 108 : FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
499 : : {
500 : 24 : fprintf (out, " access:");
501 : 24 : a->dump (out);
502 : : }
503 : : }
504 : : }
505 : : }
506 : :
507 : : /* Dump all escape points of NODE to OUT. */
508 : :
509 : : static void
510 : 179 : dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
511 : : {
512 : 179 : int i = 0;
513 : 179 : if (!escape_summaries)
514 : : return;
515 : 120 : for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
516 : : {
517 : 26 : class escape_summary *sum = escape_summaries->get (e);
518 : 26 : if (sum)
519 : : {
520 : 0 : fprintf (out, "%*sIndirect call %i in %s escapes:",
521 : : depth, "", i, node->dump_name ());
522 : 0 : sum->dump (out);
523 : : }
524 : 26 : i++;
525 : : }
526 : 194 : for (cgraph_edge *e = node->callees; e; e = e->next_callee)
527 : : {
528 : 100 : if (!e->inline_failed)
529 : 0 : dump_modref_edge_summaries (out, e->callee, depth + 1);
530 : 100 : class escape_summary *sum = escape_summaries->get (e);
531 : 100 : if (sum)
532 : : {
533 : 11 : fprintf (out, "%*sCall %s->%s escapes:", depth, "",
534 : 11 : node->dump_name (), e->callee->dump_name ());
535 : 11 : sum->dump (out);
536 : : }
537 : 100 : class fnspec_summary *fsum = fnspec_summaries->get (e);
538 : 100 : if (fsum)
539 : : {
540 : 2 : fprintf (out, "%*sCall %s->%s fnspec: %s\n", depth, "",
541 : 2 : node->dump_name (), e->callee->dump_name (),
542 : : fsum->fnspec);
543 : : }
544 : : }
545 : : }
546 : :
547 : : /* Remove all call edge summaries associated with NODE. */
548 : :
549 : : static void
550 : 392231 : remove_modref_edge_summaries (cgraph_node *node)
551 : : {
552 : 392231 : if (!escape_summaries)
553 : : return;
554 : 434571 : for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
555 : 42340 : escape_summaries->remove (e);
556 : 2106652 : for (cgraph_edge *e = node->callees; e; e = e->next_callee)
557 : : {
558 : 1714421 : if (!e->inline_failed)
559 : 135477 : remove_modref_edge_summaries (e->callee);
560 : 1714421 : escape_summaries->remove (e);
561 : 1714421 : fnspec_summaries->remove (e);
562 : : }
563 : : }
564 : :
565 : : /* Dump summary. */
566 : :
567 : : void
568 : 642 : modref_summary::dump (FILE *out) const
569 : : {
570 : 642 : if (loads)
571 : : {
572 : 642 : fprintf (out, " loads:\n");
573 : 642 : dump_records (loads, out);
574 : : }
575 : 642 : if (stores)
576 : : {
577 : 642 : fprintf (out, " stores:\n");
578 : 642 : dump_records (stores, out);
579 : : }
580 : 642 : if (kills.length ())
581 : : {
582 : 41 : fprintf (out, " kills:\n");
583 : 175 : for (auto kill : kills)
584 : : {
585 : 52 : fprintf (out, " ");
586 : 52 : kill.dump (out);
587 : : }
588 : : }
589 : 642 : if (writes_errno)
590 : 0 : fprintf (out, " Writes errno\n");
591 : 642 : if (side_effects)
592 : 108 : fprintf (out, " Side effects\n");
593 : 642 : if (nondeterministic)
594 : 483 : fprintf (out, " Nondeterministic\n");
595 : 642 : if (calls_interposable)
596 : 0 : fprintf (out, " Calls interposable\n");
597 : 642 : if (global_memory_read)
598 : 146 : fprintf (out, " Global memory read\n");
599 : 642 : if (global_memory_written)
600 : 113 : fprintf (out, " Global memory written\n");
601 : 642 : if (try_dse)
602 : 450 : fprintf (out, " Try dse\n");
603 : 642 : if (arg_flags.length ())
604 : : {
605 : 1306 : for (unsigned int i = 0; i < arg_flags.length (); i++)
606 : 924 : if (arg_flags[i])
607 : : {
608 : 816 : fprintf (out, " parm %i flags:", i);
609 : 816 : dump_eaf_flags (out, arg_flags[i]);
610 : : }
611 : : }
612 : 642 : if (retslot_flags)
613 : : {
614 : 4 : fprintf (out, " Retslot flags:");
615 : 4 : dump_eaf_flags (out, retslot_flags);
616 : : }
617 : 642 : if (static_chain_flags)
618 : : {
619 : 4 : fprintf (out, " Static chain flags:");
620 : 4 : dump_eaf_flags (out, static_chain_flags);
621 : : }
622 : 642 : }
623 : :
624 : : /* Dump summary. */
625 : :
626 : : void
627 : 37 : modref_summary_lto::dump (FILE *out)
628 : : {
629 : 37 : fprintf (out, " loads:\n");
630 : 37 : dump_lto_records (loads, out);
631 : 37 : fprintf (out, " stores:\n");
632 : 37 : dump_lto_records (stores, out);
633 : 37 : if (kills.length ())
634 : : {
635 : 6 : fprintf (out, " kills:\n");
636 : 24 : for (auto kill : kills)
637 : : {
638 : 6 : fprintf (out, " ");
639 : 6 : kill.dump (out);
640 : : }
641 : : }
642 : 37 : if (writes_errno)
643 : 0 : fprintf (out, " Writes errno\n");
644 : 37 : if (side_effects)
645 : 8 : fprintf (out, " Side effects\n");
646 : 37 : if (nondeterministic)
647 : 2 : fprintf (out, " Nondeterministic\n");
648 : 37 : if (calls_interposable)
649 : 0 : fprintf (out, " Calls interposable\n");
650 : 37 : if (arg_flags.length ())
651 : : {
652 : 72 : for (unsigned int i = 0; i < arg_flags.length (); i++)
653 : 54 : if (arg_flags[i])
654 : : {
655 : 48 : fprintf (out, " parm %i flags:", i);
656 : 48 : dump_eaf_flags (out, arg_flags[i]);
657 : : }
658 : : }
659 : 37 : if (retslot_flags)
660 : : {
661 : 0 : fprintf (out, " Retslot flags:");
662 : 0 : dump_eaf_flags (out, retslot_flags);
663 : : }
664 : 37 : if (static_chain_flags)
665 : : {
666 : 0 : fprintf (out, " Static chain flags:");
667 : 0 : dump_eaf_flags (out, static_chain_flags);
668 : : }
669 : 37 : }
670 : :
671 : : /* Called after summary is produced and before it is used by local analysis.
672 : : Can be called multiple times in case summary needs to update signature.
673 : : FUN is decl of function summary is attached to. */
674 : : void
675 : 4075191 : modref_summary::finalize (tree fun)
676 : : {
677 : 4075191 : global_memory_read = !loads || loads->global_access_p ();
678 : 4075191 : global_memory_written = !stores || stores->global_access_p ();
679 : :
680 : : /* We can do DSE if we know function has no side effects and
681 : : we can analyze all stores. Disable dse if there are too many
682 : : stores to try. */
683 : 4075191 : if (side_effects || global_memory_written || writes_errno)
684 : 2103226 : try_dse = false;
685 : : else
686 : : {
687 : 1971965 : try_dse = true;
688 : 1971965 : size_t i, j, k;
689 : 1971965 : int num_tests = 0, max_tests
690 : 1971965 : = opt_for_fn (fun, param_modref_max_tests);
691 : 1971965 : modref_base_node <alias_set_type> *base_node;
692 : 1971965 : modref_ref_node <alias_set_type> *ref_node;
693 : 1971965 : modref_access_node *access_node;
694 : 2532195 : FOR_EACH_VEC_SAFE_ELT (stores->bases, i, base_node)
695 : : {
696 : 602514 : if (base_node->every_ref)
697 : : {
698 : 0 : try_dse = false;
699 : 0 : break;
700 : : }
701 : 1437041 : FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
702 : : {
703 : 876811 : if (base_node->every_ref)
704 : : {
705 : : try_dse = false;
706 : : break;
707 : : }
708 : 1791446 : FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
709 : 956919 : if (num_tests++ > max_tests
710 : 956919 : || !access_node->parm_offset_known)
711 : : {
712 : 42284 : try_dse = false;
713 : 42284 : break;
714 : : }
715 : 876811 : if (!try_dse)
716 : : break;
717 : : }
718 : 602514 : if (!try_dse)
719 : : break;
720 : : }
721 : : }
722 : 4075191 : if (loads->every_base)
723 : 1186384 : load_accesses = 1;
724 : : else
725 : : {
726 : 2888807 : load_accesses = 0;
727 : 8238773 : for (auto base_node : loads->bases)
728 : : {
729 : 2194174 : if (base_node->every_ref)
730 : 5884 : load_accesses++;
731 : : else
732 : 9019677 : for (auto ref_node : base_node->refs)
733 : 2454807 : if (ref_node->every_access)
734 : 873417 : load_accesses++;
735 : : else
736 : 1581390 : load_accesses += ref_node->accesses->length ();
737 : : }
738 : : }
739 : 4075191 : }
740 : :
741 : : /* Get function summary for FUNC if it exists, return NULL otherwise. */
742 : :
743 : : modref_summary *
744 : 472391114 : get_modref_function_summary (cgraph_node *func)
745 : : {
746 : : /* Avoid creation of the summary too early (e.g. when front-end calls us). */
747 : 472391114 : if (!optimization_summaries)
748 : : return NULL;
749 : :
750 : : /* A single function body may be represented by multiple symbols with
751 : : different visibility. For example, if FUNC is an interposable alias,
752 : : we don't want to return anything, even if we have summary for the target
753 : : function. */
754 : 460040909 : enum availability avail;
755 : 460040909 : func = func->ultimate_alias_target
756 : 919903142 : (&avail, current_function_decl ?
757 : 459862233 : cgraph_node::get (current_function_decl) : NULL);
758 : 460040909 : if (avail <= AVAIL_INTERPOSABLE)
759 : : return NULL;
760 : :
761 : 115841412 : modref_summary *r = optimization_summaries->get (func);
762 : 115841412 : return r;
763 : : }
764 : :
765 : : /* Get function summary for CALL if it exists, return NULL otherwise.
766 : : If non-null set interposed to indicate whether function may not
767 : : bind to current def. In this case sometimes loads from function
768 : : needs to be ignored. */
769 : :
770 : : modref_summary *
771 : 35852308 : get_modref_function_summary (gcall *call, bool *interposed)
772 : : {
773 : 35852308 : tree callee = gimple_call_fndecl (call);
774 : 35852308 : if (!callee)
775 : : return NULL;
776 : 34225262 : struct cgraph_node *node = cgraph_node::get (callee);
777 : 34225262 : if (!node)
778 : : return NULL;
779 : 34145533 : modref_summary *r = get_modref_function_summary (node);
780 : 34145533 : if (interposed && r)
781 : 5913090 : *interposed = r->calls_interposable
782 : 5913090 : || !node->binds_to_current_def_p ();
783 : : return r;
784 : : }
785 : :
786 : :
787 : : namespace {
788 : :
789 : : /* Return true if ECF flags says that nondeterminism can be ignored. */
790 : :
791 : : static bool
792 : 7797254 : ignore_nondeterminism_p (tree caller, int flags, tree callee_fntype)
793 : : {
794 : 7797254 : int caller_flags = flags_from_decl_or_type (caller);
795 : 7797254 : if ((flags | caller_flags) & (ECF_CONST | ECF_PURE))
796 : : return true;
797 : 7518236 : if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
798 : 7518236 : || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
799 : : return true;
800 : : /* C language defines unsequenced and reproducible functions
801 : : to be deterministic. */
802 : 6930689 : if (lookup_attribute ("unsequenced", TYPE_ATTRIBUTES (TREE_TYPE (caller)))
803 : 13861378 : || lookup_attribute ("reproducible",
804 : 6930689 : TYPE_ATTRIBUTES (TREE_TYPE (caller))))
805 : 0 : return true;
806 : 6930689 : if (callee_fntype
807 : 6930689 : && (lookup_attribute ("unsequenced", TYPE_ATTRIBUTES (callee_fntype))
808 : 5637843 : || lookup_attribute ("reproducible",
809 : 5637843 : TYPE_ATTRIBUTES (callee_fntype))))
810 : 0 : return true;
811 : : return false;
812 : : }
813 : :
814 : : /* Return true if ECF flags says that return value can be ignored. */
815 : :
816 : : static bool
817 : 5480392 : ignore_retval_p (tree caller, int flags)
818 : : {
819 : 5480392 : if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
820 : 5480392 : || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
821 : 41899 : return true;
822 : : return false;
823 : : }
824 : :
825 : : /* Return true if ECF flags says that stores can be ignored. */
826 : :
827 : : static bool
828 : 25965352 : ignore_stores_p (tree caller, int flags)
829 : : {
830 : 25965352 : if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
831 : : return true;
832 : 22974177 : if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
833 : 22974177 : || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
834 : 1530772 : return true;
835 : : return false;
836 : : }
837 : :
838 : : /* Determine parm_map for PTR which is supposed to be a pointer. */
839 : :
840 : : modref_parm_map
841 : 14758409 : parm_map_for_ptr (tree op)
842 : : {
843 : 14758409 : bool offset_known;
844 : 14758409 : poly_int64 offset;
845 : 14758409 : struct modref_parm_map parm_map;
846 : 14758409 : gcall *call;
847 : :
848 : 14758409 : parm_map.parm_offset_known = false;
849 : 14758409 : parm_map.parm_offset = 0;
850 : :
851 : 14758409 : offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
852 : 14758409 : if (TREE_CODE (op) == SSA_NAME
853 : 9802084 : && SSA_NAME_IS_DEFAULT_DEF (op)
854 : 22637157 : && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
855 : : {
856 : 7865671 : int index = 0;
857 : :
858 : 7865671 : if (cfun->static_chain_decl
859 : 7865671 : && op == ssa_default_def (cfun, cfun->static_chain_decl))
860 : : index = MODREF_STATIC_CHAIN_PARM;
861 : : else
862 : 7786931 : for (tree t = DECL_ARGUMENTS (current_function_decl);
863 : 12691700 : t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
864 : 4904769 : index++;
865 : 7865671 : parm_map.parm_index = index;
866 : 7865671 : parm_map.parm_offset_known = offset_known;
867 : 7865671 : parm_map.parm_offset = offset;
868 : : }
869 : 6892738 : else if (points_to_local_or_readonly_memory_p (op))
870 : : parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM;
871 : : /* Memory allocated in the function is not visible to caller before the
872 : : call and thus we do not need to record it as load/stores/kills. */
873 : 6172410 : else if (TREE_CODE (op) == SSA_NAME
874 : 1817646 : && (call = dyn_cast<gcall *>(SSA_NAME_DEF_STMT (op))) != NULL
875 : 6851951 : && gimple_call_flags (call) & ECF_MALLOC)
876 : : parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM;
877 : : else
878 : : parm_map.parm_index = MODREF_UNKNOWN_PARM;
879 : 14758409 : return parm_map;
880 : : }
881 : :
882 : : /* Return true if ARG with EAF flags FLAGS can not make any caller's parameter
883 : : used (if LOAD is true we check loads, otherwise stores). */
884 : :
885 : : static bool
886 : 10542656 : verify_arg (tree arg, int flags, bool load)
887 : : {
888 : 10542656 : if (flags & EAF_UNUSED)
889 : : return true;
890 : 10300874 : if (load && (flags & EAF_NO_DIRECT_READ))
891 : : return true;
892 : : if (!load
893 : 4464535 : && (flags & (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER))
894 : : == (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER))
895 : : return true;
896 : 9392684 : if (is_gimple_constant (arg))
897 : : return true;
898 : 7308189 : if (DECL_P (arg) && TREE_READONLY (arg))
899 : : return true;
900 : 7308085 : if (TREE_CODE (arg) == ADDR_EXPR)
901 : : {
902 : 3146307 : tree t = get_base_address (TREE_OPERAND (arg, 0));
903 : 6962637 : if (is_gimple_constant (t))
904 : : return true;
905 : 2224877 : if (DECL_P (t)
906 : 2224877 : && (TREE_READONLY (t) || TREE_CODE (t) == FUNCTION_DECL))
907 : : return true;
908 : : }
909 : : return false;
910 : : }
911 : :
912 : : /* Return true if STMT may access memory that is pointed to by parameters
913 : : of caller and which is not seen as an escape by PTA.
914 : : CALLEE_ECF_FLAGS are ECF flags of callee. If LOAD is true then by access
915 : : we mean load, otherwise we mean store. */
916 : :
917 : : static bool
918 : 8607822 : may_access_nonescaping_parm_p (gcall *call, int callee_ecf_flags, bool load)
919 : : {
920 : 8607822 : int implicit_flags = 0;
921 : :
922 : 8607822 : if (ignore_stores_p (current_function_decl, callee_ecf_flags))
923 : 615670 : implicit_flags |= ignore_stores_eaf_flags;
924 : 8607822 : if (callee_ecf_flags & ECF_PURE)
925 : 237981 : implicit_flags |= implicit_pure_eaf_flags;
926 : 8607822 : if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
927 : 0 : implicit_flags |= implicit_const_eaf_flags;
928 : 8607822 : if (gimple_call_chain (call)
929 : 8646959 : && !verify_arg (gimple_call_chain (call),
930 : 39137 : gimple_call_static_chain_flags (call) | implicit_flags,
931 : : load))
932 : : return true;
933 : 13306445 : for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
934 : 10503519 : if (!verify_arg (gimple_call_arg (call, i),
935 : 10503519 : gimple_call_arg_flags (call, i) | implicit_flags,
936 : : load))
937 : : return true;
938 : : return false;
939 : : }
940 : :
941 : :
942 : : /* Analyze memory accesses (loads, stores and kills) performed
943 : : by the function. Set also side_effects, calls_interposable
944 : : and nondeterminism flags. */
945 : :
946 : 8966578 : class modref_access_analysis
947 : : {
948 : : public:
949 : 4483289 : modref_access_analysis (bool ipa, modref_summary *summary,
950 : : modref_summary_lto *summary_lto)
951 : 4483289 : : m_summary (summary), m_summary_lto (summary_lto), m_ipa (ipa)
952 : : {
953 : : }
954 : : void analyze ();
955 : : private:
956 : : bool set_side_effects ();
957 : : bool set_nondeterministic ();
958 : : static modref_access_node get_access (ao_ref *ref);
959 : : static void record_access (modref_records *, ao_ref *, modref_access_node &);
960 : : static void record_access_lto (modref_records_lto *, ao_ref *,
961 : : modref_access_node &a);
962 : : bool record_access_p (tree);
963 : : bool record_unknown_load ();
964 : : bool record_unknown_store ();
965 : : bool record_global_memory_load ();
966 : : bool record_global_memory_store ();
967 : : bool merge_call_side_effects (gimple *, modref_summary *,
968 : : cgraph_node *, bool);
969 : : modref_access_node get_access_for_fnspec (gcall *, attr_fnspec &,
970 : : unsigned int, modref_parm_map &);
971 : : void process_fnspec (gcall *);
972 : : void analyze_call (gcall *);
973 : : static bool analyze_load (gimple *, tree, tree, void *);
974 : : static bool analyze_store (gimple *, tree, tree, void *);
975 : : void analyze_stmt (gimple *, bool);
976 : : void propagate ();
977 : :
978 : : /* Summary being computed.
979 : : We work either with m_summary or m_summary_lto. Never on both. */
980 : : modref_summary *m_summary;
981 : : modref_summary_lto *m_summary_lto;
982 : : /* Recursive calls needs simplistic dataflow after analysis finished.
983 : : Collect all calls into this vector during analysis and later process
984 : : them in propagate. */
985 : : auto_vec <gimple *, 32> m_recursive_calls;
986 : : /* ECF flags of function being analyzed. */
987 : : int m_ecf_flags;
988 : : /* True if IPA propagation will be done later. */
989 : : bool m_ipa;
990 : : /* Set true if statement currently analyze is known to be
991 : : executed each time function is called. */
992 : : bool m_always_executed;
993 : : };
994 : :
995 : : /* Set side_effects flag and return if something changed. */
996 : :
997 : : bool
998 : 6636737 : modref_access_analysis::set_side_effects ()
999 : : {
1000 : 6636737 : bool changed = false;
1001 : :
1002 : 6636737 : if (m_summary && !m_summary->side_effects)
1003 : : {
1004 : 1510122 : m_summary->side_effects = true;
1005 : 1510122 : changed = true;
1006 : : }
1007 : 6636737 : if (m_summary_lto && !m_summary_lto->side_effects)
1008 : : {
1009 : 1488 : m_summary_lto->side_effects = true;
1010 : 1488 : changed = true;
1011 : : }
1012 : 6636737 : return changed;
1013 : : }
1014 : :
1015 : : /* Set nondeterministic flag and return if something changed. */
1016 : :
1017 : : bool
1018 : 4101422 : modref_access_analysis::set_nondeterministic ()
1019 : : {
1020 : 4101422 : bool changed = false;
1021 : :
1022 : 4101422 : if (m_summary && !m_summary->nondeterministic)
1023 : : {
1024 : 1315346 : m_summary->side_effects = m_summary->nondeterministic = true;
1025 : 1315346 : changed = true;
1026 : : }
1027 : 4101422 : if (m_summary_lto && !m_summary_lto->nondeterministic)
1028 : : {
1029 : 5881 : m_summary_lto->side_effects = m_summary_lto->nondeterministic = true;
1030 : 5881 : changed = true;
1031 : : }
1032 : 4101422 : return changed;
1033 : : }
1034 : :
1035 : : /* Construct modref_access_node from REF. */
1036 : :
1037 : : modref_access_node
1038 : 12736174 : modref_access_analysis::get_access (ao_ref *ref)
1039 : : {
1040 : 12736174 : tree base;
1041 : :
1042 : 12736174 : base = ao_ref_base (ref);
1043 : 12736174 : modref_access_node a = {ref->offset, ref->size, ref->max_size,
1044 : 12736174 : 0, MODREF_UNKNOWN_PARM, false, 0};
1045 : 12736174 : if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
1046 : : {
1047 : 10311966 : tree memref = base;
1048 : 10311966 : modref_parm_map m = parm_map_for_ptr (TREE_OPERAND (base, 0));
1049 : :
1050 : 10311966 : a.parm_index = m.parm_index;
1051 : 10311966 : if (a.parm_index != MODREF_UNKNOWN_PARM && TREE_CODE (memref) == MEM_REF)
1052 : : {
1053 : 6837152 : a.parm_offset_known
1054 : 6837152 : = wi::to_poly_wide (TREE_OPERAND
1055 : 6837152 : (memref, 1)).to_shwi (&a.parm_offset);
1056 : 6837152 : if (a.parm_offset_known && m.parm_offset_known)
1057 : 10311966 : a.parm_offset += m.parm_offset;
1058 : : else
1059 : 502208 : a.parm_offset_known = false;
1060 : : }
1061 : : }
1062 : : else
1063 : : a.parm_index = MODREF_UNKNOWN_PARM;
1064 : 12736174 : return a;
1065 : : }
1066 : :
1067 : : /* Record access into the modref_records data structure. */
1068 : :
1069 : : void
1070 : 12369450 : modref_access_analysis::record_access (modref_records *tt,
1071 : : ao_ref *ref,
1072 : : modref_access_node &a)
1073 : : {
1074 : 12369450 : alias_set_type base_set = !flag_strict_aliasing
1075 : 12369450 : || !flag_ipa_strict_aliasing ? 0
1076 : 9850041 : : ao_ref_base_alias_set (ref);
1077 : 12369450 : alias_set_type ref_set = !flag_strict_aliasing
1078 : 12369450 : || !flag_ipa_strict_aliasing ? 0
1079 : 9850041 : : (ao_ref_alias_set (ref));
1080 : 12369450 : if (dump_file)
1081 : : {
1082 : 247 : fprintf (dump_file, " - Recording base_set=%i ref_set=%i ",
1083 : : base_set, ref_set);
1084 : 247 : a.dump (dump_file);
1085 : : }
1086 : 12369450 : tt->insert (current_function_decl, base_set, ref_set, a, false);
1087 : 12369450 : }
1088 : :
1089 : : /* IPA version of record_access_tree. */
1090 : :
1091 : : void
1092 : 163259 : modref_access_analysis::record_access_lto (modref_records_lto *tt, ao_ref *ref,
1093 : : modref_access_node &a)
1094 : : {
1095 : : /* get_alias_set sometimes use different type to compute the alias set
1096 : : than TREE_TYPE (base). Do same adjustments. */
1097 : 163259 : tree base_type = NULL_TREE, ref_type = NULL_TREE;
1098 : 163259 : if (flag_strict_aliasing && flag_ipa_strict_aliasing)
1099 : : {
1100 : 162785 : tree base;
1101 : :
1102 : 162785 : base = ref->ref;
1103 : 219578 : while (handled_component_p (base))
1104 : 56793 : base = TREE_OPERAND (base, 0);
1105 : :
1106 : 162785 : base_type = reference_alias_ptr_type_1 (&base);
1107 : :
1108 : 162785 : if (!base_type)
1109 : 161399 : base_type = TREE_TYPE (base);
1110 : : else
1111 : 1386 : base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
1112 : 1386 : ? NULL_TREE : TREE_TYPE (base_type);
1113 : :
1114 : 162785 : tree ref_expr = ref->ref;
1115 : 162785 : ref_type = reference_alias_ptr_type_1 (&ref_expr);
1116 : :
1117 : 162785 : if (!ref_type)
1118 : 161493 : ref_type = TREE_TYPE (ref_expr);
1119 : : else
1120 : 1292 : ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
1121 : 1292 : ? NULL_TREE : TREE_TYPE (ref_type);
1122 : :
1123 : : /* Sanity check that we are in sync with what get_alias_set does. */
1124 : 162785 : gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
1125 : : || get_alias_set (base_type)
1126 : : == ao_ref_base_alias_set (ref));
1127 : 162785 : gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
1128 : : || get_alias_set (ref_type)
1129 : : == ao_ref_alias_set (ref));
1130 : :
1131 : : /* Do not bother to record types that have no meaningful alias set.
1132 : : Also skip variably modified types since these go to local streams. */
1133 : 162785 : if (base_type && (!get_alias_set (base_type)
1134 : 152297 : || variably_modified_type_p (base_type, NULL_TREE)))
1135 : : base_type = NULL_TREE;
1136 : 162785 : if (ref_type && (!get_alias_set (ref_type)
1137 : 154161 : || variably_modified_type_p (ref_type, NULL_TREE)))
1138 : : ref_type = NULL_TREE;
1139 : : }
1140 : 163259 : if (dump_file)
1141 : : {
1142 : 28 : fprintf (dump_file, " - Recording base type:");
1143 : 28 : print_generic_expr (dump_file, base_type);
1144 : 56 : fprintf (dump_file, " (alias set %i) ref type:",
1145 : 28 : base_type ? get_alias_set (base_type) : 0);
1146 : 28 : print_generic_expr (dump_file, ref_type);
1147 : 56 : fprintf (dump_file, " (alias set %i) ",
1148 : 28 : ref_type ? get_alias_set (ref_type) : 0);
1149 : 28 : a.dump (dump_file);
1150 : : }
1151 : :
1152 : 163259 : tt->insert (current_function_decl, base_type, ref_type, a, false);
1153 : 163259 : }
1154 : :
1155 : : /* Returns true if and only if we should store the access to EXPR.
1156 : : Some accesses, e.g. loads from automatic variables, are not interesting. */
1157 : :
1158 : : bool
1159 : 25556331 : modref_access_analysis::record_access_p (tree expr)
1160 : : {
1161 : 25556331 : if (TREE_THIS_VOLATILE (expr)
1162 : 25556331 : && !ignore_nondeterminism_p (current_function_decl, 0, NULL))
1163 : : {
1164 : 900323 : if (dump_file)
1165 : 0 : fprintf (dump_file, " (volatile; marking nondeterministic) ");
1166 : 900323 : set_nondeterministic ();
1167 : : }
1168 : 25556331 : if (cfun->can_throw_non_call_exceptions
1169 : 25556331 : && tree_could_throw_p (expr))
1170 : : {
1171 : 1579908 : if (dump_file)
1172 : 0 : fprintf (dump_file, " (can throw; marking side effects) ");
1173 : 1579908 : set_side_effects ();
1174 : : }
1175 : :
1176 : 25556331 : if (refs_local_or_readonly_memory_p (expr))
1177 : : {
1178 : 12820157 : if (dump_file)
1179 : 57 : fprintf (dump_file, " - Read-only or local, ignoring.\n");
1180 : 12820157 : return false;
1181 : : }
1182 : : return true;
1183 : : }
1184 : :
1185 : : /* Collapse loads and return true if something changed. */
1186 : :
1187 : : bool
1188 : 2351530 : modref_access_analysis::record_unknown_load ()
1189 : : {
1190 : 2351530 : bool changed = false;
1191 : :
1192 : 2351530 : if (m_summary && !m_summary->loads->every_base)
1193 : : {
1194 : 916067 : m_summary->loads->collapse ();
1195 : 916067 : changed = true;
1196 : : }
1197 : 2351530 : if (m_summary_lto && !m_summary_lto->loads->every_base)
1198 : : {
1199 : 1777 : m_summary_lto->loads->collapse ();
1200 : 1777 : changed = true;
1201 : : }
1202 : 2351530 : return changed;
1203 : : }
1204 : :
1205 : : /* Collapse loads and return true if something changed. */
1206 : :
1207 : : bool
1208 : 2082534 : modref_access_analysis::record_unknown_store ()
1209 : : {
1210 : 2082534 : bool changed = false;
1211 : :
1212 : 2082534 : if (m_summary && !m_summary->stores->every_base)
1213 : : {
1214 : 969588 : m_summary->stores->collapse ();
1215 : 969588 : changed = true;
1216 : : }
1217 : 2082534 : if (m_summary_lto && !m_summary_lto->stores->every_base)
1218 : : {
1219 : 1691 : m_summary_lto->stores->collapse ();
1220 : 1691 : changed = true;
1221 : : }
1222 : 2082534 : return changed;
1223 : : }
1224 : :
1225 : : /* Record unknown load from global memory. */
1226 : :
1227 : : bool
1228 : 1126057 : modref_access_analysis::record_global_memory_load ()
1229 : : {
1230 : 1126057 : bool changed = false;
1231 : 1126057 : modref_access_node a = {0, -1, -1,
1232 : : 0, MODREF_GLOBAL_MEMORY_PARM, false, 0};
1233 : :
1234 : 1126057 : if (m_summary && !m_summary->loads->every_base)
1235 : 775534 : changed |= m_summary->loads->insert (current_function_decl, 0, 0, a, false);
1236 : 1126057 : if (m_summary_lto && !m_summary_lto->loads->every_base)
1237 : 461 : changed |= m_summary_lto->loads->insert (current_function_decl,
1238 : : 0, 0, a, false);
1239 : 1126057 : return changed;
1240 : : }
1241 : :
1242 : : /* Record unknown store from global memory. */
1243 : :
1244 : : bool
1245 : 764882 : modref_access_analysis::record_global_memory_store ()
1246 : : {
1247 : 764882 : bool changed = false;
1248 : 764882 : modref_access_node a = {0, -1, -1,
1249 : : 0, MODREF_GLOBAL_MEMORY_PARM, false, 0};
1250 : :
1251 : 764882 : if (m_summary && !m_summary->stores->every_base)
1252 : 567338 : changed |= m_summary->stores->insert (current_function_decl,
1253 : : 0, 0, a, false);
1254 : 764882 : if (m_summary_lto && !m_summary_lto->stores->every_base)
1255 : 336 : changed |= m_summary_lto->stores->insert (current_function_decl,
1256 : : 0, 0, a, false);
1257 : 764882 : return changed;
1258 : : }
1259 : :
1260 : : /* Merge side effects of call STMT to function with CALLEE_SUMMARY.
1261 : : Return true if something changed.
1262 : : If IGNORE_STORES is true, do not merge stores.
1263 : : If RECORD_ADJUSTMENTS is true cap number of adjustments to
1264 : : a given access to make dataflow finite. */
1265 : :
1266 : : bool
1267 : 1434816 : modref_access_analysis::merge_call_side_effects
1268 : : (gimple *stmt, modref_summary *callee_summary,
1269 : : cgraph_node *callee_node, bool record_adjustments)
1270 : : {
1271 : 1434816 : gcall *call = as_a <gcall *> (stmt);
1272 : 1434816 : int flags = gimple_call_flags (call);
1273 : :
1274 : : /* Nothing to do for non-looping cont functions. */
1275 : 1434816 : if ((flags & ECF_CONST)
1276 : : && !(flags & ECF_LOOPING_CONST_OR_PURE))
1277 : : return false;
1278 : :
1279 : 1434816 : bool changed = false;
1280 : :
1281 : 1434816 : if (dump_file)
1282 : 13 : fprintf (dump_file, " - Merging side effects of %s\n",
1283 : : callee_node->dump_name ());
1284 : :
1285 : : /* Merge side effects and non-determinism.
1286 : : PURE/CONST flags makes functions deterministic and if there is
1287 : : no LOOPING_CONST_OR_PURE they also have no side effects. */
1288 : 1434816 : if (!(flags & (ECF_CONST | ECF_PURE))
1289 : 127387 : || (flags & ECF_LOOPING_CONST_OR_PURE))
1290 : : {
1291 : 1351100 : if (!m_summary->side_effects && callee_summary->side_effects)
1292 : : {
1293 : 350656 : if (dump_file)
1294 : 0 : fprintf (dump_file, " - merging side effects.\n");
1295 : 350656 : m_summary->side_effects = true;
1296 : 350656 : changed = true;
1297 : : }
1298 : 882764 : if (!m_summary->nondeterministic && callee_summary->nondeterministic
1299 : 1693092 : && !ignore_nondeterminism_p (current_function_decl, flags,
1300 : : gimple_call_fntype (call)))
1301 : : {
1302 : 340456 : if (dump_file)
1303 : 0 : fprintf (dump_file, " - merging nondeterministic.\n");
1304 : 340456 : m_summary->nondeterministic = true;
1305 : 340456 : changed = true;
1306 : : }
1307 : : }
1308 : :
1309 : : /* For const functions we are done. */
1310 : 1434816 : if (flags & (ECF_CONST | ECF_NOVOPS))
1311 : : return changed;
1312 : :
1313 : : /* Merge calls_interposable flags. */
1314 : 1434351 : if (!m_summary->calls_interposable && callee_summary->calls_interposable)
1315 : : {
1316 : 161270 : if (dump_file)
1317 : 0 : fprintf (dump_file, " - merging calls interposable.\n");
1318 : 161270 : m_summary->calls_interposable = true;
1319 : 161270 : changed = true;
1320 : : }
1321 : :
1322 : 1434351 : if (!callee_node->binds_to_current_def_p () && !m_summary->calls_interposable)
1323 : : {
1324 : 142217 : if (dump_file)
1325 : 0 : fprintf (dump_file, " - May be interposed.\n");
1326 : 142217 : m_summary->calls_interposable = true;
1327 : 142217 : changed = true;
1328 : : }
1329 : :
1330 : : /* Now merge the actual load, store and kill vectors. For this we need
1331 : : to compute map translating new parameters to old. */
1332 : 1434351 : if (dump_file)
1333 : 13 : fprintf (dump_file, " Parm map:");
1334 : :
1335 : 1434351 : auto_vec <modref_parm_map, 32> parm_map;
1336 : 1434351 : parm_map.safe_grow_cleared (gimple_call_num_args (call), true);
1337 : 5051379 : for (unsigned i = 0; i < gimple_call_num_args (call); i++)
1338 : : {
1339 : 3617028 : parm_map[i] = parm_map_for_ptr (gimple_call_arg (call, i));
1340 : 3617028 : if (dump_file)
1341 : : {
1342 : 23 : fprintf (dump_file, " %i", parm_map[i].parm_index);
1343 : 23 : if (parm_map[i].parm_offset_known)
1344 : : {
1345 : 12 : fprintf (dump_file, " offset:");
1346 : 12 : print_dec ((poly_int64)parm_map[i].parm_offset,
1347 : : dump_file, SIGNED);
1348 : : }
1349 : : }
1350 : : }
1351 : :
1352 : 1434351 : modref_parm_map chain_map;
1353 : 1434351 : if (gimple_call_chain (call))
1354 : : {
1355 : 2466 : chain_map = parm_map_for_ptr (gimple_call_chain (call));
1356 : 2466 : if (dump_file)
1357 : : {
1358 : 0 : fprintf (dump_file, "static chain %i", chain_map.parm_index);
1359 : 0 : if (chain_map.parm_offset_known)
1360 : : {
1361 : 0 : fprintf (dump_file, " offset:");
1362 : 0 : print_dec ((poly_int64)chain_map.parm_offset,
1363 : : dump_file, SIGNED);
1364 : : }
1365 : : }
1366 : : }
1367 : 1434351 : if (dump_file)
1368 : 13 : fprintf (dump_file, "\n");
1369 : :
1370 : : /* Kills can me merged in only if we know the function is going to be
1371 : : always executed. */
1372 : 1434351 : if (m_always_executed
1373 : 586581 : && callee_summary->kills.length ()
1374 : 1505195 : && (!cfun->can_throw_non_call_exceptions
1375 : 75 : || !stmt_could_throw_p (cfun, call)))
1376 : : {
1377 : : /* Watch for self recursive updates. */
1378 : 70806 : auto_vec<modref_access_node, 32> saved_kills;
1379 : :
1380 : 141612 : saved_kills.reserve_exact (callee_summary->kills.length ());
1381 : 70806 : saved_kills.splice (callee_summary->kills);
1382 : 294337 : for (auto kill : saved_kills)
1383 : : {
1384 : 163838 : if (kill.parm_index >= (int)parm_map.length ())
1385 : 34782 : continue;
1386 : 81919 : modref_parm_map &m
1387 : : = kill.parm_index == MODREF_STATIC_CHAIN_PARM
1388 : 81919 : ? chain_map
1389 : 81487 : : parm_map[kill.parm_index];
1390 : 116701 : if (m.parm_index == MODREF_LOCAL_MEMORY_PARM
1391 : 81919 : || m.parm_index == MODREF_UNKNOWN_PARM
1392 : : || m.parm_index == MODREF_RETSLOT_PARM
1393 : 47165 : || !m.parm_offset_known)
1394 : 34782 : continue;
1395 : 47137 : modref_access_node n = kill;
1396 : 47137 : n.parm_index = m.parm_index;
1397 : 47137 : n.parm_offset += m.parm_offset;
1398 : 47137 : if (modref_access_node::insert_kill (m_summary->kills, n,
1399 : : record_adjustments))
1400 : 28052 : changed = true;
1401 : : }
1402 : 70806 : }
1403 : :
1404 : : /* Merge in loads. */
1405 : 4303053 : changed |= m_summary->loads->merge (current_function_decl,
1406 : : callee_summary->loads,
1407 : : &parm_map, &chain_map,
1408 : : record_adjustments,
1409 : 1434351 : !may_access_nonescaping_parm_p
1410 : 1434351 : (call, flags, true));
1411 : : /* Merge in stores. */
1412 : 1434351 : if (!ignore_stores_p (current_function_decl, flags))
1413 : : {
1414 : 3921039 : changed |= m_summary->stores->merge (current_function_decl,
1415 : : callee_summary->stores,
1416 : : &parm_map, &chain_map,
1417 : : record_adjustments,
1418 : 1307013 : !may_access_nonescaping_parm_p
1419 : 1307013 : (call, flags, false));
1420 : 1307013 : if (!m_summary->writes_errno
1421 : 1134410 : && callee_summary->writes_errno)
1422 : : {
1423 : 101887 : m_summary->writes_errno = true;
1424 : 101887 : changed = true;
1425 : : }
1426 : : }
1427 : 1434351 : return changed;
1428 : 1434351 : }
1429 : :
1430 : : /* Return access mode for argument I of call STMT with FNSPEC. */
1431 : :
1432 : : modref_access_node
1433 : 278648 : modref_access_analysis::get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
1434 : : unsigned int i,
1435 : : modref_parm_map &map)
1436 : : {
1437 : 278648 : tree size = NULL_TREE;
1438 : 278648 : unsigned int size_arg;
1439 : :
1440 : 278648 : if (!fnspec.arg_specified_p (i))
1441 : : ;
1442 : 278648 : else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
1443 : 59595 : size = gimple_call_arg (call, size_arg);
1444 : 219053 : else if (fnspec.arg_access_size_given_by_type_p (i))
1445 : : {
1446 : 33 : tree callee = gimple_call_fndecl (call);
1447 : 33 : tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
1448 : :
1449 : 82 : for (unsigned int p = 0; p < i; p++)
1450 : 49 : t = TREE_CHAIN (t);
1451 : 33 : size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
1452 : : }
1453 : 278648 : modref_access_node a = {0, -1, -1,
1454 : 278648 : map.parm_offset, map.parm_index,
1455 : 278648 : map.parm_offset_known, 0};
1456 : 278648 : poly_int64 size_hwi;
1457 : 278648 : if (size
1458 : 59628 : && poly_int_tree_p (size, &size_hwi)
1459 : 295423 : && coeffs_in_range_p (size_hwi, 0,
1460 : : HOST_WIDE_INT_MAX / BITS_PER_UNIT))
1461 : : {
1462 : 16553 : a.size = -1;
1463 : 16553 : a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
1464 : : }
1465 : 278648 : return a;
1466 : : }
1467 : :
1468 : : /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1469 : : If IGNORE_STORES is true ignore them.
1470 : : Return false if no useful summary can be produced. */
1471 : :
1472 : : void
1473 : 3843390 : modref_access_analysis::process_fnspec (gcall *call)
1474 : : {
1475 : 3843390 : int flags = gimple_call_flags (call);
1476 : :
1477 : : /* PURE/CONST flags makes functions deterministic and if there is
1478 : : no LOOPING_CONST_OR_PURE they also have no side effects. */
1479 : 3843390 : if (!(flags & (ECF_CONST | ECF_PURE))
1480 : 369865 : || (flags & ECF_LOOPING_CONST_OR_PURE)
1481 : 4201124 : || (cfun->can_throw_non_call_exceptions
1482 : 36066 : && stmt_could_throw_p (cfun, call)))
1483 : : {
1484 : 3486288 : set_side_effects ();
1485 : 6805063 : if (!ignore_nondeterminism_p (current_function_decl, flags,
1486 : : gimple_call_fntype (call)))
1487 : 3085481 : set_nondeterministic ();
1488 : : }
1489 : :
1490 : : /* For const functions we are done. */
1491 : 3843390 : if (flags & (ECF_CONST | ECF_NOVOPS))
1492 : 3349629 : return;
1493 : :
1494 : 3836620 : attr_fnspec fnspec = gimple_call_fnspec (call);
1495 : : /* If there is no fnpec we know nothing about loads & stores. */
1496 : 3836620 : if (!fnspec.known_p ())
1497 : : {
1498 : 3025961 : if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
1499 : 0 : fprintf (dump_file, " Builtin with no fnspec: %s\n",
1500 : 0 : IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
1501 : 3025961 : if (!ignore_stores_p (current_function_decl, flags))
1502 : : {
1503 : 2597165 : if (!may_access_nonescaping_parm_p (call, flags, false))
1504 : 737727 : record_global_memory_store ();
1505 : : else
1506 : 1859438 : record_unknown_store ();
1507 : 2597165 : if (!may_access_nonescaping_parm_p (call, flags, true))
1508 : 737727 : record_global_memory_load ();
1509 : : else
1510 : 1859438 : record_unknown_load ();
1511 : : }
1512 : : else
1513 : : {
1514 : 428796 : if (!may_access_nonescaping_parm_p (call, flags, true))
1515 : 350514 : record_global_memory_load ();
1516 : : else
1517 : 78282 : record_unknown_load ();
1518 : : }
1519 : 3025961 : return;
1520 : : }
1521 : : /* Process fnspec. */
1522 : 810659 : if (fnspec.global_memory_read_p ())
1523 : : {
1524 : 151434 : if (may_access_nonescaping_parm_p (call, flags, true))
1525 : 113618 : record_unknown_load ();
1526 : : else
1527 : 37816 : record_global_memory_load ();
1528 : : }
1529 : : else
1530 : : {
1531 : 1536096 : for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1532 : 1165209 : if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1533 : : ;
1534 : 822408 : else if (!fnspec.arg_specified_p (i)
1535 : 822408 : || fnspec.arg_maybe_read_p (i))
1536 : : {
1537 : 535517 : modref_parm_map map = parm_map_for_ptr
1538 : 535517 : (gimple_call_arg (call, i));
1539 : :
1540 : 535517 : if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
1541 : 34986 : continue;
1542 : 500531 : if (map.parm_index == MODREF_UNKNOWN_PARM)
1543 : : {
1544 : 288338 : record_unknown_load ();
1545 : 288338 : break;
1546 : : }
1547 : 212193 : modref_access_node a = get_access_for_fnspec (call, fnspec, i, map);
1548 : 212193 : if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1549 : 0 : continue;
1550 : 212193 : if (m_summary)
1551 : 212193 : m_summary->loads->insert (current_function_decl, 0, 0, a, false);
1552 : 212193 : if (m_summary_lto)
1553 : 0 : m_summary_lto->loads->insert (current_function_decl, 0, 0, a,
1554 : : false);
1555 : : }
1556 : : }
1557 : 810659 : if (ignore_stores_p (current_function_decl, flags))
1558 : : return;
1559 : 493761 : if (fnspec.global_memory_written_p ())
1560 : : {
1561 : 91898 : if (may_access_nonescaping_parm_p (call, flags, false))
1562 : 64743 : record_unknown_store ();
1563 : : else
1564 : 27155 : record_global_memory_store ();
1565 : : }
1566 : : else
1567 : : {
1568 : 857302 : for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
1569 : 601938 : if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
1570 : : ;
1571 : 348773 : else if (!fnspec.arg_specified_p (i)
1572 : 348773 : || fnspec.arg_maybe_written_p (i))
1573 : : {
1574 : 291432 : modref_parm_map map = parm_map_for_ptr
1575 : 291432 : (gimple_call_arg (call, i));
1576 : :
1577 : 291432 : if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
1578 : 78478 : continue;
1579 : 212954 : if (map.parm_index == MODREF_UNKNOWN_PARM)
1580 : : {
1581 : 146499 : record_unknown_store ();
1582 : 146499 : break;
1583 : : }
1584 : 66455 : modref_access_node a = get_access_for_fnspec (call, fnspec, i, map);
1585 : 66455 : if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1586 : 0 : continue;
1587 : 66455 : if (m_summary)
1588 : 66455 : m_summary->stores->insert (current_function_decl, 0, 0, a, false);
1589 : 66455 : if (m_summary_lto)
1590 : 0 : m_summary_lto->stores->insert (current_function_decl,
1591 : : 0, 0, a, false);
1592 : : }
1593 : 401863 : if (fnspec.errno_maybe_written_p () && flag_errno_math)
1594 : : {
1595 : 64169 : if (m_summary)
1596 : 64169 : m_summary->writes_errno = true;
1597 : 64169 : if (m_summary_lto)
1598 : 0 : m_summary_lto->writes_errno = true;
1599 : : }
1600 : : }
1601 : : }
1602 : :
1603 : : /* Analyze function call STMT in function F.
1604 : : Remember recursive calls in RECURSIVE_CALLS. */
1605 : :
1606 : : void
1607 : 5997782 : modref_access_analysis::analyze_call (gcall *stmt)
1608 : : {
1609 : : /* Check flags on the function call. In certain cases, analysis can be
1610 : : simplified. */
1611 : 5997782 : int flags = gimple_call_flags (stmt);
1612 : :
1613 : 5997782 : if (dump_file)
1614 : : {
1615 : 33 : fprintf (dump_file, " - Analyzing call:");
1616 : 33 : print_gimple_stmt (dump_file, stmt, 0);
1617 : : }
1618 : :
1619 : 5997782 : if ((flags & ECF_CONST)
1620 : : && !(flags & ECF_LOOPING_CONST_OR_PURE))
1621 : : {
1622 : 572443 : if (dump_file)
1623 : 0 : fprintf (dump_file,
1624 : : " - ECF_CONST, ignoring all stores and all loads "
1625 : : "except for args.\n");
1626 : 572443 : return;
1627 : : }
1628 : :
1629 : : /* Next, we try to get the callee's function declaration. The goal is to
1630 : : merge their summary with ours. */
1631 : 5425339 : tree callee = gimple_call_fndecl (stmt);
1632 : :
1633 : : /* Check if this is an indirect call. */
1634 : 5425339 : if (!callee)
1635 : : {
1636 : 367527 : if (dump_file)
1637 : 52 : fprintf (dump_file, gimple_call_internal_p (stmt)
1638 : : ? " - Internal call" : " - Indirect call.\n");
1639 : 367527 : process_fnspec (stmt);
1640 : 367527 : return;
1641 : : }
1642 : : /* We only need to handle internal calls in IPA mode. */
1643 : 5057812 : gcc_checking_assert (!m_summary_lto && !m_ipa);
1644 : :
1645 : 5057812 : struct cgraph_node *callee_node = cgraph_node::get_create (callee);
1646 : :
1647 : : /* If this is a recursive call, the target summary is the same as ours, so
1648 : : there's nothing to do. */
1649 : 5057812 : if (recursive_call_p (current_function_decl, callee))
1650 : : {
1651 : 10729 : m_recursive_calls.safe_push (stmt);
1652 : 10729 : set_side_effects ();
1653 : 10729 : if (dump_file)
1654 : 1 : fprintf (dump_file, " - Skipping recursive call.\n");
1655 : 10729 : return;
1656 : : }
1657 : :
1658 : 5047083 : gcc_assert (callee_node != NULL);
1659 : :
1660 : : /* Get the function symbol and its availability. */
1661 : 5047083 : enum availability avail;
1662 : 5047083 : callee_node = callee_node->function_symbol (&avail);
1663 : 5047083 : bool looping;
1664 : 5047083 : if (builtin_safe_for_const_function_p (&looping, callee))
1665 : : {
1666 : 147475 : if (looping)
1667 : 2711 : set_side_effects ();
1668 : 147475 : if (dump_file)
1669 : 0 : fprintf (dump_file, " - Builtin is safe for const.\n");
1670 : 147475 : return;
1671 : : }
1672 : 4899608 : if (avail <= AVAIL_INTERPOSABLE)
1673 : : {
1674 : 3071345 : if (dump_file)
1675 : 3 : fprintf (dump_file,
1676 : : " - Function availability <= AVAIL_INTERPOSABLE.\n");
1677 : 3071345 : process_fnspec (stmt);
1678 : 3071345 : return;
1679 : : }
1680 : :
1681 : : /* Get callee's modref summary. As above, if there's no summary, we either
1682 : : have to give up or, if stores are ignored, we can just purge loads. */
1683 : 1828263 : modref_summary *callee_summary = optimization_summaries->get (callee_node);
1684 : 1828263 : if (!callee_summary)
1685 : : {
1686 : 404518 : if (dump_file)
1687 : 0 : fprintf (dump_file, " - No modref summary available for callee.\n");
1688 : 404518 : process_fnspec (stmt);
1689 : 404518 : return;
1690 : : }
1691 : :
1692 : 1423745 : merge_call_side_effects (stmt, callee_summary, callee_node, false);
1693 : :
1694 : 1423745 : return;
1695 : : }
1696 : :
1697 : : /* Helper for analyze_stmt. */
1698 : :
1699 : : bool
1700 : 12869840 : modref_access_analysis::analyze_load (gimple *, tree, tree op, void *data)
1701 : : {
1702 : 12869840 : modref_access_analysis *t = (modref_access_analysis *)data;
1703 : :
1704 : 12869840 : if (dump_file)
1705 : : {
1706 : 220 : fprintf (dump_file, " - Analyzing load: ");
1707 : 220 : print_generic_expr (dump_file, op);
1708 : 220 : fprintf (dump_file, "\n");
1709 : : }
1710 : :
1711 : 12869840 : if (!t->record_access_p (op))
1712 : : return false;
1713 : :
1714 : 8367147 : ao_ref r;
1715 : 8367147 : ao_ref_init (&r, op);
1716 : 8367147 : modref_access_node a = get_access (&r);
1717 : 8367147 : if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1718 : : return false;
1719 : :
1720 : 8340378 : if (t->m_summary)
1721 : 8302972 : t->record_access (t->m_summary->loads, &r, a);
1722 : 8340378 : if (t->m_summary_lto)
1723 : 107795 : t->record_access_lto (t->m_summary_lto->loads, &r, a);
1724 : : return false;
1725 : : }
1726 : :
1727 : : /* Helper for analyze_stmt. */
1728 : :
1729 : : bool
1730 : 12140442 : modref_access_analysis::analyze_store (gimple *stmt, tree, tree op, void *data)
1731 : : {
1732 : 12140442 : modref_access_analysis *t = (modref_access_analysis *)data;
1733 : :
1734 : 12140442 : if (dump_file)
1735 : : {
1736 : 100 : fprintf (dump_file, " - Analyzing store: ");
1737 : 100 : print_generic_expr (dump_file, op);
1738 : 100 : fprintf (dump_file, "\n");
1739 : : }
1740 : :
1741 : 12140442 : if (!t->record_access_p (op))
1742 : : return false;
1743 : :
1744 : 4246554 : ao_ref r;
1745 : 4246554 : ao_ref_init (&r, op);
1746 : 4246554 : modref_access_node a = get_access (&r);
1747 : 4246554 : if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
1748 : : return false;
1749 : :
1750 : 4089713 : if (t->m_summary)
1751 : 4066478 : t->record_access (t->m_summary->stores, &r, a);
1752 : 4089713 : if (t->m_summary_lto)
1753 : 55464 : t->record_access_lto (t->m_summary_lto->stores, &r, a);
1754 : 4089713 : if (t->m_always_executed
1755 : 1883066 : && a.useful_for_kill_p ()
1756 : 5415666 : && (!cfun->can_throw_non_call_exceptions
1757 : 5830 : || !stmt_could_throw_p (cfun, stmt)))
1758 : : {
1759 : 1320679 : if (dump_file)
1760 : 21 : fprintf (dump_file, " - Recording kill\n");
1761 : 1320679 : if (t->m_summary)
1762 : 1318203 : modref_access_node::insert_kill (t->m_summary->kills, a, false);
1763 : 1320679 : if (t->m_summary_lto)
1764 : 5345 : modref_access_node::insert_kill (t->m_summary_lto->kills, a, false);
1765 : : }
1766 : : return false;
1767 : : }
1768 : :
1769 : : /* Analyze statement STMT of function F.
1770 : : If IPA is true do not merge in side effects of calls. */
1771 : :
1772 : : void
1773 : 64269996 : modref_access_analysis::analyze_stmt (gimple *stmt, bool always_executed)
1774 : : {
1775 : 64269996 : m_always_executed = always_executed;
1776 : : /* In general we can not ignore clobbers because they are barriers for code
1777 : : motion, however after inlining it is safe to do because local optimization
1778 : : passes do not consider clobbers from other functions.
1779 : : Similar logic is in ipa-pure-const.cc. */
1780 : 64269996 : if ((m_ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
1781 : : {
1782 : 1734775 : if (always_executed && record_access_p (gimple_assign_lhs (stmt)))
1783 : : {
1784 : 122473 : ao_ref r;
1785 : 122473 : ao_ref_init (&r, gimple_assign_lhs (stmt));
1786 : 122473 : modref_access_node a = get_access (&r);
1787 : 122473 : if (a.useful_for_kill_p ())
1788 : : {
1789 : 115000 : if (dump_file)
1790 : 0 : fprintf (dump_file, " - Recording kill\n");
1791 : 115000 : if (m_summary)
1792 : 114571 : modref_access_node::insert_kill (m_summary->kills, a, false);
1793 : 115000 : if (m_summary_lto)
1794 : 781 : modref_access_node::insert_kill (m_summary_lto->kills,
1795 : : a, false);
1796 : : }
1797 : : }
1798 : 1734775 : return;
1799 : : }
1800 : :
1801 : : /* Analyze all loads and stores in STMT. */
1802 : 62535221 : walk_stmt_load_store_ops (stmt, this,
1803 : : analyze_load, analyze_store);
1804 : :
1805 : 62535221 : switch (gimple_code (stmt))
1806 : : {
1807 : 134610 : case GIMPLE_ASM:
1808 : 134610 : if (gimple_asm_volatile_p (as_a <gasm *> (stmt))
1809 : 134610 : && !ignore_nondeterminism_p (current_function_decl, 0, NULL))
1810 : 115618 : set_nondeterministic ();
1811 : 134610 : if (cfun->can_throw_non_call_exceptions
1812 : 134610 : && stmt_could_throw_p (cfun, stmt))
1813 : 151 : set_side_effects ();
1814 : : /* If the ASM statement does not read nor write memory, there's nothing
1815 : : to do. Otherwise just give up. */
1816 : 134610 : if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
1817 : : return;
1818 : 11854 : if (dump_file)
1819 : 1 : fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
1820 : : "which clobbers memory.\n");
1821 : 11854 : record_unknown_load ();
1822 : 11854 : record_unknown_store ();
1823 : 11854 : return;
1824 : 10370276 : case GIMPLE_CALL:
1825 : 10370276 : if (!m_ipa || gimple_call_internal_p (stmt))
1826 : 5997782 : analyze_call (as_a <gcall *> (stmt));
1827 : : else
1828 : : {
1829 : 4372494 : attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
1830 : :
1831 : 4372494 : if (fnspec.known_p ()
1832 : 4372494 : && (!fnspec.global_memory_read_p ()
1833 : 281100 : || !fnspec.global_memory_written_p ()))
1834 : : {
1835 : 491510 : cgraph_edge *e = cgraph_node::get
1836 : 491510 : (current_function_decl)->get_edge (stmt);
1837 : 491510 : if (e->callee)
1838 : : {
1839 : 491506 : fnspec_summaries->get_create (e)->fnspec
1840 : 491506 : = xstrdup (fnspec.get_str ());
1841 : 491506 : if (dump_file)
1842 : 2 : fprintf (dump_file, " Recorded fnspec %s\n",
1843 : : fnspec.get_str ());
1844 : : }
1845 : : }
1846 : : }
1847 : : return;
1848 : 52030335 : default:
1849 : 52030335 : if (cfun->can_throw_non_call_exceptions
1850 : 52030335 : && stmt_could_throw_p (cfun, stmt))
1851 : 1556682 : set_side_effects ();
1852 : : return;
1853 : : }
1854 : : }
1855 : :
1856 : : /* Propagate load/stores across recursive calls. */
1857 : :
1858 : : void
1859 : 2231794 : modref_access_analysis::propagate ()
1860 : : {
1861 : 2231794 : if (m_ipa && m_summary)
1862 : : return;
1863 : :
1864 : 2231794 : bool changed = true;
1865 : 2231794 : bool first = true;
1866 : 2231794 : cgraph_node *fnode = cgraph_node::get (current_function_decl);
1867 : :
1868 : 2231794 : m_always_executed = false;
1869 : 4465010 : while (changed && m_summary->useful_p (m_ecf_flags, false))
1870 : : {
1871 : : changed = false;
1872 : 6709081 : for (unsigned i = 0; i < m_recursive_calls.length (); i++)
1873 : : {
1874 : 11071 : changed |= merge_call_side_effects (m_recursive_calls[i], m_summary,
1875 : 11071 : fnode, !first);
1876 : : }
1877 : : first = false;
1878 : : }
1879 : : }
1880 : :
1881 : : /* Analyze function. */
1882 : :
1883 : : void
1884 : 4483289 : modref_access_analysis::analyze ()
1885 : : {
1886 : 4483289 : m_ecf_flags = flags_from_decl_or_type (current_function_decl);
1887 : 4483289 : bool summary_useful = true;
1888 : :
1889 : : /* Analyze each statement in each basic block of the function. If the
1890 : : statement cannot be analyzed (for any reason), the entire function cannot
1891 : : be analyzed by modref. */
1892 : 4483289 : basic_block bb;
1893 : 4483289 : bitmap always_executed_bbs = find_always_executed_bbs (cfun, true);
1894 : 26253510 : FOR_EACH_BB_FN (bb, cfun)
1895 : : {
1896 : 22899582 : gimple_stmt_iterator si;
1897 : 22899582 : bool always_executed = bitmap_bit_p (always_executed_bbs, bb->index);
1898 : :
1899 : 22899582 : for (si = gsi_start_nondebug_after_labels_bb (bb);
1900 : 86040217 : !gsi_end_p (si); gsi_next_nondebug (&si))
1901 : : {
1902 : : /* NULL memory accesses terminates BB. These accesses are known
1903 : : to trip undefined behavior. gimple-ssa-isolate-paths turns them
1904 : : to volatile accesses and adds builtin_trap call which would
1905 : : confuse us otherwise. */
1906 : 64271790 : if (infer_nonnull_range_by_dereference (gsi_stmt (si),
1907 : : null_pointer_node))
1908 : : {
1909 : 1794 : if (dump_file)
1910 : 0 : fprintf (dump_file, " - NULL memory access; terminating BB\n");
1911 : 1794 : if (flag_non_call_exceptions)
1912 : 268 : set_side_effects ();
1913 : : break;
1914 : : }
1915 : 64269996 : analyze_stmt (gsi_stmt (si), always_executed);
1916 : :
1917 : : /* Avoid doing useless work. */
1918 : 63856539 : if ((!m_summary || !m_summary->useful_p (m_ecf_flags, false))
1919 : 65395278 : && (!m_summary_lto
1920 : 418070 : || !m_summary_lto->useful_p (m_ecf_flags, false)))
1921 : : {
1922 : : summary_useful = false;
1923 : : break;
1924 : : }
1925 : 63140635 : if (always_executed
1926 : 63140635 : && stmt_can_throw_external (cfun, gsi_stmt (si)))
1927 : : always_executed = false;
1928 : : }
1929 : 22899582 : if (!summary_useful)
1930 : : break;
1931 : : }
1932 : : /* In non-IPA mode we need to perform iterative dataflow on recursive calls.
1933 : : This needs to be done after all other side effects are computed. */
1934 : 4483289 : if (summary_useful)
1935 : : {
1936 : 3353928 : if (!m_ipa)
1937 : 2231794 : propagate ();
1938 : 3353928 : if (m_summary && !m_summary->side_effects && !finite_function_p ())
1939 : 48927 : m_summary->side_effects = true;
1940 : 81280 : if (m_summary_lto && !m_summary_lto->side_effects
1941 : 3430221 : && !finite_function_p ())
1942 : 2977 : m_summary_lto->side_effects = true;
1943 : : }
1944 : 4483289 : BITMAP_FREE (always_executed_bbs);
1945 : 4483289 : }
1946 : :
1947 : : /* Return true if OP accesses memory pointed to by SSA_NAME. */
1948 : :
1949 : : bool
1950 : 21399530 : memory_access_to (tree op, tree ssa_name)
1951 : : {
1952 : 21399530 : tree base = get_base_address (op);
1953 : 21399530 : if (!base)
1954 : : return false;
1955 : 21399530 : if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
1956 : : return false;
1957 : 8381315 : return TREE_OPERAND (base, 0) == ssa_name;
1958 : : }
1959 : :
1960 : : /* Consider statement val = *arg.
1961 : : return EAF flags of ARG that can be determined from EAF flags of VAL
1962 : : (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1963 : : all stores to VAL, i.e. when handling noreturn function. */
1964 : :
1965 : : static int
1966 : 7650989 : deref_flags (int flags, bool ignore_stores)
1967 : : {
1968 : : /* Dereference is also a direct read but dereferenced value does not
1969 : : yield any other direct use. */
1970 : 7957792 : int ret = EAF_NO_DIRECT_CLOBBER | EAF_NO_DIRECT_ESCAPE
1971 : : | EAF_NOT_RETURNED_DIRECTLY;
1972 : : /* If argument is unused just account for
1973 : : the read involved in dereference. */
1974 : 7650989 : if (flags & EAF_UNUSED)
1975 : : ret |= EAF_NO_INDIRECT_READ | EAF_NO_INDIRECT_CLOBBER
1976 : : | EAF_NO_INDIRECT_ESCAPE;
1977 : : else
1978 : : {
1979 : : /* Direct or indirect accesses leads to indirect accesses. */
1980 : 7612941 : if (((flags & EAF_NO_DIRECT_CLOBBER)
1981 : : && (flags & EAF_NO_INDIRECT_CLOBBER))
1982 : 3867934 : || ignore_stores)
1983 : 3771331 : ret |= EAF_NO_INDIRECT_CLOBBER;
1984 : 7612941 : if (((flags & EAF_NO_DIRECT_ESCAPE)
1985 : : && (flags & EAF_NO_INDIRECT_ESCAPE))
1986 : 3467543 : || ignore_stores)
1987 : 4171720 : ret |= EAF_NO_INDIRECT_ESCAPE;
1988 : 7612941 : if ((flags & EAF_NO_DIRECT_READ)
1989 : : && (flags & EAF_NO_INDIRECT_READ))
1990 : 3425867 : ret |= EAF_NO_INDIRECT_READ;
1991 : 7612941 : if ((flags & EAF_NOT_RETURNED_DIRECTLY)
1992 : : && (flags & EAF_NOT_RETURNED_INDIRECTLY))
1993 : 2661181 : ret |= EAF_NOT_RETURNED_INDIRECTLY;
1994 : : }
1995 : 7650989 : return ret;
1996 : : }
1997 : :
1998 : :
1999 : : /* Description of an escape point: a call which affects flags of a given
2000 : : SSA name. */
2001 : :
2002 : : struct escape_point
2003 : : {
2004 : : /* Value escapes to this call. */
2005 : : gcall *call;
2006 : : /* Argument it escapes to. */
2007 : : unsigned int arg;
2008 : : /* Flags already known about the argument (this can save us from recording
2009 : : escape points if local analysis did good job already). */
2010 : : eaf_flags_t min_flags;
2011 : : /* Does value escape directly or indirectly? */
2012 : : bool direct;
2013 : : };
2014 : :
2015 : : /* Lattice used during the eaf flags analysis dataflow. For a given SSA name
2016 : : we aim to compute its flags and escape points. We also use the lattice
2017 : : to dynamically build dataflow graph to propagate on. */
2018 : :
2019 : : class modref_lattice
2020 : : {
2021 : : public:
2022 : : /* EAF flags of the SSA name. */
2023 : : eaf_flags_t flags;
2024 : : /* Used during DFS walk to mark names where final value was determined
2025 : : without need for dataflow. */
2026 : : bool known;
2027 : : /* Used during DFS walk to mark open vertices (for cycle detection). */
2028 : : bool open;
2029 : : /* Set during DFS walk for names that needs dataflow propagation. */
2030 : : bool do_dataflow;
2031 : : /* Used during the iterative dataflow. */
2032 : : bool changed;
2033 : :
2034 : : /* When doing IPA analysis we can not merge in callee escape points;
2035 : : Only remember them and do the merging at IPA propagation time. */
2036 : : vec <escape_point, va_heap, vl_ptr> escape_points;
2037 : :
2038 : : /* Representation of a graph for dataflow. This graph is built on-demand
2039 : : using modref_eaf_analysis::analyze_ssa and later solved by
2040 : : modref_eaf_analysis::propagate.
2041 : : Each edge represents the fact that flags of current lattice should be
2042 : : propagated to lattice of SSA_NAME. */
2043 : : struct propagate_edge
2044 : : {
2045 : : int ssa_name;
2046 : : bool deref;
2047 : : };
2048 : : vec <propagate_edge, va_heap, vl_ptr> propagate_to;
2049 : :
2050 : : void init ();
2051 : : void release ();
2052 : : bool merge (const modref_lattice &with);
2053 : : bool merge (int flags);
2054 : : bool merge_deref (const modref_lattice &with, bool ignore_stores);
2055 : : bool merge_direct_load ();
2056 : : bool merge_direct_store ();
2057 : : bool add_escape_point (gcall *call, unsigned int arg,
2058 : : eaf_flags_t min_flags, bool direct);
2059 : : void dump (FILE *out, int indent = 0) const;
2060 : : };
2061 : :
2062 : : /* Lattices are saved to vectors, so keep them PODs. */
2063 : : void
2064 : 21531592 : modref_lattice::init ()
2065 : : {
2066 : : /* All flags we track. */
2067 : 21531592 : int f = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
2068 : : | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE
2069 : : | EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ
2070 : : | EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY
2071 : : | EAF_UNUSED;
2072 : 21531592 : flags = f;
2073 : : /* Check that eaf_flags_t is wide enough to hold all flags. */
2074 : 21531592 : gcc_checking_assert (f == flags);
2075 : 21531592 : open = true;
2076 : 21531592 : known = false;
2077 : 0 : }
2078 : :
2079 : : /* Release memory. */
2080 : : void
2081 : 39838967 : modref_lattice::release ()
2082 : : {
2083 : 0 : escape_points.release ();
2084 : 39838967 : propagate_to.release ();
2085 : 0 : }
2086 : :
2087 : : /* Dump lattice to OUT; indent with INDENT spaces. */
2088 : :
2089 : : void
2090 : 2620 : modref_lattice::dump (FILE *out, int indent) const
2091 : : {
2092 : 2620 : dump_eaf_flags (out, flags);
2093 : 2620 : if (escape_points.length ())
2094 : : {
2095 : 37 : fprintf (out, "%*sEscapes:\n", indent, "");
2096 : 76 : for (unsigned int i = 0; i < escape_points.length (); i++)
2097 : : {
2098 : 117 : fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
2099 : 39 : escape_points[i].arg,
2100 : 39 : escape_points[i].direct ? "direct" : "indirect");
2101 : 39 : dump_eaf_flags (out, escape_points[i].min_flags, false);
2102 : 39 : fprintf (out, " in call ");
2103 : 39 : print_gimple_stmt (out, escape_points[i].call, 0);
2104 : : }
2105 : : }
2106 : 2620 : }
2107 : :
2108 : : /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
2109 : : point exists. */
2110 : :
2111 : : bool
2112 : 1881778 : modref_lattice::add_escape_point (gcall *call, unsigned arg,
2113 : : eaf_flags_t min_flags, bool direct)
2114 : : {
2115 : 1881778 : escape_point *ep;
2116 : 1881778 : unsigned int i;
2117 : :
2118 : : /* If we already determined flags to be bad enough,
2119 : : we do not need to record. */
2120 : 1881778 : if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
2121 : : return false;
2122 : :
2123 : 4027218 : FOR_EACH_VEC_ELT (escape_points, i, ep)
2124 : 3412529 : if (ep->call == call && ep->arg == arg && ep->direct == direct)
2125 : : {
2126 : 54982 : if ((ep->min_flags & min_flags) == min_flags)
2127 : : return false;
2128 : 0 : ep->min_flags &= min_flags;
2129 : 0 : return true;
2130 : : }
2131 : : /* Give up if max escape points is met. */
2132 : 767253 : if ((int)escape_points.length () > param_modref_max_escape_points)
2133 : : {
2134 : 0 : if (dump_file)
2135 : 0 : fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
2136 : 0 : merge (0);
2137 : 0 : return true;
2138 : : }
2139 : 614689 : escape_point new_ep = {call, arg, min_flags, direct};
2140 : 614689 : escape_points.safe_push (new_ep);
2141 : 614689 : return true;
2142 : : }
2143 : :
2144 : : /* Merge in flags from F. */
2145 : : bool
2146 : 66004673 : modref_lattice::merge (int f)
2147 : : {
2148 : 66004673 : if (f & EAF_UNUSED)
2149 : : return false;
2150 : : /* Check that flags seems sane: if function does not read the parameter
2151 : : it can not access it indirectly. */
2152 : 65995545 : gcc_checking_assert (!(f & EAF_NO_DIRECT_READ)
2153 : : || ((f & EAF_NO_INDIRECT_READ)
2154 : : && (f & EAF_NO_INDIRECT_CLOBBER)
2155 : : && (f & EAF_NO_INDIRECT_ESCAPE)
2156 : : && (f & EAF_NOT_RETURNED_INDIRECTLY)));
2157 : 65995545 : if ((flags & f) != flags)
2158 : : {
2159 : 41516253 : flags &= f;
2160 : : /* Prune obviously useless flags;
2161 : : We do not have ECF_FLAGS handy which is not big problem since
2162 : : we will do final flags cleanup before producing summary.
2163 : : Merging should be fast so it can work well with dataflow. */
2164 : 41516253 : flags = remove_useless_eaf_flags (flags, 0, false);
2165 : 41516253 : if (!flags)
2166 : 7873720 : escape_points.release ();
2167 : 41516253 : return true;
2168 : : }
2169 : : return false;
2170 : : }
2171 : :
2172 : : /* Merge in WITH. Return true if anything changed. */
2173 : :
2174 : : bool
2175 : 14507176 : modref_lattice::merge (const modref_lattice &with)
2176 : : {
2177 : 14507176 : if (!with.known)
2178 : 2235333 : do_dataflow = true;
2179 : :
2180 : 14507176 : bool changed = merge (with.flags);
2181 : :
2182 : 14507176 : if (!flags)
2183 : : return changed;
2184 : 11056538 : for (unsigned int i = 0; i < with.escape_points.length (); i++)
2185 : 241490 : changed |= add_escape_point (with.escape_points[i].call,
2186 : 241490 : with.escape_points[i].arg,
2187 : 241490 : with.escape_points[i].min_flags,
2188 : 241490 : with.escape_points[i].direct);
2189 : : return changed;
2190 : : }
2191 : :
2192 : : /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
2193 : : stores. Return true if anything changed. */
2194 : :
2195 : : bool
2196 : 7363779 : modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
2197 : : {
2198 : 7363779 : if (!with.known)
2199 : 338076 : do_dataflow = true;
2200 : :
2201 : 7363779 : bool changed = merge (deref_flags (with.flags, ignore_stores));
2202 : :
2203 : 7363779 : if (!flags)
2204 : : return changed;
2205 : 7135637 : for (unsigned int i = 0; i < with.escape_points.length (); i++)
2206 : : {
2207 : 138731 : int min_flags = with.escape_points[i].min_flags;
2208 : :
2209 : 138731 : if (with.escape_points[i].direct)
2210 : 116378 : min_flags = deref_flags (min_flags, ignore_stores);
2211 : 22353 : else if (ignore_stores)
2212 : 0 : min_flags |= ignore_stores_eaf_flags;
2213 : 138731 : changed |= add_escape_point (with.escape_points[i].call,
2214 : 138731 : with.escape_points[i].arg,
2215 : : min_flags,
2216 : : false);
2217 : : }
2218 : : return changed;
2219 : : }
2220 : :
2221 : : /* Merge in flags for direct load. */
2222 : :
2223 : : bool
2224 : 152 : modref_lattice::merge_direct_load ()
2225 : : {
2226 : 0 : return merge (~(EAF_UNUSED | EAF_NO_DIRECT_READ));
2227 : : }
2228 : :
2229 : : /* Merge in flags for direct store. */
2230 : :
2231 : : bool
2232 : 2676463 : modref_lattice::merge_direct_store ()
2233 : : {
2234 : 0 : return merge (~(EAF_UNUSED | EAF_NO_DIRECT_CLOBBER));
2235 : : }
2236 : :
2237 : : /* Analyzer of EAF flags.
2238 : : This is generally dataflow problem over the SSA graph, however we only
2239 : : care about flags of few selected ssa names (arguments, return slot and
2240 : : static chain). So we first call analyze_ssa_name on all relevant names
2241 : : and perform a DFS walk to discover SSA names where flags needs to be
2242 : : determined. For acyclic graphs we try to determine final flags during
2243 : : this walk. Once cycles or recursion depth is met we enlist SSA names
2244 : : for dataflow which is done by propagate call.
2245 : :
2246 : : After propagation the flags can be obtained using get_ssa_name_flags. */
2247 : :
2248 : : class modref_eaf_analysis
2249 : : {
2250 : : public:
2251 : : /* Mark NAME as relevant for analysis. */
2252 : : void analyze_ssa_name (tree name, bool deferred = false);
2253 : : /* Dataflow solver. */
2254 : : void propagate ();
2255 : : /* Return flags computed earlier for NAME. */
2256 : 6435284 : int get_ssa_name_flags (tree name)
2257 : : {
2258 : 6435284 : int version = SSA_NAME_VERSION (name);
2259 : 6435284 : gcc_checking_assert (m_lattice[version].known);
2260 : 6435284 : return m_lattice[version].flags;
2261 : : }
2262 : : /* In IPA mode this will record all escape points
2263 : : determined for NAME to PARM_IDNEX. Flags are minimal
2264 : : flags known. */
2265 : : void record_escape_points (tree name, int parm_index, int flags);
2266 : 3800754 : modref_eaf_analysis (bool ipa)
2267 : 3800754 : {
2268 : 3800754 : m_ipa = ipa;
2269 : 3800754 : m_depth = 0;
2270 : 7601508 : m_lattice.safe_grow_cleared (num_ssa_names, true);
2271 : 3800754 : }
2272 : 3800754 : ~modref_eaf_analysis ()
2273 : : {
2274 : 3800754 : gcc_checking_assert (!m_depth);
2275 : 3800754 : if (m_ipa || m_names_to_propagate.length ())
2276 : 40993860 : for (unsigned int i = 0; i < num_ssa_names; i++)
2277 : 79677934 : m_lattice[i].release ();
2278 : 3800754 : }
2279 : : private:
2280 : : /* If true, we produce analysis for IPA mode. In this case escape points are
2281 : : collected. */
2282 : : bool m_ipa;
2283 : : /* Depth of recursion of analyze_ssa_name. */
2284 : : int m_depth;
2285 : : /* Propagation lattice for individual ssa names. */
2286 : : auto_vec<modref_lattice> m_lattice;
2287 : : auto_vec<tree> m_deferred_names;
2288 : : auto_vec<int> m_names_to_propagate;
2289 : :
2290 : : void merge_with_ssa_name (tree dest, tree src, bool deref);
2291 : : void merge_call_lhs_flags (gcall *call, int arg, tree name, bool direct,
2292 : : bool deref);
2293 : : };
2294 : :
2295 : :
2296 : : /* Call statements may return their parameters. Consider argument number
2297 : : ARG of USE_STMT and determine flags that can needs to be cleared
2298 : : in case pointer possibly indirectly references from ARG I is returned.
2299 : : If DIRECT is true consider direct returns and if INDIRECT consider
2300 : : indirect returns.
2301 : : LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
2302 : : ARG is set to -1 for static chain. */
2303 : :
2304 : : void
2305 : 5365209 : modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg,
2306 : : tree name, bool direct,
2307 : : bool indirect)
2308 : : {
2309 : 5365209 : int index = SSA_NAME_VERSION (name);
2310 : 5365209 : bool returned_directly = false;
2311 : :
2312 : : /* If there is no return value, no flags are affected. */
2313 : 5365209 : if (!gimple_call_lhs (call))
2314 : : return;
2315 : :
2316 : : /* If we know that function returns given argument and it is not ARG
2317 : : we can still be happy. */
2318 : 2922066 : if (arg >= 0)
2319 : : {
2320 : 2914720 : int flags = gimple_call_return_flags (call);
2321 : 2914720 : if (flags & ERF_RETURNS_ARG)
2322 : : {
2323 : 18820 : if ((flags & ERF_RETURN_ARG_MASK) == arg)
2324 : : returned_directly = true;
2325 : : else
2326 : : return;
2327 : : }
2328 : : }
2329 : : /* Make ERF_RETURNS_ARG overwrite EAF_UNUSED. */
2330 : : if (returned_directly)
2331 : : {
2332 : : direct = true;
2333 : : indirect = false;
2334 : : }
2335 : : /* If value is not returned at all, do nothing. */
2336 : 2903246 : else if (!direct && !indirect)
2337 : : return;
2338 : :
2339 : : /* If return value is SSA name determine its flags. */
2340 : 2702265 : if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
2341 : : {
2342 : 2363343 : tree lhs = gimple_call_lhs (call);
2343 : 2363343 : if (direct)
2344 : 2224225 : merge_with_ssa_name (name, lhs, false);
2345 : 2363343 : if (indirect)
2346 : 1919987 : merge_with_ssa_name (name, lhs, true);
2347 : : }
2348 : : /* In the case of memory store we can do nothing. */
2349 : 338922 : else if (!direct)
2350 : 105012 : m_lattice[index].merge (deref_flags (0, false));
2351 : : else
2352 : 233910 : m_lattice[index].merge (0);
2353 : : }
2354 : :
2355 : : /* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
2356 : : into flags for caller, update LATTICE of corresponding
2357 : : argument if needed. */
2358 : :
2359 : : static int
2360 : 4748331 : callee_to_caller_flags (int call_flags, bool ignore_stores,
2361 : : modref_lattice &lattice)
2362 : : {
2363 : : /* call_flags is about callee returning a value
2364 : : that is not the same as caller returning it. */
2365 : 4748331 : call_flags |= EAF_NOT_RETURNED_DIRECTLY
2366 : : | EAF_NOT_RETURNED_INDIRECTLY;
2367 : 4748331 : if (!ignore_stores && !(call_flags & EAF_UNUSED))
2368 : : {
2369 : : /* If value escapes we are no longer able to track what happens
2370 : : with it because we can read it from the escaped location
2371 : : anytime. */
2372 : 4071578 : if (!(call_flags & EAF_NO_DIRECT_ESCAPE))
2373 : 3065783 : lattice.merge (0);
2374 : 1005795 : else if (!(call_flags & EAF_NO_INDIRECT_ESCAPE))
2375 : 466620 : lattice.merge (~(EAF_NOT_RETURNED_INDIRECTLY
2376 : : | EAF_NO_DIRECT_READ
2377 : : | EAF_NO_INDIRECT_READ
2378 : : | EAF_NO_INDIRECT_CLOBBER
2379 : : | EAF_UNUSED));
2380 : : }
2381 : : else
2382 : 676753 : call_flags |= ignore_stores_eaf_flags;
2383 : 4748331 : return call_flags;
2384 : : }
2385 : :
2386 : : /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
2387 : : LATTICE is an array of modref_lattices.
2388 : : DEPTH is a recursion depth used to make debug output prettier.
2389 : : If IPA is true we analyze for IPA propagation (and thus call escape points
2390 : : are processed later) */
2391 : :
2392 : : void
2393 : 25939768 : modref_eaf_analysis::analyze_ssa_name (tree name, bool deferred)
2394 : : {
2395 : 25939768 : imm_use_iterator ui;
2396 : 25939768 : gimple *use_stmt;
2397 : 25939768 : int index = SSA_NAME_VERSION (name);
2398 : :
2399 : 25939768 : if (!deferred)
2400 : : {
2401 : : /* See if value is already computed. */
2402 : 25937022 : if (m_lattice[index].known || m_lattice[index].do_dataflow)
2403 : 4408176 : return;
2404 : 21900372 : if (m_lattice[index].open)
2405 : : {
2406 : 368780 : if (dump_file)
2407 : 41 : fprintf (dump_file,
2408 : : "%*sCycle in SSA graph\n",
2409 : 41 : m_depth * 4, "");
2410 : 368780 : return;
2411 : : }
2412 : : /* Recursion guard. */
2413 : 21531592 : m_lattice[index].init ();
2414 : 21531592 : if (m_depth == param_modref_max_depth)
2415 : : {
2416 : 2746 : if (dump_file)
2417 : 0 : fprintf (dump_file,
2418 : : "%*sMax recursion depth reached; postponing\n",
2419 : : m_depth * 4, "");
2420 : 2746 : m_deferred_names.safe_push (name);
2421 : 2746 : return;
2422 : : }
2423 : : }
2424 : :
2425 : 21531592 : if (dump_file)
2426 : : {
2427 : 1139 : fprintf (dump_file,
2428 : 1139 : "%*sAnalyzing flags of ssa name: ", m_depth * 4, "");
2429 : 1139 : print_generic_expr (dump_file, name);
2430 : 1139 : fprintf (dump_file, "\n");
2431 : : }
2432 : :
2433 : 58501934 : FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
2434 : : {
2435 : 39833864 : if (m_lattice[index].flags == 0)
2436 : : break;
2437 : 36970342 : if (is_gimple_debug (use_stmt))
2438 : 5813392 : continue;
2439 : 31156950 : if (dump_file)
2440 : : {
2441 : 1477 : fprintf (dump_file, "%*s Analyzing stmt: ", m_depth * 4, "");
2442 : 1477 : print_gimple_stmt (dump_file, use_stmt, 0);
2443 : : }
2444 : : /* If we see a direct non-debug use, clear unused bit.
2445 : : All dereferences should be accounted below using deref_flags. */
2446 : 31156950 : m_lattice[index].merge (~EAF_UNUSED);
2447 : :
2448 : : /* Gimple return may load the return value.
2449 : : Returning name counts as an use by tree-ssa-structalias.cc */
2450 : 31156950 : if (greturn *ret = dyn_cast <greturn *> (use_stmt))
2451 : : {
2452 : : /* Returning through return slot is seen as memory write earlier. */
2453 : 1213763 : if (DECL_RESULT (current_function_decl)
2454 : 1213763 : && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2455 : : ;
2456 : 1169682 : else if (gimple_return_retval (ret) == name)
2457 : 1169682 : m_lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED_DIRECTLY
2458 : : | EAF_NOT_RETURNED_DIRECTLY));
2459 : 0 : else if (memory_access_to (gimple_return_retval (ret), name))
2460 : : {
2461 : 0 : m_lattice[index].merge_direct_load ();
2462 : 0 : m_lattice[index].merge (~(EAF_UNUSED
2463 : : | EAF_NOT_RETURNED_INDIRECTLY));
2464 : : }
2465 : : }
2466 : : /* Account for LHS store, arg loads and flags from callee function. */
2467 : 29943187 : else if (gcall *call = dyn_cast <gcall *> (use_stmt))
2468 : : {
2469 : 5493414 : tree callee = gimple_call_fndecl (call);
2470 : :
2471 : : /* IPA PTA internally it treats calling a function as "writing" to
2472 : : the argument space of all functions the function pointer points to
2473 : : (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
2474 : : is on since that would allow propagation of this from -fno-ipa-pta
2475 : : to -fipa-pta functions. */
2476 : 5493414 : if (gimple_call_fn (use_stmt) == name)
2477 : 54014 : m_lattice[index].merge (~(EAF_NO_DIRECT_CLOBBER | EAF_UNUSED));
2478 : :
2479 : : /* Recursion would require bit of propagation; give up for now. */
2480 : 5493414 : if (callee && !m_ipa && recursive_call_p (current_function_decl,
2481 : : callee))
2482 : 13022 : m_lattice[index].merge (0);
2483 : : else
2484 : : {
2485 : 5480392 : int ecf_flags = gimple_call_flags (call);
2486 : 5480392 : bool ignore_stores = ignore_stores_p (current_function_decl,
2487 : : ecf_flags);
2488 : 5480392 : bool ignore_retval = ignore_retval_p (current_function_decl,
2489 : : ecf_flags);
2490 : :
2491 : : /* Handle *name = func (...). */
2492 : 5480392 : if (gimple_call_lhs (call)
2493 : 5480392 : && memory_access_to (gimple_call_lhs (call), name))
2494 : : {
2495 : 16297 : m_lattice[index].merge_direct_store ();
2496 : : /* Return slot optimization passes address of
2497 : : LHS to callee via hidden parameter and this
2498 : : may make LHS to escape. See PR 98499. */
2499 : 16297 : if (gimple_call_return_slot_opt_p (call)
2500 : 16297 : && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
2501 : : {
2502 : 12607 : int call_flags = gimple_call_retslot_flags (call);
2503 : 12607 : bool isretslot = false;
2504 : :
2505 : 12607 : if (DECL_RESULT (current_function_decl)
2506 : 12607 : && DECL_BY_REFERENCE
2507 : : (DECL_RESULT (current_function_decl)))
2508 : 23964 : isretslot = ssa_default_def
2509 : 11982 : (cfun,
2510 : 11982 : DECL_RESULT (current_function_decl))
2511 : : == name;
2512 : :
2513 : : /* Passing returnslot to return slot is special because
2514 : : not_returned and escape has same meaning.
2515 : : However passing arg to return slot is different. If
2516 : : the callee's return slot is returned it means that
2517 : : arg is written to itself which is an escape.
2518 : : Since we do not track the memory it is written to we
2519 : : need to give up on analyzing it. */
2520 : 11982 : if (!isretslot)
2521 : : {
2522 : 625 : if (!(call_flags & (EAF_NOT_RETURNED_DIRECTLY
2523 : : | EAF_UNUSED)))
2524 : 455 : m_lattice[index].merge (0);
2525 : 170 : else gcc_checking_assert
2526 : : (call_flags & (EAF_NOT_RETURNED_INDIRECTLY
2527 : : | EAF_UNUSED));
2528 : 625 : call_flags = callee_to_caller_flags
2529 : 625 : (call_flags, false,
2530 : : m_lattice[index]);
2531 : : }
2532 : 12607 : m_lattice[index].merge (call_flags);
2533 : : }
2534 : : }
2535 : :
2536 : 5480392 : if (gimple_call_chain (call)
2537 : 5480392 : && (gimple_call_chain (call) == name))
2538 : : {
2539 : 27680 : int call_flags = gimple_call_static_chain_flags (call);
2540 : 27680 : if (!ignore_retval && !(call_flags & EAF_UNUSED))
2541 : 27680 : merge_call_lhs_flags
2542 : 27680 : (call, -1, name,
2543 : 27680 : !(call_flags & EAF_NOT_RETURNED_DIRECTLY),
2544 : 27680 : !(call_flags & EAF_NOT_RETURNED_INDIRECTLY));
2545 : 27680 : call_flags = callee_to_caller_flags
2546 : 27680 : (call_flags, ignore_stores,
2547 : : m_lattice[index]);
2548 : 27680 : if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2549 : 27680 : m_lattice[index].merge (call_flags);
2550 : : }
2551 : :
2552 : : /* Process internal functions and right away. */
2553 : 5480392 : bool record_ipa = m_ipa && !gimple_call_internal_p (call);
2554 : :
2555 : : /* Handle all function parameters. */
2556 : 20748073 : for (unsigned i = 0;
2557 : 20748073 : i < gimple_call_num_args (call)
2558 : 20748073 : && m_lattice[index].flags; i++)
2559 : : /* Name is directly passed to the callee. */
2560 : 15267681 : if (gimple_call_arg (call, i) == name)
2561 : : {
2562 : 5319335 : int call_flags = gimple_call_arg_flags (call, i);
2563 : 5319335 : if (!ignore_retval)
2564 : 5277435 : merge_call_lhs_flags
2565 : 5277435 : (call, i, name,
2566 : 5277435 : !(call_flags & (EAF_NOT_RETURNED_DIRECTLY
2567 : : | EAF_UNUSED)),
2568 : 5277435 : !(call_flags & (EAF_NOT_RETURNED_INDIRECTLY
2569 : : | EAF_UNUSED)));
2570 : 5319335 : if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
2571 : : {
2572 : 4660062 : call_flags = callee_to_caller_flags
2573 : 4660062 : (call_flags, ignore_stores,
2574 : : m_lattice[index]);
2575 : 4660062 : if (!record_ipa)
2576 : 3179551 : m_lattice[index].merge (call_flags);
2577 : : else
2578 : 1480511 : m_lattice[index].add_escape_point (call, i,
2579 : : call_flags, true);
2580 : : }
2581 : : }
2582 : : /* Name is dereferenced and passed to a callee. */
2583 : 9948346 : else if (memory_access_to (gimple_call_arg (call, i), name))
2584 : : {
2585 : 60116 : int call_flags = deref_flags
2586 : 60116 : (gimple_call_arg_flags (call, i), ignore_stores);
2587 : 60116 : if (!ignore_retval && !(call_flags & EAF_UNUSED)
2588 : 60094 : && (call_flags & (EAF_NOT_RETURNED_DIRECTLY
2589 : : | EAF_NOT_RETURNED_INDIRECTLY))
2590 : : != (EAF_NOT_RETURNED_DIRECTLY
2591 : : | EAF_NOT_RETURNED_INDIRECTLY))
2592 : 60094 : merge_call_lhs_flags (call, i, name, false, true);
2593 : 60116 : if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
2594 : 152 : m_lattice[index].merge_direct_load ();
2595 : : else
2596 : : {
2597 : 59964 : call_flags = callee_to_caller_flags
2598 : 59964 : (call_flags, ignore_stores,
2599 : : m_lattice[index]);
2600 : 59964 : if (!record_ipa)
2601 : 38918 : m_lattice[index].merge (call_flags);
2602 : : else
2603 : 21046 : m_lattice[index].add_escape_point (call, i,
2604 : : call_flags, false);
2605 : : }
2606 : : }
2607 : : }
2608 : : }
2609 : 24449773 : else if (gimple_assign_load_p (use_stmt))
2610 : : {
2611 : 5525386 : gassign *assign = as_a <gassign *> (use_stmt);
2612 : : /* Memory to memory copy. */
2613 : 5525386 : if (gimple_store_p (assign))
2614 : : {
2615 : : /* Handle *lhs = *name.
2616 : :
2617 : : We do not track memory locations, so assume that value
2618 : : is used arbitrarily. */
2619 : 296043 : if (memory_access_to (gimple_assign_rhs1 (assign), name))
2620 : 201791 : m_lattice[index].merge (deref_flags (0, false));
2621 : :
2622 : : /* Handle *name = *exp. */
2623 : 296043 : if (memory_access_to (gimple_assign_lhs (assign), name))
2624 : 93435 : m_lattice[index].merge_direct_store ();
2625 : : }
2626 : : /* Handle lhs = *name. */
2627 : 5229343 : else if (memory_access_to (gimple_assign_rhs1 (assign), name))
2628 : : {
2629 : 5094650 : tree lhs = gimple_assign_lhs (assign);
2630 : 5094650 : merge_with_ssa_name (name, lhs, true);
2631 : : }
2632 : : }
2633 : 18924387 : else if (gimple_store_p (use_stmt))
2634 : : {
2635 : 4337595 : gassign *assign = dyn_cast <gassign *> (use_stmt);
2636 : :
2637 : : /* Handle *lhs = name. */
2638 : 4337595 : if (assign && gimple_assign_rhs1 (assign) == name)
2639 : : {
2640 : 1664810 : if (dump_file)
2641 : 63 : fprintf (dump_file, "%*s ssa name saved to memory\n",
2642 : 63 : m_depth * 4, "");
2643 : 1664810 : m_lattice[index].merge (0);
2644 : : }
2645 : : /* Handle *name = exp. */
2646 : 2672785 : else if (assign
2647 : 2672785 : && memory_access_to (gimple_assign_lhs (assign), name))
2648 : : {
2649 : : /* In general we can not ignore clobbers because they are
2650 : : barriers for code motion, however after inlining it is safe to
2651 : : do because local optimization passes do not consider clobbers
2652 : : from other functions.
2653 : : Similar logic is in ipa-pure-const.cc. */
2654 : 2612692 : if (!cfun->after_inlining || !gimple_clobber_p (assign))
2655 : 2566731 : m_lattice[index].merge_direct_store ();
2656 : : }
2657 : : /* ASM statements etc. */
2658 : 60093 : else if (!assign)
2659 : : {
2660 : 0 : if (dump_file)
2661 : 0 : fprintf (dump_file, "%*s Unhandled store\n", m_depth * 4, "");
2662 : 0 : m_lattice[index].merge (0);
2663 : : }
2664 : : }
2665 : 14586792 : else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
2666 : : {
2667 : 9295645 : enum tree_code code = gimple_assign_rhs_code (assign);
2668 : :
2669 : : /* See if operation is a merge as considered by
2670 : : tree-ssa-structalias.cc:find_func_aliases. */
2671 : 9295645 : if (!truth_value_p (code)
2672 : 8762053 : && code != POINTER_DIFF_EXPR
2673 : 17853743 : && (code != POINTER_PLUS_EXPR
2674 : 1238743 : || gimple_assign_rhs1 (assign) == name))
2675 : : {
2676 : 8127276 : tree lhs = gimple_assign_lhs (assign);
2677 : 8127276 : merge_with_ssa_name (name, lhs, false);
2678 : : }
2679 : : }
2680 : 5291147 : else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
2681 : : {
2682 : 1889392 : tree result = gimple_phi_result (phi);
2683 : 1889392 : merge_with_ssa_name (name, result, false);
2684 : : }
2685 : : /* Conditions are not considered escape points
2686 : : by tree-ssa-structalias. */
2687 : 3401755 : else if (gimple_code (use_stmt) == GIMPLE_COND)
2688 : : ;
2689 : : else
2690 : : {
2691 : 66298 : if (dump_file)
2692 : 6 : fprintf (dump_file, "%*s Unhandled stmt\n", m_depth * 4, "");
2693 : 66298 : m_lattice[index].merge (0);
2694 : : }
2695 : :
2696 : 31156950 : if (dump_file)
2697 : : {
2698 : 1477 : fprintf (dump_file, "%*s current flags of ", m_depth * 4, "");
2699 : 1477 : print_generic_expr (dump_file, name);
2700 : 1477 : m_lattice[index].dump (dump_file, m_depth * 4 + 4);
2701 : : }
2702 : 21531592 : }
2703 : 21531592 : if (dump_file)
2704 : : {
2705 : 1139 : fprintf (dump_file, "%*sflags of ssa name ", m_depth * 4, "");
2706 : 1139 : print_generic_expr (dump_file, name);
2707 : 1139 : m_lattice[index].dump (dump_file, m_depth * 4 + 2);
2708 : : }
2709 : 21531592 : m_lattice[index].open = false;
2710 : 21531592 : if (!m_lattice[index].do_dataflow)
2711 : 19448513 : m_lattice[index].known = true;
2712 : : }
2713 : :
2714 : : /* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
2715 : : is dereferenced. */
2716 : :
2717 : : void
2718 : 19255530 : modref_eaf_analysis::merge_with_ssa_name (tree dest, tree src, bool deref)
2719 : : {
2720 : 19255530 : int index = SSA_NAME_VERSION (dest);
2721 : 19255530 : int src_index = SSA_NAME_VERSION (src);
2722 : :
2723 : : /* Merging lattice with itself is a no-op. */
2724 : 19255530 : if (!deref && src == dest)
2725 : 26 : return;
2726 : :
2727 : 19255504 : m_depth++;
2728 : 19255504 : analyze_ssa_name (src);
2729 : 19255504 : m_depth--;
2730 : 19255504 : if (deref)
2731 : 7014637 : m_lattice[index].merge_deref (m_lattice[src_index], false);
2732 : : else
2733 : 12240867 : m_lattice[index].merge (m_lattice[src_index]);
2734 : :
2735 : : /* If we failed to produce final solution add an edge to the dataflow
2736 : : graph. */
2737 : 19255504 : if (!m_lattice[src_index].known)
2738 : : {
2739 : 2573409 : modref_lattice::propagate_edge e = {index, deref};
2740 : :
2741 : 2573409 : if (!m_lattice[src_index].propagate_to.length ())
2742 : 1855240 : m_names_to_propagate.safe_push (src_index);
2743 : 2573409 : m_lattice[src_index].propagate_to.safe_push (e);
2744 : 2573409 : m_lattice[src_index].changed = true;
2745 : 2573409 : m_lattice[src_index].do_dataflow = true;
2746 : 2573409 : if (dump_file)
2747 : 135 : fprintf (dump_file,
2748 : : "%*sWill propgate from ssa_name %i to %i%s\n",
2749 : 135 : m_depth * 4 + 4,
2750 : : "", src_index, index, deref ? " (deref)" : "");
2751 : : }
2752 : : }
2753 : :
2754 : : /* In the case we deferred some SSA names, reprocess them. In the case some
2755 : : dataflow edges were introduced, do the actual iterative dataflow. */
2756 : :
2757 : : void
2758 : 3800754 : modref_eaf_analysis::propagate ()
2759 : : {
2760 : 3800754 : int iterations = 0;
2761 : 3800754 : size_t i;
2762 : 3800754 : int index;
2763 : 3800754 : bool changed = true;
2764 : :
2765 : 3803500 : while (m_deferred_names.length ())
2766 : : {
2767 : 2746 : tree name = m_deferred_names.pop ();
2768 : 2746 : if (dump_file)
2769 : 0 : fprintf (dump_file, "Analyzing deferred SSA name\n");
2770 : 2746 : analyze_ssa_name (name, true);
2771 : : }
2772 : :
2773 : 3800754 : if (!m_names_to_propagate.length ())
2774 : 3635895 : return;
2775 : 164859 : if (dump_file)
2776 : 41 : fprintf (dump_file, "Propagating EAF flags\n");
2777 : :
2778 : : /* Compute reverse postorder. */
2779 : 164859 : auto_vec <int> rpo;
2780 : 164859 : struct stack_entry
2781 : : {
2782 : : int name;
2783 : : unsigned pos;
2784 : : };
2785 : 164859 : auto_vec <struct stack_entry> stack;
2786 : 164859 : int pos = m_names_to_propagate.length () - 1;
2787 : :
2788 : 164859 : rpo.safe_grow (m_names_to_propagate.length (), true);
2789 : 329718 : stack.reserve_exact (m_names_to_propagate.length ());
2790 : :
2791 : : /* We reuse known flag for RPO DFS walk bookkeeping. */
2792 : 164859 : if (flag_checking)
2793 : 2020009 : FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2794 : 1855165 : gcc_assert (!m_lattice[index].known && m_lattice[index].changed);
2795 : :
2796 : 2020099 : FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
2797 : : {
2798 : 1855240 : if (!m_lattice[index].known)
2799 : : {
2800 : 325306 : stack_entry e = {index, 0};
2801 : :
2802 : 325306 : stack.quick_push (e);
2803 : 325306 : m_lattice[index].known = true;
2804 : : }
2805 : 5240414 : while (stack.length ())
2806 : : {
2807 : 3385174 : bool found = false;
2808 : 3385174 : int index1 = stack.last ().name;
2809 : :
2810 : 4428649 : while (stack.last ().pos < m_lattice[index1].propagate_to.length ())
2811 : : {
2812 : 2573409 : int index2 = m_lattice[index1]
2813 : 2573409 : .propagate_to[stack.last ().pos].ssa_name;
2814 : :
2815 : 2573409 : stack.last ().pos++;
2816 : 2573409 : if (!m_lattice[index2].known
2817 : 3616884 : && m_lattice[index2].propagate_to.length ())
2818 : : {
2819 : 1529934 : stack_entry e = {index2, 0};
2820 : :
2821 : 1529934 : stack.quick_push (e);
2822 : 1529934 : m_lattice[index2].known = true;
2823 : 1529934 : found = true;
2824 : 1529934 : break;
2825 : : }
2826 : : }
2827 : 1529934 : if (!found
2828 : 3710480 : && stack.last ().pos == m_lattice[index1].propagate_to.length ())
2829 : : {
2830 : 1855240 : rpo[pos--] = index1;
2831 : 1855240 : stack.pop ();
2832 : : }
2833 : : }
2834 : : }
2835 : :
2836 : : /* Perform iterative dataflow. */
2837 : 419386 : while (changed)
2838 : : {
2839 : 254527 : changed = false;
2840 : 254527 : iterations++;
2841 : 254527 : if (dump_file)
2842 : 43 : fprintf (dump_file, " iteration %i\n", iterations);
2843 : 3822138 : FOR_EACH_VEC_ELT (rpo, i, index)
2844 : : {
2845 : 3148225 : if (m_lattice[index].changed)
2846 : : {
2847 : 1882838 : size_t j;
2848 : :
2849 : 1882838 : m_lattice[index].changed = false;
2850 : 1882838 : if (dump_file)
2851 : 96 : fprintf (dump_file, " Visiting ssa name %i\n", index);
2852 : 5763676 : for (j = 0; j < m_lattice[index].propagate_to.length (); j++)
2853 : : {
2854 : 2615451 : bool ch;
2855 : 2615451 : int target = m_lattice[index].propagate_to[j].ssa_name;
2856 : 2615451 : bool deref = m_lattice[index].propagate_to[j].deref;
2857 : :
2858 : 2615451 : if (dump_file)
2859 : 274 : fprintf (dump_file, " Propagating flags of ssa name"
2860 : : " %i to %i%s\n",
2861 : : index, target, deref ? " (deref)" : "");
2862 : 2615451 : m_lattice[target].known = true;
2863 : 2615451 : if (!m_lattice[index].propagate_to[j].deref)
2864 : 2266309 : ch = m_lattice[target].merge (m_lattice[index]);
2865 : : else
2866 : 349142 : ch = m_lattice[target].merge_deref (m_lattice[index],
2867 : : false);
2868 : 2615451 : if (!ch)
2869 : 2324917 : continue;
2870 : 290534 : if (dump_file)
2871 : : {
2872 : 4 : fprintf (dump_file, " New lattice: ");
2873 : 4 : m_lattice[target].dump (dump_file);
2874 : : }
2875 : 290534 : changed = true;
2876 : 290534 : m_lattice[target].changed = true;
2877 : : }
2878 : : }
2879 : : }
2880 : : }
2881 : 164859 : if (dump_file)
2882 : 41 : fprintf (dump_file, "EAF flags propagated in %i iterations\n", iterations);
2883 : 164859 : }
2884 : :
2885 : : /* Record escape points of PARM_INDEX according to LATTICE. */
2886 : :
2887 : : void
2888 : 3153419 : modref_eaf_analysis::record_escape_points (tree name, int parm_index, int flags)
2889 : : {
2890 : 3153419 : modref_lattice &lattice = m_lattice[SSA_NAME_VERSION (name)];
2891 : :
2892 : 3153419 : if (lattice.escape_points.length ())
2893 : : {
2894 : 170517 : escape_point *ep;
2895 : 170517 : unsigned int ip;
2896 : 170517 : cgraph_node *node = cgraph_node::get (current_function_decl);
2897 : :
2898 : 170517 : gcc_assert (m_ipa);
2899 : 439668 : FOR_EACH_VEC_ELT (lattice.escape_points, ip, ep)
2900 : 269151 : if ((ep->min_flags & flags) != flags)
2901 : : {
2902 : 234796 : cgraph_edge *e = node->get_edge (ep->call);
2903 : 234796 : struct escape_entry ee = {parm_index, ep->arg,
2904 : 234796 : ep->min_flags, ep->direct};
2905 : :
2906 : 234796 : escape_summaries->get_create (e)->esc.safe_push (ee);
2907 : : }
2908 : : }
2909 : 3153419 : }
2910 : :
2911 : : /* Determine EAF flags for function parameters
2912 : : and fill in SUMMARY/SUMMARY_LTO. If IPA is true work in IPA mode
2913 : : where we also collect escape points.
2914 : : PAST_FLAGS, PAST_RETSLOT_FLAGS, PAST_STATIC_CHAIN_FLAGS can be
2915 : : used to preserve flags from previous (IPA) run for cases where
2916 : : late optimizations changed code in a way we can no longer analyze
2917 : : it easily. */
2918 : :
2919 : : static void
2920 : 4483289 : analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
2921 : : bool ipa, vec<eaf_flags_t> &past_flags,
2922 : : int past_retslot_flags, int past_static_chain_flags)
2923 : : {
2924 : 4483289 : unsigned int parm_index = 0;
2925 : 4483289 : unsigned int count = 0;
2926 : 4483289 : int ecf_flags = flags_from_decl_or_type (current_function_decl);
2927 : 4483289 : tree retslot = NULL;
2928 : 4483289 : tree static_chain = NULL;
2929 : :
2930 : : /* If there is return slot, look up its SSA name. */
2931 : 4483289 : if (DECL_RESULT (current_function_decl)
2932 : 4483289 : && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
2933 : 56954 : retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
2934 : 4483289 : if (cfun->static_chain_decl)
2935 : 48716 : static_chain = ssa_default_def (cfun, cfun->static_chain_decl);
2936 : :
2937 : 14188113 : for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2938 : 9704824 : parm = TREE_CHAIN (parm))
2939 : 9704824 : count++;
2940 : :
2941 : 4483289 : if (!count && !retslot && !static_chain)
2942 : 682535 : return;
2943 : :
2944 : 3800754 : modref_eaf_analysis eaf_analysis (ipa);
2945 : :
2946 : : /* Determine all SSA names we need to know flags for. */
2947 : 13505578 : for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
2948 : 9704824 : parm = TREE_CHAIN (parm))
2949 : : {
2950 : 9704824 : tree name = ssa_default_def (cfun, parm);
2951 : 9704824 : if (name)
2952 : 6576239 : eaf_analysis.analyze_ssa_name (name);
2953 : : }
2954 : 3800754 : if (retslot)
2955 : 56767 : eaf_analysis.analyze_ssa_name (retslot);
2956 : 3800754 : if (static_chain)
2957 : 48512 : eaf_analysis.analyze_ssa_name (static_chain);
2958 : :
2959 : : /* Do the dataflow. */
2960 : 3800754 : eaf_analysis.propagate ();
2961 : :
2962 : 3800754 : tree attr = lookup_attribute ("fn spec",
2963 : 3800754 : TYPE_ATTRIBUTES
2964 : : (TREE_TYPE (current_function_decl)));
2965 : 3800754 : attr_fnspec fnspec (attr
2966 : 100559 : ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)))
2967 : 3901313 : : "");
2968 : :
2969 : :
2970 : : /* Store results to summaries. */
2971 : 13505578 : for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
2972 : 9704824 : parm = TREE_CHAIN (parm))
2973 : : {
2974 : 9704824 : tree name = ssa_default_def (cfun, parm);
2975 : 9704824 : if (!name || has_zero_uses (name))
2976 : : {
2977 : : /* We do not track non-SSA parameters,
2978 : : but we want to track unused gimple_regs. */
2979 : 3374819 : if (!is_gimple_reg (parm))
2980 : 618280 : continue;
2981 : 2756539 : if (summary)
2982 : : {
2983 : 2648227 : if (parm_index >= summary->arg_flags.length ())
2984 : 599527 : summary->arg_flags.safe_grow_cleared (count, true);
2985 : 2648227 : summary->arg_flags[parm_index] = EAF_UNUSED;
2986 : : }
2987 : 2756539 : if (summary_lto)
2988 : : {
2989 : 217856 : if (parm_index >= summary_lto->arg_flags.length ())
2990 : 9639 : summary_lto->arg_flags.safe_grow_cleared (count, true);
2991 : 217856 : summary_lto->arg_flags[parm_index] = EAF_UNUSED;
2992 : : }
2993 : 2756539 : continue;
2994 : : }
2995 : 6330005 : int flags = eaf_analysis.get_ssa_name_flags (name);
2996 : 6330005 : int attr_flags = fnspec.arg_eaf_flags (parm_index);
2997 : :
2998 : 6330005 : if (dump_file && (flags | attr_flags) != flags && !(flags & EAF_UNUSED))
2999 : : {
3000 : 0 : fprintf (dump_file,
3001 : : " Flags for param %i combined with fnspec flags:",
3002 : : (int)parm_index);
3003 : 0 : dump_eaf_flags (dump_file, attr_flags, false);
3004 : 0 : fprintf (dump_file, " determined: ");
3005 : 0 : dump_eaf_flags (dump_file, flags, true);
3006 : : }
3007 : 6330005 : flags |= attr_flags;
3008 : :
3009 : : /* Eliminate useless flags so we do not end up storing unnecessary
3010 : : summaries. */
3011 : :
3012 : 6330005 : flags = remove_useless_eaf_flags
3013 : 6330005 : (flags, ecf_flags,
3014 : 6330005 : VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3015 : 6330005 : if (past_flags.length () > parm_index)
3016 : : {
3017 : 663799 : int past = past_flags[parm_index];
3018 : 663799 : past = remove_useless_eaf_flags
3019 : 663799 : (past, ecf_flags,
3020 : 663799 : VOID_TYPE_P (TREE_TYPE
3021 : : (TREE_TYPE (current_function_decl))));
3022 : : /* Store merging can produce reads when combining together multiple
3023 : : bitfields. See PR111613. */
3024 : 663799 : past &= ~(EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ);
3025 : 663799 : if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
3026 : : {
3027 : 24 : fprintf (dump_file,
3028 : : " Flags for param %i combined with IPA pass:",
3029 : : (int)parm_index);
3030 : 24 : dump_eaf_flags (dump_file, past, false);
3031 : 24 : fprintf (dump_file, " determined: ");
3032 : 24 : dump_eaf_flags (dump_file, flags, true);
3033 : : }
3034 : 663799 : if (!(flags & EAF_UNUSED))
3035 : 663799 : flags |= past;
3036 : : }
3037 : :
3038 : 6330005 : if (flags)
3039 : : {
3040 : 3067071 : if (summary)
3041 : : {
3042 : 3040351 : if (parm_index >= summary->arg_flags.length ())
3043 : 1917201 : summary->arg_flags.safe_grow_cleared (count, true);
3044 : 3040351 : summary->arg_flags[parm_index] = flags;
3045 : : }
3046 : 3067071 : if (summary_lto)
3047 : : {
3048 : 60688 : if (parm_index >= summary_lto->arg_flags.length ())
3049 : 42793 : summary_lto->arg_flags.safe_grow_cleared (count, true);
3050 : 60688 : summary_lto->arg_flags[parm_index] = flags;
3051 : : }
3052 : 3067071 : eaf_analysis.record_escape_points (name, parm_index, flags);
3053 : : }
3054 : : }
3055 : 3800754 : if (retslot)
3056 : : {
3057 : 56767 : int flags = eaf_analysis.get_ssa_name_flags (retslot);
3058 : 56767 : int past = past_retslot_flags;
3059 : :
3060 : 56767 : flags = remove_useless_eaf_flags (flags, ecf_flags, false);
3061 : 56767 : past = remove_useless_eaf_flags
3062 : 56767 : (past, ecf_flags,
3063 : 56767 : VOID_TYPE_P (TREE_TYPE
3064 : : (TREE_TYPE (current_function_decl))));
3065 : 56767 : if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
3066 : : {
3067 : 0 : fprintf (dump_file,
3068 : : " Retslot flags combined with IPA pass:");
3069 : 0 : dump_eaf_flags (dump_file, past, false);
3070 : 0 : fprintf (dump_file, " determined: ");
3071 : 0 : dump_eaf_flags (dump_file, flags, true);
3072 : : }
3073 : 56767 : if (!(flags & EAF_UNUSED))
3074 : 56684 : flags |= past;
3075 : 56684 : if (flags)
3076 : : {
3077 : 39396 : if (summary)
3078 : 39254 : summary->retslot_flags = flags;
3079 : 39396 : if (summary_lto)
3080 : 284 : summary_lto->retslot_flags = flags;
3081 : 39396 : eaf_analysis.record_escape_points (retslot,
3082 : : MODREF_RETSLOT_PARM, flags);
3083 : : }
3084 : : }
3085 : 3800754 : if (static_chain)
3086 : : {
3087 : 48512 : int flags = eaf_analysis.get_ssa_name_flags (static_chain);
3088 : 48512 : int past = past_static_chain_flags;
3089 : :
3090 : 48512 : flags = remove_useless_eaf_flags (flags, ecf_flags, false);
3091 : 48512 : past = remove_useless_eaf_flags
3092 : 48512 : (past, ecf_flags,
3093 : 48512 : VOID_TYPE_P (TREE_TYPE
3094 : : (TREE_TYPE (current_function_decl))));
3095 : 48512 : if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
3096 : : {
3097 : 0 : fprintf (dump_file,
3098 : : " Static chain flags combined with IPA pass:");
3099 : 0 : dump_eaf_flags (dump_file, past, false);
3100 : 0 : fprintf (dump_file, " determined: ");
3101 : 0 : dump_eaf_flags (dump_file, flags, true);
3102 : : }
3103 : 48512 : if (!(flags & EAF_UNUSED))
3104 : 48428 : flags |= past;
3105 : 48428 : if (flags)
3106 : : {
3107 : 46952 : if (summary)
3108 : 46877 : summary->static_chain_flags = flags;
3109 : 46952 : if (summary_lto)
3110 : 153 : summary_lto->static_chain_flags = flags;
3111 : 46952 : eaf_analysis.record_escape_points (static_chain,
3112 : : MODREF_STATIC_CHAIN_PARM,
3113 : : flags);
3114 : : }
3115 : : }
3116 : 3800754 : }
3117 : :
3118 : : /* Analyze function. IPA indicates whether we're running in local mode
3119 : : (false) or the IPA mode (true).
3120 : : Return true if fixup cfg is needed after the pass. */
3121 : :
3122 : : static bool
3123 : 4958882 : analyze_function (bool ipa)
3124 : : {
3125 : 4958882 : bool fixup_cfg = false;
3126 : 4958882 : if (dump_file)
3127 : 188 : fprintf (dump_file, "\n\nmodref analyzing '%s' (ipa=%i)%s%s\n",
3128 : 188 : cgraph_node::get (current_function_decl)->dump_name (), ipa,
3129 : 188 : TREE_READONLY (current_function_decl) ? " (const)" : "",
3130 : 188 : DECL_PURE_P (current_function_decl) ? " (pure)" : "");
3131 : :
3132 : : /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
3133 : 4958882 : if (!flag_ipa_modref
3134 : 4958882 : || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
3135 : 475593 : return false;
3136 : :
3137 : : /* Compute no-LTO summaries when local optimization is going to happen. */
3138 : 1268988 : bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
3139 : 4523702 : || (in_lto_p && !flag_wpa
3140 : 883 : && flag_incremental_link != INCREMENTAL_LINK_LTO));
3141 : : /* Compute LTO when LTO streaming is going to happen. */
3142 : 1268988 : bool lto = ipa && ((flag_lto && !in_lto_p)
3143 : 1179089 : || flag_wpa
3144 : 1179016 : || flag_incremental_link == INCREMENTAL_LINK_LTO);
3145 : 4483289 : cgraph_node *fnode = cgraph_node::get (current_function_decl);
3146 : :
3147 : 4483289 : modref_summary *summary = NULL;
3148 : 4483289 : modref_summary_lto *summary_lto = NULL;
3149 : :
3150 : 4483289 : bool past_flags_known = false;
3151 : 4483289 : auto_vec <eaf_flags_t> past_flags;
3152 : 4483289 : int past_retslot_flags = 0;
3153 : 4483289 : int past_static_chain_flags = 0;
3154 : :
3155 : : /* Initialize the summary.
3156 : : If we run in local mode there is possibly pre-existing summary from
3157 : : IPA pass. Dump it so it is easy to compare if mod-ref info has
3158 : : improved. */
3159 : 4483289 : if (!ipa)
3160 : : {
3161 : 3214301 : if (!optimization_summaries)
3162 : 137405 : optimization_summaries = modref_summaries::create_ggc (symtab);
3163 : : else /* Remove existing summary if we are re-running the pass. */
3164 : : {
3165 : 3076896 : summary = optimization_summaries->get (fnode);
3166 : 3076896 : if (summary != NULL
3167 : 707954 : && summary->loads)
3168 : : {
3169 : 707954 : if (dump_file)
3170 : : {
3171 : 23 : fprintf (dump_file, "Past summary:\n");
3172 : 23 : optimization_summaries->get (fnode)->dump (dump_file);
3173 : : }
3174 : 1136216 : past_flags.reserve_exact (summary->arg_flags.length ());
3175 : 707954 : past_flags.splice (summary->arg_flags);
3176 : 707954 : past_retslot_flags = summary->retslot_flags;
3177 : 707954 : past_static_chain_flags = summary->static_chain_flags;
3178 : 707954 : past_flags_known = true;
3179 : : }
3180 : 3076896 : optimization_summaries->remove (fnode);
3181 : : }
3182 : 3214301 : summary = optimization_summaries->get_create (fnode);
3183 : 3214301 : gcc_checking_assert (nolto && !lto);
3184 : : }
3185 : : /* In IPA mode we analyze every function precisely once. Assert that. */
3186 : : else
3187 : : {
3188 : 1268988 : if (nolto)
3189 : : {
3190 : 1229458 : if (!summaries)
3191 : 128749 : summaries = modref_summaries::create_ggc (symtab);
3192 : : else
3193 : 1100709 : summaries->remove (fnode);
3194 : 1229458 : summary = summaries->get_create (fnode);
3195 : : }
3196 : 1268988 : if (lto)
3197 : : {
3198 : 89972 : if (!summaries_lto)
3199 : 18598 : summaries_lto = modref_summaries_lto::create_ggc (symtab);
3200 : : else
3201 : 71374 : summaries_lto->remove (fnode);
3202 : 89972 : summary_lto = summaries_lto->get_create (fnode);
3203 : : }
3204 : 1268988 : if (!fnspec_summaries)
3205 : 137315 : fnspec_summaries = new fnspec_summaries_t (symtab);
3206 : 1268988 : if (!escape_summaries)
3207 : 137315 : escape_summaries = new escape_summaries_t (symtab);
3208 : : }
3209 : :
3210 : :
3211 : : /* Create and initialize summary for F.
3212 : : Note that summaries may be already allocated from previous
3213 : : run of the pass. */
3214 : 1268988 : if (nolto)
3215 : : {
3216 : 4443759 : gcc_assert (!summary->loads);
3217 : 4443759 : summary->loads = modref_records::create_ggc ();
3218 : 4443759 : gcc_assert (!summary->stores);
3219 : 4443759 : summary->stores = modref_records::create_ggc ();
3220 : 4443759 : summary->writes_errno = false;
3221 : 4443759 : summary->side_effects = false;
3222 : 4443759 : summary->nondeterministic = false;
3223 : 4443759 : summary->calls_interposable = false;
3224 : : }
3225 : 4483289 : if (lto)
3226 : : {
3227 : 89972 : gcc_assert (!summary_lto->loads);
3228 : 89972 : summary_lto->loads = modref_records_lto::create_ggc ();
3229 : 89972 : gcc_assert (!summary_lto->stores);
3230 : 89972 : summary_lto->stores = modref_records_lto::create_ggc ();
3231 : 89972 : summary_lto->writes_errno = false;
3232 : 89972 : summary_lto->side_effects = false;
3233 : 89972 : summary_lto->nondeterministic = false;
3234 : 89972 : summary_lto->calls_interposable = false;
3235 : : }
3236 : :
3237 : 4483289 : analyze_parms (summary, summary_lto, ipa,
3238 : : past_flags, past_retslot_flags, past_static_chain_flags);
3239 : :
3240 : 4483289 : {
3241 : 4483289 : modref_access_analysis analyzer (ipa, summary, summary_lto);
3242 : 4483289 : analyzer.analyze ();
3243 : 4483289 : }
3244 : :
3245 : 4483289 : if (!ipa && flag_ipa_pure_const)
3246 : : {
3247 : 3214166 : if (!summary->stores->every_base && !summary->stores->bases
3248 : 1062541 : && !summary->nondeterministic)
3249 : : {
3250 : 1033628 : if (!summary->loads->every_base && !summary->loads->bases
3251 : 641403 : && !summary->calls_interposable)
3252 : 639161 : fixup_cfg = ipa_make_function_const (fnode,
3253 : : summary->side_effects, true);
3254 : : else
3255 : 394467 : fixup_cfg = ipa_make_function_pure (fnode,
3256 : : summary->side_effects, true);
3257 : : }
3258 : : }
3259 : 4483289 : int ecf_flags = flags_from_decl_or_type (current_function_decl);
3260 : 4483289 : if (summary && !summary->useful_p (ecf_flags))
3261 : : {
3262 : 1093715 : if (!ipa)
3263 : 955857 : optimization_summaries->remove (fnode);
3264 : : else
3265 : 137858 : summaries->remove (fnode);
3266 : : summary = NULL;
3267 : : }
3268 : 3389574 : if (summary)
3269 : 3350044 : summary->finalize (current_function_decl);
3270 : 4483289 : if (summary_lto && !summary_lto->useful_p (ecf_flags))
3271 : : {
3272 : 8836 : summaries_lto->remove (fnode);
3273 : 8836 : summary_lto = NULL;
3274 : : }
3275 : :
3276 : 4483289 : if (ipa && !summary && !summary_lto)
3277 : 142008 : remove_modref_edge_summaries (fnode);
3278 : :
3279 : 4483289 : if (dump_file)
3280 : : {
3281 : 153 : fprintf (dump_file, " - modref done with result: tracked.\n");
3282 : 153 : if (summary)
3283 : 127 : summary->dump (dump_file);
3284 : 153 : if (summary_lto)
3285 : 14 : summary_lto->dump (dump_file);
3286 : 153 : dump_modref_edge_summaries (dump_file, fnode, 2);
3287 : : /* To simplify debugging, compare IPA and local solutions. */
3288 : 153 : if (past_flags_known && summary)
3289 : : {
3290 : 23 : size_t len = summary->arg_flags.length ();
3291 : :
3292 : 23 : if (past_flags.length () > len)
3293 : 0 : len = past_flags.length ();
3294 : 107 : for (size_t i = 0; i < len; i++)
3295 : : {
3296 : 84 : int old_flags = i < past_flags.length () ? past_flags[i] : 0;
3297 : 84 : int new_flags = i < summary->arg_flags.length ()
3298 : 84 : ? summary->arg_flags[i] : 0;
3299 : 84 : old_flags = remove_useless_eaf_flags
3300 : 168 : (old_flags, flags_from_decl_or_type (current_function_decl),
3301 : 84 : VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3302 : 84 : if (old_flags != new_flags)
3303 : : {
3304 : 0 : if ((old_flags & ~new_flags) == 0
3305 : 0 : || (new_flags & EAF_UNUSED))
3306 : 0 : fprintf (dump_file, " Flags for param %i improved:",
3307 : : (int)i);
3308 : : else
3309 : 0 : fprintf (dump_file, " Flags for param %i changed:",
3310 : : (int)i);
3311 : 0 : dump_eaf_flags (dump_file, old_flags, false);
3312 : 0 : fprintf (dump_file, " -> ");
3313 : 0 : dump_eaf_flags (dump_file, new_flags, true);
3314 : : }
3315 : : }
3316 : 23 : past_retslot_flags = remove_useless_eaf_flags
3317 : 46 : (past_retslot_flags,
3318 : : flags_from_decl_or_type (current_function_decl),
3319 : 23 : VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3320 : 23 : if (past_retslot_flags != summary->retslot_flags)
3321 : : {
3322 : 0 : if ((past_retslot_flags & ~summary->retslot_flags) == 0
3323 : 0 : || (summary->retslot_flags & EAF_UNUSED))
3324 : 0 : fprintf (dump_file, " Flags for retslot improved:");
3325 : : else
3326 : 0 : fprintf (dump_file, " Flags for retslot changed:");
3327 : 0 : dump_eaf_flags (dump_file, past_retslot_flags, false);
3328 : 0 : fprintf (dump_file, " -> ");
3329 : 0 : dump_eaf_flags (dump_file, summary->retslot_flags, true);
3330 : : }
3331 : 23 : past_static_chain_flags = remove_useless_eaf_flags
3332 : 46 : (past_static_chain_flags,
3333 : : flags_from_decl_or_type (current_function_decl),
3334 : 23 : VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3335 : 23 : if (past_static_chain_flags != summary->static_chain_flags)
3336 : : {
3337 : 0 : if ((past_static_chain_flags & ~summary->static_chain_flags) == 0
3338 : 0 : || (summary->static_chain_flags & EAF_UNUSED))
3339 : 0 : fprintf (dump_file, " Flags for static chain improved:");
3340 : : else
3341 : 0 : fprintf (dump_file, " Flags for static chain changed:");
3342 : 0 : dump_eaf_flags (dump_file, past_static_chain_flags, false);
3343 : 0 : fprintf (dump_file, " -> ");
3344 : 0 : dump_eaf_flags (dump_file, summary->static_chain_flags, true);
3345 : : }
3346 : : }
3347 : 130 : else if (past_flags_known && !summary)
3348 : : {
3349 : 0 : for (size_t i = 0; i < past_flags.length (); i++)
3350 : : {
3351 : 0 : int old_flags = past_flags[i];
3352 : 0 : old_flags = remove_useless_eaf_flags
3353 : 0 : (old_flags, flags_from_decl_or_type (current_function_decl),
3354 : 0 : VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3355 : 0 : if (old_flags)
3356 : : {
3357 : 0 : fprintf (dump_file, " Flags for param %i worsened:",
3358 : : (int)i);
3359 : 0 : dump_eaf_flags (dump_file, old_flags, false);
3360 : 0 : fprintf (dump_file, " -> \n");
3361 : : }
3362 : : }
3363 : 0 : past_retslot_flags = remove_useless_eaf_flags
3364 : 0 : (past_retslot_flags,
3365 : : flags_from_decl_or_type (current_function_decl),
3366 : 0 : VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3367 : 0 : if (past_retslot_flags)
3368 : : {
3369 : 0 : fprintf (dump_file, " Flags for retslot worsened:");
3370 : 0 : dump_eaf_flags (dump_file, past_retslot_flags, false);
3371 : 0 : fprintf (dump_file, " ->\n");
3372 : : }
3373 : 0 : past_static_chain_flags = remove_useless_eaf_flags
3374 : 0 : (past_static_chain_flags,
3375 : : flags_from_decl_or_type (current_function_decl),
3376 : 0 : VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
3377 : 0 : if (past_static_chain_flags)
3378 : : {
3379 : 0 : fprintf (dump_file, " Flags for static chain worsened:");
3380 : 0 : dump_eaf_flags (dump_file, past_static_chain_flags, false);
3381 : 0 : fprintf (dump_file, " ->\n");
3382 : : }
3383 : : }
3384 : : }
3385 : 4483289 : return fixup_cfg;
3386 : 4483289 : }
3387 : :
3388 : : /* Callback for generate_summary. */
3389 : :
3390 : : static void
3391 : 225620 : modref_generate (void)
3392 : : {
3393 : 225620 : struct cgraph_node *node;
3394 : 1917695 : FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
3395 : : {
3396 : 1692075 : function *f = DECL_STRUCT_FUNCTION (node->decl);
3397 : 1692075 : if (!f)
3398 : 0 : continue;
3399 : 1692075 : push_cfun (f);
3400 : 1692075 : analyze_function (true);
3401 : 1692075 : pop_cfun ();
3402 : : }
3403 : 225620 : }
3404 : :
3405 : : } /* ANON namespace. */
3406 : :
3407 : : /* Debugging helper. */
3408 : :
3409 : : void
3410 : 0 : debug_eaf_flags (int flags)
3411 : : {
3412 : 0 : dump_eaf_flags (stderr, flags, true);
3413 : 0 : }
3414 : :
3415 : : /* Called when a new function is inserted to callgraph late. */
3416 : :
3417 : : void
3418 : 81899 : modref_summaries::insert (struct cgraph_node *node, modref_summary *)
3419 : : {
3420 : : /* Local passes ought to be executed by the pass manager. */
3421 : 81899 : if (this == optimization_summaries)
3422 : : {
3423 : 64011 : optimization_summaries->remove (node);
3424 : 64011 : return;
3425 : : }
3426 : 17888 : if (!DECL_STRUCT_FUNCTION (node->decl)
3427 : 17888 : || !opt_for_fn (node->decl, flag_ipa_modref))
3428 : : {
3429 : 0 : summaries->remove (node);
3430 : 0 : return;
3431 : : }
3432 : 17888 : push_cfun (DECL_STRUCT_FUNCTION (node->decl));
3433 : 17888 : analyze_function (true);
3434 : 17888 : pop_cfun ();
3435 : : }
3436 : :
3437 : : /* Called when a new function is inserted to callgraph late. */
3438 : :
3439 : : void
3440 : 1507 : modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
3441 : : {
3442 : : /* We do not support adding new function when IPA information is already
3443 : : propagated. This is done only by SIMD cloning that is not very
3444 : : critical. */
3445 : 1507 : if (!DECL_STRUCT_FUNCTION (node->decl)
3446 : 1507 : || !opt_for_fn (node->decl, flag_ipa_modref)
3447 : 3013 : || propagated)
3448 : : {
3449 : 373 : summaries_lto->remove (node);
3450 : 373 : return;
3451 : : }
3452 : 1134 : push_cfun (DECL_STRUCT_FUNCTION (node->decl));
3453 : 1134 : analyze_function (true);
3454 : 1134 : pop_cfun ();
3455 : : }
3456 : :
3457 : : /* Called when new clone is inserted to callgraph late. */
3458 : :
3459 : : void
3460 : 2413992 : modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
3461 : : modref_summary *src_data,
3462 : : modref_summary *dst_data)
3463 : : {
3464 : : /* Do not duplicate optimization summaries; we do not handle parameter
3465 : : transforms on them. */
3466 : 2413992 : if (this == optimization_summaries)
3467 : : {
3468 : 1803797 : optimization_summaries->remove (dst);
3469 : 1803797 : return;
3470 : : }
3471 : 610195 : dst_data->stores = modref_records::create_ggc ();
3472 : 610195 : dst_data->stores->copy_from (src_data->stores);
3473 : 610195 : dst_data->loads = modref_records::create_ggc ();
3474 : 610195 : dst_data->loads->copy_from (src_data->loads);
3475 : 717791 : dst_data->kills.reserve_exact (src_data->kills.length ());
3476 : 610195 : dst_data->kills.splice (src_data->kills);
3477 : 610195 : dst_data->writes_errno = src_data->writes_errno;
3478 : 610195 : dst_data->side_effects = src_data->side_effects;
3479 : 610195 : dst_data->nondeterministic = src_data->nondeterministic;
3480 : 610195 : dst_data->calls_interposable = src_data->calls_interposable;
3481 : 610195 : if (src_data->arg_flags.length ())
3482 : 380009 : dst_data->arg_flags = src_data->arg_flags.copy ();
3483 : 610195 : dst_data->retslot_flags = src_data->retslot_flags;
3484 : 610195 : dst_data->static_chain_flags = src_data->static_chain_flags;
3485 : : }
3486 : :
3487 : : /* Called when new clone is inserted to callgraph late. */
3488 : :
3489 : : void
3490 : 31978 : modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
3491 : : modref_summary_lto *src_data,
3492 : : modref_summary_lto *dst_data)
3493 : : {
3494 : : /* Be sure that no further cloning happens after ipa-modref. If it does
3495 : : we will need to update signatures for possible param changes. */
3496 : 31978 : gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
3497 : 31978 : dst_data->stores = modref_records_lto::create_ggc ();
3498 : 31978 : dst_data->stores->copy_from (src_data->stores);
3499 : 31978 : dst_data->loads = modref_records_lto::create_ggc ();
3500 : 31978 : dst_data->loads->copy_from (src_data->loads);
3501 : 32618 : dst_data->kills.reserve_exact (src_data->kills.length ());
3502 : 31978 : dst_data->kills.splice (src_data->kills);
3503 : 31978 : dst_data->writes_errno = src_data->writes_errno;
3504 : 31978 : dst_data->side_effects = src_data->side_effects;
3505 : 31978 : dst_data->nondeterministic = src_data->nondeterministic;
3506 : 31978 : dst_data->calls_interposable = src_data->calls_interposable;
3507 : 31978 : if (src_data->arg_flags.length ())
3508 : 29771 : dst_data->arg_flags = src_data->arg_flags.copy ();
3509 : 31978 : dst_data->retslot_flags = src_data->retslot_flags;
3510 : 31978 : dst_data->static_chain_flags = src_data->static_chain_flags;
3511 : 31978 : }
3512 : :
3513 : : namespace
3514 : : {
3515 : : /* Definition of the modref pass on GIMPLE. */
3516 : : const pass_data pass_data_modref = {
3517 : : GIMPLE_PASS,
3518 : : "modref",
3519 : : OPTGROUP_IPA,
3520 : : TV_TREE_MODREF,
3521 : : (PROP_cfg | PROP_ssa),
3522 : : 0,
3523 : : 0,
3524 : : 0,
3525 : : 0,
3526 : : };
3527 : :
3528 : : class pass_modref : public gimple_opt_pass
3529 : : {
3530 : : public:
3531 : 561662 : pass_modref (gcc::context *ctxt)
3532 : 1123324 : : gimple_opt_pass (pass_data_modref, ctxt) {}
3533 : :
3534 : : /* opt_pass methods: */
3535 : 280831 : opt_pass *clone () final override
3536 : : {
3537 : 280831 : return new pass_modref (m_ctxt);
3538 : : }
3539 : 3251412 : bool gate (function *) final override
3540 : : {
3541 : 3251412 : return flag_ipa_modref;
3542 : : }
3543 : : unsigned int execute (function *) final override;
3544 : : };
3545 : :
3546 : : /* Encode TT to the output block OB using the summary streaming API. */
3547 : :
3548 : : static void
3549 : 187818 : write_modref_records (modref_records_lto *tt, struct output_block *ob)
3550 : : {
3551 : 187818 : streamer_write_uhwi (ob, tt->every_base);
3552 : 248769 : streamer_write_uhwi (ob, vec_safe_length (tt->bases));
3553 : 385776 : for (auto base_node : tt->bases)
3554 : : {
3555 : 76056 : stream_write_tree (ob, base_node->base, true);
3556 : :
3557 : 76056 : streamer_write_uhwi (ob, base_node->every_ref);
3558 : 151885 : streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
3559 : :
3560 : 306418 : for (auto ref_node : base_node->refs)
3561 : : {
3562 : 78704 : stream_write_tree (ob, ref_node->ref, true);
3563 : 78704 : streamer_write_uhwi (ob, ref_node->every_access);
3564 : 99438 : streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
3565 : :
3566 : 142513 : for (auto access_node : ref_node->accesses)
3567 : 22341 : access_node.stream_out (ob);
3568 : : }
3569 : : }
3570 : 187818 : }
3571 : :
3572 : : /* Read a modref_tree from the input block IB using the data from DATA_IN.
3573 : : This assumes that the tree was encoded using write_modref_tree.
3574 : : Either nolto_ret or lto_ret is initialized by the tree depending whether
3575 : : LTO streaming is expected or not. */
3576 : :
3577 : : static void
3578 : 164078 : read_modref_records (tree decl,
3579 : : lto_input_block *ib, struct data_in *data_in,
3580 : : modref_records **nolto_ret,
3581 : : modref_records_lto **lto_ret)
3582 : : {
3583 : 164078 : size_t max_bases = opt_for_fn (decl, param_modref_max_bases);
3584 : 164078 : size_t max_refs = opt_for_fn (decl, param_modref_max_refs);
3585 : 164078 : size_t max_accesses = opt_for_fn (decl, param_modref_max_accesses);
3586 : :
3587 : 164078 : if (lto_ret)
3588 : 76588 : *lto_ret = modref_records_lto::create_ggc ();
3589 : 164078 : if (nolto_ret)
3590 : 87584 : *nolto_ret = modref_records::create_ggc ();
3591 : 164078 : gcc_checking_assert (lto_ret || nolto_ret);
3592 : :
3593 : 164078 : size_t every_base = streamer_read_uhwi (ib);
3594 : 164078 : size_t nbase = streamer_read_uhwi (ib);
3595 : :
3596 : 164078 : gcc_assert (!every_base || nbase == 0);
3597 : 164078 : if (every_base)
3598 : : {
3599 : 11204 : if (nolto_ret)
3600 : 9756 : (*nolto_ret)->collapse ();
3601 : 11204 : if (lto_ret)
3602 : 1448 : (*lto_ret)->collapse ();
3603 : : }
3604 : 227419 : for (size_t i = 0; i < nbase; i++)
3605 : : {
3606 : 63341 : tree base_tree = stream_read_tree (ib, data_in);
3607 : 63341 : modref_base_node <alias_set_type> *nolto_base_node = NULL;
3608 : 63341 : modref_base_node <tree> *lto_base_node = NULL;
3609 : :
3610 : : /* At stream in time we have LTO alias info. Check if we streamed in
3611 : : something obviously unnecessary. Do not glob types by alias sets;
3612 : : it is not 100% clear that ltrans types will get merged same way.
3613 : : Types may get refined based on ODR type conflicts. */
3614 : 63341 : if (base_tree && !get_alias_set (base_tree))
3615 : : {
3616 : 7 : if (dump_file)
3617 : : {
3618 : 0 : fprintf (dump_file, "Streamed in alias set 0 type ");
3619 : 0 : print_generic_expr (dump_file, base_tree);
3620 : 0 : fprintf (dump_file, "\n");
3621 : : }
3622 : : base_tree = NULL;
3623 : : }
3624 : :
3625 : 63341 : if (nolto_ret)
3626 : 71660 : nolto_base_node = (*nolto_ret)->insert_base (base_tree
3627 : 35275 : ? get_alias_set (base_tree)
3628 : : : 0, 0, INT_MAX);
3629 : 63341 : if (lto_ret)
3630 : 26992 : lto_base_node = (*lto_ret)->insert_base (base_tree, 0, max_bases);
3631 : 63341 : size_t every_ref = streamer_read_uhwi (ib);
3632 : 63341 : size_t nref = streamer_read_uhwi (ib);
3633 : :
3634 : 63341 : gcc_assert (!every_ref || nref == 0);
3635 : 63341 : if (every_ref)
3636 : : {
3637 : 100 : if (nolto_base_node)
3638 : 46 : nolto_base_node->collapse ();
3639 : 100 : if (lto_base_node)
3640 : 54 : lto_base_node->collapse ();
3641 : : }
3642 : 128754 : for (size_t j = 0; j < nref; j++)
3643 : : {
3644 : 65413 : tree ref_tree = stream_read_tree (ib, data_in);
3645 : :
3646 : 65413 : if (ref_tree && !get_alias_set (ref_tree))
3647 : : {
3648 : 29 : if (dump_file)
3649 : : {
3650 : 0 : fprintf (dump_file, "Streamed in alias set 0 type ");
3651 : 0 : print_generic_expr (dump_file, ref_tree);
3652 : 0 : fprintf (dump_file, "\n");
3653 : : }
3654 : : ref_tree = NULL;
3655 : : }
3656 : :
3657 : 65413 : modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
3658 : 65413 : modref_ref_node <tree> *lto_ref_node = NULL;
3659 : :
3660 : 65413 : if (nolto_base_node)
3661 : 37409 : nolto_ref_node
3662 : 74055 : = nolto_base_node->insert_ref (ref_tree
3663 : 36646 : ? get_alias_set (ref_tree) : 0,
3664 : : max_refs);
3665 : 65413 : if (lto_base_node)
3666 : 28040 : lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
3667 : :
3668 : 65413 : size_t every_access = streamer_read_uhwi (ib);
3669 : 65413 : size_t naccesses = streamer_read_uhwi (ib);
3670 : :
3671 : 65413 : if (nolto_ref_node && every_access)
3672 : 29487 : nolto_ref_node->collapse ();
3673 : 65413 : if (lto_ref_node && every_access)
3674 : 20325 : lto_ref_node->collapse ();
3675 : :
3676 : 81834 : for (size_t k = 0; k < naccesses; k++)
3677 : : {
3678 : 16421 : modref_access_node a = modref_access_node::stream_in (ib);
3679 : 16421 : if (nolto_ref_node)
3680 : 8290 : nolto_ref_node->insert_access (a, max_accesses, false);
3681 : 16421 : if (lto_ref_node)
3682 : 8151 : lto_ref_node->insert_access (a, max_accesses, false);
3683 : : }
3684 : : }
3685 : : }
3686 : 164078 : if (lto_ret)
3687 : 76588 : (*lto_ret)->cleanup ();
3688 : 164078 : if (nolto_ret)
3689 : 87584 : (*nolto_ret)->cleanup ();
3690 : 164078 : }
3691 : :
3692 : : /* Write ESUM to BP. */
3693 : :
3694 : : static void
3695 : 325144 : modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
3696 : : {
3697 : 325144 : if (!esum)
3698 : : {
3699 : 301967 : bp_pack_var_len_unsigned (bp, 0);
3700 : 301967 : return;
3701 : : }
3702 : 23177 : bp_pack_var_len_unsigned (bp, esum->esc.length ());
3703 : 23177 : unsigned int i;
3704 : 23177 : escape_entry *ee;
3705 : 69982 : FOR_EACH_VEC_ELT (esum->esc, i, ee)
3706 : : {
3707 : 23628 : bp_pack_var_len_int (bp, ee->parm_index);
3708 : 23628 : bp_pack_var_len_unsigned (bp, ee->arg);
3709 : 23628 : bp_pack_var_len_unsigned (bp, ee->min_flags);
3710 : 23628 : bp_pack_value (bp, ee->direct, 1);
3711 : : }
3712 : : }
3713 : :
3714 : : /* Read escape summary for E from BP. */
3715 : :
3716 : : static void
3717 : 306878 : modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
3718 : : {
3719 : 306878 : unsigned int n = bp_unpack_var_len_unsigned (bp);
3720 : 306878 : if (!n)
3721 : : return;
3722 : 22712 : escape_summary *esum = escape_summaries->get_create (e);
3723 : 22712 : esum->esc.reserve_exact (n);
3724 : 45822 : for (unsigned int i = 0; i < n; i++)
3725 : : {
3726 : 23110 : escape_entry ee;
3727 : 23110 : ee.parm_index = bp_unpack_var_len_int (bp);
3728 : 23110 : ee.arg = bp_unpack_var_len_unsigned (bp);
3729 : 23110 : ee.min_flags = bp_unpack_var_len_unsigned (bp);
3730 : 23110 : ee.direct = bp_unpack_value (bp, 1);
3731 : 23110 : esum->esc.quick_push (ee);
3732 : : }
3733 : : }
3734 : :
3735 : : /* Callback for write_summary. */
3736 : :
3737 : : static void
3738 : 32653 : modref_write ()
3739 : : {
3740 : 32653 : struct output_block *ob = create_output_block (LTO_section_ipa_modref);
3741 : 32653 : lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
3742 : 32653 : unsigned int count = 0;
3743 : 32653 : int i;
3744 : :
3745 : 32653 : if (!summaries_lto)
3746 : : {
3747 : 5064 : streamer_write_uhwi (ob, 0);
3748 : 5064 : streamer_write_char_stream (ob->main_stream, 0);
3749 : 5064 : produce_asm (ob);
3750 : 5064 : destroy_output_block (ob);
3751 : 5064 : return;
3752 : : }
3753 : :
3754 : 615209 : for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3755 : : {
3756 : 280020 : symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3757 : 560040 : cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3758 : 200533 : modref_summary_lto *r;
3759 : :
3760 : 200533 : if (cnode && cnode->definition && !cnode->alias
3761 : 144134 : && (r = summaries_lto->get (cnode))
3762 : 97501 : && r->useful_p (flags_from_decl_or_type (cnode->decl)))
3763 : 93909 : count++;
3764 : : }
3765 : 27589 : streamer_write_uhwi (ob, count);
3766 : :
3767 : 615209 : for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
3768 : : {
3769 : 280020 : symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
3770 : 560040 : cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
3771 : :
3772 : 200533 : if (cnode && cnode->definition && !cnode->alias)
3773 : : {
3774 : 144134 : modref_summary_lto *r = summaries_lto->get (cnode);
3775 : :
3776 : 144134 : if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
3777 : 50225 : continue;
3778 : :
3779 : 93909 : streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
3780 : :
3781 : 93909 : streamer_write_uhwi (ob, r->arg_flags.length ());
3782 : 391628 : for (unsigned int i = 0; i < r->arg_flags.length (); i++)
3783 : 297719 : streamer_write_uhwi (ob, r->arg_flags[i]);
3784 : 93909 : streamer_write_uhwi (ob, r->retslot_flags);
3785 : 93909 : streamer_write_uhwi (ob, r->static_chain_flags);
3786 : :
3787 : 93909 : write_modref_records (r->loads, ob);
3788 : 93909 : write_modref_records (r->stores, ob);
3789 : 98349 : streamer_write_uhwi (ob, r->kills.length ());
3790 : 108040 : for (auto kill : r->kills)
3791 : 5251 : kill.stream_out (ob);
3792 : :
3793 : 93909 : struct bitpack_d bp = bitpack_create (ob->main_stream);
3794 : 93909 : bp_pack_value (&bp, r->writes_errno, 1);
3795 : 93909 : bp_pack_value (&bp, r->side_effects, 1);
3796 : 93909 : bp_pack_value (&bp, r->nondeterministic, 1);
3797 : 93909 : bp_pack_value (&bp, r->calls_interposable, 1);
3798 : 93909 : if (!flag_wpa)
3799 : : {
3800 : 79299 : for (cgraph_edge *e = cnode->indirect_calls;
3801 : 81011 : e; e = e->next_callee)
3802 : : {
3803 : 1712 : class fnspec_summary *sum = fnspec_summaries->get (e);
3804 : 1712 : bp_pack_value (&bp, sum != NULL, 1);
3805 : 1712 : if (sum)
3806 : 0 : bp_pack_string (ob, &bp, sum->fnspec, true);
3807 : 1712 : class escape_summary *esum = escape_summaries->get (e);
3808 : 1712 : modref_write_escape_summary (&bp,esum);
3809 : : }
3810 : 402731 : for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
3811 : : {
3812 : 323432 : class fnspec_summary *sum = fnspec_summaries->get (e);
3813 : 323432 : bp_pack_value (&bp, sum != NULL, 1);
3814 : 323432 : if (sum)
3815 : 73744 : bp_pack_string (ob, &bp, sum->fnspec, true);
3816 : 323432 : class escape_summary *esum = escape_summaries->get (e);
3817 : 323432 : modref_write_escape_summary (&bp,esum);
3818 : : }
3819 : : }
3820 : 93909 : streamer_write_bitpack (&bp);
3821 : : }
3822 : : }
3823 : 27589 : streamer_write_char_stream (ob->main_stream, 0);
3824 : 27589 : produce_asm (ob);
3825 : 27589 : destroy_output_block (ob);
3826 : : }
3827 : :
3828 : : static void
3829 : 22791 : read_section (struct lto_file_decl_data *file_data, const char *data,
3830 : : size_t len)
3831 : : {
3832 : 22791 : const struct lto_function_header *header
3833 : : = (const struct lto_function_header *) data;
3834 : 22791 : const int cfg_offset = sizeof (struct lto_function_header);
3835 : 22791 : const int main_offset = cfg_offset + header->cfg_size;
3836 : 22791 : const int string_offset = main_offset + header->main_size;
3837 : 22791 : struct data_in *data_in;
3838 : 22791 : unsigned int i;
3839 : 22791 : unsigned int f_count;
3840 : :
3841 : 22791 : lto_input_block ib ((const char *) data + main_offset, header->main_size,
3842 : 22791 : file_data);
3843 : :
3844 : 22791 : data_in
3845 : 45582 : = lto_data_in_create (file_data, (const char *) data + string_offset,
3846 : 22791 : header->string_size, vNULL);
3847 : 22791 : f_count = streamer_read_uhwi (&ib);
3848 : 104830 : for (i = 0; i < f_count; i++)
3849 : : {
3850 : 82039 : struct cgraph_node *node;
3851 : 82039 : lto_symtab_encoder_t encoder;
3852 : :
3853 : 82039 : unsigned int index = streamer_read_uhwi (&ib);
3854 : 82039 : encoder = file_data->symtab_node_encoder;
3855 : 82039 : node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
3856 : : index));
3857 : :
3858 : 82039 : modref_summary *modref_sum = summaries
3859 : 82039 : ? summaries->get_create (node) : NULL;
3860 : 82039 : modref_summary_lto *modref_sum_lto = summaries_lto
3861 : 82039 : ? summaries_lto->get_create (node)
3862 : 82039 : : NULL;
3863 : 82039 : if (optimization_summaries)
3864 : 14610 : modref_sum = optimization_summaries->get_create (node);
3865 : :
3866 : 82039 : if (modref_sum)
3867 : : {
3868 : 43792 : modref_sum->writes_errno = false;
3869 : 43792 : modref_sum->side_effects = false;
3870 : 43792 : modref_sum->nondeterministic = false;
3871 : 43792 : modref_sum->calls_interposable = false;
3872 : : }
3873 : 82039 : if (modref_sum_lto)
3874 : : {
3875 : 38294 : modref_sum_lto->writes_errno = false;
3876 : 38294 : modref_sum_lto->side_effects = false;
3877 : 38294 : modref_sum_lto->nondeterministic = false;
3878 : 38294 : modref_sum_lto->calls_interposable = false;
3879 : : }
3880 : :
3881 : 82039 : gcc_assert (!modref_sum || (!modref_sum->loads
3882 : : && !modref_sum->stores));
3883 : 82039 : gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
3884 : : && !modref_sum_lto->stores));
3885 : 82039 : unsigned int args = streamer_read_uhwi (&ib);
3886 : 82039 : if (args && modref_sum)
3887 : 29766 : modref_sum->arg_flags.reserve_exact (args);
3888 : 82039 : if (args && modref_sum_lto)
3889 : 23929 : modref_sum_lto->arg_flags.reserve_exact (args);
3890 : 161590 : for (unsigned int i = 0; i < args; i++)
3891 : : {
3892 : 79551 : eaf_flags_t flags = streamer_read_uhwi (&ib);
3893 : 79551 : if (modref_sum)
3894 : 44209 : modref_sum->arg_flags.quick_push (flags);
3895 : 79551 : if (modref_sum_lto)
3896 : 35394 : modref_sum_lto->arg_flags.quick_push (flags);
3897 : : }
3898 : 82039 : eaf_flags_t flags = streamer_read_uhwi (&ib);
3899 : 82039 : if (modref_sum)
3900 : 43792 : modref_sum->retslot_flags = flags;
3901 : 82039 : if (modref_sum_lto)
3902 : 38294 : modref_sum_lto->retslot_flags = flags;
3903 : :
3904 : 82039 : flags = streamer_read_uhwi (&ib);
3905 : 82039 : if (modref_sum)
3906 : 43792 : modref_sum->static_chain_flags = flags;
3907 : 82039 : if (modref_sum_lto)
3908 : 38294 : modref_sum_lto->static_chain_flags = flags;
3909 : :
3910 : 82039 : read_modref_records (node->decl, &ib, data_in,
3911 : : modref_sum ? &modref_sum->loads : NULL,
3912 : : modref_sum_lto ? &modref_sum_lto->loads : NULL);
3913 : 82039 : read_modref_records (node->decl, &ib, data_in,
3914 : : modref_sum ? &modref_sum->stores : NULL,
3915 : : modref_sum_lto ? &modref_sum_lto->stores : NULL);
3916 : 82039 : int j = streamer_read_uhwi (&ib);
3917 : 82039 : if (j && modref_sum)
3918 : 1846 : modref_sum->kills.reserve_exact (j);
3919 : 82039 : if (j && modref_sum_lto)
3920 : 1446 : modref_sum_lto->kills.reserve_exact (j);
3921 : 86062 : for (int k = 0; k < j; k++)
3922 : : {
3923 : 4023 : modref_access_node a = modref_access_node::stream_in (&ib);
3924 : :
3925 : 4023 : if (modref_sum)
3926 : 2223 : modref_sum->kills.quick_push (a);
3927 : 4023 : if (modref_sum_lto)
3928 : 1807 : modref_sum_lto->kills.quick_push (a);
3929 : : }
3930 : 82039 : struct bitpack_d bp = streamer_read_bitpack (&ib);
3931 : 82039 : if (bp_unpack_value (&bp, 1))
3932 : : {
3933 : 96 : if (modref_sum)
3934 : 96 : modref_sum->writes_errno = true;
3935 : 96 : if (modref_sum_lto)
3936 : 0 : modref_sum_lto->writes_errno = true;
3937 : : }
3938 : 82039 : if (bp_unpack_value (&bp, 1))
3939 : : {
3940 : 13320 : if (modref_sum)
3941 : 9830 : modref_sum->side_effects = true;
3942 : 13320 : if (modref_sum_lto)
3943 : 3491 : modref_sum_lto->side_effects = true;
3944 : : }
3945 : 82039 : if (bp_unpack_value (&bp, 1))
3946 : : {
3947 : 7016 : if (modref_sum)
3948 : 4392 : modref_sum->nondeterministic = true;
3949 : 7016 : if (modref_sum_lto)
3950 : 2624 : modref_sum_lto->nondeterministic = true;
3951 : : }
3952 : 82039 : if (bp_unpack_value (&bp, 1))
3953 : : {
3954 : 0 : if (modref_sum)
3955 : 0 : modref_sum->calls_interposable = true;
3956 : 0 : if (modref_sum_lto)
3957 : 0 : modref_sum_lto->calls_interposable = true;
3958 : : }
3959 : 82039 : if (!flag_ltrans)
3960 : : {
3961 : 68735 : for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
3962 : : {
3963 : 1306 : if (bp_unpack_value (&bp, 1))
3964 : : {
3965 : 0 : class fnspec_summary *sum = fnspec_summaries->get_create (e);
3966 : 0 : sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3967 : : }
3968 : 1306 : modref_read_escape_summary (&bp, e);
3969 : : }
3970 : 373001 : for (cgraph_edge *e = node->callees; e; e = e->next_callee)
3971 : : {
3972 : 305572 : if (bp_unpack_value (&bp, 1))
3973 : : {
3974 : 71218 : class fnspec_summary *sum = fnspec_summaries->get_create (e);
3975 : 71218 : sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
3976 : : }
3977 : 305572 : modref_read_escape_summary (&bp, e);
3978 : : }
3979 : : }
3980 : 82039 : if (flag_ltrans)
3981 : 14610 : modref_sum->finalize (node->decl);
3982 : 82039 : if (dump_file)
3983 : : {
3984 : 16 : fprintf (dump_file, "Read modref for %s\n",
3985 : : node->dump_name ());
3986 : 16 : if (modref_sum)
3987 : 10 : modref_sum->dump (dump_file);
3988 : 16 : if (modref_sum_lto)
3989 : 6 : modref_sum_lto->dump (dump_file);
3990 : 16 : dump_modref_edge_summaries (dump_file, node, 4);
3991 : : }
3992 : : }
3993 : :
3994 : 22791 : lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
3995 : : len);
3996 : 22791 : lto_data_in_delete (data_in);
3997 : 22791 : }
3998 : :
3999 : : /* Callback for read_summary. */
4000 : :
4001 : : static void
4002 : 21767 : modref_read (void)
4003 : : {
4004 : 21767 : struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
4005 : 21767 : struct lto_file_decl_data *file_data;
4006 : 21767 : unsigned int j = 0;
4007 : :
4008 : 21767 : gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
4009 : 21767 : if (flag_ltrans)
4010 : 8957 : optimization_summaries = modref_summaries::create_ggc (symtab);
4011 : : else
4012 : : {
4013 : 12810 : if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
4014 : 8634 : summaries_lto = modref_summaries_lto::create_ggc (symtab);
4015 : 12810 : if (!flag_wpa
4016 : 8600 : || (flag_incremental_link == INCREMENTAL_LINK_LTO
4017 : 0 : && flag_fat_lto_objects))
4018 : 4210 : summaries = modref_summaries::create_ggc (symtab);
4019 : 12810 : if (!fnspec_summaries)
4020 : 12810 : fnspec_summaries = new fnspec_summaries_t (symtab);
4021 : 12810 : if (!escape_summaries)
4022 : 12810 : escape_summaries = new escape_summaries_t (symtab);
4023 : : }
4024 : :
4025 : 44558 : while ((file_data = file_data_vec[j++]))
4026 : : {
4027 : 22791 : size_t len;
4028 : 22791 : const char *data = lto_get_summary_section_data (file_data,
4029 : : LTO_section_ipa_modref,
4030 : : &len);
4031 : 22791 : if (data)
4032 : 22791 : read_section (file_data, data, len);
4033 : : else
4034 : : /* Fatal error here. We do not want to support compiling ltrans units
4035 : : with different version of compiler or different flags than the WPA
4036 : : unit, so this should never happen. */
4037 : 0 : fatal_error (input_location,
4038 : : "IPA modref summary is missing in input file");
4039 : : }
4040 : 21767 : }
4041 : :
4042 : : /* Recompute arg_flags for param adjustments in INFO. */
4043 : :
4044 : : static void
4045 : 17647 : remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
4046 : : {
4047 : 17647 : auto_vec<eaf_flags_t> old = arg_flags.copy ();
4048 : 17647 : int max = -1;
4049 : 17647 : size_t i;
4050 : 17647 : ipa_adjusted_param *p;
4051 : :
4052 : 17647 : arg_flags.release ();
4053 : :
4054 : 57368 : FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4055 : : {
4056 : 39721 : int o = info->param_adjustments->get_original_index (i);
4057 : 69459 : if (o >= 0 && (int)old.length () > o && old[o])
4058 : : max = i;
4059 : : }
4060 : 17647 : if (max >= 0)
4061 : 11255 : arg_flags.safe_grow_cleared (max + 1, true);
4062 : 73470 : FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4063 : : {
4064 : 39721 : int o = info->param_adjustments->get_original_index (i);
4065 : 29738 : if (o >= 0 && (int)old.length () > o && old[o])
4066 : 16168 : arg_flags[i] = old[o];
4067 : : }
4068 : 17647 : }
4069 : :
4070 : : /* Update kills according to the parm map MAP. */
4071 : :
4072 : : static void
4073 : 19606 : remap_kills (vec <modref_access_node> &kills, const vec <int> &map)
4074 : : {
4075 : 21299 : for (size_t i = 0; i < kills.length ();)
4076 : 1693 : if (kills[i].parm_index >= 0)
4077 : : {
4078 : 1591 : if (kills[i].parm_index < (int)map.length ()
4079 : 1591 : && map[kills[i].parm_index] != MODREF_UNKNOWN_PARM)
4080 : : {
4081 : 1474 : kills[i].parm_index = map[kills[i].parm_index];
4082 : 1474 : i++;
4083 : : }
4084 : : else
4085 : 117 : kills.unordered_remove (i);
4086 : : }
4087 : : else
4088 : 102 : i++;
4089 : 19606 : }
4090 : :
4091 : : /* Return true if the V can overlap with KILL. */
4092 : :
4093 : : static bool
4094 : 6761 : ipcp_argagg_and_kill_overlap_p (const ipa_argagg_value &v,
4095 : : const modref_access_node &kill)
4096 : : {
4097 : 6761 : if (kill.parm_index == v.index)
4098 : : {
4099 : 430 : gcc_assert (kill.parm_offset_known);
4100 : 430 : gcc_assert (known_eq (kill.max_size, kill.size));
4101 : 430 : poly_int64 repl_size;
4102 : 430 : bool ok = poly_int_tree_p (TYPE_SIZE (TREE_TYPE (v.value)),
4103 : : &repl_size);
4104 : 430 : gcc_assert (ok);
4105 : 430 : poly_int64 repl_offset (v.unit_offset);
4106 : 430 : repl_offset <<= LOG2_BITS_PER_UNIT;
4107 : 430 : poly_int64 combined_offset
4108 : 430 : = (kill.parm_offset << LOG2_BITS_PER_UNIT) + kill.offset;
4109 : 430 : if (ranges_maybe_overlap_p (repl_offset, repl_size,
4110 : 430 : combined_offset, kill.size))
4111 : 384 : return true;
4112 : : }
4113 : : return false;
4114 : : }
4115 : :
4116 : : /* If signature changed, update the summary. */
4117 : :
4118 : : static void
4119 : 3051668 : update_signature (struct cgraph_node *node)
4120 : : {
4121 : 6103336 : modref_summary *r = optimization_summaries
4122 : 3051668 : ? optimization_summaries->get (node) : NULL;
4123 : 6103336 : modref_summary_lto *r_lto = summaries_lto
4124 : 3051668 : ? summaries_lto->get (node) : NULL;
4125 : 3051668 : if (!r && !r_lto)
4126 : : return;
4127 : :
4128 : : /* Propagating constants in killed memory can lead to eliminated stores in
4129 : : both callees (because they are considered redundant) and callers, leading
4130 : : to missing them altogether. */
4131 : 824687 : ipcp_transformation *ipcp_ts = ipcp_get_transformation_summary (node);
4132 : 824687 : if (ipcp_ts)
4133 : : {
4134 : 61134 : for (auto &v : ipcp_ts->m_agg_values)
4135 : : {
4136 : 15551 : if (!v.by_ref)
4137 : 2276 : continue;
4138 : 13275 : if (r)
4139 : 22883 : for (const modref_access_node &kill : r->kills)
4140 : 6714 : if (ipcp_argagg_and_kill_overlap_p (v, kill))
4141 : : {
4142 : 366 : v.killed = true;
4143 : 366 : break;
4144 : : }
4145 : 13275 : if (!v.killed && r_lto)
4146 : 1132 : for (const modref_access_node &kill : r_lto->kills)
4147 : 47 : if (ipcp_argagg_and_kill_overlap_p (v, kill))
4148 : : {
4149 : 18 : v.killed = true;
4150 : 18 : break;
4151 : : }
4152 : : }
4153 : : }
4154 : :
4155 : 824687 : clone_info *info = clone_info::get (node);
4156 : 824687 : if (!info || !info->param_adjustments)
4157 : : return;
4158 : :
4159 : 19463 : if (dump_file)
4160 : : {
4161 : 1 : fprintf (dump_file, "Updating summary for %s from:\n",
4162 : : node->dump_name ());
4163 : 1 : if (r)
4164 : 1 : r->dump (dump_file);
4165 : 1 : if (r_lto)
4166 : 0 : r_lto->dump (dump_file);
4167 : : }
4168 : :
4169 : : size_t i, max = 0;
4170 : : ipa_adjusted_param *p;
4171 : :
4172 : 62263 : FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4173 : : {
4174 : 42800 : int idx = info->param_adjustments->get_original_index (i);
4175 : 42800 : if (idx > (int)max)
4176 : 21846 : max = idx;
4177 : : }
4178 : :
4179 : 19463 : auto_vec <int, 32> map;
4180 : :
4181 : 19463 : map.reserve (max + 1);
4182 : 83084 : for (i = 0; i <= max; i++)
4183 : 44158 : map.quick_push (MODREF_UNKNOWN_PARM);
4184 : 62263 : FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
4185 : : {
4186 : 42800 : int idx = info->param_adjustments->get_original_index (i);
4187 : 42800 : if (idx >= 0)
4188 : 32145 : map[idx] = i;
4189 : : }
4190 : 19463 : if (r)
4191 : : {
4192 : 18133 : r->loads->remap_params (&map);
4193 : 18133 : r->stores->remap_params (&map);
4194 : 18133 : remap_kills (r->kills, map);
4195 : 18133 : if (r->arg_flags.length ())
4196 : 16467 : remap_arg_flags (r->arg_flags, info);
4197 : : }
4198 : 19463 : if (r_lto)
4199 : : {
4200 : 1473 : r_lto->loads->remap_params (&map);
4201 : 1473 : r_lto->stores->remap_params (&map);
4202 : 1473 : remap_kills (r_lto->kills, map);
4203 : 1473 : if (r_lto->arg_flags.length ())
4204 : 1180 : remap_arg_flags (r_lto->arg_flags, info);
4205 : : }
4206 : 19463 : if (dump_file)
4207 : : {
4208 : 1 : fprintf (dump_file, "to:\n");
4209 : 1 : if (r)
4210 : 1 : r->dump (dump_file);
4211 : 1 : if (r_lto)
4212 : 0 : r_lto->dump (dump_file);
4213 : : }
4214 : 19463 : if (r)
4215 : 18133 : r->finalize (node->decl);
4216 : 19463 : return;
4217 : 19463 : }
4218 : :
4219 : : /* Definition of the modref IPA pass. */
4220 : : const pass_data pass_data_ipa_modref =
4221 : : {
4222 : : IPA_PASS, /* type */
4223 : : "modref", /* name */
4224 : : OPTGROUP_IPA, /* optinfo_flags */
4225 : : TV_IPA_MODREF, /* tv_id */
4226 : : 0, /* properties_required */
4227 : : 0, /* properties_provided */
4228 : : 0, /* properties_destroyed */
4229 : : 0, /* todo_flags_start */
4230 : : ( TODO_dump_symtab ), /* todo_flags_finish */
4231 : : };
4232 : :
4233 : : class pass_ipa_modref : public ipa_opt_pass_d
4234 : : {
4235 : : public:
4236 : 280831 : pass_ipa_modref (gcc::context *ctxt)
4237 : : : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
4238 : : modref_generate, /* generate_summary */
4239 : : modref_write, /* write_summary */
4240 : : modref_read, /* read_summary */
4241 : : modref_write, /* write_optimization_summary */
4242 : : modref_read, /* read_optimization_summary */
4243 : : NULL, /* stmt_fixup */
4244 : : 0, /* function_transform_todo_flags_start */
4245 : : NULL, /* function_transform */
4246 : 280831 : NULL) /* variable_transform */
4247 : 280831 : {}
4248 : :
4249 : : /* opt_pass methods: */
4250 : 0 : opt_pass *clone () final override { return new pass_ipa_modref (m_ctxt); }
4251 : 588139 : bool gate (function *) final override
4252 : : {
4253 : 588139 : return true;
4254 : : }
4255 : : unsigned int execute (function *) final override;
4256 : :
4257 : : };
4258 : :
4259 : : }
4260 : :
4261 : 3247785 : unsigned int pass_modref::execute (function *)
4262 : : {
4263 : 3247785 : if (analyze_function (false))
4264 : 7407 : return execute_fixup_cfg ();
4265 : : return 0;
4266 : : }
4267 : :
4268 : : gimple_opt_pass *
4269 : 280831 : make_pass_modref (gcc::context *ctxt)
4270 : : {
4271 : 280831 : return new pass_modref (ctxt);
4272 : : }
4273 : :
4274 : : ipa_opt_pass_d *
4275 : 280831 : make_pass_ipa_modref (gcc::context *ctxt)
4276 : : {
4277 : 280831 : return new pass_ipa_modref (ctxt);
4278 : : }
4279 : :
4280 : : namespace {
4281 : :
4282 : : /* Skip edges from and to nodes without ipa_pure_const enabled.
4283 : : Ignore not available symbols. */
4284 : :
4285 : : static bool
4286 : 6658205 : ignore_edge (struct cgraph_edge *e)
4287 : : {
4288 : : /* We merge summaries of inline clones into summaries of functions they
4289 : : are inlined to. For that reason the complete function bodies must
4290 : : act as unit. */
4291 : 6658205 : if (!e->inline_failed)
4292 : : return false;
4293 : 5520340 : enum availability avail;
4294 : 5520340 : cgraph_node *callee = e->callee->ultimate_alias_target
4295 : 5520340 : (&avail, e->caller);
4296 : :
4297 : 5520340 : return (avail <= AVAIL_INTERPOSABLE
4298 : 5520340 : || ((!optimization_summaries || !optimization_summaries->get (callee))
4299 : 198890 : && (!summaries_lto || !summaries_lto->get (callee))));
4300 : : }
4301 : :
4302 : : /* Compute parm_map for CALLEE_EDGE. */
4303 : :
4304 : : static bool
4305 : 1913173 : compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
4306 : : {
4307 : 1913173 : class ipa_edge_args *args;
4308 : 1913173 : if (ipa_node_params_sum
4309 : 1913173 : && !callee_edge->call_stmt_cannot_inline_p
4310 : 3826345 : && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
4311 : : {
4312 : 1878644 : int i, count = ipa_get_cs_argument_count (args);
4313 : 1878644 : class ipa_node_params *caller_parms_info, *callee_pi;
4314 : 1878644 : class ipa_call_summary *es
4315 : 1878644 : = ipa_call_summaries->get (callee_edge);
4316 : 1878644 : cgraph_node *callee
4317 : 1878644 : = callee_edge->callee->ultimate_alias_target
4318 : 1878644 : (NULL, callee_edge->caller);
4319 : :
4320 : 1878644 : caller_parms_info
4321 : 1878644 : = ipa_node_params_sum->get (callee_edge->caller->inlined_to
4322 : : ? callee_edge->caller->inlined_to
4323 : : : callee_edge->caller);
4324 : 1878644 : callee_pi = ipa_node_params_sum->get (callee);
4325 : :
4326 : 1878644 : (*parm_map).safe_grow_cleared (count, true);
4327 : :
4328 : 6091280 : for (i = 0; i < count; i++)
4329 : : {
4330 : 4212636 : if (es && es->param[i].points_to_local_or_readonly_memory)
4331 : : {
4332 : 736817 : (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
4333 : 736817 : continue;
4334 : : }
4335 : :
4336 : 3475819 : struct ipa_jump_func *jf
4337 : 3475819 : = ipa_get_ith_jump_func (args, i);
4338 : 3475819 : if (jf && callee_pi)
4339 : : {
4340 : 2588059 : tree cst = ipa_value_from_jfunc (caller_parms_info,
4341 : : jf,
4342 : : ipa_get_type
4343 : : (callee_pi, i));
4344 : 2588059 : if (cst && points_to_local_or_readonly_memory_p (cst))
4345 : : {
4346 : 541 : (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
4347 : 541 : continue;
4348 : : }
4349 : : }
4350 : 3475278 : if (jf && jf->type == IPA_JF_PASS_THROUGH)
4351 : : {
4352 : 713690 : (*parm_map)[i].parm_index
4353 : 713690 : = ipa_get_jf_pass_through_formal_id (jf);
4354 : 713690 : if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
4355 : : {
4356 : 702189 : (*parm_map)[i].parm_offset_known = true;
4357 : 702189 : (*parm_map)[i].parm_offset = 0;
4358 : : }
4359 : 11501 : else if (ipa_get_jf_pass_through_operation (jf)
4360 : : == POINTER_PLUS_EXPR
4361 : 13902 : && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
4362 : 2401 : &(*parm_map)[i].parm_offset))
4363 : 2401 : (*parm_map)[i].parm_offset_known = true;
4364 : : else
4365 : 9100 : (*parm_map)[i].parm_offset_known = false;
4366 : 713690 : continue;
4367 : : }
4368 : 2761588 : if (jf && jf->type == IPA_JF_ANCESTOR)
4369 : : {
4370 : 103565 : (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
4371 : 103565 : (*parm_map)[i].parm_offset_known = true;
4372 : 103565 : gcc_checking_assert
4373 : : (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
4374 : 207130 : (*parm_map)[i].parm_offset
4375 : 103565 : = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
4376 : : }
4377 : : else
4378 : 2658023 : (*parm_map)[i].parm_index = -1;
4379 : : }
4380 : 1878644 : if (dump_file)
4381 : : {
4382 : 439 : fprintf (dump_file, " Parm map: ");
4383 : 1458 : for (i = 0; i < count; i++)
4384 : 580 : fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
4385 : 439 : fprintf (dump_file, "\n");
4386 : : }
4387 : 1878644 : return true;
4388 : : }
4389 : : return false;
4390 : : }
4391 : :
4392 : : /* Map used to translate escape infos. */
4393 : :
4394 : : struct escape_map
4395 : : {
4396 : : int parm_index;
4397 : : bool direct;
4398 : : };
4399 : :
4400 : : /* Update escape map for E. */
4401 : :
4402 : : static void
4403 : 1900235 : update_escape_summary_1 (cgraph_edge *e,
4404 : : vec <vec <escape_map>> &map,
4405 : : bool ignore_stores)
4406 : : {
4407 : 1900235 : escape_summary *sum = escape_summaries->get (e);
4408 : 1900235 : if (!sum)
4409 : 1789031 : return;
4410 : 111204 : auto_vec <escape_entry> old = sum->esc.copy ();
4411 : 111204 : sum->esc.release ();
4412 : :
4413 : 111204 : unsigned int i;
4414 : 111204 : escape_entry *ee;
4415 : 241649 : FOR_EACH_VEC_ELT (old, i, ee)
4416 : : {
4417 : 130445 : unsigned int j;
4418 : 130445 : struct escape_map *em;
4419 : : /* TODO: We do not have jump functions for return slots, so we
4420 : : never propagate them to outer function. */
4421 : 130445 : if (ee->parm_index >= (int)map.length ()
4422 : 130445 : || ee->parm_index < 0)
4423 : 99809 : continue;
4424 : 182214 : FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
4425 : : {
4426 : 25949 : eaf_flags_t min_flags = ee->min_flags;
4427 : 25949 : if (ee->direct && !em->direct)
4428 : 3931 : min_flags = deref_flags (min_flags, ignore_stores);
4429 : 25949 : struct escape_entry entry = {em->parm_index, ee->arg,
4430 : : min_flags,
4431 : 25949 : ee->direct && em->direct};
4432 : 25949 : sum->esc.safe_push (entry);
4433 : : }
4434 : : }
4435 : 111204 : if (!sum->esc.length ())
4436 : 89490 : escape_summaries->remove (e);
4437 : 111204 : }
4438 : :
4439 : : /* Update escape map for NODE. */
4440 : :
4441 : : static void
4442 : 1164706 : update_escape_summary (cgraph_node *node,
4443 : : vec <vec <escape_map>> &map,
4444 : : bool ignore_stores)
4445 : : {
4446 : 1164706 : if (!escape_summaries)
4447 : : return;
4448 : 1224029 : for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
4449 : 59323 : update_escape_summary_1 (e, map, ignore_stores);
4450 : 3466553 : for (cgraph_edge *e = node->callees; e; e = e->next_callee)
4451 : : {
4452 : 2301847 : if (!e->inline_failed)
4453 : 460935 : update_escape_summary (e->callee, map, ignore_stores);
4454 : : else
4455 : 1840912 : update_escape_summary_1 (e, map, ignore_stores);
4456 : : }
4457 : : }
4458 : :
4459 : : /* Get parameter type from DECL. This is only safe for special cases
4460 : : like builtins we create fnspec for because the type match is checked
4461 : : at fnspec creation time. */
4462 : :
4463 : : static tree
4464 : 19190 : get_parm_type (tree decl, unsigned int i)
4465 : : {
4466 : 19190 : tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
4467 : :
4468 : 57497 : for (unsigned int p = 0; p < i; p++)
4469 : 38307 : t = TREE_CHAIN (t);
4470 : 19190 : return TREE_VALUE (t);
4471 : : }
4472 : :
4473 : : /* Return access mode for argument I of call E with FNSPEC. */
4474 : :
4475 : : static modref_access_node
4476 : 243486 : get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
4477 : : unsigned int i, modref_parm_map &map)
4478 : : {
4479 : 243486 : tree size = NULL_TREE;
4480 : 243486 : unsigned int size_arg;
4481 : :
4482 : 243486 : if (!fnspec.arg_specified_p (i))
4483 : : ;
4484 : 243486 : else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
4485 : : {
4486 : 38374 : cgraph_node *node = e->caller->inlined_to
4487 : 19187 : ? e->caller->inlined_to : e->caller;
4488 : 19187 : ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
4489 : 19187 : ipa_edge_args *args = ipa_edge_args_sum->get (e);
4490 : 19187 : struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
4491 : :
4492 : 19187 : if (jf)
4493 : 19187 : size = ipa_value_from_jfunc (caller_parms_info, jf,
4494 : 19187 : get_parm_type (e->callee->decl, size_arg));
4495 : : }
4496 : 224299 : else if (fnspec.arg_access_size_given_by_type_p (i))
4497 : 3 : size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
4498 : 243486 : modref_access_node a = {0, -1, -1,
4499 : 243486 : map.parm_offset, map.parm_index,
4500 : 243486 : map.parm_offset_known, 0};
4501 : 243486 : poly_int64 size_hwi;
4502 : 243486 : if (size
4503 : 8543 : && poly_int_tree_p (size, &size_hwi)
4504 : 251893 : && coeffs_in_range_p (size_hwi, 0,
4505 : : HOST_WIDE_INT_MAX / BITS_PER_UNIT))
4506 : : {
4507 : 8240 : a.size = -1;
4508 : 8240 : a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
4509 : : }
4510 : 243486 : return a;
4511 : : }
4512 : :
4513 : : /* Collapse loads and return true if something changed. */
4514 : : static bool
4515 : 2270529 : collapse_loads (modref_summary *cur_summary,
4516 : : modref_summary_lto *cur_summary_lto)
4517 : : {
4518 : 2270529 : bool changed = false;
4519 : :
4520 : 2270529 : if (cur_summary && !cur_summary->loads->every_base)
4521 : : {
4522 : 416787 : cur_summary->loads->collapse ();
4523 : 416787 : changed = true;
4524 : : }
4525 : 2270529 : if (cur_summary_lto
4526 : 176926 : && !cur_summary_lto->loads->every_base)
4527 : : {
4528 : 23804 : cur_summary_lto->loads->collapse ();
4529 : 23804 : changed = true;
4530 : : }
4531 : 2270529 : return changed;
4532 : : }
4533 : :
4534 : : /* Collapse loads and return true if something changed. */
4535 : :
4536 : : static bool
4537 : 1753492 : collapse_stores (modref_summary *cur_summary,
4538 : : modref_summary_lto *cur_summary_lto)
4539 : : {
4540 : 1753492 : bool changed = false;
4541 : :
4542 : 1753492 : if (cur_summary && !cur_summary->stores->every_base)
4543 : : {
4544 : 413872 : cur_summary->stores->collapse ();
4545 : 413872 : changed = true;
4546 : : }
4547 : 1753492 : if (cur_summary_lto
4548 : 43143 : && !cur_summary_lto->stores->every_base)
4549 : : {
4550 : 9567 : cur_summary_lto->stores->collapse ();
4551 : 9567 : changed = true;
4552 : : }
4553 : 1753492 : return changed;
4554 : : }
4555 : :
4556 : : /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
4557 : : CUR_SUMMARY_LTO accordingly. Return true if something changed. */
4558 : :
4559 : : static bool
4560 : 2740317 : propagate_unknown_call (cgraph_node *node,
4561 : : cgraph_edge *e, int ecf_flags,
4562 : : modref_summary *cur_summary,
4563 : : modref_summary_lto *cur_summary_lto,
4564 : : bool nontrivial_scc)
4565 : : {
4566 : 2740317 : bool changed = false;
4567 : 2740317 : class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
4568 : 2740317 : auto_vec <modref_parm_map, 32> parm_map;
4569 : 2740317 : bool looping;
4570 : :
4571 : 2740317 : if (e->callee
4572 : 2740317 : && builtin_safe_for_const_function_p (&looping, e->callee->decl))
4573 : : {
4574 : 246487 : if (looping && cur_summary && !cur_summary->side_effects)
4575 : : {
4576 : 265 : cur_summary->side_effects = true;
4577 : 265 : changed = true;
4578 : : }
4579 : 246487 : if (looping && cur_summary_lto && !cur_summary_lto->side_effects)
4580 : : {
4581 : 45 : cur_summary_lto->side_effects = true;
4582 : 45 : changed = true;
4583 : : }
4584 : 246487 : return changed;
4585 : : }
4586 : :
4587 : 2493830 : if (!(ecf_flags & (ECF_CONST | ECF_PURE))
4588 : 267949 : || (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
4589 : 264616 : || nontrivial_scc)
4590 : : {
4591 : 2229317 : if (cur_summary && !cur_summary->side_effects)
4592 : : {
4593 : 384465 : cur_summary->side_effects = true;
4594 : 384465 : changed = true;
4595 : : }
4596 : 2229317 : if (cur_summary_lto && !cur_summary_lto->side_effects)
4597 : : {
4598 : 19861 : cur_summary_lto->side_effects = true;
4599 : 19861 : changed = true;
4600 : : }
4601 : 2229317 : if (!ignore_nondeterminism_p (node->decl, ecf_flags,
4602 : 2229317 : e->callee ? TREE_TYPE (e->callee->decl)
4603 : : : NULL_TREE))
4604 : : {
4605 : 1837759 : if (cur_summary && !cur_summary->nondeterministic)
4606 : : {
4607 : 349577 : cur_summary->nondeterministic = true;
4608 : 349577 : changed = true;
4609 : : }
4610 : 1837759 : if (cur_summary_lto && !cur_summary_lto->nondeterministic)
4611 : : {
4612 : 5922 : cur_summary_lto->nondeterministic = true;
4613 : 5922 : changed = true;
4614 : : }
4615 : : }
4616 : : }
4617 : 2493830 : if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
4618 : : return changed;
4619 : :
4620 : 2493473 : if (fnspec_sum
4621 : 2493473 : && compute_parm_map (e, &parm_map))
4622 : : {
4623 : 480401 : attr_fnspec fnspec (fnspec_sum->fnspec);
4624 : :
4625 : 480401 : gcc_checking_assert (fnspec.known_p ());
4626 : 480401 : if (fnspec.global_memory_read_p ())
4627 : 0 : collapse_loads (cur_summary, cur_summary_lto);
4628 : : else
4629 : : {
4630 : 480401 : tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4631 : 1066190 : for (unsigned i = 0; i < parm_map.length () && t;
4632 : 585789 : i++, t = TREE_CHAIN (t))
4633 : 843246 : if (!POINTER_TYPE_P (TREE_VALUE (t)))
4634 : : ;
4635 : 643452 : else if (!fnspec.arg_specified_p (i)
4636 : 643452 : || fnspec.arg_maybe_read_p (i))
4637 : : {
4638 : 451764 : modref_parm_map map = parm_map[i];
4639 : 451764 : if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4640 : 29024 : continue;
4641 : 422740 : if (map.parm_index == MODREF_UNKNOWN_PARM)
4642 : : {
4643 : 257457 : collapse_loads (cur_summary, cur_summary_lto);
4644 : 257457 : break;
4645 : : }
4646 : 165283 : if (cur_summary)
4647 : 277006 : changed |= cur_summary->loads->insert
4648 : 138503 : (node->decl, 0, 0,
4649 : 277006 : get_access_for_fnspec (e, fnspec, i, map), false);
4650 : 165283 : if (cur_summary_lto)
4651 : 178190 : changed |= cur_summary_lto->loads->insert
4652 : 89095 : (node->decl, 0, 0,
4653 : 178190 : get_access_for_fnspec (e, fnspec, i, map), false);
4654 : : }
4655 : : }
4656 : 480401 : if (ignore_stores_p (node->decl, ecf_flags))
4657 : : ;
4658 : 253711 : else if (fnspec.global_memory_written_p ())
4659 : 0 : collapse_stores (cur_summary, cur_summary_lto);
4660 : : else
4661 : : {
4662 : 253711 : tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
4663 : 427955 : for (unsigned i = 0; i < parm_map.length () && t;
4664 : 174244 : i++, t = TREE_CHAIN (t))
4665 : 317886 : if (!POINTER_TYPE_P (TREE_VALUE (t)))
4666 : : ;
4667 : 216372 : else if (!fnspec.arg_specified_p (i)
4668 : 216372 : || fnspec.arg_maybe_written_p (i))
4669 : : {
4670 : 195716 : modref_parm_map map = parm_map[i];
4671 : 195716 : if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
4672 : 36542 : continue;
4673 : 159174 : if (map.parm_index == MODREF_UNKNOWN_PARM)
4674 : : {
4675 : 143642 : collapse_stores (cur_summary, cur_summary_lto);
4676 : 143642 : break;
4677 : : }
4678 : 15532 : if (cur_summary)
4679 : 30942 : changed |= cur_summary->stores->insert
4680 : 15471 : (node->decl, 0, 0,
4681 : 30942 : get_access_for_fnspec (e, fnspec, i, map), false);
4682 : 15532 : if (cur_summary_lto)
4683 : 834 : changed |= cur_summary_lto->stores->insert
4684 : 417 : (node->decl, 0, 0,
4685 : 834 : get_access_for_fnspec (e, fnspec, i, map), false);
4686 : : }
4687 : : }
4688 : 480401 : if (fnspec.errno_maybe_written_p () && flag_errno_math)
4689 : : {
4690 : 32727 : if (cur_summary && !cur_summary->writes_errno)
4691 : : {
4692 : 17117 : cur_summary->writes_errno = true;
4693 : 17117 : changed = true;
4694 : : }
4695 : 32727 : if (cur_summary_lto && !cur_summary_lto->writes_errno)
4696 : : {
4697 : 357 : cur_summary_lto->writes_errno = true;
4698 : 357 : changed = true;
4699 : : }
4700 : : }
4701 : 480401 : return changed;
4702 : : }
4703 : 2013072 : if (dump_file)
4704 : 50 : fprintf (dump_file, " collapsing loads\n");
4705 : 2013072 : changed |= collapse_loads (cur_summary, cur_summary_lto);
4706 : 2013072 : if (!ignore_stores_p (node->decl, ecf_flags))
4707 : : {
4708 : 1609850 : if (dump_file)
4709 : 48 : fprintf (dump_file, " collapsing stores\n");
4710 : 1609850 : changed |= collapse_stores (cur_summary, cur_summary_lto);
4711 : : }
4712 : : return changed;
4713 : 2740317 : }
4714 : :
4715 : : /* Maybe remove summaries of NODE pointed to by CUR_SUMMARY_PTR
4716 : : and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
4717 : :
4718 : : static void
4719 : 597629 : remove_useless_summaries (cgraph_node *node,
4720 : : modref_summary **cur_summary_ptr,
4721 : : modref_summary_lto **cur_summary_lto_ptr,
4722 : : int ecf_flags)
4723 : : {
4724 : 597629 : if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
4725 : : {
4726 : 122087 : optimization_summaries->remove (node);
4727 : 122087 : *cur_summary_ptr = NULL;
4728 : : }
4729 : 597629 : if (*cur_summary_lto_ptr
4730 : 597629 : && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
4731 : : {
4732 : 3896 : summaries_lto->remove (node);
4733 : 3896 : *cur_summary_lto_ptr = NULL;
4734 : : }
4735 : 597629 : }
4736 : :
4737 : : /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4738 : : and propagate loads/stores. */
4739 : :
4740 : : static bool
4741 : 2156944 : modref_propagate_in_scc (cgraph_node *component_node)
4742 : : {
4743 : 2156944 : bool changed = true;
4744 : 2156944 : bool first = true;
4745 : 2156944 : int iteration = 0;
4746 : :
4747 : 4982242 : while (changed)
4748 : : {
4749 : 2825298 : bool nontrivial_scc
4750 : 2825298 : = ((struct ipa_dfs_info *) component_node->aux)->next_cycle;
4751 : 2825298 : changed = false;
4752 : 5684419 : for (struct cgraph_node *cur = component_node; cur;
4753 : 2859121 : cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4754 : : {
4755 : 2859121 : cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
4756 : 5718242 : modref_summary *cur_summary = optimization_summaries
4757 : 2859121 : ? optimization_summaries->get (node)
4758 : : : NULL;
4759 : 5718242 : modref_summary_lto *cur_summary_lto = summaries_lto
4760 : 2859121 : ? summaries_lto->get (node)
4761 : : : NULL;
4762 : :
4763 : 2859121 : if (!cur_summary && !cur_summary_lto)
4764 : 721465 : continue;
4765 : :
4766 : 2164486 : int cur_ecf_flags = flags_from_decl_or_type (node->decl);
4767 : :
4768 : 2164486 : if (dump_file)
4769 : 74 : fprintf (dump_file, " Processing %s%s%s\n",
4770 : : cur->dump_name (),
4771 : 74 : TREE_READONLY (cur->decl) ? " (const)" : "",
4772 : 74 : DECL_PURE_P (cur->decl) ? " (pure)" : "");
4773 : :
4774 : 2250799 : for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
4775 : : {
4776 : 113143 : if (dump_file)
4777 : 48 : fprintf (dump_file, " Indirect call\n");
4778 : 113143 : if (propagate_unknown_call
4779 : 113143 : (node, e, e->indirect_info->ecf_flags,
4780 : : cur_summary, cur_summary_lto,
4781 : : nontrivial_scc))
4782 : : {
4783 : 45159 : changed = true;
4784 : 45159 : remove_useless_summaries (node, &cur_summary,
4785 : : &cur_summary_lto,
4786 : : cur_ecf_flags);
4787 : 45159 : if (!cur_summary && !cur_summary_lto)
4788 : : break;
4789 : : }
4790 : : }
4791 : :
4792 : 2164486 : if (!cur_summary && !cur_summary_lto)
4793 : 26830 : continue;
4794 : :
4795 : 8528684 : for (cgraph_edge *callee_edge = cur->callees; callee_edge;
4796 : 6391028 : callee_edge = callee_edge->next_callee)
4797 : : {
4798 : 6488131 : int flags = flags_from_decl_or_type (callee_edge->callee->decl);
4799 : 6488131 : modref_summary *callee_summary = NULL;
4800 : 6488131 : modref_summary_lto *callee_summary_lto = NULL;
4801 : 6488131 : struct cgraph_node *callee;
4802 : :
4803 : 6488131 : if (!callee_edge->inline_failed
4804 : 5636169 : || ((flags & ECF_CONST)
4805 : : && !(flags & ECF_LOOPING_CONST_OR_PURE)))
4806 : 6897337 : continue;
4807 : :
4808 : : /* Get the callee and its summary. */
4809 : 5341138 : enum availability avail;
4810 : 5341138 : callee = callee_edge->callee->ultimate_alias_target
4811 : 5341138 : (&avail, cur);
4812 : :
4813 : : /* It is not necessary to re-process calls outside of the
4814 : : SCC component. */
4815 : 5341138 : if (iteration > 0
4816 : 2063091 : && (!callee->aux
4817 : 501750 : || ((struct ipa_dfs_info *)cur->aux)->scc_no
4818 : 501750 : != ((struct ipa_dfs_info *)callee->aux)->scc_no))
4819 : 2052998 : continue;
4820 : :
4821 : 3288140 : if (dump_file)
4822 : 15 : fprintf (dump_file, " Call to %s\n",
4823 : 15 : callee_edge->callee->dump_name ());
4824 : :
4825 : 3288140 : bool ignore_stores = ignore_stores_p (cur->decl, flags);
4826 : :
4827 : 3288140 : if (avail <= AVAIL_INTERPOSABLE)
4828 : : {
4829 : 2547890 : if (dump_file)
4830 : 5 : fprintf (dump_file, " Call target interposable"
4831 : : " or not available\n");
4832 : 5095780 : changed |= propagate_unknown_call
4833 : 2547890 : (node, callee_edge, flags,
4834 : : cur_summary, cur_summary_lto,
4835 : : nontrivial_scc);
4836 : 2547890 : if (!cur_summary && !cur_summary_lto)
4837 : : break;
4838 : 2547890 : continue;
4839 : : }
4840 : :
4841 : : /* We don't know anything about CALLEE, hence we cannot tell
4842 : : anything about the entire component. */
4843 : :
4844 : 740250 : if (cur_summary
4845 : 740250 : && !(callee_summary = optimization_summaries->get (callee)))
4846 : : {
4847 : 78003 : if (dump_file)
4848 : 0 : fprintf (dump_file, " No call target summary\n");
4849 : 78003 : changed |= propagate_unknown_call
4850 : 78003 : (node, callee_edge, flags,
4851 : : cur_summary, NULL,
4852 : : nontrivial_scc);
4853 : : }
4854 : 740250 : if (cur_summary_lto
4855 : 740250 : && !(callee_summary_lto = summaries_lto->get (callee)))
4856 : : {
4857 : 1281 : if (dump_file)
4858 : 0 : fprintf (dump_file, " No call target summary\n");
4859 : 1281 : changed |= propagate_unknown_call
4860 : 1281 : (node, callee_edge, flags,
4861 : : NULL, cur_summary_lto,
4862 : : nontrivial_scc);
4863 : : }
4864 : :
4865 : 576377 : if (callee_summary && !cur_summary->side_effects
4866 : 848500 : && (callee_summary->side_effects
4867 : 62499 : || callee_edge->recursive_p ()))
4868 : : {
4869 : 46701 : cur_summary->side_effects = true;
4870 : 46701 : changed = true;
4871 : : }
4872 : 183899 : if (callee_summary_lto && !cur_summary_lto->side_effects
4873 : 763210 : && (callee_summary_lto->side_effects
4874 : 20802 : || callee_edge->recursive_p ()))
4875 : : {
4876 : 2216 : cur_summary_lto->side_effects = true;
4877 : 2216 : changed = true;
4878 : : }
4879 : 576377 : if (callee_summary && !cur_summary->nondeterministic
4880 : 179290 : && callee_summary->nondeterministic
4881 : 780287 : && !ignore_nondeterminism_p
4882 : 40037 : (cur->decl, flags,
4883 : 40037 : TREE_TYPE (callee_edge->callee->decl)))
4884 : : {
4885 : 38602 : cur_summary->nondeterministic = true;
4886 : 38602 : changed = true;
4887 : : }
4888 : 183899 : if (callee_summary_lto && !cur_summary_lto->nondeterministic
4889 : 62395 : && callee_summary_lto->nondeterministic
4890 : 742659 : && !ignore_nondeterminism_p
4891 : 2409 : (cur->decl, flags,
4892 : 2409 : TREE_TYPE (callee_edge->callee->decl)))
4893 : : {
4894 : 2053 : cur_summary_lto->nondeterministic = true;
4895 : 2053 : changed = true;
4896 : : }
4897 : 740250 : if (flags & (ECF_CONST | ECF_NOVOPS))
4898 : 2463 : continue;
4899 : :
4900 : : /* We can not safely optimize based on summary of callee if it
4901 : : does not always bind to current def: it is possible that
4902 : : memory load was optimized out earlier which may not happen in
4903 : : the interposed variant. */
4904 : 737787 : if (!callee_edge->binds_to_current_def_p ())
4905 : : {
4906 : 121817 : if (cur_summary && !cur_summary->calls_interposable)
4907 : : {
4908 : 37825 : cur_summary->calls_interposable = true;
4909 : 37825 : changed = true;
4910 : : }
4911 : 121817 : if (cur_summary_lto && !cur_summary_lto->calls_interposable)
4912 : : {
4913 : 54 : cur_summary_lto->calls_interposable = true;
4914 : 54 : changed = true;
4915 : : }
4916 : 121817 : if (dump_file)
4917 : 0 : fprintf (dump_file, " May not bind local;"
4918 : : " collapsing loads\n");
4919 : : }
4920 : :
4921 : :
4922 : 737787 : auto_vec <modref_parm_map, 32> parm_map;
4923 : 737787 : modref_parm_map chain_map;
4924 : : /* TODO: Once we get jump functions for static chains we could
4925 : : compute this. */
4926 : 737787 : chain_map.parm_index = MODREF_UNKNOWN_PARM;
4927 : :
4928 : 737787 : compute_parm_map (callee_edge, &parm_map);
4929 : :
4930 : : /* Merge in callee's information. */
4931 : 737787 : if (callee_summary)
4932 : : {
4933 : 1148076 : changed |= cur_summary->loads->merge
4934 : 574038 : (node->decl, callee_summary->loads,
4935 : 574038 : &parm_map, &chain_map, !first);
4936 : 574038 : if (!ignore_stores)
4937 : : {
4938 : 1065652 : changed |= cur_summary->stores->merge
4939 : 532826 : (node->decl, callee_summary->stores,
4940 : : &parm_map, &chain_map, !first);
4941 : 532826 : if (!cur_summary->writes_errno
4942 : 453731 : && callee_summary->writes_errno)
4943 : : {
4944 : 12899 : cur_summary->writes_errno = true;
4945 : 12899 : changed = true;
4946 : : }
4947 : : }
4948 : : }
4949 : 737787 : if (callee_summary_lto)
4950 : : {
4951 : 367522 : changed |= cur_summary_lto->loads->merge
4952 : 183761 : (node->decl, callee_summary_lto->loads,
4953 : 183761 : &parm_map, &chain_map, !first);
4954 : 183761 : if (!ignore_stores)
4955 : : {
4956 : 354964 : changed |= cur_summary_lto->stores->merge
4957 : 177482 : (node->decl, callee_summary_lto->stores,
4958 : : &parm_map, &chain_map, !first);
4959 : 177482 : if (!cur_summary_lto->writes_errno
4960 : 177440 : && callee_summary_lto->writes_errno)
4961 : : {
4962 : 87 : cur_summary_lto->writes_errno = true;
4963 : 87 : changed = true;
4964 : : }
4965 : : }
4966 : : }
4967 : 737787 : if (changed)
4968 : 552470 : remove_useless_summaries (node, &cur_summary,
4969 : : &cur_summary_lto,
4970 : : cur_ecf_flags);
4971 : 737787 : if (!cur_summary && !cur_summary_lto)
4972 : : break;
4973 : 640684 : if (dump_file && changed)
4974 : : {
4975 : 10 : if (cur_summary)
4976 : 6 : cur_summary->dump (dump_file);
4977 : 10 : if (cur_summary_lto)
4978 : 4 : cur_summary_lto->dump (dump_file);
4979 : 10 : dump_modref_edge_summaries (dump_file, node, 4);
4980 : : }
4981 : 737787 : }
4982 : : }
4983 : 2825298 : iteration++;
4984 : 2825298 : first = false;
4985 : : }
4986 : 2156944 : if (dump_file)
4987 : 58 : fprintf (dump_file,
4988 : : "Propagation finished in %i iterations\n", iteration);
4989 : : bool pureconst = false;
4990 : 4332376 : for (struct cgraph_node *cur = component_node; cur;
4991 : 2175432 : cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
4992 : 2175432 : if (!cur->inlined_to && opt_for_fn (cur->decl, flag_ipa_pure_const))
4993 : : {
4994 : 2053160 : modref_summary *summary = optimization_summaries
4995 : 1026580 : ? optimization_summaries->get (cur)
4996 : : : NULL;
4997 : 2053160 : modref_summary_lto *summary_lto = summaries_lto
4998 : 1026580 : ? summaries_lto->get (cur)
4999 : : : NULL;
5000 : 1026580 : if (summary && !summary->stores->every_base && !summary->stores->bases
5001 : 154224 : && !summary->nondeterministic)
5002 : : {
5003 : 142926 : if (!summary->loads->every_base && !summary->loads->bases
5004 : 66731 : && !summary->calls_interposable)
5005 : 66349 : pureconst |= ipa_make_function_const
5006 : 66349 : (cur, summary->side_effects, false);
5007 : : else
5008 : 76577 : pureconst |= ipa_make_function_pure
5009 : 76577 : (cur, summary->side_effects, false);
5010 : : }
5011 : 1026580 : if (summary_lto && !summary_lto->stores->every_base
5012 : 47816 : && !summary_lto->stores->bases && !summary_lto->nondeterministic)
5013 : : {
5014 : 12709 : if (!summary_lto->loads->every_base && !summary_lto->loads->bases
5015 : 3133 : && !summary_lto->calls_interposable)
5016 : 3131 : pureconst |= ipa_make_function_const
5017 : 3131 : (cur, summary_lto->side_effects, false);
5018 : : else
5019 : 9578 : pureconst |= ipa_make_function_pure
5020 : 9578 : (cur, summary_lto->side_effects, false);
5021 : : }
5022 : : }
5023 : 2156944 : return pureconst;
5024 : : }
5025 : :
5026 : : /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
5027 : :
5028 : : static void
5029 : 58 : modref_propagate_dump_scc (cgraph_node *component_node)
5030 : : {
5031 : 116 : for (struct cgraph_node *cur = component_node; cur;
5032 : 58 : cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5033 : 58 : if (!cur->inlined_to)
5034 : : {
5035 : 94 : modref_summary *cur_summary = optimization_summaries
5036 : 47 : ? optimization_summaries->get (cur)
5037 : : : NULL;
5038 : 94 : modref_summary_lto *cur_summary_lto = summaries_lto
5039 : 47 : ? summaries_lto->get (cur)
5040 : : : NULL;
5041 : :
5042 : 47 : fprintf (dump_file, "Propagated modref for %s%s%s\n",
5043 : : cur->dump_name (),
5044 : 47 : TREE_READONLY (cur->decl) ? " (const)" : "",
5045 : 47 : DECL_PURE_P (cur->decl) ? " (pure)" : "");
5046 : 47 : if (optimization_summaries)
5047 : : {
5048 : 41 : if (cur_summary)
5049 : 35 : cur_summary->dump (dump_file);
5050 : : else
5051 : 6 : fprintf (dump_file, " Not tracked\n");
5052 : : }
5053 : 47 : if (summaries_lto)
5054 : : {
5055 : 10 : if (cur_summary_lto)
5056 : 10 : cur_summary_lto->dump (dump_file);
5057 : : else
5058 : 0 : fprintf (dump_file, " Not tracked (lto)\n");
5059 : : }
5060 : : }
5061 : 58 : }
5062 : :
5063 : : /* Determine EAF flags know for call E with CALLEE_ECF_FLAGS and ARG. */
5064 : :
5065 : : int
5066 : 214548 : implicit_eaf_flags_for_edge_and_arg (cgraph_edge *e, int callee_ecf_flags,
5067 : : bool ignore_stores, int arg)
5068 : : {
5069 : : /* Returning the value is already accounted to at local propagation. */
5070 : 214548 : int implicit_flags = EAF_NOT_RETURNED_DIRECTLY
5071 : : | EAF_NOT_RETURNED_INDIRECTLY;
5072 : 214548 : if (ignore_stores)
5073 : 99593 : implicit_flags |= ignore_stores_eaf_flags;
5074 : 214548 : if (callee_ecf_flags & ECF_PURE)
5075 : 94963 : implicit_flags |= implicit_pure_eaf_flags;
5076 : 214548 : if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
5077 : 482 : implicit_flags |= implicit_const_eaf_flags;
5078 : 214548 : class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
5079 : 214548 : if (fnspec_sum)
5080 : : {
5081 : 86678 : attr_fnspec fnspec (fnspec_sum->fnspec);
5082 : 86678 : implicit_flags |= fnspec.arg_eaf_flags (arg);
5083 : : }
5084 : 214548 : return implicit_flags;
5085 : : }
5086 : :
5087 : : /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
5088 : : and SUMMARY_LTO to CUR_SUMMARY_LTO.
5089 : : Return true if something changed. */
5090 : :
5091 : : static bool
5092 : 120783 : modref_merge_call_site_flags (escape_summary *sum,
5093 : : modref_summary *cur_summary,
5094 : : modref_summary_lto *cur_summary_lto,
5095 : : modref_summary *summary,
5096 : : modref_summary_lto *summary_lto,
5097 : : tree caller,
5098 : : cgraph_edge *e,
5099 : : int caller_ecf_flags,
5100 : : int callee_ecf_flags,
5101 : : bool binds_to_current_def)
5102 : : {
5103 : 120783 : escape_entry *ee;
5104 : 120783 : unsigned int i;
5105 : 120783 : bool changed = false;
5106 : 120783 : bool ignore_stores = ignore_stores_p (caller, callee_ecf_flags);
5107 : :
5108 : : /* Return early if we have no useful info to propagate. */
5109 : 120783 : if ((!cur_summary
5110 : 99366 : || (!cur_summary->arg_flags.length ()
5111 : : && !cur_summary->static_chain_flags
5112 : 549 : && !cur_summary->retslot_flags))
5113 : 120788 : && (!cur_summary_lto
5114 : 21417 : || (!cur_summary_lto->arg_flags.length ()
5115 : : && !cur_summary_lto->static_chain_flags
5116 : 29 : && !cur_summary_lto->retslot_flags)))
5117 : : return false;
5118 : :
5119 : 255245 : FOR_EACH_VEC_ELT (sum->esc, i, ee)
5120 : : {
5121 : 134467 : int flags = 0;
5122 : 134467 : int flags_lto = 0;
5123 : 134467 : int implicit_flags = implicit_eaf_flags_for_edge_and_arg
5124 : 134467 : (e, callee_ecf_flags, ignore_stores, ee->arg);
5125 : :
5126 : 134467 : if (summary && ee->arg < summary->arg_flags.length ())
5127 : 29684 : flags = summary->arg_flags[ee->arg];
5128 : 134467 : if (summary_lto
5129 : 134467 : && ee->arg < summary_lto->arg_flags.length ())
5130 : 801 : flags_lto = summary_lto->arg_flags[ee->arg];
5131 : 134467 : if (!ee->direct)
5132 : : {
5133 : 26195 : flags = deref_flags (flags, ignore_stores);
5134 : 26195 : flags_lto = deref_flags (flags_lto, ignore_stores);
5135 : : }
5136 : 134467 : if (ignore_stores)
5137 : 87651 : implicit_flags |= ignore_stores_eaf_flags;
5138 : 134467 : if (callee_ecf_flags & ECF_PURE)
5139 : 83315 : implicit_flags |= implicit_pure_eaf_flags;
5140 : 134467 : if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
5141 : 482 : implicit_flags |= implicit_const_eaf_flags;
5142 : 134467 : class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
5143 : 134467 : if (fnspec_sum)
5144 : : {
5145 : 86678 : attr_fnspec fnspec (fnspec_sum->fnspec);
5146 : 86678 : implicit_flags |= fnspec.arg_eaf_flags (ee->arg);
5147 : : }
5148 : 134467 : if (!ee->direct)
5149 : 26195 : implicit_flags = deref_flags (implicit_flags, ignore_stores);
5150 : 134467 : flags |= implicit_flags;
5151 : 134467 : flags_lto |= implicit_flags;
5152 : 134467 : if (!binds_to_current_def && (flags || flags_lto))
5153 : : {
5154 : 112647 : flags = interposable_eaf_flags (flags, implicit_flags);
5155 : 112647 : flags_lto = interposable_eaf_flags (flags_lto, implicit_flags);
5156 : : }
5157 : 134467 : if (!(flags & EAF_UNUSED)
5158 : 245726 : && cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ())
5159 : : {
5160 : 111809 : eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5161 : 111809 : ? cur_summary->retslot_flags
5162 : : : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5163 : : ? cur_summary->static_chain_flags
5164 : 110917 : : cur_summary->arg_flags[ee->parm_index];
5165 : 111809 : if ((f & flags) != f)
5166 : : {
5167 : 96746 : f = remove_useless_eaf_flags
5168 : 48373 : (f & flags, caller_ecf_flags,
5169 : 48373 : VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
5170 : 48373 : changed = true;
5171 : : }
5172 : : }
5173 : 134467 : if (!(flags_lto & EAF_UNUSED)
5174 : 134467 : && cur_summary_lto
5175 : 221241 : && ee->parm_index < (int)cur_summary_lto->arg_flags.length ())
5176 : : {
5177 : 43418 : eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5178 : 43418 : ? cur_summary_lto->retslot_flags
5179 : : : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5180 : : ? cur_summary_lto->static_chain_flags
5181 : 43314 : : cur_summary_lto->arg_flags[ee->parm_index];
5182 : 43418 : if ((f & flags_lto) != f)
5183 : : {
5184 : 3332 : f = remove_useless_eaf_flags
5185 : 1666 : (f & flags_lto, caller_ecf_flags,
5186 : 1666 : VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
5187 : 1666 : changed = true;
5188 : : }
5189 : : }
5190 : : }
5191 : : return changed;
5192 : : }
5193 : :
5194 : : /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
5195 : : and propagate arg flags. */
5196 : :
5197 : : static void
5198 : 2156944 : modref_propagate_flags_in_scc (cgraph_node *component_node)
5199 : : {
5200 : 2156944 : bool changed = true;
5201 : 2156944 : int iteration = 0;
5202 : :
5203 : 4351994 : while (changed)
5204 : : {
5205 : : changed = false;
5206 : 4409041 : for (struct cgraph_node *cur = component_node; cur;
5207 : 2213991 : cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5208 : : {
5209 : 2213991 : cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
5210 : 4427982 : modref_summary *cur_summary = optimization_summaries
5211 : 2213991 : ? optimization_summaries->get (node)
5212 : : : NULL;
5213 : 4427982 : modref_summary_lto *cur_summary_lto = summaries_lto
5214 : 2213991 : ? summaries_lto->get (node)
5215 : : : NULL;
5216 : :
5217 : 2213991 : if (!cur_summary && !cur_summary_lto)
5218 : 693068 : continue;
5219 : 1520923 : int caller_ecf_flags = flags_from_decl_or_type (cur->decl);
5220 : :
5221 : 1520923 : if (dump_file)
5222 : 55 : fprintf (dump_file, " Processing %s%s%s\n",
5223 : : cur->dump_name (),
5224 : 55 : TREE_READONLY (cur->decl) ? " (const)" : "",
5225 : 55 : DECL_PURE_P (cur->decl) ? " (pure)" : "");
5226 : :
5227 : 1581889 : for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
5228 : : {
5229 : 60966 : escape_summary *sum = escape_summaries->get (e);
5230 : :
5231 : 60966 : if (!sum || ((e->indirect_info->ecf_flags & ECF_CONST)
5232 : 220 : && !(e->indirect_info->ecf_flags & ECF_LOOPING_CONST_OR_PURE)))
5233 : 60746 : continue;
5234 : :
5235 : 220 : changed |= modref_merge_call_site_flags
5236 : 220 : (sum, cur_summary, cur_summary_lto,
5237 : : NULL, NULL,
5238 : : node->decl,
5239 : : e,
5240 : : caller_ecf_flags,
5241 : : e->indirect_info->ecf_flags,
5242 : : false);
5243 : : }
5244 : :
5245 : 1520923 : if (!cur_summary && !cur_summary_lto)
5246 : : continue;
5247 : :
5248 : 5916037 : for (cgraph_edge *callee_edge = cur->callees; callee_edge;
5249 : 4395114 : callee_edge = callee_edge->next_callee)
5250 : : {
5251 : 4395114 : int ecf_flags = flags_from_decl_or_type
5252 : 4395114 : (callee_edge->callee->decl);
5253 : 4395114 : modref_summary *callee_summary = NULL;
5254 : 4395114 : modref_summary_lto *callee_summary_lto = NULL;
5255 : 4395114 : struct cgraph_node *callee;
5256 : :
5257 : 4395114 : if ((ecf_flags & ECF_CONST)
5258 : : && !(ecf_flags & ECF_LOOPING_CONST_OR_PURE))
5259 : 4274551 : continue;
5260 : :
5261 : : /* Get the callee and its summary. */
5262 : 4188413 : enum availability avail;
5263 : 4188413 : callee = callee_edge->callee->ultimate_alias_target
5264 : 4188413 : (&avail, cur);
5265 : :
5266 : : /* It is not necessary to re-process calls outside of the
5267 : : SCC component. */
5268 : 4188413 : if (iteration > 0
5269 : 380943 : && (!callee->aux
5270 : 234240 : || ((struct ipa_dfs_info *)cur->aux)->scc_no
5271 : 234240 : != ((struct ipa_dfs_info *)callee->aux)->scc_no))
5272 : 379488 : continue;
5273 : :
5274 : 3808925 : escape_summary *sum = escape_summaries->get (callee_edge);
5275 : 3808925 : if (!sum)
5276 : 3688362 : continue;
5277 : :
5278 : 120563 : if (dump_file)
5279 : 3 : fprintf (dump_file, " Call to %s\n",
5280 : 3 : callee_edge->callee->dump_name ());
5281 : :
5282 : 120563 : if (avail <= AVAIL_INTERPOSABLE
5283 : 24439 : || callee_edge->call_stmt_cannot_inline_p)
5284 : : ;
5285 : : else
5286 : : {
5287 : 24439 : if (cur_summary)
5288 : 24169 : callee_summary = optimization_summaries->get (callee);
5289 : 24439 : if (cur_summary_lto)
5290 : 590 : callee_summary_lto = summaries_lto->get (callee);
5291 : : }
5292 : 241126 : changed |= modref_merge_call_site_flags
5293 : 120563 : (sum, cur_summary, cur_summary_lto,
5294 : : callee_summary, callee_summary_lto,
5295 : : node->decl,
5296 : : callee_edge,
5297 : : caller_ecf_flags,
5298 : : ecf_flags,
5299 : 120563 : callee->binds_to_current_def_p ());
5300 : 120563 : if (dump_file && changed)
5301 : : {
5302 : 3 : if (cur_summary)
5303 : 3 : cur_summary->dump (dump_file);
5304 : 3 : if (cur_summary_lto)
5305 : 0 : cur_summary_lto->dump (dump_file);
5306 : : }
5307 : : }
5308 : : }
5309 : 2195050 : iteration++;
5310 : : }
5311 : 2156944 : if (dump_file)
5312 : 58 : fprintf (dump_file,
5313 : : "Propagation of flags finished in %i iterations\n", iteration);
5314 : 2156944 : }
5315 : :
5316 : : } /* ANON namespace. */
5317 : :
5318 : : /* Call EDGE was inlined; merge summary from callee to the caller. */
5319 : :
5320 : : void
5321 : 3427415 : ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
5322 : : {
5323 : 3427415 : if (!summaries && !summaries_lto)
5324 : : return;
5325 : :
5326 : 1607816 : struct cgraph_node *to = (edge->caller->inlined_to
5327 : 803908 : ? edge->caller->inlined_to : edge->caller);
5328 : 803908 : class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
5329 : 1607816 : class modref_summary_lto *to_info_lto = summaries_lto
5330 : 803908 : ? summaries_lto->get (to) : NULL;
5331 : :
5332 : 803908 : if (!to_info && !to_info_lto)
5333 : : {
5334 : 100137 : if (summaries)
5335 : 99668 : summaries->remove (edge->callee);
5336 : 100137 : if (summaries_lto)
5337 : 885 : summaries_lto->remove (edge->callee);
5338 : 100137 : remove_modref_edge_summaries (edge->callee);
5339 : 100137 : return;
5340 : : }
5341 : :
5342 : 703771 : class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
5343 : : : NULL;
5344 : 1407542 : class modref_summary_lto *callee_info_lto
5345 : 703771 : = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
5346 : 703771 : int flags = flags_from_decl_or_type (edge->callee->decl);
5347 : : /* Combine in outer flags. */
5348 : 703771 : cgraph_node *n;
5349 : 1084532 : for (n = edge->caller; n->inlined_to; n = n->callers->caller)
5350 : 380761 : flags |= flags_from_decl_or_type (n->decl);
5351 : 703771 : flags |= flags_from_decl_or_type (n->decl);
5352 : 703771 : bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
5353 : :
5354 : 703771 : if (!callee_info && to_info)
5355 : : {
5356 : 9234 : if (!(flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
5357 : 6891 : to_info->loads->collapse ();
5358 : 9234 : if (!ignore_stores)
5359 : 6784 : to_info->stores->collapse ();
5360 : : }
5361 : 703771 : if (!callee_info_lto && to_info_lto)
5362 : : {
5363 : 246 : if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5364 : 133 : to_info_lto->loads->collapse ();
5365 : 246 : if (!ignore_stores)
5366 : 105 : to_info_lto->stores->collapse ();
5367 : : }
5368 : : /* Merge side effects and non-determinism.
5369 : : PURE/CONST flags makes functions deterministic and if there is
5370 : : no LOOPING_CONST_OR_PURE they also have no side effects. */
5371 : 703771 : if (!(flags & (ECF_CONST | ECF_PURE))
5372 : 86227 : || (flags & ECF_LOOPING_CONST_OR_PURE))
5373 : : {
5374 : 639736 : bool set_nondeterministic
5375 : : = !ignore_nondeterminism_p
5376 : 639736 : (edge->caller->decl, flags,
5377 : 639736 : TREE_TYPE (edge->callee->decl));
5378 : 639736 : if (to_info)
5379 : : {
5380 : 626098 : if (!callee_info || callee_info->side_effects)
5381 : 52471 : to_info->side_effects = true;
5382 : 626098 : if (set_nondeterministic)
5383 : 597479 : to_info->nondeterministic = true;
5384 : : }
5385 : 639736 : if (to_info_lto)
5386 : : {
5387 : 28288 : if (!callee_info_lto || callee_info_lto->side_effects)
5388 : 20946 : to_info_lto->side_effects = true;
5389 : 28288 : if (set_nondeterministic)
5390 : 26841 : to_info_lto->nondeterministic = true;
5391 : : }
5392 : : }
5393 : 703771 : if (callee_info || callee_info_lto)
5394 : : {
5395 : 694378 : auto_vec <modref_parm_map, 32> parm_map;
5396 : 694378 : modref_parm_map chain_map;
5397 : : /* TODO: Once we get jump functions for static chains we could
5398 : : compute parm_index. */
5399 : :
5400 : 694378 : compute_parm_map (edge, &parm_map);
5401 : :
5402 : 694378 : if (!ignore_stores)
5403 : : {
5404 : 603559 : if (to_info && callee_info)
5405 : 590695 : to_info->stores->merge (to->decl, callee_info->stores, &parm_map,
5406 : : &chain_map, false);
5407 : 603559 : if (to_info_lto && callee_info_lto)
5408 : 26736 : to_info_lto->stores->merge (to->decl, callee_info_lto->stores,
5409 : : &parm_map, &chain_map, false);
5410 : : }
5411 : 694378 : if (!(flags & (ECF_CONST | ECF_NOVOPS)))
5412 : : {
5413 : 685093 : if (to_info && callee_info)
5414 : 670578 : to_info->loads->merge (to->decl, callee_info->loads, &parm_map,
5415 : : &chain_map, false);
5416 : 685093 : if (to_info_lto && callee_info_lto)
5417 : 30606 : to_info_lto->loads->merge (to->decl, callee_info_lto->loads,
5418 : : &parm_map, &chain_map, false);
5419 : : }
5420 : 694378 : }
5421 : :
5422 : : /* Now merge escape summaries.
5423 : : For every escape to the callee we need to merge callee flags
5424 : : and remap callee's escapes. */
5425 : 703771 : class escape_summary *sum = escape_summaries->get (edge);
5426 : 703771 : int max_escape = -1;
5427 : 703771 : escape_entry *ee;
5428 : 703771 : unsigned int i;
5429 : :
5430 : 703771 : if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
5431 : 144706 : FOR_EACH_VEC_ELT (sum->esc, i, ee)
5432 : 80081 : if ((int)ee->arg > max_escape)
5433 : : max_escape = ee->arg;
5434 : :
5435 : 703771 : auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
5436 : 703771 : emap.safe_grow (max_escape + 1, true);
5437 : 1523580 : for (i = 0; (int)i < max_escape + 1; i++)
5438 : 116038 : emap[i] = vNULL;
5439 : :
5440 : 703771 : if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
5441 : 144706 : FOR_EACH_VEC_ELT (sum->esc, i, ee)
5442 : : {
5443 : 80081 : bool needed = false;
5444 : 80081 : int implicit_flags = implicit_eaf_flags_for_edge_and_arg
5445 : 160162 : (edge, flags, ignore_stores,
5446 : 80081 : ee->arg);
5447 : 80081 : if (!ee->direct)
5448 : 14081 : implicit_flags = deref_flags (implicit_flags, ignore_stores);
5449 : 159585 : if (to_info && (int)to_info->arg_flags.length () > ee->parm_index)
5450 : : {
5451 : 79628 : int flags = callee_info
5452 : 79556 : && callee_info->arg_flags.length () > ee->arg
5453 : 150413 : ? callee_info->arg_flags[ee->arg] : 0;
5454 : 79628 : if (!ee->direct)
5455 : 14064 : flags = deref_flags (flags, ignore_stores);
5456 : 79628 : flags |= ee->min_flags | implicit_flags;
5457 : 79628 : eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5458 : 79628 : ? to_info->retslot_flags
5459 : : : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5460 : : ? to_info->static_chain_flags
5461 : 78932 : : to_info->arg_flags[ee->parm_index];
5462 : 79628 : f &= flags;
5463 : 79628 : if (f)
5464 : 80081 : needed = true;
5465 : : }
5466 : 80081 : if (to_info_lto
5467 : 80858 : && (int)to_info_lto->arg_flags.length () > ee->parm_index)
5468 : : {
5469 : 779 : int flags = callee_info_lto
5470 : 779 : && callee_info_lto->arg_flags.length () > ee->arg
5471 : 1541 : ? callee_info_lto->arg_flags[ee->arg] : 0;
5472 : 779 : if (!ee->direct)
5473 : 55 : flags = deref_flags (flags, ignore_stores);
5474 : 779 : flags |= ee->min_flags | implicit_flags;
5475 : 779 : eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
5476 : 779 : ? to_info_lto->retslot_flags
5477 : : : ee->parm_index == MODREF_STATIC_CHAIN_PARM
5478 : : ? to_info_lto->static_chain_flags
5479 : 767 : : to_info_lto->arg_flags[ee->parm_index];
5480 : 779 : f &= flags;
5481 : 779 : if (f)
5482 : 80081 : needed = true;
5483 : : }
5484 : 80081 : struct escape_map entry = {ee->parm_index, ee->direct};
5485 : 80081 : if (needed)
5486 : 79620 : emap[ee->arg].safe_push (entry);
5487 : : }
5488 : 703771 : update_escape_summary (edge->callee, emap, ignore_stores);
5489 : 1523580 : for (i = 0; (int)i < max_escape + 1; i++)
5490 : 116038 : emap[i].release ();
5491 : 703771 : if (sum)
5492 : 64627 : escape_summaries->remove (edge);
5493 : :
5494 : 703771 : if (summaries)
5495 : : {
5496 : 688904 : if (to_info && !to_info->useful_p (flags))
5497 : : {
5498 : 14273 : if (dump_file)
5499 : 11 : fprintf (dump_file, "Removed mod-ref summary for %s\n",
5500 : : to->dump_name ());
5501 : 14273 : summaries->remove (to);
5502 : 14273 : to_info = NULL;
5503 : : }
5504 : 674631 : else if (to_info && dump_file)
5505 : : {
5506 : 436 : if (dump_file)
5507 : 436 : fprintf (dump_file, "Updated mod-ref summary for %s\n",
5508 : : to->dump_name ());
5509 : 436 : to_info->dump (dump_file);
5510 : : }
5511 : 688904 : if (callee_info)
5512 : 679670 : summaries->remove (edge->callee);
5513 : : }
5514 : 703771 : if (summaries_lto)
5515 : : {
5516 : 31958 : if (to_info_lto && !to_info_lto->useful_p (flags))
5517 : : {
5518 : 569 : if (dump_file)
5519 : 1 : fprintf (dump_file, "Removed mod-ref summary for %s\n",
5520 : : to->dump_name ());
5521 : 569 : summaries_lto->remove (to);
5522 : 569 : to_info_lto = NULL;
5523 : : }
5524 : 31389 : else if (to_info_lto && dump_file)
5525 : : {
5526 : 3 : if (dump_file)
5527 : 3 : fprintf (dump_file, "Updated mod-ref summary for %s\n",
5528 : : to->dump_name ());
5529 : 3 : to_info_lto->dump (dump_file);
5530 : : }
5531 : 31958 : if (callee_info_lto)
5532 : 31712 : summaries_lto->remove (edge->callee);
5533 : : }
5534 : 703771 : if (!to_info && !to_info_lto)
5535 : 14609 : remove_modref_edge_summaries (to);
5536 : 703771 : return;
5537 : 703771 : }
5538 : :
5539 : : /* Run the IPA pass. This will take a function's summaries and calls and
5540 : : construct new summaries which represent a transitive closure. So that
5541 : : summary of an analyzed function contains information about the loads and
5542 : : stores that the function or any function that it calls does. */
5543 : :
5544 : : unsigned int
5545 : 225234 : pass_ipa_modref::execute (function *)
5546 : : {
5547 : 225234 : if (!summaries && !summaries_lto)
5548 : : return 0;
5549 : 141525 : bool pureconst = false;
5550 : :
5551 : 141525 : if (optimization_summaries)
5552 : 128709 : ggc_delete (optimization_summaries);
5553 : 141525 : optimization_summaries = summaries;
5554 : 141525 : summaries = NULL;
5555 : :
5556 : 141525 : struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
5557 : : symtab->cgraph_count);
5558 : 141525 : int order_pos;
5559 : 141525 : order_pos = ipa_reduced_postorder (order, true, ignore_edge);
5560 : 141525 : int i;
5561 : :
5562 : : /* Iterate over all strongly connected components in post-order. */
5563 : 2298469 : for (i = 0; i < order_pos; i++)
5564 : : {
5565 : : /* Get the component's representative. That's just any node in the
5566 : : component from which we can traverse the entire component. */
5567 : 2156944 : struct cgraph_node *component_node = order[i];
5568 : :
5569 : 2156944 : if (dump_file)
5570 : 58 : fprintf (dump_file, "\n\nStart of SCC component\n");
5571 : :
5572 : 2156944 : pureconst |= modref_propagate_in_scc (component_node);
5573 : 2156944 : modref_propagate_flags_in_scc (component_node);
5574 : 2156944 : if (optimization_summaries)
5575 : 4204213 : for (struct cgraph_node *cur = component_node; cur;
5576 : 2111314 : cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
5577 : 2111314 : if (modref_summary *sum = optimization_summaries->get (cur))
5578 : 692404 : sum->finalize (cur->decl);
5579 : 2156944 : if (dump_file)
5580 : 58 : modref_propagate_dump_scc (component_node);
5581 : : }
5582 : 141525 : cgraph_node *node;
5583 : 6386386 : FOR_EACH_FUNCTION (node)
5584 : 3051668 : update_signature (node);
5585 : 141525 : if (summaries_lto)
5586 : 18632 : ((modref_summaries_lto *)summaries_lto)->propagated = true;
5587 : 141525 : ipa_free_postorder_info ();
5588 : 141525 : free (order);
5589 : 141525 : delete fnspec_summaries;
5590 : 141525 : fnspec_summaries = NULL;
5591 : 141525 : delete escape_summaries;
5592 : 141525 : escape_summaries = NULL;
5593 : :
5594 : : /* If we possibly made constructors const/pure we may need to remove
5595 : : them. */
5596 : 141525 : return pureconst ? TODO_remove_functions : 0;
5597 : : }
5598 : :
5599 : : /* Summaries must stay alive until end of compilation. */
5600 : :
5601 : : void
5602 : 253153 : ipa_modref_cc_finalize ()
5603 : : {
5604 : 253153 : if (optimization_summaries)
5605 : 150353 : ggc_delete (optimization_summaries);
5606 : 253153 : optimization_summaries = NULL;
5607 : 253153 : if (summaries_lto)
5608 : 27222 : ggc_delete (summaries_lto);
5609 : 253153 : summaries_lto = NULL;
5610 : 253153 : if (fnspec_summaries)
5611 : 8599 : delete fnspec_summaries;
5612 : 253153 : fnspec_summaries = NULL;
5613 : 253153 : if (escape_summaries)
5614 : 8599 : delete escape_summaries;
5615 : 253153 : escape_summaries = NULL;
5616 : 253153 : }
5617 : :
5618 : : /* Return true if call is known to perform no memory reads. */
5619 : :
5620 : : bool
5621 : 30700745 : ipa_modref_callee_reads_no_memory_p (gcall *call)
5622 : : {
5623 : 30700745 : if (gimple_call_flags (call) & ECF_CONST)
5624 : : return true;
5625 : 30680054 : attr_fnspec fnspec = gimple_call_fnspec (call);
5626 : 30680054 : if (fnspec.known_p ()
5627 : 30680054 : && !fnspec.global_memory_read_p ())
5628 : : {
5629 : : bool found = false;
5630 : 7062355 : for (unsigned int i = 0; i < gimple_call_num_args (call) && !found; i++)
5631 : 4004042 : if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
5632 : : ;
5633 : 3003622 : else if (!fnspec.arg_specified_p (i)
5634 : 3003622 : || fnspec.arg_maybe_read_p (i))
5635 : : found = true;
5636 : 3058313 : if (!found)
5637 : : return true;
5638 : : }
5639 : :
5640 : : /* For interposed calls we can not be sure that the other, semantically
5641 : : equivalent body, will not perform some redundant load from memory
5642 : : that may become undefined if we optimize out some stores. */
5643 : 29693332 : bool interposed;
5644 : 29693332 : modref_summary *sum = get_modref_function_summary (call, &interposed);
5645 : 29693332 : if (sum && !interposed && !sum->global_memory_read && !sum->loads)
5646 : : return true;
5647 : : return false;
5648 : : }
5649 : :
5650 : : #include "gt-ipa-modref.h"
|