1 /* Search for references that a functions loads or stores.
2 Copyright (C) 2020-2024 Free Software Foundation, Inc.
3 Contributed by David Cepelik and Jan Hubicka
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
| ECF_NOVOPS
))
338 return ((!side_effects
|| !nondeterministic
)
339 && (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
));
340 if (loads
&& !loads
->every_base
)
344 if (ecf_flags
& ECF_PURE
)
345 return ((!side_effects
|| !nondeterministic
)
346 && (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
));
347 return stores
&& !stores
->every_base
;
350 /* Single function summary used for LTO. */
352 typedef modref_tree
<tree
> modref_records_lto
;
353 struct GTY(()) modref_summary_lto
355 /* Load and stores in functions using types rather then alias sets.
357 This is necessary to make the information streamable for LTO but is also
358 more verbose and thus more likely to hit the limits. */
359 modref_records_lto
*loads
;
360 modref_records_lto
*stores
;
361 auto_vec
<modref_access_node
> GTY((skip
)) kills
;
362 auto_vec
<eaf_flags_t
> GTY((skip
)) arg_flags
;
363 eaf_flags_t retslot_flags
;
364 eaf_flags_t static_chain_flags
;
365 unsigned writes_errno
: 1;
366 unsigned side_effects
: 1;
367 unsigned nondeterministic
: 1;
368 unsigned calls_interposable
: 1;
370 modref_summary_lto ();
371 ~modref_summary_lto ();
373 bool useful_p (int ecf_flags
, bool check_flags
= true);
376 /* Summary for a single function which this pass produces. */
378 modref_summary_lto::modref_summary_lto ()
379 : loads (NULL
), stores (NULL
), retslot_flags (0), static_chain_flags (0),
380 writes_errno (false), side_effects (false), nondeterministic (false),
381 calls_interposable (false)
385 modref_summary_lto::~modref_summary_lto ()
394 /* Return true if lto summary is potentially useful for optimization.
395 If CHECK_FLAGS is false assume that arg_flags are useful. */
398 modref_summary_lto::useful_p (int ecf_flags
, bool check_flags
)
400 if (arg_flags
.length () && !check_flags
)
402 if (check_flags
&& eaf_flags_useful_p (arg_flags
, ecf_flags
))
404 arg_flags
.release ();
405 if (check_flags
&& remove_useless_eaf_flags (retslot_flags
, ecf_flags
, false))
408 && remove_useless_eaf_flags (static_chain_flags
, ecf_flags
, false))
410 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
411 return ((!side_effects
|| !nondeterministic
)
412 && (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
));
413 if (loads
&& !loads
->every_base
)
417 if (ecf_flags
& ECF_PURE
)
418 return ((!side_effects
|| !nondeterministic
)
419 && (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
));
420 return stores
&& !stores
->every_base
;
423 /* Dump records TT to OUT. */
426 dump_records (modref_records
*tt
, FILE *out
)
430 fprintf (out
, " Every base\n");
434 modref_base_node
<alias_set_type
> *n
;
435 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
437 fprintf (out
, " Base %i: alias set %i\n", (int)i
, n
->base
);
440 fprintf (out
, " Every ref\n");
444 modref_ref_node
<alias_set_type
> *r
;
445 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
447 fprintf (out
, " Ref %i: alias set %i\n", (int)j
, r
->ref
);
450 fprintf (out
, " Every access\n");
454 modref_access_node
*a
;
455 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
457 fprintf (out
, " access:");
464 /* Dump records TT to OUT. */
467 dump_lto_records (modref_records_lto
*tt
, FILE *out
)
471 fprintf (out
, " Every base\n");
475 modref_base_node
<tree
> *n
;
476 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
478 fprintf (out
, " Base %i:", (int)i
);
479 print_generic_expr (out
, n
->base
);
480 fprintf (out
, " (alias set %i)\n",
481 n
->base
? get_alias_set (n
->base
) : 0);
484 fprintf (out
, " Every ref\n");
488 modref_ref_node
<tree
> *r
;
489 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
491 fprintf (out
, " Ref %i:", (int)j
);
492 print_generic_expr (out
, r
->ref
);
493 fprintf (out
, " (alias set %i)\n",
494 r
->ref
? get_alias_set (r
->ref
) : 0);
497 fprintf (out
, " Every access\n");
501 modref_access_node
*a
;
502 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
504 fprintf (out
, " access:");
511 /* Dump all escape points of NODE to OUT. */
514 dump_modref_edge_summaries (FILE *out
, cgraph_node
*node
, int depth
)
517 if (!escape_summaries
)
519 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
521 class escape_summary
*sum
= escape_summaries
->get (e
);
524 fprintf (out
, "%*sIndirect call %i in %s escapes:",
525 depth
, "", i
, node
->dump_name ());
530 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
532 if (!e
->inline_failed
)
533 dump_modref_edge_summaries (out
, e
->callee
, depth
+ 1);
534 class escape_summary
*sum
= escape_summaries
->get (e
);
537 fprintf (out
, "%*sCall %s->%s escapes:", depth
, "",
538 node
->dump_name (), e
->callee
->dump_name ());
541 class fnspec_summary
*fsum
= fnspec_summaries
->get (e
);
544 fprintf (out
, "%*sCall %s->%s fnspec: %s\n", depth
, "",
545 node
->dump_name (), e
->callee
->dump_name (),
551 /* Remove all call edge summaries associated with NODE. */
554 remove_modref_edge_summaries (cgraph_node
*node
)
556 if (!escape_summaries
)
558 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
559 escape_summaries
->remove (e
);
560 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
562 if (!e
->inline_failed
)
563 remove_modref_edge_summaries (e
->callee
);
564 escape_summaries
->remove (e
);
565 fnspec_summaries
->remove (e
);
572 modref_summary::dump (FILE *out
) const
576 fprintf (out
, " loads:\n");
577 dump_records (loads
, out
);
581 fprintf (out
, " stores:\n");
582 dump_records (stores
, out
);
586 fprintf (out
, " kills:\n");
587 for (auto kill
: kills
)
594 fprintf (out
, " Writes errno\n");
596 fprintf (out
, " Side effects\n");
597 if (nondeterministic
)
598 fprintf (out
, " Nondeterministic\n");
599 if (calls_interposable
)
600 fprintf (out
, " Calls interposable\n");
601 if (global_memory_read
)
602 fprintf (out
, " Global memory read\n");
603 if (global_memory_written
)
604 fprintf (out
, " Global memory written\n");
606 fprintf (out
, " Try dse\n");
607 if (arg_flags
.length ())
609 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
612 fprintf (out
, " parm %i flags:", i
);
613 dump_eaf_flags (out
, arg_flags
[i
]);
618 fprintf (out
, " Retslot flags:");
619 dump_eaf_flags (out
, retslot_flags
);
621 if (static_chain_flags
)
623 fprintf (out
, " Static chain flags:");
624 dump_eaf_flags (out
, static_chain_flags
);
631 modref_summary_lto::dump (FILE *out
)
633 fprintf (out
, " loads:\n");
634 dump_lto_records (loads
, out
);
635 fprintf (out
, " stores:\n");
636 dump_lto_records (stores
, out
);
639 fprintf (out
, " kills:\n");
640 for (auto kill
: kills
)
647 fprintf (out
, " Writes errno\n");
649 fprintf (out
, " Side effects\n");
650 if (nondeterministic
)
651 fprintf (out
, " Nondeterministic\n");
652 if (calls_interposable
)
653 fprintf (out
, " Calls interposable\n");
654 if (arg_flags
.length ())
656 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
659 fprintf (out
, " parm %i flags:", i
);
660 dump_eaf_flags (out
, arg_flags
[i
]);
665 fprintf (out
, " Retslot flags:");
666 dump_eaf_flags (out
, retslot_flags
);
668 if (static_chain_flags
)
670 fprintf (out
, " Static chain flags:");
671 dump_eaf_flags (out
, static_chain_flags
);
675 /* Called after summary is produced and before it is used by local analysis.
676 Can be called multiple times in case summary needs to update signature.
677 FUN is decl of function summary is attached to. */
679 modref_summary::finalize (tree fun
)
681 global_memory_read
= !loads
|| loads
->global_access_p ();
682 global_memory_written
= !stores
|| stores
->global_access_p ();
684 /* We can do DSE if we know function has no side effects and
685 we can analyze all stores. Disable dse if there are too many
687 if (side_effects
|| global_memory_written
|| writes_errno
)
693 int num_tests
= 0, max_tests
694 = opt_for_fn (fun
, param_modref_max_tests
);
695 modref_base_node
<alias_set_type
> *base_node
;
696 modref_ref_node
<alias_set_type
> *ref_node
;
697 modref_access_node
*access_node
;
698 FOR_EACH_VEC_SAFE_ELT (stores
->bases
, i
, base_node
)
700 if (base_node
->every_ref
)
705 FOR_EACH_VEC_SAFE_ELT (base_node
->refs
, j
, ref_node
)
707 if (base_node
->every_ref
)
712 FOR_EACH_VEC_SAFE_ELT (ref_node
->accesses
, k
, access_node
)
713 if (num_tests
++ > max_tests
714 || !access_node
->parm_offset_known
)
726 if (loads
->every_base
)
731 for (auto base_node
: loads
->bases
)
733 if (base_node
->every_ref
)
736 for (auto ref_node
: base_node
->refs
)
737 if (ref_node
->every_access
)
740 load_accesses
+= ref_node
->accesses
->length ();
745 /* Get function summary for FUNC if it exists, return NULL otherwise. */
748 get_modref_function_summary (cgraph_node
*func
)
750 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
751 if (!optimization_summaries
)
754 /* A single function body may be represented by multiple symbols with
755 different visibility. For example, if FUNC is an interposable alias,
756 we don't want to return anything, even if we have summary for the target
758 enum availability avail
;
759 func
= func
->ultimate_alias_target
760 (&avail
, current_function_decl
?
761 cgraph_node::get (current_function_decl
) : NULL
);
762 if (avail
<= AVAIL_INTERPOSABLE
)
765 modref_summary
*r
= optimization_summaries
->get (func
);
769 /* Get function summary for CALL if it exists, return NULL otherwise.
770 If non-null set interposed to indicate whether function may not
771 bind to current def. In this case sometimes loads from function
772 needs to be ignored. */
775 get_modref_function_summary (gcall
*call
, bool *interposed
)
777 tree callee
= gimple_call_fndecl (call
);
780 struct cgraph_node
*node
= cgraph_node::get (callee
);
783 modref_summary
*r
= get_modref_function_summary (node
);
785 *interposed
= r
->calls_interposable
786 || !node
->binds_to_current_def_p ();
793 /* Return true if ECF flags says that nondeterminism can be ignored. */
796 ignore_nondeterminism_p (tree caller
, int flags
)
798 if (flags
& (ECF_CONST
| ECF_PURE
))
800 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
801 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
806 /* Return true if ECF flags says that return value can be ignored. */
809 ignore_retval_p (tree caller
, int flags
)
811 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
812 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
817 /* Return true if ECF flags says that stores can be ignored. */
820 ignore_stores_p (tree caller
, int flags
)
822 if (flags
& (ECF_PURE
| ECF_CONST
| ECF_NOVOPS
))
824 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
825 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
830 /* Determine parm_map for PTR which is supposed to be a pointer. */
833 parm_map_for_ptr (tree op
)
837 struct modref_parm_map parm_map
;
840 parm_map
.parm_offset_known
= false;
841 parm_map
.parm_offset
= 0;
843 offset_known
= unadjusted_ptr_and_unit_offset (op
, &op
, &offset
);
844 if (TREE_CODE (op
) == SSA_NAME
845 && SSA_NAME_IS_DEFAULT_DEF (op
)
846 && TREE_CODE (SSA_NAME_VAR (op
)) == PARM_DECL
)
850 if (cfun
->static_chain_decl
851 && op
== ssa_default_def (cfun
, cfun
->static_chain_decl
))
852 index
= MODREF_STATIC_CHAIN_PARM
;
854 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
855 t
!= SSA_NAME_VAR (op
); t
= DECL_CHAIN (t
))
857 parm_map
.parm_index
= index
;
858 parm_map
.parm_offset_known
= offset_known
;
859 parm_map
.parm_offset
= offset
;
861 else if (points_to_local_or_readonly_memory_p (op
))
862 parm_map
.parm_index
= MODREF_LOCAL_MEMORY_PARM
;
863 /* Memory allocated in the function is not visible to caller before the
864 call and thus we do not need to record it as load/stores/kills. */
865 else if (TREE_CODE (op
) == SSA_NAME
866 && (call
= dyn_cast
<gcall
*>(SSA_NAME_DEF_STMT (op
))) != NULL
867 && gimple_call_flags (call
) & ECF_MALLOC
)
868 parm_map
.parm_index
= MODREF_LOCAL_MEMORY_PARM
;
870 parm_map
.parm_index
= MODREF_UNKNOWN_PARM
;
874 /* Return true if ARG with EAF flags FLAGS can not make any caller's parameter
875 used (if LOAD is true we check loads, otherwise stores). */
878 verify_arg (tree arg
, int flags
, bool load
)
880 if (flags
& EAF_UNUSED
)
882 if (load
&& (flags
& EAF_NO_DIRECT_READ
))
885 && (flags
& (EAF_NO_DIRECT_CLOBBER
| EAF_NO_INDIRECT_CLOBBER
))
886 == (EAF_NO_DIRECT_CLOBBER
| EAF_NO_INDIRECT_CLOBBER
))
888 if (is_gimple_constant (arg
))
890 if (DECL_P (arg
) && TREE_READONLY (arg
))
892 if (TREE_CODE (arg
) == ADDR_EXPR
)
894 tree t
= get_base_address (TREE_OPERAND (arg
, 0));
895 if (is_gimple_constant (t
))
898 && (TREE_READONLY (t
) || TREE_CODE (t
) == FUNCTION_DECL
))
904 /* Return true if STMT may access memory that is pointed to by parameters
905 of caller and which is not seen as an escape by PTA.
906 CALLEE_ECF_FLAGS are ECF flags of callee. If LOAD is true then by access
907 we mean load, otherwise we mean store. */
910 may_access_nonescaping_parm_p (gcall
*call
, int callee_ecf_flags
, bool load
)
912 int implicit_flags
= 0;
914 if (ignore_stores_p (current_function_decl
, callee_ecf_flags
))
915 implicit_flags
|= ignore_stores_eaf_flags
;
916 if (callee_ecf_flags
& ECF_PURE
)
917 implicit_flags
|= implicit_pure_eaf_flags
;
918 if (callee_ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
919 implicit_flags
|= implicit_const_eaf_flags
;
920 if (gimple_call_chain (call
)
921 && !verify_arg (gimple_call_chain (call
),
922 gimple_call_static_chain_flags (call
) | implicit_flags
,
925 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
926 if (!verify_arg (gimple_call_arg (call
, i
),
927 gimple_call_arg_flags (call
, i
) | implicit_flags
,
934 /* Analyze memory accesses (loads, stores and kills) performed
935 by the function. Set also side_effects, calls_interposable
936 and nondeterminism flags. */
938 class modref_access_analysis
941 modref_access_analysis (bool ipa
, modref_summary
*summary
,
942 modref_summary_lto
*summary_lto
)
943 : m_summary (summary
), m_summary_lto (summary_lto
), m_ipa (ipa
)
948 bool set_side_effects ();
949 bool set_nondeterministic ();
950 static modref_access_node
get_access (ao_ref
*ref
);
951 static void record_access (modref_records
*, ao_ref
*, modref_access_node
&);
952 static void record_access_lto (modref_records_lto
*, ao_ref
*,
953 modref_access_node
&a
);
954 bool record_access_p (tree
);
955 bool record_unknown_load ();
956 bool record_unknown_store ();
957 bool record_global_memory_load ();
958 bool record_global_memory_store ();
959 bool merge_call_side_effects (gimple
*, modref_summary
*,
960 cgraph_node
*, bool);
961 modref_access_node
get_access_for_fnspec (gcall
*, attr_fnspec
&,
962 unsigned int, modref_parm_map
&);
963 void process_fnspec (gcall
*);
964 void analyze_call (gcall
*);
965 static bool analyze_load (gimple
*, tree
, tree
, void *);
966 static bool analyze_store (gimple
*, tree
, tree
, void *);
967 void analyze_stmt (gimple
*, bool);
970 /* Summary being computed.
971 We work either with m_summary or m_summary_lto. Never on both. */
972 modref_summary
*m_summary
;
973 modref_summary_lto
*m_summary_lto
;
974 /* Recursive calls needs simplistic dataflow after analysis finished.
975 Collect all calls into this vector during analysis and later process
976 them in propagate. */
977 auto_vec
<gimple
*, 32> m_recursive_calls
;
978 /* ECF flags of function being analyzed. */
980 /* True if IPA propagation will be done later. */
982 /* Set true if statement currently analyze is known to be
983 executed each time function is called. */
984 bool m_always_executed
;
987 /* Set side_effects flag and return if something changed. */
990 modref_access_analysis::set_side_effects ()
992 bool changed
= false;
994 if (m_summary
&& !m_summary
->side_effects
)
996 m_summary
->side_effects
= true;
999 if (m_summary_lto
&& !m_summary_lto
->side_effects
)
1001 m_summary_lto
->side_effects
= true;
1007 /* Set nondeterministic flag and return if something changed. */
1010 modref_access_analysis::set_nondeterministic ()
1012 bool changed
= false;
1014 if (m_summary
&& !m_summary
->nondeterministic
)
1016 m_summary
->side_effects
= m_summary
->nondeterministic
= true;
1019 if (m_summary_lto
&& !m_summary_lto
->nondeterministic
)
1021 m_summary_lto
->side_effects
= m_summary_lto
->nondeterministic
= true;
1027 /* Construct modref_access_node from REF. */
1030 modref_access_analysis::get_access (ao_ref
*ref
)
1034 base
= ao_ref_base (ref
);
1035 modref_access_node a
= {ref
->offset
, ref
->size
, ref
->max_size
,
1036 0, MODREF_UNKNOWN_PARM
, false, 0};
1037 if (TREE_CODE (base
) == MEM_REF
|| TREE_CODE (base
) == TARGET_MEM_REF
)
1040 modref_parm_map m
= parm_map_for_ptr (TREE_OPERAND (base
, 0));
1042 a
.parm_index
= m
.parm_index
;
1043 if (a
.parm_index
!= MODREF_UNKNOWN_PARM
&& TREE_CODE (memref
) == MEM_REF
)
1046 = wi::to_poly_wide (TREE_OPERAND
1047 (memref
, 1)).to_shwi (&a
.parm_offset
);
1048 if (a
.parm_offset_known
&& m
.parm_offset_known
)
1049 a
.parm_offset
+= m
.parm_offset
;
1051 a
.parm_offset_known
= false;
1055 a
.parm_index
= MODREF_UNKNOWN_PARM
;
1059 /* Record access into the modref_records data structure. */
1062 modref_access_analysis::record_access (modref_records
*tt
,
1064 modref_access_node
&a
)
1066 alias_set_type base_set
= !flag_strict_aliasing
1067 || !flag_ipa_strict_aliasing
? 0
1068 : ao_ref_base_alias_set (ref
);
1069 alias_set_type ref_set
= !flag_strict_aliasing
1070 || !flag_ipa_strict_aliasing
? 0
1071 : (ao_ref_alias_set (ref
));
1074 fprintf (dump_file
, " - Recording base_set=%i ref_set=%i ",
1078 tt
->insert (current_function_decl
, base_set
, ref_set
, a
, false);
1081 /* IPA version of record_access_tree. */
1084 modref_access_analysis::record_access_lto (modref_records_lto
*tt
, ao_ref
*ref
,
1085 modref_access_node
&a
)
1087 /* get_alias_set sometimes use different type to compute the alias set
1088 than TREE_TYPE (base). Do same adjustments. */
1089 tree base_type
= NULL_TREE
, ref_type
= NULL_TREE
;
1090 if (flag_strict_aliasing
&& flag_ipa_strict_aliasing
)
1095 while (handled_component_p (base
))
1096 base
= TREE_OPERAND (base
, 0);
1098 base_type
= reference_alias_ptr_type_1 (&base
);
1101 base_type
= TREE_TYPE (base
);
1103 base_type
= TYPE_REF_CAN_ALIAS_ALL (base_type
)
1104 ? NULL_TREE
: TREE_TYPE (base_type
);
1106 tree ref_expr
= ref
->ref
;
1107 ref_type
= reference_alias_ptr_type_1 (&ref_expr
);
1110 ref_type
= TREE_TYPE (ref_expr
);
1112 ref_type
= TYPE_REF_CAN_ALIAS_ALL (ref_type
)
1113 ? NULL_TREE
: TREE_TYPE (ref_type
);
1115 /* Sanity check that we are in sync with what get_alias_set does. */
1116 gcc_checking_assert ((!base_type
&& !ao_ref_base_alias_set (ref
))
1117 || get_alias_set (base_type
)
1118 == ao_ref_base_alias_set (ref
));
1119 gcc_checking_assert ((!ref_type
&& !ao_ref_alias_set (ref
))
1120 || get_alias_set (ref_type
)
1121 == ao_ref_alias_set (ref
));
1123 /* Do not bother to record types that have no meaningful alias set.
1124 Also skip variably modified types since these go to local streams. */
1125 if (base_type
&& (!get_alias_set (base_type
)
1126 || variably_modified_type_p (base_type
, NULL_TREE
)))
1127 base_type
= NULL_TREE
;
1128 if (ref_type
&& (!get_alias_set (ref_type
)
1129 || variably_modified_type_p (ref_type
, NULL_TREE
)))
1130 ref_type
= NULL_TREE
;
1134 fprintf (dump_file
, " - Recording base type:");
1135 print_generic_expr (dump_file
, base_type
);
1136 fprintf (dump_file
, " (alias set %i) ref type:",
1137 base_type
? get_alias_set (base_type
) : 0);
1138 print_generic_expr (dump_file
, ref_type
);
1139 fprintf (dump_file
, " (alias set %i) ",
1140 ref_type
? get_alias_set (ref_type
) : 0);
1144 tt
->insert (current_function_decl
, base_type
, ref_type
, a
, false);
1147 /* Returns true if and only if we should store the access to EXPR.
1148 Some accesses, e.g. loads from automatic variables, are not interesting. */
1151 modref_access_analysis::record_access_p (tree expr
)
1153 if (TREE_THIS_VOLATILE (expr
))
1156 fprintf (dump_file
, " (volatile; marking nondeterministic) ");
1157 set_nondeterministic ();
1159 if (cfun
->can_throw_non_call_exceptions
1160 && tree_could_throw_p (expr
))
1163 fprintf (dump_file
, " (can throw; marking side effects) ");
1164 set_side_effects ();
1167 if (refs_local_or_readonly_memory_p (expr
))
1170 fprintf (dump_file
, " - Read-only or local, ignoring.\n");
1176 /* Collapse loads and return true if something changed. */
1179 modref_access_analysis::record_unknown_load ()
1181 bool changed
= false;
1183 if (m_summary
&& !m_summary
->loads
->every_base
)
1185 m_summary
->loads
->collapse ();
1188 if (m_summary_lto
&& !m_summary_lto
->loads
->every_base
)
1190 m_summary_lto
->loads
->collapse ();
1196 /* Collapse loads and return true if something changed. */
1199 modref_access_analysis::record_unknown_store ()
1201 bool changed
= false;
1203 if (m_summary
&& !m_summary
->stores
->every_base
)
1205 m_summary
->stores
->collapse ();
1208 if (m_summary_lto
&& !m_summary_lto
->stores
->every_base
)
1210 m_summary_lto
->stores
->collapse ();
1216 /* Record unknown load from global memory. */
1219 modref_access_analysis::record_global_memory_load ()
1221 bool changed
= false;
1222 modref_access_node a
= {0, -1, -1,
1223 0, MODREF_GLOBAL_MEMORY_PARM
, false, 0};
1225 if (m_summary
&& !m_summary
->loads
->every_base
)
1226 changed
|= m_summary
->loads
->insert (current_function_decl
, 0, 0, a
, false);
1227 if (m_summary_lto
&& !m_summary_lto
->loads
->every_base
)
1228 changed
|= m_summary_lto
->loads
->insert (current_function_decl
,
1233 /* Record unknown store from global memory. */
1236 modref_access_analysis::record_global_memory_store ()
1238 bool changed
= false;
1239 modref_access_node a
= {0, -1, -1,
1240 0, MODREF_GLOBAL_MEMORY_PARM
, false, 0};
1242 if (m_summary
&& !m_summary
->stores
->every_base
)
1243 changed
|= m_summary
->stores
->insert (current_function_decl
,
1245 if (m_summary_lto
&& !m_summary_lto
->stores
->every_base
)
1246 changed
|= m_summary_lto
->stores
->insert (current_function_decl
,
1251 /* Merge side effects of call STMT to function with CALLEE_SUMMARY.
1252 Return true if something changed.
1253 If IGNORE_STORES is true, do not merge stores.
1254 If RECORD_ADJUSTMENTS is true cap number of adjustments to
1255 a given access to make dataflow finite. */
1258 modref_access_analysis::merge_call_side_effects
1259 (gimple
*stmt
, modref_summary
*callee_summary
,
1260 cgraph_node
*callee_node
, bool record_adjustments
)
1262 gcall
*call
= as_a
<gcall
*> (stmt
);
1263 int flags
= gimple_call_flags (call
);
1265 /* Nothing to do for non-looping cont functions. */
1266 if ((flags
& (ECF_CONST
| ECF_NOVOPS
))
1267 && !(flags
& ECF_LOOPING_CONST_OR_PURE
))
1270 bool changed
= false;
1273 fprintf (dump_file
, " - Merging side effects of %s\n",
1274 callee_node
->dump_name ());
1276 /* Merge side effects and non-determinism.
1277 PURE/CONST flags makes functions deterministic and if there is
1278 no LOOPING_CONST_OR_PURE they also have no side effects. */
1279 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
| ECF_PURE
))
1280 || (flags
& ECF_LOOPING_CONST_OR_PURE
))
1282 if (!m_summary
->side_effects
&& callee_summary
->side_effects
)
1285 fprintf (dump_file
, " - merging side effects.\n");
1286 m_summary
->side_effects
= true;
1289 if (!m_summary
->nondeterministic
&& callee_summary
->nondeterministic
1290 && !ignore_nondeterminism_p (current_function_decl
, flags
))
1293 fprintf (dump_file
, " - merging nondeterministic.\n");
1294 m_summary
->nondeterministic
= true;
1299 /* For const functions we are done. */
1300 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
1303 /* Merge calls_interposable flags. */
1304 if (!m_summary
->calls_interposable
&& callee_summary
->calls_interposable
)
1307 fprintf (dump_file
, " - merging calls interposable.\n");
1308 m_summary
->calls_interposable
= true;
1312 if (!callee_node
->binds_to_current_def_p () && !m_summary
->calls_interposable
)
1315 fprintf (dump_file
, " - May be interposed.\n");
1316 m_summary
->calls_interposable
= true;
1320 /* Now merge the actual load, store and kill vectors. For this we need
1321 to compute map translating new parameters to old. */
1323 fprintf (dump_file
, " Parm map:");
1325 auto_vec
<modref_parm_map
, 32> parm_map
;
1326 parm_map
.safe_grow_cleared (gimple_call_num_args (call
), true);
1327 for (unsigned i
= 0; i
< gimple_call_num_args (call
); i
++)
1329 parm_map
[i
] = parm_map_for_ptr (gimple_call_arg (call
, i
));
1332 fprintf (dump_file
, " %i", parm_map
[i
].parm_index
);
1333 if (parm_map
[i
].parm_offset_known
)
1335 fprintf (dump_file
, " offset:");
1336 print_dec ((poly_int64
)parm_map
[i
].parm_offset
,
1342 modref_parm_map chain_map
;
1343 if (gimple_call_chain (call
))
1345 chain_map
= parm_map_for_ptr (gimple_call_chain (call
));
1348 fprintf (dump_file
, "static chain %i", chain_map
.parm_index
);
1349 if (chain_map
.parm_offset_known
)
1351 fprintf (dump_file
, " offset:");
1352 print_dec ((poly_int64
)chain_map
.parm_offset
,
1358 fprintf (dump_file
, "\n");
1360 /* Kills can me merged in only if we know the function is going to be
1362 if (m_always_executed
1363 && callee_summary
->kills
.length ()
1364 && (!cfun
->can_throw_non_call_exceptions
1365 || !stmt_could_throw_p (cfun
, call
)))
1367 /* Watch for self recursive updates. */
1368 auto_vec
<modref_access_node
, 32> saved_kills
;
1370 saved_kills
.reserve_exact (callee_summary
->kills
.length ());
1371 saved_kills
.splice (callee_summary
->kills
);
1372 for (auto kill
: saved_kills
)
1374 if (kill
.parm_index
>= (int)parm_map
.length ())
1377 = kill
.parm_index
== MODREF_STATIC_CHAIN_PARM
1379 : parm_map
[kill
.parm_index
];
1380 if (m
.parm_index
== MODREF_LOCAL_MEMORY_PARM
1381 || m
.parm_index
== MODREF_UNKNOWN_PARM
1382 || m
.parm_index
== MODREF_RETSLOT_PARM
1383 || !m
.parm_offset_known
)
1385 modref_access_node n
= kill
;
1386 n
.parm_index
= m
.parm_index
;
1387 n
.parm_offset
+= m
.parm_offset
;
1388 if (modref_access_node::insert_kill (m_summary
->kills
, n
,
1389 record_adjustments
))
1394 /* Merge in loads. */
1395 changed
|= m_summary
->loads
->merge (current_function_decl
,
1396 callee_summary
->loads
,
1397 &parm_map
, &chain_map
,
1399 !may_access_nonescaping_parm_p
1400 (call
, flags
, true));
1401 /* Merge in stores. */
1402 if (!ignore_stores_p (current_function_decl
, flags
))
1404 changed
|= m_summary
->stores
->merge (current_function_decl
,
1405 callee_summary
->stores
,
1406 &parm_map
, &chain_map
,
1408 !may_access_nonescaping_parm_p
1409 (call
, flags
, false));
1410 if (!m_summary
->writes_errno
1411 && callee_summary
->writes_errno
)
1413 m_summary
->writes_errno
= true;
1420 /* Return access mode for argument I of call STMT with FNSPEC. */
1423 modref_access_analysis::get_access_for_fnspec (gcall
*call
, attr_fnspec
&fnspec
,
1425 modref_parm_map
&map
)
1427 tree size
= NULL_TREE
;
1428 unsigned int size_arg
;
1430 if (!fnspec
.arg_specified_p (i
))
1432 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
1433 size
= gimple_call_arg (call
, size_arg
);
1434 else if (fnspec
.arg_access_size_given_by_type_p (i
))
1436 tree callee
= gimple_call_fndecl (call
);
1437 tree t
= TYPE_ARG_TYPES (TREE_TYPE (callee
));
1439 for (unsigned int p
= 0; p
< i
; p
++)
1441 size
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t
)));
1443 modref_access_node a
= {0, -1, -1,
1444 map
.parm_offset
, map
.parm_index
,
1445 map
.parm_offset_known
, 0};
1446 poly_int64 size_hwi
;
1448 && poly_int_tree_p (size
, &size_hwi
)
1449 && coeffs_in_range_p (size_hwi
, 0,
1450 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
1453 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
1457 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1458 If IGNORE_STORES is true ignore them.
1459 Return false if no useful summary can be produced. */
1462 modref_access_analysis::process_fnspec (gcall
*call
)
1464 int flags
= gimple_call_flags (call
);
1466 /* PURE/CONST flags makes functions deterministic and if there is
1467 no LOOPING_CONST_OR_PURE they also have no side effects. */
1468 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
| ECF_PURE
))
1469 || (flags
& ECF_LOOPING_CONST_OR_PURE
)
1470 || (cfun
->can_throw_non_call_exceptions
1471 && stmt_could_throw_p (cfun
, call
)))
1473 set_side_effects ();
1474 if (!ignore_nondeterminism_p (current_function_decl
, flags
))
1475 set_nondeterministic ();
1478 /* For const functions we are done. */
1479 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
1482 attr_fnspec fnspec
= gimple_call_fnspec (call
);
1483 /* If there is no fnpec we know nothing about loads & stores. */
1484 if (!fnspec
.known_p ())
1486 if (dump_file
&& gimple_call_builtin_p (call
, BUILT_IN_NORMAL
))
1487 fprintf (dump_file
, " Builtin with no fnspec: %s\n",
1488 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call
))));
1489 if (!ignore_stores_p (current_function_decl
, flags
))
1491 if (!may_access_nonescaping_parm_p (call
, flags
, false))
1492 record_global_memory_store ();
1494 record_unknown_store ();
1495 if (!may_access_nonescaping_parm_p (call
, flags
, true))
1496 record_global_memory_load ();
1498 record_unknown_load ();
1502 if (!may_access_nonescaping_parm_p (call
, flags
, true))
1503 record_global_memory_load ();
1505 record_unknown_load ();
1509 /* Process fnspec. */
1510 if (fnspec
.global_memory_read_p ())
1512 if (may_access_nonescaping_parm_p (call
, flags
, true))
1513 record_unknown_load ();
1515 record_global_memory_load ();
1519 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1520 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1522 else if (!fnspec
.arg_specified_p (i
)
1523 || fnspec
.arg_maybe_read_p (i
))
1525 modref_parm_map map
= parm_map_for_ptr
1526 (gimple_call_arg (call
, i
));
1528 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1530 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
1532 record_unknown_load ();
1535 modref_access_node a
= get_access_for_fnspec (call
, fnspec
, i
, map
);
1536 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1539 m_summary
->loads
->insert (current_function_decl
, 0, 0, a
, false);
1541 m_summary_lto
->loads
->insert (current_function_decl
, 0, 0, a
,
1545 if (ignore_stores_p (current_function_decl
, flags
))
1547 if (fnspec
.global_memory_written_p ())
1549 if (may_access_nonescaping_parm_p (call
, flags
, false))
1550 record_unknown_store ();
1552 record_global_memory_store ();
1556 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1557 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1559 else if (!fnspec
.arg_specified_p (i
)
1560 || fnspec
.arg_maybe_written_p (i
))
1562 modref_parm_map map
= parm_map_for_ptr
1563 (gimple_call_arg (call
, i
));
1565 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1567 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
1569 record_unknown_store ();
1572 modref_access_node a
= get_access_for_fnspec (call
, fnspec
, i
, map
);
1573 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1576 m_summary
->stores
->insert (current_function_decl
, 0, 0, a
, false);
1578 m_summary_lto
->stores
->insert (current_function_decl
,
1581 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
1584 m_summary
->writes_errno
= true;
1586 m_summary_lto
->writes_errno
= true;
1591 /* Analyze function call STMT in function F.
1592 Remember recursive calls in RECURSIVE_CALLS. */
1595 modref_access_analysis::analyze_call (gcall
*stmt
)
1597 /* Check flags on the function call. In certain cases, analysis can be
1599 int flags
= gimple_call_flags (stmt
);
1603 fprintf (dump_file
, " - Analyzing call:");
1604 print_gimple_stmt (dump_file
, stmt
, 0);
1607 if ((flags
& (ECF_CONST
| ECF_NOVOPS
))
1608 && !(flags
& ECF_LOOPING_CONST_OR_PURE
))
1612 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1613 "except for args.\n");
1617 /* Next, we try to get the callee's function declaration. The goal is to
1618 merge their summary with ours. */
1619 tree callee
= gimple_call_fndecl (stmt
);
1621 /* Check if this is an indirect call. */
1625 fprintf (dump_file
, gimple_call_internal_p (stmt
)
1626 ? " - Internal call" : " - Indirect call.\n");
1627 process_fnspec (stmt
);
1630 /* We only need to handle internal calls in IPA mode. */
1631 gcc_checking_assert (!m_summary_lto
&& !m_ipa
);
1633 struct cgraph_node
*callee_node
= cgraph_node::get_create (callee
);
1635 /* If this is a recursive call, the target summary is the same as ours, so
1636 there's nothing to do. */
1637 if (recursive_call_p (current_function_decl
, callee
))
1639 m_recursive_calls
.safe_push (stmt
);
1640 set_side_effects ();
1642 fprintf (dump_file
, " - Skipping recursive call.\n");
1646 gcc_assert (callee_node
!= NULL
);
1648 /* Get the function symbol and its availability. */
1649 enum availability avail
;
1650 callee_node
= callee_node
->function_symbol (&avail
);
1652 if (builtin_safe_for_const_function_p (&looping
, callee
))
1655 set_side_effects ();
1657 fprintf (dump_file
, " - Builtin is safe for const.\n");
1660 if (avail
<= AVAIL_INTERPOSABLE
)
1664 " - Function availability <= AVAIL_INTERPOSABLE.\n");
1665 process_fnspec (stmt
);
1669 /* Get callee's modref summary. As above, if there's no summary, we either
1670 have to give up or, if stores are ignored, we can just purge loads. */
1671 modref_summary
*callee_summary
= optimization_summaries
->get (callee_node
);
1672 if (!callee_summary
)
1675 fprintf (dump_file
, " - No modref summary available for callee.\n");
1676 process_fnspec (stmt
);
1680 merge_call_side_effects (stmt
, callee_summary
, callee_node
, false);
1685 /* Helper for analyze_stmt. */
1688 modref_access_analysis::analyze_load (gimple
*, tree
, tree op
, void *data
)
1690 modref_access_analysis
*t
= (modref_access_analysis
*)data
;
1694 fprintf (dump_file
, " - Analyzing load: ");
1695 print_generic_expr (dump_file
, op
);
1696 fprintf (dump_file
, "\n");
1699 if (!t
->record_access_p (op
))
1703 ao_ref_init (&r
, op
);
1704 modref_access_node a
= get_access (&r
);
1705 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1709 t
->record_access (t
->m_summary
->loads
, &r
, a
);
1710 if (t
->m_summary_lto
)
1711 t
->record_access_lto (t
->m_summary_lto
->loads
, &r
, a
);
1715 /* Helper for analyze_stmt. */
1718 modref_access_analysis::analyze_store (gimple
*stmt
, tree
, tree op
, void *data
)
1720 modref_access_analysis
*t
= (modref_access_analysis
*)data
;
1724 fprintf (dump_file
, " - Analyzing store: ");
1725 print_generic_expr (dump_file
, op
);
1726 fprintf (dump_file
, "\n");
1729 if (!t
->record_access_p (op
))
1733 ao_ref_init (&r
, op
);
1734 modref_access_node a
= get_access (&r
);
1735 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1739 t
->record_access (t
->m_summary
->stores
, &r
, a
);
1740 if (t
->m_summary_lto
)
1741 t
->record_access_lto (t
->m_summary_lto
->stores
, &r
, a
);
1742 if (t
->m_always_executed
1743 && a
.useful_for_kill_p ()
1744 && (!cfun
->can_throw_non_call_exceptions
1745 || !stmt_could_throw_p (cfun
, stmt
)))
1748 fprintf (dump_file
, " - Recording kill\n");
1750 modref_access_node::insert_kill (t
->m_summary
->kills
, a
, false);
1751 if (t
->m_summary_lto
)
1752 modref_access_node::insert_kill (t
->m_summary_lto
->kills
, a
, false);
1757 /* Analyze statement STMT of function F.
1758 If IPA is true do not merge in side effects of calls. */
1761 modref_access_analysis::analyze_stmt (gimple
*stmt
, bool always_executed
)
1763 m_always_executed
= always_executed
;
1764 /* In general we can not ignore clobbers because they are barriers for code
1765 motion, however after inlining it is safe to do because local optimization
1766 passes do not consider clobbers from other functions.
1767 Similar logic is in ipa-pure-const.cc. */
1768 if ((m_ipa
|| cfun
->after_inlining
) && gimple_clobber_p (stmt
))
1770 if (always_executed
&& record_access_p (gimple_assign_lhs (stmt
)))
1773 ao_ref_init (&r
, gimple_assign_lhs (stmt
));
1774 modref_access_node a
= get_access (&r
);
1775 if (a
.useful_for_kill_p ())
1778 fprintf (dump_file
, " - Recording kill\n");
1780 modref_access_node::insert_kill (m_summary
->kills
, a
, false);
1782 modref_access_node::insert_kill (m_summary_lto
->kills
,
1789 /* Analyze all loads and stores in STMT. */
1790 walk_stmt_load_store_ops (stmt
, this,
1791 analyze_load
, analyze_store
);
1793 switch (gimple_code (stmt
))
1796 if (gimple_asm_volatile_p (as_a
<gasm
*> (stmt
)))
1797 set_nondeterministic ();
1798 if (cfun
->can_throw_non_call_exceptions
1799 && stmt_could_throw_p (cfun
, stmt
))
1800 set_side_effects ();
1801 /* If the ASM statement does not read nor write memory, there's nothing
1802 to do. Otherwise just give up. */
1803 if (!gimple_asm_clobbers_memory_p (as_a
<gasm
*> (stmt
)))
1806 fprintf (dump_file
, " - Function contains GIMPLE_ASM statement "
1807 "which clobbers memory.\n");
1808 record_unknown_load ();
1809 record_unknown_store ();
1812 if (!m_ipa
|| gimple_call_internal_p (stmt
))
1813 analyze_call (as_a
<gcall
*> (stmt
));
1816 attr_fnspec fnspec
= gimple_call_fnspec (as_a
<gcall
*>(stmt
));
1818 if (fnspec
.known_p ()
1819 && (!fnspec
.global_memory_read_p ()
1820 || !fnspec
.global_memory_written_p ()))
1822 cgraph_edge
*e
= cgraph_node::get
1823 (current_function_decl
)->get_edge (stmt
);
1826 fnspec_summaries
->get_create (e
)->fnspec
1827 = xstrdup (fnspec
.get_str ());
1829 fprintf (dump_file
, " Recorded fnspec %s\n",
1836 if (cfun
->can_throw_non_call_exceptions
1837 && stmt_could_throw_p (cfun
, stmt
))
1838 set_side_effects ();
1843 /* Propagate load/stores across recursive calls. */
1846 modref_access_analysis::propagate ()
1848 if (m_ipa
&& m_summary
)
1851 bool changed
= true;
1853 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1855 m_always_executed
= false;
1856 while (changed
&& m_summary
->useful_p (m_ecf_flags
, false))
1859 for (unsigned i
= 0; i
< m_recursive_calls
.length (); i
++)
1861 changed
|= merge_call_side_effects (m_recursive_calls
[i
], m_summary
,
1868 /* Analyze function. */
1871 modref_access_analysis::analyze ()
1873 m_ecf_flags
= flags_from_decl_or_type (current_function_decl
);
1874 bool summary_useful
= true;
1876 /* Analyze each statement in each basic block of the function. If the
1877 statement cannot be analyzed (for any reason), the entire function cannot
1878 be analyzed by modref. */
1880 bitmap always_executed_bbs
= find_always_executed_bbs (cfun
, true);
1881 FOR_EACH_BB_FN (bb
, cfun
)
1883 gimple_stmt_iterator si
;
1884 bool always_executed
= bitmap_bit_p (always_executed_bbs
, bb
->index
);
1886 for (si
= gsi_start_nondebug_after_labels_bb (bb
);
1887 !gsi_end_p (si
); gsi_next_nondebug (&si
))
1889 /* NULL memory accesses terminates BB. These accesses are known
1890 to trip undefined behavior. gimple-ssa-isolate-paths turns them
1891 to volatile accesses and adds builtin_trap call which would
1892 confuse us otherwise. */
1893 if (infer_nonnull_range_by_dereference (gsi_stmt (si
),
1897 fprintf (dump_file
, " - NULL memory access; terminating BB\n");
1898 if (flag_non_call_exceptions
)
1899 set_side_effects ();
1902 analyze_stmt (gsi_stmt (si
), always_executed
);
1904 /* Avoid doing useless work. */
1905 if ((!m_summary
|| !m_summary
->useful_p (m_ecf_flags
, false))
1907 || !m_summary_lto
->useful_p (m_ecf_flags
, false)))
1909 summary_useful
= false;
1913 && stmt_can_throw_external (cfun
, gsi_stmt (si
)))
1914 always_executed
= false;
1916 if (!summary_useful
)
1919 /* In non-IPA mode we need to perform iterative dataflow on recursive calls.
1920 This needs to be done after all other side effects are computed. */
1925 if (m_summary
&& !m_summary
->side_effects
&& !finite_function_p ())
1926 m_summary
->side_effects
= true;
1927 if (m_summary_lto
&& !m_summary_lto
->side_effects
1928 && !finite_function_p ())
1929 m_summary_lto
->side_effects
= true;
1931 BITMAP_FREE (always_executed_bbs
);
1934 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1937 memory_access_to (tree op
, tree ssa_name
)
1939 tree base
= get_base_address (op
);
1942 if (TREE_CODE (base
) != MEM_REF
&& TREE_CODE (base
) != TARGET_MEM_REF
)
1944 return TREE_OPERAND (base
, 0) == ssa_name
;
1947 /* Consider statement val = *arg.
1948 return EAF flags of ARG that can be determined from EAF flags of VAL
1949 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1950 all stores to VAL, i.e. when handling noreturn function. */
1953 deref_flags (int flags
, bool ignore_stores
)
1955 /* Dereference is also a direct read but dereferenced value does not
1956 yield any other direct use. */
1957 int ret
= EAF_NO_DIRECT_CLOBBER
| EAF_NO_DIRECT_ESCAPE
1958 | EAF_NOT_RETURNED_DIRECTLY
;
1959 /* If argument is unused just account for
1960 the read involved in dereference. */
1961 if (flags
& EAF_UNUSED
)
1962 ret
|= EAF_NO_INDIRECT_READ
| EAF_NO_INDIRECT_CLOBBER
1963 | EAF_NO_INDIRECT_ESCAPE
;
1966 /* Direct or indirect accesses leads to indirect accesses. */
1967 if (((flags
& EAF_NO_DIRECT_CLOBBER
)
1968 && (flags
& EAF_NO_INDIRECT_CLOBBER
))
1970 ret
|= EAF_NO_INDIRECT_CLOBBER
;
1971 if (((flags
& EAF_NO_DIRECT_ESCAPE
)
1972 && (flags
& EAF_NO_INDIRECT_ESCAPE
))
1974 ret
|= EAF_NO_INDIRECT_ESCAPE
;
1975 if ((flags
& EAF_NO_DIRECT_READ
)
1976 && (flags
& EAF_NO_INDIRECT_READ
))
1977 ret
|= EAF_NO_INDIRECT_READ
;
1978 if ((flags
& EAF_NOT_RETURNED_DIRECTLY
)
1979 && (flags
& EAF_NOT_RETURNED_INDIRECTLY
))
1980 ret
|= EAF_NOT_RETURNED_INDIRECTLY
;
1986 /* Description of an escape point: a call which affects flags of a given
1991 /* Value escapes to this call. */
1993 /* Argument it escapes to. */
1995 /* Flags already known about the argument (this can save us from recording
1996 escape points if local analysis did good job already). */
1997 eaf_flags_t min_flags
;
1998 /* Does value escape directly or indirectly? */
2002 /* Lattice used during the eaf flags analysis dataflow. For a given SSA name
2003 we aim to compute its flags and escape points. We also use the lattice
2004 to dynamically build dataflow graph to propagate on. */
2006 class modref_lattice
2009 /* EAF flags of the SSA name. */
2011 /* Used during DFS walk to mark names where final value was determined
2012 without need for dataflow. */
2014 /* Used during DFS walk to mark open vertices (for cycle detection). */
2016 /* Set during DFS walk for names that needs dataflow propagation. */
2018 /* Used during the iterative dataflow. */
2021 /* When doing IPA analysis we can not merge in callee escape points;
2022 Only remember them and do the merging at IPA propagation time. */
2023 vec
<escape_point
, va_heap
, vl_ptr
> escape_points
;
2025 /* Representation of a graph for dataflow. This graph is built on-demand
2026 using modref_eaf_analysis::analyze_ssa and later solved by
2027 modref_eaf_analysis::propagate.
2028 Each edge represents the fact that flags of current lattice should be
2029 propagated to lattice of SSA_NAME. */
2030 struct propagate_edge
2035 vec
<propagate_edge
, va_heap
, vl_ptr
> propagate_to
;
2039 bool merge (const modref_lattice
&with
);
2040 bool merge (int flags
);
2041 bool merge_deref (const modref_lattice
&with
, bool ignore_stores
);
2042 bool merge_direct_load ();
2043 bool merge_direct_store ();
2044 bool add_escape_point (gcall
*call
, int arg
, int min_flags
, bool diret
);
2045 void dump (FILE *out
, int indent
= 0) const;
2048 /* Lattices are saved to vectors, so keep them PODs. */
2050 modref_lattice::init ()
2052 /* All flags we track. */
2053 int f
= EAF_NO_DIRECT_CLOBBER
| EAF_NO_INDIRECT_CLOBBER
2054 | EAF_NO_DIRECT_ESCAPE
| EAF_NO_INDIRECT_ESCAPE
2055 | EAF_NO_DIRECT_READ
| EAF_NO_INDIRECT_READ
2056 | EAF_NOT_RETURNED_DIRECTLY
| EAF_NOT_RETURNED_INDIRECTLY
2059 /* Check that eaf_flags_t is wide enough to hold all flags. */
2060 gcc_checking_assert (f
== flags
);
2065 /* Release memory. */
2067 modref_lattice::release ()
2069 escape_points
.release ();
2070 propagate_to
.release ();
2073 /* Dump lattice to OUT; indent with INDENT spaces. */
2076 modref_lattice::dump (FILE *out
, int indent
) const
2078 dump_eaf_flags (out
, flags
);
2079 if (escape_points
.length ())
2081 fprintf (out
, "%*sEscapes:\n", indent
, "");
2082 for (unsigned int i
= 0; i
< escape_points
.length (); i
++)
2084 fprintf (out
, "%*s Arg %i (%s) min flags", indent
, "",
2085 escape_points
[i
].arg
,
2086 escape_points
[i
].direct
? "direct" : "indirect");
2087 dump_eaf_flags (out
, escape_points
[i
].min_flags
, false);
2088 fprintf (out
, " in call ");
2089 print_gimple_stmt (out
, escape_points
[i
].call
, 0);
2094 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
2098 modref_lattice::add_escape_point (gcall
*call
, int arg
, int min_flags
,
2104 /* If we already determined flags to be bad enough,
2105 we do not need to record. */
2106 if ((flags
& min_flags
) == flags
|| (min_flags
& EAF_UNUSED
))
2109 FOR_EACH_VEC_ELT (escape_points
, i
, ep
)
2110 if (ep
->call
== call
&& ep
->arg
== arg
&& ep
->direct
== direct
)
2112 if ((ep
->min_flags
& min_flags
) == min_flags
)
2114 ep
->min_flags
&= min_flags
;
2117 /* Give up if max escape points is met. */
2118 if ((int)escape_points
.length () > param_modref_max_escape_points
)
2121 fprintf (dump_file
, "--param modref-max-escape-points limit reached\n");
2125 escape_point new_ep
= {call
, arg
, min_flags
, direct
};
2126 escape_points
.safe_push (new_ep
);
2130 /* Merge in flags from F. */
2132 modref_lattice::merge (int f
)
2136 /* Check that flags seems sane: if function does not read the parameter
2137 it can not access it indirectly. */
2138 gcc_checking_assert (!(f
& EAF_NO_DIRECT_READ
)
2139 || ((f
& EAF_NO_INDIRECT_READ
)
2140 && (f
& EAF_NO_INDIRECT_CLOBBER
)
2141 && (f
& EAF_NO_INDIRECT_ESCAPE
)
2142 && (f
& EAF_NOT_RETURNED_INDIRECTLY
)));
2143 if ((flags
& f
) != flags
)
2146 /* Prune obviously useless flags;
2147 We do not have ECF_FLAGS handy which is not big problem since
2148 we will do final flags cleanup before producing summary.
2149 Merging should be fast so it can work well with dataflow. */
2150 flags
= remove_useless_eaf_flags (flags
, 0, false);
2152 escape_points
.release ();
2158 /* Merge in WITH. Return true if anything changed. */
2161 modref_lattice::merge (const modref_lattice
&with
)
2166 bool changed
= merge (with
.flags
);
2170 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
2171 changed
|= add_escape_point (with
.escape_points
[i
].call
,
2172 with
.escape_points
[i
].arg
,
2173 with
.escape_points
[i
].min_flags
,
2174 with
.escape_points
[i
].direct
);
2178 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
2179 stores. Return true if anything changed. */
2182 modref_lattice::merge_deref (const modref_lattice
&with
, bool ignore_stores
)
2187 bool changed
= merge (deref_flags (with
.flags
, ignore_stores
));
2191 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
2193 int min_flags
= with
.escape_points
[i
].min_flags
;
2195 if (with
.escape_points
[i
].direct
)
2196 min_flags
= deref_flags (min_flags
, ignore_stores
);
2197 else if (ignore_stores
)
2198 min_flags
|= ignore_stores_eaf_flags
;
2199 changed
|= add_escape_point (with
.escape_points
[i
].call
,
2200 with
.escape_points
[i
].arg
,
2207 /* Merge in flags for direct load. */
2210 modref_lattice::merge_direct_load ()
2212 return merge (~(EAF_UNUSED
| EAF_NO_DIRECT_READ
));
2215 /* Merge in flags for direct store. */
2218 modref_lattice::merge_direct_store ()
2220 return merge (~(EAF_UNUSED
| EAF_NO_DIRECT_CLOBBER
));
2223 /* Analyzer of EAF flags.
2224 This is generally dataflow problem over the SSA graph, however we only
2225 care about flags of few selected ssa names (arguments, return slot and
2226 static chain). So we first call analyze_ssa_name on all relevant names
2227 and perform a DFS walk to discover SSA names where flags needs to be
2228 determined. For acyclic graphs we try to determine final flags during
2229 this walk. Once cycles or recursion depth is met we enlist SSA names
2230 for dataflow which is done by propagate call.
2232 After propagation the flags can be obtained using get_ssa_name_flags. */
2234 class modref_eaf_analysis
2237 /* Mark NAME as relevant for analysis. */
2238 void analyze_ssa_name (tree name
, bool deferred
= false);
2239 /* Dataflow solver. */
2241 /* Return flags computed earlier for NAME. */
2242 int get_ssa_name_flags (tree name
)
2244 int version
= SSA_NAME_VERSION (name
);
2245 gcc_checking_assert (m_lattice
[version
].known
);
2246 return m_lattice
[version
].flags
;
2248 /* In IPA mode this will record all escape points
2249 determined for NAME to PARM_IDNEX. Flags are minimal
2251 void record_escape_points (tree name
, int parm_index
, int flags
);
2252 modref_eaf_analysis (bool ipa
)
2256 m_lattice
.safe_grow_cleared (num_ssa_names
, true);
2258 ~modref_eaf_analysis ()
2260 gcc_checking_assert (!m_depth
);
2261 if (m_ipa
|| m_names_to_propagate
.length ())
2262 for (unsigned int i
= 0; i
< num_ssa_names
; i
++)
2263 m_lattice
[i
].release ();
2266 /* If true, we produce analysis for IPA mode. In this case escape points are
2269 /* Depth of recursion of analyze_ssa_name. */
2271 /* Propagation lattice for individual ssa names. */
2272 auto_vec
<modref_lattice
> m_lattice
;
2273 auto_vec
<tree
> m_deferred_names
;
2274 auto_vec
<int> m_names_to_propagate
;
2276 void merge_with_ssa_name (tree dest
, tree src
, bool deref
);
2277 void merge_call_lhs_flags (gcall
*call
, int arg
, tree name
, bool direct
,
2282 /* Call statements may return their parameters. Consider argument number
2283 ARG of USE_STMT and determine flags that can needs to be cleared
2284 in case pointer possibly indirectly references from ARG I is returned.
2285 If DIRECT is true consider direct returns and if INDIRECT consider
2287 LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
2288 ARG is set to -1 for static chain. */
2291 modref_eaf_analysis::merge_call_lhs_flags (gcall
*call
, int arg
,
2292 tree name
, bool direct
,
2295 int index
= SSA_NAME_VERSION (name
);
2296 bool returned_directly
= false;
2298 /* If there is no return value, no flags are affected. */
2299 if (!gimple_call_lhs (call
))
2302 /* If we know that function returns given argument and it is not ARG
2303 we can still be happy. */
2306 int flags
= gimple_call_return_flags (call
);
2307 if (flags
& ERF_RETURNS_ARG
)
2309 if ((flags
& ERF_RETURN_ARG_MASK
) == arg
)
2310 returned_directly
= true;
2315 /* Make ERF_RETURNS_ARG overwrite EAF_UNUSED. */
2316 if (returned_directly
)
2321 /* If value is not returned at all, do nothing. */
2322 else if (!direct
&& !indirect
)
2325 /* If return value is SSA name determine its flags. */
2326 if (TREE_CODE (gimple_call_lhs (call
)) == SSA_NAME
)
2328 tree lhs
= gimple_call_lhs (call
);
2330 merge_with_ssa_name (name
, lhs
, false);
2332 merge_with_ssa_name (name
, lhs
, true);
2334 /* In the case of memory store we can do nothing. */
2336 m_lattice
[index
].merge (deref_flags (0, false));
2338 m_lattice
[index
].merge (0);
2341 /* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
2342 into flags for caller, update LATTICE of corresponding
2343 argument if needed. */
2346 callee_to_caller_flags (int call_flags
, bool ignore_stores
,
2347 modref_lattice
&lattice
)
2349 /* call_flags is about callee returning a value
2350 that is not the same as caller returning it. */
2351 call_flags
|= EAF_NOT_RETURNED_DIRECTLY
2352 | EAF_NOT_RETURNED_INDIRECTLY
;
2353 if (!ignore_stores
&& !(call_flags
& EAF_UNUSED
))
2355 /* If value escapes we are no longer able to track what happens
2356 with it because we can read it from the escaped location
2358 if (!(call_flags
& EAF_NO_DIRECT_ESCAPE
))
2360 else if (!(call_flags
& EAF_NO_INDIRECT_ESCAPE
))
2361 lattice
.merge (~(EAF_NOT_RETURNED_INDIRECTLY
2362 | EAF_NO_DIRECT_READ
2363 | EAF_NO_INDIRECT_READ
2364 | EAF_NO_INDIRECT_CLOBBER
2368 call_flags
|= ignore_stores_eaf_flags
;
2372 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
2373 LATTICE is an array of modref_lattices.
2374 DEPTH is a recursion depth used to make debug output prettier.
2375 If IPA is true we analyze for IPA propagation (and thus call escape points
2376 are processed later) */
2379 modref_eaf_analysis::analyze_ssa_name (tree name
, bool deferred
)
2381 imm_use_iterator ui
;
2383 int index
= SSA_NAME_VERSION (name
);
2387 /* See if value is already computed. */
2388 if (m_lattice
[index
].known
|| m_lattice
[index
].do_dataflow
)
2390 if (m_lattice
[index
].open
)
2394 "%*sCycle in SSA graph\n",
2398 /* Recursion guard. */
2399 m_lattice
[index
].init ();
2400 if (m_depth
== param_modref_max_depth
)
2404 "%*sMax recursion depth reached; postponing\n",
2406 m_deferred_names
.safe_push (name
);
2414 "%*sAnalyzing flags of ssa name: ", m_depth
* 4, "");
2415 print_generic_expr (dump_file
, name
);
2416 fprintf (dump_file
, "\n");
2419 FOR_EACH_IMM_USE_STMT (use_stmt
, ui
, name
)
2421 if (m_lattice
[index
].flags
== 0)
2423 if (is_gimple_debug (use_stmt
))
2427 fprintf (dump_file
, "%*s Analyzing stmt: ", m_depth
* 4, "");
2428 print_gimple_stmt (dump_file
, use_stmt
, 0);
2430 /* If we see a direct non-debug use, clear unused bit.
2431 All dereferences should be accounted below using deref_flags. */
2432 m_lattice
[index
].merge (~EAF_UNUSED
);
2434 /* Gimple return may load the return value.
2435 Returning name counts as an use by tree-ssa-structalias.cc */
2436 if (greturn
*ret
= dyn_cast
<greturn
*> (use_stmt
))
2438 /* Returning through return slot is seen as memory write earlier. */
2439 if (DECL_RESULT (current_function_decl
)
2440 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl
)))
2442 else if (gimple_return_retval (ret
) == name
)
2443 m_lattice
[index
].merge (~(EAF_UNUSED
| EAF_NOT_RETURNED_DIRECTLY
2444 | EAF_NOT_RETURNED_DIRECTLY
));
2445 else if (memory_access_to (gimple_return_retval (ret
), name
))
2447 m_lattice
[index
].merge_direct_load ();
2448 m_lattice
[index
].merge (~(EAF_UNUSED
2449 | EAF_NOT_RETURNED_INDIRECTLY
));
2452 /* Account for LHS store, arg loads and flags from callee function. */
2453 else if (gcall
*call
= dyn_cast
<gcall
*> (use_stmt
))
2455 tree callee
= gimple_call_fndecl (call
);
2457 /* IPA PTA internally it treats calling a function as "writing" to
2458 the argument space of all functions the function pointer points to
2459 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
2460 is on since that would allow propagation of this from -fno-ipa-pta
2461 to -fipa-pta functions. */
2462 if (gimple_call_fn (use_stmt
) == name
)
2463 m_lattice
[index
].merge (~(EAF_NO_DIRECT_CLOBBER
| EAF_UNUSED
));
2465 /* Recursion would require bit of propagation; give up for now. */
2466 if (callee
&& !m_ipa
&& recursive_call_p (current_function_decl
,
2468 m_lattice
[index
].merge (0);
2471 int ecf_flags
= gimple_call_flags (call
);
2472 bool ignore_stores
= ignore_stores_p (current_function_decl
,
2474 bool ignore_retval
= ignore_retval_p (current_function_decl
,
2477 /* Handle *name = func (...). */
2478 if (gimple_call_lhs (call
)
2479 && memory_access_to (gimple_call_lhs (call
), name
))
2481 m_lattice
[index
].merge_direct_store ();
2482 /* Return slot optimization passes address of
2483 LHS to callee via hidden parameter and this
2484 may make LHS to escape. See PR 98499. */
2485 if (gimple_call_return_slot_opt_p (call
)
2486 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call
))))
2488 int call_flags
= gimple_call_retslot_flags (call
);
2489 bool isretslot
= false;
2491 if (DECL_RESULT (current_function_decl
)
2492 && DECL_BY_REFERENCE
2493 (DECL_RESULT (current_function_decl
)))
2494 isretslot
= ssa_default_def
2496 DECL_RESULT (current_function_decl
))
2499 /* Passing returnslot to return slot is special because
2500 not_returned and escape has same meaning.
2501 However passing arg to return slot is different. If
2502 the callee's return slot is returned it means that
2503 arg is written to itself which is an escape.
2504 Since we do not track the memory it is written to we
2505 need to give up on analyzing it. */
2508 if (!(call_flags
& (EAF_NOT_RETURNED_DIRECTLY
2510 m_lattice
[index
].merge (0);
2511 else gcc_checking_assert
2512 (call_flags
& (EAF_NOT_RETURNED_INDIRECTLY
2514 call_flags
= callee_to_caller_flags
2518 m_lattice
[index
].merge (call_flags
);
2522 if (gimple_call_chain (call
)
2523 && (gimple_call_chain (call
) == name
))
2525 int call_flags
= gimple_call_static_chain_flags (call
);
2526 if (!ignore_retval
&& !(call_flags
& EAF_UNUSED
))
2527 merge_call_lhs_flags
2529 !(call_flags
& EAF_NOT_RETURNED_DIRECTLY
),
2530 !(call_flags
& EAF_NOT_RETURNED_INDIRECTLY
));
2531 call_flags
= callee_to_caller_flags
2532 (call_flags
, ignore_stores
,
2534 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
2535 m_lattice
[index
].merge (call_flags
);
2538 /* Process internal functions and right away. */
2539 bool record_ipa
= m_ipa
&& !gimple_call_internal_p (call
);
2541 /* Handle all function parameters. */
2542 for (unsigned i
= 0;
2543 i
< gimple_call_num_args (call
)
2544 && m_lattice
[index
].flags
; i
++)
2545 /* Name is directly passed to the callee. */
2546 if (gimple_call_arg (call
, i
) == name
)
2548 int call_flags
= gimple_call_arg_flags (call
, i
);
2550 merge_call_lhs_flags
2552 !(call_flags
& (EAF_NOT_RETURNED_DIRECTLY
2554 !(call_flags
& (EAF_NOT_RETURNED_INDIRECTLY
2556 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
2558 call_flags
= callee_to_caller_flags
2559 (call_flags
, ignore_stores
,
2562 m_lattice
[index
].merge (call_flags
);
2564 m_lattice
[index
].add_escape_point (call
, i
,
2568 /* Name is dereferenced and passed to a callee. */
2569 else if (memory_access_to (gimple_call_arg (call
, i
), name
))
2571 int call_flags
= deref_flags
2572 (gimple_call_arg_flags (call
, i
), ignore_stores
);
2573 if (!ignore_retval
&& !(call_flags
& EAF_UNUSED
)
2574 && !(call_flags
& EAF_NOT_RETURNED_DIRECTLY
)
2575 && !(call_flags
& EAF_NOT_RETURNED_INDIRECTLY
))
2576 merge_call_lhs_flags (call
, i
, name
, false, true);
2577 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
2578 m_lattice
[index
].merge_direct_load ();
2581 call_flags
= callee_to_caller_flags
2582 (call_flags
, ignore_stores
,
2585 m_lattice
[index
].merge (call_flags
);
2587 m_lattice
[index
].add_escape_point (call
, i
,
2593 else if (gimple_assign_load_p (use_stmt
))
2595 gassign
*assign
= as_a
<gassign
*> (use_stmt
);
2596 /* Memory to memory copy. */
2597 if (gimple_store_p (assign
))
2599 /* Handle *lhs = *name.
2601 We do not track memory locations, so assume that value
2602 is used arbitrarily. */
2603 if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
2604 m_lattice
[index
].merge (deref_flags (0, false));
2605 /* Handle *name = *exp. */
2606 else if (memory_access_to (gimple_assign_lhs (assign
), name
))
2607 m_lattice
[index
].merge_direct_store ();
2609 /* Handle lhs = *name. */
2610 else if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
2612 tree lhs
= gimple_assign_lhs (assign
);
2613 merge_with_ssa_name (name
, lhs
, true);
2616 else if (gimple_store_p (use_stmt
))
2618 gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
);
2620 /* Handle *lhs = name. */
2621 if (assign
&& gimple_assign_rhs1 (assign
) == name
)
2624 fprintf (dump_file
, "%*s ssa name saved to memory\n",
2626 m_lattice
[index
].merge (0);
2628 /* Handle *name = exp. */
2630 && memory_access_to (gimple_assign_lhs (assign
), name
))
2632 /* In general we can not ignore clobbers because they are
2633 barriers for code motion, however after inlining it is safe to
2634 do because local optimization passes do not consider clobbers
2635 from other functions.
2636 Similar logic is in ipa-pure-const.cc. */
2637 if (!cfun
->after_inlining
|| !gimple_clobber_p (assign
))
2638 m_lattice
[index
].merge_direct_store ();
2640 /* ASM statements etc. */
2644 fprintf (dump_file
, "%*s Unhandled store\n", m_depth
* 4, "");
2645 m_lattice
[index
].merge (0);
2648 else if (gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
))
2650 enum tree_code code
= gimple_assign_rhs_code (assign
);
2652 /* See if operation is a merge as considered by
2653 tree-ssa-structalias.cc:find_func_aliases. */
2654 if (!truth_value_p (code
)
2655 && code
!= POINTER_DIFF_EXPR
2656 && (code
!= POINTER_PLUS_EXPR
2657 || gimple_assign_rhs1 (assign
) == name
))
2659 tree lhs
= gimple_assign_lhs (assign
);
2660 merge_with_ssa_name (name
, lhs
, false);
2663 else if (gphi
*phi
= dyn_cast
<gphi
*> (use_stmt
))
2665 tree result
= gimple_phi_result (phi
);
2666 merge_with_ssa_name (name
, result
, false);
2668 /* Conditions are not considered escape points
2669 by tree-ssa-structalias. */
2670 else if (gimple_code (use_stmt
) == GIMPLE_COND
)
2675 fprintf (dump_file
, "%*s Unhandled stmt\n", m_depth
* 4, "");
2676 m_lattice
[index
].merge (0);
2681 fprintf (dump_file
, "%*s current flags of ", m_depth
* 4, "");
2682 print_generic_expr (dump_file
, name
);
2683 m_lattice
[index
].dump (dump_file
, m_depth
* 4 + 4);
2688 fprintf (dump_file
, "%*sflags of ssa name ", m_depth
* 4, "");
2689 print_generic_expr (dump_file
, name
);
2690 m_lattice
[index
].dump (dump_file
, m_depth
* 4 + 2);
2692 m_lattice
[index
].open
= false;
2693 if (!m_lattice
[index
].do_dataflow
)
2694 m_lattice
[index
].known
= true;
2697 /* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
2701 modref_eaf_analysis::merge_with_ssa_name (tree dest
, tree src
, bool deref
)
2703 int index
= SSA_NAME_VERSION (dest
);
2704 int src_index
= SSA_NAME_VERSION (src
);
2706 /* Merging lattice with itself is a no-op. */
2707 if (!deref
&& src
== dest
)
2711 analyze_ssa_name (src
);
2714 m_lattice
[index
].merge_deref (m_lattice
[src_index
], false);
2716 m_lattice
[index
].merge (m_lattice
[src_index
]);
2718 /* If we failed to produce final solution add an edge to the dataflow
2720 if (!m_lattice
[src_index
].known
)
2722 modref_lattice::propagate_edge e
= {index
, deref
};
2724 if (!m_lattice
[src_index
].propagate_to
.length ())
2725 m_names_to_propagate
.safe_push (src_index
);
2726 m_lattice
[src_index
].propagate_to
.safe_push (e
);
2727 m_lattice
[src_index
].changed
= true;
2728 m_lattice
[src_index
].do_dataflow
= true;
2731 "%*sWill propgate from ssa_name %i to %i%s\n",
2733 "", src_index
, index
, deref
? " (deref)" : "");
2737 /* In the case we deferred some SSA names, reprocess them. In the case some
2738 dataflow edges were introduced, do the actual iterative dataflow. */
2741 modref_eaf_analysis::propagate ()
2746 bool changed
= true;
2748 while (m_deferred_names
.length ())
2750 tree name
= m_deferred_names
.pop ();
2752 fprintf (dump_file
, "Analyzing deferred SSA name\n");
2753 analyze_ssa_name (name
, true);
2756 if (!m_names_to_propagate
.length ())
2759 fprintf (dump_file
, "Propagating EAF flags\n");
2761 /* Compute reverse postorder. */
2768 auto_vec
<struct stack_entry
> stack
;
2769 int pos
= m_names_to_propagate
.length () - 1;
2771 rpo
.safe_grow (m_names_to_propagate
.length (), true);
2772 stack
.reserve_exact (m_names_to_propagate
.length ());
2774 /* We reuse known flag for RPO DFS walk bookkeeping. */
2776 FOR_EACH_VEC_ELT (m_names_to_propagate
, i
, index
)
2777 gcc_assert (!m_lattice
[index
].known
&& m_lattice
[index
].changed
);
2779 FOR_EACH_VEC_ELT (m_names_to_propagate
, i
, index
)
2781 if (!m_lattice
[index
].known
)
2783 stack_entry e
= {index
, 0};
2785 stack
.quick_push (e
);
2786 m_lattice
[index
].known
= true;
2788 while (stack
.length ())
2791 int index1
= stack
.last ().name
;
2793 while (stack
.last ().pos
< m_lattice
[index1
].propagate_to
.length ())
2795 int index2
= m_lattice
[index1
]
2796 .propagate_to
[stack
.last ().pos
].ssa_name
;
2798 stack
.last ().pos
++;
2799 if (!m_lattice
[index2
].known
2800 && m_lattice
[index2
].propagate_to
.length ())
2802 stack_entry e
= {index2
, 0};
2804 stack
.quick_push (e
);
2805 m_lattice
[index2
].known
= true;
2811 && stack
.last ().pos
== m_lattice
[index1
].propagate_to
.length ())
2813 rpo
[pos
--] = index1
;
2819 /* Perform iterative dataflow. */
2825 fprintf (dump_file
, " iteration %i\n", iterations
);
2826 FOR_EACH_VEC_ELT (rpo
, i
, index
)
2828 if (m_lattice
[index
].changed
)
2832 m_lattice
[index
].changed
= false;
2834 fprintf (dump_file
, " Visiting ssa name %i\n", index
);
2835 for (j
= 0; j
< m_lattice
[index
].propagate_to
.length (); j
++)
2838 int target
= m_lattice
[index
].propagate_to
[j
].ssa_name
;
2839 bool deref
= m_lattice
[index
].propagate_to
[j
].deref
;
2842 fprintf (dump_file
, " Propagating flags of ssa name"
2844 index
, target
, deref
? " (deref)" : "");
2845 m_lattice
[target
].known
= true;
2846 if (!m_lattice
[index
].propagate_to
[j
].deref
)
2847 ch
= m_lattice
[target
].merge (m_lattice
[index
]);
2849 ch
= m_lattice
[target
].merge_deref (m_lattice
[index
],
2855 fprintf (dump_file
, " New lattice: ");
2856 m_lattice
[target
].dump (dump_file
);
2859 m_lattice
[target
].changed
= true;
2865 fprintf (dump_file
, "EAF flags propagated in %i iterations\n", iterations
);
2868 /* Record escape points of PARM_INDEX according to LATTICE. */
2871 modref_eaf_analysis::record_escape_points (tree name
, int parm_index
, int flags
)
2873 modref_lattice
&lattice
= m_lattice
[SSA_NAME_VERSION (name
)];
2875 if (lattice
.escape_points
.length ())
2879 cgraph_node
*node
= cgraph_node::get (current_function_decl
);
2882 FOR_EACH_VEC_ELT (lattice
.escape_points
, ip
, ep
)
2883 if ((ep
->min_flags
& flags
) != flags
)
2885 cgraph_edge
*e
= node
->get_edge (ep
->call
);
2886 struct escape_entry ee
= {parm_index
, ep
->arg
,
2887 ep
->min_flags
, ep
->direct
};
2889 escape_summaries
->get_create (e
)->esc
.safe_push (ee
);
2894 /* Determine EAF flags for function parameters
2895 and fill in SUMMARY/SUMMARY_LTO. If IPA is true work in IPA mode
2896 where we also collect escape points.
2897 PAST_FLAGS, PAST_RETSLOT_FLAGS, PAST_STATIC_CHAIN_FLAGS can be
2898 used to preserve flags from previous (IPA) run for cases where
2899 late optimizations changed code in a way we can no longer analyze
2903 analyze_parms (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
2904 bool ipa
, vec
<eaf_flags_t
> &past_flags
,
2905 int past_retslot_flags
, int past_static_chain_flags
)
2907 unsigned int parm_index
= 0;
2908 unsigned int count
= 0;
2909 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
2910 tree retslot
= NULL
;
2911 tree static_chain
= NULL
;
2913 /* If there is return slot, look up its SSA name. */
2914 if (DECL_RESULT (current_function_decl
)
2915 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl
)))
2916 retslot
= ssa_default_def (cfun
, DECL_RESULT (current_function_decl
));
2917 if (cfun
->static_chain_decl
)
2918 static_chain
= ssa_default_def (cfun
, cfun
->static_chain_decl
);
2920 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
2921 parm
= TREE_CHAIN (parm
))
2924 if (!count
&& !retslot
&& !static_chain
)
2927 modref_eaf_analysis
eaf_analysis (ipa
);
2929 /* Determine all SSA names we need to know flags for. */
2930 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
2931 parm
= TREE_CHAIN (parm
))
2933 tree name
= ssa_default_def (cfun
, parm
);
2935 eaf_analysis
.analyze_ssa_name (name
);
2938 eaf_analysis
.analyze_ssa_name (retslot
);
2940 eaf_analysis
.analyze_ssa_name (static_chain
);
2942 /* Do the dataflow. */
2943 eaf_analysis
.propagate ();
2945 tree attr
= lookup_attribute ("fn spec",
2947 (TREE_TYPE (current_function_decl
)));
2948 attr_fnspec
fnspec (attr
2949 ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr
)))
2953 /* Store results to summaries. */
2954 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
; parm_index
++,
2955 parm
= TREE_CHAIN (parm
))
2957 tree name
= ssa_default_def (cfun
, parm
);
2958 if (!name
|| has_zero_uses (name
))
2960 /* We do not track non-SSA parameters,
2961 but we want to track unused gimple_regs. */
2962 if (!is_gimple_reg (parm
))
2966 if (parm_index
>= summary
->arg_flags
.length ())
2967 summary
->arg_flags
.safe_grow_cleared (count
, true);
2968 summary
->arg_flags
[parm_index
] = EAF_UNUSED
;
2970 else if (summary_lto
)
2972 if (parm_index
>= summary_lto
->arg_flags
.length ())
2973 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
2974 summary_lto
->arg_flags
[parm_index
] = EAF_UNUSED
;
2978 int flags
= eaf_analysis
.get_ssa_name_flags (name
);
2979 int attr_flags
= fnspec
.arg_eaf_flags (parm_index
);
2981 if (dump_file
&& (flags
| attr_flags
) != flags
&& !(flags
& EAF_UNUSED
))
2984 " Flags for param %i combined with fnspec flags:",
2986 dump_eaf_flags (dump_file
, attr_flags
, false);
2987 fprintf (dump_file
, " determined: ");
2988 dump_eaf_flags (dump_file
, flags
, true);
2990 flags
|= attr_flags
;
2992 /* Eliminate useless flags so we do not end up storing unnecessary
2995 flags
= remove_useless_eaf_flags
2997 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
2998 if (past_flags
.length () > parm_index
)
3000 int past
= past_flags
[parm_index
];
3001 past
= remove_useless_eaf_flags
3003 VOID_TYPE_P (TREE_TYPE
3004 (TREE_TYPE (current_function_decl
))));
3005 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
3008 " Flags for param %i combined with IPA pass:",
3010 dump_eaf_flags (dump_file
, past
, false);
3011 fprintf (dump_file
, " determined: ");
3012 dump_eaf_flags (dump_file
, flags
, true);
3014 if (!(flags
& EAF_UNUSED
))
3022 if (parm_index
>= summary
->arg_flags
.length ())
3023 summary
->arg_flags
.safe_grow_cleared (count
, true);
3024 summary
->arg_flags
[parm_index
] = flags
;
3026 else if (summary_lto
)
3028 if (parm_index
>= summary_lto
->arg_flags
.length ())
3029 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
3030 summary_lto
->arg_flags
[parm_index
] = flags
;
3032 eaf_analysis
.record_escape_points (name
, parm_index
, flags
);
3037 int flags
= eaf_analysis
.get_ssa_name_flags (retslot
);
3038 int past
= past_retslot_flags
;
3040 flags
= remove_useless_eaf_flags (flags
, ecf_flags
, false);
3041 past
= remove_useless_eaf_flags
3043 VOID_TYPE_P (TREE_TYPE
3044 (TREE_TYPE (current_function_decl
))));
3045 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
3048 " Retslot flags combined with IPA pass:");
3049 dump_eaf_flags (dump_file
, past
, false);
3050 fprintf (dump_file
, " determined: ");
3051 dump_eaf_flags (dump_file
, flags
, true);
3053 if (!(flags
& EAF_UNUSED
))
3058 summary
->retslot_flags
= flags
;
3060 summary_lto
->retslot_flags
= flags
;
3061 eaf_analysis
.record_escape_points (retslot
,
3062 MODREF_RETSLOT_PARM
, flags
);
3067 int flags
= eaf_analysis
.get_ssa_name_flags (static_chain
);
3068 int past
= past_static_chain_flags
;
3070 flags
= remove_useless_eaf_flags (flags
, ecf_flags
, false);
3071 past
= remove_useless_eaf_flags
3073 VOID_TYPE_P (TREE_TYPE
3074 (TREE_TYPE (current_function_decl
))));
3075 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
3078 " Static chain flags combined with IPA pass:");
3079 dump_eaf_flags (dump_file
, past
, false);
3080 fprintf (dump_file
, " determined: ");
3081 dump_eaf_flags (dump_file
, flags
, true);
3083 if (!(flags
& EAF_UNUSED
))
3088 summary
->static_chain_flags
= flags
;
3090 summary_lto
->static_chain_flags
= flags
;
3091 eaf_analysis
.record_escape_points (static_chain
,
3092 MODREF_STATIC_CHAIN_PARM
,
3098 /* Analyze function. IPA indicates whether we're running in local mode
3099 (false) or the IPA mode (true).
3100 Return true if fixup cfg is needed after the pass. */
3103 analyze_function (bool ipa
)
3105 bool fixup_cfg
= false;
3107 fprintf (dump_file
, "\n\nmodref analyzing '%s' (ipa=%i)%s%s\n",
3108 cgraph_node::get (current_function_decl
)->dump_name (), ipa
,
3109 TREE_READONLY (current_function_decl
) ? " (const)" : "",
3110 DECL_PURE_P (current_function_decl
) ? " (pure)" : "");
3112 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
3113 if (!flag_ipa_modref
3114 || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl
)))
3117 /* Compute no-LTO summaries when local optimization is going to happen. */
3118 bool nolto
= (!ipa
|| ((!flag_lto
|| flag_fat_lto_objects
) && !in_lto_p
)
3119 || (in_lto_p
&& !flag_wpa
3120 && flag_incremental_link
!= INCREMENTAL_LINK_LTO
));
3121 /* Compute LTO when LTO streaming is going to happen. */
3122 bool lto
= ipa
&& ((flag_lto
&& !in_lto_p
)
3124 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
3125 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
3127 modref_summary
*summary
= NULL
;
3128 modref_summary_lto
*summary_lto
= NULL
;
3130 bool past_flags_known
= false;
3131 auto_vec
<eaf_flags_t
> past_flags
;
3132 int past_retslot_flags
= 0;
3133 int past_static_chain_flags
= 0;
3135 /* Initialize the summary.
3136 If we run in local mode there is possibly pre-existing summary from
3137 IPA pass. Dump it so it is easy to compare if mod-ref info has
3141 if (!optimization_summaries
)
3142 optimization_summaries
= modref_summaries::create_ggc (symtab
);
3143 else /* Remove existing summary if we are re-running the pass. */
3145 summary
= optimization_summaries
->get (fnode
);
3151 fprintf (dump_file
, "Past summary:\n");
3152 optimization_summaries
->get (fnode
)->dump (dump_file
);
3154 past_flags
.reserve_exact (summary
->arg_flags
.length ());
3155 past_flags
.splice (summary
->arg_flags
);
3156 past_retslot_flags
= summary
->retslot_flags
;
3157 past_static_chain_flags
= summary
->static_chain_flags
;
3158 past_flags_known
= true;
3160 optimization_summaries
->remove (fnode
);
3162 summary
= optimization_summaries
->get_create (fnode
);
3163 gcc_checking_assert (nolto
&& !lto
);
3165 /* In IPA mode we analyze every function precisely once. Assert that. */
3171 summaries
= modref_summaries::create_ggc (symtab
);
3173 summaries
->remove (fnode
);
3174 summary
= summaries
->get_create (fnode
);
3179 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
3181 summaries_lto
->remove (fnode
);
3182 summary_lto
= summaries_lto
->get_create (fnode
);
3184 if (!fnspec_summaries
)
3185 fnspec_summaries
= new fnspec_summaries_t (symtab
);
3186 if (!escape_summaries
)
3187 escape_summaries
= new escape_summaries_t (symtab
);
3191 /* Create and initialize summary for F.
3192 Note that summaries may be already allocated from previous
3196 gcc_assert (!summary
->loads
);
3197 summary
->loads
= modref_records::create_ggc ();
3198 gcc_assert (!summary
->stores
);
3199 summary
->stores
= modref_records::create_ggc ();
3200 summary
->writes_errno
= false;
3201 summary
->side_effects
= false;
3202 summary
->nondeterministic
= false;
3203 summary
->calls_interposable
= false;
3207 gcc_assert (!summary_lto
->loads
);
3208 summary_lto
->loads
= modref_records_lto::create_ggc ();
3209 gcc_assert (!summary_lto
->stores
);
3210 summary_lto
->stores
= modref_records_lto::create_ggc ();
3211 summary_lto
->writes_errno
= false;
3212 summary_lto
->side_effects
= false;
3213 summary_lto
->nondeterministic
= false;
3214 summary_lto
->calls_interposable
= false;
3217 analyze_parms (summary
, summary_lto
, ipa
,
3218 past_flags
, past_retslot_flags
, past_static_chain_flags
);
3221 modref_access_analysis
analyzer (ipa
, summary
, summary_lto
);
3222 analyzer
.analyze ();
3225 if (!ipa
&& flag_ipa_pure_const
)
3227 if (!summary
->stores
->every_base
&& !summary
->stores
->bases
3228 && !summary
->nondeterministic
)
3230 if (!summary
->loads
->every_base
&& !summary
->loads
->bases
3231 && !summary
->calls_interposable
)
3232 fixup_cfg
= ipa_make_function_const (fnode
,
3233 summary
->side_effects
, true);
3235 fixup_cfg
= ipa_make_function_pure (fnode
,
3236 summary
->side_effects
, true);
3239 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
3240 if (summary
&& !summary
->useful_p (ecf_flags
))
3243 optimization_summaries
->remove (fnode
);
3245 summaries
->remove (fnode
);
3249 summary
->finalize (current_function_decl
);
3250 if (summary_lto
&& !summary_lto
->useful_p (ecf_flags
))
3252 summaries_lto
->remove (fnode
);
3256 if (ipa
&& !summary
&& !summary_lto
)
3257 remove_modref_edge_summaries (fnode
);
3261 fprintf (dump_file
, " - modref done with result: tracked.\n");
3263 summary
->dump (dump_file
);
3265 summary_lto
->dump (dump_file
);
3266 dump_modref_edge_summaries (dump_file
, fnode
, 2);
3267 /* To simplify debugging, compare IPA and local solutions. */
3268 if (past_flags_known
&& summary
)
3270 size_t len
= summary
->arg_flags
.length ();
3272 if (past_flags
.length () > len
)
3273 len
= past_flags
.length ();
3274 for (size_t i
= 0; i
< len
; i
++)
3276 int old_flags
= i
< past_flags
.length () ? past_flags
[i
] : 0;
3277 int new_flags
= i
< summary
->arg_flags
.length ()
3278 ? summary
->arg_flags
[i
] : 0;
3279 old_flags
= remove_useless_eaf_flags
3280 (old_flags
, flags_from_decl_or_type (current_function_decl
),
3281 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3282 if (old_flags
!= new_flags
)
3284 if ((old_flags
& ~new_flags
) == 0
3285 || (new_flags
& EAF_UNUSED
))
3286 fprintf (dump_file
, " Flags for param %i improved:",
3290 dump_eaf_flags (dump_file
, old_flags
, false);
3291 fprintf (dump_file
, " -> ");
3292 dump_eaf_flags (dump_file
, new_flags
, true);
3295 past_retslot_flags
= remove_useless_eaf_flags
3296 (past_retslot_flags
,
3297 flags_from_decl_or_type (current_function_decl
),
3298 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3299 if (past_retslot_flags
!= summary
->retslot_flags
)
3301 if ((past_retslot_flags
& ~summary
->retslot_flags
) == 0
3302 || (summary
->retslot_flags
& EAF_UNUSED
))
3303 fprintf (dump_file
, " Flags for retslot improved:");
3306 dump_eaf_flags (dump_file
, past_retslot_flags
, false);
3307 fprintf (dump_file
, " -> ");
3308 dump_eaf_flags (dump_file
, summary
->retslot_flags
, true);
3310 past_static_chain_flags
= remove_useless_eaf_flags
3311 (past_static_chain_flags
,
3312 flags_from_decl_or_type (current_function_decl
),
3313 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3314 if (past_static_chain_flags
!= summary
->static_chain_flags
)
3316 if ((past_static_chain_flags
& ~summary
->static_chain_flags
) == 0
3317 || (summary
->static_chain_flags
& EAF_UNUSED
))
3318 fprintf (dump_file
, " Flags for static chain improved:");
3321 dump_eaf_flags (dump_file
, past_static_chain_flags
, false);
3322 fprintf (dump_file
, " -> ");
3323 dump_eaf_flags (dump_file
, summary
->static_chain_flags
, true);
3326 else if (past_flags_known
&& !summary
)
3328 for (size_t i
= 0; i
< past_flags
.length (); i
++)
3330 int old_flags
= past_flags
[i
];
3331 old_flags
= remove_useless_eaf_flags
3332 (old_flags
, flags_from_decl_or_type (current_function_decl
),
3333 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3336 fprintf (dump_file
, " Flags for param %i worsened:",
3338 dump_eaf_flags (dump_file
, old_flags
, false);
3339 fprintf (dump_file
, " -> \n");
3342 past_retslot_flags
= remove_useless_eaf_flags
3343 (past_retslot_flags
,
3344 flags_from_decl_or_type (current_function_decl
),
3345 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3346 if (past_retslot_flags
)
3348 fprintf (dump_file
, " Flags for retslot worsened:");
3349 dump_eaf_flags (dump_file
, past_retslot_flags
, false);
3350 fprintf (dump_file
, " ->\n");
3352 past_static_chain_flags
= remove_useless_eaf_flags
3353 (past_static_chain_flags
,
3354 flags_from_decl_or_type (current_function_decl
),
3355 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3356 if (past_static_chain_flags
)
3358 fprintf (dump_file
, " Flags for static chain worsened:");
3359 dump_eaf_flags (dump_file
, past_static_chain_flags
, false);
3360 fprintf (dump_file
, " ->\n");
3367 /* Callback for generate_summary. */
3370 modref_generate (void)
3372 struct cgraph_node
*node
;
3373 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
3375 function
*f
= DECL_STRUCT_FUNCTION (node
->decl
);
3379 analyze_function (true);
3384 } /* ANON namespace. */
3386 /* Debugging helper. */
3389 debug_eaf_flags (int flags
)
3391 dump_eaf_flags (stderr
, flags
, true);
3394 /* Called when a new function is inserted to callgraph late. */
3397 modref_summaries::insert (struct cgraph_node
*node
, modref_summary
*)
3399 /* Local passes ought to be executed by the pass manager. */
3400 if (this == optimization_summaries
)
3402 optimization_summaries
->remove (node
);
3405 if (!DECL_STRUCT_FUNCTION (node
->decl
)
3406 || !opt_for_fn (node
->decl
, flag_ipa_modref
))
3408 summaries
->remove (node
);
3411 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
3412 analyze_function (true);
3416 /* Called when a new function is inserted to callgraph late. */
3419 modref_summaries_lto::insert (struct cgraph_node
*node
, modref_summary_lto
*)
3421 /* We do not support adding new function when IPA information is already
3422 propagated. This is done only by SIMD cloning that is not very
3424 if (!DECL_STRUCT_FUNCTION (node
->decl
)
3425 || !opt_for_fn (node
->decl
, flag_ipa_modref
)
3428 summaries_lto
->remove (node
);
3431 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
3432 analyze_function (true);
3436 /* Called when new clone is inserted to callgraph late. */
3439 modref_summaries::duplicate (cgraph_node
*, cgraph_node
*dst
,
3440 modref_summary
*src_data
,
3441 modref_summary
*dst_data
)
3443 /* Do not duplicate optimization summaries; we do not handle parameter
3444 transforms on them. */
3445 if (this == optimization_summaries
)
3447 optimization_summaries
->remove (dst
);
3450 dst_data
->stores
= modref_records::create_ggc ();
3451 dst_data
->stores
->copy_from (src_data
->stores
);
3452 dst_data
->loads
= modref_records::create_ggc ();
3453 dst_data
->loads
->copy_from (src_data
->loads
);
3454 dst_data
->kills
.reserve_exact (src_data
->kills
.length ());
3455 dst_data
->kills
.splice (src_data
->kills
);
3456 dst_data
->writes_errno
= src_data
->writes_errno
;
3457 dst_data
->side_effects
= src_data
->side_effects
;
3458 dst_data
->nondeterministic
= src_data
->nondeterministic
;
3459 dst_data
->calls_interposable
= src_data
->calls_interposable
;
3460 if (src_data
->arg_flags
.length ())
3461 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
3462 dst_data
->retslot_flags
= src_data
->retslot_flags
;
3463 dst_data
->static_chain_flags
= src_data
->static_chain_flags
;
3466 /* Called when new clone is inserted to callgraph late. */
3469 modref_summaries_lto::duplicate (cgraph_node
*, cgraph_node
*,
3470 modref_summary_lto
*src_data
,
3471 modref_summary_lto
*dst_data
)
3473 /* Be sure that no further cloning happens after ipa-modref. If it does
3474 we will need to update signatures for possible param changes. */
3475 gcc_checking_assert (!((modref_summaries_lto
*)summaries_lto
)->propagated
);
3476 dst_data
->stores
= modref_records_lto::create_ggc ();
3477 dst_data
->stores
->copy_from (src_data
->stores
);
3478 dst_data
->loads
= modref_records_lto::create_ggc ();
3479 dst_data
->loads
->copy_from (src_data
->loads
);
3480 dst_data
->kills
.reserve_exact (src_data
->kills
.length ());
3481 dst_data
->kills
.splice (src_data
->kills
);
3482 dst_data
->writes_errno
= src_data
->writes_errno
;
3483 dst_data
->side_effects
= src_data
->side_effects
;
3484 dst_data
->nondeterministic
= src_data
->nondeterministic
;
3485 dst_data
->calls_interposable
= src_data
->calls_interposable
;
3486 if (src_data
->arg_flags
.length ())
3487 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
3488 dst_data
->retslot_flags
= src_data
->retslot_flags
;
3489 dst_data
->static_chain_flags
= src_data
->static_chain_flags
;
3494 /* Definition of the modref pass on GIMPLE. */
3495 const pass_data pass_data_modref
= {
3500 (PROP_cfg
| PROP_ssa
),
3507 class pass_modref
: public gimple_opt_pass
3510 pass_modref (gcc::context
*ctxt
)
3511 : gimple_opt_pass (pass_data_modref
, ctxt
) {}
3513 /* opt_pass methods: */
3514 opt_pass
*clone () final override
3516 return new pass_modref (m_ctxt
);
3518 bool gate (function
*) final override
3520 return flag_ipa_modref
;
3522 unsigned int execute (function
*) final override
;
3525 /* Encode TT to the output block OB using the summary streaming API. */
3528 write_modref_records (modref_records_lto
*tt
, struct output_block
*ob
)
3530 streamer_write_uhwi (ob
, tt
->every_base
);
3531 streamer_write_uhwi (ob
, vec_safe_length (tt
->bases
));
3532 for (auto base_node
: tt
->bases
)
3534 stream_write_tree (ob
, base_node
->base
, true);
3536 streamer_write_uhwi (ob
, base_node
->every_ref
);
3537 streamer_write_uhwi (ob
, vec_safe_length (base_node
->refs
));
3539 for (auto ref_node
: base_node
->refs
)
3541 stream_write_tree (ob
, ref_node
->ref
, true);
3542 streamer_write_uhwi (ob
, ref_node
->every_access
);
3543 streamer_write_uhwi (ob
, vec_safe_length (ref_node
->accesses
));
3545 for (auto access_node
: ref_node
->accesses
)
3546 access_node
.stream_out (ob
);
3551 /* Read a modref_tree from the input block IB using the data from DATA_IN.
3552 This assumes that the tree was encoded using write_modref_tree.
3553 Either nolto_ret or lto_ret is initialized by the tree depending whether
3554 LTO streaming is expected or not. */
3557 read_modref_records (tree decl
,
3558 lto_input_block
*ib
, struct data_in
*data_in
,
3559 modref_records
**nolto_ret
,
3560 modref_records_lto
**lto_ret
)
3562 size_t max_bases
= opt_for_fn (decl
, param_modref_max_bases
);
3563 size_t max_refs
= opt_for_fn (decl
, param_modref_max_refs
);
3564 size_t max_accesses
= opt_for_fn (decl
, param_modref_max_accesses
);
3567 *lto_ret
= modref_records_lto::create_ggc ();
3569 *nolto_ret
= modref_records::create_ggc ();
3570 gcc_checking_assert (lto_ret
|| nolto_ret
);
3572 size_t every_base
= streamer_read_uhwi (ib
);
3573 size_t nbase
= streamer_read_uhwi (ib
);
3575 gcc_assert (!every_base
|| nbase
== 0);
3579 (*nolto_ret
)->collapse ();
3581 (*lto_ret
)->collapse ();
3583 for (size_t i
= 0; i
< nbase
; i
++)
3585 tree base_tree
= stream_read_tree (ib
, data_in
);
3586 modref_base_node
<alias_set_type
> *nolto_base_node
= NULL
;
3587 modref_base_node
<tree
> *lto_base_node
= NULL
;
3589 /* At stream in time we have LTO alias info. Check if we streamed in
3590 something obviously unnecessary. Do not glob types by alias sets;
3591 it is not 100% clear that ltrans types will get merged same way.
3592 Types may get refined based on ODR type conflicts. */
3593 if (base_tree
&& !get_alias_set (base_tree
))
3597 fprintf (dump_file
, "Streamed in alias set 0 type ");
3598 print_generic_expr (dump_file
, base_tree
);
3599 fprintf (dump_file
, "\n");
3605 nolto_base_node
= (*nolto_ret
)->insert_base (base_tree
3606 ? get_alias_set (base_tree
)
3609 lto_base_node
= (*lto_ret
)->insert_base (base_tree
, 0, max_bases
);
3610 size_t every_ref
= streamer_read_uhwi (ib
);
3611 size_t nref
= streamer_read_uhwi (ib
);
3613 gcc_assert (!every_ref
|| nref
== 0);
3616 if (nolto_base_node
)
3617 nolto_base_node
->collapse ();
3619 lto_base_node
->collapse ();
3621 for (size_t j
= 0; j
< nref
; j
++)
3623 tree ref_tree
= stream_read_tree (ib
, data_in
);
3625 if (ref_tree
&& !get_alias_set (ref_tree
))
3629 fprintf (dump_file
, "Streamed in alias set 0 type ");
3630 print_generic_expr (dump_file
, ref_tree
);
3631 fprintf (dump_file
, "\n");
3636 modref_ref_node
<alias_set_type
> *nolto_ref_node
= NULL
;
3637 modref_ref_node
<tree
> *lto_ref_node
= NULL
;
3639 if (nolto_base_node
)
3641 = nolto_base_node
->insert_ref (ref_tree
3642 ? get_alias_set (ref_tree
) : 0,
3645 lto_ref_node
= lto_base_node
->insert_ref (ref_tree
, max_refs
);
3647 size_t every_access
= streamer_read_uhwi (ib
);
3648 size_t naccesses
= streamer_read_uhwi (ib
);
3650 if (nolto_ref_node
&& every_access
)
3651 nolto_ref_node
->collapse ();
3652 if (lto_ref_node
&& every_access
)
3653 lto_ref_node
->collapse ();
3655 for (size_t k
= 0; k
< naccesses
; k
++)
3657 modref_access_node a
= modref_access_node::stream_in (ib
);
3659 nolto_ref_node
->insert_access (a
, max_accesses
, false);
3661 lto_ref_node
->insert_access (a
, max_accesses
, false);
3666 (*lto_ret
)->cleanup ();
3668 (*nolto_ret
)->cleanup ();
3671 /* Write ESUM to BP. */
3674 modref_write_escape_summary (struct bitpack_d
*bp
, escape_summary
*esum
)
3678 bp_pack_var_len_unsigned (bp
, 0);
3681 bp_pack_var_len_unsigned (bp
, esum
->esc
.length ());
3684 FOR_EACH_VEC_ELT (esum
->esc
, i
, ee
)
3686 bp_pack_var_len_int (bp
, ee
->parm_index
);
3687 bp_pack_var_len_unsigned (bp
, ee
->arg
);
3688 bp_pack_var_len_unsigned (bp
, ee
->min_flags
);
3689 bp_pack_value (bp
, ee
->direct
, 1);
3693 /* Read escape summary for E from BP. */
3696 modref_read_escape_summary (struct bitpack_d
*bp
, cgraph_edge
*e
)
3698 unsigned int n
= bp_unpack_var_len_unsigned (bp
);
3701 escape_summary
*esum
= escape_summaries
->get_create (e
);
3702 esum
->esc
.reserve_exact (n
);
3703 for (unsigned int i
= 0; i
< n
; i
++)
3706 ee
.parm_index
= bp_unpack_var_len_int (bp
);
3707 ee
.arg
= bp_unpack_var_len_unsigned (bp
);
3708 ee
.min_flags
= bp_unpack_var_len_unsigned (bp
);
3709 ee
.direct
= bp_unpack_value (bp
, 1);
3710 esum
->esc
.quick_push (ee
);
3714 /* Callback for write_summary. */
3719 struct output_block
*ob
= create_output_block (LTO_section_ipa_modref
);
3720 lto_symtab_encoder_t encoder
= ob
->decl_state
->symtab_node_encoder
;
3721 unsigned int count
= 0;
3726 streamer_write_uhwi (ob
, 0);
3727 streamer_write_char_stream (ob
->main_stream
, 0);
3728 produce_asm (ob
, NULL
);
3729 destroy_output_block (ob
);
3733 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
3735 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
3736 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
3737 modref_summary_lto
*r
;
3739 if (cnode
&& cnode
->definition
&& !cnode
->alias
3740 && (r
= summaries_lto
->get (cnode
))
3741 && r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
3744 streamer_write_uhwi (ob
, count
);
3746 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
3748 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
3749 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
3751 if (cnode
&& cnode
->definition
&& !cnode
->alias
)
3753 modref_summary_lto
*r
= summaries_lto
->get (cnode
);
3755 if (!r
|| !r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
3758 streamer_write_uhwi (ob
, lto_symtab_encoder_encode (encoder
, cnode
));
3760 streamer_write_uhwi (ob
, r
->arg_flags
.length ());
3761 for (unsigned int i
= 0; i
< r
->arg_flags
.length (); i
++)
3762 streamer_write_uhwi (ob
, r
->arg_flags
[i
]);
3763 streamer_write_uhwi (ob
, r
->retslot_flags
);
3764 streamer_write_uhwi (ob
, r
->static_chain_flags
);
3766 write_modref_records (r
->loads
, ob
);
3767 write_modref_records (r
->stores
, ob
);
3768 streamer_write_uhwi (ob
, r
->kills
.length ());
3769 for (auto kill
: r
->kills
)
3770 kill
.stream_out (ob
);
3772 struct bitpack_d bp
= bitpack_create (ob
->main_stream
);
3773 bp_pack_value (&bp
, r
->writes_errno
, 1);
3774 bp_pack_value (&bp
, r
->side_effects
, 1);
3775 bp_pack_value (&bp
, r
->nondeterministic
, 1);
3776 bp_pack_value (&bp
, r
->calls_interposable
, 1);
3779 for (cgraph_edge
*e
= cnode
->indirect_calls
;
3780 e
; e
= e
->next_callee
)
3782 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
3783 bp_pack_value (&bp
, sum
!= NULL
, 1);
3785 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
3786 class escape_summary
*esum
= escape_summaries
->get (e
);
3787 modref_write_escape_summary (&bp
,esum
);
3789 for (cgraph_edge
*e
= cnode
->callees
; e
; e
= e
->next_callee
)
3791 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
3792 bp_pack_value (&bp
, sum
!= NULL
, 1);
3794 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
3795 class escape_summary
*esum
= escape_summaries
->get (e
);
3796 modref_write_escape_summary (&bp
,esum
);
3799 streamer_write_bitpack (&bp
);
3802 streamer_write_char_stream (ob
->main_stream
, 0);
3803 produce_asm (ob
, NULL
);
3804 destroy_output_block (ob
);
3808 read_section (struct lto_file_decl_data
*file_data
, const char *data
,
3811 const struct lto_function_header
*header
3812 = (const struct lto_function_header
*) data
;
3813 const int cfg_offset
= sizeof (struct lto_function_header
);
3814 const int main_offset
= cfg_offset
+ header
->cfg_size
;
3815 const int string_offset
= main_offset
+ header
->main_size
;
3816 struct data_in
*data_in
;
3818 unsigned int f_count
;
3820 lto_input_block
ib ((const char *) data
+ main_offset
, header
->main_size
,
3824 = lto_data_in_create (file_data
, (const char *) data
+ string_offset
,
3825 header
->string_size
, vNULL
);
3826 f_count
= streamer_read_uhwi (&ib
);
3827 for (i
= 0; i
< f_count
; i
++)
3829 struct cgraph_node
*node
;
3830 lto_symtab_encoder_t encoder
;
3832 unsigned int index
= streamer_read_uhwi (&ib
);
3833 encoder
= file_data
->symtab_node_encoder
;
3834 node
= dyn_cast
<cgraph_node
*> (lto_symtab_encoder_deref (encoder
,
3837 modref_summary
*modref_sum
= summaries
3838 ? summaries
->get_create (node
) : NULL
;
3839 modref_summary_lto
*modref_sum_lto
= summaries_lto
3840 ? summaries_lto
->get_create (node
)
3842 if (optimization_summaries
)
3843 modref_sum
= optimization_summaries
->get_create (node
);
3847 modref_sum
->writes_errno
= false;
3848 modref_sum
->side_effects
= false;
3849 modref_sum
->nondeterministic
= false;
3850 modref_sum
->calls_interposable
= false;
3854 modref_sum_lto
->writes_errno
= false;
3855 modref_sum_lto
->side_effects
= false;
3856 modref_sum_lto
->nondeterministic
= false;
3857 modref_sum_lto
->calls_interposable
= false;
3860 gcc_assert (!modref_sum
|| (!modref_sum
->loads
3861 && !modref_sum
->stores
));
3862 gcc_assert (!modref_sum_lto
|| (!modref_sum_lto
->loads
3863 && !modref_sum_lto
->stores
));
3864 unsigned int args
= streamer_read_uhwi (&ib
);
3865 if (args
&& modref_sum
)
3866 modref_sum
->arg_flags
.reserve_exact (args
);
3867 if (args
&& modref_sum_lto
)
3868 modref_sum_lto
->arg_flags
.reserve_exact (args
);
3869 for (unsigned int i
= 0; i
< args
; i
++)
3871 eaf_flags_t flags
= streamer_read_uhwi (&ib
);
3873 modref_sum
->arg_flags
.quick_push (flags
);
3875 modref_sum_lto
->arg_flags
.quick_push (flags
);
3877 eaf_flags_t flags
= streamer_read_uhwi (&ib
);
3879 modref_sum
->retslot_flags
= flags
;
3881 modref_sum_lto
->retslot_flags
= flags
;
3883 flags
= streamer_read_uhwi (&ib
);
3885 modref_sum
->static_chain_flags
= flags
;
3887 modref_sum_lto
->static_chain_flags
= flags
;
3889 read_modref_records (node
->decl
, &ib
, data_in
,
3890 modref_sum
? &modref_sum
->loads
: NULL
,
3891 modref_sum_lto
? &modref_sum_lto
->loads
: NULL
);
3892 read_modref_records (node
->decl
, &ib
, data_in
,
3893 modref_sum
? &modref_sum
->stores
: NULL
,
3894 modref_sum_lto
? &modref_sum_lto
->stores
: NULL
);
3895 int j
= streamer_read_uhwi (&ib
);
3896 if (j
&& modref_sum
)
3897 modref_sum
->kills
.reserve_exact (j
);
3898 if (j
&& modref_sum_lto
)
3899 modref_sum_lto
->kills
.reserve_exact (j
);
3900 for (int k
= 0; k
< j
; k
++)
3902 modref_access_node a
= modref_access_node::stream_in (&ib
);
3905 modref_sum
->kills
.quick_push (a
);
3907 modref_sum_lto
->kills
.quick_push (a
);
3909 struct bitpack_d bp
= streamer_read_bitpack (&ib
);
3910 if (bp_unpack_value (&bp
, 1))
3913 modref_sum
->writes_errno
= true;
3915 modref_sum_lto
->writes_errno
= true;
3917 if (bp_unpack_value (&bp
, 1))
3920 modref_sum
->side_effects
= true;
3922 modref_sum_lto
->side_effects
= true;
3924 if (bp_unpack_value (&bp
, 1))
3927 modref_sum
->nondeterministic
= true;
3929 modref_sum_lto
->nondeterministic
= true;
3931 if (bp_unpack_value (&bp
, 1))
3934 modref_sum
->calls_interposable
= true;
3936 modref_sum_lto
->calls_interposable
= true;
3940 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
3942 if (bp_unpack_value (&bp
, 1))
3944 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
3945 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
3947 modref_read_escape_summary (&bp
, e
);
3949 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
3951 if (bp_unpack_value (&bp
, 1))
3953 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
3954 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
3956 modref_read_escape_summary (&bp
, e
);
3960 modref_sum
->finalize (node
->decl
);
3963 fprintf (dump_file
, "Read modref for %s\n",
3964 node
->dump_name ());
3966 modref_sum
->dump (dump_file
);
3968 modref_sum_lto
->dump (dump_file
);
3969 dump_modref_edge_summaries (dump_file
, node
, 4);
3973 lto_free_section_data (file_data
, LTO_section_ipa_modref
, NULL
, data
,
3975 lto_data_in_delete (data_in
);
3978 /* Callback for read_summary. */
3983 struct lto_file_decl_data
**file_data_vec
= lto_get_file_decl_data ();
3984 struct lto_file_decl_data
*file_data
;
3987 gcc_checking_assert (!optimization_summaries
&& !summaries
&& !summaries_lto
);
3989 optimization_summaries
= modref_summaries::create_ggc (symtab
);
3992 if (flag_wpa
|| flag_incremental_link
== INCREMENTAL_LINK_LTO
)
3993 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
3995 || (flag_incremental_link
== INCREMENTAL_LINK_LTO
3996 && flag_fat_lto_objects
))
3997 summaries
= modref_summaries::create_ggc (symtab
);
3998 if (!fnspec_summaries
)
3999 fnspec_summaries
= new fnspec_summaries_t (symtab
);
4000 if (!escape_summaries
)
4001 escape_summaries
= new escape_summaries_t (symtab
);
4004 while ((file_data
= file_data_vec
[j
++]))
4007 const char *data
= lto_get_summary_section_data (file_data
,
4008 LTO_section_ipa_modref
,
4011 read_section (file_data
, data
, len
);
4013 /* Fatal error here. We do not want to support compiling ltrans units
4014 with different version of compiler or different flags than the WPA
4015 unit, so this should never happen. */
4016 fatal_error (input_location
,
4017 "IPA modref summary is missing in input file");
4021 /* Recompute arg_flags for param adjustments in INFO. */
4024 remap_arg_flags (auto_vec
<eaf_flags_t
> &arg_flags
, clone_info
*info
)
4026 auto_vec
<eaf_flags_t
> old
= arg_flags
.copy ();
4029 ipa_adjusted_param
*p
;
4031 arg_flags
.release ();
4033 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
4035 int o
= info
->param_adjustments
->get_original_index (i
);
4036 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
4040 arg_flags
.safe_grow_cleared (max
+ 1, true);
4041 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
4043 int o
= info
->param_adjustments
->get_original_index (i
);
4044 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
4045 arg_flags
[i
] = old
[o
];
4049 /* Update kills according to the parm map MAP. */
4052 remap_kills (vec
<modref_access_node
> &kills
, const vec
<int> &map
)
4054 for (size_t i
= 0; i
< kills
.length ();)
4055 if (kills
[i
].parm_index
>= 0)
4057 if (kills
[i
].parm_index
< (int)map
.length ()
4058 && map
[kills
[i
].parm_index
] != MODREF_UNKNOWN_PARM
)
4060 kills
[i
].parm_index
= map
[kills
[i
].parm_index
];
4064 kills
.unordered_remove (i
);
4070 /* Return true if the V can overlap with KILL. */
4073 ipcp_argagg_and_kill_overlap_p (const ipa_argagg_value
&v
,
4074 const modref_access_node
&kill
)
4076 if (kill
.parm_index
== v
.index
)
4078 gcc_assert (kill
.parm_offset_known
);
4079 gcc_assert (known_eq (kill
.max_size
, kill
.size
));
4080 poly_int64 repl_size
;
4081 bool ok
= poly_int_tree_p (TYPE_SIZE (TREE_TYPE (v
.value
)),
4084 poly_int64
repl_offset (v
.unit_offset
);
4085 repl_offset
<<= LOG2_BITS_PER_UNIT
;
4086 poly_int64 combined_offset
4087 = (kill
.parm_offset
<< LOG2_BITS_PER_UNIT
) + kill
.offset
;
4088 if (ranges_maybe_overlap_p (repl_offset
, repl_size
,
4089 combined_offset
, kill
.size
))
4095 /* If signature changed, update the summary. */
4098 update_signature (struct cgraph_node
*node
)
4100 modref_summary
*r
= optimization_summaries
4101 ? optimization_summaries
->get (node
) : NULL
;
4102 modref_summary_lto
*r_lto
= summaries_lto
4103 ? summaries_lto
->get (node
) : NULL
;
4107 /* Propagating constants in killed memory can lead to eliminated stores in
4108 both callees (because they are considered redundant) and callers, leading
4109 to missing them altogether. */
4110 ipcp_transformation
*ipcp_ts
= ipcp_get_transformation_summary (node
);
4113 for (auto &v
: ipcp_ts
->m_agg_values
)
4118 for (const modref_access_node
&kill
: r
->kills
)
4119 if (ipcp_argagg_and_kill_overlap_p (v
, kill
))
4124 if (!v
.killed
&& r_lto
)
4125 for (const modref_access_node
&kill
: r_lto
->kills
)
4126 if (ipcp_argagg_and_kill_overlap_p (v
, kill
))
4134 clone_info
*info
= clone_info::get (node
);
4135 if (!info
|| !info
->param_adjustments
)
4140 fprintf (dump_file
, "Updating summary for %s from:\n",
4141 node
->dump_name ());
4143 r
->dump (dump_file
);
4145 r_lto
->dump (dump_file
);
4149 ipa_adjusted_param
*p
;
4151 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
4153 int idx
= info
->param_adjustments
->get_original_index (i
);
4158 auto_vec
<int, 32> map
;
4160 map
.reserve (max
+ 1);
4161 for (i
= 0; i
<= max
; i
++)
4162 map
.quick_push (MODREF_UNKNOWN_PARM
);
4163 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
4165 int idx
= info
->param_adjustments
->get_original_index (i
);
4171 r
->loads
->remap_params (&map
);
4172 r
->stores
->remap_params (&map
);
4173 remap_kills (r
->kills
, map
);
4174 if (r
->arg_flags
.length ())
4175 remap_arg_flags (r
->arg_flags
, info
);
4179 r_lto
->loads
->remap_params (&map
);
4180 r_lto
->stores
->remap_params (&map
);
4181 remap_kills (r_lto
->kills
, map
);
4182 if (r_lto
->arg_flags
.length ())
4183 remap_arg_flags (r_lto
->arg_flags
, info
);
4187 fprintf (dump_file
, "to:\n");
4189 r
->dump (dump_file
);
4191 r_lto
->dump (dump_file
);
4194 r
->finalize (node
->decl
);
4198 /* Definition of the modref IPA pass. */
4199 const pass_data pass_data_ipa_modref
=
4201 IPA_PASS
, /* type */
4202 "modref", /* name */
4203 OPTGROUP_IPA
, /* optinfo_flags */
4204 TV_IPA_MODREF
, /* tv_id */
4205 0, /* properties_required */
4206 0, /* properties_provided */
4207 0, /* properties_destroyed */
4208 0, /* todo_flags_start */
4209 ( TODO_dump_symtab
), /* todo_flags_finish */
4212 class pass_ipa_modref
: public ipa_opt_pass_d
4215 pass_ipa_modref (gcc::context
*ctxt
)
4216 : ipa_opt_pass_d (pass_data_ipa_modref
, ctxt
,
4217 modref_generate
, /* generate_summary */
4218 modref_write
, /* write_summary */
4219 modref_read
, /* read_summary */
4220 modref_write
, /* write_optimization_summary */
4221 modref_read
, /* read_optimization_summary */
4222 NULL
, /* stmt_fixup */
4223 0, /* function_transform_todo_flags_start */
4224 NULL
, /* function_transform */
4225 NULL
) /* variable_transform */
4228 /* opt_pass methods: */
4229 opt_pass
*clone () final override
{ return new pass_ipa_modref (m_ctxt
); }
4230 bool gate (function
*) final override
4234 unsigned int execute (function
*) final override
;
4240 unsigned int pass_modref::execute (function
*)
4242 if (analyze_function (false))
4243 return execute_fixup_cfg ();
4248 make_pass_modref (gcc::context
*ctxt
)
4250 return new pass_modref (ctxt
);
4254 make_pass_ipa_modref (gcc::context
*ctxt
)
4256 return new pass_ipa_modref (ctxt
);
4261 /* Skip edges from and to nodes without ipa_pure_const enabled.
4262 Ignore not available symbols. */
4265 ignore_edge (struct cgraph_edge
*e
)
4267 /* We merge summaries of inline clones into summaries of functions they
4268 are inlined to. For that reason the complete function bodies must
4270 if (!e
->inline_failed
)
4272 enum availability avail
;
4273 cgraph_node
*callee
= e
->callee
->ultimate_alias_target
4274 (&avail
, e
->caller
);
4276 return (avail
<= AVAIL_INTERPOSABLE
4277 || ((!optimization_summaries
|| !optimization_summaries
->get (callee
))
4278 && (!summaries_lto
|| !summaries_lto
->get (callee
))));
4281 /* Compute parm_map for CALLEE_EDGE. */
4284 compute_parm_map (cgraph_edge
*callee_edge
, vec
<modref_parm_map
> *parm_map
)
4286 class ipa_edge_args
*args
;
4287 if (ipa_node_params_sum
4288 && !callee_edge
->call_stmt_cannot_inline_p
4289 && (args
= ipa_edge_args_sum
->get (callee_edge
)) != NULL
)
4291 int i
, count
= ipa_get_cs_argument_count (args
);
4292 class ipa_node_params
*caller_parms_info
, *callee_pi
;
4293 class ipa_call_summary
*es
4294 = ipa_call_summaries
->get (callee_edge
);
4296 = callee_edge
->callee
->ultimate_alias_target
4297 (NULL
, callee_edge
->caller
);
4300 = ipa_node_params_sum
->get (callee_edge
->caller
->inlined_to
4301 ? callee_edge
->caller
->inlined_to
4302 : callee_edge
->caller
);
4303 callee_pi
= ipa_node_params_sum
->get (callee
);
4305 (*parm_map
).safe_grow_cleared (count
, true);
4307 for (i
= 0; i
< count
; i
++)
4309 if (es
&& es
->param
[i
].points_to_local_or_readonly_memory
)
4311 (*parm_map
)[i
].parm_index
= MODREF_LOCAL_MEMORY_PARM
;
4315 struct ipa_jump_func
*jf
4316 = ipa_get_ith_jump_func (args
, i
);
4317 if (jf
&& callee_pi
)
4319 tree cst
= ipa_value_from_jfunc (caller_parms_info
,
4323 if (cst
&& points_to_local_or_readonly_memory_p (cst
))
4325 (*parm_map
)[i
].parm_index
= MODREF_LOCAL_MEMORY_PARM
;
4329 if (jf
&& jf
->type
== IPA_JF_PASS_THROUGH
)
4331 (*parm_map
)[i
].parm_index
4332 = ipa_get_jf_pass_through_formal_id (jf
);
4333 if (ipa_get_jf_pass_through_operation (jf
) == NOP_EXPR
)
4335 (*parm_map
)[i
].parm_offset_known
= true;
4336 (*parm_map
)[i
].parm_offset
= 0;
4338 else if (ipa_get_jf_pass_through_operation (jf
)
4339 == POINTER_PLUS_EXPR
4340 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf
),
4341 &(*parm_map
)[i
].parm_offset
))
4342 (*parm_map
)[i
].parm_offset_known
= true;
4344 (*parm_map
)[i
].parm_offset_known
= false;
4347 if (jf
&& jf
->type
== IPA_JF_ANCESTOR
)
4349 (*parm_map
)[i
].parm_index
= ipa_get_jf_ancestor_formal_id (jf
);
4350 (*parm_map
)[i
].parm_offset_known
= true;
4352 (!(ipa_get_jf_ancestor_offset (jf
) & (BITS_PER_UNIT
- 1)));
4353 (*parm_map
)[i
].parm_offset
4354 = ipa_get_jf_ancestor_offset (jf
) >> LOG2_BITS_PER_UNIT
;
4357 (*parm_map
)[i
].parm_index
= -1;
4361 fprintf (dump_file
, " Parm map: ");
4362 for (i
= 0; i
< count
; i
++)
4363 fprintf (dump_file
, " %i", (*parm_map
)[i
].parm_index
);
4364 fprintf (dump_file
, "\n");
4371 /* Map used to translate escape infos. */
4379 /* Update escape map for E. */
4382 update_escape_summary_1 (cgraph_edge
*e
,
4383 vec
<vec
<escape_map
>> &map
,
4386 escape_summary
*sum
= escape_summaries
->get (e
);
4389 auto_vec
<escape_entry
> old
= sum
->esc
.copy ();
4390 sum
->esc
.release ();
4394 FOR_EACH_VEC_ELT (old
, i
, ee
)
4397 struct escape_map
*em
;
4398 /* TODO: We do not have jump functions for return slots, so we
4399 never propagate them to outer function. */
4400 if (ee
->parm_index
>= (int)map
.length ()
4401 || ee
->parm_index
< 0)
4403 FOR_EACH_VEC_ELT (map
[ee
->parm_index
], j
, em
)
4405 int min_flags
= ee
->min_flags
;
4406 if (ee
->direct
&& !em
->direct
)
4407 min_flags
= deref_flags (min_flags
, ignore_stores
);
4408 struct escape_entry entry
= {em
->parm_index
, ee
->arg
,
4410 ee
->direct
& em
->direct
};
4411 sum
->esc
.safe_push (entry
);
4414 if (!sum
->esc
.length ())
4415 escape_summaries
->remove (e
);
4418 /* Update escape map for NODE. */
4421 update_escape_summary (cgraph_node
*node
,
4422 vec
<vec
<escape_map
>> &map
,
4425 if (!escape_summaries
)
4427 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
4428 update_escape_summary_1 (e
, map
, ignore_stores
);
4429 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
4431 if (!e
->inline_failed
)
4432 update_escape_summary (e
->callee
, map
, ignore_stores
);
4434 update_escape_summary_1 (e
, map
, ignore_stores
);
4438 /* Get parameter type from DECL. This is only safe for special cases
4439 like builtins we create fnspec for because the type match is checked
4440 at fnspec creation time. */
4443 get_parm_type (tree decl
, unsigned int i
)
4445 tree t
= TYPE_ARG_TYPES (TREE_TYPE (decl
));
4447 for (unsigned int p
= 0; p
< i
; p
++)
4449 return TREE_VALUE (t
);
4452 /* Return access mode for argument I of call E with FNSPEC. */
4454 static modref_access_node
4455 get_access_for_fnspec (cgraph_edge
*e
, attr_fnspec
&fnspec
,
4456 unsigned int i
, modref_parm_map
&map
)
4458 tree size
= NULL_TREE
;
4459 unsigned int size_arg
;
4461 if (!fnspec
.arg_specified_p (i
))
4463 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
4465 cgraph_node
*node
= e
->caller
->inlined_to
4466 ? e
->caller
->inlined_to
: e
->caller
;
4467 ipa_node_params
*caller_parms_info
= ipa_node_params_sum
->get (node
);
4468 ipa_edge_args
*args
= ipa_edge_args_sum
->get (e
);
4469 struct ipa_jump_func
*jf
= ipa_get_ith_jump_func (args
, size_arg
);
4472 size
= ipa_value_from_jfunc (caller_parms_info
, jf
,
4473 get_parm_type (e
->callee
->decl
, size_arg
));
4475 else if (fnspec
.arg_access_size_given_by_type_p (i
))
4476 size
= TYPE_SIZE_UNIT (get_parm_type (e
->callee
->decl
, i
));
4477 modref_access_node a
= {0, -1, -1,
4478 map
.parm_offset
, map
.parm_index
,
4479 map
.parm_offset_known
, 0};
4480 poly_int64 size_hwi
;
4482 && poly_int_tree_p (size
, &size_hwi
)
4483 && coeffs_in_range_p (size_hwi
, 0,
4484 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
4487 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
4492 /* Collapse loads and return true if something changed. */
4494 collapse_loads (modref_summary
*cur_summary
,
4495 modref_summary_lto
*cur_summary_lto
)
4497 bool changed
= false;
4499 if (cur_summary
&& !cur_summary
->loads
->every_base
)
4501 cur_summary
->loads
->collapse ();
4505 && !cur_summary_lto
->loads
->every_base
)
4507 cur_summary_lto
->loads
->collapse ();
4513 /* Collapse loads and return true if something changed. */
4516 collapse_stores (modref_summary
*cur_summary
,
4517 modref_summary_lto
*cur_summary_lto
)
4519 bool changed
= false;
4521 if (cur_summary
&& !cur_summary
->stores
->every_base
)
4523 cur_summary
->stores
->collapse ();
4527 && !cur_summary_lto
->stores
->every_base
)
4529 cur_summary_lto
->stores
->collapse ();
4535 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
4536 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
4539 propagate_unknown_call (cgraph_node
*node
,
4540 cgraph_edge
*e
, int ecf_flags
,
4541 modref_summary
*cur_summary
,
4542 modref_summary_lto
*cur_summary_lto
,
4543 bool nontrivial_scc
)
4545 bool changed
= false;
4546 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
4547 auto_vec
<modref_parm_map
, 32> parm_map
;
4551 && builtin_safe_for_const_function_p (&looping
, e
->callee
->decl
))
4553 if (looping
&& cur_summary
&& !cur_summary
->side_effects
)
4555 cur_summary
->side_effects
= true;
4558 if (looping
&& cur_summary_lto
&& !cur_summary_lto
->side_effects
)
4560 cur_summary_lto
->side_effects
= true;
4566 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
| ECF_PURE
))
4567 || (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
)
4570 if (cur_summary
&& !cur_summary
->side_effects
)
4572 cur_summary
->side_effects
= true;
4575 if (cur_summary_lto
&& !cur_summary_lto
->side_effects
)
4577 cur_summary_lto
->side_effects
= true;
4580 if (cur_summary
&& !cur_summary
->nondeterministic
4581 && !ignore_nondeterminism_p (node
->decl
, ecf_flags
))
4583 cur_summary
->nondeterministic
= true;
4586 if (cur_summary_lto
&& !cur_summary_lto
->nondeterministic
4587 && !ignore_nondeterminism_p (node
->decl
, ecf_flags
))
4589 cur_summary_lto
->nondeterministic
= true;
4593 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
4597 && compute_parm_map (e
, &parm_map
))
4599 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
4601 gcc_checking_assert (fnspec
.known_p ());
4602 if (fnspec
.global_memory_read_p ())
4603 collapse_loads (cur_summary
, cur_summary_lto
);
4606 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
4607 for (unsigned i
= 0; i
< parm_map
.length () && t
;
4608 i
++, t
= TREE_CHAIN (t
))
4609 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
4611 else if (!fnspec
.arg_specified_p (i
)
4612 || fnspec
.arg_maybe_read_p (i
))
4614 modref_parm_map map
= parm_map
[i
];
4615 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
4617 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
4619 collapse_loads (cur_summary
, cur_summary_lto
);
4623 changed
|= cur_summary
->loads
->insert
4625 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4626 if (cur_summary_lto
)
4627 changed
|= cur_summary_lto
->loads
->insert
4629 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4632 if (ignore_stores_p (node
->decl
, ecf_flags
))
4634 else if (fnspec
.global_memory_written_p ())
4635 collapse_stores (cur_summary
, cur_summary_lto
);
4638 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
4639 for (unsigned i
= 0; i
< parm_map
.length () && t
;
4640 i
++, t
= TREE_CHAIN (t
))
4641 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
4643 else if (!fnspec
.arg_specified_p (i
)
4644 || fnspec
.arg_maybe_written_p (i
))
4646 modref_parm_map map
= parm_map
[i
];
4647 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
4649 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
4651 collapse_stores (cur_summary
, cur_summary_lto
);
4655 changed
|= cur_summary
->stores
->insert
4657 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4658 if (cur_summary_lto
)
4659 changed
|= cur_summary_lto
->stores
->insert
4661 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4664 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
4666 if (cur_summary
&& !cur_summary
->writes_errno
)
4668 cur_summary
->writes_errno
= true;
4671 if (cur_summary_lto
&& !cur_summary_lto
->writes_errno
)
4673 cur_summary_lto
->writes_errno
= true;
4680 fprintf (dump_file
, " collapsing loads\n");
4681 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
4682 if (!ignore_stores_p (node
->decl
, ecf_flags
))
4685 fprintf (dump_file
, " collapsing stores\n");
4686 changed
|= collapse_stores (cur_summary
, cur_summary_lto
);
4691 /* Maybe remove summaries of NODE pointed to by CUR_SUMMARY_PTR
4692 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
4695 remove_useless_summaries (cgraph_node
*node
,
4696 modref_summary
**cur_summary_ptr
,
4697 modref_summary_lto
**cur_summary_lto_ptr
,
4700 if (*cur_summary_ptr
&& !(*cur_summary_ptr
)->useful_p (ecf_flags
, false))
4702 optimization_summaries
->remove (node
);
4703 *cur_summary_ptr
= NULL
;
4705 if (*cur_summary_lto_ptr
4706 && !(*cur_summary_lto_ptr
)->useful_p (ecf_flags
, false))
4708 summaries_lto
->remove (node
);
4709 *cur_summary_lto_ptr
= NULL
;
4713 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4714 and propagate loads/stores. */
4717 modref_propagate_in_scc (cgraph_node
*component_node
)
4719 bool changed
= true;
4726 = ((struct ipa_dfs_info
*) component_node
->aux
)->next_cycle
;
4728 for (struct cgraph_node
*cur
= component_node
; cur
;
4729 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4731 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
4732 modref_summary
*cur_summary
= optimization_summaries
4733 ? optimization_summaries
->get (node
)
4735 modref_summary_lto
*cur_summary_lto
= summaries_lto
4736 ? summaries_lto
->get (node
)
4739 if (!cur_summary
&& !cur_summary_lto
)
4742 int cur_ecf_flags
= flags_from_decl_or_type (node
->decl
);
4745 fprintf (dump_file
, " Processing %s%s%s\n",
4747 TREE_READONLY (cur
->decl
) ? " (const)" : "",
4748 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
4750 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
4753 fprintf (dump_file
, " Indirect call\n");
4754 if (propagate_unknown_call
4755 (node
, e
, e
->indirect_info
->ecf_flags
,
4756 cur_summary
, cur_summary_lto
,
4760 remove_useless_summaries (node
, &cur_summary
,
4763 if (!cur_summary
&& !cur_summary_lto
)
4768 if (!cur_summary
&& !cur_summary_lto
)
4771 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
4772 callee_edge
= callee_edge
->next_callee
)
4774 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
4775 modref_summary
*callee_summary
= NULL
;
4776 modref_summary_lto
*callee_summary_lto
= NULL
;
4777 struct cgraph_node
*callee
;
4779 if (!callee_edge
->inline_failed
4780 || ((flags
& (ECF_CONST
| ECF_NOVOPS
))
4781 && !(flags
& ECF_LOOPING_CONST_OR_PURE
)))
4784 /* Get the callee and its summary. */
4785 enum availability avail
;
4786 callee
= callee_edge
->callee
->ultimate_alias_target
4789 /* It is not necessary to re-process calls outside of the
4793 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
4794 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
4798 fprintf (dump_file
, " Call to %s\n",
4799 callee_edge
->callee
->dump_name ());
4801 bool ignore_stores
= ignore_stores_p (cur
->decl
, flags
);
4803 if (avail
<= AVAIL_INTERPOSABLE
)
4806 fprintf (dump_file
, " Call target interposable"
4807 " or not available\n");
4808 changed
|= propagate_unknown_call
4809 (node
, callee_edge
, flags
,
4810 cur_summary
, cur_summary_lto
,
4812 if (!cur_summary
&& !cur_summary_lto
)
4817 /* We don't know anything about CALLEE, hence we cannot tell
4818 anything about the entire component. */
4821 && !(callee_summary
= optimization_summaries
->get (callee
)))
4824 fprintf (dump_file
, " No call target summary\n");
4825 changed
|= propagate_unknown_call
4826 (node
, callee_edge
, flags
,
4831 && !(callee_summary_lto
= summaries_lto
->get (callee
)))
4834 fprintf (dump_file
, " No call target summary\n");
4835 changed
|= propagate_unknown_call
4836 (node
, callee_edge
, flags
,
4837 NULL
, cur_summary_lto
,
4841 if (callee_summary
&& !cur_summary
->side_effects
4842 && (callee_summary
->side_effects
4843 || callee_edge
->recursive_p ()))
4845 cur_summary
->side_effects
= true;
4848 if (callee_summary_lto
&& !cur_summary_lto
->side_effects
4849 && (callee_summary_lto
->side_effects
4850 || callee_edge
->recursive_p ()))
4852 cur_summary_lto
->side_effects
= true;
4855 if (callee_summary
&& !cur_summary
->nondeterministic
4856 && callee_summary
->nondeterministic
4857 && !ignore_nondeterminism_p (cur
->decl
, flags
))
4859 cur_summary
->nondeterministic
= true;
4862 if (callee_summary_lto
&& !cur_summary_lto
->nondeterministic
4863 && callee_summary_lto
->nondeterministic
4864 && !ignore_nondeterminism_p (cur
->decl
, flags
))
4866 cur_summary_lto
->nondeterministic
= true;
4869 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
4872 /* We can not safely optimize based on summary of callee if it
4873 does not always bind to current def: it is possible that
4874 memory load was optimized out earlier which may not happen in
4875 the interposed variant. */
4876 if (!callee_edge
->binds_to_current_def_p ())
4878 if (cur_summary
&& !cur_summary
->calls_interposable
)
4880 cur_summary
->calls_interposable
= true;
4883 if (cur_summary_lto
&& !cur_summary_lto
->calls_interposable
)
4885 cur_summary_lto
->calls_interposable
= true;
4889 fprintf (dump_file
, " May not bind local;"
4890 " collapsing loads\n");
4894 auto_vec
<modref_parm_map
, 32> parm_map
;
4895 modref_parm_map chain_map
;
4896 /* TODO: Once we get jump functions for static chains we could
4898 chain_map
.parm_index
= MODREF_UNKNOWN_PARM
;
4900 compute_parm_map (callee_edge
, &parm_map
);
4902 /* Merge in callee's information. */
4905 changed
|= cur_summary
->loads
->merge
4906 (node
->decl
, callee_summary
->loads
,
4907 &parm_map
, &chain_map
, !first
);
4910 changed
|= cur_summary
->stores
->merge
4911 (node
->decl
, callee_summary
->stores
,
4912 &parm_map
, &chain_map
, !first
);
4913 if (!cur_summary
->writes_errno
4914 && callee_summary
->writes_errno
)
4916 cur_summary
->writes_errno
= true;
4921 if (callee_summary_lto
)
4923 changed
|= cur_summary_lto
->loads
->merge
4924 (node
->decl
, callee_summary_lto
->loads
,
4925 &parm_map
, &chain_map
, !first
);
4928 changed
|= cur_summary_lto
->stores
->merge
4929 (node
->decl
, callee_summary_lto
->stores
,
4930 &parm_map
, &chain_map
, !first
);
4931 if (!cur_summary_lto
->writes_errno
4932 && callee_summary_lto
->writes_errno
)
4934 cur_summary_lto
->writes_errno
= true;
4940 remove_useless_summaries (node
, &cur_summary
,
4943 if (!cur_summary
&& !cur_summary_lto
)
4945 if (dump_file
&& changed
)
4948 cur_summary
->dump (dump_file
);
4949 if (cur_summary_lto
)
4950 cur_summary_lto
->dump (dump_file
);
4951 dump_modref_edge_summaries (dump_file
, node
, 4);
4960 "Propagation finished in %i iterations\n", iteration
);
4961 bool pureconst
= false;
4962 for (struct cgraph_node
*cur
= component_node
; cur
;
4963 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4964 if (!cur
->inlined_to
&& opt_for_fn (cur
->decl
, flag_ipa_pure_const
))
4966 modref_summary
*summary
= optimization_summaries
4967 ? optimization_summaries
->get (cur
)
4969 modref_summary_lto
*summary_lto
= summaries_lto
4970 ? summaries_lto
->get (cur
)
4972 if (summary
&& !summary
->stores
->every_base
&& !summary
->stores
->bases
4973 && !summary
->nondeterministic
)
4975 if (!summary
->loads
->every_base
&& !summary
->loads
->bases
4976 && !summary
->calls_interposable
)
4977 pureconst
|= ipa_make_function_const
4978 (cur
, summary
->side_effects
, false);
4980 pureconst
|= ipa_make_function_pure
4981 (cur
, summary
->side_effects
, false);
4983 if (summary_lto
&& !summary_lto
->stores
->every_base
4984 && !summary_lto
->stores
->bases
&& !summary_lto
->nondeterministic
)
4986 if (!summary_lto
->loads
->every_base
&& !summary_lto
->loads
->bases
4987 && !summary_lto
->calls_interposable
)
4988 pureconst
|= ipa_make_function_const
4989 (cur
, summary_lto
->side_effects
, false);
4991 pureconst
|= ipa_make_function_pure
4992 (cur
, summary_lto
->side_effects
, false);
4998 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
5001 modref_propagate_dump_scc (cgraph_node
*component_node
)
5003 for (struct cgraph_node
*cur
= component_node
; cur
;
5004 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
5005 if (!cur
->inlined_to
)
5007 modref_summary
*cur_summary
= optimization_summaries
5008 ? optimization_summaries
->get (cur
)
5010 modref_summary_lto
*cur_summary_lto
= summaries_lto
5011 ? summaries_lto
->get (cur
)
5014 fprintf (dump_file
, "Propagated modref for %s%s%s\n",
5016 TREE_READONLY (cur
->decl
) ? " (const)" : "",
5017 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
5018 if (optimization_summaries
)
5021 cur_summary
->dump (dump_file
);
5023 fprintf (dump_file
, " Not tracked\n");
5027 if (cur_summary_lto
)
5028 cur_summary_lto
->dump (dump_file
);
5030 fprintf (dump_file
, " Not tracked (lto)\n");
5035 /* Determine EAF flags know for call E with CALLEE_ECF_FLAGS and ARG. */
5038 implicit_eaf_flags_for_edge_and_arg (cgraph_edge
*e
, int callee_ecf_flags
,
5039 bool ignore_stores
, int arg
)
5041 /* Returning the value is already accounted to at local propagation. */
5042 int implicit_flags
= EAF_NOT_RETURNED_DIRECTLY
5043 | EAF_NOT_RETURNED_INDIRECTLY
;
5045 implicit_flags
|= ignore_stores_eaf_flags
;
5046 if (callee_ecf_flags
& ECF_PURE
)
5047 implicit_flags
|= implicit_pure_eaf_flags
;
5048 if (callee_ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
5049 implicit_flags
|= implicit_const_eaf_flags
;
5050 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
5053 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
5054 implicit_flags
|= fnspec
.arg_eaf_flags (arg
);
5056 return implicit_flags
;
5059 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
5060 and SUMMARY_LTO to CUR_SUMMARY_LTO.
5061 Return true if something changed. */
5064 modref_merge_call_site_flags (escape_summary
*sum
,
5065 modref_summary
*cur_summary
,
5066 modref_summary_lto
*cur_summary_lto
,
5067 modref_summary
*summary
,
5068 modref_summary_lto
*summary_lto
,
5071 int caller_ecf_flags
,
5072 int callee_ecf_flags
,
5073 bool binds_to_current_def
)
5077 bool changed
= false;
5078 bool ignore_stores
= ignore_stores_p (caller
, callee_ecf_flags
);
5080 /* Return early if we have no useful info to propagate. */
5082 || (!cur_summary
->arg_flags
.length ()
5083 && !cur_summary
->static_chain_flags
5084 && !cur_summary
->retslot_flags
))
5085 && (!cur_summary_lto
5086 || (!cur_summary_lto
->arg_flags
.length ()
5087 && !cur_summary_lto
->static_chain_flags
5088 && !cur_summary_lto
->retslot_flags
)))
5091 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
5095 int implicit_flags
= implicit_eaf_flags_for_edge_and_arg
5096 (e
, callee_ecf_flags
, ignore_stores
, ee
->arg
);
5098 if (summary
&& ee
->arg
< summary
->arg_flags
.length ())
5099 flags
= summary
->arg_flags
[ee
->arg
];
5101 && ee
->arg
< summary_lto
->arg_flags
.length ())
5102 flags_lto
= summary_lto
->arg_flags
[ee
->arg
];
5105 flags
= deref_flags (flags
, ignore_stores
);
5106 flags_lto
= deref_flags (flags_lto
, ignore_stores
);
5109 implicit_flags
|= ignore_stores_eaf_flags
;
5110 if (callee_ecf_flags
& ECF_PURE
)
5111 implicit_flags
|= implicit_pure_eaf_flags
;
5112 if (callee_ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
5113 implicit_flags
|= implicit_const_eaf_flags
;
5114 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
5117 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
5118 implicit_flags
|= fnspec
.arg_eaf_flags (ee
->arg
);
5121 implicit_flags
= deref_flags (implicit_flags
, ignore_stores
);
5122 flags
|= implicit_flags
;
5123 flags_lto
|= implicit_flags
;
5124 if (!binds_to_current_def
&& (flags
|| flags_lto
))
5126 flags
= interposable_eaf_flags (flags
, implicit_flags
);
5127 flags_lto
= interposable_eaf_flags (flags_lto
, implicit_flags
);
5129 if (!(flags
& EAF_UNUSED
)
5130 && cur_summary
&& ee
->parm_index
< (int)cur_summary
->arg_flags
.length ())
5132 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
5133 ? cur_summary
->retslot_flags
5134 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
5135 ? cur_summary
->static_chain_flags
5136 : cur_summary
->arg_flags
[ee
->parm_index
];
5137 if ((f
& flags
) != f
)
5139 f
= remove_useless_eaf_flags
5140 (f
& flags
, caller_ecf_flags
,
5141 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
5145 if (!(flags_lto
& EAF_UNUSED
)
5147 && ee
->parm_index
< (int)cur_summary_lto
->arg_flags
.length ())
5149 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
5150 ? cur_summary_lto
->retslot_flags
5151 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
5152 ? cur_summary_lto
->static_chain_flags
5153 : cur_summary_lto
->arg_flags
[ee
->parm_index
];
5154 if ((f
& flags_lto
) != f
)
5156 f
= remove_useless_eaf_flags
5157 (f
& flags_lto
, caller_ecf_flags
,
5158 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
5166 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
5167 and propagate arg flags. */
5170 modref_propagate_flags_in_scc (cgraph_node
*component_node
)
5172 bool changed
= true;
5178 for (struct cgraph_node
*cur
= component_node
; cur
;
5179 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
5181 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
5182 modref_summary
*cur_summary
= optimization_summaries
5183 ? optimization_summaries
->get (node
)
5185 modref_summary_lto
*cur_summary_lto
= summaries_lto
5186 ? summaries_lto
->get (node
)
5189 if (!cur_summary
&& !cur_summary_lto
)
5191 int caller_ecf_flags
= flags_from_decl_or_type (cur
->decl
);
5194 fprintf (dump_file
, " Processing %s%s%s\n",
5196 TREE_READONLY (cur
->decl
) ? " (const)" : "",
5197 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
5199 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
5201 escape_summary
*sum
= escape_summaries
->get (e
);
5203 if (!sum
|| (e
->indirect_info
->ecf_flags
5204 & (ECF_CONST
| ECF_NOVOPS
)))
5207 changed
|= modref_merge_call_site_flags
5208 (sum
, cur_summary
, cur_summary_lto
,
5213 e
->indirect_info
->ecf_flags
,
5217 if (!cur_summary
&& !cur_summary_lto
)
5220 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
5221 callee_edge
= callee_edge
->next_callee
)
5223 int ecf_flags
= flags_from_decl_or_type
5224 (callee_edge
->callee
->decl
);
5225 modref_summary
*callee_summary
= NULL
;
5226 modref_summary_lto
*callee_summary_lto
= NULL
;
5227 struct cgraph_node
*callee
;
5229 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)
5230 || !callee_edge
->inline_failed
)
5233 /* Get the callee and its summary. */
5234 enum availability avail
;
5235 callee
= callee_edge
->callee
->ultimate_alias_target
5238 /* It is not necessary to re-process calls outside of the
5242 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
5243 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
5246 escape_summary
*sum
= escape_summaries
->get (callee_edge
);
5251 fprintf (dump_file
, " Call to %s\n",
5252 callee_edge
->callee
->dump_name ());
5254 if (avail
<= AVAIL_INTERPOSABLE
5255 || callee_edge
->call_stmt_cannot_inline_p
)
5260 callee_summary
= optimization_summaries
->get (callee
);
5261 if (cur_summary_lto
)
5262 callee_summary_lto
= summaries_lto
->get (callee
);
5264 changed
|= modref_merge_call_site_flags
5265 (sum
, cur_summary
, cur_summary_lto
,
5266 callee_summary
, callee_summary_lto
,
5271 callee
->binds_to_current_def_p ());
5272 if (dump_file
&& changed
)
5275 cur_summary
->dump (dump_file
);
5276 if (cur_summary_lto
)
5277 cur_summary_lto
->dump (dump_file
);
5285 "Propagation of flags finished in %i iterations\n", iteration
);
5288 } /* ANON namespace. */
5290 /* Call EDGE was inlined; merge summary from callee to the caller. */
5293 ipa_merge_modref_summary_after_inlining (cgraph_edge
*edge
)
5295 if (!summaries
&& !summaries_lto
)
5298 struct cgraph_node
*to
= (edge
->caller
->inlined_to
5299 ? edge
->caller
->inlined_to
: edge
->caller
);
5300 class modref_summary
*to_info
= summaries
? summaries
->get (to
) : NULL
;
5301 class modref_summary_lto
*to_info_lto
= summaries_lto
5302 ? summaries_lto
->get (to
) : NULL
;
5304 if (!to_info
&& !to_info_lto
)
5307 summaries
->remove (edge
->callee
);
5309 summaries_lto
->remove (edge
->callee
);
5310 remove_modref_edge_summaries (edge
->callee
);
5314 class modref_summary
*callee_info
= summaries
? summaries
->get (edge
->callee
)
5316 class modref_summary_lto
*callee_info_lto
5317 = summaries_lto
? summaries_lto
->get (edge
->callee
) : NULL
;
5318 int flags
= flags_from_decl_or_type (edge
->callee
->decl
);
5319 /* Combine in outer flags. */
5321 for (n
= edge
->caller
; n
->inlined_to
; n
= n
->callers
->caller
)
5322 flags
|= flags_from_decl_or_type (n
->decl
);
5323 flags
|= flags_from_decl_or_type (n
->decl
);
5324 bool ignore_stores
= ignore_stores_p (edge
->caller
->decl
, flags
);
5326 if (!callee_info
&& to_info
)
5328 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5329 to_info
->loads
->collapse ();
5331 to_info
->stores
->collapse ();
5333 if (!callee_info_lto
&& to_info_lto
)
5335 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5336 to_info_lto
->loads
->collapse ();
5338 to_info_lto
->stores
->collapse ();
5340 /* Merge side effects and non-determinism.
5341 PURE/CONST flags makes functions deterministic and if there is
5342 no LOOPING_CONST_OR_PURE they also have no side effects. */
5343 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
| ECF_PURE
))
5344 || (flags
& ECF_LOOPING_CONST_OR_PURE
))
5348 if (!callee_info
|| callee_info
->side_effects
)
5349 to_info
->side_effects
= true;
5350 if ((!callee_info
|| callee_info
->nondeterministic
)
5351 && !ignore_nondeterminism_p (edge
->caller
->decl
, flags
))
5352 to_info
->nondeterministic
= true;
5356 if (!callee_info_lto
|| callee_info_lto
->side_effects
)
5357 to_info_lto
->side_effects
= true;
5358 if ((!callee_info_lto
|| callee_info_lto
->nondeterministic
)
5359 && !ignore_nondeterminism_p (edge
->caller
->decl
, flags
))
5360 to_info_lto
->nondeterministic
= true;
5363 if (callee_info
|| callee_info_lto
)
5365 auto_vec
<modref_parm_map
, 32> parm_map
;
5366 modref_parm_map chain_map
;
5367 /* TODO: Once we get jump functions for static chains we could
5368 compute parm_index. */
5370 compute_parm_map (edge
, &parm_map
);
5374 if (to_info
&& callee_info
)
5375 to_info
->stores
->merge (to
->decl
, callee_info
->stores
, &parm_map
,
5377 if (to_info_lto
&& callee_info_lto
)
5378 to_info_lto
->stores
->merge (to
->decl
, callee_info_lto
->stores
,
5379 &parm_map
, &chain_map
, false);
5381 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5383 if (to_info
&& callee_info
)
5384 to_info
->loads
->merge (to
->decl
, callee_info
->loads
, &parm_map
,
5386 if (to_info_lto
&& callee_info_lto
)
5387 to_info_lto
->loads
->merge (to
->decl
, callee_info_lto
->loads
,
5388 &parm_map
, &chain_map
, false);
5392 /* Now merge escape summaries.
5393 For every escape to the callee we need to merge callee flags
5394 and remap callee's escapes. */
5395 class escape_summary
*sum
= escape_summaries
->get (edge
);
5396 int max_escape
= -1;
5400 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5401 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
5402 if ((int)ee
->arg
> max_escape
)
5403 max_escape
= ee
->arg
;
5405 auto_vec
<vec
<struct escape_map
>, 32> emap (max_escape
+ 1);
5406 emap
.safe_grow (max_escape
+ 1, true);
5407 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
5410 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5411 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
5413 bool needed
= false;
5414 int implicit_flags
= implicit_eaf_flags_for_edge_and_arg
5415 (edge
, flags
, ignore_stores
,
5418 implicit_flags
= deref_flags (implicit_flags
, ignore_stores
);
5419 if (to_info
&& (int)to_info
->arg_flags
.length () > ee
->parm_index
)
5421 int flags
= callee_info
5422 && callee_info
->arg_flags
.length () > ee
->arg
5423 ? callee_info
->arg_flags
[ee
->arg
] : 0;
5425 flags
= deref_flags (flags
, ignore_stores
);
5426 flags
|= ee
->min_flags
| implicit_flags
;
5427 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
5428 ? to_info
->retslot_flags
5429 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
5430 ? to_info
->static_chain_flags
5431 : to_info
->arg_flags
[ee
->parm_index
];
5437 && (int)to_info_lto
->arg_flags
.length () > ee
->parm_index
)
5439 int flags
= callee_info_lto
5440 && callee_info_lto
->arg_flags
.length () > ee
->arg
5441 ? callee_info_lto
->arg_flags
[ee
->arg
] : 0;
5443 flags
= deref_flags (flags
, ignore_stores
);
5444 flags
|= ee
->min_flags
| implicit_flags
;
5445 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
5446 ? to_info_lto
->retslot_flags
5447 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
5448 ? to_info_lto
->static_chain_flags
5449 : to_info_lto
->arg_flags
[ee
->parm_index
];
5454 struct escape_map entry
= {ee
->parm_index
, ee
->direct
};
5456 emap
[ee
->arg
].safe_push (entry
);
5458 update_escape_summary (edge
->callee
, emap
, ignore_stores
);
5459 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
5462 escape_summaries
->remove (edge
);
5466 if (to_info
&& !to_info
->useful_p (flags
))
5469 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
5471 summaries
->remove (to
);
5474 else if (to_info
&& dump_file
)
5477 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
5479 to_info
->dump (dump_file
);
5482 summaries
->remove (edge
->callee
);
5486 if (to_info_lto
&& !to_info_lto
->useful_p (flags
))
5489 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
5491 summaries_lto
->remove (to
);
5494 else if (to_info_lto
&& dump_file
)
5497 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
5499 to_info_lto
->dump (dump_file
);
5501 if (callee_info_lto
)
5502 summaries_lto
->remove (edge
->callee
);
5504 if (!to_info
&& !to_info_lto
)
5505 remove_modref_edge_summaries (to
);
5509 /* Run the IPA pass. This will take a function's summaries and calls and
5510 construct new summaries which represent a transitive closure. So that
5511 summary of an analyzed function contains information about the loads and
5512 stores that the function or any function that it calls does. */
5515 pass_ipa_modref::execute (function
*)
5517 if (!summaries
&& !summaries_lto
)
5519 bool pureconst
= false;
5521 if (optimization_summaries
)
5522 ggc_delete (optimization_summaries
);
5523 optimization_summaries
= summaries
;
5526 struct cgraph_node
**order
= XCNEWVEC (struct cgraph_node
*,
5527 symtab
->cgraph_count
);
5529 order_pos
= ipa_reduced_postorder (order
, true, ignore_edge
);
5532 /* Iterate over all strongly connected components in post-order. */
5533 for (i
= 0; i
< order_pos
; i
++)
5535 /* Get the component's representative. That's just any node in the
5536 component from which we can traverse the entire component. */
5537 struct cgraph_node
*component_node
= order
[i
];
5540 fprintf (dump_file
, "\n\nStart of SCC component\n");
5542 pureconst
|= modref_propagate_in_scc (component_node
);
5543 modref_propagate_flags_in_scc (component_node
);
5544 if (optimization_summaries
)
5545 for (struct cgraph_node
*cur
= component_node
; cur
;
5546 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
5547 if (modref_summary
*sum
= optimization_summaries
->get (cur
))
5548 sum
->finalize (cur
->decl
);
5550 modref_propagate_dump_scc (component_node
);
5553 FOR_EACH_FUNCTION (node
)
5554 update_signature (node
);
5556 ((modref_summaries_lto
*)summaries_lto
)->propagated
= true;
5557 ipa_free_postorder_info ();
5559 delete fnspec_summaries
;
5560 fnspec_summaries
= NULL
;
5561 delete escape_summaries
;
5562 escape_summaries
= NULL
;
5564 /* If we possibly made constructors const/pure we may need to remove
5566 return pureconst
? TODO_remove_functions
: 0;
5569 /* Summaries must stay alive until end of compilation. */
5572 ipa_modref_cc_finalize ()
5574 if (optimization_summaries
)
5575 ggc_delete (optimization_summaries
);
5576 optimization_summaries
= NULL
;
5578 ggc_delete (summaries_lto
);
5579 summaries_lto
= NULL
;
5580 if (fnspec_summaries
)
5581 delete fnspec_summaries
;
5582 fnspec_summaries
= NULL
;
5583 if (escape_summaries
)
5584 delete escape_summaries
;
5585 escape_summaries
= NULL
;
5588 #include "gt-ipa-modref.h"