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
5 This file is part of GCC.
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
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
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/>. */
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.
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.
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.
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.
44 There are multiple summaries computed and used during the propagation:
45 - summaries holds summaries from analysis to IPA propagation
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). */
58 #include "coretypes.h"
62 #include "alloc-pool.h"
63 #include "tree-pass.h"
64 #include "gimple-iterator.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"
75 #include "ipa-modref-tree.h"
76 #include "ipa-modref.h"
77 #include "value-range.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"
97 /* We record fnspec specifiers for call edges since they depends on actual
116 /* Summary holding fnspec string for a given call. */
118 class fnspec_summaries_t
: public call_summary
<fnspec_summary
*>
121 fnspec_summaries_t (symbol_table
*symtab
)
122 : call_summary
<fnspec_summary
*> (symtab
) {}
123 /* Hook that is called by summary when an edge is duplicated. */
124 void duplicate (cgraph_edge
*,
127 fnspec_summary
*dst
) final override
129 dst
->fnspec
= xstrdup (src
->fnspec
);
133 static fnspec_summaries_t
*fnspec_summaries
= NULL
;
135 /* Escape summary holds a vector of param indexes that escape to
139 /* Parameter that escapes at a given call. */
141 /* Argument it escapes to. */
143 /* Minimal flags known about the argument. */
144 eaf_flags_t min_flags
;
145 /* Does it escape directly or indirectly? */
149 /* Dump EAF flags. */
152 dump_eaf_flags (FILE *out
, int flags
, bool newline
= true)
154 if (flags
& EAF_UNUSED
)
155 fprintf (out
, " unused");
156 if (flags
& EAF_NO_DIRECT_CLOBBER
)
157 fprintf (out
, " no_direct_clobber");
158 if (flags
& EAF_NO_INDIRECT_CLOBBER
)
159 fprintf (out
, " no_indirect_clobber");
160 if (flags
& EAF_NO_DIRECT_ESCAPE
)
161 fprintf (out
, " no_direct_escape");
162 if (flags
& EAF_NO_INDIRECT_ESCAPE
)
163 fprintf (out
, " no_indirect_escape");
164 if (flags
& EAF_NOT_RETURNED_DIRECTLY
)
165 fprintf (out
, " not_returned_directly");
166 if (flags
& EAF_NOT_RETURNED_INDIRECTLY
)
167 fprintf (out
, " not_returned_indirectly");
168 if (flags
& EAF_NO_DIRECT_READ
)
169 fprintf (out
, " no_direct_read");
170 if (flags
& EAF_NO_INDIRECT_READ
)
171 fprintf (out
, " no_indirect_read");
176 struct escape_summary
178 auto_vec
<escape_entry
> esc
;
179 void dump (FILE *out
)
181 for (unsigned int i
= 0; i
< esc
.length (); i
++)
183 fprintf (out
, " parm %i arg %i %s min:",
186 esc
[i
].direct
? "(direct)" : "(indirect)");
187 dump_eaf_flags (out
, esc
[i
].min_flags
, false);
193 class escape_summaries_t
: public call_summary
<escape_summary
*>
196 escape_summaries_t (symbol_table
*symtab
)
197 : call_summary
<escape_summary
*> (symtab
) {}
198 /* Hook that is called by summary when an edge is duplicated. */
199 void duplicate (cgraph_edge
*,
202 escape_summary
*dst
) final override
204 dst
->esc
= src
->esc
.copy ();
208 static escape_summaries_t
*escape_summaries
= NULL
;
210 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
213 /* Class (from which there is one global instance) that holds modref summaries
214 for all analyzed functions. */
216 class GTY((user
)) modref_summaries
217 : public fast_function_summary
<modref_summary
*, va_gc
>
220 modref_summaries (symbol_table
*symtab
)
221 : 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 static modref_summaries
*create_ggc (symbol_table
*symtab
)
229 return new (ggc_alloc_no_dtor
<modref_summaries
> ())
230 modref_summaries (symtab
);
234 class modref_summary_lto
;
236 /* Class (from which there is one global instance) that holds modref summaries
237 for all analyzed functions. */
239 class GTY((user
)) modref_summaries_lto
240 : public fast_function_summary
<modref_summary_lto
*, va_gc
>
243 modref_summaries_lto (symbol_table
*symtab
)
244 : fast_function_summary
<modref_summary_lto
*, va_gc
> (symtab
),
245 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 static modref_summaries_lto
*create_ggc (symbol_table
*symtab
)
253 return new (ggc_alloc_no_dtor
<modref_summaries_lto
> ())
254 modref_summaries_lto (symtab
);
259 /* Global variable holding all modref summaries
260 (from analysis to IPA propagation time). */
262 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
265 /* Global variable holding all modref optimization summaries
266 (from IPA propagation time or used by local optimization pass). */
268 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
269 *optimization_summaries
;
271 /* LTO summaries hold info from analysis to LTO streaming or from LTO
272 stream-in through propagation to LTO stream-out. */
274 static GTY(()) fast_function_summary
<modref_summary_lto
*, va_gc
>
277 /* Summary for a single function which this pass produces. */
279 modref_summary::modref_summary ()
280 : loads (NULL
), stores (NULL
), retslot_flags (0), static_chain_flags (0),
281 writes_errno (false), side_effects (false), nondeterministic (false),
282 calls_interposable (false), global_memory_read (false),
283 global_memory_written (false), try_dse (false)
287 modref_summary::~modref_summary ()
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
299 remove_useless_eaf_flags (int eaf_flags
, int ecf_flags
, bool returns_void
)
301 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
302 eaf_flags
&= ~implicit_const_eaf_flags
;
303 else if (ecf_flags
& ECF_PURE
)
304 eaf_flags
&= ~implicit_pure_eaf_flags
;
305 else if ((ecf_flags
& ECF_NORETURN
) || returns_void
)
306 eaf_flags
&= ~(EAF_NOT_RETURNED_DIRECTLY
| EAF_NOT_RETURNED_INDIRECTLY
);
310 /* Return true if FLAGS holds some useful information. */
313 eaf_flags_useful_p (vec
<eaf_flags_t
> &flags
, int ecf_flags
)
315 for (unsigned i
= 0; i
< flags
.length (); i
++)
316 if (remove_useless_eaf_flags (flags
[i
], ecf_flags
, false))
321 /* Return true if summary is potentially useful for optimization.
322 If CHECK_FLAGS is false assume that arg_flags are useful. */
325 modref_summary::useful_p (int ecf_flags
, bool check_flags
)
327 if (arg_flags
.length () && !check_flags
)
329 if (check_flags
&& eaf_flags_useful_p (arg_flags
, ecf_flags
))
331 arg_flags
.release ();
332 if (check_flags
&& remove_useless_eaf_flags (retslot_flags
, ecf_flags
, false))
335 && remove_useless_eaf_flags (static_chain_flags
, ecf_flags
, false))
337 if (ecf_flags
& ECF_CONST
)
338 return (!side_effects
&& (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
));
339 if (loads
&& !loads
->every_base
)
343 if (ecf_flags
& ECF_PURE
)
344 return (!side_effects
&& (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
));
345 return stores
&& !stores
->every_base
;
348 /* Single function summary used for LTO. */
350 typedef modref_tree
<tree
> modref_records_lto
;
351 struct GTY(()) modref_summary_lto
353 /* Load and stores in functions using types rather then alias sets.
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;
368 modref_summary_lto ();
369 ~modref_summary_lto ();
371 bool useful_p (int ecf_flags
, bool check_flags
= true);
374 /* Summary for a single function which this pass produces. */
376 modref_summary_lto::modref_summary_lto ()
377 : loads (NULL
), stores (NULL
), retslot_flags (0), static_chain_flags (0),
378 writes_errno (false), side_effects (false), nondeterministic (false),
379 calls_interposable (false)
383 modref_summary_lto::~modref_summary_lto ()
392 /* Return true if lto summary is potentially useful for optimization.
393 If CHECK_FLAGS is false assume that arg_flags are useful. */
396 modref_summary_lto::useful_p (int ecf_flags
, bool check_flags
)
398 if (arg_flags
.length () && !check_flags
)
400 if (check_flags
&& eaf_flags_useful_p (arg_flags
, ecf_flags
))
402 arg_flags
.release ();
403 if (check_flags
&& remove_useless_eaf_flags (retslot_flags
, ecf_flags
, false))
406 && remove_useless_eaf_flags (static_chain_flags
, ecf_flags
, false))
408 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
409 return (!side_effects
&& (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
));
410 if (loads
&& !loads
->every_base
)
414 if (ecf_flags
& ECF_PURE
)
415 return (!side_effects
&& (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
));
416 return stores
&& !stores
->every_base
;
419 /* Dump records TT to OUT. */
422 dump_records (modref_records
*tt
, FILE *out
)
426 fprintf (out
, " Every base\n");
430 modref_base_node
<alias_set_type
> *n
;
431 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
433 fprintf (out
, " Base %i: alias set %i\n", (int)i
, n
->base
);
436 fprintf (out
, " Every ref\n");
440 modref_ref_node
<alias_set_type
> *r
;
441 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
443 fprintf (out
, " Ref %i: alias set %i\n", (int)j
, r
->ref
);
446 fprintf (out
, " Every access\n");
450 modref_access_node
*a
;
451 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
453 fprintf (out
, " access:");
460 /* Dump records TT to OUT. */
463 dump_lto_records (modref_records_lto
*tt
, FILE *out
)
467 fprintf (out
, " Every base\n");
471 modref_base_node
<tree
> *n
;
472 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
474 fprintf (out
, " Base %i:", (int)i
);
475 print_generic_expr (out
, n
->base
);
476 fprintf (out
, " (alias set %i)\n",
477 n
->base
? get_alias_set (n
->base
) : 0);
480 fprintf (out
, " Every ref\n");
484 modref_ref_node
<tree
> *r
;
485 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
487 fprintf (out
, " Ref %i:", (int)j
);
488 print_generic_expr (out
, r
->ref
);
489 fprintf (out
, " (alias set %i)\n",
490 r
->ref
? get_alias_set (r
->ref
) : 0);
493 fprintf (out
, " Every access\n");
497 modref_access_node
*a
;
498 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
500 fprintf (out
, " access:");
507 /* Dump all escape points of NODE to OUT. */
510 dump_modref_edge_summaries (FILE *out
, cgraph_node
*node
, int depth
)
513 if (!escape_summaries
)
515 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
517 class escape_summary
*sum
= escape_summaries
->get (e
);
520 fprintf (out
, "%*sIndirect call %i in %s escapes:",
521 depth
, "", i
, node
->dump_name ());
526 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
528 if (!e
->inline_failed
)
529 dump_modref_edge_summaries (out
, e
->callee
, depth
+ 1);
530 class escape_summary
*sum
= escape_summaries
->get (e
);
533 fprintf (out
, "%*sCall %s->%s escapes:", depth
, "",
534 node
->dump_name (), e
->callee
->dump_name ());
537 class fnspec_summary
*fsum
= fnspec_summaries
->get (e
);
540 fprintf (out
, "%*sCall %s->%s fnspec: %s\n", depth
, "",
541 node
->dump_name (), e
->callee
->dump_name (),
547 /* Remove all call edge summaries associated with NODE. */
550 remove_modref_edge_summaries (cgraph_node
*node
)
552 if (!escape_summaries
)
554 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
555 escape_summaries
->remove (e
);
556 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
558 if (!e
->inline_failed
)
559 remove_modref_edge_summaries (e
->callee
);
560 escape_summaries
->remove (e
);
561 fnspec_summaries
->remove (e
);
568 modref_summary::dump (FILE *out
) const
572 fprintf (out
, " loads:\n");
573 dump_records (loads
, out
);
577 fprintf (out
, " stores:\n");
578 dump_records (stores
, out
);
582 fprintf (out
, " kills:\n");
583 for (auto kill
: kills
)
590 fprintf (out
, " Writes errno\n");
592 fprintf (out
, " Side effects\n");
593 if (nondeterministic
)
594 fprintf (out
, " Nondeterministic\n");
595 if (calls_interposable
)
596 fprintf (out
, " Calls interposable\n");
597 if (global_memory_read
)
598 fprintf (out
, " Global memory read\n");
599 if (global_memory_written
)
600 fprintf (out
, " Global memory written\n");
602 fprintf (out
, " Try dse\n");
603 if (arg_flags
.length ())
605 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
608 fprintf (out
, " parm %i flags:", i
);
609 dump_eaf_flags (out
, arg_flags
[i
]);
614 fprintf (out
, " Retslot flags:");
615 dump_eaf_flags (out
, retslot_flags
);
617 if (static_chain_flags
)
619 fprintf (out
, " Static chain flags:");
620 dump_eaf_flags (out
, static_chain_flags
);
627 modref_summary_lto::dump (FILE *out
)
629 fprintf (out
, " loads:\n");
630 dump_lto_records (loads
, out
);
631 fprintf (out
, " stores:\n");
632 dump_lto_records (stores
, out
);
635 fprintf (out
, " kills:\n");
636 for (auto kill
: kills
)
643 fprintf (out
, " Writes errno\n");
645 fprintf (out
, " Side effects\n");
646 if (nondeterministic
)
647 fprintf (out
, " Nondeterministic\n");
648 if (calls_interposable
)
649 fprintf (out
, " Calls interposable\n");
650 if (arg_flags
.length ())
652 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
655 fprintf (out
, " parm %i flags:", i
);
656 dump_eaf_flags (out
, arg_flags
[i
]);
661 fprintf (out
, " Retslot flags:");
662 dump_eaf_flags (out
, retslot_flags
);
664 if (static_chain_flags
)
666 fprintf (out
, " Static chain flags:");
667 dump_eaf_flags (out
, static_chain_flags
);
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. */
675 modref_summary::finalize (tree fun
)
677 global_memory_read
= !loads
|| loads
->global_access_p ();
678 global_memory_written
= !stores
|| stores
->global_access_p ();
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
683 if (side_effects
|| global_memory_written
|| writes_errno
)
689 int num_tests
= 0, max_tests
690 = opt_for_fn (fun
, param_modref_max_tests
);
691 modref_base_node
<alias_set_type
> *base_node
;
692 modref_ref_node
<alias_set_type
> *ref_node
;
693 modref_access_node
*access_node
;
694 FOR_EACH_VEC_SAFE_ELT (stores
->bases
, i
, base_node
)
696 if (base_node
->every_ref
)
701 FOR_EACH_VEC_SAFE_ELT (base_node
->refs
, j
, ref_node
)
703 if (base_node
->every_ref
)
708 FOR_EACH_VEC_SAFE_ELT (ref_node
->accesses
, k
, access_node
)
709 if (num_tests
++ > max_tests
710 || !access_node
->parm_offset_known
)
722 if (loads
->every_base
)
727 for (auto base_node
: loads
->bases
)
729 if (base_node
->every_ref
)
732 for (auto ref_node
: base_node
->refs
)
733 if (ref_node
->every_access
)
736 load_accesses
+= ref_node
->accesses
->length ();
741 /* Get function summary for FUNC if it exists, return NULL otherwise. */
744 get_modref_function_summary (cgraph_node
*func
)
746 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
747 if (!optimization_summaries
)
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
754 enum availability avail
;
755 func
= func
->ultimate_alias_target
756 (&avail
, current_function_decl
?
757 cgraph_node::get (current_function_decl
) : NULL
);
758 if (avail
<= AVAIL_INTERPOSABLE
)
761 modref_summary
*r
= optimization_summaries
->get (func
);
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. */
771 get_modref_function_summary (gcall
*call
, bool *interposed
)
773 tree callee
= gimple_call_fndecl (call
);
776 struct cgraph_node
*node
= cgraph_node::get (callee
);
779 modref_summary
*r
= get_modref_function_summary (node
);
781 *interposed
= r
->calls_interposable
782 || !node
->binds_to_current_def_p ();
789 /* Return true if ECF flags says that nondeterminism can be ignored. */
792 ignore_nondeterminism_p (tree caller
, int flags
, tree callee_fntype
)
794 int caller_flags
= flags_from_decl_or_type (caller
);
795 if ((flags
| caller_flags
) & (ECF_CONST
| ECF_PURE
))
797 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
798 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
800 /* C language defines unsequenced and reproducible functions
801 to be deterministic. */
802 if (lookup_attribute ("unsequenced", TYPE_ATTRIBUTES (TREE_TYPE (caller
)))
803 || lookup_attribute ("reproducible",
804 TYPE_ATTRIBUTES (TREE_TYPE (caller
))))
807 && (lookup_attribute ("unsequenced", TYPE_ATTRIBUTES (callee_fntype
))
808 || lookup_attribute ("reproducible",
809 TYPE_ATTRIBUTES (callee_fntype
))))
814 /* Return true if ECF flags says that return value can be ignored. */
817 ignore_retval_p (tree caller
, int flags
)
819 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
820 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
825 /* Return true if ECF flags says that stores can be ignored. */
828 ignore_stores_p (tree caller
, int flags
)
830 if (flags
& (ECF_PURE
| ECF_CONST
| ECF_NOVOPS
))
832 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
833 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
838 /* Determine parm_map for PTR which is supposed to be a pointer. */
841 parm_map_for_ptr (tree op
)
845 struct modref_parm_map parm_map
;
848 parm_map
.parm_offset_known
= false;
849 parm_map
.parm_offset
= 0;
851 offset_known
= unadjusted_ptr_and_unit_offset (op
, &op
, &offset
);
852 if (TREE_CODE (op
) == SSA_NAME
853 && SSA_NAME_IS_DEFAULT_DEF (op
)
854 && TREE_CODE (SSA_NAME_VAR (op
)) == PARM_DECL
)
858 if (cfun
->static_chain_decl
859 && op
== ssa_default_def (cfun
, cfun
->static_chain_decl
))
860 index
= MODREF_STATIC_CHAIN_PARM
;
862 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
863 t
!= SSA_NAME_VAR (op
); t
= DECL_CHAIN (t
))
865 parm_map
.parm_index
= index
;
866 parm_map
.parm_offset_known
= offset_known
;
867 parm_map
.parm_offset
= offset
;
869 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 else if (TREE_CODE (op
) == SSA_NAME
874 && (call
= dyn_cast
<gcall
*>(SSA_NAME_DEF_STMT (op
))) != NULL
875 && gimple_call_flags (call
) & ECF_MALLOC
)
876 parm_map
.parm_index
= MODREF_LOCAL_MEMORY_PARM
;
878 parm_map
.parm_index
= MODREF_UNKNOWN_PARM
;
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). */
886 verify_arg (tree arg
, int flags
, bool load
)
888 if (flags
& EAF_UNUSED
)
890 if (load
&& (flags
& EAF_NO_DIRECT_READ
))
893 && (flags
& (EAF_NO_DIRECT_CLOBBER
| EAF_NO_INDIRECT_CLOBBER
))
894 == (EAF_NO_DIRECT_CLOBBER
| EAF_NO_INDIRECT_CLOBBER
))
896 if (is_gimple_constant (arg
))
898 if (DECL_P (arg
) && TREE_READONLY (arg
))
900 if (TREE_CODE (arg
) == ADDR_EXPR
)
902 tree t
= get_base_address (TREE_OPERAND (arg
, 0));
903 if (is_gimple_constant (t
))
906 && (TREE_READONLY (t
) || TREE_CODE (t
) == FUNCTION_DECL
))
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. */
918 may_access_nonescaping_parm_p (gcall
*call
, int callee_ecf_flags
, bool load
)
920 int implicit_flags
= 0;
922 if (ignore_stores_p (current_function_decl
, callee_ecf_flags
))
923 implicit_flags
|= ignore_stores_eaf_flags
;
924 if (callee_ecf_flags
& ECF_PURE
)
925 implicit_flags
|= implicit_pure_eaf_flags
;
926 if (callee_ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
927 implicit_flags
|= implicit_const_eaf_flags
;
928 if (gimple_call_chain (call
)
929 && !verify_arg (gimple_call_chain (call
),
930 gimple_call_static_chain_flags (call
) | implicit_flags
,
933 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
934 if (!verify_arg (gimple_call_arg (call
, i
),
935 gimple_call_arg_flags (call
, i
) | implicit_flags
,
942 /* Analyze memory accesses (loads, stores and kills) performed
943 by the function. Set also side_effects, calls_interposable
944 and nondeterminism flags. */
946 class modref_access_analysis
949 modref_access_analysis (bool ipa
, modref_summary
*summary
,
950 modref_summary_lto
*summary_lto
)
951 : m_summary (summary
), m_summary_lto (summary_lto
), m_ipa (ipa
)
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);
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. */
988 /* True if IPA propagation will be done later. */
990 /* Set true if statement currently analyze is known to be
991 executed each time function is called. */
992 bool m_always_executed
;
995 /* Set side_effects flag and return if something changed. */
998 modref_access_analysis::set_side_effects ()
1000 bool changed
= false;
1002 if (m_summary
&& !m_summary
->side_effects
)
1004 m_summary
->side_effects
= true;
1007 if (m_summary_lto
&& !m_summary_lto
->side_effects
)
1009 m_summary_lto
->side_effects
= true;
1015 /* Set nondeterministic flag and return if something changed. */
1018 modref_access_analysis::set_nondeterministic ()
1020 bool changed
= false;
1022 if (m_summary
&& !m_summary
->nondeterministic
)
1024 m_summary
->side_effects
= m_summary
->nondeterministic
= true;
1027 if (m_summary_lto
&& !m_summary_lto
->nondeterministic
)
1029 m_summary_lto
->side_effects
= m_summary_lto
->nondeterministic
= true;
1035 /* Construct modref_access_node from REF. */
1038 modref_access_analysis::get_access (ao_ref
*ref
)
1042 base
= ao_ref_base (ref
);
1043 modref_access_node a
= {ref
->offset
, ref
->size
, ref
->max_size
,
1044 0, MODREF_UNKNOWN_PARM
, false, 0};
1045 if (TREE_CODE (base
) == MEM_REF
|| TREE_CODE (base
) == TARGET_MEM_REF
)
1048 modref_parm_map m
= parm_map_for_ptr (TREE_OPERAND (base
, 0));
1050 a
.parm_index
= m
.parm_index
;
1051 if (a
.parm_index
!= MODREF_UNKNOWN_PARM
&& TREE_CODE (memref
) == MEM_REF
)
1054 = wi::to_poly_wide (TREE_OPERAND
1055 (memref
, 1)).to_shwi (&a
.parm_offset
);
1056 if (a
.parm_offset_known
&& m
.parm_offset_known
)
1057 a
.parm_offset
+= m
.parm_offset
;
1059 a
.parm_offset_known
= false;
1063 a
.parm_index
= MODREF_UNKNOWN_PARM
;
1067 /* Record access into the modref_records data structure. */
1070 modref_access_analysis::record_access (modref_records
*tt
,
1072 modref_access_node
&a
)
1074 alias_set_type base_set
= !flag_strict_aliasing
1075 || !flag_ipa_strict_aliasing
? 0
1076 : ao_ref_base_alias_set (ref
);
1077 alias_set_type ref_set
= !flag_strict_aliasing
1078 || !flag_ipa_strict_aliasing
? 0
1079 : (ao_ref_alias_set (ref
));
1082 fprintf (dump_file
, " - Recording base_set=%i ref_set=%i ",
1086 tt
->insert (current_function_decl
, base_set
, ref_set
, a
, false);
1089 /* IPA version of record_access_tree. */
1092 modref_access_analysis::record_access_lto (modref_records_lto
*tt
, ao_ref
*ref
,
1093 modref_access_node
&a
)
1095 /* get_alias_set sometimes use different type to compute the alias set
1096 than TREE_TYPE (base). Do same adjustments. */
1097 tree base_type
= NULL_TREE
, ref_type
= NULL_TREE
;
1098 if (flag_strict_aliasing
&& flag_ipa_strict_aliasing
)
1103 while (handled_component_p (base
))
1104 base
= TREE_OPERAND (base
, 0);
1106 base_type
= reference_alias_ptr_type_1 (&base
);
1109 base_type
= TREE_TYPE (base
);
1111 base_type
= TYPE_REF_CAN_ALIAS_ALL (base_type
)
1112 ? NULL_TREE
: TREE_TYPE (base_type
);
1114 tree ref_expr
= ref
->ref
;
1115 ref_type
= reference_alias_ptr_type_1 (&ref_expr
);
1118 ref_type
= TREE_TYPE (ref_expr
);
1120 ref_type
= TYPE_REF_CAN_ALIAS_ALL (ref_type
)
1121 ? NULL_TREE
: TREE_TYPE (ref_type
);
1123 /* Sanity check that we are in sync with what get_alias_set does. */
1124 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 gcc_checking_assert ((!ref_type
&& !ao_ref_alias_set (ref
))
1128 || get_alias_set (ref_type
)
1129 == ao_ref_alias_set (ref
));
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 if (base_type
&& (!get_alias_set (base_type
)
1134 || variably_modified_type_p (base_type
, NULL_TREE
)))
1135 base_type
= NULL_TREE
;
1136 if (ref_type
&& (!get_alias_set (ref_type
)
1137 || variably_modified_type_p (ref_type
, NULL_TREE
)))
1138 ref_type
= NULL_TREE
;
1142 fprintf (dump_file
, " - Recording base type:");
1143 print_generic_expr (dump_file
, base_type
);
1144 fprintf (dump_file
, " (alias set %i) ref type:",
1145 base_type
? get_alias_set (base_type
) : 0);
1146 print_generic_expr (dump_file
, ref_type
);
1147 fprintf (dump_file
, " (alias set %i) ",
1148 ref_type
? get_alias_set (ref_type
) : 0);
1152 tt
->insert (current_function_decl
, base_type
, ref_type
, a
, false);
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. */
1159 modref_access_analysis::record_access_p (tree expr
)
1161 if (TREE_THIS_VOLATILE (expr
)
1162 && !ignore_nondeterminism_p (current_function_decl
, 0, NULL
))
1165 fprintf (dump_file
, " (volatile; marking nondeterministic) ");
1166 set_nondeterministic ();
1168 if (cfun
->can_throw_non_call_exceptions
1169 && tree_could_throw_p (expr
))
1172 fprintf (dump_file
, " (can throw; marking side effects) ");
1173 set_side_effects ();
1176 if (refs_local_or_readonly_memory_p (expr
))
1179 fprintf (dump_file
, " - Read-only or local, ignoring.\n");
1185 /* Collapse loads and return true if something changed. */
1188 modref_access_analysis::record_unknown_load ()
1190 bool changed
= false;
1192 if (m_summary
&& !m_summary
->loads
->every_base
)
1194 m_summary
->loads
->collapse ();
1197 if (m_summary_lto
&& !m_summary_lto
->loads
->every_base
)
1199 m_summary_lto
->loads
->collapse ();
1205 /* Collapse loads and return true if something changed. */
1208 modref_access_analysis::record_unknown_store ()
1210 bool changed
= false;
1212 if (m_summary
&& !m_summary
->stores
->every_base
)
1214 m_summary
->stores
->collapse ();
1217 if (m_summary_lto
&& !m_summary_lto
->stores
->every_base
)
1219 m_summary_lto
->stores
->collapse ();
1225 /* Record unknown load from global memory. */
1228 modref_access_analysis::record_global_memory_load ()
1230 bool changed
= false;
1231 modref_access_node a
= {0, -1, -1,
1232 0, MODREF_GLOBAL_MEMORY_PARM
, false, 0};
1234 if (m_summary
&& !m_summary
->loads
->every_base
)
1235 changed
|= m_summary
->loads
->insert (current_function_decl
, 0, 0, a
, false);
1236 if (m_summary_lto
&& !m_summary_lto
->loads
->every_base
)
1237 changed
|= m_summary_lto
->loads
->insert (current_function_decl
,
1242 /* Record unknown store from global memory. */
1245 modref_access_analysis::record_global_memory_store ()
1247 bool changed
= false;
1248 modref_access_node a
= {0, -1, -1,
1249 0, MODREF_GLOBAL_MEMORY_PARM
, false, 0};
1251 if (m_summary
&& !m_summary
->stores
->every_base
)
1252 changed
|= m_summary
->stores
->insert (current_function_decl
,
1254 if (m_summary_lto
&& !m_summary_lto
->stores
->every_base
)
1255 changed
|= m_summary_lto
->stores
->insert (current_function_decl
,
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. */
1267 modref_access_analysis::merge_call_side_effects
1268 (gimple
*stmt
, modref_summary
*callee_summary
,
1269 cgraph_node
*callee_node
, bool record_adjustments
)
1271 gcall
*call
= as_a
<gcall
*> (stmt
);
1272 int flags
= gimple_call_flags (call
);
1274 /* Nothing to do for non-looping cont functions. */
1275 if ((flags
& ECF_CONST
)
1276 && !(flags
& ECF_LOOPING_CONST_OR_PURE
))
1279 bool changed
= false;
1282 fprintf (dump_file
, " - Merging side effects of %s\n",
1283 callee_node
->dump_name ());
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 if (!(flags
& (ECF_CONST
| ECF_PURE
))
1289 || (flags
& ECF_LOOPING_CONST_OR_PURE
))
1291 if (!m_summary
->side_effects
&& callee_summary
->side_effects
)
1294 fprintf (dump_file
, " - merging side effects.\n");
1295 m_summary
->side_effects
= true;
1298 if (!m_summary
->nondeterministic
&& callee_summary
->nondeterministic
1299 && !ignore_nondeterminism_p (current_function_decl
, flags
,
1300 gimple_call_fntype (call
)))
1303 fprintf (dump_file
, " - merging nondeterministic.\n");
1304 m_summary
->nondeterministic
= true;
1309 /* For const functions we are done. */
1310 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
1313 /* Merge calls_interposable flags. */
1314 if (!m_summary
->calls_interposable
&& callee_summary
->calls_interposable
)
1317 fprintf (dump_file
, " - merging calls interposable.\n");
1318 m_summary
->calls_interposable
= true;
1322 if (!callee_node
->binds_to_current_def_p () && !m_summary
->calls_interposable
)
1325 fprintf (dump_file
, " - May be interposed.\n");
1326 m_summary
->calls_interposable
= true;
1330 /* Now merge the actual load, store and kill vectors. For this we need
1331 to compute map translating new parameters to old. */
1333 fprintf (dump_file
, " Parm map:");
1335 auto_vec
<modref_parm_map
, 32> parm_map
;
1336 parm_map
.safe_grow_cleared (gimple_call_num_args (call
), true);
1337 for (unsigned i
= 0; i
< gimple_call_num_args (call
); i
++)
1339 parm_map
[i
] = parm_map_for_ptr (gimple_call_arg (call
, i
));
1342 fprintf (dump_file
, " %i", parm_map
[i
].parm_index
);
1343 if (parm_map
[i
].parm_offset_known
)
1345 fprintf (dump_file
, " offset:");
1346 print_dec ((poly_int64
)parm_map
[i
].parm_offset
,
1352 modref_parm_map chain_map
;
1353 if (gimple_call_chain (call
))
1355 chain_map
= parm_map_for_ptr (gimple_call_chain (call
));
1358 fprintf (dump_file
, "static chain %i", chain_map
.parm_index
);
1359 if (chain_map
.parm_offset_known
)
1361 fprintf (dump_file
, " offset:");
1362 print_dec ((poly_int64
)chain_map
.parm_offset
,
1368 fprintf (dump_file
, "\n");
1370 /* Kills can me merged in only if we know the function is going to be
1372 if (m_always_executed
1373 && callee_summary
->kills
.length ()
1374 && (!cfun
->can_throw_non_call_exceptions
1375 || !stmt_could_throw_p (cfun
, call
)))
1377 /* Watch for self recursive updates. */
1378 auto_vec
<modref_access_node
, 32> saved_kills
;
1380 saved_kills
.reserve_exact (callee_summary
->kills
.length ());
1381 saved_kills
.splice (callee_summary
->kills
);
1382 for (auto kill
: saved_kills
)
1384 if (kill
.parm_index
>= (int)parm_map
.length ())
1387 = kill
.parm_index
== MODREF_STATIC_CHAIN_PARM
1389 : parm_map
[kill
.parm_index
];
1390 if (m
.parm_index
== MODREF_LOCAL_MEMORY_PARM
1391 || m
.parm_index
== MODREF_UNKNOWN_PARM
1392 || m
.parm_index
== MODREF_RETSLOT_PARM
1393 || !m
.parm_offset_known
)
1395 modref_access_node n
= kill
;
1396 n
.parm_index
= m
.parm_index
;
1397 n
.parm_offset
+= m
.parm_offset
;
1398 if (modref_access_node::insert_kill (m_summary
->kills
, n
,
1399 record_adjustments
))
1404 /* Merge in loads. */
1405 changed
|= m_summary
->loads
->merge (current_function_decl
,
1406 callee_summary
->loads
,
1407 &parm_map
, &chain_map
,
1409 !may_access_nonescaping_parm_p
1410 (call
, flags
, true));
1411 /* Merge in stores. */
1412 if (!ignore_stores_p (current_function_decl
, flags
))
1414 changed
|= m_summary
->stores
->merge (current_function_decl
,
1415 callee_summary
->stores
,
1416 &parm_map
, &chain_map
,
1418 !may_access_nonescaping_parm_p
1419 (call
, flags
, false));
1420 if (!m_summary
->writes_errno
1421 && callee_summary
->writes_errno
)
1423 m_summary
->writes_errno
= true;
1430 /* Return access mode for argument I of call STMT with FNSPEC. */
1433 modref_access_analysis::get_access_for_fnspec (gcall
*call
, attr_fnspec
&fnspec
,
1435 modref_parm_map
&map
)
1437 tree size
= NULL_TREE
;
1438 unsigned int size_arg
;
1440 if (!fnspec
.arg_specified_p (i
))
1442 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
1443 size
= gimple_call_arg (call
, size_arg
);
1444 else if (fnspec
.arg_access_size_given_by_type_p (i
))
1446 tree callee
= gimple_call_fndecl (call
);
1447 tree t
= TYPE_ARG_TYPES (TREE_TYPE (callee
));
1449 for (unsigned int p
= 0; p
< i
; p
++)
1451 size
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t
)));
1453 modref_access_node a
= {0, -1, -1,
1454 map
.parm_offset
, map
.parm_index
,
1455 map
.parm_offset_known
, 0};
1456 poly_int64 size_hwi
;
1458 && poly_int_tree_p (size
, &size_hwi
)
1459 && coeffs_in_range_p (size_hwi
, 0,
1460 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
1463 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
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. */
1473 modref_access_analysis::process_fnspec (gcall
*call
)
1475 int flags
= gimple_call_flags (call
);
1477 /* PURE/CONST flags makes functions deterministic and if there is
1478 no LOOPING_CONST_OR_PURE they also have no side effects. */
1479 if (!(flags
& (ECF_CONST
| ECF_PURE
))
1480 || (flags
& ECF_LOOPING_CONST_OR_PURE
)
1481 || (cfun
->can_throw_non_call_exceptions
1482 && stmt_could_throw_p (cfun
, call
)))
1484 set_side_effects ();
1485 if (!ignore_nondeterminism_p (current_function_decl
, flags
,
1486 gimple_call_fntype (call
)))
1487 set_nondeterministic ();
1490 /* For const functions we are done. */
1491 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
1494 attr_fnspec fnspec
= gimple_call_fnspec (call
);
1495 /* If there is no fnpec we know nothing about loads & stores. */
1496 if (!fnspec
.known_p ())
1498 if (dump_file
&& gimple_call_builtin_p (call
, BUILT_IN_NORMAL
))
1499 fprintf (dump_file
, " Builtin with no fnspec: %s\n",
1500 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call
))));
1501 if (!ignore_stores_p (current_function_decl
, flags
))
1503 if (!may_access_nonescaping_parm_p (call
, flags
, false))
1504 record_global_memory_store ();
1506 record_unknown_store ();
1507 if (!may_access_nonescaping_parm_p (call
, flags
, true))
1508 record_global_memory_load ();
1510 record_unknown_load ();
1514 if (!may_access_nonescaping_parm_p (call
, flags
, true))
1515 record_global_memory_load ();
1517 record_unknown_load ();
1521 /* Process fnspec. */
1522 if (fnspec
.global_memory_read_p ())
1524 if (may_access_nonescaping_parm_p (call
, flags
, true))
1525 record_unknown_load ();
1527 record_global_memory_load ();
1531 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1532 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1534 else if (!fnspec
.arg_specified_p (i
)
1535 || fnspec
.arg_maybe_read_p (i
))
1537 modref_parm_map map
= parm_map_for_ptr
1538 (gimple_call_arg (call
, i
));
1540 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1542 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
1544 record_unknown_load ();
1547 modref_access_node a
= get_access_for_fnspec (call
, fnspec
, i
, map
);
1548 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1551 m_summary
->loads
->insert (current_function_decl
, 0, 0, a
, false);
1553 m_summary_lto
->loads
->insert (current_function_decl
, 0, 0, a
,
1557 if (ignore_stores_p (current_function_decl
, flags
))
1559 if (fnspec
.global_memory_written_p ())
1561 if (may_access_nonescaping_parm_p (call
, flags
, false))
1562 record_unknown_store ();
1564 record_global_memory_store ();
1568 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1569 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1571 else if (!fnspec
.arg_specified_p (i
)
1572 || fnspec
.arg_maybe_written_p (i
))
1574 modref_parm_map map
= parm_map_for_ptr
1575 (gimple_call_arg (call
, i
));
1577 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1579 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
1581 record_unknown_store ();
1584 modref_access_node a
= get_access_for_fnspec (call
, fnspec
, i
, map
);
1585 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1588 m_summary
->stores
->insert (current_function_decl
, 0, 0, a
, false);
1590 m_summary_lto
->stores
->insert (current_function_decl
,
1593 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
1596 m_summary
->writes_errno
= true;
1598 m_summary_lto
->writes_errno
= true;
1603 /* Analyze function call STMT in function F.
1604 Remember recursive calls in RECURSIVE_CALLS. */
1607 modref_access_analysis::analyze_call (gcall
*stmt
)
1609 /* Check flags on the function call. In certain cases, analysis can be
1611 int flags
= gimple_call_flags (stmt
);
1615 fprintf (dump_file
, " - Analyzing call:");
1616 print_gimple_stmt (dump_file
, stmt
, 0);
1619 if ((flags
& ECF_CONST
)
1620 && !(flags
& ECF_LOOPING_CONST_OR_PURE
))
1624 " - ECF_CONST, ignoring all stores and all loads "
1625 "except for args.\n");
1629 /* Next, we try to get the callee's function declaration. The goal is to
1630 merge their summary with ours. */
1631 tree callee
= gimple_call_fndecl (stmt
);
1633 /* Check if this is an indirect call. */
1637 fprintf (dump_file
, gimple_call_internal_p (stmt
)
1638 ? " - Internal call" : " - Indirect call.\n");
1639 process_fnspec (stmt
);
1642 /* We only need to handle internal calls in IPA mode. */
1643 gcc_checking_assert (!m_summary_lto
&& !m_ipa
);
1645 struct cgraph_node
*callee_node
= cgraph_node::get_create (callee
);
1647 /* If this is a recursive call, the target summary is the same as ours, so
1648 there's nothing to do. */
1649 if (recursive_call_p (current_function_decl
, callee
))
1651 m_recursive_calls
.safe_push (stmt
);
1652 set_side_effects ();
1654 fprintf (dump_file
, " - Skipping recursive call.\n");
1658 gcc_assert (callee_node
!= NULL
);
1660 /* Get the function symbol and its availability. */
1661 enum availability avail
;
1662 callee_node
= callee_node
->function_symbol (&avail
);
1664 if (builtin_safe_for_const_function_p (&looping
, callee
))
1667 set_side_effects ();
1669 fprintf (dump_file
, " - Builtin is safe for const.\n");
1672 if (avail
<= AVAIL_INTERPOSABLE
)
1676 " - Function availability <= AVAIL_INTERPOSABLE.\n");
1677 process_fnspec (stmt
);
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 modref_summary
*callee_summary
= optimization_summaries
->get (callee_node
);
1684 if (!callee_summary
)
1687 fprintf (dump_file
, " - No modref summary available for callee.\n");
1688 process_fnspec (stmt
);
1692 merge_call_side_effects (stmt
, callee_summary
, callee_node
, false);
1697 /* Helper for analyze_stmt. */
1700 modref_access_analysis::analyze_load (gimple
*, tree
, tree op
, void *data
)
1702 modref_access_analysis
*t
= (modref_access_analysis
*)data
;
1706 fprintf (dump_file
, " - Analyzing load: ");
1707 print_generic_expr (dump_file
, op
);
1708 fprintf (dump_file
, "\n");
1711 if (!t
->record_access_p (op
))
1715 ao_ref_init (&r
, op
);
1716 modref_access_node a
= get_access (&r
);
1717 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1721 t
->record_access (t
->m_summary
->loads
, &r
, a
);
1722 if (t
->m_summary_lto
)
1723 t
->record_access_lto (t
->m_summary_lto
->loads
, &r
, a
);
1727 /* Helper for analyze_stmt. */
1730 modref_access_analysis::analyze_store (gimple
*stmt
, tree
, tree op
, void *data
)
1732 modref_access_analysis
*t
= (modref_access_analysis
*)data
;
1736 fprintf (dump_file
, " - Analyzing store: ");
1737 print_generic_expr (dump_file
, op
);
1738 fprintf (dump_file
, "\n");
1741 if (!t
->record_access_p (op
))
1745 ao_ref_init (&r
, op
);
1746 modref_access_node a
= get_access (&r
);
1747 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1751 t
->record_access (t
->m_summary
->stores
, &r
, a
);
1752 if (t
->m_summary_lto
)
1753 t
->record_access_lto (t
->m_summary_lto
->stores
, &r
, a
);
1754 if (t
->m_always_executed
1755 && a
.useful_for_kill_p ()
1756 && (!cfun
->can_throw_non_call_exceptions
1757 || !stmt_could_throw_p (cfun
, stmt
)))
1760 fprintf (dump_file
, " - Recording kill\n");
1762 modref_access_node::insert_kill (t
->m_summary
->kills
, a
, false);
1763 if (t
->m_summary_lto
)
1764 modref_access_node::insert_kill (t
->m_summary_lto
->kills
, a
, false);
1769 /* Analyze statement STMT of function F.
1770 If IPA is true do not merge in side effects of calls. */
1773 modref_access_analysis::analyze_stmt (gimple
*stmt
, bool always_executed
)
1775 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 if ((m_ipa
|| cfun
->after_inlining
) && gimple_clobber_p (stmt
))
1782 if (always_executed
&& record_access_p (gimple_assign_lhs (stmt
)))
1785 ao_ref_init (&r
, gimple_assign_lhs (stmt
));
1786 modref_access_node a
= get_access (&r
);
1787 if (a
.useful_for_kill_p ())
1790 fprintf (dump_file
, " - Recording kill\n");
1792 modref_access_node::insert_kill (m_summary
->kills
, a
, false);
1794 modref_access_node::insert_kill (m_summary_lto
->kills
,
1801 /* Analyze all loads and stores in STMT. */
1802 walk_stmt_load_store_ops (stmt
, this,
1803 analyze_load
, analyze_store
);
1805 switch (gimple_code (stmt
))
1808 if (gimple_asm_volatile_p (as_a
<gasm
*> (stmt
))
1809 && !ignore_nondeterminism_p (current_function_decl
, 0, NULL
))
1810 set_nondeterministic ();
1811 if (cfun
->can_throw_non_call_exceptions
1812 && stmt_could_throw_p (cfun
, stmt
))
1813 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 if (!gimple_asm_clobbers_memory_p (as_a
<gasm
*> (stmt
)))
1819 fprintf (dump_file
, " - Function contains GIMPLE_ASM statement "
1820 "which clobbers memory.\n");
1821 record_unknown_load ();
1822 record_unknown_store ();
1825 if (!m_ipa
|| gimple_call_internal_p (stmt
))
1826 analyze_call (as_a
<gcall
*> (stmt
));
1829 attr_fnspec fnspec
= gimple_call_fnspec (as_a
<gcall
*>(stmt
));
1831 if (fnspec
.known_p ()
1832 && (!fnspec
.global_memory_read_p ()
1833 || !fnspec
.global_memory_written_p ()))
1835 cgraph_edge
*e
= cgraph_node::get
1836 (current_function_decl
)->get_edge (stmt
);
1839 fnspec_summaries
->get_create (e
)->fnspec
1840 = xstrdup (fnspec
.get_str ());
1842 fprintf (dump_file
, " Recorded fnspec %s\n",
1849 if (cfun
->can_throw_non_call_exceptions
1850 && stmt_could_throw_p (cfun
, stmt
))
1851 set_side_effects ();
1856 /* Propagate load/stores across recursive calls. */
1859 modref_access_analysis::propagate ()
1861 if (m_ipa
&& m_summary
)
1864 bool changed
= true;
1866 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1868 m_always_executed
= false;
1869 while (changed
&& m_summary
->useful_p (m_ecf_flags
, false))
1872 for (unsigned i
= 0; i
< m_recursive_calls
.length (); i
++)
1874 changed
|= merge_call_side_effects (m_recursive_calls
[i
], m_summary
,
1881 /* Analyze function. */
1884 modref_access_analysis::analyze ()
1886 m_ecf_flags
= flags_from_decl_or_type (current_function_decl
);
1887 bool summary_useful
= true;
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. */
1893 bitmap always_executed_bbs
= find_always_executed_bbs (cfun
, true);
1894 FOR_EACH_BB_FN (bb
, cfun
)
1896 gimple_stmt_iterator si
;
1897 bool always_executed
= bitmap_bit_p (always_executed_bbs
, bb
->index
);
1899 for (si
= gsi_start_nondebug_after_labels_bb (bb
);
1900 !gsi_end_p (si
); gsi_next_nondebug (&si
))
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 if (infer_nonnull_range_by_dereference (gsi_stmt (si
),
1910 fprintf (dump_file
, " - NULL memory access; terminating BB\n");
1911 if (flag_non_call_exceptions
)
1912 set_side_effects ();
1915 analyze_stmt (gsi_stmt (si
), always_executed
);
1917 /* Avoid doing useless work. */
1918 if ((!m_summary
|| !m_summary
->useful_p (m_ecf_flags
, false))
1920 || !m_summary_lto
->useful_p (m_ecf_flags
, false)))
1922 summary_useful
= false;
1926 && stmt_can_throw_external (cfun
, gsi_stmt (si
)))
1927 always_executed
= false;
1929 if (!summary_useful
)
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. */
1938 if (m_summary
&& !m_summary
->side_effects
&& !finite_function_p ())
1939 m_summary
->side_effects
= true;
1940 if (m_summary_lto
&& !m_summary_lto
->side_effects
1941 && !finite_function_p ())
1942 m_summary_lto
->side_effects
= true;
1944 BITMAP_FREE (always_executed_bbs
);
1947 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1950 memory_access_to (tree op
, tree ssa_name
)
1952 tree base
= get_base_address (op
);
1955 if (TREE_CODE (base
) != MEM_REF
&& TREE_CODE (base
) != TARGET_MEM_REF
)
1957 return TREE_OPERAND (base
, 0) == ssa_name
;
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. */
1966 deref_flags (int flags
, bool ignore_stores
)
1968 /* Dereference is also a direct read but dereferenced value does not
1969 yield any other direct use. */
1970 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 if (flags
& EAF_UNUSED
)
1975 ret
|= EAF_NO_INDIRECT_READ
| EAF_NO_INDIRECT_CLOBBER
1976 | EAF_NO_INDIRECT_ESCAPE
;
1979 /* Direct or indirect accesses leads to indirect accesses. */
1980 if (((flags
& EAF_NO_DIRECT_CLOBBER
)
1981 && (flags
& EAF_NO_INDIRECT_CLOBBER
))
1983 ret
|= EAF_NO_INDIRECT_CLOBBER
;
1984 if (((flags
& EAF_NO_DIRECT_ESCAPE
)
1985 && (flags
& EAF_NO_INDIRECT_ESCAPE
))
1987 ret
|= EAF_NO_INDIRECT_ESCAPE
;
1988 if ((flags
& EAF_NO_DIRECT_READ
)
1989 && (flags
& EAF_NO_INDIRECT_READ
))
1990 ret
|= EAF_NO_INDIRECT_READ
;
1991 if ((flags
& EAF_NOT_RETURNED_DIRECTLY
)
1992 && (flags
& EAF_NOT_RETURNED_INDIRECTLY
))
1993 ret
|= EAF_NOT_RETURNED_INDIRECTLY
;
1999 /* Description of an escape point: a call which affects flags of a given
2004 /* Value escapes to this call. */
2006 /* Argument it escapes to. */
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? */
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. */
2019 class modref_lattice
2022 /* EAF flags of the SSA name. */
2024 /* Used during DFS walk to mark names where final value was determined
2025 without need for dataflow. */
2027 /* Used during DFS walk to mark open vertices (for cycle detection). */
2029 /* Set during DFS walk for names that needs dataflow propagation. */
2031 /* Used during the iterative dataflow. */
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
;
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
2048 vec
<propagate_edge
, va_heap
, vl_ptr
> propagate_to
;
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;
2062 /* Lattices are saved to vectors, so keep them PODs. */
2064 modref_lattice::init ()
2066 /* All flags we track. */
2067 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
2073 /* Check that eaf_flags_t is wide enough to hold all flags. */
2074 gcc_checking_assert (f
== flags
);
2079 /* Release memory. */
2081 modref_lattice::release ()
2083 escape_points
.release ();
2084 propagate_to
.release ();
2087 /* Dump lattice to OUT; indent with INDENT spaces. */
2090 modref_lattice::dump (FILE *out
, int indent
) const
2092 dump_eaf_flags (out
, flags
);
2093 if (escape_points
.length ())
2095 fprintf (out
, "%*sEscapes:\n", indent
, "");
2096 for (unsigned int i
= 0; i
< escape_points
.length (); i
++)
2098 fprintf (out
, "%*s Arg %i (%s) min flags", indent
, "",
2099 escape_points
[i
].arg
,
2100 escape_points
[i
].direct
? "direct" : "indirect");
2101 dump_eaf_flags (out
, escape_points
[i
].min_flags
, false);
2102 fprintf (out
, " in call ");
2103 print_gimple_stmt (out
, escape_points
[i
].call
, 0);
2108 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
2112 modref_lattice::add_escape_point (gcall
*call
, unsigned arg
,
2113 eaf_flags_t min_flags
, bool direct
)
2118 /* If we already determined flags to be bad enough,
2119 we do not need to record. */
2120 if ((flags
& min_flags
) == flags
|| (min_flags
& EAF_UNUSED
))
2123 FOR_EACH_VEC_ELT (escape_points
, i
, ep
)
2124 if (ep
->call
== call
&& ep
->arg
== arg
&& ep
->direct
== direct
)
2126 if ((ep
->min_flags
& min_flags
) == min_flags
)
2128 ep
->min_flags
&= min_flags
;
2131 /* Give up if max escape points is met. */
2132 if ((int)escape_points
.length () > param_modref_max_escape_points
)
2135 fprintf (dump_file
, "--param modref-max-escape-points limit reached\n");
2139 escape_point new_ep
= {call
, arg
, min_flags
, direct
};
2140 escape_points
.safe_push (new_ep
);
2144 /* Merge in flags from F. */
2146 modref_lattice::merge (int f
)
2150 /* Check that flags seems sane: if function does not read the parameter
2151 it can not access it indirectly. */
2152 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 if ((flags
& f
) != flags
)
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 flags
= remove_useless_eaf_flags (flags
, 0, false);
2166 escape_points
.release ();
2172 /* Merge in WITH. Return true if anything changed. */
2175 modref_lattice::merge (const modref_lattice
&with
)
2180 bool changed
= merge (with
.flags
);
2184 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
2185 changed
|= add_escape_point (with
.escape_points
[i
].call
,
2186 with
.escape_points
[i
].arg
,
2187 with
.escape_points
[i
].min_flags
,
2188 with
.escape_points
[i
].direct
);
2192 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
2193 stores. Return true if anything changed. */
2196 modref_lattice::merge_deref (const modref_lattice
&with
, bool ignore_stores
)
2201 bool changed
= merge (deref_flags (with
.flags
, ignore_stores
));
2205 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
2207 int min_flags
= with
.escape_points
[i
].min_flags
;
2209 if (with
.escape_points
[i
].direct
)
2210 min_flags
= deref_flags (min_flags
, ignore_stores
);
2211 else if (ignore_stores
)
2212 min_flags
|= ignore_stores_eaf_flags
;
2213 changed
|= add_escape_point (with
.escape_points
[i
].call
,
2214 with
.escape_points
[i
].arg
,
2221 /* Merge in flags for direct load. */
2224 modref_lattice::merge_direct_load ()
2226 return merge (~(EAF_UNUSED
| EAF_NO_DIRECT_READ
));
2229 /* Merge in flags for direct store. */
2232 modref_lattice::merge_direct_store ()
2234 return merge (~(EAF_UNUSED
| EAF_NO_DIRECT_CLOBBER
));
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.
2246 After propagation the flags can be obtained using get_ssa_name_flags. */
2248 class modref_eaf_analysis
2251 /* Mark NAME as relevant for analysis. */
2252 void analyze_ssa_name (tree name
, bool deferred
= false);
2253 /* Dataflow solver. */
2255 /* Return flags computed earlier for NAME. */
2256 int get_ssa_name_flags (tree name
)
2258 int version
= SSA_NAME_VERSION (name
);
2259 gcc_checking_assert (m_lattice
[version
].known
);
2260 return m_lattice
[version
].flags
;
2262 /* In IPA mode this will record all escape points
2263 determined for NAME to PARM_IDNEX. Flags are minimal
2265 void record_escape_points (tree name
, int parm_index
, int flags
);
2266 modref_eaf_analysis (bool ipa
)
2270 m_lattice
.safe_grow_cleared (num_ssa_names
, true);
2272 ~modref_eaf_analysis ()
2274 gcc_checking_assert (!m_depth
);
2275 if (m_ipa
|| m_names_to_propagate
.length ())
2276 for (unsigned int i
= 0; i
< num_ssa_names
; i
++)
2277 m_lattice
[i
].release ();
2280 /* If true, we produce analysis for IPA mode. In this case escape points are
2283 /* Depth of recursion of analyze_ssa_name. */
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
;
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
,
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
2301 LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
2302 ARG is set to -1 for static chain. */
2305 modref_eaf_analysis::merge_call_lhs_flags (gcall
*call
, int arg
,
2306 tree name
, bool direct
,
2309 int index
= SSA_NAME_VERSION (name
);
2310 bool returned_directly
= false;
2312 /* If there is no return value, no flags are affected. */
2313 if (!gimple_call_lhs (call
))
2316 /* If we know that function returns given argument and it is not ARG
2317 we can still be happy. */
2320 int flags
= gimple_call_return_flags (call
);
2321 if (flags
& ERF_RETURNS_ARG
)
2323 if ((flags
& ERF_RETURN_ARG_MASK
) == arg
)
2324 returned_directly
= true;
2329 /* Make ERF_RETURNS_ARG overwrite EAF_UNUSED. */
2330 if (returned_directly
)
2335 /* If value is not returned at all, do nothing. */
2336 else if (!direct
&& !indirect
)
2339 /* If return value is SSA name determine its flags. */
2340 if (TREE_CODE (gimple_call_lhs (call
)) == SSA_NAME
)
2342 tree lhs
= gimple_call_lhs (call
);
2344 merge_with_ssa_name (name
, lhs
, false);
2346 merge_with_ssa_name (name
, lhs
, true);
2348 /* In the case of memory store we can do nothing. */
2350 m_lattice
[index
].merge (deref_flags (0, false));
2352 m_lattice
[index
].merge (0);
2355 /* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
2356 into flags for caller, update LATTICE of corresponding
2357 argument if needed. */
2360 callee_to_caller_flags (int call_flags
, bool ignore_stores
,
2361 modref_lattice
&lattice
)
2363 /* call_flags is about callee returning a value
2364 that is not the same as caller returning it. */
2365 call_flags
|= EAF_NOT_RETURNED_DIRECTLY
2366 | EAF_NOT_RETURNED_INDIRECTLY
;
2367 if (!ignore_stores
&& !(call_flags
& EAF_UNUSED
))
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
2372 if (!(call_flags
& EAF_NO_DIRECT_ESCAPE
))
2374 else if (!(call_flags
& EAF_NO_INDIRECT_ESCAPE
))
2375 lattice
.merge (~(EAF_NOT_RETURNED_INDIRECTLY
2376 | EAF_NO_DIRECT_READ
2377 | EAF_NO_INDIRECT_READ
2378 | EAF_NO_INDIRECT_CLOBBER
2382 call_flags
|= ignore_stores_eaf_flags
;
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) */
2393 modref_eaf_analysis::analyze_ssa_name (tree name
, bool deferred
)
2395 imm_use_iterator ui
;
2397 int index
= SSA_NAME_VERSION (name
);
2401 /* See if value is already computed. */
2402 if (m_lattice
[index
].known
|| m_lattice
[index
].do_dataflow
)
2404 if (m_lattice
[index
].open
)
2408 "%*sCycle in SSA graph\n",
2412 /* Recursion guard. */
2413 m_lattice
[index
].init ();
2414 if (m_depth
== param_modref_max_depth
)
2418 "%*sMax recursion depth reached; postponing\n",
2420 m_deferred_names
.safe_push (name
);
2428 "%*sAnalyzing flags of ssa name: ", m_depth
* 4, "");
2429 print_generic_expr (dump_file
, name
);
2430 fprintf (dump_file
, "\n");
2433 FOR_EACH_IMM_USE_STMT (use_stmt
, ui
, name
)
2435 if (m_lattice
[index
].flags
== 0)
2437 if (is_gimple_debug (use_stmt
))
2441 fprintf (dump_file
, "%*s Analyzing stmt: ", m_depth
* 4, "");
2442 print_gimple_stmt (dump_file
, use_stmt
, 0);
2444 /* If we see a direct non-debug use, clear unused bit.
2445 All dereferences should be accounted below using deref_flags. */
2446 m_lattice
[index
].merge (~EAF_UNUSED
);
2448 /* Gimple return may load the return value.
2449 Returning name counts as an use by tree-ssa-structalias.cc */
2450 if (greturn
*ret
= dyn_cast
<greturn
*> (use_stmt
))
2452 /* Returning through return slot is seen as memory write earlier. */
2453 if (DECL_RESULT (current_function_decl
)
2454 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl
)))
2456 else if (gimple_return_retval (ret
) == name
)
2457 m_lattice
[index
].merge (~(EAF_UNUSED
| EAF_NOT_RETURNED_DIRECTLY
2458 | EAF_NOT_RETURNED_DIRECTLY
));
2459 else if (memory_access_to (gimple_return_retval (ret
), name
))
2461 m_lattice
[index
].merge_direct_load ();
2462 m_lattice
[index
].merge (~(EAF_UNUSED
2463 | EAF_NOT_RETURNED_INDIRECTLY
));
2466 /* Account for LHS store, arg loads and flags from callee function. */
2467 else if (gcall
*call
= dyn_cast
<gcall
*> (use_stmt
))
2469 tree callee
= gimple_call_fndecl (call
);
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 if (gimple_call_fn (use_stmt
) == name
)
2477 m_lattice
[index
].merge (~(EAF_NO_DIRECT_CLOBBER
| EAF_UNUSED
));
2479 /* Recursion would require bit of propagation; give up for now. */
2480 if (callee
&& !m_ipa
&& recursive_call_p (current_function_decl
,
2482 m_lattice
[index
].merge (0);
2485 int ecf_flags
= gimple_call_flags (call
);
2486 bool ignore_stores
= ignore_stores_p (current_function_decl
,
2488 bool ignore_retval
= ignore_retval_p (current_function_decl
,
2491 /* Handle *name = func (...). */
2492 if (gimple_call_lhs (call
)
2493 && memory_access_to (gimple_call_lhs (call
), name
))
2495 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 if (gimple_call_return_slot_opt_p (call
)
2500 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call
))))
2502 int call_flags
= gimple_call_retslot_flags (call
);
2503 bool isretslot
= false;
2505 if (DECL_RESULT (current_function_decl
)
2506 && DECL_BY_REFERENCE
2507 (DECL_RESULT (current_function_decl
)))
2508 isretslot
= ssa_default_def
2510 DECL_RESULT (current_function_decl
))
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. */
2522 if (!(call_flags
& (EAF_NOT_RETURNED_DIRECTLY
2524 m_lattice
[index
].merge (0);
2525 else gcc_checking_assert
2526 (call_flags
& (EAF_NOT_RETURNED_INDIRECTLY
2528 call_flags
= callee_to_caller_flags
2532 m_lattice
[index
].merge (call_flags
);
2536 if (gimple_call_chain (call
)
2537 && (gimple_call_chain (call
) == name
))
2539 int call_flags
= gimple_call_static_chain_flags (call
);
2540 if (!ignore_retval
&& !(call_flags
& EAF_UNUSED
))
2541 merge_call_lhs_flags
2543 !(call_flags
& EAF_NOT_RETURNED_DIRECTLY
),
2544 !(call_flags
& EAF_NOT_RETURNED_INDIRECTLY
));
2545 call_flags
= callee_to_caller_flags
2546 (call_flags
, ignore_stores
,
2548 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
2549 m_lattice
[index
].merge (call_flags
);
2552 /* Process internal functions and right away. */
2553 bool record_ipa
= m_ipa
&& !gimple_call_internal_p (call
);
2555 /* Handle all function parameters. */
2556 for (unsigned i
= 0;
2557 i
< gimple_call_num_args (call
)
2558 && m_lattice
[index
].flags
; i
++)
2559 /* Name is directly passed to the callee. */
2560 if (gimple_call_arg (call
, i
) == name
)
2562 int call_flags
= gimple_call_arg_flags (call
, i
);
2564 merge_call_lhs_flags
2566 !(call_flags
& (EAF_NOT_RETURNED_DIRECTLY
2568 !(call_flags
& (EAF_NOT_RETURNED_INDIRECTLY
2570 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
2572 call_flags
= callee_to_caller_flags
2573 (call_flags
, ignore_stores
,
2576 m_lattice
[index
].merge (call_flags
);
2578 m_lattice
[index
].add_escape_point (call
, i
,
2582 /* Name is dereferenced and passed to a callee. */
2583 else if (memory_access_to (gimple_call_arg (call
, i
), name
))
2585 int call_flags
= deref_flags
2586 (gimple_call_arg_flags (call
, i
), ignore_stores
);
2587 if (!ignore_retval
&& !(call_flags
& EAF_UNUSED
)
2588 && (call_flags
& (EAF_NOT_RETURNED_DIRECTLY
2589 | EAF_NOT_RETURNED_INDIRECTLY
))
2590 != (EAF_NOT_RETURNED_DIRECTLY
2591 | EAF_NOT_RETURNED_INDIRECTLY
))
2592 merge_call_lhs_flags (call
, i
, name
, false, true);
2593 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
2594 m_lattice
[index
].merge_direct_load ();
2597 call_flags
= callee_to_caller_flags
2598 (call_flags
, ignore_stores
,
2601 m_lattice
[index
].merge (call_flags
);
2603 m_lattice
[index
].add_escape_point (call
, i
,
2609 else if (gimple_assign_load_p (use_stmt
))
2611 gassign
*assign
= as_a
<gassign
*> (use_stmt
);
2612 /* Memory to memory copy. */
2613 if (gimple_store_p (assign
))
2615 /* Handle *lhs = *name.
2617 We do not track memory locations, so assume that value
2618 is used arbitrarily. */
2619 if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
2620 m_lattice
[index
].merge (deref_flags (0, false));
2622 /* Handle *name = *exp. */
2623 if (memory_access_to (gimple_assign_lhs (assign
), name
))
2624 m_lattice
[index
].merge_direct_store ();
2626 /* Handle lhs = *name. */
2627 else if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
2629 tree lhs
= gimple_assign_lhs (assign
);
2630 merge_with_ssa_name (name
, lhs
, true);
2633 else if (gimple_store_p (use_stmt
))
2635 gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
);
2637 /* Handle *lhs = name. */
2638 if (assign
&& gimple_assign_rhs1 (assign
) == name
)
2641 fprintf (dump_file
, "%*s ssa name saved to memory\n",
2643 m_lattice
[index
].merge (0);
2645 /* Handle *name = exp. */
2647 && memory_access_to (gimple_assign_lhs (assign
), name
))
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 if (!cfun
->after_inlining
|| !gimple_clobber_p (assign
))
2655 m_lattice
[index
].merge_direct_store ();
2657 /* ASM statements etc. */
2661 fprintf (dump_file
, "%*s Unhandled store\n", m_depth
* 4, "");
2662 m_lattice
[index
].merge (0);
2665 else if (gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
))
2667 enum tree_code code
= gimple_assign_rhs_code (assign
);
2669 /* See if operation is a merge as considered by
2670 tree-ssa-structalias.cc:find_func_aliases. */
2671 if (!truth_value_p (code
)
2672 && code
!= POINTER_DIFF_EXPR
2673 && (code
!= POINTER_PLUS_EXPR
2674 || gimple_assign_rhs1 (assign
) == name
))
2676 tree lhs
= gimple_assign_lhs (assign
);
2677 merge_with_ssa_name (name
, lhs
, false);
2680 else if (gphi
*phi
= dyn_cast
<gphi
*> (use_stmt
))
2682 tree result
= gimple_phi_result (phi
);
2683 merge_with_ssa_name (name
, result
, false);
2685 /* Conditions are not considered escape points
2686 by tree-ssa-structalias. */
2687 else if (gimple_code (use_stmt
) == GIMPLE_COND
)
2692 fprintf (dump_file
, "%*s Unhandled stmt\n", m_depth
* 4, "");
2693 m_lattice
[index
].merge (0);
2698 fprintf (dump_file
, "%*s current flags of ", m_depth
* 4, "");
2699 print_generic_expr (dump_file
, name
);
2700 m_lattice
[index
].dump (dump_file
, m_depth
* 4 + 4);
2705 fprintf (dump_file
, "%*sflags of ssa name ", m_depth
* 4, "");
2706 print_generic_expr (dump_file
, name
);
2707 m_lattice
[index
].dump (dump_file
, m_depth
* 4 + 2);
2709 m_lattice
[index
].open
= false;
2710 if (!m_lattice
[index
].do_dataflow
)
2711 m_lattice
[index
].known
= true;
2714 /* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
2718 modref_eaf_analysis::merge_with_ssa_name (tree dest
, tree src
, bool deref
)
2720 int index
= SSA_NAME_VERSION (dest
);
2721 int src_index
= SSA_NAME_VERSION (src
);
2723 /* Merging lattice with itself is a no-op. */
2724 if (!deref
&& src
== dest
)
2728 analyze_ssa_name (src
);
2731 m_lattice
[index
].merge_deref (m_lattice
[src_index
], false);
2733 m_lattice
[index
].merge (m_lattice
[src_index
]);
2735 /* If we failed to produce final solution add an edge to the dataflow
2737 if (!m_lattice
[src_index
].known
)
2739 modref_lattice::propagate_edge e
= {index
, deref
};
2741 if (!m_lattice
[src_index
].propagate_to
.length ())
2742 m_names_to_propagate
.safe_push (src_index
);
2743 m_lattice
[src_index
].propagate_to
.safe_push (e
);
2744 m_lattice
[src_index
].changed
= true;
2745 m_lattice
[src_index
].do_dataflow
= true;
2748 "%*sWill propgate from ssa_name %i to %i%s\n",
2750 "", src_index
, index
, deref
? " (deref)" : "");
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. */
2758 modref_eaf_analysis::propagate ()
2763 bool changed
= true;
2765 while (m_deferred_names
.length ())
2767 tree name
= m_deferred_names
.pop ();
2769 fprintf (dump_file
, "Analyzing deferred SSA name\n");
2770 analyze_ssa_name (name
, true);
2773 if (!m_names_to_propagate
.length ())
2776 fprintf (dump_file
, "Propagating EAF flags\n");
2778 /* Compute reverse postorder. */
2785 auto_vec
<struct stack_entry
> stack
;
2786 int pos
= m_names_to_propagate
.length () - 1;
2788 rpo
.safe_grow (m_names_to_propagate
.length (), true);
2789 stack
.reserve_exact (m_names_to_propagate
.length ());
2791 /* We reuse known flag for RPO DFS walk bookkeeping. */
2793 FOR_EACH_VEC_ELT (m_names_to_propagate
, i
, index
)
2794 gcc_assert (!m_lattice
[index
].known
&& m_lattice
[index
].changed
);
2796 FOR_EACH_VEC_ELT (m_names_to_propagate
, i
, index
)
2798 if (!m_lattice
[index
].known
)
2800 stack_entry e
= {index
, 0};
2802 stack
.quick_push (e
);
2803 m_lattice
[index
].known
= true;
2805 while (stack
.length ())
2808 int index1
= stack
.last ().name
;
2810 while (stack
.last ().pos
< m_lattice
[index1
].propagate_to
.length ())
2812 int index2
= m_lattice
[index1
]
2813 .propagate_to
[stack
.last ().pos
].ssa_name
;
2815 stack
.last ().pos
++;
2816 if (!m_lattice
[index2
].known
2817 && m_lattice
[index2
].propagate_to
.length ())
2819 stack_entry e
= {index2
, 0};
2821 stack
.quick_push (e
);
2822 m_lattice
[index2
].known
= true;
2828 && stack
.last ().pos
== m_lattice
[index1
].propagate_to
.length ())
2830 rpo
[pos
--] = index1
;
2836 /* Perform iterative dataflow. */
2842 fprintf (dump_file
, " iteration %i\n", iterations
);
2843 FOR_EACH_VEC_ELT (rpo
, i
, index
)
2845 if (m_lattice
[index
].changed
)
2849 m_lattice
[index
].changed
= false;
2851 fprintf (dump_file
, " Visiting ssa name %i\n", index
);
2852 for (j
= 0; j
< m_lattice
[index
].propagate_to
.length (); j
++)
2855 int target
= m_lattice
[index
].propagate_to
[j
].ssa_name
;
2856 bool deref
= m_lattice
[index
].propagate_to
[j
].deref
;
2859 fprintf (dump_file
, " Propagating flags of ssa name"
2861 index
, target
, deref
? " (deref)" : "");
2862 m_lattice
[target
].known
= true;
2863 if (!m_lattice
[index
].propagate_to
[j
].deref
)
2864 ch
= m_lattice
[target
].merge (m_lattice
[index
]);
2866 ch
= m_lattice
[target
].merge_deref (m_lattice
[index
],
2872 fprintf (dump_file
, " New lattice: ");
2873 m_lattice
[target
].dump (dump_file
);
2876 m_lattice
[target
].changed
= true;
2882 fprintf (dump_file
, "EAF flags propagated in %i iterations\n", iterations
);
2885 /* Record escape points of PARM_INDEX according to LATTICE. */
2888 modref_eaf_analysis::record_escape_points (tree name
, int parm_index
, int flags
)
2890 modref_lattice
&lattice
= m_lattice
[SSA_NAME_VERSION (name
)];
2892 if (lattice
.escape_points
.length ())
2896 cgraph_node
*node
= cgraph_node::get (current_function_decl
);
2899 FOR_EACH_VEC_ELT (lattice
.escape_points
, ip
, ep
)
2900 if ((ep
->min_flags
& flags
) != flags
)
2902 cgraph_edge
*e
= node
->get_edge (ep
->call
);
2903 struct escape_entry ee
= {parm_index
, ep
->arg
,
2904 ep
->min_flags
, ep
->direct
};
2906 escape_summaries
->get_create (e
)->esc
.safe_push (ee
);
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
2920 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
)
2924 unsigned int parm_index
= 0;
2925 unsigned int count
= 0;
2926 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
2927 tree retslot
= NULL
;
2928 tree static_chain
= NULL
;
2930 /* If there is return slot, look up its SSA name. */
2931 if (DECL_RESULT (current_function_decl
)
2932 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl
)))
2933 retslot
= ssa_default_def (cfun
, DECL_RESULT (current_function_decl
));
2934 if (cfun
->static_chain_decl
)
2935 static_chain
= ssa_default_def (cfun
, cfun
->static_chain_decl
);
2937 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
2938 parm
= TREE_CHAIN (parm
))
2941 if (!count
&& !retslot
&& !static_chain
)
2944 modref_eaf_analysis
eaf_analysis (ipa
);
2946 /* Determine all SSA names we need to know flags for. */
2947 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
2948 parm
= TREE_CHAIN (parm
))
2950 tree name
= ssa_default_def (cfun
, parm
);
2952 eaf_analysis
.analyze_ssa_name (name
);
2955 eaf_analysis
.analyze_ssa_name (retslot
);
2957 eaf_analysis
.analyze_ssa_name (static_chain
);
2959 /* Do the dataflow. */
2960 eaf_analysis
.propagate ();
2962 tree attr
= lookup_attribute ("fn spec",
2964 (TREE_TYPE (current_function_decl
)));
2965 attr_fnspec
fnspec (attr
2966 ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr
)))
2970 /* Store results to summaries. */
2971 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
; parm_index
++,
2972 parm
= TREE_CHAIN (parm
))
2974 tree name
= ssa_default_def (cfun
, parm
);
2975 if (!name
|| has_zero_uses (name
))
2977 /* We do not track non-SSA parameters,
2978 but we want to track unused gimple_regs. */
2979 if (!is_gimple_reg (parm
))
2983 if (parm_index
>= summary
->arg_flags
.length ())
2984 summary
->arg_flags
.safe_grow_cleared (count
, true);
2985 summary
->arg_flags
[parm_index
] = EAF_UNUSED
;
2989 if (parm_index
>= summary_lto
->arg_flags
.length ())
2990 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
2991 summary_lto
->arg_flags
[parm_index
] = EAF_UNUSED
;
2995 int flags
= eaf_analysis
.get_ssa_name_flags (name
);
2996 int attr_flags
= fnspec
.arg_eaf_flags (parm_index
);
2998 if (dump_file
&& (flags
| attr_flags
) != flags
&& !(flags
& EAF_UNUSED
))
3001 " Flags for param %i combined with fnspec flags:",
3003 dump_eaf_flags (dump_file
, attr_flags
, false);
3004 fprintf (dump_file
, " determined: ");
3005 dump_eaf_flags (dump_file
, flags
, true);
3007 flags
|= attr_flags
;
3009 /* Eliminate useless flags so we do not end up storing unnecessary
3012 flags
= remove_useless_eaf_flags
3014 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3015 if (past_flags
.length () > parm_index
)
3017 int past
= past_flags
[parm_index
];
3018 past
= remove_useless_eaf_flags
3020 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 past
&= ~(EAF_NO_DIRECT_READ
| EAF_NO_INDIRECT_READ
);
3025 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
3028 " Flags for param %i combined with IPA pass:",
3030 dump_eaf_flags (dump_file
, past
, false);
3031 fprintf (dump_file
, " determined: ");
3032 dump_eaf_flags (dump_file
, flags
, true);
3034 if (!(flags
& EAF_UNUSED
))
3042 if (parm_index
>= summary
->arg_flags
.length ())
3043 summary
->arg_flags
.safe_grow_cleared (count
, true);
3044 summary
->arg_flags
[parm_index
] = flags
;
3048 if (parm_index
>= summary_lto
->arg_flags
.length ())
3049 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
3050 summary_lto
->arg_flags
[parm_index
] = flags
;
3052 eaf_analysis
.record_escape_points (name
, parm_index
, flags
);
3057 int flags
= eaf_analysis
.get_ssa_name_flags (retslot
);
3058 int past
= past_retslot_flags
;
3060 flags
= remove_useless_eaf_flags (flags
, ecf_flags
, false);
3061 past
= remove_useless_eaf_flags
3063 VOID_TYPE_P (TREE_TYPE
3064 (TREE_TYPE (current_function_decl
))));
3065 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
3068 " Retslot flags combined with IPA pass:");
3069 dump_eaf_flags (dump_file
, past
, false);
3070 fprintf (dump_file
, " determined: ");
3071 dump_eaf_flags (dump_file
, flags
, true);
3073 if (!(flags
& EAF_UNUSED
))
3078 summary
->retslot_flags
= flags
;
3080 summary_lto
->retslot_flags
= flags
;
3081 eaf_analysis
.record_escape_points (retslot
,
3082 MODREF_RETSLOT_PARM
, flags
);
3087 int flags
= eaf_analysis
.get_ssa_name_flags (static_chain
);
3088 int past
= past_static_chain_flags
;
3090 flags
= remove_useless_eaf_flags (flags
, ecf_flags
, false);
3091 past
= remove_useless_eaf_flags
3093 VOID_TYPE_P (TREE_TYPE
3094 (TREE_TYPE (current_function_decl
))));
3095 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
3098 " Static chain flags combined with IPA pass:");
3099 dump_eaf_flags (dump_file
, past
, false);
3100 fprintf (dump_file
, " determined: ");
3101 dump_eaf_flags (dump_file
, flags
, true);
3103 if (!(flags
& EAF_UNUSED
))
3108 summary
->static_chain_flags
= flags
;
3110 summary_lto
->static_chain_flags
= flags
;
3111 eaf_analysis
.record_escape_points (static_chain
,
3112 MODREF_STATIC_CHAIN_PARM
,
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. */
3123 analyze_function (bool ipa
)
3125 bool fixup_cfg
= false;
3127 fprintf (dump_file
, "\n\nmodref analyzing '%s' (ipa=%i)%s%s\n",
3128 cgraph_node::get (current_function_decl
)->dump_name (), ipa
,
3129 TREE_READONLY (current_function_decl
) ? " (const)" : "",
3130 DECL_PURE_P (current_function_decl
) ? " (pure)" : "");
3132 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
3133 if (!flag_ipa_modref
3134 || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl
)))
3137 /* Compute no-LTO summaries when local optimization is going to happen. */
3138 bool nolto
= (!ipa
|| ((!flag_lto
|| flag_fat_lto_objects
) && !in_lto_p
)
3139 || (in_lto_p
&& !flag_wpa
3140 && flag_incremental_link
!= INCREMENTAL_LINK_LTO
));
3141 /* Compute LTO when LTO streaming is going to happen. */
3142 bool lto
= ipa
&& ((flag_lto
&& !in_lto_p
)
3144 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
3145 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
3147 modref_summary
*summary
= NULL
;
3148 modref_summary_lto
*summary_lto
= NULL
;
3150 bool past_flags_known
= false;
3151 auto_vec
<eaf_flags_t
> past_flags
;
3152 int past_retslot_flags
= 0;
3153 int past_static_chain_flags
= 0;
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
3161 if (!optimization_summaries
)
3162 optimization_summaries
= modref_summaries::create_ggc (symtab
);
3163 else /* Remove existing summary if we are re-running the pass. */
3165 summary
= optimization_summaries
->get (fnode
);
3171 fprintf (dump_file
, "Past summary:\n");
3172 optimization_summaries
->get (fnode
)->dump (dump_file
);
3174 past_flags
.reserve_exact (summary
->arg_flags
.length ());
3175 past_flags
.splice (summary
->arg_flags
);
3176 past_retslot_flags
= summary
->retslot_flags
;
3177 past_static_chain_flags
= summary
->static_chain_flags
;
3178 past_flags_known
= true;
3180 optimization_summaries
->remove (fnode
);
3182 summary
= optimization_summaries
->get_create (fnode
);
3183 gcc_checking_assert (nolto
&& !lto
);
3185 /* In IPA mode we analyze every function precisely once. Assert that. */
3191 summaries
= modref_summaries::create_ggc (symtab
);
3193 summaries
->remove (fnode
);
3194 summary
= summaries
->get_create (fnode
);
3199 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
3201 summaries_lto
->remove (fnode
);
3202 summary_lto
= summaries_lto
->get_create (fnode
);
3204 if (!fnspec_summaries
)
3205 fnspec_summaries
= new fnspec_summaries_t (symtab
);
3206 if (!escape_summaries
)
3207 escape_summaries
= new escape_summaries_t (symtab
);
3211 /* Create and initialize summary for F.
3212 Note that summaries may be already allocated from previous
3216 gcc_assert (!summary
->loads
);
3217 summary
->loads
= modref_records::create_ggc ();
3218 gcc_assert (!summary
->stores
);
3219 summary
->stores
= modref_records::create_ggc ();
3220 summary
->writes_errno
= false;
3221 summary
->side_effects
= false;
3222 summary
->nondeterministic
= false;
3223 summary
->calls_interposable
= false;
3227 gcc_assert (!summary_lto
->loads
);
3228 summary_lto
->loads
= modref_records_lto::create_ggc ();
3229 gcc_assert (!summary_lto
->stores
);
3230 summary_lto
->stores
= modref_records_lto::create_ggc ();
3231 summary_lto
->writes_errno
= false;
3232 summary_lto
->side_effects
= false;
3233 summary_lto
->nondeterministic
= false;
3234 summary_lto
->calls_interposable
= false;
3237 analyze_parms (summary
, summary_lto
, ipa
,
3238 past_flags
, past_retslot_flags
, past_static_chain_flags
);
3241 modref_access_analysis
analyzer (ipa
, summary
, summary_lto
);
3242 analyzer
.analyze ();
3245 if (!ipa
&& flag_ipa_pure_const
)
3247 if (!summary
->stores
->every_base
&& !summary
->stores
->bases
3248 && !summary
->nondeterministic
)
3250 if (!summary
->loads
->every_base
&& !summary
->loads
->bases
3251 && !summary
->calls_interposable
)
3252 fixup_cfg
= ipa_make_function_const (fnode
,
3253 summary
->side_effects
, true);
3255 fixup_cfg
= ipa_make_function_pure (fnode
,
3256 summary
->side_effects
, true);
3259 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
3260 if (summary
&& !summary
->useful_p (ecf_flags
))
3263 optimization_summaries
->remove (fnode
);
3265 summaries
->remove (fnode
);
3269 summary
->finalize (current_function_decl
);
3270 if (summary_lto
&& !summary_lto
->useful_p (ecf_flags
))
3272 summaries_lto
->remove (fnode
);
3276 if (ipa
&& !summary
&& !summary_lto
)
3277 remove_modref_edge_summaries (fnode
);
3281 fprintf (dump_file
, " - modref done with result: tracked.\n");
3283 summary
->dump (dump_file
);
3285 summary_lto
->dump (dump_file
);
3286 dump_modref_edge_summaries (dump_file
, fnode
, 2);
3287 /* To simplify debugging, compare IPA and local solutions. */
3288 if (past_flags_known
&& summary
)
3290 size_t len
= summary
->arg_flags
.length ();
3292 if (past_flags
.length () > len
)
3293 len
= past_flags
.length ();
3294 for (size_t i
= 0; i
< len
; i
++)
3296 int old_flags
= i
< past_flags
.length () ? past_flags
[i
] : 0;
3297 int new_flags
= i
< summary
->arg_flags
.length ()
3298 ? summary
->arg_flags
[i
] : 0;
3299 old_flags
= remove_useless_eaf_flags
3300 (old_flags
, flags_from_decl_or_type (current_function_decl
),
3301 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3302 if (old_flags
!= new_flags
)
3304 if ((old_flags
& ~new_flags
) == 0
3305 || (new_flags
& EAF_UNUSED
))
3306 fprintf (dump_file
, " Flags for param %i improved:",
3309 fprintf (dump_file
, " Flags for param %i changed:",
3311 dump_eaf_flags (dump_file
, old_flags
, false);
3312 fprintf (dump_file
, " -> ");
3313 dump_eaf_flags (dump_file
, new_flags
, true);
3316 past_retslot_flags
= remove_useless_eaf_flags
3317 (past_retslot_flags
,
3318 flags_from_decl_or_type (current_function_decl
),
3319 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3320 if (past_retslot_flags
!= summary
->retslot_flags
)
3322 if ((past_retslot_flags
& ~summary
->retslot_flags
) == 0
3323 || (summary
->retslot_flags
& EAF_UNUSED
))
3324 fprintf (dump_file
, " Flags for retslot improved:");
3326 fprintf (dump_file
, " Flags for retslot changed:");
3327 dump_eaf_flags (dump_file
, past_retslot_flags
, false);
3328 fprintf (dump_file
, " -> ");
3329 dump_eaf_flags (dump_file
, summary
->retslot_flags
, true);
3331 past_static_chain_flags
= remove_useless_eaf_flags
3332 (past_static_chain_flags
,
3333 flags_from_decl_or_type (current_function_decl
),
3334 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3335 if (past_static_chain_flags
!= summary
->static_chain_flags
)
3337 if ((past_static_chain_flags
& ~summary
->static_chain_flags
) == 0
3338 || (summary
->static_chain_flags
& EAF_UNUSED
))
3339 fprintf (dump_file
, " Flags for static chain improved:");
3341 fprintf (dump_file
, " Flags for static chain changed:");
3342 dump_eaf_flags (dump_file
, past_static_chain_flags
, false);
3343 fprintf (dump_file
, " -> ");
3344 dump_eaf_flags (dump_file
, summary
->static_chain_flags
, true);
3347 else if (past_flags_known
&& !summary
)
3349 for (size_t i
= 0; i
< past_flags
.length (); i
++)
3351 int old_flags
= past_flags
[i
];
3352 old_flags
= remove_useless_eaf_flags
3353 (old_flags
, flags_from_decl_or_type (current_function_decl
),
3354 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3357 fprintf (dump_file
, " Flags for param %i worsened:",
3359 dump_eaf_flags (dump_file
, old_flags
, false);
3360 fprintf (dump_file
, " -> \n");
3363 past_retslot_flags
= remove_useless_eaf_flags
3364 (past_retslot_flags
,
3365 flags_from_decl_or_type (current_function_decl
),
3366 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3367 if (past_retslot_flags
)
3369 fprintf (dump_file
, " Flags for retslot worsened:");
3370 dump_eaf_flags (dump_file
, past_retslot_flags
, false);
3371 fprintf (dump_file
, " ->\n");
3373 past_static_chain_flags
= remove_useless_eaf_flags
3374 (past_static_chain_flags
,
3375 flags_from_decl_or_type (current_function_decl
),
3376 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3377 if (past_static_chain_flags
)
3379 fprintf (dump_file
, " Flags for static chain worsened:");
3380 dump_eaf_flags (dump_file
, past_static_chain_flags
, false);
3381 fprintf (dump_file
, " ->\n");
3388 /* Callback for generate_summary. */
3391 modref_generate (void)
3393 struct cgraph_node
*node
;
3394 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
3396 function
*f
= DECL_STRUCT_FUNCTION (node
->decl
);
3400 analyze_function (true);
3405 } /* ANON namespace. */
3407 /* Debugging helper. */
3410 debug_eaf_flags (int flags
)
3412 dump_eaf_flags (stderr
, flags
, true);
3415 /* Called when a new function is inserted to callgraph late. */
3418 modref_summaries::insert (struct cgraph_node
*node
, modref_summary
*)
3420 /* Local passes ought to be executed by the pass manager. */
3421 if (this == optimization_summaries
)
3423 optimization_summaries
->remove (node
);
3426 if (!DECL_STRUCT_FUNCTION (node
->decl
)
3427 || !opt_for_fn (node
->decl
, flag_ipa_modref
))
3429 summaries
->remove (node
);
3432 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
3433 analyze_function (true);
3437 /* Called when a new function is inserted to callgraph late. */
3440 modref_summaries_lto::insert (struct cgraph_node
*node
, modref_summary_lto
*)
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
3445 if (!DECL_STRUCT_FUNCTION (node
->decl
)
3446 || !opt_for_fn (node
->decl
, flag_ipa_modref
)
3449 summaries_lto
->remove (node
);
3452 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
3453 analyze_function (true);
3457 /* Called when new clone is inserted to callgraph late. */
3460 modref_summaries::duplicate (cgraph_node
*, cgraph_node
*dst
,
3461 modref_summary
*src_data
,
3462 modref_summary
*dst_data
)
3464 /* Do not duplicate optimization summaries; we do not handle parameter
3465 transforms on them. */
3466 if (this == optimization_summaries
)
3468 optimization_summaries
->remove (dst
);
3471 dst_data
->stores
= modref_records::create_ggc ();
3472 dst_data
->stores
->copy_from (src_data
->stores
);
3473 dst_data
->loads
= modref_records::create_ggc ();
3474 dst_data
->loads
->copy_from (src_data
->loads
);
3475 dst_data
->kills
.reserve_exact (src_data
->kills
.length ());
3476 dst_data
->kills
.splice (src_data
->kills
);
3477 dst_data
->writes_errno
= src_data
->writes_errno
;
3478 dst_data
->side_effects
= src_data
->side_effects
;
3479 dst_data
->nondeterministic
= src_data
->nondeterministic
;
3480 dst_data
->calls_interposable
= src_data
->calls_interposable
;
3481 if (src_data
->arg_flags
.length ())
3482 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
3483 dst_data
->retslot_flags
= src_data
->retslot_flags
;
3484 dst_data
->static_chain_flags
= src_data
->static_chain_flags
;
3487 /* Called when new clone is inserted to callgraph late. */
3490 modref_summaries_lto::duplicate (cgraph_node
*, cgraph_node
*,
3491 modref_summary_lto
*src_data
,
3492 modref_summary_lto
*dst_data
)
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 gcc_checking_assert (!((modref_summaries_lto
*)summaries_lto
)->propagated
);
3497 dst_data
->stores
= modref_records_lto::create_ggc ();
3498 dst_data
->stores
->copy_from (src_data
->stores
);
3499 dst_data
->loads
= modref_records_lto::create_ggc ();
3500 dst_data
->loads
->copy_from (src_data
->loads
);
3501 dst_data
->kills
.reserve_exact (src_data
->kills
.length ());
3502 dst_data
->kills
.splice (src_data
->kills
);
3503 dst_data
->writes_errno
= src_data
->writes_errno
;
3504 dst_data
->side_effects
= src_data
->side_effects
;
3505 dst_data
->nondeterministic
= src_data
->nondeterministic
;
3506 dst_data
->calls_interposable
= src_data
->calls_interposable
;
3507 if (src_data
->arg_flags
.length ())
3508 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
3509 dst_data
->retslot_flags
= src_data
->retslot_flags
;
3510 dst_data
->static_chain_flags
= src_data
->static_chain_flags
;
3515 /* Definition of the modref pass on GIMPLE. */
3516 const pass_data pass_data_modref
= {
3521 (PROP_cfg
| PROP_ssa
),
3528 class pass_modref
: public gimple_opt_pass
3531 pass_modref (gcc::context
*ctxt
)
3532 : gimple_opt_pass (pass_data_modref
, ctxt
) {}
3534 /* opt_pass methods: */
3535 opt_pass
*clone () final override
3537 return new pass_modref (m_ctxt
);
3539 bool gate (function
*) final override
3541 return flag_ipa_modref
;
3543 unsigned int execute (function
*) final override
;
3546 /* Encode TT to the output block OB using the summary streaming API. */
3549 write_modref_records (modref_records_lto
*tt
, struct output_block
*ob
)
3551 streamer_write_uhwi (ob
, tt
->every_base
);
3552 streamer_write_uhwi (ob
, vec_safe_length (tt
->bases
));
3553 for (auto base_node
: tt
->bases
)
3555 stream_write_tree (ob
, base_node
->base
, true);
3557 streamer_write_uhwi (ob
, base_node
->every_ref
);
3558 streamer_write_uhwi (ob
, vec_safe_length (base_node
->refs
));
3560 for (auto ref_node
: base_node
->refs
)
3562 stream_write_tree (ob
, ref_node
->ref
, true);
3563 streamer_write_uhwi (ob
, ref_node
->every_access
);
3564 streamer_write_uhwi (ob
, vec_safe_length (ref_node
->accesses
));
3566 for (auto access_node
: ref_node
->accesses
)
3567 access_node
.stream_out (ob
);
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. */
3578 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
)
3583 size_t max_bases
= opt_for_fn (decl
, param_modref_max_bases
);
3584 size_t max_refs
= opt_for_fn (decl
, param_modref_max_refs
);
3585 size_t max_accesses
= opt_for_fn (decl
, param_modref_max_accesses
);
3588 *lto_ret
= modref_records_lto::create_ggc ();
3590 *nolto_ret
= modref_records::create_ggc ();
3591 gcc_checking_assert (lto_ret
|| nolto_ret
);
3593 size_t every_base
= streamer_read_uhwi (ib
);
3594 size_t nbase
= streamer_read_uhwi (ib
);
3596 gcc_assert (!every_base
|| nbase
== 0);
3600 (*nolto_ret
)->collapse ();
3602 (*lto_ret
)->collapse ();
3604 for (size_t i
= 0; i
< nbase
; i
++)
3606 tree base_tree
= stream_read_tree (ib
, data_in
);
3607 modref_base_node
<alias_set_type
> *nolto_base_node
= NULL
;
3608 modref_base_node
<tree
> *lto_base_node
= NULL
;
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 if (base_tree
&& !get_alias_set (base_tree
))
3618 fprintf (dump_file
, "Streamed in alias set 0 type ");
3619 print_generic_expr (dump_file
, base_tree
);
3620 fprintf (dump_file
, "\n");
3626 nolto_base_node
= (*nolto_ret
)->insert_base (base_tree
3627 ? get_alias_set (base_tree
)
3630 lto_base_node
= (*lto_ret
)->insert_base (base_tree
, 0, max_bases
);
3631 size_t every_ref
= streamer_read_uhwi (ib
);
3632 size_t nref
= streamer_read_uhwi (ib
);
3634 gcc_assert (!every_ref
|| nref
== 0);
3637 if (nolto_base_node
)
3638 nolto_base_node
->collapse ();
3640 lto_base_node
->collapse ();
3642 for (size_t j
= 0; j
< nref
; j
++)
3644 tree ref_tree
= stream_read_tree (ib
, data_in
);
3646 if (ref_tree
&& !get_alias_set (ref_tree
))
3650 fprintf (dump_file
, "Streamed in alias set 0 type ");
3651 print_generic_expr (dump_file
, ref_tree
);
3652 fprintf (dump_file
, "\n");
3657 modref_ref_node
<alias_set_type
> *nolto_ref_node
= NULL
;
3658 modref_ref_node
<tree
> *lto_ref_node
= NULL
;
3660 if (nolto_base_node
)
3662 = nolto_base_node
->insert_ref (ref_tree
3663 ? get_alias_set (ref_tree
) : 0,
3666 lto_ref_node
= lto_base_node
->insert_ref (ref_tree
, max_refs
);
3668 size_t every_access
= streamer_read_uhwi (ib
);
3669 size_t naccesses
= streamer_read_uhwi (ib
);
3671 if (nolto_ref_node
&& every_access
)
3672 nolto_ref_node
->collapse ();
3673 if (lto_ref_node
&& every_access
)
3674 lto_ref_node
->collapse ();
3676 for (size_t k
= 0; k
< naccesses
; k
++)
3678 modref_access_node a
= modref_access_node::stream_in (ib
);
3680 nolto_ref_node
->insert_access (a
, max_accesses
, false);
3682 lto_ref_node
->insert_access (a
, max_accesses
, false);
3687 (*lto_ret
)->cleanup ();
3689 (*nolto_ret
)->cleanup ();
3692 /* Write ESUM to BP. */
3695 modref_write_escape_summary (struct bitpack_d
*bp
, escape_summary
*esum
)
3699 bp_pack_var_len_unsigned (bp
, 0);
3702 bp_pack_var_len_unsigned (bp
, esum
->esc
.length ());
3705 FOR_EACH_VEC_ELT (esum
->esc
, i
, ee
)
3707 bp_pack_var_len_int (bp
, ee
->parm_index
);
3708 bp_pack_var_len_unsigned (bp
, ee
->arg
);
3709 bp_pack_var_len_unsigned (bp
, ee
->min_flags
);
3710 bp_pack_value (bp
, ee
->direct
, 1);
3714 /* Read escape summary for E from BP. */
3717 modref_read_escape_summary (struct bitpack_d
*bp
, cgraph_edge
*e
)
3719 unsigned int n
= bp_unpack_var_len_unsigned (bp
);
3722 escape_summary
*esum
= escape_summaries
->get_create (e
);
3723 esum
->esc
.reserve_exact (n
);
3724 for (unsigned int i
= 0; i
< n
; i
++)
3727 ee
.parm_index
= bp_unpack_var_len_int (bp
);
3728 ee
.arg
= bp_unpack_var_len_unsigned (bp
);
3729 ee
.min_flags
= bp_unpack_var_len_unsigned (bp
);
3730 ee
.direct
= bp_unpack_value (bp
, 1);
3731 esum
->esc
.quick_push (ee
);
3735 /* Callback for write_summary. */
3740 struct output_block
*ob
= create_output_block (LTO_section_ipa_modref
);
3741 lto_symtab_encoder_t encoder
= ob
->decl_state
->symtab_node_encoder
;
3742 unsigned int count
= 0;
3747 streamer_write_uhwi (ob
, 0);
3748 streamer_write_char_stream (ob
->main_stream
, 0);
3750 destroy_output_block (ob
);
3754 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
3756 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
3757 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
3758 modref_summary_lto
*r
;
3760 if (cnode
&& cnode
->definition
&& !cnode
->alias
3761 && (r
= summaries_lto
->get (cnode
))
3762 && r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
3765 streamer_write_uhwi (ob
, count
);
3767 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
3769 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
3770 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
3772 if (cnode
&& cnode
->definition
&& !cnode
->alias
)
3774 modref_summary_lto
*r
= summaries_lto
->get (cnode
);
3776 if (!r
|| !r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
3779 streamer_write_uhwi (ob
, lto_symtab_encoder_encode (encoder
, cnode
));
3781 streamer_write_uhwi (ob
, r
->arg_flags
.length ());
3782 for (unsigned int i
= 0; i
< r
->arg_flags
.length (); i
++)
3783 streamer_write_uhwi (ob
, r
->arg_flags
[i
]);
3784 streamer_write_uhwi (ob
, r
->retslot_flags
);
3785 streamer_write_uhwi (ob
, r
->static_chain_flags
);
3787 write_modref_records (r
->loads
, ob
);
3788 write_modref_records (r
->stores
, ob
);
3789 streamer_write_uhwi (ob
, r
->kills
.length ());
3790 for (auto kill
: r
->kills
)
3791 kill
.stream_out (ob
);
3793 struct bitpack_d bp
= bitpack_create (ob
->main_stream
);
3794 bp_pack_value (&bp
, r
->writes_errno
, 1);
3795 bp_pack_value (&bp
, r
->side_effects
, 1);
3796 bp_pack_value (&bp
, r
->nondeterministic
, 1);
3797 bp_pack_value (&bp
, r
->calls_interposable
, 1);
3800 for (cgraph_edge
*e
= cnode
->indirect_calls
;
3801 e
; e
= e
->next_callee
)
3803 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
3804 bp_pack_value (&bp
, sum
!= NULL
, 1);
3806 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
3807 class escape_summary
*esum
= escape_summaries
->get (e
);
3808 modref_write_escape_summary (&bp
,esum
);
3810 for (cgraph_edge
*e
= cnode
->callees
; e
; e
= e
->next_callee
)
3812 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
3813 bp_pack_value (&bp
, sum
!= NULL
, 1);
3815 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
3816 class escape_summary
*esum
= escape_summaries
->get (e
);
3817 modref_write_escape_summary (&bp
,esum
);
3820 streamer_write_bitpack (&bp
);
3823 streamer_write_char_stream (ob
->main_stream
, 0);
3825 destroy_output_block (ob
);
3829 read_section (struct lto_file_decl_data
*file_data
, const char *data
,
3832 const struct lto_function_header
*header
3833 = (const struct lto_function_header
*) data
;
3834 const int cfg_offset
= sizeof (struct lto_function_header
);
3835 const int main_offset
= cfg_offset
+ header
->cfg_size
;
3836 const int string_offset
= main_offset
+ header
->main_size
;
3837 struct data_in
*data_in
;
3839 unsigned int f_count
;
3841 lto_input_block
ib ((const char *) data
+ main_offset
, header
->main_size
,
3845 = lto_data_in_create (file_data
, (const char *) data
+ string_offset
,
3846 header
->string_size
, vNULL
);
3847 f_count
= streamer_read_uhwi (&ib
);
3848 for (i
= 0; i
< f_count
; i
++)
3850 struct cgraph_node
*node
;
3851 lto_symtab_encoder_t encoder
;
3853 unsigned int index
= streamer_read_uhwi (&ib
);
3854 encoder
= file_data
->symtab_node_encoder
;
3855 node
= dyn_cast
<cgraph_node
*> (lto_symtab_encoder_deref (encoder
,
3858 modref_summary
*modref_sum
= summaries
3859 ? summaries
->get_create (node
) : NULL
;
3860 modref_summary_lto
*modref_sum_lto
= summaries_lto
3861 ? summaries_lto
->get_create (node
)
3863 if (optimization_summaries
)
3864 modref_sum
= optimization_summaries
->get_create (node
);
3868 modref_sum
->writes_errno
= false;
3869 modref_sum
->side_effects
= false;
3870 modref_sum
->nondeterministic
= false;
3871 modref_sum
->calls_interposable
= false;
3875 modref_sum_lto
->writes_errno
= false;
3876 modref_sum_lto
->side_effects
= false;
3877 modref_sum_lto
->nondeterministic
= false;
3878 modref_sum_lto
->calls_interposable
= false;
3881 gcc_assert (!modref_sum
|| (!modref_sum
->loads
3882 && !modref_sum
->stores
));
3883 gcc_assert (!modref_sum_lto
|| (!modref_sum_lto
->loads
3884 && !modref_sum_lto
->stores
));
3885 unsigned int args
= streamer_read_uhwi (&ib
);
3886 if (args
&& modref_sum
)
3887 modref_sum
->arg_flags
.reserve_exact (args
);
3888 if (args
&& modref_sum_lto
)
3889 modref_sum_lto
->arg_flags
.reserve_exact (args
);
3890 for (unsigned int i
= 0; i
< args
; i
++)
3892 eaf_flags_t flags
= streamer_read_uhwi (&ib
);
3894 modref_sum
->arg_flags
.quick_push (flags
);
3896 modref_sum_lto
->arg_flags
.quick_push (flags
);
3898 eaf_flags_t flags
= streamer_read_uhwi (&ib
);
3900 modref_sum
->retslot_flags
= flags
;
3902 modref_sum_lto
->retslot_flags
= flags
;
3904 flags
= streamer_read_uhwi (&ib
);
3906 modref_sum
->static_chain_flags
= flags
;
3908 modref_sum_lto
->static_chain_flags
= flags
;
3910 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 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 int j
= streamer_read_uhwi (&ib
);
3917 if (j
&& modref_sum
)
3918 modref_sum
->kills
.reserve_exact (j
);
3919 if (j
&& modref_sum_lto
)
3920 modref_sum_lto
->kills
.reserve_exact (j
);
3921 for (int k
= 0; k
< j
; k
++)
3923 modref_access_node a
= modref_access_node::stream_in (&ib
);
3926 modref_sum
->kills
.quick_push (a
);
3928 modref_sum_lto
->kills
.quick_push (a
);
3930 struct bitpack_d bp
= streamer_read_bitpack (&ib
);
3931 if (bp_unpack_value (&bp
, 1))
3934 modref_sum
->writes_errno
= true;
3936 modref_sum_lto
->writes_errno
= true;
3938 if (bp_unpack_value (&bp
, 1))
3941 modref_sum
->side_effects
= true;
3943 modref_sum_lto
->side_effects
= true;
3945 if (bp_unpack_value (&bp
, 1))
3948 modref_sum
->nondeterministic
= true;
3950 modref_sum_lto
->nondeterministic
= true;
3952 if (bp_unpack_value (&bp
, 1))
3955 modref_sum
->calls_interposable
= true;
3957 modref_sum_lto
->calls_interposable
= true;
3961 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
3963 if (bp_unpack_value (&bp
, 1))
3965 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
3966 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
3968 modref_read_escape_summary (&bp
, e
);
3970 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
3972 if (bp_unpack_value (&bp
, 1))
3974 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
3975 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
3977 modref_read_escape_summary (&bp
, e
);
3981 modref_sum
->finalize (node
->decl
);
3984 fprintf (dump_file
, "Read modref for %s\n",
3985 node
->dump_name ());
3987 modref_sum
->dump (dump_file
);
3989 modref_sum_lto
->dump (dump_file
);
3990 dump_modref_edge_summaries (dump_file
, node
, 4);
3994 lto_free_section_data (file_data
, LTO_section_ipa_modref
, NULL
, data
,
3996 lto_data_in_delete (data_in
);
3999 /* Callback for read_summary. */
4004 struct lto_file_decl_data
**file_data_vec
= lto_get_file_decl_data ();
4005 struct lto_file_decl_data
*file_data
;
4008 gcc_checking_assert (!optimization_summaries
&& !summaries
&& !summaries_lto
);
4010 optimization_summaries
= modref_summaries::create_ggc (symtab
);
4013 if (flag_wpa
|| flag_incremental_link
== INCREMENTAL_LINK_LTO
)
4014 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
4016 || (flag_incremental_link
== INCREMENTAL_LINK_LTO
4017 && flag_fat_lto_objects
))
4018 summaries
= modref_summaries::create_ggc (symtab
);
4019 if (!fnspec_summaries
)
4020 fnspec_summaries
= new fnspec_summaries_t (symtab
);
4021 if (!escape_summaries
)
4022 escape_summaries
= new escape_summaries_t (symtab
);
4025 while ((file_data
= file_data_vec
[j
++]))
4028 const char *data
= lto_get_summary_section_data (file_data
,
4029 LTO_section_ipa_modref
,
4032 read_section (file_data
, data
, len
);
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 fatal_error (input_location
,
4038 "IPA modref summary is missing in input file");
4042 /* Recompute arg_flags for param adjustments in INFO. */
4045 remap_arg_flags (auto_vec
<eaf_flags_t
> &arg_flags
, clone_info
*info
)
4047 auto_vec
<eaf_flags_t
> old
= arg_flags
.copy ();
4050 ipa_adjusted_param
*p
;
4052 arg_flags
.release ();
4054 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
4056 int o
= info
->param_adjustments
->get_original_index (i
);
4057 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
4061 arg_flags
.safe_grow_cleared (max
+ 1, true);
4062 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
4064 int o
= info
->param_adjustments
->get_original_index (i
);
4065 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
4066 arg_flags
[i
] = old
[o
];
4070 /* Update kills according to the parm map MAP. */
4073 remap_kills (vec
<modref_access_node
> &kills
, const vec
<int> &map
)
4075 for (size_t i
= 0; i
< kills
.length ();)
4076 if (kills
[i
].parm_index
>= 0)
4078 if (kills
[i
].parm_index
< (int)map
.length ()
4079 && map
[kills
[i
].parm_index
] != MODREF_UNKNOWN_PARM
)
4081 kills
[i
].parm_index
= map
[kills
[i
].parm_index
];
4085 kills
.unordered_remove (i
);
4091 /* Return true if the V can overlap with KILL. */
4094 ipcp_argagg_and_kill_overlap_p (const ipa_argagg_value
&v
,
4095 const modref_access_node
&kill
)
4097 if (kill
.parm_index
== v
.index
)
4099 gcc_assert (kill
.parm_offset_known
);
4100 gcc_assert (known_eq (kill
.max_size
, kill
.size
));
4101 poly_int64 repl_size
;
4102 bool ok
= poly_int_tree_p (TYPE_SIZE (TREE_TYPE (v
.value
)),
4105 poly_int64
repl_offset (v
.unit_offset
);
4106 repl_offset
<<= LOG2_BITS_PER_UNIT
;
4107 poly_int64 combined_offset
4108 = (kill
.parm_offset
<< LOG2_BITS_PER_UNIT
) + kill
.offset
;
4109 if (ranges_maybe_overlap_p (repl_offset
, repl_size
,
4110 combined_offset
, kill
.size
))
4116 /* If signature changed, update the summary. */
4119 update_signature (struct cgraph_node
*node
)
4121 modref_summary
*r
= optimization_summaries
4122 ? optimization_summaries
->get (node
) : NULL
;
4123 modref_summary_lto
*r_lto
= summaries_lto
4124 ? summaries_lto
->get (node
) : NULL
;
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 ipcp_transformation
*ipcp_ts
= ipcp_get_transformation_summary (node
);
4134 for (auto &v
: ipcp_ts
->m_agg_values
)
4139 for (const modref_access_node
&kill
: r
->kills
)
4140 if (ipcp_argagg_and_kill_overlap_p (v
, kill
))
4145 if (!v
.killed
&& r_lto
)
4146 for (const modref_access_node
&kill
: r_lto
->kills
)
4147 if (ipcp_argagg_and_kill_overlap_p (v
, kill
))
4155 clone_info
*info
= clone_info::get (node
);
4156 if (!info
|| !info
->param_adjustments
)
4161 fprintf (dump_file
, "Updating summary for %s from:\n",
4162 node
->dump_name ());
4164 r
->dump (dump_file
);
4166 r_lto
->dump (dump_file
);
4170 ipa_adjusted_param
*p
;
4172 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
4174 int idx
= info
->param_adjustments
->get_original_index (i
);
4179 auto_vec
<int, 32> map
;
4181 map
.reserve (max
+ 1);
4182 for (i
= 0; i
<= max
; i
++)
4183 map
.quick_push (MODREF_UNKNOWN_PARM
);
4184 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
4186 int idx
= info
->param_adjustments
->get_original_index (i
);
4192 r
->loads
->remap_params (&map
);
4193 r
->stores
->remap_params (&map
);
4194 remap_kills (r
->kills
, map
);
4195 if (r
->arg_flags
.length ())
4196 remap_arg_flags (r
->arg_flags
, info
);
4200 r_lto
->loads
->remap_params (&map
);
4201 r_lto
->stores
->remap_params (&map
);
4202 remap_kills (r_lto
->kills
, map
);
4203 if (r_lto
->arg_flags
.length ())
4204 remap_arg_flags (r_lto
->arg_flags
, info
);
4208 fprintf (dump_file
, "to:\n");
4210 r
->dump (dump_file
);
4212 r_lto
->dump (dump_file
);
4215 r
->finalize (node
->decl
);
4219 /* Definition of the modref IPA pass. */
4220 const pass_data pass_data_ipa_modref
=
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 */
4233 class pass_ipa_modref
: public ipa_opt_pass_d
4236 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 NULL
) /* variable_transform */
4249 /* opt_pass methods: */
4250 opt_pass
*clone () final override
{ return new pass_ipa_modref (m_ctxt
); }
4251 bool gate (function
*) final override
4255 unsigned int execute (function
*) final override
;
4261 unsigned int pass_modref::execute (function
*)
4263 if (analyze_function (false))
4264 return execute_fixup_cfg ();
4269 make_pass_modref (gcc::context
*ctxt
)
4271 return new pass_modref (ctxt
);
4275 make_pass_ipa_modref (gcc::context
*ctxt
)
4277 return new pass_ipa_modref (ctxt
);
4282 /* Skip edges from and to nodes without ipa_pure_const enabled.
4283 Ignore not available symbols. */
4286 ignore_edge (struct cgraph_edge
*e
)
4288 /* We merge summaries of inline clones into summaries of functions they
4289 are inlined to. For that reason the complete function bodies must
4291 if (!e
->inline_failed
)
4293 enum availability avail
;
4294 cgraph_node
*callee
= e
->callee
->ultimate_alias_target
4295 (&avail
, e
->caller
);
4297 return (avail
<= AVAIL_INTERPOSABLE
4298 || ((!optimization_summaries
|| !optimization_summaries
->get (callee
))
4299 && (!summaries_lto
|| !summaries_lto
->get (callee
))));
4302 /* Compute parm_map for CALLEE_EDGE. */
4305 compute_parm_map (cgraph_edge
*callee_edge
, vec
<modref_parm_map
> *parm_map
)
4307 class ipa_edge_args
*args
;
4308 if (ipa_node_params_sum
4309 && !callee_edge
->call_stmt_cannot_inline_p
4310 && (args
= ipa_edge_args_sum
->get (callee_edge
)) != NULL
)
4312 int i
, count
= ipa_get_cs_argument_count (args
);
4313 class ipa_node_params
*caller_parms_info
, *callee_pi
;
4314 class ipa_call_summary
*es
4315 = ipa_call_summaries
->get (callee_edge
);
4317 = callee_edge
->callee
->ultimate_alias_target
4318 (NULL
, callee_edge
->caller
);
4321 = ipa_node_params_sum
->get (callee_edge
->caller
->inlined_to
4322 ? callee_edge
->caller
->inlined_to
4323 : callee_edge
->caller
);
4324 callee_pi
= ipa_node_params_sum
->get (callee
);
4326 (*parm_map
).safe_grow_cleared (count
, true);
4328 for (i
= 0; i
< count
; i
++)
4330 if (es
&& es
->param
[i
].points_to_local_or_readonly_memory
)
4332 (*parm_map
)[i
].parm_index
= MODREF_LOCAL_MEMORY_PARM
;
4336 struct ipa_jump_func
*jf
4337 = ipa_get_ith_jump_func (args
, i
);
4338 if (jf
&& callee_pi
)
4340 tree cst
= ipa_value_from_jfunc (caller_parms_info
,
4344 if (cst
&& points_to_local_or_readonly_memory_p (cst
))
4346 (*parm_map
)[i
].parm_index
= MODREF_LOCAL_MEMORY_PARM
;
4350 if (jf
&& jf
->type
== IPA_JF_PASS_THROUGH
)
4352 (*parm_map
)[i
].parm_index
4353 = ipa_get_jf_pass_through_formal_id (jf
);
4354 if (ipa_get_jf_pass_through_operation (jf
) == NOP_EXPR
)
4356 (*parm_map
)[i
].parm_offset_known
= true;
4357 (*parm_map
)[i
].parm_offset
= 0;
4359 else if (ipa_get_jf_pass_through_operation (jf
)
4360 == POINTER_PLUS_EXPR
4361 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf
),
4362 &(*parm_map
)[i
].parm_offset
))
4363 (*parm_map
)[i
].parm_offset_known
= true;
4365 (*parm_map
)[i
].parm_offset_known
= false;
4368 if (jf
&& jf
->type
== IPA_JF_ANCESTOR
)
4370 (*parm_map
)[i
].parm_index
= ipa_get_jf_ancestor_formal_id (jf
);
4371 (*parm_map
)[i
].parm_offset_known
= true;
4373 (!(ipa_get_jf_ancestor_offset (jf
) & (BITS_PER_UNIT
- 1)));
4374 (*parm_map
)[i
].parm_offset
4375 = ipa_get_jf_ancestor_offset (jf
) >> LOG2_BITS_PER_UNIT
;
4378 (*parm_map
)[i
].parm_index
= -1;
4382 fprintf (dump_file
, " Parm map: ");
4383 for (i
= 0; i
< count
; i
++)
4384 fprintf (dump_file
, " %i", (*parm_map
)[i
].parm_index
);
4385 fprintf (dump_file
, "\n");
4392 /* Map used to translate escape infos. */
4400 /* Update escape map for E. */
4403 update_escape_summary_1 (cgraph_edge
*e
,
4404 vec
<vec
<escape_map
>> &map
,
4407 escape_summary
*sum
= escape_summaries
->get (e
);
4410 auto_vec
<escape_entry
> old
= sum
->esc
.copy ();
4411 sum
->esc
.release ();
4415 FOR_EACH_VEC_ELT (old
, i
, ee
)
4418 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 if (ee
->parm_index
>= (int)map
.length ()
4422 || ee
->parm_index
< 0)
4424 FOR_EACH_VEC_ELT (map
[ee
->parm_index
], j
, em
)
4426 eaf_flags_t min_flags
= ee
->min_flags
;
4427 if (ee
->direct
&& !em
->direct
)
4428 min_flags
= deref_flags (min_flags
, ignore_stores
);
4429 struct escape_entry entry
= {em
->parm_index
, ee
->arg
,
4431 ee
->direct
&& em
->direct
};
4432 sum
->esc
.safe_push (entry
);
4435 if (!sum
->esc
.length ())
4436 escape_summaries
->remove (e
);
4439 /* Update escape map for NODE. */
4442 update_escape_summary (cgraph_node
*node
,
4443 vec
<vec
<escape_map
>> &map
,
4446 if (!escape_summaries
)
4448 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
4449 update_escape_summary_1 (e
, map
, ignore_stores
);
4450 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
4452 if (!e
->inline_failed
)
4453 update_escape_summary (e
->callee
, map
, ignore_stores
);
4455 update_escape_summary_1 (e
, map
, ignore_stores
);
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. */
4464 get_parm_type (tree decl
, unsigned int i
)
4466 tree t
= TYPE_ARG_TYPES (TREE_TYPE (decl
));
4468 for (unsigned int p
= 0; p
< i
; p
++)
4470 return TREE_VALUE (t
);
4473 /* Return access mode for argument I of call E with FNSPEC. */
4475 static modref_access_node
4476 get_access_for_fnspec (cgraph_edge
*e
, attr_fnspec
&fnspec
,
4477 unsigned int i
, modref_parm_map
&map
)
4479 tree size
= NULL_TREE
;
4480 unsigned int size_arg
;
4482 if (!fnspec
.arg_specified_p (i
))
4484 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
4486 cgraph_node
*node
= e
->caller
->inlined_to
4487 ? e
->caller
->inlined_to
: e
->caller
;
4488 ipa_node_params
*caller_parms_info
= ipa_node_params_sum
->get (node
);
4489 ipa_edge_args
*args
= ipa_edge_args_sum
->get (e
);
4490 struct ipa_jump_func
*jf
= ipa_get_ith_jump_func (args
, size_arg
);
4493 size
= ipa_value_from_jfunc (caller_parms_info
, jf
,
4494 get_parm_type (e
->callee
->decl
, size_arg
));
4496 else if (fnspec
.arg_access_size_given_by_type_p (i
))
4497 size
= TYPE_SIZE_UNIT (get_parm_type (e
->callee
->decl
, i
));
4498 modref_access_node a
= {0, -1, -1,
4499 map
.parm_offset
, map
.parm_index
,
4500 map
.parm_offset_known
, 0};
4501 poly_int64 size_hwi
;
4503 && poly_int_tree_p (size
, &size_hwi
)
4504 && coeffs_in_range_p (size_hwi
, 0,
4505 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
4508 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
4513 /* Collapse loads and return true if something changed. */
4515 collapse_loads (modref_summary
*cur_summary
,
4516 modref_summary_lto
*cur_summary_lto
)
4518 bool changed
= false;
4520 if (cur_summary
&& !cur_summary
->loads
->every_base
)
4522 cur_summary
->loads
->collapse ();
4526 && !cur_summary_lto
->loads
->every_base
)
4528 cur_summary_lto
->loads
->collapse ();
4534 /* Collapse loads and return true if something changed. */
4537 collapse_stores (modref_summary
*cur_summary
,
4538 modref_summary_lto
*cur_summary_lto
)
4540 bool changed
= false;
4542 if (cur_summary
&& !cur_summary
->stores
->every_base
)
4544 cur_summary
->stores
->collapse ();
4548 && !cur_summary_lto
->stores
->every_base
)
4550 cur_summary_lto
->stores
->collapse ();
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. */
4560 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
)
4566 bool changed
= false;
4567 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
4568 auto_vec
<modref_parm_map
, 32> parm_map
;
4572 && builtin_safe_for_const_function_p (&looping
, e
->callee
->decl
))
4574 if (looping
&& cur_summary
&& !cur_summary
->side_effects
)
4576 cur_summary
->side_effects
= true;
4579 if (looping
&& cur_summary_lto
&& !cur_summary_lto
->side_effects
)
4581 cur_summary_lto
->side_effects
= true;
4587 if (!(ecf_flags
& (ECF_CONST
| ECF_PURE
))
4588 || (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
)
4591 if (cur_summary
&& !cur_summary
->side_effects
)
4593 cur_summary
->side_effects
= true;
4596 if (cur_summary_lto
&& !cur_summary_lto
->side_effects
)
4598 cur_summary_lto
->side_effects
= true;
4601 if (!ignore_nondeterminism_p (node
->decl
, ecf_flags
,
4602 e
->callee
? TREE_TYPE (e
->callee
->decl
)
4605 if (cur_summary
&& !cur_summary
->nondeterministic
)
4607 cur_summary
->nondeterministic
= true;
4610 if (cur_summary_lto
&& !cur_summary_lto
->nondeterministic
)
4612 cur_summary_lto
->nondeterministic
= true;
4617 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
4621 && compute_parm_map (e
, &parm_map
))
4623 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
4625 gcc_checking_assert (fnspec
.known_p ());
4626 if (fnspec
.global_memory_read_p ())
4627 collapse_loads (cur_summary
, cur_summary_lto
);
4630 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
4631 for (unsigned i
= 0; i
< parm_map
.length () && t
;
4632 i
++, t
= TREE_CHAIN (t
))
4633 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
4635 else if (!fnspec
.arg_specified_p (i
)
4636 || fnspec
.arg_maybe_read_p (i
))
4638 modref_parm_map map
= parm_map
[i
];
4639 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
4641 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
4643 collapse_loads (cur_summary
, cur_summary_lto
);
4647 changed
|= cur_summary
->loads
->insert
4649 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4650 if (cur_summary_lto
)
4651 changed
|= cur_summary_lto
->loads
->insert
4653 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4656 if (ignore_stores_p (node
->decl
, ecf_flags
))
4658 else if (fnspec
.global_memory_written_p ())
4659 collapse_stores (cur_summary
, cur_summary_lto
);
4662 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
4663 for (unsigned i
= 0; i
< parm_map
.length () && t
;
4664 i
++, t
= TREE_CHAIN (t
))
4665 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
4667 else if (!fnspec
.arg_specified_p (i
)
4668 || fnspec
.arg_maybe_written_p (i
))
4670 modref_parm_map map
= parm_map
[i
];
4671 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
4673 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
4675 collapse_stores (cur_summary
, cur_summary_lto
);
4679 changed
|= cur_summary
->stores
->insert
4681 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4682 if (cur_summary_lto
)
4683 changed
|= cur_summary_lto
->stores
->insert
4685 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4688 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
4690 if (cur_summary
&& !cur_summary
->writes_errno
)
4692 cur_summary
->writes_errno
= true;
4695 if (cur_summary_lto
&& !cur_summary_lto
->writes_errno
)
4697 cur_summary_lto
->writes_errno
= true;
4704 fprintf (dump_file
, " collapsing loads\n");
4705 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
4706 if (!ignore_stores_p (node
->decl
, ecf_flags
))
4709 fprintf (dump_file
, " collapsing stores\n");
4710 changed
|= collapse_stores (cur_summary
, cur_summary_lto
);
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. */
4719 remove_useless_summaries (cgraph_node
*node
,
4720 modref_summary
**cur_summary_ptr
,
4721 modref_summary_lto
**cur_summary_lto_ptr
,
4724 if (*cur_summary_ptr
&& !(*cur_summary_ptr
)->useful_p (ecf_flags
, false))
4726 optimization_summaries
->remove (node
);
4727 *cur_summary_ptr
= NULL
;
4729 if (*cur_summary_lto_ptr
4730 && !(*cur_summary_lto_ptr
)->useful_p (ecf_flags
, false))
4732 summaries_lto
->remove (node
);
4733 *cur_summary_lto_ptr
= NULL
;
4737 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4738 and propagate loads/stores. */
4741 modref_propagate_in_scc (cgraph_node
*component_node
)
4743 bool changed
= true;
4750 = ((struct ipa_dfs_info
*) component_node
->aux
)->next_cycle
;
4752 for (struct cgraph_node
*cur
= component_node
; cur
;
4753 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4755 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
4756 modref_summary
*cur_summary
= optimization_summaries
4757 ? optimization_summaries
->get (node
)
4759 modref_summary_lto
*cur_summary_lto
= summaries_lto
4760 ? summaries_lto
->get (node
)
4763 if (!cur_summary
&& !cur_summary_lto
)
4766 int cur_ecf_flags
= flags_from_decl_or_type (node
->decl
);
4769 fprintf (dump_file
, " Processing %s%s%s\n",
4771 TREE_READONLY (cur
->decl
) ? " (const)" : "",
4772 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
4774 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
4777 fprintf (dump_file
, " Indirect call\n");
4778 if (propagate_unknown_call
4779 (node
, e
, e
->indirect_info
->ecf_flags
,
4780 cur_summary
, cur_summary_lto
,
4784 remove_useless_summaries (node
, &cur_summary
,
4787 if (!cur_summary
&& !cur_summary_lto
)
4792 if (!cur_summary
&& !cur_summary_lto
)
4795 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
4796 callee_edge
= callee_edge
->next_callee
)
4798 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
4799 modref_summary
*callee_summary
= NULL
;
4800 modref_summary_lto
*callee_summary_lto
= NULL
;
4801 struct cgraph_node
*callee
;
4803 if (!callee_edge
->inline_failed
4804 || ((flags
& ECF_CONST
)
4805 && !(flags
& ECF_LOOPING_CONST_OR_PURE
)))
4808 /* Get the callee and its summary. */
4809 enum availability avail
;
4810 callee
= callee_edge
->callee
->ultimate_alias_target
4813 /* It is not necessary to re-process calls outside of the
4817 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
4818 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
4822 fprintf (dump_file
, " Call to %s\n",
4823 callee_edge
->callee
->dump_name ());
4825 bool ignore_stores
= ignore_stores_p (cur
->decl
, flags
);
4827 if (avail
<= AVAIL_INTERPOSABLE
)
4830 fprintf (dump_file
, " Call target interposable"
4831 " or not available\n");
4832 changed
|= propagate_unknown_call
4833 (node
, callee_edge
, flags
,
4834 cur_summary
, cur_summary_lto
,
4836 if (!cur_summary
&& !cur_summary_lto
)
4841 /* We don't know anything about CALLEE, hence we cannot tell
4842 anything about the entire component. */
4845 && !(callee_summary
= optimization_summaries
->get (callee
)))
4848 fprintf (dump_file
, " No call target summary\n");
4849 changed
|= propagate_unknown_call
4850 (node
, callee_edge
, flags
,
4855 && !(callee_summary_lto
= summaries_lto
->get (callee
)))
4858 fprintf (dump_file
, " No call target summary\n");
4859 changed
|= propagate_unknown_call
4860 (node
, callee_edge
, flags
,
4861 NULL
, cur_summary_lto
,
4865 if (callee_summary
&& !cur_summary
->side_effects
4866 && (callee_summary
->side_effects
4867 || callee_edge
->recursive_p ()))
4869 cur_summary
->side_effects
= true;
4872 if (callee_summary_lto
&& !cur_summary_lto
->side_effects
4873 && (callee_summary_lto
->side_effects
4874 || callee_edge
->recursive_p ()))
4876 cur_summary_lto
->side_effects
= true;
4879 if (callee_summary
&& !cur_summary
->nondeterministic
4880 && callee_summary
->nondeterministic
4881 && !ignore_nondeterminism_p
4883 TREE_TYPE (callee_edge
->callee
->decl
)))
4885 cur_summary
->nondeterministic
= true;
4888 if (callee_summary_lto
&& !cur_summary_lto
->nondeterministic
4889 && callee_summary_lto
->nondeterministic
4890 && !ignore_nondeterminism_p
4892 TREE_TYPE (callee_edge
->callee
->decl
)))
4894 cur_summary_lto
->nondeterministic
= true;
4897 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
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 if (!callee_edge
->binds_to_current_def_p ())
4906 if (cur_summary
&& !cur_summary
->calls_interposable
)
4908 cur_summary
->calls_interposable
= true;
4911 if (cur_summary_lto
&& !cur_summary_lto
->calls_interposable
)
4913 cur_summary_lto
->calls_interposable
= true;
4917 fprintf (dump_file
, " May not bind local;"
4918 " collapsing loads\n");
4922 auto_vec
<modref_parm_map
, 32> parm_map
;
4923 modref_parm_map chain_map
;
4924 /* TODO: Once we get jump functions for static chains we could
4926 chain_map
.parm_index
= MODREF_UNKNOWN_PARM
;
4928 compute_parm_map (callee_edge
, &parm_map
);
4930 /* Merge in callee's information. */
4933 changed
|= cur_summary
->loads
->merge
4934 (node
->decl
, callee_summary
->loads
,
4935 &parm_map
, &chain_map
, !first
);
4938 changed
|= cur_summary
->stores
->merge
4939 (node
->decl
, callee_summary
->stores
,
4940 &parm_map
, &chain_map
, !first
);
4941 if (!cur_summary
->writes_errno
4942 && callee_summary
->writes_errno
)
4944 cur_summary
->writes_errno
= true;
4949 if (callee_summary_lto
)
4951 changed
|= cur_summary_lto
->loads
->merge
4952 (node
->decl
, callee_summary_lto
->loads
,
4953 &parm_map
, &chain_map
, !first
);
4956 changed
|= cur_summary_lto
->stores
->merge
4957 (node
->decl
, callee_summary_lto
->stores
,
4958 &parm_map
, &chain_map
, !first
);
4959 if (!cur_summary_lto
->writes_errno
4960 && callee_summary_lto
->writes_errno
)
4962 cur_summary_lto
->writes_errno
= true;
4968 remove_useless_summaries (node
, &cur_summary
,
4971 if (!cur_summary
&& !cur_summary_lto
)
4973 if (dump_file
&& changed
)
4976 cur_summary
->dump (dump_file
);
4977 if (cur_summary_lto
)
4978 cur_summary_lto
->dump (dump_file
);
4979 dump_modref_edge_summaries (dump_file
, node
, 4);
4988 "Propagation finished in %i iterations\n", iteration
);
4989 bool pureconst
= false;
4990 for (struct cgraph_node
*cur
= component_node
; cur
;
4991 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4992 if (!cur
->inlined_to
&& opt_for_fn (cur
->decl
, flag_ipa_pure_const
))
4994 modref_summary
*summary
= optimization_summaries
4995 ? optimization_summaries
->get (cur
)
4997 modref_summary_lto
*summary_lto
= summaries_lto
4998 ? summaries_lto
->get (cur
)
5000 if (summary
&& !summary
->stores
->every_base
&& !summary
->stores
->bases
5001 && !summary
->nondeterministic
)
5003 if (!summary
->loads
->every_base
&& !summary
->loads
->bases
5004 && !summary
->calls_interposable
)
5005 pureconst
|= ipa_make_function_const
5006 (cur
, summary
->side_effects
, false);
5008 pureconst
|= ipa_make_function_pure
5009 (cur
, summary
->side_effects
, false);
5011 if (summary_lto
&& !summary_lto
->stores
->every_base
5012 && !summary_lto
->stores
->bases
&& !summary_lto
->nondeterministic
)
5014 if (!summary_lto
->loads
->every_base
&& !summary_lto
->loads
->bases
5015 && !summary_lto
->calls_interposable
)
5016 pureconst
|= ipa_make_function_const
5017 (cur
, summary_lto
->side_effects
, false);
5019 pureconst
|= ipa_make_function_pure
5020 (cur
, summary_lto
->side_effects
, false);
5026 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
5029 modref_propagate_dump_scc (cgraph_node
*component_node
)
5031 for (struct cgraph_node
*cur
= component_node
; cur
;
5032 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
5033 if (!cur
->inlined_to
)
5035 modref_summary
*cur_summary
= optimization_summaries
5036 ? optimization_summaries
->get (cur
)
5038 modref_summary_lto
*cur_summary_lto
= summaries_lto
5039 ? summaries_lto
->get (cur
)
5042 fprintf (dump_file
, "Propagated modref for %s%s%s\n",
5044 TREE_READONLY (cur
->decl
) ? " (const)" : "",
5045 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
5046 if (optimization_summaries
)
5049 cur_summary
->dump (dump_file
);
5051 fprintf (dump_file
, " Not tracked\n");
5055 if (cur_summary_lto
)
5056 cur_summary_lto
->dump (dump_file
);
5058 fprintf (dump_file
, " Not tracked (lto)\n");
5063 /* Determine EAF flags know for call E with CALLEE_ECF_FLAGS and ARG. */
5066 implicit_eaf_flags_for_edge_and_arg (cgraph_edge
*e
, int callee_ecf_flags
,
5067 bool ignore_stores
, int arg
)
5069 /* Returning the value is already accounted to at local propagation. */
5070 int implicit_flags
= EAF_NOT_RETURNED_DIRECTLY
5071 | EAF_NOT_RETURNED_INDIRECTLY
;
5073 implicit_flags
|= ignore_stores_eaf_flags
;
5074 if (callee_ecf_flags
& ECF_PURE
)
5075 implicit_flags
|= implicit_pure_eaf_flags
;
5076 if (callee_ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
5077 implicit_flags
|= implicit_const_eaf_flags
;
5078 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
5081 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
5082 implicit_flags
|= fnspec
.arg_eaf_flags (arg
);
5084 return implicit_flags
;
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. */
5092 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
,
5099 int caller_ecf_flags
,
5100 int callee_ecf_flags
,
5101 bool binds_to_current_def
)
5105 bool changed
= false;
5106 bool ignore_stores
= ignore_stores_p (caller
, callee_ecf_flags
);
5108 /* Return early if we have no useful info to propagate. */
5110 || (!cur_summary
->arg_flags
.length ()
5111 && !cur_summary
->static_chain_flags
5112 && !cur_summary
->retslot_flags
))
5113 && (!cur_summary_lto
5114 || (!cur_summary_lto
->arg_flags
.length ()
5115 && !cur_summary_lto
->static_chain_flags
5116 && !cur_summary_lto
->retslot_flags
)))
5119 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
5123 int implicit_flags
= implicit_eaf_flags_for_edge_and_arg
5124 (e
, callee_ecf_flags
, ignore_stores
, ee
->arg
);
5126 if (summary
&& ee
->arg
< summary
->arg_flags
.length ())
5127 flags
= summary
->arg_flags
[ee
->arg
];
5129 && ee
->arg
< summary_lto
->arg_flags
.length ())
5130 flags_lto
= summary_lto
->arg_flags
[ee
->arg
];
5133 flags
= deref_flags (flags
, ignore_stores
);
5134 flags_lto
= deref_flags (flags_lto
, ignore_stores
);
5137 implicit_flags
|= ignore_stores_eaf_flags
;
5138 if (callee_ecf_flags
& ECF_PURE
)
5139 implicit_flags
|= implicit_pure_eaf_flags
;
5140 if (callee_ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
5141 implicit_flags
|= implicit_const_eaf_flags
;
5142 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
5145 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
5146 implicit_flags
|= fnspec
.arg_eaf_flags (ee
->arg
);
5149 implicit_flags
= deref_flags (implicit_flags
, ignore_stores
);
5150 flags
|= implicit_flags
;
5151 flags_lto
|= implicit_flags
;
5152 if (!binds_to_current_def
&& (flags
|| flags_lto
))
5154 flags
= interposable_eaf_flags (flags
, implicit_flags
);
5155 flags_lto
= interposable_eaf_flags (flags_lto
, implicit_flags
);
5157 if (!(flags
& EAF_UNUSED
)
5158 && cur_summary
&& ee
->parm_index
< (int)cur_summary
->arg_flags
.length ())
5160 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
5161 ? cur_summary
->retslot_flags
5162 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
5163 ? cur_summary
->static_chain_flags
5164 : cur_summary
->arg_flags
[ee
->parm_index
];
5165 if ((f
& flags
) != f
)
5167 f
= remove_useless_eaf_flags
5168 (f
& flags
, caller_ecf_flags
,
5169 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
5173 if (!(flags_lto
& EAF_UNUSED
)
5175 && ee
->parm_index
< (int)cur_summary_lto
->arg_flags
.length ())
5177 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
5178 ? cur_summary_lto
->retslot_flags
5179 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
5180 ? cur_summary_lto
->static_chain_flags
5181 : cur_summary_lto
->arg_flags
[ee
->parm_index
];
5182 if ((f
& flags_lto
) != f
)
5184 f
= remove_useless_eaf_flags
5185 (f
& flags_lto
, caller_ecf_flags
,
5186 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
5194 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
5195 and propagate arg flags. */
5198 modref_propagate_flags_in_scc (cgraph_node
*component_node
)
5200 bool changed
= true;
5206 for (struct cgraph_node
*cur
= component_node
; cur
;
5207 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
5209 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
5210 modref_summary
*cur_summary
= optimization_summaries
5211 ? optimization_summaries
->get (node
)
5213 modref_summary_lto
*cur_summary_lto
= summaries_lto
5214 ? summaries_lto
->get (node
)
5217 if (!cur_summary
&& !cur_summary_lto
)
5219 int caller_ecf_flags
= flags_from_decl_or_type (cur
->decl
);
5222 fprintf (dump_file
, " Processing %s%s%s\n",
5224 TREE_READONLY (cur
->decl
) ? " (const)" : "",
5225 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
5227 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
5229 escape_summary
*sum
= escape_summaries
->get (e
);
5231 if (!sum
|| ((e
->indirect_info
->ecf_flags
& ECF_CONST
)
5232 && !(e
->indirect_info
->ecf_flags
& ECF_LOOPING_CONST_OR_PURE
)))
5235 changed
|= modref_merge_call_site_flags
5236 (sum
, cur_summary
, cur_summary_lto
,
5241 e
->indirect_info
->ecf_flags
,
5245 if (!cur_summary
&& !cur_summary_lto
)
5248 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
5249 callee_edge
= callee_edge
->next_callee
)
5251 int ecf_flags
= flags_from_decl_or_type
5252 (callee_edge
->callee
->decl
);
5253 modref_summary
*callee_summary
= NULL
;
5254 modref_summary_lto
*callee_summary_lto
= NULL
;
5255 struct cgraph_node
*callee
;
5257 if ((ecf_flags
& ECF_CONST
)
5258 && !(ecf_flags
& ECF_LOOPING_CONST_OR_PURE
))
5261 /* Get the callee and its summary. */
5262 enum availability avail
;
5263 callee
= callee_edge
->callee
->ultimate_alias_target
5266 /* It is not necessary to re-process calls outside of the
5270 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
5271 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
5274 escape_summary
*sum
= escape_summaries
->get (callee_edge
);
5279 fprintf (dump_file
, " Call to %s\n",
5280 callee_edge
->callee
->dump_name ());
5282 if (avail
<= AVAIL_INTERPOSABLE
5283 || callee_edge
->call_stmt_cannot_inline_p
)
5288 callee_summary
= optimization_summaries
->get (callee
);
5289 if (cur_summary_lto
)
5290 callee_summary_lto
= summaries_lto
->get (callee
);
5292 changed
|= modref_merge_call_site_flags
5293 (sum
, cur_summary
, cur_summary_lto
,
5294 callee_summary
, callee_summary_lto
,
5299 callee
->binds_to_current_def_p ());
5300 if (dump_file
&& changed
)
5303 cur_summary
->dump (dump_file
);
5304 if (cur_summary_lto
)
5305 cur_summary_lto
->dump (dump_file
);
5313 "Propagation of flags finished in %i iterations\n", iteration
);
5316 } /* ANON namespace. */
5318 /* Call EDGE was inlined; merge summary from callee to the caller. */
5321 ipa_merge_modref_summary_after_inlining (cgraph_edge
*edge
)
5323 if (!summaries
&& !summaries_lto
)
5326 struct cgraph_node
*to
= (edge
->caller
->inlined_to
5327 ? edge
->caller
->inlined_to
: edge
->caller
);
5328 class modref_summary
*to_info
= summaries
? summaries
->get (to
) : NULL
;
5329 class modref_summary_lto
*to_info_lto
= summaries_lto
5330 ? summaries_lto
->get (to
) : NULL
;
5332 if (!to_info
&& !to_info_lto
)
5335 summaries
->remove (edge
->callee
);
5337 summaries_lto
->remove (edge
->callee
);
5338 remove_modref_edge_summaries (edge
->callee
);
5342 class modref_summary
*callee_info
= summaries
? summaries
->get (edge
->callee
)
5344 class modref_summary_lto
*callee_info_lto
5345 = summaries_lto
? summaries_lto
->get (edge
->callee
) : NULL
;
5346 int flags
= flags_from_decl_or_type (edge
->callee
->decl
);
5347 /* Combine in outer flags. */
5349 for (n
= edge
->caller
; n
->inlined_to
; n
= n
->callers
->caller
)
5350 flags
|= flags_from_decl_or_type (n
->decl
);
5351 flags
|= flags_from_decl_or_type (n
->decl
);
5352 bool ignore_stores
= ignore_stores_p (edge
->caller
->decl
, flags
);
5354 if (!callee_info
&& to_info
)
5356 if (!(flags
& (ECF_CONST
| ECF_PURE
| ECF_NOVOPS
)))
5357 to_info
->loads
->collapse ();
5359 to_info
->stores
->collapse ();
5361 if (!callee_info_lto
&& to_info_lto
)
5363 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5364 to_info_lto
->loads
->collapse ();
5366 to_info_lto
->stores
->collapse ();
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 if (!(flags
& (ECF_CONST
| ECF_PURE
))
5372 || (flags
& ECF_LOOPING_CONST_OR_PURE
))
5374 bool set_nondeterministic
5375 = !ignore_nondeterminism_p
5376 (edge
->caller
->decl
, flags
,
5377 TREE_TYPE (edge
->callee
->decl
));
5380 if (!callee_info
|| callee_info
->side_effects
)
5381 to_info
->side_effects
= true;
5382 if (set_nondeterministic
)
5383 to_info
->nondeterministic
= true;
5387 if (!callee_info_lto
|| callee_info_lto
->side_effects
)
5388 to_info_lto
->side_effects
= true;
5389 if (set_nondeterministic
)
5390 to_info_lto
->nondeterministic
= true;
5393 if (callee_info
|| callee_info_lto
)
5395 auto_vec
<modref_parm_map
, 32> parm_map
;
5396 modref_parm_map chain_map
;
5397 /* TODO: Once we get jump functions for static chains we could
5398 compute parm_index. */
5400 compute_parm_map (edge
, &parm_map
);
5404 if (to_info
&& callee_info
)
5405 to_info
->stores
->merge (to
->decl
, callee_info
->stores
, &parm_map
,
5407 if (to_info_lto
&& callee_info_lto
)
5408 to_info_lto
->stores
->merge (to
->decl
, callee_info_lto
->stores
,
5409 &parm_map
, &chain_map
, false);
5411 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5413 if (to_info
&& callee_info
)
5414 to_info
->loads
->merge (to
->decl
, callee_info
->loads
, &parm_map
,
5416 if (to_info_lto
&& callee_info_lto
)
5417 to_info_lto
->loads
->merge (to
->decl
, callee_info_lto
->loads
,
5418 &parm_map
, &chain_map
, false);
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 class escape_summary
*sum
= escape_summaries
->get (edge
);
5426 int max_escape
= -1;
5430 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5431 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
5432 if ((int)ee
->arg
> max_escape
)
5433 max_escape
= ee
->arg
;
5435 auto_vec
<vec
<struct escape_map
>, 32> emap (max_escape
+ 1);
5436 emap
.safe_grow (max_escape
+ 1, true);
5437 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
5440 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5441 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
5443 bool needed
= false;
5444 int implicit_flags
= implicit_eaf_flags_for_edge_and_arg
5445 (edge
, flags
, ignore_stores
,
5448 implicit_flags
= deref_flags (implicit_flags
, ignore_stores
);
5449 if (to_info
&& (int)to_info
->arg_flags
.length () > ee
->parm_index
)
5451 int flags
= callee_info
5452 && callee_info
->arg_flags
.length () > ee
->arg
5453 ? callee_info
->arg_flags
[ee
->arg
] : 0;
5455 flags
= deref_flags (flags
, ignore_stores
);
5456 flags
|= ee
->min_flags
| implicit_flags
;
5457 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
5458 ? to_info
->retslot_flags
5459 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
5460 ? to_info
->static_chain_flags
5461 : to_info
->arg_flags
[ee
->parm_index
];
5467 && (int)to_info_lto
->arg_flags
.length () > ee
->parm_index
)
5469 int flags
= callee_info_lto
5470 && callee_info_lto
->arg_flags
.length () > ee
->arg
5471 ? callee_info_lto
->arg_flags
[ee
->arg
] : 0;
5473 flags
= deref_flags (flags
, ignore_stores
);
5474 flags
|= ee
->min_flags
| implicit_flags
;
5475 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
5476 ? to_info_lto
->retslot_flags
5477 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
5478 ? to_info_lto
->static_chain_flags
5479 : to_info_lto
->arg_flags
[ee
->parm_index
];
5484 struct escape_map entry
= {ee
->parm_index
, ee
->direct
};
5486 emap
[ee
->arg
].safe_push (entry
);
5488 update_escape_summary (edge
->callee
, emap
, ignore_stores
);
5489 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
5492 escape_summaries
->remove (edge
);
5496 if (to_info
&& !to_info
->useful_p (flags
))
5499 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
5501 summaries
->remove (to
);
5504 else if (to_info
&& dump_file
)
5507 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
5509 to_info
->dump (dump_file
);
5512 summaries
->remove (edge
->callee
);
5516 if (to_info_lto
&& !to_info_lto
->useful_p (flags
))
5519 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
5521 summaries_lto
->remove (to
);
5524 else if (to_info_lto
&& dump_file
)
5527 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
5529 to_info_lto
->dump (dump_file
);
5531 if (callee_info_lto
)
5532 summaries_lto
->remove (edge
->callee
);
5534 if (!to_info
&& !to_info_lto
)
5535 remove_modref_edge_summaries (to
);
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. */
5545 pass_ipa_modref::execute (function
*)
5547 if (!summaries
&& !summaries_lto
)
5549 bool pureconst
= false;
5551 if (optimization_summaries
)
5552 ggc_delete (optimization_summaries
);
5553 optimization_summaries
= summaries
;
5556 struct cgraph_node
**order
= XCNEWVEC (struct cgraph_node
*,
5557 symtab
->cgraph_count
);
5559 order_pos
= ipa_reduced_postorder (order
, true, ignore_edge
);
5562 /* Iterate over all strongly connected components in post-order. */
5563 for (i
= 0; i
< order_pos
; i
++)
5565 /* Get the component's representative. That's just any node in the
5566 component from which we can traverse the entire component. */
5567 struct cgraph_node
*component_node
= order
[i
];
5570 fprintf (dump_file
, "\n\nStart of SCC component\n");
5572 pureconst
|= modref_propagate_in_scc (component_node
);
5573 modref_propagate_flags_in_scc (component_node
);
5574 if (optimization_summaries
)
5575 for (struct cgraph_node
*cur
= component_node
; cur
;
5576 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
5577 if (modref_summary
*sum
= optimization_summaries
->get (cur
))
5578 sum
->finalize (cur
->decl
);
5580 modref_propagate_dump_scc (component_node
);
5583 FOR_EACH_FUNCTION (node
)
5584 update_signature (node
);
5586 ((modref_summaries_lto
*)summaries_lto
)->propagated
= true;
5587 ipa_free_postorder_info ();
5589 delete fnspec_summaries
;
5590 fnspec_summaries
= NULL
;
5591 delete escape_summaries
;
5592 escape_summaries
= NULL
;
5594 /* If we possibly made constructors const/pure we may need to remove
5596 return pureconst
? TODO_remove_functions
: 0;
5599 /* Summaries must stay alive until end of compilation. */
5602 ipa_modref_cc_finalize ()
5604 if (optimization_summaries
)
5605 ggc_delete (optimization_summaries
);
5606 optimization_summaries
= NULL
;
5608 ggc_delete (summaries_lto
);
5609 summaries_lto
= NULL
;
5610 if (fnspec_summaries
)
5611 delete fnspec_summaries
;
5612 fnspec_summaries
= NULL
;
5613 if (escape_summaries
)
5614 delete escape_summaries
;
5615 escape_summaries
= NULL
;
5618 /* Return true if call is known to perform no memory reads. */
5621 ipa_modref_callee_reads_no_memory_p (gcall
*call
)
5623 if (gimple_call_flags (call
) & ECF_CONST
)
5625 attr_fnspec fnspec
= gimple_call_fnspec (call
);
5626 if (fnspec
.known_p ()
5627 && !fnspec
.global_memory_read_p ())
5630 for (unsigned int i
= 0; i
< gimple_call_num_args (call
) && !found
; i
++)
5631 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
5633 else if (!fnspec
.arg_specified_p (i
)
5634 || fnspec
.arg_maybe_read_p (i
))
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. */
5644 modref_summary
*sum
= get_modref_function_summary (call
, &interposed
);
5645 if (sum
&& !interposed
&& !sum
->global_memory_read
&& !sum
->loads
)
5650 #include "gt-ipa-modref.h"