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
)
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
)
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_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_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
)
1608 && !(flags
& ECF_LOOPING_CONST_OR_PURE
))
1612 " - ECF_CONST, 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 if (flags
& ECF_NOVOPS
)
1629 set_side_effects ();
1630 set_nondeterministic ();
1633 process_fnspec (stmt
);
1636 /* We only need to handle internal calls in IPA mode. */
1637 gcc_checking_assert (!m_summary_lto
&& !m_ipa
);
1639 struct cgraph_node
*callee_node
= cgraph_node::get_create (callee
);
1641 /* If this is a recursive call, the target summary is the same as ours, so
1642 there's nothing to do. */
1643 if (recursive_call_p (current_function_decl
, callee
))
1645 m_recursive_calls
.safe_push (stmt
);
1646 set_side_effects ();
1648 fprintf (dump_file
, " - Skipping recursive call.\n");
1652 gcc_assert (callee_node
!= NULL
);
1654 /* Get the function symbol and its availability. */
1655 enum availability avail
;
1656 callee_node
= callee_node
->function_symbol (&avail
);
1658 if (builtin_safe_for_const_function_p (&looping
, callee
))
1661 set_side_effects ();
1663 fprintf (dump_file
, " - Builtin is safe for const.\n");
1666 if (avail
<= AVAIL_INTERPOSABLE
)
1670 " - Function availability <= AVAIL_INTERPOSABLE.\n");
1671 process_fnspec (stmt
);
1675 /* Get callee's modref summary. As above, if there's no summary, we either
1676 have to give up or, if stores are ignored, we can just purge loads. */
1677 modref_summary
*callee_summary
= optimization_summaries
->get (callee_node
);
1678 if (!callee_summary
)
1681 fprintf (dump_file
, " - No modref summary available for callee.\n");
1682 process_fnspec (stmt
);
1686 merge_call_side_effects (stmt
, callee_summary
, callee_node
, false);
1691 /* Helper for analyze_stmt. */
1694 modref_access_analysis::analyze_load (gimple
*, tree
, tree op
, void *data
)
1696 modref_access_analysis
*t
= (modref_access_analysis
*)data
;
1700 fprintf (dump_file
, " - Analyzing load: ");
1701 print_generic_expr (dump_file
, op
);
1702 fprintf (dump_file
, "\n");
1705 if (!t
->record_access_p (op
))
1709 ao_ref_init (&r
, op
);
1710 modref_access_node a
= get_access (&r
);
1711 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1715 t
->record_access (t
->m_summary
->loads
, &r
, a
);
1716 if (t
->m_summary_lto
)
1717 t
->record_access_lto (t
->m_summary_lto
->loads
, &r
, a
);
1721 /* Helper for analyze_stmt. */
1724 modref_access_analysis::analyze_store (gimple
*stmt
, tree
, tree op
, void *data
)
1726 modref_access_analysis
*t
= (modref_access_analysis
*)data
;
1730 fprintf (dump_file
, " - Analyzing store: ");
1731 print_generic_expr (dump_file
, op
);
1732 fprintf (dump_file
, "\n");
1735 if (!t
->record_access_p (op
))
1739 ao_ref_init (&r
, op
);
1740 modref_access_node a
= get_access (&r
);
1741 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1745 t
->record_access (t
->m_summary
->stores
, &r
, a
);
1746 if (t
->m_summary_lto
)
1747 t
->record_access_lto (t
->m_summary_lto
->stores
, &r
, a
);
1748 if (t
->m_always_executed
1749 && a
.useful_for_kill_p ()
1750 && (!cfun
->can_throw_non_call_exceptions
1751 || !stmt_could_throw_p (cfun
, stmt
)))
1754 fprintf (dump_file
, " - Recording kill\n");
1756 modref_access_node::insert_kill (t
->m_summary
->kills
, a
, false);
1757 if (t
->m_summary_lto
)
1758 modref_access_node::insert_kill (t
->m_summary_lto
->kills
, a
, false);
1763 /* Analyze statement STMT of function F.
1764 If IPA is true do not merge in side effects of calls. */
1767 modref_access_analysis::analyze_stmt (gimple
*stmt
, bool always_executed
)
1769 m_always_executed
= always_executed
;
1770 /* In general we can not ignore clobbers because they are barriers for code
1771 motion, however after inlining it is safe to do because local optimization
1772 passes do not consider clobbers from other functions.
1773 Similar logic is in ipa-pure-const.cc. */
1774 if ((m_ipa
|| cfun
->after_inlining
) && gimple_clobber_p (stmt
))
1776 if (always_executed
&& record_access_p (gimple_assign_lhs (stmt
)))
1779 ao_ref_init (&r
, gimple_assign_lhs (stmt
));
1780 modref_access_node a
= get_access (&r
);
1781 if (a
.useful_for_kill_p ())
1784 fprintf (dump_file
, " - Recording kill\n");
1786 modref_access_node::insert_kill (m_summary
->kills
, a
, false);
1788 modref_access_node::insert_kill (m_summary_lto
->kills
,
1795 /* Analyze all loads and stores in STMT. */
1796 walk_stmt_load_store_ops (stmt
, this,
1797 analyze_load
, analyze_store
);
1799 switch (gimple_code (stmt
))
1802 if (gimple_asm_volatile_p (as_a
<gasm
*> (stmt
)))
1803 set_nondeterministic ();
1804 if (cfun
->can_throw_non_call_exceptions
1805 && stmt_could_throw_p (cfun
, stmt
))
1806 set_side_effects ();
1807 /* If the ASM statement does not read nor write memory, there's nothing
1808 to do. Otherwise just give up. */
1809 if (!gimple_asm_clobbers_memory_p (as_a
<gasm
*> (stmt
)))
1812 fprintf (dump_file
, " - Function contains GIMPLE_ASM statement "
1813 "which clobbers memory.\n");
1814 record_unknown_load ();
1815 record_unknown_store ();
1818 if (!m_ipa
|| gimple_call_internal_p (stmt
))
1819 analyze_call (as_a
<gcall
*> (stmt
));
1822 attr_fnspec fnspec
= gimple_call_fnspec (as_a
<gcall
*>(stmt
));
1824 if (fnspec
.known_p ()
1825 && (!fnspec
.global_memory_read_p ()
1826 || !fnspec
.global_memory_written_p ()))
1828 cgraph_edge
*e
= cgraph_node::get
1829 (current_function_decl
)->get_edge (stmt
);
1832 fnspec_summaries
->get_create (e
)->fnspec
1833 = xstrdup (fnspec
.get_str ());
1835 fprintf (dump_file
, " Recorded fnspec %s\n",
1842 if (cfun
->can_throw_non_call_exceptions
1843 && stmt_could_throw_p (cfun
, stmt
))
1844 set_side_effects ();
1849 /* Propagate load/stores across recursive calls. */
1852 modref_access_analysis::propagate ()
1854 if (m_ipa
&& m_summary
)
1857 bool changed
= true;
1859 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1861 m_always_executed
= false;
1862 while (changed
&& m_summary
->useful_p (m_ecf_flags
, false))
1865 for (unsigned i
= 0; i
< m_recursive_calls
.length (); i
++)
1867 changed
|= merge_call_side_effects (m_recursive_calls
[i
], m_summary
,
1874 /* Analyze function. */
1877 modref_access_analysis::analyze ()
1879 m_ecf_flags
= flags_from_decl_or_type (current_function_decl
);
1880 bool summary_useful
= true;
1882 /* Analyze each statement in each basic block of the function. If the
1883 statement cannot be analyzed (for any reason), the entire function cannot
1884 be analyzed by modref. */
1886 bitmap always_executed_bbs
= find_always_executed_bbs (cfun
, true);
1887 FOR_EACH_BB_FN (bb
, cfun
)
1889 gimple_stmt_iterator si
;
1890 bool always_executed
= bitmap_bit_p (always_executed_bbs
, bb
->index
);
1892 for (si
= gsi_start_nondebug_after_labels_bb (bb
);
1893 !gsi_end_p (si
); gsi_next_nondebug (&si
))
1895 /* NULL memory accesses terminates BB. These accesses are known
1896 to trip undefined behavior. gimple-ssa-isolate-paths turns them
1897 to volatile accesses and adds builtin_trap call which would
1898 confuse us otherwise. */
1899 if (infer_nonnull_range_by_dereference (gsi_stmt (si
),
1903 fprintf (dump_file
, " - NULL memory access; terminating BB\n");
1904 if (flag_non_call_exceptions
)
1905 set_side_effects ();
1908 analyze_stmt (gsi_stmt (si
), always_executed
);
1910 /* Avoid doing useless work. */
1911 if ((!m_summary
|| !m_summary
->useful_p (m_ecf_flags
, false))
1913 || !m_summary_lto
->useful_p (m_ecf_flags
, false)))
1915 summary_useful
= false;
1919 && stmt_can_throw_external (cfun
, gsi_stmt (si
)))
1920 always_executed
= false;
1922 if (!summary_useful
)
1925 /* In non-IPA mode we need to perform iterative dataflow on recursive calls.
1926 This needs to be done after all other side effects are computed. */
1931 if (m_summary
&& !m_summary
->side_effects
&& !finite_function_p ())
1932 m_summary
->side_effects
= true;
1933 if (m_summary_lto
&& !m_summary_lto
->side_effects
1934 && !finite_function_p ())
1935 m_summary_lto
->side_effects
= true;
1937 BITMAP_FREE (always_executed_bbs
);
1940 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1943 memory_access_to (tree op
, tree ssa_name
)
1945 tree base
= get_base_address (op
);
1948 if (TREE_CODE (base
) != MEM_REF
&& TREE_CODE (base
) != TARGET_MEM_REF
)
1950 return TREE_OPERAND (base
, 0) == ssa_name
;
1953 /* Consider statement val = *arg.
1954 return EAF flags of ARG that can be determined from EAF flags of VAL
1955 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1956 all stores to VAL, i.e. when handling noreturn function. */
1959 deref_flags (int flags
, bool ignore_stores
)
1961 /* Dereference is also a direct read but dereferenced value does not
1962 yield any other direct use. */
1963 int ret
= EAF_NO_DIRECT_CLOBBER
| EAF_NO_DIRECT_ESCAPE
1964 | EAF_NOT_RETURNED_DIRECTLY
;
1965 /* If argument is unused just account for
1966 the read involved in dereference. */
1967 if (flags
& EAF_UNUSED
)
1968 ret
|= EAF_NO_INDIRECT_READ
| EAF_NO_INDIRECT_CLOBBER
1969 | EAF_NO_INDIRECT_ESCAPE
;
1972 /* Direct or indirect accesses leads to indirect accesses. */
1973 if (((flags
& EAF_NO_DIRECT_CLOBBER
)
1974 && (flags
& EAF_NO_INDIRECT_CLOBBER
))
1976 ret
|= EAF_NO_INDIRECT_CLOBBER
;
1977 if (((flags
& EAF_NO_DIRECT_ESCAPE
)
1978 && (flags
& EAF_NO_INDIRECT_ESCAPE
))
1980 ret
|= EAF_NO_INDIRECT_ESCAPE
;
1981 if ((flags
& EAF_NO_DIRECT_READ
)
1982 && (flags
& EAF_NO_INDIRECT_READ
))
1983 ret
|= EAF_NO_INDIRECT_READ
;
1984 if ((flags
& EAF_NOT_RETURNED_DIRECTLY
)
1985 && (flags
& EAF_NOT_RETURNED_INDIRECTLY
))
1986 ret
|= EAF_NOT_RETURNED_INDIRECTLY
;
1992 /* Description of an escape point: a call which affects flags of a given
1997 /* Value escapes to this call. */
1999 /* Argument it escapes to. */
2001 /* Flags already known about the argument (this can save us from recording
2002 escape points if local analysis did good job already). */
2003 eaf_flags_t min_flags
;
2004 /* Does value escape directly or indirectly? */
2008 /* Lattice used during the eaf flags analysis dataflow. For a given SSA name
2009 we aim to compute its flags and escape points. We also use the lattice
2010 to dynamically build dataflow graph to propagate on. */
2012 class modref_lattice
2015 /* EAF flags of the SSA name. */
2017 /* Used during DFS walk to mark names where final value was determined
2018 without need for dataflow. */
2020 /* Used during DFS walk to mark open vertices (for cycle detection). */
2022 /* Set during DFS walk for names that needs dataflow propagation. */
2024 /* Used during the iterative dataflow. */
2027 /* When doing IPA analysis we can not merge in callee escape points;
2028 Only remember them and do the merging at IPA propagation time. */
2029 vec
<escape_point
, va_heap
, vl_ptr
> escape_points
;
2031 /* Representation of a graph for dataflow. This graph is built on-demand
2032 using modref_eaf_analysis::analyze_ssa and later solved by
2033 modref_eaf_analysis::propagate.
2034 Each edge represents the fact that flags of current lattice should be
2035 propagated to lattice of SSA_NAME. */
2036 struct propagate_edge
2041 vec
<propagate_edge
, va_heap
, vl_ptr
> propagate_to
;
2045 bool merge (const modref_lattice
&with
);
2046 bool merge (int flags
);
2047 bool merge_deref (const modref_lattice
&with
, bool ignore_stores
);
2048 bool merge_direct_load ();
2049 bool merge_direct_store ();
2050 bool add_escape_point (gcall
*call
, unsigned int arg
,
2051 eaf_flags_t min_flags
, bool direct
);
2052 void dump (FILE *out
, int indent
= 0) const;
2055 /* Lattices are saved to vectors, so keep them PODs. */
2057 modref_lattice::init ()
2059 /* All flags we track. */
2060 int f
= EAF_NO_DIRECT_CLOBBER
| EAF_NO_INDIRECT_CLOBBER
2061 | EAF_NO_DIRECT_ESCAPE
| EAF_NO_INDIRECT_ESCAPE
2062 | EAF_NO_DIRECT_READ
| EAF_NO_INDIRECT_READ
2063 | EAF_NOT_RETURNED_DIRECTLY
| EAF_NOT_RETURNED_INDIRECTLY
2066 /* Check that eaf_flags_t is wide enough to hold all flags. */
2067 gcc_checking_assert (f
== flags
);
2072 /* Release memory. */
2074 modref_lattice::release ()
2076 escape_points
.release ();
2077 propagate_to
.release ();
2080 /* Dump lattice to OUT; indent with INDENT spaces. */
2083 modref_lattice::dump (FILE *out
, int indent
) const
2085 dump_eaf_flags (out
, flags
);
2086 if (escape_points
.length ())
2088 fprintf (out
, "%*sEscapes:\n", indent
, "");
2089 for (unsigned int i
= 0; i
< escape_points
.length (); i
++)
2091 fprintf (out
, "%*s Arg %i (%s) min flags", indent
, "",
2092 escape_points
[i
].arg
,
2093 escape_points
[i
].direct
? "direct" : "indirect");
2094 dump_eaf_flags (out
, escape_points
[i
].min_flags
, false);
2095 fprintf (out
, " in call ");
2096 print_gimple_stmt (out
, escape_points
[i
].call
, 0);
2101 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
2105 modref_lattice::add_escape_point (gcall
*call
, unsigned arg
,
2106 eaf_flags_t min_flags
, bool direct
)
2111 /* If we already determined flags to be bad enough,
2112 we do not need to record. */
2113 if ((flags
& min_flags
) == flags
|| (min_flags
& EAF_UNUSED
))
2116 FOR_EACH_VEC_ELT (escape_points
, i
, ep
)
2117 if (ep
->call
== call
&& ep
->arg
== arg
&& ep
->direct
== direct
)
2119 if ((ep
->min_flags
& min_flags
) == min_flags
)
2121 ep
->min_flags
&= min_flags
;
2124 /* Give up if max escape points is met. */
2125 if ((int)escape_points
.length () > param_modref_max_escape_points
)
2128 fprintf (dump_file
, "--param modref-max-escape-points limit reached\n");
2132 escape_point new_ep
= {call
, arg
, min_flags
, direct
};
2133 escape_points
.safe_push (new_ep
);
2137 /* Merge in flags from F. */
2139 modref_lattice::merge (int f
)
2143 /* Check that flags seems sane: if function does not read the parameter
2144 it can not access it indirectly. */
2145 gcc_checking_assert (!(f
& EAF_NO_DIRECT_READ
)
2146 || ((f
& EAF_NO_INDIRECT_READ
)
2147 && (f
& EAF_NO_INDIRECT_CLOBBER
)
2148 && (f
& EAF_NO_INDIRECT_ESCAPE
)
2149 && (f
& EAF_NOT_RETURNED_INDIRECTLY
)));
2150 if ((flags
& f
) != flags
)
2153 /* Prune obviously useless flags;
2154 We do not have ECF_FLAGS handy which is not big problem since
2155 we will do final flags cleanup before producing summary.
2156 Merging should be fast so it can work well with dataflow. */
2157 flags
= remove_useless_eaf_flags (flags
, 0, false);
2159 escape_points
.release ();
2165 /* Merge in WITH. Return true if anything changed. */
2168 modref_lattice::merge (const modref_lattice
&with
)
2173 bool changed
= merge (with
.flags
);
2177 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
2178 changed
|= add_escape_point (with
.escape_points
[i
].call
,
2179 with
.escape_points
[i
].arg
,
2180 with
.escape_points
[i
].min_flags
,
2181 with
.escape_points
[i
].direct
);
2185 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
2186 stores. Return true if anything changed. */
2189 modref_lattice::merge_deref (const modref_lattice
&with
, bool ignore_stores
)
2194 bool changed
= merge (deref_flags (with
.flags
, ignore_stores
));
2198 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
2200 int min_flags
= with
.escape_points
[i
].min_flags
;
2202 if (with
.escape_points
[i
].direct
)
2203 min_flags
= deref_flags (min_flags
, ignore_stores
);
2204 else if (ignore_stores
)
2205 min_flags
|= ignore_stores_eaf_flags
;
2206 changed
|= add_escape_point (with
.escape_points
[i
].call
,
2207 with
.escape_points
[i
].arg
,
2214 /* Merge in flags for direct load. */
2217 modref_lattice::merge_direct_load ()
2219 return merge (~(EAF_UNUSED
| EAF_NO_DIRECT_READ
));
2222 /* Merge in flags for direct store. */
2225 modref_lattice::merge_direct_store ()
2227 return merge (~(EAF_UNUSED
| EAF_NO_DIRECT_CLOBBER
));
2230 /* Analyzer of EAF flags.
2231 This is generally dataflow problem over the SSA graph, however we only
2232 care about flags of few selected ssa names (arguments, return slot and
2233 static chain). So we first call analyze_ssa_name on all relevant names
2234 and perform a DFS walk to discover SSA names where flags needs to be
2235 determined. For acyclic graphs we try to determine final flags during
2236 this walk. Once cycles or recursion depth is met we enlist SSA names
2237 for dataflow which is done by propagate call.
2239 After propagation the flags can be obtained using get_ssa_name_flags. */
2241 class modref_eaf_analysis
2244 /* Mark NAME as relevant for analysis. */
2245 void analyze_ssa_name (tree name
, bool deferred
= false);
2246 /* Dataflow solver. */
2248 /* Return flags computed earlier for NAME. */
2249 int get_ssa_name_flags (tree name
)
2251 int version
= SSA_NAME_VERSION (name
);
2252 gcc_checking_assert (m_lattice
[version
].known
);
2253 return m_lattice
[version
].flags
;
2255 /* In IPA mode this will record all escape points
2256 determined for NAME to PARM_IDNEX. Flags are minimal
2258 void record_escape_points (tree name
, int parm_index
, int flags
);
2259 modref_eaf_analysis (bool ipa
)
2263 m_lattice
.safe_grow_cleared (num_ssa_names
, true);
2265 ~modref_eaf_analysis ()
2267 gcc_checking_assert (!m_depth
);
2268 if (m_ipa
|| m_names_to_propagate
.length ())
2269 for (unsigned int i
= 0; i
< num_ssa_names
; i
++)
2270 m_lattice
[i
].release ();
2273 /* If true, we produce analysis for IPA mode. In this case escape points are
2276 /* Depth of recursion of analyze_ssa_name. */
2278 /* Propagation lattice for individual ssa names. */
2279 auto_vec
<modref_lattice
> m_lattice
;
2280 auto_vec
<tree
> m_deferred_names
;
2281 auto_vec
<int> m_names_to_propagate
;
2283 void merge_with_ssa_name (tree dest
, tree src
, bool deref
);
2284 void merge_call_lhs_flags (gcall
*call
, int arg
, tree name
, bool direct
,
2289 /* Call statements may return their parameters. Consider argument number
2290 ARG of USE_STMT and determine flags that can needs to be cleared
2291 in case pointer possibly indirectly references from ARG I is returned.
2292 If DIRECT is true consider direct returns and if INDIRECT consider
2294 LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
2295 ARG is set to -1 for static chain. */
2298 modref_eaf_analysis::merge_call_lhs_flags (gcall
*call
, int arg
,
2299 tree name
, bool direct
,
2302 int index
= SSA_NAME_VERSION (name
);
2303 bool returned_directly
= false;
2305 /* If there is no return value, no flags are affected. */
2306 if (!gimple_call_lhs (call
))
2309 /* If we know that function returns given argument and it is not ARG
2310 we can still be happy. */
2313 int flags
= gimple_call_return_flags (call
);
2314 if (flags
& ERF_RETURNS_ARG
)
2316 if ((flags
& ERF_RETURN_ARG_MASK
) == arg
)
2317 returned_directly
= true;
2322 /* Make ERF_RETURNS_ARG overwrite EAF_UNUSED. */
2323 if (returned_directly
)
2328 /* If value is not returned at all, do nothing. */
2329 else if (!direct
&& !indirect
)
2332 /* If return value is SSA name determine its flags. */
2333 if (TREE_CODE (gimple_call_lhs (call
)) == SSA_NAME
)
2335 tree lhs
= gimple_call_lhs (call
);
2337 merge_with_ssa_name (name
, lhs
, false);
2339 merge_with_ssa_name (name
, lhs
, true);
2341 /* In the case of memory store we can do nothing. */
2343 m_lattice
[index
].merge (deref_flags (0, false));
2345 m_lattice
[index
].merge (0);
2348 /* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
2349 into flags for caller, update LATTICE of corresponding
2350 argument if needed. */
2353 callee_to_caller_flags (int call_flags
, bool ignore_stores
,
2354 modref_lattice
&lattice
)
2356 /* call_flags is about callee returning a value
2357 that is not the same as caller returning it. */
2358 call_flags
|= EAF_NOT_RETURNED_DIRECTLY
2359 | EAF_NOT_RETURNED_INDIRECTLY
;
2360 if (!ignore_stores
&& !(call_flags
& EAF_UNUSED
))
2362 /* If value escapes we are no longer able to track what happens
2363 with it because we can read it from the escaped location
2365 if (!(call_flags
& EAF_NO_DIRECT_ESCAPE
))
2367 else if (!(call_flags
& EAF_NO_INDIRECT_ESCAPE
))
2368 lattice
.merge (~(EAF_NOT_RETURNED_INDIRECTLY
2369 | EAF_NO_DIRECT_READ
2370 | EAF_NO_INDIRECT_READ
2371 | EAF_NO_INDIRECT_CLOBBER
2375 call_flags
|= ignore_stores_eaf_flags
;
2379 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
2380 LATTICE is an array of modref_lattices.
2381 DEPTH is a recursion depth used to make debug output prettier.
2382 If IPA is true we analyze for IPA propagation (and thus call escape points
2383 are processed later) */
2386 modref_eaf_analysis::analyze_ssa_name (tree name
, bool deferred
)
2388 imm_use_iterator ui
;
2390 int index
= SSA_NAME_VERSION (name
);
2394 /* See if value is already computed. */
2395 if (m_lattice
[index
].known
|| m_lattice
[index
].do_dataflow
)
2397 if (m_lattice
[index
].open
)
2401 "%*sCycle in SSA graph\n",
2405 /* Recursion guard. */
2406 m_lattice
[index
].init ();
2407 if (m_depth
== param_modref_max_depth
)
2411 "%*sMax recursion depth reached; postponing\n",
2413 m_deferred_names
.safe_push (name
);
2421 "%*sAnalyzing flags of ssa name: ", m_depth
* 4, "");
2422 print_generic_expr (dump_file
, name
);
2423 fprintf (dump_file
, "\n");
2426 FOR_EACH_IMM_USE_STMT (use_stmt
, ui
, name
)
2428 if (m_lattice
[index
].flags
== 0)
2430 if (is_gimple_debug (use_stmt
))
2434 fprintf (dump_file
, "%*s Analyzing stmt: ", m_depth
* 4, "");
2435 print_gimple_stmt (dump_file
, use_stmt
, 0);
2437 /* If we see a direct non-debug use, clear unused bit.
2438 All dereferences should be accounted below using deref_flags. */
2439 m_lattice
[index
].merge (~EAF_UNUSED
);
2441 /* Gimple return may load the return value.
2442 Returning name counts as an use by tree-ssa-structalias.cc */
2443 if (greturn
*ret
= dyn_cast
<greturn
*> (use_stmt
))
2445 /* Returning through return slot is seen as memory write earlier. */
2446 if (DECL_RESULT (current_function_decl
)
2447 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl
)))
2449 else if (gimple_return_retval (ret
) == name
)
2450 m_lattice
[index
].merge (~(EAF_UNUSED
| EAF_NOT_RETURNED_DIRECTLY
2451 | EAF_NOT_RETURNED_DIRECTLY
));
2452 else if (memory_access_to (gimple_return_retval (ret
), name
))
2454 m_lattice
[index
].merge_direct_load ();
2455 m_lattice
[index
].merge (~(EAF_UNUSED
2456 | EAF_NOT_RETURNED_INDIRECTLY
));
2459 /* Account for LHS store, arg loads and flags from callee function. */
2460 else if (gcall
*call
= dyn_cast
<gcall
*> (use_stmt
))
2462 tree callee
= gimple_call_fndecl (call
);
2464 /* IPA PTA internally it treats calling a function as "writing" to
2465 the argument space of all functions the function pointer points to
2466 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
2467 is on since that would allow propagation of this from -fno-ipa-pta
2468 to -fipa-pta functions. */
2469 if (gimple_call_fn (use_stmt
) == name
)
2470 m_lattice
[index
].merge (~(EAF_NO_DIRECT_CLOBBER
| EAF_UNUSED
));
2472 /* Recursion would require bit of propagation; give up for now. */
2473 if (callee
&& !m_ipa
&& recursive_call_p (current_function_decl
,
2475 m_lattice
[index
].merge (0);
2478 int ecf_flags
= gimple_call_flags (call
);
2479 bool ignore_stores
= ignore_stores_p (current_function_decl
,
2481 bool ignore_retval
= ignore_retval_p (current_function_decl
,
2484 /* Handle *name = func (...). */
2485 if (gimple_call_lhs (call
)
2486 && memory_access_to (gimple_call_lhs (call
), name
))
2488 m_lattice
[index
].merge_direct_store ();
2489 /* Return slot optimization passes address of
2490 LHS to callee via hidden parameter and this
2491 may make LHS to escape. See PR 98499. */
2492 if (gimple_call_return_slot_opt_p (call
)
2493 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call
))))
2495 int call_flags
= gimple_call_retslot_flags (call
);
2496 bool isretslot
= false;
2498 if (DECL_RESULT (current_function_decl
)
2499 && DECL_BY_REFERENCE
2500 (DECL_RESULT (current_function_decl
)))
2501 isretslot
= ssa_default_def
2503 DECL_RESULT (current_function_decl
))
2506 /* Passing returnslot to return slot is special because
2507 not_returned and escape has same meaning.
2508 However passing arg to return slot is different. If
2509 the callee's return slot is returned it means that
2510 arg is written to itself which is an escape.
2511 Since we do not track the memory it is written to we
2512 need to give up on analyzing it. */
2515 if (!(call_flags
& (EAF_NOT_RETURNED_DIRECTLY
2517 m_lattice
[index
].merge (0);
2518 else gcc_checking_assert
2519 (call_flags
& (EAF_NOT_RETURNED_INDIRECTLY
2521 call_flags
= callee_to_caller_flags
2525 m_lattice
[index
].merge (call_flags
);
2529 if (gimple_call_chain (call
)
2530 && (gimple_call_chain (call
) == name
))
2532 int call_flags
= gimple_call_static_chain_flags (call
);
2533 if (!ignore_retval
&& !(call_flags
& EAF_UNUSED
))
2534 merge_call_lhs_flags
2536 !(call_flags
& EAF_NOT_RETURNED_DIRECTLY
),
2537 !(call_flags
& EAF_NOT_RETURNED_INDIRECTLY
));
2538 call_flags
= callee_to_caller_flags
2539 (call_flags
, ignore_stores
,
2541 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
2542 m_lattice
[index
].merge (call_flags
);
2545 /* Process internal functions and right away. */
2546 bool record_ipa
= m_ipa
&& !gimple_call_internal_p (call
);
2548 /* Handle all function parameters. */
2549 for (unsigned i
= 0;
2550 i
< gimple_call_num_args (call
)
2551 && m_lattice
[index
].flags
; i
++)
2552 /* Name is directly passed to the callee. */
2553 if (gimple_call_arg (call
, i
) == name
)
2555 int call_flags
= gimple_call_arg_flags (call
, i
);
2557 merge_call_lhs_flags
2559 !(call_flags
& (EAF_NOT_RETURNED_DIRECTLY
2561 !(call_flags
& (EAF_NOT_RETURNED_INDIRECTLY
2563 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
2565 call_flags
= callee_to_caller_flags
2566 (call_flags
, ignore_stores
,
2569 m_lattice
[index
].merge (call_flags
);
2571 m_lattice
[index
].add_escape_point (call
, i
,
2575 /* Name is dereferenced and passed to a callee. */
2576 else if (memory_access_to (gimple_call_arg (call
, i
), name
))
2578 int call_flags
= deref_flags
2579 (gimple_call_arg_flags (call
, i
), ignore_stores
);
2580 if (!ignore_retval
&& !(call_flags
& EAF_UNUSED
)
2581 && (call_flags
& (EAF_NOT_RETURNED_DIRECTLY
2582 | EAF_NOT_RETURNED_INDIRECTLY
))
2583 != (EAF_NOT_RETURNED_DIRECTLY
2584 | EAF_NOT_RETURNED_INDIRECTLY
))
2585 merge_call_lhs_flags (call
, i
, name
, false, true);
2586 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
2587 m_lattice
[index
].merge_direct_load ();
2590 call_flags
= callee_to_caller_flags
2591 (call_flags
, ignore_stores
,
2594 m_lattice
[index
].merge (call_flags
);
2596 m_lattice
[index
].add_escape_point (call
, i
,
2602 else if (gimple_assign_load_p (use_stmt
))
2604 gassign
*assign
= as_a
<gassign
*> (use_stmt
);
2605 /* Memory to memory copy. */
2606 if (gimple_store_p (assign
))
2608 /* Handle *lhs = *name.
2610 We do not track memory locations, so assume that value
2611 is used arbitrarily. */
2612 if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
2613 m_lattice
[index
].merge (deref_flags (0, false));
2615 /* Handle *name = *exp. */
2616 if (memory_access_to (gimple_assign_lhs (assign
), name
))
2617 m_lattice
[index
].merge_direct_store ();
2619 /* Handle lhs = *name. */
2620 else if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
2622 tree lhs
= gimple_assign_lhs (assign
);
2623 merge_with_ssa_name (name
, lhs
, true);
2626 else if (gimple_store_p (use_stmt
))
2628 gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
);
2630 /* Handle *lhs = name. */
2631 if (assign
&& gimple_assign_rhs1 (assign
) == name
)
2634 fprintf (dump_file
, "%*s ssa name saved to memory\n",
2636 m_lattice
[index
].merge (0);
2638 /* Handle *name = exp. */
2640 && memory_access_to (gimple_assign_lhs (assign
), name
))
2642 /* In general we can not ignore clobbers because they are
2643 barriers for code motion, however after inlining it is safe to
2644 do because local optimization passes do not consider clobbers
2645 from other functions.
2646 Similar logic is in ipa-pure-const.cc. */
2647 if (!cfun
->after_inlining
|| !gimple_clobber_p (assign
))
2648 m_lattice
[index
].merge_direct_store ();
2650 /* ASM statements etc. */
2654 fprintf (dump_file
, "%*s Unhandled store\n", m_depth
* 4, "");
2655 m_lattice
[index
].merge (0);
2658 else if (gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
))
2660 enum tree_code code
= gimple_assign_rhs_code (assign
);
2662 /* See if operation is a merge as considered by
2663 tree-ssa-structalias.cc:find_func_aliases. */
2664 if (!truth_value_p (code
)
2665 && code
!= POINTER_DIFF_EXPR
2666 && (code
!= POINTER_PLUS_EXPR
2667 || gimple_assign_rhs1 (assign
) == name
))
2669 tree lhs
= gimple_assign_lhs (assign
);
2670 merge_with_ssa_name (name
, lhs
, false);
2673 else if (gphi
*phi
= dyn_cast
<gphi
*> (use_stmt
))
2675 tree result
= gimple_phi_result (phi
);
2676 merge_with_ssa_name (name
, result
, false);
2678 /* Conditions are not considered escape points
2679 by tree-ssa-structalias. */
2680 else if (gimple_code (use_stmt
) == GIMPLE_COND
)
2685 fprintf (dump_file
, "%*s Unhandled stmt\n", m_depth
* 4, "");
2686 m_lattice
[index
].merge (0);
2691 fprintf (dump_file
, "%*s current flags of ", m_depth
* 4, "");
2692 print_generic_expr (dump_file
, name
);
2693 m_lattice
[index
].dump (dump_file
, m_depth
* 4 + 4);
2698 fprintf (dump_file
, "%*sflags of ssa name ", m_depth
* 4, "");
2699 print_generic_expr (dump_file
, name
);
2700 m_lattice
[index
].dump (dump_file
, m_depth
* 4 + 2);
2702 m_lattice
[index
].open
= false;
2703 if (!m_lattice
[index
].do_dataflow
)
2704 m_lattice
[index
].known
= true;
2707 /* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
2711 modref_eaf_analysis::merge_with_ssa_name (tree dest
, tree src
, bool deref
)
2713 int index
= SSA_NAME_VERSION (dest
);
2714 int src_index
= SSA_NAME_VERSION (src
);
2716 /* Merging lattice with itself is a no-op. */
2717 if (!deref
&& src
== dest
)
2721 analyze_ssa_name (src
);
2724 m_lattice
[index
].merge_deref (m_lattice
[src_index
], false);
2726 m_lattice
[index
].merge (m_lattice
[src_index
]);
2728 /* If we failed to produce final solution add an edge to the dataflow
2730 if (!m_lattice
[src_index
].known
)
2732 modref_lattice::propagate_edge e
= {index
, deref
};
2734 if (!m_lattice
[src_index
].propagate_to
.length ())
2735 m_names_to_propagate
.safe_push (src_index
);
2736 m_lattice
[src_index
].propagate_to
.safe_push (e
);
2737 m_lattice
[src_index
].changed
= true;
2738 m_lattice
[src_index
].do_dataflow
= true;
2741 "%*sWill propgate from ssa_name %i to %i%s\n",
2743 "", src_index
, index
, deref
? " (deref)" : "");
2747 /* In the case we deferred some SSA names, reprocess them. In the case some
2748 dataflow edges were introduced, do the actual iterative dataflow. */
2751 modref_eaf_analysis::propagate ()
2756 bool changed
= true;
2758 while (m_deferred_names
.length ())
2760 tree name
= m_deferred_names
.pop ();
2762 fprintf (dump_file
, "Analyzing deferred SSA name\n");
2763 analyze_ssa_name (name
, true);
2766 if (!m_names_to_propagate
.length ())
2769 fprintf (dump_file
, "Propagating EAF flags\n");
2771 /* Compute reverse postorder. */
2778 auto_vec
<struct stack_entry
> stack
;
2779 int pos
= m_names_to_propagate
.length () - 1;
2781 rpo
.safe_grow (m_names_to_propagate
.length (), true);
2782 stack
.reserve_exact (m_names_to_propagate
.length ());
2784 /* We reuse known flag for RPO DFS walk bookkeeping. */
2786 FOR_EACH_VEC_ELT (m_names_to_propagate
, i
, index
)
2787 gcc_assert (!m_lattice
[index
].known
&& m_lattice
[index
].changed
);
2789 FOR_EACH_VEC_ELT (m_names_to_propagate
, i
, index
)
2791 if (!m_lattice
[index
].known
)
2793 stack_entry e
= {index
, 0};
2795 stack
.quick_push (e
);
2796 m_lattice
[index
].known
= true;
2798 while (stack
.length ())
2801 int index1
= stack
.last ().name
;
2803 while (stack
.last ().pos
< m_lattice
[index1
].propagate_to
.length ())
2805 int index2
= m_lattice
[index1
]
2806 .propagate_to
[stack
.last ().pos
].ssa_name
;
2808 stack
.last ().pos
++;
2809 if (!m_lattice
[index2
].known
2810 && m_lattice
[index2
].propagate_to
.length ())
2812 stack_entry e
= {index2
, 0};
2814 stack
.quick_push (e
);
2815 m_lattice
[index2
].known
= true;
2821 && stack
.last ().pos
== m_lattice
[index1
].propagate_to
.length ())
2823 rpo
[pos
--] = index1
;
2829 /* Perform iterative dataflow. */
2835 fprintf (dump_file
, " iteration %i\n", iterations
);
2836 FOR_EACH_VEC_ELT (rpo
, i
, index
)
2838 if (m_lattice
[index
].changed
)
2842 m_lattice
[index
].changed
= false;
2844 fprintf (dump_file
, " Visiting ssa name %i\n", index
);
2845 for (j
= 0; j
< m_lattice
[index
].propagate_to
.length (); j
++)
2848 int target
= m_lattice
[index
].propagate_to
[j
].ssa_name
;
2849 bool deref
= m_lattice
[index
].propagate_to
[j
].deref
;
2852 fprintf (dump_file
, " Propagating flags of ssa name"
2854 index
, target
, deref
? " (deref)" : "");
2855 m_lattice
[target
].known
= true;
2856 if (!m_lattice
[index
].propagate_to
[j
].deref
)
2857 ch
= m_lattice
[target
].merge (m_lattice
[index
]);
2859 ch
= m_lattice
[target
].merge_deref (m_lattice
[index
],
2865 fprintf (dump_file
, " New lattice: ");
2866 m_lattice
[target
].dump (dump_file
);
2869 m_lattice
[target
].changed
= true;
2875 fprintf (dump_file
, "EAF flags propagated in %i iterations\n", iterations
);
2878 /* Record escape points of PARM_INDEX according to LATTICE. */
2881 modref_eaf_analysis::record_escape_points (tree name
, int parm_index
, int flags
)
2883 modref_lattice
&lattice
= m_lattice
[SSA_NAME_VERSION (name
)];
2885 if (lattice
.escape_points
.length ())
2889 cgraph_node
*node
= cgraph_node::get (current_function_decl
);
2892 FOR_EACH_VEC_ELT (lattice
.escape_points
, ip
, ep
)
2893 if ((ep
->min_flags
& flags
) != flags
)
2895 cgraph_edge
*e
= node
->get_edge (ep
->call
);
2896 struct escape_entry ee
= {parm_index
, ep
->arg
,
2897 ep
->min_flags
, ep
->direct
};
2899 escape_summaries
->get_create (e
)->esc
.safe_push (ee
);
2904 /* Determine EAF flags for function parameters
2905 and fill in SUMMARY/SUMMARY_LTO. If IPA is true work in IPA mode
2906 where we also collect escape points.
2907 PAST_FLAGS, PAST_RETSLOT_FLAGS, PAST_STATIC_CHAIN_FLAGS can be
2908 used to preserve flags from previous (IPA) run for cases where
2909 late optimizations changed code in a way we can no longer analyze
2913 analyze_parms (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
2914 bool ipa
, vec
<eaf_flags_t
> &past_flags
,
2915 int past_retslot_flags
, int past_static_chain_flags
)
2917 unsigned int parm_index
= 0;
2918 unsigned int count
= 0;
2919 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
2920 tree retslot
= NULL
;
2921 tree static_chain
= NULL
;
2923 /* If there is return slot, look up its SSA name. */
2924 if (DECL_RESULT (current_function_decl
)
2925 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl
)))
2926 retslot
= ssa_default_def (cfun
, DECL_RESULT (current_function_decl
));
2927 if (cfun
->static_chain_decl
)
2928 static_chain
= ssa_default_def (cfun
, cfun
->static_chain_decl
);
2930 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
2931 parm
= TREE_CHAIN (parm
))
2934 if (!count
&& !retslot
&& !static_chain
)
2937 modref_eaf_analysis
eaf_analysis (ipa
);
2939 /* Determine all SSA names we need to know flags for. */
2940 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
2941 parm
= TREE_CHAIN (parm
))
2943 tree name
= ssa_default_def (cfun
, parm
);
2945 eaf_analysis
.analyze_ssa_name (name
);
2948 eaf_analysis
.analyze_ssa_name (retslot
);
2950 eaf_analysis
.analyze_ssa_name (static_chain
);
2952 /* Do the dataflow. */
2953 eaf_analysis
.propagate ();
2955 tree attr
= lookup_attribute ("fn spec",
2957 (TREE_TYPE (current_function_decl
)));
2958 attr_fnspec
fnspec (attr
2959 ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr
)))
2963 /* Store results to summaries. */
2964 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
; parm_index
++,
2965 parm
= TREE_CHAIN (parm
))
2967 tree name
= ssa_default_def (cfun
, parm
);
2968 if (!name
|| has_zero_uses (name
))
2970 /* We do not track non-SSA parameters,
2971 but we want to track unused gimple_regs. */
2972 if (!is_gimple_reg (parm
))
2976 if (parm_index
>= summary
->arg_flags
.length ())
2977 summary
->arg_flags
.safe_grow_cleared (count
, true);
2978 summary
->arg_flags
[parm_index
] = EAF_UNUSED
;
2982 if (parm_index
>= summary_lto
->arg_flags
.length ())
2983 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
2984 summary_lto
->arg_flags
[parm_index
] = EAF_UNUSED
;
2988 int flags
= eaf_analysis
.get_ssa_name_flags (name
);
2989 int attr_flags
= fnspec
.arg_eaf_flags (parm_index
);
2991 if (dump_file
&& (flags
| attr_flags
) != flags
&& !(flags
& EAF_UNUSED
))
2994 " Flags for param %i combined with fnspec flags:",
2996 dump_eaf_flags (dump_file
, attr_flags
, false);
2997 fprintf (dump_file
, " determined: ");
2998 dump_eaf_flags (dump_file
, flags
, true);
3000 flags
|= attr_flags
;
3002 /* Eliminate useless flags so we do not end up storing unnecessary
3005 flags
= remove_useless_eaf_flags
3007 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3008 if (past_flags
.length () > parm_index
)
3010 int past
= past_flags
[parm_index
];
3011 past
= remove_useless_eaf_flags
3013 VOID_TYPE_P (TREE_TYPE
3014 (TREE_TYPE (current_function_decl
))));
3015 /* Store merging can produce reads when combining together multiple
3016 bitfields. See PR111613. */
3017 past
&= ~(EAF_NO_DIRECT_READ
| EAF_NO_INDIRECT_READ
);
3018 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
3021 " Flags for param %i combined with IPA pass:",
3023 dump_eaf_flags (dump_file
, past
, false);
3024 fprintf (dump_file
, " determined: ");
3025 dump_eaf_flags (dump_file
, flags
, true);
3027 if (!(flags
& EAF_UNUSED
))
3035 if (parm_index
>= summary
->arg_flags
.length ())
3036 summary
->arg_flags
.safe_grow_cleared (count
, true);
3037 summary
->arg_flags
[parm_index
] = flags
;
3041 if (parm_index
>= summary_lto
->arg_flags
.length ())
3042 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
3043 summary_lto
->arg_flags
[parm_index
] = flags
;
3045 eaf_analysis
.record_escape_points (name
, parm_index
, flags
);
3050 int flags
= eaf_analysis
.get_ssa_name_flags (retslot
);
3051 int past
= past_retslot_flags
;
3053 flags
= remove_useless_eaf_flags (flags
, ecf_flags
, false);
3054 past
= remove_useless_eaf_flags
3056 VOID_TYPE_P (TREE_TYPE
3057 (TREE_TYPE (current_function_decl
))));
3058 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
3061 " Retslot flags combined with IPA pass:");
3062 dump_eaf_flags (dump_file
, past
, false);
3063 fprintf (dump_file
, " determined: ");
3064 dump_eaf_flags (dump_file
, flags
, true);
3066 if (!(flags
& EAF_UNUSED
))
3071 summary
->retslot_flags
= flags
;
3073 summary_lto
->retslot_flags
= flags
;
3074 eaf_analysis
.record_escape_points (retslot
,
3075 MODREF_RETSLOT_PARM
, flags
);
3080 int flags
= eaf_analysis
.get_ssa_name_flags (static_chain
);
3081 int past
= past_static_chain_flags
;
3083 flags
= remove_useless_eaf_flags (flags
, ecf_flags
, false);
3084 past
= remove_useless_eaf_flags
3086 VOID_TYPE_P (TREE_TYPE
3087 (TREE_TYPE (current_function_decl
))));
3088 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
3091 " Static chain flags combined with IPA pass:");
3092 dump_eaf_flags (dump_file
, past
, false);
3093 fprintf (dump_file
, " determined: ");
3094 dump_eaf_flags (dump_file
, flags
, true);
3096 if (!(flags
& EAF_UNUSED
))
3101 summary
->static_chain_flags
= flags
;
3103 summary_lto
->static_chain_flags
= flags
;
3104 eaf_analysis
.record_escape_points (static_chain
,
3105 MODREF_STATIC_CHAIN_PARM
,
3111 /* Analyze function. IPA indicates whether we're running in local mode
3112 (false) or the IPA mode (true).
3113 Return true if fixup cfg is needed after the pass. */
3116 analyze_function (bool ipa
)
3118 bool fixup_cfg
= false;
3120 fprintf (dump_file
, "\n\nmodref analyzing '%s' (ipa=%i)%s%s\n",
3121 cgraph_node::get (current_function_decl
)->dump_name (), ipa
,
3122 TREE_READONLY (current_function_decl
) ? " (const)" : "",
3123 DECL_PURE_P (current_function_decl
) ? " (pure)" : "");
3125 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
3126 if (!flag_ipa_modref
3127 || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl
)))
3130 /* Compute no-LTO summaries when local optimization is going to happen. */
3131 bool nolto
= (!ipa
|| ((!flag_lto
|| flag_fat_lto_objects
) && !in_lto_p
)
3132 || (in_lto_p
&& !flag_wpa
3133 && flag_incremental_link
!= INCREMENTAL_LINK_LTO
));
3134 /* Compute LTO when LTO streaming is going to happen. */
3135 bool lto
= ipa
&& ((flag_lto
&& !in_lto_p
)
3137 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
3138 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
3140 modref_summary
*summary
= NULL
;
3141 modref_summary_lto
*summary_lto
= NULL
;
3143 bool past_flags_known
= false;
3144 auto_vec
<eaf_flags_t
> past_flags
;
3145 int past_retslot_flags
= 0;
3146 int past_static_chain_flags
= 0;
3148 /* Initialize the summary.
3149 If we run in local mode there is possibly pre-existing summary from
3150 IPA pass. Dump it so it is easy to compare if mod-ref info has
3154 if (!optimization_summaries
)
3155 optimization_summaries
= modref_summaries::create_ggc (symtab
);
3156 else /* Remove existing summary if we are re-running the pass. */
3158 summary
= optimization_summaries
->get (fnode
);
3164 fprintf (dump_file
, "Past summary:\n");
3165 optimization_summaries
->get (fnode
)->dump (dump_file
);
3167 past_flags
.reserve_exact (summary
->arg_flags
.length ());
3168 past_flags
.splice (summary
->arg_flags
);
3169 past_retslot_flags
= summary
->retslot_flags
;
3170 past_static_chain_flags
= summary
->static_chain_flags
;
3171 past_flags_known
= true;
3173 optimization_summaries
->remove (fnode
);
3175 summary
= optimization_summaries
->get_create (fnode
);
3176 gcc_checking_assert (nolto
&& !lto
);
3178 /* In IPA mode we analyze every function precisely once. Assert that. */
3184 summaries
= modref_summaries::create_ggc (symtab
);
3186 summaries
->remove (fnode
);
3187 summary
= summaries
->get_create (fnode
);
3192 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
3194 summaries_lto
->remove (fnode
);
3195 summary_lto
= summaries_lto
->get_create (fnode
);
3197 if (!fnspec_summaries
)
3198 fnspec_summaries
= new fnspec_summaries_t (symtab
);
3199 if (!escape_summaries
)
3200 escape_summaries
= new escape_summaries_t (symtab
);
3204 /* Create and initialize summary for F.
3205 Note that summaries may be already allocated from previous
3209 gcc_assert (!summary
->loads
);
3210 summary
->loads
= modref_records::create_ggc ();
3211 gcc_assert (!summary
->stores
);
3212 summary
->stores
= modref_records::create_ggc ();
3213 summary
->writes_errno
= false;
3214 summary
->side_effects
= false;
3215 summary
->nondeterministic
= false;
3216 summary
->calls_interposable
= false;
3220 gcc_assert (!summary_lto
->loads
);
3221 summary_lto
->loads
= modref_records_lto::create_ggc ();
3222 gcc_assert (!summary_lto
->stores
);
3223 summary_lto
->stores
= modref_records_lto::create_ggc ();
3224 summary_lto
->writes_errno
= false;
3225 summary_lto
->side_effects
= false;
3226 summary_lto
->nondeterministic
= false;
3227 summary_lto
->calls_interposable
= false;
3230 analyze_parms (summary
, summary_lto
, ipa
,
3231 past_flags
, past_retslot_flags
, past_static_chain_flags
);
3234 modref_access_analysis
analyzer (ipa
, summary
, summary_lto
);
3235 analyzer
.analyze ();
3238 if (!ipa
&& flag_ipa_pure_const
)
3240 if (!summary
->stores
->every_base
&& !summary
->stores
->bases
3241 && !summary
->nondeterministic
)
3243 if (!summary
->loads
->every_base
&& !summary
->loads
->bases
3244 && !summary
->calls_interposable
)
3245 fixup_cfg
= ipa_make_function_const (fnode
,
3246 summary
->side_effects
, true);
3248 fixup_cfg
= ipa_make_function_pure (fnode
,
3249 summary
->side_effects
, true);
3252 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
3253 if (summary
&& !summary
->useful_p (ecf_flags
))
3256 optimization_summaries
->remove (fnode
);
3258 summaries
->remove (fnode
);
3262 summary
->finalize (current_function_decl
);
3263 if (summary_lto
&& !summary_lto
->useful_p (ecf_flags
))
3265 summaries_lto
->remove (fnode
);
3269 if (ipa
&& !summary
&& !summary_lto
)
3270 remove_modref_edge_summaries (fnode
);
3274 fprintf (dump_file
, " - modref done with result: tracked.\n");
3276 summary
->dump (dump_file
);
3278 summary_lto
->dump (dump_file
);
3279 dump_modref_edge_summaries (dump_file
, fnode
, 2);
3280 /* To simplify debugging, compare IPA and local solutions. */
3281 if (past_flags_known
&& summary
)
3283 size_t len
= summary
->arg_flags
.length ();
3285 if (past_flags
.length () > len
)
3286 len
= past_flags
.length ();
3287 for (size_t i
= 0; i
< len
; i
++)
3289 int old_flags
= i
< past_flags
.length () ? past_flags
[i
] : 0;
3290 int new_flags
= i
< summary
->arg_flags
.length ()
3291 ? summary
->arg_flags
[i
] : 0;
3292 old_flags
= remove_useless_eaf_flags
3293 (old_flags
, flags_from_decl_or_type (current_function_decl
),
3294 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3295 if (old_flags
!= new_flags
)
3297 if ((old_flags
& ~new_flags
) == 0
3298 || (new_flags
& EAF_UNUSED
))
3299 fprintf (dump_file
, " Flags for param %i improved:",
3302 fprintf (dump_file
, " Flags for param %i changed:",
3304 dump_eaf_flags (dump_file
, old_flags
, false);
3305 fprintf (dump_file
, " -> ");
3306 dump_eaf_flags (dump_file
, new_flags
, true);
3309 past_retslot_flags
= remove_useless_eaf_flags
3310 (past_retslot_flags
,
3311 flags_from_decl_or_type (current_function_decl
),
3312 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3313 if (past_retslot_flags
!= summary
->retslot_flags
)
3315 if ((past_retslot_flags
& ~summary
->retslot_flags
) == 0
3316 || (summary
->retslot_flags
& EAF_UNUSED
))
3317 fprintf (dump_file
, " Flags for retslot improved:");
3319 fprintf (dump_file
, " Flags for retslot changed:");
3320 dump_eaf_flags (dump_file
, past_retslot_flags
, false);
3321 fprintf (dump_file
, " -> ");
3322 dump_eaf_flags (dump_file
, summary
->retslot_flags
, true);
3324 past_static_chain_flags
= remove_useless_eaf_flags
3325 (past_static_chain_flags
,
3326 flags_from_decl_or_type (current_function_decl
),
3327 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3328 if (past_static_chain_flags
!= summary
->static_chain_flags
)
3330 if ((past_static_chain_flags
& ~summary
->static_chain_flags
) == 0
3331 || (summary
->static_chain_flags
& EAF_UNUSED
))
3332 fprintf (dump_file
, " Flags for static chain improved:");
3334 fprintf (dump_file
, " Flags for static chain changed:");
3335 dump_eaf_flags (dump_file
, past_static_chain_flags
, false);
3336 fprintf (dump_file
, " -> ");
3337 dump_eaf_flags (dump_file
, summary
->static_chain_flags
, true);
3340 else if (past_flags_known
&& !summary
)
3342 for (size_t i
= 0; i
< past_flags
.length (); i
++)
3344 int old_flags
= past_flags
[i
];
3345 old_flags
= remove_useless_eaf_flags
3346 (old_flags
, flags_from_decl_or_type (current_function_decl
),
3347 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3350 fprintf (dump_file
, " Flags for param %i worsened:",
3352 dump_eaf_flags (dump_file
, old_flags
, false);
3353 fprintf (dump_file
, " -> \n");
3356 past_retslot_flags
= remove_useless_eaf_flags
3357 (past_retslot_flags
,
3358 flags_from_decl_or_type (current_function_decl
),
3359 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3360 if (past_retslot_flags
)
3362 fprintf (dump_file
, " Flags for retslot worsened:");
3363 dump_eaf_flags (dump_file
, past_retslot_flags
, false);
3364 fprintf (dump_file
, " ->\n");
3366 past_static_chain_flags
= remove_useless_eaf_flags
3367 (past_static_chain_flags
,
3368 flags_from_decl_or_type (current_function_decl
),
3369 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3370 if (past_static_chain_flags
)
3372 fprintf (dump_file
, " Flags for static chain worsened:");
3373 dump_eaf_flags (dump_file
, past_static_chain_flags
, false);
3374 fprintf (dump_file
, " ->\n");
3381 /* Callback for generate_summary. */
3384 modref_generate (void)
3386 struct cgraph_node
*node
;
3387 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
3389 function
*f
= DECL_STRUCT_FUNCTION (node
->decl
);
3393 analyze_function (true);
3398 } /* ANON namespace. */
3400 /* Debugging helper. */
3403 debug_eaf_flags (int flags
)
3405 dump_eaf_flags (stderr
, flags
, true);
3408 /* Called when a new function is inserted to callgraph late. */
3411 modref_summaries::insert (struct cgraph_node
*node
, modref_summary
*)
3413 /* Local passes ought to be executed by the pass manager. */
3414 if (this == optimization_summaries
)
3416 optimization_summaries
->remove (node
);
3419 if (!DECL_STRUCT_FUNCTION (node
->decl
)
3420 || !opt_for_fn (node
->decl
, flag_ipa_modref
))
3422 summaries
->remove (node
);
3425 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
3426 analyze_function (true);
3430 /* Called when a new function is inserted to callgraph late. */
3433 modref_summaries_lto::insert (struct cgraph_node
*node
, modref_summary_lto
*)
3435 /* We do not support adding new function when IPA information is already
3436 propagated. This is done only by SIMD cloning that is not very
3438 if (!DECL_STRUCT_FUNCTION (node
->decl
)
3439 || !opt_for_fn (node
->decl
, flag_ipa_modref
)
3442 summaries_lto
->remove (node
);
3445 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
3446 analyze_function (true);
3450 /* Called when new clone is inserted to callgraph late. */
3453 modref_summaries::duplicate (cgraph_node
*, cgraph_node
*dst
,
3454 modref_summary
*src_data
,
3455 modref_summary
*dst_data
)
3457 /* Do not duplicate optimization summaries; we do not handle parameter
3458 transforms on them. */
3459 if (this == optimization_summaries
)
3461 optimization_summaries
->remove (dst
);
3464 dst_data
->stores
= modref_records::create_ggc ();
3465 dst_data
->stores
->copy_from (src_data
->stores
);
3466 dst_data
->loads
= modref_records::create_ggc ();
3467 dst_data
->loads
->copy_from (src_data
->loads
);
3468 dst_data
->kills
.reserve_exact (src_data
->kills
.length ());
3469 dst_data
->kills
.splice (src_data
->kills
);
3470 dst_data
->writes_errno
= src_data
->writes_errno
;
3471 dst_data
->side_effects
= src_data
->side_effects
;
3472 dst_data
->nondeterministic
= src_data
->nondeterministic
;
3473 dst_data
->calls_interposable
= src_data
->calls_interposable
;
3474 if (src_data
->arg_flags
.length ())
3475 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
3476 dst_data
->retslot_flags
= src_data
->retslot_flags
;
3477 dst_data
->static_chain_flags
= src_data
->static_chain_flags
;
3480 /* Called when new clone is inserted to callgraph late. */
3483 modref_summaries_lto::duplicate (cgraph_node
*, cgraph_node
*,
3484 modref_summary_lto
*src_data
,
3485 modref_summary_lto
*dst_data
)
3487 /* Be sure that no further cloning happens after ipa-modref. If it does
3488 we will need to update signatures for possible param changes. */
3489 gcc_checking_assert (!((modref_summaries_lto
*)summaries_lto
)->propagated
);
3490 dst_data
->stores
= modref_records_lto::create_ggc ();
3491 dst_data
->stores
->copy_from (src_data
->stores
);
3492 dst_data
->loads
= modref_records_lto::create_ggc ();
3493 dst_data
->loads
->copy_from (src_data
->loads
);
3494 dst_data
->kills
.reserve_exact (src_data
->kills
.length ());
3495 dst_data
->kills
.splice (src_data
->kills
);
3496 dst_data
->writes_errno
= src_data
->writes_errno
;
3497 dst_data
->side_effects
= src_data
->side_effects
;
3498 dst_data
->nondeterministic
= src_data
->nondeterministic
;
3499 dst_data
->calls_interposable
= src_data
->calls_interposable
;
3500 if (src_data
->arg_flags
.length ())
3501 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
3502 dst_data
->retslot_flags
= src_data
->retslot_flags
;
3503 dst_data
->static_chain_flags
= src_data
->static_chain_flags
;
3508 /* Definition of the modref pass on GIMPLE. */
3509 const pass_data pass_data_modref
= {
3514 (PROP_cfg
| PROP_ssa
),
3521 class pass_modref
: public gimple_opt_pass
3524 pass_modref (gcc::context
*ctxt
)
3525 : gimple_opt_pass (pass_data_modref
, ctxt
) {}
3527 /* opt_pass methods: */
3528 opt_pass
*clone () final override
3530 return new pass_modref (m_ctxt
);
3532 bool gate (function
*) final override
3534 return flag_ipa_modref
;
3536 unsigned int execute (function
*) final override
;
3539 /* Encode TT to the output block OB using the summary streaming API. */
3542 write_modref_records (modref_records_lto
*tt
, struct output_block
*ob
)
3544 streamer_write_uhwi (ob
, tt
->every_base
);
3545 streamer_write_uhwi (ob
, vec_safe_length (tt
->bases
));
3546 for (auto base_node
: tt
->bases
)
3548 stream_write_tree (ob
, base_node
->base
, true);
3550 streamer_write_uhwi (ob
, base_node
->every_ref
);
3551 streamer_write_uhwi (ob
, vec_safe_length (base_node
->refs
));
3553 for (auto ref_node
: base_node
->refs
)
3555 stream_write_tree (ob
, ref_node
->ref
, true);
3556 streamer_write_uhwi (ob
, ref_node
->every_access
);
3557 streamer_write_uhwi (ob
, vec_safe_length (ref_node
->accesses
));
3559 for (auto access_node
: ref_node
->accesses
)
3560 access_node
.stream_out (ob
);
3565 /* Read a modref_tree from the input block IB using the data from DATA_IN.
3566 This assumes that the tree was encoded using write_modref_tree.
3567 Either nolto_ret or lto_ret is initialized by the tree depending whether
3568 LTO streaming is expected or not. */
3571 read_modref_records (tree decl
,
3572 lto_input_block
*ib
, struct data_in
*data_in
,
3573 modref_records
**nolto_ret
,
3574 modref_records_lto
**lto_ret
)
3576 size_t max_bases
= opt_for_fn (decl
, param_modref_max_bases
);
3577 size_t max_refs
= opt_for_fn (decl
, param_modref_max_refs
);
3578 size_t max_accesses
= opt_for_fn (decl
, param_modref_max_accesses
);
3581 *lto_ret
= modref_records_lto::create_ggc ();
3583 *nolto_ret
= modref_records::create_ggc ();
3584 gcc_checking_assert (lto_ret
|| nolto_ret
);
3586 size_t every_base
= streamer_read_uhwi (ib
);
3587 size_t nbase
= streamer_read_uhwi (ib
);
3589 gcc_assert (!every_base
|| nbase
== 0);
3593 (*nolto_ret
)->collapse ();
3595 (*lto_ret
)->collapse ();
3597 for (size_t i
= 0; i
< nbase
; i
++)
3599 tree base_tree
= stream_read_tree (ib
, data_in
);
3600 modref_base_node
<alias_set_type
> *nolto_base_node
= NULL
;
3601 modref_base_node
<tree
> *lto_base_node
= NULL
;
3603 /* At stream in time we have LTO alias info. Check if we streamed in
3604 something obviously unnecessary. Do not glob types by alias sets;
3605 it is not 100% clear that ltrans types will get merged same way.
3606 Types may get refined based on ODR type conflicts. */
3607 if (base_tree
&& !get_alias_set (base_tree
))
3611 fprintf (dump_file
, "Streamed in alias set 0 type ");
3612 print_generic_expr (dump_file
, base_tree
);
3613 fprintf (dump_file
, "\n");
3619 nolto_base_node
= (*nolto_ret
)->insert_base (base_tree
3620 ? get_alias_set (base_tree
)
3623 lto_base_node
= (*lto_ret
)->insert_base (base_tree
, 0, max_bases
);
3624 size_t every_ref
= streamer_read_uhwi (ib
);
3625 size_t nref
= streamer_read_uhwi (ib
);
3627 gcc_assert (!every_ref
|| nref
== 0);
3630 if (nolto_base_node
)
3631 nolto_base_node
->collapse ();
3633 lto_base_node
->collapse ();
3635 for (size_t j
= 0; j
< nref
; j
++)
3637 tree ref_tree
= stream_read_tree (ib
, data_in
);
3639 if (ref_tree
&& !get_alias_set (ref_tree
))
3643 fprintf (dump_file
, "Streamed in alias set 0 type ");
3644 print_generic_expr (dump_file
, ref_tree
);
3645 fprintf (dump_file
, "\n");
3650 modref_ref_node
<alias_set_type
> *nolto_ref_node
= NULL
;
3651 modref_ref_node
<tree
> *lto_ref_node
= NULL
;
3653 if (nolto_base_node
)
3655 = nolto_base_node
->insert_ref (ref_tree
3656 ? get_alias_set (ref_tree
) : 0,
3659 lto_ref_node
= lto_base_node
->insert_ref (ref_tree
, max_refs
);
3661 size_t every_access
= streamer_read_uhwi (ib
);
3662 size_t naccesses
= streamer_read_uhwi (ib
);
3664 if (nolto_ref_node
&& every_access
)
3665 nolto_ref_node
->collapse ();
3666 if (lto_ref_node
&& every_access
)
3667 lto_ref_node
->collapse ();
3669 for (size_t k
= 0; k
< naccesses
; k
++)
3671 modref_access_node a
= modref_access_node::stream_in (ib
);
3673 nolto_ref_node
->insert_access (a
, max_accesses
, false);
3675 lto_ref_node
->insert_access (a
, max_accesses
, false);
3680 (*lto_ret
)->cleanup ();
3682 (*nolto_ret
)->cleanup ();
3685 /* Write ESUM to BP. */
3688 modref_write_escape_summary (struct bitpack_d
*bp
, escape_summary
*esum
)
3692 bp_pack_var_len_unsigned (bp
, 0);
3695 bp_pack_var_len_unsigned (bp
, esum
->esc
.length ());
3698 FOR_EACH_VEC_ELT (esum
->esc
, i
, ee
)
3700 bp_pack_var_len_int (bp
, ee
->parm_index
);
3701 bp_pack_var_len_unsigned (bp
, ee
->arg
);
3702 bp_pack_var_len_unsigned (bp
, ee
->min_flags
);
3703 bp_pack_value (bp
, ee
->direct
, 1);
3707 /* Read escape summary for E from BP. */
3710 modref_read_escape_summary (struct bitpack_d
*bp
, cgraph_edge
*e
)
3712 unsigned int n
= bp_unpack_var_len_unsigned (bp
);
3715 escape_summary
*esum
= escape_summaries
->get_create (e
);
3716 esum
->esc
.reserve_exact (n
);
3717 for (unsigned int i
= 0; i
< n
; i
++)
3720 ee
.parm_index
= bp_unpack_var_len_int (bp
);
3721 ee
.arg
= bp_unpack_var_len_unsigned (bp
);
3722 ee
.min_flags
= bp_unpack_var_len_unsigned (bp
);
3723 ee
.direct
= bp_unpack_value (bp
, 1);
3724 esum
->esc
.quick_push (ee
);
3728 /* Callback for write_summary. */
3733 struct output_block
*ob
= create_output_block (LTO_section_ipa_modref
);
3734 lto_symtab_encoder_t encoder
= ob
->decl_state
->symtab_node_encoder
;
3735 unsigned int count
= 0;
3740 streamer_write_uhwi (ob
, 0);
3741 streamer_write_char_stream (ob
->main_stream
, 0);
3742 produce_asm (ob
, NULL
);
3743 destroy_output_block (ob
);
3747 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
3749 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
3750 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
3751 modref_summary_lto
*r
;
3753 if (cnode
&& cnode
->definition
&& !cnode
->alias
3754 && (r
= summaries_lto
->get (cnode
))
3755 && r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
3758 streamer_write_uhwi (ob
, count
);
3760 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
3762 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
3763 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
3765 if (cnode
&& cnode
->definition
&& !cnode
->alias
)
3767 modref_summary_lto
*r
= summaries_lto
->get (cnode
);
3769 if (!r
|| !r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
3772 streamer_write_uhwi (ob
, lto_symtab_encoder_encode (encoder
, cnode
));
3774 streamer_write_uhwi (ob
, r
->arg_flags
.length ());
3775 for (unsigned int i
= 0; i
< r
->arg_flags
.length (); i
++)
3776 streamer_write_uhwi (ob
, r
->arg_flags
[i
]);
3777 streamer_write_uhwi (ob
, r
->retslot_flags
);
3778 streamer_write_uhwi (ob
, r
->static_chain_flags
);
3780 write_modref_records (r
->loads
, ob
);
3781 write_modref_records (r
->stores
, ob
);
3782 streamer_write_uhwi (ob
, r
->kills
.length ());
3783 for (auto kill
: r
->kills
)
3784 kill
.stream_out (ob
);
3786 struct bitpack_d bp
= bitpack_create (ob
->main_stream
);
3787 bp_pack_value (&bp
, r
->writes_errno
, 1);
3788 bp_pack_value (&bp
, r
->side_effects
, 1);
3789 bp_pack_value (&bp
, r
->nondeterministic
, 1);
3790 bp_pack_value (&bp
, r
->calls_interposable
, 1);
3793 for (cgraph_edge
*e
= cnode
->indirect_calls
;
3794 e
; e
= e
->next_callee
)
3796 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
3797 bp_pack_value (&bp
, sum
!= NULL
, 1);
3799 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
3800 class escape_summary
*esum
= escape_summaries
->get (e
);
3801 modref_write_escape_summary (&bp
,esum
);
3803 for (cgraph_edge
*e
= cnode
->callees
; e
; e
= e
->next_callee
)
3805 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
3806 bp_pack_value (&bp
, sum
!= NULL
, 1);
3808 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
3809 class escape_summary
*esum
= escape_summaries
->get (e
);
3810 modref_write_escape_summary (&bp
,esum
);
3813 streamer_write_bitpack (&bp
);
3816 streamer_write_char_stream (ob
->main_stream
, 0);
3817 produce_asm (ob
, NULL
);
3818 destroy_output_block (ob
);
3822 read_section (struct lto_file_decl_data
*file_data
, const char *data
,
3825 const struct lto_function_header
*header
3826 = (const struct lto_function_header
*) data
;
3827 const int cfg_offset
= sizeof (struct lto_function_header
);
3828 const int main_offset
= cfg_offset
+ header
->cfg_size
;
3829 const int string_offset
= main_offset
+ header
->main_size
;
3830 struct data_in
*data_in
;
3832 unsigned int f_count
;
3834 lto_input_block
ib ((const char *) data
+ main_offset
, header
->main_size
,
3838 = lto_data_in_create (file_data
, (const char *) data
+ string_offset
,
3839 header
->string_size
, vNULL
);
3840 f_count
= streamer_read_uhwi (&ib
);
3841 for (i
= 0; i
< f_count
; i
++)
3843 struct cgraph_node
*node
;
3844 lto_symtab_encoder_t encoder
;
3846 unsigned int index
= streamer_read_uhwi (&ib
);
3847 encoder
= file_data
->symtab_node_encoder
;
3848 node
= dyn_cast
<cgraph_node
*> (lto_symtab_encoder_deref (encoder
,
3851 modref_summary
*modref_sum
= summaries
3852 ? summaries
->get_create (node
) : NULL
;
3853 modref_summary_lto
*modref_sum_lto
= summaries_lto
3854 ? summaries_lto
->get_create (node
)
3856 if (optimization_summaries
)
3857 modref_sum
= optimization_summaries
->get_create (node
);
3861 modref_sum
->writes_errno
= false;
3862 modref_sum
->side_effects
= false;
3863 modref_sum
->nondeterministic
= false;
3864 modref_sum
->calls_interposable
= false;
3868 modref_sum_lto
->writes_errno
= false;
3869 modref_sum_lto
->side_effects
= false;
3870 modref_sum_lto
->nondeterministic
= false;
3871 modref_sum_lto
->calls_interposable
= false;
3874 gcc_assert (!modref_sum
|| (!modref_sum
->loads
3875 && !modref_sum
->stores
));
3876 gcc_assert (!modref_sum_lto
|| (!modref_sum_lto
->loads
3877 && !modref_sum_lto
->stores
));
3878 unsigned int args
= streamer_read_uhwi (&ib
);
3879 if (args
&& modref_sum
)
3880 modref_sum
->arg_flags
.reserve_exact (args
);
3881 if (args
&& modref_sum_lto
)
3882 modref_sum_lto
->arg_flags
.reserve_exact (args
);
3883 for (unsigned int i
= 0; i
< args
; i
++)
3885 eaf_flags_t flags
= streamer_read_uhwi (&ib
);
3887 modref_sum
->arg_flags
.quick_push (flags
);
3889 modref_sum_lto
->arg_flags
.quick_push (flags
);
3891 eaf_flags_t flags
= streamer_read_uhwi (&ib
);
3893 modref_sum
->retslot_flags
= flags
;
3895 modref_sum_lto
->retslot_flags
= flags
;
3897 flags
= streamer_read_uhwi (&ib
);
3899 modref_sum
->static_chain_flags
= flags
;
3901 modref_sum_lto
->static_chain_flags
= flags
;
3903 read_modref_records (node
->decl
, &ib
, data_in
,
3904 modref_sum
? &modref_sum
->loads
: NULL
,
3905 modref_sum_lto
? &modref_sum_lto
->loads
: NULL
);
3906 read_modref_records (node
->decl
, &ib
, data_in
,
3907 modref_sum
? &modref_sum
->stores
: NULL
,
3908 modref_sum_lto
? &modref_sum_lto
->stores
: NULL
);
3909 int j
= streamer_read_uhwi (&ib
);
3910 if (j
&& modref_sum
)
3911 modref_sum
->kills
.reserve_exact (j
);
3912 if (j
&& modref_sum_lto
)
3913 modref_sum_lto
->kills
.reserve_exact (j
);
3914 for (int k
= 0; k
< j
; k
++)
3916 modref_access_node a
= modref_access_node::stream_in (&ib
);
3919 modref_sum
->kills
.quick_push (a
);
3921 modref_sum_lto
->kills
.quick_push (a
);
3923 struct bitpack_d bp
= streamer_read_bitpack (&ib
);
3924 if (bp_unpack_value (&bp
, 1))
3927 modref_sum
->writes_errno
= true;
3929 modref_sum_lto
->writes_errno
= true;
3931 if (bp_unpack_value (&bp
, 1))
3934 modref_sum
->side_effects
= true;
3936 modref_sum_lto
->side_effects
= true;
3938 if (bp_unpack_value (&bp
, 1))
3941 modref_sum
->nondeterministic
= true;
3943 modref_sum_lto
->nondeterministic
= true;
3945 if (bp_unpack_value (&bp
, 1))
3948 modref_sum
->calls_interposable
= true;
3950 modref_sum_lto
->calls_interposable
= true;
3954 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
3956 if (bp_unpack_value (&bp
, 1))
3958 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
3959 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
3961 modref_read_escape_summary (&bp
, e
);
3963 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
3965 if (bp_unpack_value (&bp
, 1))
3967 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
3968 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
3970 modref_read_escape_summary (&bp
, e
);
3974 modref_sum
->finalize (node
->decl
);
3977 fprintf (dump_file
, "Read modref for %s\n",
3978 node
->dump_name ());
3980 modref_sum
->dump (dump_file
);
3982 modref_sum_lto
->dump (dump_file
);
3983 dump_modref_edge_summaries (dump_file
, node
, 4);
3987 lto_free_section_data (file_data
, LTO_section_ipa_modref
, NULL
, data
,
3989 lto_data_in_delete (data_in
);
3992 /* Callback for read_summary. */
3997 struct lto_file_decl_data
**file_data_vec
= lto_get_file_decl_data ();
3998 struct lto_file_decl_data
*file_data
;
4001 gcc_checking_assert (!optimization_summaries
&& !summaries
&& !summaries_lto
);
4003 optimization_summaries
= modref_summaries::create_ggc (symtab
);
4006 if (flag_wpa
|| flag_incremental_link
== INCREMENTAL_LINK_LTO
)
4007 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
4009 || (flag_incremental_link
== INCREMENTAL_LINK_LTO
4010 && flag_fat_lto_objects
))
4011 summaries
= modref_summaries::create_ggc (symtab
);
4012 if (!fnspec_summaries
)
4013 fnspec_summaries
= new fnspec_summaries_t (symtab
);
4014 if (!escape_summaries
)
4015 escape_summaries
= new escape_summaries_t (symtab
);
4018 while ((file_data
= file_data_vec
[j
++]))
4021 const char *data
= lto_get_summary_section_data (file_data
,
4022 LTO_section_ipa_modref
,
4025 read_section (file_data
, data
, len
);
4027 /* Fatal error here. We do not want to support compiling ltrans units
4028 with different version of compiler or different flags than the WPA
4029 unit, so this should never happen. */
4030 fatal_error (input_location
,
4031 "IPA modref summary is missing in input file");
4035 /* Recompute arg_flags for param adjustments in INFO. */
4038 remap_arg_flags (auto_vec
<eaf_flags_t
> &arg_flags
, clone_info
*info
)
4040 auto_vec
<eaf_flags_t
> old
= arg_flags
.copy ();
4043 ipa_adjusted_param
*p
;
4045 arg_flags
.release ();
4047 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
4049 int o
= info
->param_adjustments
->get_original_index (i
);
4050 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
4054 arg_flags
.safe_grow_cleared (max
+ 1, true);
4055 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
4057 int o
= info
->param_adjustments
->get_original_index (i
);
4058 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
4059 arg_flags
[i
] = old
[o
];
4063 /* Update kills according to the parm map MAP. */
4066 remap_kills (vec
<modref_access_node
> &kills
, const vec
<int> &map
)
4068 for (size_t i
= 0; i
< kills
.length ();)
4069 if (kills
[i
].parm_index
>= 0)
4071 if (kills
[i
].parm_index
< (int)map
.length ()
4072 && map
[kills
[i
].parm_index
] != MODREF_UNKNOWN_PARM
)
4074 kills
[i
].parm_index
= map
[kills
[i
].parm_index
];
4078 kills
.unordered_remove (i
);
4084 /* Return true if the V can overlap with KILL. */
4087 ipcp_argagg_and_kill_overlap_p (const ipa_argagg_value
&v
,
4088 const modref_access_node
&kill
)
4090 if (kill
.parm_index
== v
.index
)
4092 gcc_assert (kill
.parm_offset_known
);
4093 gcc_assert (known_eq (kill
.max_size
, kill
.size
));
4094 poly_int64 repl_size
;
4095 bool ok
= poly_int_tree_p (TYPE_SIZE (TREE_TYPE (v
.value
)),
4098 poly_int64
repl_offset (v
.unit_offset
);
4099 repl_offset
<<= LOG2_BITS_PER_UNIT
;
4100 poly_int64 combined_offset
4101 = (kill
.parm_offset
<< LOG2_BITS_PER_UNIT
) + kill
.offset
;
4102 if (ranges_maybe_overlap_p (repl_offset
, repl_size
,
4103 combined_offset
, kill
.size
))
4109 /* If signature changed, update the summary. */
4112 update_signature (struct cgraph_node
*node
)
4114 modref_summary
*r
= optimization_summaries
4115 ? optimization_summaries
->get (node
) : NULL
;
4116 modref_summary_lto
*r_lto
= summaries_lto
4117 ? summaries_lto
->get (node
) : NULL
;
4121 /* Propagating constants in killed memory can lead to eliminated stores in
4122 both callees (because they are considered redundant) and callers, leading
4123 to missing them altogether. */
4124 ipcp_transformation
*ipcp_ts
= ipcp_get_transformation_summary (node
);
4127 for (auto &v
: ipcp_ts
->m_agg_values
)
4132 for (const modref_access_node
&kill
: r
->kills
)
4133 if (ipcp_argagg_and_kill_overlap_p (v
, kill
))
4138 if (!v
.killed
&& r_lto
)
4139 for (const modref_access_node
&kill
: r_lto
->kills
)
4140 if (ipcp_argagg_and_kill_overlap_p (v
, kill
))
4148 clone_info
*info
= clone_info::get (node
);
4149 if (!info
|| !info
->param_adjustments
)
4154 fprintf (dump_file
, "Updating summary for %s from:\n",
4155 node
->dump_name ());
4157 r
->dump (dump_file
);
4159 r_lto
->dump (dump_file
);
4163 ipa_adjusted_param
*p
;
4165 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
4167 int idx
= info
->param_adjustments
->get_original_index (i
);
4172 auto_vec
<int, 32> map
;
4174 map
.reserve (max
+ 1);
4175 for (i
= 0; i
<= max
; i
++)
4176 map
.quick_push (MODREF_UNKNOWN_PARM
);
4177 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
4179 int idx
= info
->param_adjustments
->get_original_index (i
);
4185 r
->loads
->remap_params (&map
);
4186 r
->stores
->remap_params (&map
);
4187 remap_kills (r
->kills
, map
);
4188 if (r
->arg_flags
.length ())
4189 remap_arg_flags (r
->arg_flags
, info
);
4193 r_lto
->loads
->remap_params (&map
);
4194 r_lto
->stores
->remap_params (&map
);
4195 remap_kills (r_lto
->kills
, map
);
4196 if (r_lto
->arg_flags
.length ())
4197 remap_arg_flags (r_lto
->arg_flags
, info
);
4201 fprintf (dump_file
, "to:\n");
4203 r
->dump (dump_file
);
4205 r_lto
->dump (dump_file
);
4208 r
->finalize (node
->decl
);
4212 /* Definition of the modref IPA pass. */
4213 const pass_data pass_data_ipa_modref
=
4215 IPA_PASS
, /* type */
4216 "modref", /* name */
4217 OPTGROUP_IPA
, /* optinfo_flags */
4218 TV_IPA_MODREF
, /* tv_id */
4219 0, /* properties_required */
4220 0, /* properties_provided */
4221 0, /* properties_destroyed */
4222 0, /* todo_flags_start */
4223 ( TODO_dump_symtab
), /* todo_flags_finish */
4226 class pass_ipa_modref
: public ipa_opt_pass_d
4229 pass_ipa_modref (gcc::context
*ctxt
)
4230 : ipa_opt_pass_d (pass_data_ipa_modref
, ctxt
,
4231 modref_generate
, /* generate_summary */
4232 modref_write
, /* write_summary */
4233 modref_read
, /* read_summary */
4234 modref_write
, /* write_optimization_summary */
4235 modref_read
, /* read_optimization_summary */
4236 NULL
, /* stmt_fixup */
4237 0, /* function_transform_todo_flags_start */
4238 NULL
, /* function_transform */
4239 NULL
) /* variable_transform */
4242 /* opt_pass methods: */
4243 opt_pass
*clone () final override
{ return new pass_ipa_modref (m_ctxt
); }
4244 bool gate (function
*) final override
4248 unsigned int execute (function
*) final override
;
4254 unsigned int pass_modref::execute (function
*)
4256 if (analyze_function (false))
4257 return execute_fixup_cfg ();
4262 make_pass_modref (gcc::context
*ctxt
)
4264 return new pass_modref (ctxt
);
4268 make_pass_ipa_modref (gcc::context
*ctxt
)
4270 return new pass_ipa_modref (ctxt
);
4275 /* Skip edges from and to nodes without ipa_pure_const enabled.
4276 Ignore not available symbols. */
4279 ignore_edge (struct cgraph_edge
*e
)
4281 /* We merge summaries of inline clones into summaries of functions they
4282 are inlined to. For that reason the complete function bodies must
4284 if (!e
->inline_failed
)
4286 enum availability avail
;
4287 cgraph_node
*callee
= e
->callee
->ultimate_alias_target
4288 (&avail
, e
->caller
);
4290 return (avail
<= AVAIL_INTERPOSABLE
4291 || ((!optimization_summaries
|| !optimization_summaries
->get (callee
))
4292 && (!summaries_lto
|| !summaries_lto
->get (callee
))));
4295 /* Compute parm_map for CALLEE_EDGE. */
4298 compute_parm_map (cgraph_edge
*callee_edge
, vec
<modref_parm_map
> *parm_map
)
4300 class ipa_edge_args
*args
;
4301 if (ipa_node_params_sum
4302 && !callee_edge
->call_stmt_cannot_inline_p
4303 && (args
= ipa_edge_args_sum
->get (callee_edge
)) != NULL
)
4305 int i
, count
= ipa_get_cs_argument_count (args
);
4306 class ipa_node_params
*caller_parms_info
, *callee_pi
;
4307 class ipa_call_summary
*es
4308 = ipa_call_summaries
->get (callee_edge
);
4310 = callee_edge
->callee
->ultimate_alias_target
4311 (NULL
, callee_edge
->caller
);
4314 = ipa_node_params_sum
->get (callee_edge
->caller
->inlined_to
4315 ? callee_edge
->caller
->inlined_to
4316 : callee_edge
->caller
);
4317 callee_pi
= ipa_node_params_sum
->get (callee
);
4319 (*parm_map
).safe_grow_cleared (count
, true);
4321 for (i
= 0; i
< count
; i
++)
4323 if (es
&& es
->param
[i
].points_to_local_or_readonly_memory
)
4325 (*parm_map
)[i
].parm_index
= MODREF_LOCAL_MEMORY_PARM
;
4329 struct ipa_jump_func
*jf
4330 = ipa_get_ith_jump_func (args
, i
);
4331 if (jf
&& callee_pi
)
4333 tree cst
= ipa_value_from_jfunc (caller_parms_info
,
4337 if (cst
&& points_to_local_or_readonly_memory_p (cst
))
4339 (*parm_map
)[i
].parm_index
= MODREF_LOCAL_MEMORY_PARM
;
4343 if (jf
&& jf
->type
== IPA_JF_PASS_THROUGH
)
4345 (*parm_map
)[i
].parm_index
4346 = ipa_get_jf_pass_through_formal_id (jf
);
4347 if (ipa_get_jf_pass_through_operation (jf
) == NOP_EXPR
)
4349 (*parm_map
)[i
].parm_offset_known
= true;
4350 (*parm_map
)[i
].parm_offset
= 0;
4352 else if (ipa_get_jf_pass_through_operation (jf
)
4353 == POINTER_PLUS_EXPR
4354 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf
),
4355 &(*parm_map
)[i
].parm_offset
))
4356 (*parm_map
)[i
].parm_offset_known
= true;
4358 (*parm_map
)[i
].parm_offset_known
= false;
4361 if (jf
&& jf
->type
== IPA_JF_ANCESTOR
)
4363 (*parm_map
)[i
].parm_index
= ipa_get_jf_ancestor_formal_id (jf
);
4364 (*parm_map
)[i
].parm_offset_known
= true;
4366 (!(ipa_get_jf_ancestor_offset (jf
) & (BITS_PER_UNIT
- 1)));
4367 (*parm_map
)[i
].parm_offset
4368 = ipa_get_jf_ancestor_offset (jf
) >> LOG2_BITS_PER_UNIT
;
4371 (*parm_map
)[i
].parm_index
= -1;
4375 fprintf (dump_file
, " Parm map: ");
4376 for (i
= 0; i
< count
; i
++)
4377 fprintf (dump_file
, " %i", (*parm_map
)[i
].parm_index
);
4378 fprintf (dump_file
, "\n");
4385 /* Map used to translate escape infos. */
4393 /* Update escape map for E. */
4396 update_escape_summary_1 (cgraph_edge
*e
,
4397 vec
<vec
<escape_map
>> &map
,
4400 escape_summary
*sum
= escape_summaries
->get (e
);
4403 auto_vec
<escape_entry
> old
= sum
->esc
.copy ();
4404 sum
->esc
.release ();
4408 FOR_EACH_VEC_ELT (old
, i
, ee
)
4411 struct escape_map
*em
;
4412 /* TODO: We do not have jump functions for return slots, so we
4413 never propagate them to outer function. */
4414 if (ee
->parm_index
>= (int)map
.length ()
4415 || ee
->parm_index
< 0)
4417 FOR_EACH_VEC_ELT (map
[ee
->parm_index
], j
, em
)
4419 eaf_flags_t min_flags
= ee
->min_flags
;
4420 if (ee
->direct
&& !em
->direct
)
4421 min_flags
= deref_flags (min_flags
, ignore_stores
);
4422 struct escape_entry entry
= {em
->parm_index
, ee
->arg
,
4424 ee
->direct
&& em
->direct
};
4425 sum
->esc
.safe_push (entry
);
4428 if (!sum
->esc
.length ())
4429 escape_summaries
->remove (e
);
4432 /* Update escape map for NODE. */
4435 update_escape_summary (cgraph_node
*node
,
4436 vec
<vec
<escape_map
>> &map
,
4439 if (!escape_summaries
)
4441 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
4442 update_escape_summary_1 (e
, map
, ignore_stores
);
4443 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
4445 if (!e
->inline_failed
)
4446 update_escape_summary (e
->callee
, map
, ignore_stores
);
4448 update_escape_summary_1 (e
, map
, ignore_stores
);
4452 /* Get parameter type from DECL. This is only safe for special cases
4453 like builtins we create fnspec for because the type match is checked
4454 at fnspec creation time. */
4457 get_parm_type (tree decl
, unsigned int i
)
4459 tree t
= TYPE_ARG_TYPES (TREE_TYPE (decl
));
4461 for (unsigned int p
= 0; p
< i
; p
++)
4463 return TREE_VALUE (t
);
4466 /* Return access mode for argument I of call E with FNSPEC. */
4468 static modref_access_node
4469 get_access_for_fnspec (cgraph_edge
*e
, attr_fnspec
&fnspec
,
4470 unsigned int i
, modref_parm_map
&map
)
4472 tree size
= NULL_TREE
;
4473 unsigned int size_arg
;
4475 if (!fnspec
.arg_specified_p (i
))
4477 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
4479 cgraph_node
*node
= e
->caller
->inlined_to
4480 ? e
->caller
->inlined_to
: e
->caller
;
4481 ipa_node_params
*caller_parms_info
= ipa_node_params_sum
->get (node
);
4482 ipa_edge_args
*args
= ipa_edge_args_sum
->get (e
);
4483 struct ipa_jump_func
*jf
= ipa_get_ith_jump_func (args
, size_arg
);
4486 size
= ipa_value_from_jfunc (caller_parms_info
, jf
,
4487 get_parm_type (e
->callee
->decl
, size_arg
));
4489 else if (fnspec
.arg_access_size_given_by_type_p (i
))
4490 size
= TYPE_SIZE_UNIT (get_parm_type (e
->callee
->decl
, i
));
4491 modref_access_node a
= {0, -1, -1,
4492 map
.parm_offset
, map
.parm_index
,
4493 map
.parm_offset_known
, 0};
4494 poly_int64 size_hwi
;
4496 && poly_int_tree_p (size
, &size_hwi
)
4497 && coeffs_in_range_p (size_hwi
, 0,
4498 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
4501 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
4506 /* Collapse loads and return true if something changed. */
4508 collapse_loads (modref_summary
*cur_summary
,
4509 modref_summary_lto
*cur_summary_lto
)
4511 bool changed
= false;
4513 if (cur_summary
&& !cur_summary
->loads
->every_base
)
4515 cur_summary
->loads
->collapse ();
4519 && !cur_summary_lto
->loads
->every_base
)
4521 cur_summary_lto
->loads
->collapse ();
4527 /* Collapse loads and return true if something changed. */
4530 collapse_stores (modref_summary
*cur_summary
,
4531 modref_summary_lto
*cur_summary_lto
)
4533 bool changed
= false;
4535 if (cur_summary
&& !cur_summary
->stores
->every_base
)
4537 cur_summary
->stores
->collapse ();
4541 && !cur_summary_lto
->stores
->every_base
)
4543 cur_summary_lto
->stores
->collapse ();
4549 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
4550 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
4553 propagate_unknown_call (cgraph_node
*node
,
4554 cgraph_edge
*e
, int ecf_flags
,
4555 modref_summary
*cur_summary
,
4556 modref_summary_lto
*cur_summary_lto
,
4557 bool nontrivial_scc
)
4559 bool changed
= false;
4560 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
4561 auto_vec
<modref_parm_map
, 32> parm_map
;
4565 && builtin_safe_for_const_function_p (&looping
, e
->callee
->decl
))
4567 if (looping
&& cur_summary
&& !cur_summary
->side_effects
)
4569 cur_summary
->side_effects
= true;
4572 if (looping
&& cur_summary_lto
&& !cur_summary_lto
->side_effects
)
4574 cur_summary_lto
->side_effects
= true;
4580 if (!(ecf_flags
& (ECF_CONST
| ECF_PURE
))
4581 || (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
)
4584 if (cur_summary
&& !cur_summary
->side_effects
)
4586 cur_summary
->side_effects
= true;
4589 if (cur_summary_lto
&& !cur_summary_lto
->side_effects
)
4591 cur_summary_lto
->side_effects
= true;
4594 if (cur_summary
&& !cur_summary
->nondeterministic
4595 && !ignore_nondeterminism_p (node
->decl
, ecf_flags
))
4597 cur_summary
->nondeterministic
= true;
4600 if (cur_summary_lto
&& !cur_summary_lto
->nondeterministic
4601 && !ignore_nondeterminism_p (node
->decl
, ecf_flags
))
4603 cur_summary_lto
->nondeterministic
= true;
4607 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
4611 && compute_parm_map (e
, &parm_map
))
4613 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
4615 gcc_checking_assert (fnspec
.known_p ());
4616 if (fnspec
.global_memory_read_p ())
4617 collapse_loads (cur_summary
, cur_summary_lto
);
4620 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
4621 for (unsigned i
= 0; i
< parm_map
.length () && t
;
4622 i
++, t
= TREE_CHAIN (t
))
4623 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
4625 else if (!fnspec
.arg_specified_p (i
)
4626 || fnspec
.arg_maybe_read_p (i
))
4628 modref_parm_map map
= parm_map
[i
];
4629 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
4631 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
4633 collapse_loads (cur_summary
, cur_summary_lto
);
4637 changed
|= cur_summary
->loads
->insert
4639 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4640 if (cur_summary_lto
)
4641 changed
|= cur_summary_lto
->loads
->insert
4643 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4646 if (ignore_stores_p (node
->decl
, ecf_flags
))
4648 else if (fnspec
.global_memory_written_p ())
4649 collapse_stores (cur_summary
, cur_summary_lto
);
4652 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
4653 for (unsigned i
= 0; i
< parm_map
.length () && t
;
4654 i
++, t
= TREE_CHAIN (t
))
4655 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
4657 else if (!fnspec
.arg_specified_p (i
)
4658 || fnspec
.arg_maybe_written_p (i
))
4660 modref_parm_map map
= parm_map
[i
];
4661 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
4663 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
4665 collapse_stores (cur_summary
, cur_summary_lto
);
4669 changed
|= cur_summary
->stores
->insert
4671 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4672 if (cur_summary_lto
)
4673 changed
|= cur_summary_lto
->stores
->insert
4675 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4678 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
4680 if (cur_summary
&& !cur_summary
->writes_errno
)
4682 cur_summary
->writes_errno
= true;
4685 if (cur_summary_lto
&& !cur_summary_lto
->writes_errno
)
4687 cur_summary_lto
->writes_errno
= true;
4694 fprintf (dump_file
, " collapsing loads\n");
4695 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
4696 if (!ignore_stores_p (node
->decl
, ecf_flags
))
4699 fprintf (dump_file
, " collapsing stores\n");
4700 changed
|= collapse_stores (cur_summary
, cur_summary_lto
);
4705 /* Maybe remove summaries of NODE pointed to by CUR_SUMMARY_PTR
4706 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
4709 remove_useless_summaries (cgraph_node
*node
,
4710 modref_summary
**cur_summary_ptr
,
4711 modref_summary_lto
**cur_summary_lto_ptr
,
4714 if (*cur_summary_ptr
&& !(*cur_summary_ptr
)->useful_p (ecf_flags
, false))
4716 optimization_summaries
->remove (node
);
4717 *cur_summary_ptr
= NULL
;
4719 if (*cur_summary_lto_ptr
4720 && !(*cur_summary_lto_ptr
)->useful_p (ecf_flags
, false))
4722 summaries_lto
->remove (node
);
4723 *cur_summary_lto_ptr
= NULL
;
4727 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4728 and propagate loads/stores. */
4731 modref_propagate_in_scc (cgraph_node
*component_node
)
4733 bool changed
= true;
4740 = ((struct ipa_dfs_info
*) component_node
->aux
)->next_cycle
;
4742 for (struct cgraph_node
*cur
= component_node
; cur
;
4743 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4745 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
4746 modref_summary
*cur_summary
= optimization_summaries
4747 ? optimization_summaries
->get (node
)
4749 modref_summary_lto
*cur_summary_lto
= summaries_lto
4750 ? summaries_lto
->get (node
)
4753 if (!cur_summary
&& !cur_summary_lto
)
4756 int cur_ecf_flags
= flags_from_decl_or_type (node
->decl
);
4759 fprintf (dump_file
, " Processing %s%s%s\n",
4761 TREE_READONLY (cur
->decl
) ? " (const)" : "",
4762 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
4764 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
4767 fprintf (dump_file
, " Indirect call\n");
4768 if (propagate_unknown_call
4769 (node
, e
, e
->indirect_info
->ecf_flags
,
4770 cur_summary
, cur_summary_lto
,
4774 remove_useless_summaries (node
, &cur_summary
,
4777 if (!cur_summary
&& !cur_summary_lto
)
4782 if (!cur_summary
&& !cur_summary_lto
)
4785 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
4786 callee_edge
= callee_edge
->next_callee
)
4788 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
4789 modref_summary
*callee_summary
= NULL
;
4790 modref_summary_lto
*callee_summary_lto
= NULL
;
4791 struct cgraph_node
*callee
;
4793 if (!callee_edge
->inline_failed
4794 || ((flags
& ECF_CONST
)
4795 && !(flags
& ECF_LOOPING_CONST_OR_PURE
)))
4798 /* Get the callee and its summary. */
4799 enum availability avail
;
4800 callee
= callee_edge
->callee
->ultimate_alias_target
4803 /* It is not necessary to re-process calls outside of the
4807 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
4808 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
4812 fprintf (dump_file
, " Call to %s\n",
4813 callee_edge
->callee
->dump_name ());
4815 bool ignore_stores
= ignore_stores_p (cur
->decl
, flags
);
4817 if (avail
<= AVAIL_INTERPOSABLE
)
4820 fprintf (dump_file
, " Call target interposable"
4821 " or not available\n");
4822 changed
|= propagate_unknown_call
4823 (node
, callee_edge
, flags
,
4824 cur_summary
, cur_summary_lto
,
4826 if (!cur_summary
&& !cur_summary_lto
)
4831 /* We don't know anything about CALLEE, hence we cannot tell
4832 anything about the entire component. */
4835 && !(callee_summary
= optimization_summaries
->get (callee
)))
4838 fprintf (dump_file
, " No call target summary\n");
4839 changed
|= propagate_unknown_call
4840 (node
, callee_edge
, flags
,
4845 && !(callee_summary_lto
= summaries_lto
->get (callee
)))
4848 fprintf (dump_file
, " No call target summary\n");
4849 changed
|= propagate_unknown_call
4850 (node
, callee_edge
, flags
,
4851 NULL
, cur_summary_lto
,
4855 if (callee_summary
&& !cur_summary
->side_effects
4856 && (callee_summary
->side_effects
4857 || callee_edge
->recursive_p ()))
4859 cur_summary
->side_effects
= true;
4862 if (callee_summary_lto
&& !cur_summary_lto
->side_effects
4863 && (callee_summary_lto
->side_effects
4864 || callee_edge
->recursive_p ()))
4866 cur_summary_lto
->side_effects
= true;
4869 if (callee_summary
&& !cur_summary
->nondeterministic
4870 && callee_summary
->nondeterministic
4871 && !ignore_nondeterminism_p (cur
->decl
, flags
))
4873 cur_summary
->nondeterministic
= true;
4876 if (callee_summary_lto
&& !cur_summary_lto
->nondeterministic
4877 && callee_summary_lto
->nondeterministic
4878 && !ignore_nondeterminism_p (cur
->decl
, flags
))
4880 cur_summary_lto
->nondeterministic
= true;
4883 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
4886 /* We can not safely optimize based on summary of callee if it
4887 does not always bind to current def: it is possible that
4888 memory load was optimized out earlier which may not happen in
4889 the interposed variant. */
4890 if (!callee_edge
->binds_to_current_def_p ())
4892 if (cur_summary
&& !cur_summary
->calls_interposable
)
4894 cur_summary
->calls_interposable
= true;
4897 if (cur_summary_lto
&& !cur_summary_lto
->calls_interposable
)
4899 cur_summary_lto
->calls_interposable
= true;
4903 fprintf (dump_file
, " May not bind local;"
4904 " collapsing loads\n");
4908 auto_vec
<modref_parm_map
, 32> parm_map
;
4909 modref_parm_map chain_map
;
4910 /* TODO: Once we get jump functions for static chains we could
4912 chain_map
.parm_index
= MODREF_UNKNOWN_PARM
;
4914 compute_parm_map (callee_edge
, &parm_map
);
4916 /* Merge in callee's information. */
4919 changed
|= cur_summary
->loads
->merge
4920 (node
->decl
, callee_summary
->loads
,
4921 &parm_map
, &chain_map
, !first
);
4924 changed
|= cur_summary
->stores
->merge
4925 (node
->decl
, callee_summary
->stores
,
4926 &parm_map
, &chain_map
, !first
);
4927 if (!cur_summary
->writes_errno
4928 && callee_summary
->writes_errno
)
4930 cur_summary
->writes_errno
= true;
4935 if (callee_summary_lto
)
4937 changed
|= cur_summary_lto
->loads
->merge
4938 (node
->decl
, callee_summary_lto
->loads
,
4939 &parm_map
, &chain_map
, !first
);
4942 changed
|= cur_summary_lto
->stores
->merge
4943 (node
->decl
, callee_summary_lto
->stores
,
4944 &parm_map
, &chain_map
, !first
);
4945 if (!cur_summary_lto
->writes_errno
4946 && callee_summary_lto
->writes_errno
)
4948 cur_summary_lto
->writes_errno
= true;
4954 remove_useless_summaries (node
, &cur_summary
,
4957 if (!cur_summary
&& !cur_summary_lto
)
4959 if (dump_file
&& changed
)
4962 cur_summary
->dump (dump_file
);
4963 if (cur_summary_lto
)
4964 cur_summary_lto
->dump (dump_file
);
4965 dump_modref_edge_summaries (dump_file
, node
, 4);
4974 "Propagation finished in %i iterations\n", iteration
);
4975 bool pureconst
= false;
4976 for (struct cgraph_node
*cur
= component_node
; cur
;
4977 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4978 if (!cur
->inlined_to
&& opt_for_fn (cur
->decl
, flag_ipa_pure_const
))
4980 modref_summary
*summary
= optimization_summaries
4981 ? optimization_summaries
->get (cur
)
4983 modref_summary_lto
*summary_lto
= summaries_lto
4984 ? summaries_lto
->get (cur
)
4986 if (summary
&& !summary
->stores
->every_base
&& !summary
->stores
->bases
4987 && !summary
->nondeterministic
)
4989 if (!summary
->loads
->every_base
&& !summary
->loads
->bases
4990 && !summary
->calls_interposable
)
4991 pureconst
|= ipa_make_function_const
4992 (cur
, summary
->side_effects
, false);
4994 pureconst
|= ipa_make_function_pure
4995 (cur
, summary
->side_effects
, false);
4997 if (summary_lto
&& !summary_lto
->stores
->every_base
4998 && !summary_lto
->stores
->bases
&& !summary_lto
->nondeterministic
)
5000 if (!summary_lto
->loads
->every_base
&& !summary_lto
->loads
->bases
5001 && !summary_lto
->calls_interposable
)
5002 pureconst
|= ipa_make_function_const
5003 (cur
, summary_lto
->side_effects
, false);
5005 pureconst
|= ipa_make_function_pure
5006 (cur
, summary_lto
->side_effects
, false);
5012 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
5015 modref_propagate_dump_scc (cgraph_node
*component_node
)
5017 for (struct cgraph_node
*cur
= component_node
; cur
;
5018 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
5019 if (!cur
->inlined_to
)
5021 modref_summary
*cur_summary
= optimization_summaries
5022 ? optimization_summaries
->get (cur
)
5024 modref_summary_lto
*cur_summary_lto
= summaries_lto
5025 ? summaries_lto
->get (cur
)
5028 fprintf (dump_file
, "Propagated modref for %s%s%s\n",
5030 TREE_READONLY (cur
->decl
) ? " (const)" : "",
5031 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
5032 if (optimization_summaries
)
5035 cur_summary
->dump (dump_file
);
5037 fprintf (dump_file
, " Not tracked\n");
5041 if (cur_summary_lto
)
5042 cur_summary_lto
->dump (dump_file
);
5044 fprintf (dump_file
, " Not tracked (lto)\n");
5049 /* Determine EAF flags know for call E with CALLEE_ECF_FLAGS and ARG. */
5052 implicit_eaf_flags_for_edge_and_arg (cgraph_edge
*e
, int callee_ecf_flags
,
5053 bool ignore_stores
, int arg
)
5055 /* Returning the value is already accounted to at local propagation. */
5056 int implicit_flags
= EAF_NOT_RETURNED_DIRECTLY
5057 | EAF_NOT_RETURNED_INDIRECTLY
;
5059 implicit_flags
|= ignore_stores_eaf_flags
;
5060 if (callee_ecf_flags
& ECF_PURE
)
5061 implicit_flags
|= implicit_pure_eaf_flags
;
5062 if (callee_ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
5063 implicit_flags
|= implicit_const_eaf_flags
;
5064 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
5067 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
5068 implicit_flags
|= fnspec
.arg_eaf_flags (arg
);
5070 return implicit_flags
;
5073 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
5074 and SUMMARY_LTO to CUR_SUMMARY_LTO.
5075 Return true if something changed. */
5078 modref_merge_call_site_flags (escape_summary
*sum
,
5079 modref_summary
*cur_summary
,
5080 modref_summary_lto
*cur_summary_lto
,
5081 modref_summary
*summary
,
5082 modref_summary_lto
*summary_lto
,
5085 int caller_ecf_flags
,
5086 int callee_ecf_flags
,
5087 bool binds_to_current_def
)
5091 bool changed
= false;
5092 bool ignore_stores
= ignore_stores_p (caller
, callee_ecf_flags
);
5094 /* Return early if we have no useful info to propagate. */
5096 || (!cur_summary
->arg_flags
.length ()
5097 && !cur_summary
->static_chain_flags
5098 && !cur_summary
->retslot_flags
))
5099 && (!cur_summary_lto
5100 || (!cur_summary_lto
->arg_flags
.length ()
5101 && !cur_summary_lto
->static_chain_flags
5102 && !cur_summary_lto
->retslot_flags
)))
5105 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
5109 int implicit_flags
= implicit_eaf_flags_for_edge_and_arg
5110 (e
, callee_ecf_flags
, ignore_stores
, ee
->arg
);
5112 if (summary
&& ee
->arg
< summary
->arg_flags
.length ())
5113 flags
= summary
->arg_flags
[ee
->arg
];
5115 && ee
->arg
< summary_lto
->arg_flags
.length ())
5116 flags_lto
= summary_lto
->arg_flags
[ee
->arg
];
5119 flags
= deref_flags (flags
, ignore_stores
);
5120 flags_lto
= deref_flags (flags_lto
, ignore_stores
);
5123 implicit_flags
|= ignore_stores_eaf_flags
;
5124 if (callee_ecf_flags
& ECF_PURE
)
5125 implicit_flags
|= implicit_pure_eaf_flags
;
5126 if (callee_ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
5127 implicit_flags
|= implicit_const_eaf_flags
;
5128 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
5131 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
5132 implicit_flags
|= fnspec
.arg_eaf_flags (ee
->arg
);
5135 implicit_flags
= deref_flags (implicit_flags
, ignore_stores
);
5136 flags
|= implicit_flags
;
5137 flags_lto
|= implicit_flags
;
5138 if (!binds_to_current_def
&& (flags
|| flags_lto
))
5140 flags
= interposable_eaf_flags (flags
, implicit_flags
);
5141 flags_lto
= interposable_eaf_flags (flags_lto
, implicit_flags
);
5143 if (!(flags
& EAF_UNUSED
)
5144 && cur_summary
&& ee
->parm_index
< (int)cur_summary
->arg_flags
.length ())
5146 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
5147 ? cur_summary
->retslot_flags
5148 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
5149 ? cur_summary
->static_chain_flags
5150 : cur_summary
->arg_flags
[ee
->parm_index
];
5151 if ((f
& flags
) != f
)
5153 f
= remove_useless_eaf_flags
5154 (f
& flags
, caller_ecf_flags
,
5155 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
5159 if (!(flags_lto
& EAF_UNUSED
)
5161 && ee
->parm_index
< (int)cur_summary_lto
->arg_flags
.length ())
5163 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
5164 ? cur_summary_lto
->retslot_flags
5165 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
5166 ? cur_summary_lto
->static_chain_flags
5167 : cur_summary_lto
->arg_flags
[ee
->parm_index
];
5168 if ((f
& flags_lto
) != f
)
5170 f
= remove_useless_eaf_flags
5171 (f
& flags_lto
, caller_ecf_flags
,
5172 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
5180 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
5181 and propagate arg flags. */
5184 modref_propagate_flags_in_scc (cgraph_node
*component_node
)
5186 bool changed
= true;
5192 for (struct cgraph_node
*cur
= component_node
; cur
;
5193 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
5195 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
5196 modref_summary
*cur_summary
= optimization_summaries
5197 ? optimization_summaries
->get (node
)
5199 modref_summary_lto
*cur_summary_lto
= summaries_lto
5200 ? summaries_lto
->get (node
)
5203 if (!cur_summary
&& !cur_summary_lto
)
5205 int caller_ecf_flags
= flags_from_decl_or_type (cur
->decl
);
5208 fprintf (dump_file
, " Processing %s%s%s\n",
5210 TREE_READONLY (cur
->decl
) ? " (const)" : "",
5211 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
5213 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
5215 escape_summary
*sum
= escape_summaries
->get (e
);
5217 if (!sum
|| ((e
->indirect_info
->ecf_flags
& ECF_CONST
)
5218 && !(e
->indirect_info
->ecf_flags
& ECF_LOOPING_CONST_OR_PURE
)))
5221 changed
|= modref_merge_call_site_flags
5222 (sum
, cur_summary
, cur_summary_lto
,
5227 e
->indirect_info
->ecf_flags
,
5231 if (!cur_summary
&& !cur_summary_lto
)
5234 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
5235 callee_edge
= callee_edge
->next_callee
)
5237 int ecf_flags
= flags_from_decl_or_type
5238 (callee_edge
->callee
->decl
);
5239 modref_summary
*callee_summary
= NULL
;
5240 modref_summary_lto
*callee_summary_lto
= NULL
;
5241 struct cgraph_node
*callee
;
5243 if ((ecf_flags
& ECF_CONST
)
5244 && !(ecf_flags
& ECF_LOOPING_CONST_OR_PURE
))
5247 /* Get the callee and its summary. */
5248 enum availability avail
;
5249 callee
= callee_edge
->callee
->ultimate_alias_target
5252 /* It is not necessary to re-process calls outside of the
5256 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
5257 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
5260 escape_summary
*sum
= escape_summaries
->get (callee_edge
);
5265 fprintf (dump_file
, " Call to %s\n",
5266 callee_edge
->callee
->dump_name ());
5268 if (avail
<= AVAIL_INTERPOSABLE
5269 || callee_edge
->call_stmt_cannot_inline_p
)
5274 callee_summary
= optimization_summaries
->get (callee
);
5275 if (cur_summary_lto
)
5276 callee_summary_lto
= summaries_lto
->get (callee
);
5278 changed
|= modref_merge_call_site_flags
5279 (sum
, cur_summary
, cur_summary_lto
,
5280 callee_summary
, callee_summary_lto
,
5285 callee
->binds_to_current_def_p ());
5286 if (dump_file
&& changed
)
5289 cur_summary
->dump (dump_file
);
5290 if (cur_summary_lto
)
5291 cur_summary_lto
->dump (dump_file
);
5299 "Propagation of flags finished in %i iterations\n", iteration
);
5302 } /* ANON namespace. */
5304 /* Call EDGE was inlined; merge summary from callee to the caller. */
5307 ipa_merge_modref_summary_after_inlining (cgraph_edge
*edge
)
5309 if (!summaries
&& !summaries_lto
)
5312 struct cgraph_node
*to
= (edge
->caller
->inlined_to
5313 ? edge
->caller
->inlined_to
: edge
->caller
);
5314 class modref_summary
*to_info
= summaries
? summaries
->get (to
) : NULL
;
5315 class modref_summary_lto
*to_info_lto
= summaries_lto
5316 ? summaries_lto
->get (to
) : NULL
;
5318 if (!to_info
&& !to_info_lto
)
5321 summaries
->remove (edge
->callee
);
5323 summaries_lto
->remove (edge
->callee
);
5324 remove_modref_edge_summaries (edge
->callee
);
5328 class modref_summary
*callee_info
= summaries
? summaries
->get (edge
->callee
)
5330 class modref_summary_lto
*callee_info_lto
5331 = summaries_lto
? summaries_lto
->get (edge
->callee
) : NULL
;
5332 int flags
= flags_from_decl_or_type (edge
->callee
->decl
);
5333 /* Combine in outer flags. */
5335 for (n
= edge
->caller
; n
->inlined_to
; n
= n
->callers
->caller
)
5336 flags
|= flags_from_decl_or_type (n
->decl
);
5337 flags
|= flags_from_decl_or_type (n
->decl
);
5338 bool ignore_stores
= ignore_stores_p (edge
->caller
->decl
, flags
);
5340 if (!callee_info
&& to_info
)
5342 if (!(flags
& (ECF_CONST
| ECF_PURE
| ECF_NOVOPS
)))
5343 to_info
->loads
->collapse ();
5345 to_info
->stores
->collapse ();
5347 if (!callee_info_lto
&& to_info_lto
)
5349 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5350 to_info_lto
->loads
->collapse ();
5352 to_info_lto
->stores
->collapse ();
5354 /* Merge side effects and non-determinism.
5355 PURE/CONST flags makes functions deterministic and if there is
5356 no LOOPING_CONST_OR_PURE they also have no side effects. */
5357 if (!(flags
& (ECF_CONST
| ECF_PURE
))
5358 || (flags
& ECF_LOOPING_CONST_OR_PURE
))
5362 if (!callee_info
|| callee_info
->side_effects
)
5363 to_info
->side_effects
= true;
5364 if ((!callee_info
|| callee_info
->nondeterministic
)
5365 && !ignore_nondeterminism_p (edge
->caller
->decl
, flags
))
5366 to_info
->nondeterministic
= true;
5370 if (!callee_info_lto
|| callee_info_lto
->side_effects
)
5371 to_info_lto
->side_effects
= true;
5372 if ((!callee_info_lto
|| callee_info_lto
->nondeterministic
)
5373 && !ignore_nondeterminism_p (edge
->caller
->decl
, flags
))
5374 to_info_lto
->nondeterministic
= true;
5377 if (callee_info
|| callee_info_lto
)
5379 auto_vec
<modref_parm_map
, 32> parm_map
;
5380 modref_parm_map chain_map
;
5381 /* TODO: Once we get jump functions for static chains we could
5382 compute parm_index. */
5384 compute_parm_map (edge
, &parm_map
);
5388 if (to_info
&& callee_info
)
5389 to_info
->stores
->merge (to
->decl
, callee_info
->stores
, &parm_map
,
5391 if (to_info_lto
&& callee_info_lto
)
5392 to_info_lto
->stores
->merge (to
->decl
, callee_info_lto
->stores
,
5393 &parm_map
, &chain_map
, false);
5395 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5397 if (to_info
&& callee_info
)
5398 to_info
->loads
->merge (to
->decl
, callee_info
->loads
, &parm_map
,
5400 if (to_info_lto
&& callee_info_lto
)
5401 to_info_lto
->loads
->merge (to
->decl
, callee_info_lto
->loads
,
5402 &parm_map
, &chain_map
, false);
5406 /* Now merge escape summaries.
5407 For every escape to the callee we need to merge callee flags
5408 and remap callee's escapes. */
5409 class escape_summary
*sum
= escape_summaries
->get (edge
);
5410 int max_escape
= -1;
5414 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5415 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
5416 if ((int)ee
->arg
> max_escape
)
5417 max_escape
= ee
->arg
;
5419 auto_vec
<vec
<struct escape_map
>, 32> emap (max_escape
+ 1);
5420 emap
.safe_grow (max_escape
+ 1, true);
5421 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
5424 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5425 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
5427 bool needed
= false;
5428 int implicit_flags
= implicit_eaf_flags_for_edge_and_arg
5429 (edge
, flags
, ignore_stores
,
5432 implicit_flags
= deref_flags (implicit_flags
, ignore_stores
);
5433 if (to_info
&& (int)to_info
->arg_flags
.length () > ee
->parm_index
)
5435 int flags
= callee_info
5436 && callee_info
->arg_flags
.length () > ee
->arg
5437 ? callee_info
->arg_flags
[ee
->arg
] : 0;
5439 flags
= deref_flags (flags
, ignore_stores
);
5440 flags
|= ee
->min_flags
| implicit_flags
;
5441 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
5442 ? to_info
->retslot_flags
5443 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
5444 ? to_info
->static_chain_flags
5445 : to_info
->arg_flags
[ee
->parm_index
];
5451 && (int)to_info_lto
->arg_flags
.length () > ee
->parm_index
)
5453 int flags
= callee_info_lto
5454 && callee_info_lto
->arg_flags
.length () > ee
->arg
5455 ? callee_info_lto
->arg_flags
[ee
->arg
] : 0;
5457 flags
= deref_flags (flags
, ignore_stores
);
5458 flags
|= ee
->min_flags
| implicit_flags
;
5459 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
5460 ? to_info_lto
->retslot_flags
5461 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
5462 ? to_info_lto
->static_chain_flags
5463 : to_info_lto
->arg_flags
[ee
->parm_index
];
5468 struct escape_map entry
= {ee
->parm_index
, ee
->direct
};
5470 emap
[ee
->arg
].safe_push (entry
);
5472 update_escape_summary (edge
->callee
, emap
, ignore_stores
);
5473 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
5476 escape_summaries
->remove (edge
);
5480 if (to_info
&& !to_info
->useful_p (flags
))
5483 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
5485 summaries
->remove (to
);
5488 else if (to_info
&& dump_file
)
5491 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
5493 to_info
->dump (dump_file
);
5496 summaries
->remove (edge
->callee
);
5500 if (to_info_lto
&& !to_info_lto
->useful_p (flags
))
5503 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
5505 summaries_lto
->remove (to
);
5508 else if (to_info_lto
&& dump_file
)
5511 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
5513 to_info_lto
->dump (dump_file
);
5515 if (callee_info_lto
)
5516 summaries_lto
->remove (edge
->callee
);
5518 if (!to_info
&& !to_info_lto
)
5519 remove_modref_edge_summaries (to
);
5523 /* Run the IPA pass. This will take a function's summaries and calls and
5524 construct new summaries which represent a transitive closure. So that
5525 summary of an analyzed function contains information about the loads and
5526 stores that the function or any function that it calls does. */
5529 pass_ipa_modref::execute (function
*)
5531 if (!summaries
&& !summaries_lto
)
5533 bool pureconst
= false;
5535 if (optimization_summaries
)
5536 ggc_delete (optimization_summaries
);
5537 optimization_summaries
= summaries
;
5540 struct cgraph_node
**order
= XCNEWVEC (struct cgraph_node
*,
5541 symtab
->cgraph_count
);
5543 order_pos
= ipa_reduced_postorder (order
, true, ignore_edge
);
5546 /* Iterate over all strongly connected components in post-order. */
5547 for (i
= 0; i
< order_pos
; i
++)
5549 /* Get the component's representative. That's just any node in the
5550 component from which we can traverse the entire component. */
5551 struct cgraph_node
*component_node
= order
[i
];
5554 fprintf (dump_file
, "\n\nStart of SCC component\n");
5556 pureconst
|= modref_propagate_in_scc (component_node
);
5557 modref_propagate_flags_in_scc (component_node
);
5558 if (optimization_summaries
)
5559 for (struct cgraph_node
*cur
= component_node
; cur
;
5560 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
5561 if (modref_summary
*sum
= optimization_summaries
->get (cur
))
5562 sum
->finalize (cur
->decl
);
5564 modref_propagate_dump_scc (component_node
);
5567 FOR_EACH_FUNCTION (node
)
5568 update_signature (node
);
5570 ((modref_summaries_lto
*)summaries_lto
)->propagated
= true;
5571 ipa_free_postorder_info ();
5573 delete fnspec_summaries
;
5574 fnspec_summaries
= NULL
;
5575 delete escape_summaries
;
5576 escape_summaries
= NULL
;
5578 /* If we possibly made constructors const/pure we may need to remove
5580 return pureconst
? TODO_remove_functions
: 0;
5583 /* Summaries must stay alive until end of compilation. */
5586 ipa_modref_cc_finalize ()
5588 if (optimization_summaries
)
5589 ggc_delete (optimization_summaries
);
5590 optimization_summaries
= NULL
;
5592 ggc_delete (summaries_lto
);
5593 summaries_lto
= NULL
;
5594 if (fnspec_summaries
)
5595 delete fnspec_summaries
;
5596 fnspec_summaries
= NULL
;
5597 if (escape_summaries
)
5598 delete escape_summaries
;
5599 escape_summaries
= NULL
;
5602 #include "gt-ipa-modref.h"