1 /* Search for references that a functions loads or stores.
2 Copyright (C) 2020-2021 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-structlias).
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 parmaeters
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"
79 #include "ipa-fnsummary.h"
80 #include "attr-fnspec.h"
81 #include "symtab-clones.h"
82 #include "gimple-ssa.h"
83 #include "tree-phinodes.h"
84 #include "tree-ssa-operands.h"
85 #include "ssa-iterators.h"
86 #include "stringpool.h"
87 #include "tree-ssanames.h"
95 /* We record fnspec specifiers for call edges since they depends on actual
114 /* Summary holding fnspec string for a given call. */
116 class fnspec_summaries_t
: public call_summary
<fnspec_summary
*>
119 fnspec_summaries_t (symbol_table
*symtab
)
120 : call_summary
<fnspec_summary
*> (symtab
) {}
121 /* Hook that is called by summary when an edge is duplicated. */
122 virtual void duplicate (cgraph_edge
*,
127 dst
->fnspec
= xstrdup (src
->fnspec
);
131 static fnspec_summaries_t
*fnspec_summaries
= NULL
;
133 /* Escape summary holds a vector of param indexes that escape to
137 /* Parameter that escapes at a given call. */
139 /* Argument it escapes to. */
141 /* Minimal flags known about the argument. */
142 eaf_flags_t min_flags
;
143 /* Does it escape directly or indirectly? */
147 /* Dump EAF flags. */
150 dump_eaf_flags (FILE *out
, int flags
, bool newline
= true)
152 if (flags
& EAF_UNUSED
)
153 fprintf (out
, " unused");
154 if (flags
& EAF_NO_DIRECT_CLOBBER
)
155 fprintf (out
, " no_direct_clobber");
156 if (flags
& EAF_NO_INDIRECT_CLOBBER
)
157 fprintf (out
, " no_indirect_clobber");
158 if (flags
& EAF_NO_DIRECT_ESCAPE
)
159 fprintf (out
, " no_direct_escape");
160 if (flags
& EAF_NO_INDIRECT_ESCAPE
)
161 fprintf (out
, " no_indirect_escape");
162 if (flags
& EAF_NOT_RETURNED_DIRECTLY
)
163 fprintf (out
, " not_returned_directly");
164 if (flags
& EAF_NOT_RETURNED_INDIRECTLY
)
165 fprintf (out
, " not_returned_indirectly");
166 if (flags
& EAF_NO_DIRECT_READ
)
167 fprintf (out
, " no_direct_read");
168 if (flags
& EAF_NO_INDIRECT_READ
)
169 fprintf (out
, " no_indirect_read");
174 struct escape_summary
176 auto_vec
<escape_entry
> esc
;
177 void dump (FILE *out
)
179 for (unsigned int i
= 0; i
< esc
.length (); i
++)
181 fprintf (out
, " parm %i arg %i %s min:",
184 esc
[i
].direct
? "(direct)" : "(indirect)");
185 dump_eaf_flags (out
, esc
[i
].min_flags
, false);
191 class escape_summaries_t
: public call_summary
<escape_summary
*>
194 escape_summaries_t (symbol_table
*symtab
)
195 : call_summary
<escape_summary
*> (symtab
) {}
196 /* Hook that is called by summary when an edge is duplicated. */
197 virtual void duplicate (cgraph_edge
*,
202 dst
->esc
= src
->esc
.copy ();
206 static escape_summaries_t
*escape_summaries
= NULL
;
208 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
211 /* Class (from which there is one global instance) that holds modref summaries
212 for all analyzed functions. */
214 class GTY((user
)) modref_summaries
215 : public fast_function_summary
<modref_summary
*, va_gc
>
218 modref_summaries (symbol_table
*symtab
)
219 : fast_function_summary
<modref_summary
*, va_gc
> (symtab
) {}
220 virtual void insert (cgraph_node
*, modref_summary
*state
);
221 virtual void duplicate (cgraph_node
*src_node
,
222 cgraph_node
*dst_node
,
223 modref_summary
*src_data
,
224 modref_summary
*dst_data
);
225 static modref_summaries
*create_ggc (symbol_table
*symtab
)
227 return new (ggc_alloc_no_dtor
<modref_summaries
> ())
228 modref_summaries (symtab
);
232 class modref_summary_lto
;
234 /* Class (from which there is one global instance) that holds modref summaries
235 for all analyzed functions. */
237 class GTY((user
)) modref_summaries_lto
238 : public fast_function_summary
<modref_summary_lto
*, va_gc
>
241 modref_summaries_lto (symbol_table
*symtab
)
242 : fast_function_summary
<modref_summary_lto
*, va_gc
> (symtab
),
243 propagated (false) {}
244 virtual void insert (cgraph_node
*, modref_summary_lto
*state
);
245 virtual void duplicate (cgraph_node
*src_node
,
246 cgraph_node
*dst_node
,
247 modref_summary_lto
*src_data
,
248 modref_summary_lto
*dst_data
);
249 static modref_summaries_lto
*create_ggc (symbol_table
*symtab
)
251 return new (ggc_alloc_no_dtor
<modref_summaries_lto
> ())
252 modref_summaries_lto (symtab
);
257 /* Global variable holding all modref summaries
258 (from analysis to IPA propagation time). */
260 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
263 /* Global variable holding all modref optimization summaries
264 (from IPA propagation time or used by local optimization pass). */
266 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
267 *optimization_summaries
;
269 /* LTO summaries hold info from analysis to LTO streaming or from LTO
270 stream-in through propagation to LTO stream-out. */
272 static GTY(()) fast_function_summary
<modref_summary_lto
*, va_gc
>
275 /* Summary for a single function which this pass produces. */
277 modref_summary::modref_summary ()
278 : loads (NULL
), stores (NULL
), retslot_flags (0), static_chain_flags (0),
279 writes_errno (false), side_effects (false), nondeterministic (false),
280 calls_interposable (false), global_memory_read (false),
281 global_memory_written (false), try_dse (false)
285 modref_summary::~modref_summary ()
293 /* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
294 useful to track. If returns_void is true moreover clear
297 remove_useless_eaf_flags (int eaf_flags
, int ecf_flags
, bool returns_void
)
299 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
300 eaf_flags
&= ~implicit_const_eaf_flags
;
301 else if (ecf_flags
& ECF_PURE
)
302 eaf_flags
&= ~implicit_pure_eaf_flags
;
303 else if ((ecf_flags
& ECF_NORETURN
) || returns_void
)
304 eaf_flags
&= ~(EAF_NOT_RETURNED_DIRECTLY
| EAF_NOT_RETURNED_INDIRECTLY
);
308 /* Return true if FLAGS holds some useful information. */
311 eaf_flags_useful_p (vec
<eaf_flags_t
> &flags
, int ecf_flags
)
313 for (unsigned i
= 0; i
< flags
.length (); i
++)
314 if (remove_useless_eaf_flags (flags
[i
], ecf_flags
, false))
319 /* Return true if summary is potentially useful for optimization.
320 If CHECK_FLAGS is false assume that arg_flags are useful. */
323 modref_summary::useful_p (int ecf_flags
, bool check_flags
)
325 if (arg_flags
.length () && !check_flags
)
327 if (check_flags
&& eaf_flags_useful_p (arg_flags
, ecf_flags
))
329 arg_flags
.release ();
330 if (check_flags
&& remove_useless_eaf_flags (retslot_flags
, ecf_flags
, false))
333 && remove_useless_eaf_flags (static_chain_flags
, ecf_flags
, false))
335 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
336 return ((!side_effects
|| !nondeterministic
)
337 && (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
));
338 if (loads
&& !loads
->every_base
)
342 if (ecf_flags
& ECF_PURE
)
343 return ((!side_effects
|| !nondeterministic
)
344 && (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
));
345 return stores
&& !stores
->every_base
;
348 /* Single function summary used for LTO. */
350 typedef modref_tree
<tree
> modref_records_lto
;
351 struct GTY(()) modref_summary_lto
353 /* Load and stores in functions using types rather then alias sets.
355 This is necessary to make the information streamable for LTO but is also
356 more verbose and thus more likely to hit the limits. */
357 modref_records_lto
*loads
;
358 modref_records_lto
*stores
;
359 auto_vec
<modref_access_node
> GTY((skip
)) kills
;
360 auto_vec
<eaf_flags_t
> GTY((skip
)) arg_flags
;
361 eaf_flags_t retslot_flags
;
362 eaf_flags_t static_chain_flags
;
363 unsigned writes_errno
: 1;
364 unsigned side_effects
: 1;
365 unsigned nondeterministic
: 1;
366 unsigned calls_interposable
: 1;
368 modref_summary_lto ();
369 ~modref_summary_lto ();
371 bool useful_p (int ecf_flags
, bool check_flags
= true);
374 /* Summary for a single function which this pass produces. */
376 modref_summary_lto::modref_summary_lto ()
377 : loads (NULL
), stores (NULL
), retslot_flags (0), static_chain_flags (0),
378 writes_errno (false), side_effects (false), nondeterministic (false),
379 calls_interposable (false)
383 modref_summary_lto::~modref_summary_lto ()
392 /* Return true if lto summary is potentially useful for optimization.
393 If CHECK_FLAGS is false assume that arg_flags are useful. */
396 modref_summary_lto::useful_p (int ecf_flags
, bool check_flags
)
398 if (arg_flags
.length () && !check_flags
)
400 if (check_flags
&& eaf_flags_useful_p (arg_flags
, ecf_flags
))
402 arg_flags
.release ();
403 if (check_flags
&& remove_useless_eaf_flags (retslot_flags
, ecf_flags
, false))
406 && remove_useless_eaf_flags (static_chain_flags
, ecf_flags
, false))
408 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
409 return ((!side_effects
|| !nondeterministic
)
410 && (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
));
411 if (loads
&& !loads
->every_base
)
415 if (ecf_flags
& ECF_PURE
)
416 return ((!side_effects
|| !nondeterministic
)
417 && (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
));
418 return stores
&& !stores
->every_base
;
421 /* Dump records TT to OUT. */
424 dump_records (modref_records
*tt
, FILE *out
)
426 fprintf (out
, " Limits: %i bases, %i refs\n",
427 (int)tt
->max_bases
, (int)tt
->max_refs
);
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
)
469 fprintf (out
, " Limits: %i bases, %i refs\n",
470 (int)tt
->max_bases
, (int)tt
->max_refs
);
473 fprintf (out
, " Every base\n");
477 modref_base_node
<tree
> *n
;
478 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
480 fprintf (out
, " Base %i:", (int)i
);
481 print_generic_expr (dump_file
, n
->base
);
482 fprintf (out
, " (alias set %i)\n",
483 n
->base
? get_alias_set (n
->base
) : 0);
486 fprintf (out
, " Every ref\n");
490 modref_ref_node
<tree
> *r
;
491 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
493 fprintf (out
, " Ref %i:", (int)j
);
494 print_generic_expr (dump_file
, r
->ref
);
495 fprintf (out
, " (alias set %i)\n",
496 r
->ref
? get_alias_set (r
->ref
) : 0);
499 fprintf (out
, " Every access\n");
503 modref_access_node
*a
;
504 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
506 fprintf (out
, " access:");
513 /* Dump all escape points of NODE to OUT. */
516 dump_modref_edge_summaries (FILE *out
, cgraph_node
*node
, int depth
)
519 if (!escape_summaries
)
521 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
523 class escape_summary
*sum
= escape_summaries
->get (e
);
526 fprintf (out
, "%*sIndirect call %i in %s escapes:",
527 depth
, "", i
, node
->dump_name ());
532 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
534 if (!e
->inline_failed
)
535 dump_modref_edge_summaries (out
, e
->callee
, depth
+ 1);
536 class escape_summary
*sum
= escape_summaries
->get (e
);
539 fprintf (out
, "%*sCall %s->%s escapes:", depth
, "",
540 node
->dump_name (), e
->callee
->dump_name ());
543 class fnspec_summary
*fsum
= fnspec_summaries
->get (e
);
546 fprintf (out
, "%*sCall %s->%s fnspec: %s\n", depth
, "",
547 node
->dump_name (), e
->callee
->dump_name (),
553 /* Remove all call edge summaries associated with NODE. */
556 remove_modref_edge_summaries (cgraph_node
*node
)
558 if (!escape_summaries
)
560 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
561 escape_summaries
->remove (e
);
562 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
564 if (!e
->inline_failed
)
565 remove_modref_edge_summaries (e
->callee
);
566 escape_summaries
->remove (e
);
567 fnspec_summaries
->remove (e
);
574 modref_summary::dump (FILE *out
)
578 fprintf (out
, " loads:\n");
579 dump_records (loads
, out
);
583 fprintf (out
, " stores:\n");
584 dump_records (stores
, out
);
588 fprintf (out
, " kills:\n");
589 for (auto kill
: kills
)
596 fprintf (out
, " Writes errno\n");
598 fprintf (out
, " Side effects\n");
599 if (nondeterministic
)
600 fprintf (out
, " Nondeterministic\n");
601 if (calls_interposable
)
602 fprintf (out
, " Calls interposable\n");
603 if (global_memory_read
)
604 fprintf (out
, " Global memory read\n");
605 if (global_memory_written
)
606 fprintf (out
, " Global memory written\n");
608 fprintf (out
, " Try dse\n");
609 if (arg_flags
.length ())
611 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
614 fprintf (out
, " parm %i flags:", i
);
615 dump_eaf_flags (out
, arg_flags
[i
]);
620 fprintf (out
, " Retslot flags:");
621 dump_eaf_flags (out
, retslot_flags
);
623 if (static_chain_flags
)
625 fprintf (out
, " Static chain flags:");
626 dump_eaf_flags (out
, static_chain_flags
);
633 modref_summary_lto::dump (FILE *out
)
635 fprintf (out
, " loads:\n");
636 dump_lto_records (loads
, out
);
637 fprintf (out
, " stores:\n");
638 dump_lto_records (stores
, out
);
641 fprintf (out
, " kills:\n");
642 for (auto kill
: kills
)
649 fprintf (out
, " Writes errno\n");
651 fprintf (out
, " Side effects\n");
652 if (nondeterministic
)
653 fprintf (out
, " Nondeterministic\n");
654 if (calls_interposable
)
655 fprintf (out
, " Calls interposable\n");
656 if (arg_flags
.length ())
658 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
661 fprintf (out
, " parm %i flags:", i
);
662 dump_eaf_flags (out
, arg_flags
[i
]);
667 fprintf (out
, " Retslot flags:");
668 dump_eaf_flags (out
, retslot_flags
);
670 if (static_chain_flags
)
672 fprintf (out
, " Static chain flags:");
673 dump_eaf_flags (out
, static_chain_flags
);
677 /* Called after summary is produced and before it is used by local analysis.
678 Can be called multiple times in case summary needs to update signature.
679 FUN is decl of function summary is attached to. */
681 modref_summary::finalize (tree fun
)
683 global_memory_read
= !loads
|| loads
->global_access_p ();
684 global_memory_written
= !stores
|| stores
->global_access_p ();
686 /* We can do DSE if we know function has no side effects and
687 we can analyse all stores. Disable dse if there are too many
689 if (side_effects
|| global_memory_written
|| writes_errno
)
695 int num_tests
= 0, max_tests
696 = opt_for_fn (fun
, param_modref_max_tests
);
697 modref_base_node
<alias_set_type
> *base_node
;
698 modref_ref_node
<alias_set_type
> *ref_node
;
699 modref_access_node
*access_node
;
700 FOR_EACH_VEC_SAFE_ELT (stores
->bases
, i
, base_node
)
702 if (base_node
->every_ref
)
707 FOR_EACH_VEC_SAFE_ELT (base_node
->refs
, j
, ref_node
)
709 if (base_node
->every_ref
)
714 FOR_EACH_VEC_SAFE_ELT (ref_node
->accesses
, k
, access_node
)
715 if (num_tests
++ > max_tests
716 || !access_node
->parm_offset_known
)
730 /* Get function summary for FUNC if it exists, return NULL otherwise. */
733 get_modref_function_summary (cgraph_node
*func
)
735 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
736 if (!optimization_summaries
)
739 /* A single function body may be represented by multiple symbols with
740 different visibility. For example, if FUNC is an interposable alias,
741 we don't want to return anything, even if we have summary for the target
743 enum availability avail
;
744 func
= func
->function_or_virtual_thunk_symbol
745 (&avail
, current_function_decl
?
746 cgraph_node::get (current_function_decl
) : NULL
);
747 if (avail
<= AVAIL_INTERPOSABLE
)
750 modref_summary
*r
= optimization_summaries
->get (func
);
754 /* Get function summary for CALL if it exists, return NULL otherwise.
755 If non-null set interposed to indicate whether function may not
756 bind to current def. In this case sometimes loads from function
757 needs to be ignored. */
760 get_modref_function_summary (gcall
*call
, bool *interposed
)
762 tree callee
= gimple_call_fndecl (call
);
765 struct cgraph_node
*node
= cgraph_node::get (callee
);
768 modref_summary
*r
= get_modref_function_summary (node
);
770 *interposed
= r
->calls_interposable
771 || !node
->binds_to_current_def_p ();
778 /* Construct modref_access_node from REF. */
779 static modref_access_node
780 get_access (ao_ref
*ref
)
784 base
= ao_ref_base (ref
);
785 modref_access_node a
= {ref
->offset
, ref
->size
, ref
->max_size
,
786 0, MODREF_UNKNOWN_PARM
, false, 0};
787 if (TREE_CODE (base
) == MEM_REF
|| TREE_CODE (base
) == TARGET_MEM_REF
)
790 base
= TREE_OPERAND (base
, 0);
792 if (TREE_CODE (base
) == SSA_NAME
793 && SSA_NAME_IS_DEFAULT_DEF (base
)
794 && TREE_CODE (SSA_NAME_VAR (base
)) == PARM_DECL
)
797 if (cfun
->static_chain_decl
798 && base
== ssa_default_def (cfun
, cfun
->static_chain_decl
))
799 a
.parm_index
= MODREF_STATIC_CHAIN_PARM
;
801 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
802 t
!= SSA_NAME_VAR (base
); t
= DECL_CHAIN (t
))
806 a
.parm_index
= MODREF_UNKNOWN_PARM
;
808 if (a
.parm_index
!= MODREF_UNKNOWN_PARM
809 && TREE_CODE (memref
) == MEM_REF
)
812 = wi::to_poly_wide (TREE_OPERAND
813 (memref
, 1)).to_shwi (&a
.parm_offset
);
816 a
.parm_offset_known
= false;
819 a
.parm_index
= MODREF_UNKNOWN_PARM
;
823 /* Record access into the modref_records data structure. */
826 record_access (modref_records
*tt
, ao_ref
*ref
, modref_access_node
&a
)
828 alias_set_type base_set
= !flag_strict_aliasing
? 0
829 : ao_ref_base_alias_set (ref
);
830 alias_set_type ref_set
= !flag_strict_aliasing
? 0
831 : (ao_ref_alias_set (ref
));
834 fprintf (dump_file
, " - Recording base_set=%i ref_set=%i ",
838 tt
->insert (base_set
, ref_set
, a
, false);
841 /* IPA version of record_access_tree. */
844 record_access_lto (modref_records_lto
*tt
, ao_ref
*ref
, modref_access_node
&a
)
846 /* get_alias_set sometimes use different type to compute the alias set
847 than TREE_TYPE (base). Do same adjustments. */
848 tree base_type
= NULL_TREE
, ref_type
= NULL_TREE
;
849 if (flag_strict_aliasing
)
854 while (handled_component_p (base
))
855 base
= TREE_OPERAND (base
, 0);
857 base_type
= reference_alias_ptr_type_1 (&base
);
860 base_type
= TREE_TYPE (base
);
862 base_type
= TYPE_REF_CAN_ALIAS_ALL (base_type
)
863 ? NULL_TREE
: TREE_TYPE (base_type
);
865 tree ref_expr
= ref
->ref
;
866 ref_type
= reference_alias_ptr_type_1 (&ref_expr
);
869 ref_type
= TREE_TYPE (ref_expr
);
871 ref_type
= TYPE_REF_CAN_ALIAS_ALL (ref_type
)
872 ? NULL_TREE
: TREE_TYPE (ref_type
);
874 /* Sanity check that we are in sync with what get_alias_set does. */
875 gcc_checking_assert ((!base_type
&& !ao_ref_base_alias_set (ref
))
876 || get_alias_set (base_type
)
877 == ao_ref_base_alias_set (ref
));
878 gcc_checking_assert ((!ref_type
&& !ao_ref_alias_set (ref
))
879 || get_alias_set (ref_type
)
880 == ao_ref_alias_set (ref
));
882 /* Do not bother to record types that have no meaningful alias set.
883 Also skip variably modified types since these go to local streams. */
884 if (base_type
&& (!get_alias_set (base_type
)
885 || variably_modified_type_p (base_type
, NULL_TREE
)))
886 base_type
= NULL_TREE
;
887 if (ref_type
&& (!get_alias_set (ref_type
)
888 || variably_modified_type_p (ref_type
, NULL_TREE
)))
889 ref_type
= NULL_TREE
;
893 fprintf (dump_file
, " - Recording base type:");
894 print_generic_expr (dump_file
, base_type
);
895 fprintf (dump_file
, " (alias set %i) ref type:",
896 base_type
? get_alias_set (base_type
) : 0);
897 print_generic_expr (dump_file
, ref_type
);
898 fprintf (dump_file
, " (alias set %i) ",
899 ref_type
? get_alias_set (ref_type
) : 0);
903 tt
->insert (base_type
, ref_type
, a
, false);
906 /* Returns true if and only if we should store the access to EXPR.
907 Some accesses, e.g. loads from automatic variables, are not interesting. */
910 record_access_p (tree expr
)
912 if (refs_local_or_readonly_memory_p (expr
))
915 fprintf (dump_file
, " - Read-only or local, ignoring.\n");
921 /* Return true if ECF flags says that nondeterminsm can be ignored. */
924 ignore_nondeterminism_p (tree caller
, int flags
)
926 if ((flags
& (ECF_CONST
| ECF_PURE
))
927 && !(flags
& ECF_LOOPING_CONST_OR_PURE
))
929 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
930 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
935 /* Return true if ECF flags says that return value can be ignored. */
938 ignore_retval_p (tree caller
, int flags
)
940 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
941 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
946 /* Return true if ECF flags says that stores can be ignored. */
949 ignore_stores_p (tree caller
, int flags
)
951 if (flags
& (ECF_PURE
| ECF_CONST
| ECF_NOVOPS
))
953 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
954 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
959 /* Determine parm_map for argument OP. */
962 parm_map_for_arg (tree op
)
966 struct modref_parm_map parm_map
;
968 parm_map
.parm_offset_known
= false;
969 parm_map
.parm_offset
= 0;
971 offset_known
= unadjusted_ptr_and_unit_offset (op
, &op
, &offset
);
972 if (TREE_CODE (op
) == SSA_NAME
973 && SSA_NAME_IS_DEFAULT_DEF (op
)
974 && TREE_CODE (SSA_NAME_VAR (op
)) == PARM_DECL
)
977 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
978 t
!= SSA_NAME_VAR (op
); t
= DECL_CHAIN (t
))
982 index
= MODREF_UNKNOWN_PARM
;
987 parm_map
.parm_index
= index
;
988 parm_map
.parm_offset_known
= offset_known
;
989 parm_map
.parm_offset
= offset
;
991 else if (points_to_local_or_readonly_memory_p (op
))
992 parm_map
.parm_index
= MODREF_LOCAL_MEMORY_PARM
;
994 parm_map
.parm_index
= MODREF_UNKNOWN_PARM
;
998 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
999 int CUR_SUMMARY. Return true if something changed.
1000 If IGNORE_STORES is true, do not merge stores.
1001 If RECORD_ADJUSTMENTS is true cap number of adjustments to
1002 a given access to make dataflow finite. */
1005 merge_call_side_effects (modref_summary
*cur_summary
,
1006 gimple
*stmt
, modref_summary
*callee_summary
,
1007 bool ignore_stores
, cgraph_node
*callee_node
,
1008 bool record_adjustments
, bool always_executed
)
1010 auto_vec
<modref_parm_map
, 32> parm_map
;
1011 modref_parm_map chain_map
;
1012 bool changed
= false;
1013 int flags
= gimple_call_flags (stmt
);
1015 if ((flags
& (ECF_CONST
| ECF_NOVOPS
))
1016 && !(flags
& ECF_LOOPING_CONST_OR_PURE
))
1019 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
| ECF_PURE
))
1020 || (flags
& ECF_LOOPING_CONST_OR_PURE
))
1022 if (!cur_summary
->side_effects
&& callee_summary
->side_effects
)
1025 fprintf (dump_file
, " - merging side effects.\n");
1026 cur_summary
->side_effects
= true;
1029 if (!cur_summary
->nondeterministic
&& callee_summary
->nondeterministic
1030 && !ignore_nondeterminism_p (current_function_decl
, flags
))
1033 fprintf (dump_file
, " - merging nondeterministic.\n");
1034 cur_summary
->nondeterministic
= true;
1039 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
1042 if (!cur_summary
->calls_interposable
&& callee_summary
->calls_interposable
)
1045 fprintf (dump_file
, " - merging calls interposable.\n");
1046 cur_summary
->calls_interposable
= true;
1050 /* We can not safely optimize based on summary of callee if it does
1051 not always bind to current def: it is possible that memory load
1052 was optimized out earlier which may not happen in the interposed
1054 if (!callee_node
->binds_to_current_def_p ()
1055 && !cur_summary
->calls_interposable
)
1058 fprintf (dump_file
, " - May be interposed.\n");
1059 cur_summary
->calls_interposable
= true;
1064 fprintf (dump_file
, " - Merging side effects of %s with parm map:",
1065 callee_node
->dump_name ());
1067 parm_map
.safe_grow_cleared (gimple_call_num_args (stmt
), true);
1068 for (unsigned i
= 0; i
< gimple_call_num_args (stmt
); i
++)
1070 parm_map
[i
] = parm_map_for_arg (gimple_call_arg (stmt
, i
));
1073 fprintf (dump_file
, " %i", parm_map
[i
].parm_index
);
1074 if (parm_map
[i
].parm_offset_known
)
1076 fprintf (dump_file
, " offset:");
1077 print_dec ((poly_int64_pod
)parm_map
[i
].parm_offset
,
1082 if (gimple_call_chain (stmt
))
1084 chain_map
= parm_map_for_arg (gimple_call_chain (stmt
));
1087 fprintf (dump_file
, "static chain %i", chain_map
.parm_index
);
1088 if (chain_map
.parm_offset_known
)
1090 fprintf (dump_file
, " offset:");
1091 print_dec ((poly_int64_pod
)chain_map
.parm_offset
,
1097 fprintf (dump_file
, "\n");
1100 && callee_summary
->kills
.length ()
1101 && (!cfun
->can_throw_non_call_exceptions
1102 || !stmt_could_throw_p (cfun
, stmt
)))
1104 /* Watch for self recursive updates. */
1105 auto_vec
<modref_access_node
, 32> saved_kills
;
1107 saved_kills
.reserve_exact (callee_summary
->kills
.length ());
1108 saved_kills
.splice (callee_summary
->kills
);
1109 for (auto kill
: saved_kills
)
1111 if (kill
.parm_index
>= (int)parm_map
.length ())
1114 = kill
.parm_index
== MODREF_STATIC_CHAIN_PARM
1116 : parm_map
[kill
.parm_index
];
1117 if (m
.parm_index
== MODREF_LOCAL_MEMORY_PARM
1118 || m
.parm_index
== MODREF_UNKNOWN_PARM
1119 || m
.parm_index
== MODREF_RETSLOT_PARM
1120 || !m
.parm_offset_known
)
1122 modref_access_node n
= kill
;
1123 n
.parm_index
= m
.parm_index
;
1124 n
.parm_offset
+= m
.parm_offset
;
1125 if (modref_access_node::insert_kill (cur_summary
->kills
, n
,
1126 record_adjustments
))
1131 /* Merge with callee's summary. */
1132 changed
|= cur_summary
->loads
->merge (callee_summary
->loads
, &parm_map
,
1133 &chain_map
, record_adjustments
);
1136 changed
|= cur_summary
->stores
->merge (callee_summary
->stores
,
1137 &parm_map
, &chain_map
,
1138 record_adjustments
);
1139 if (!cur_summary
->writes_errno
1140 && callee_summary
->writes_errno
)
1142 cur_summary
->writes_errno
= true;
1149 /* Return access mode for argument I of call STMT with FNSPEC. */
1151 static modref_access_node
1152 get_access_for_fnspec (gcall
*call
, attr_fnspec
&fnspec
,
1153 unsigned int i
, modref_parm_map
&map
)
1155 tree size
= NULL_TREE
;
1156 unsigned int size_arg
;
1158 if (!fnspec
.arg_specified_p (i
))
1160 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
1161 size
= gimple_call_arg (call
, size_arg
);
1162 else if (fnspec
.arg_access_size_given_by_type_p (i
))
1164 tree callee
= gimple_call_fndecl (call
);
1165 tree t
= TYPE_ARG_TYPES (TREE_TYPE (callee
));
1167 for (unsigned int p
= 0; p
< i
; p
++)
1169 size
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t
)));
1171 modref_access_node a
= {0, -1, -1,
1172 map
.parm_offset
, map
.parm_index
,
1173 map
.parm_offset_known
, 0};
1174 poly_int64 size_hwi
;
1176 && poly_int_tree_p (size
, &size_hwi
)
1177 && coeffs_in_range_p (size_hwi
, 0,
1178 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
1181 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
1186 /* Collapse loads and return true if something changed. */
1189 collapse_loads (modref_summary
*cur_summary
,
1190 modref_summary_lto
*cur_summary_lto
)
1192 bool changed
= false;
1194 if (cur_summary
&& !cur_summary
->loads
->every_base
)
1196 cur_summary
->loads
->collapse ();
1200 && !cur_summary_lto
->loads
->every_base
)
1202 cur_summary_lto
->loads
->collapse ();
1208 /* Collapse loads and return true if something changed. */
1211 collapse_stores (modref_summary
*cur_summary
,
1212 modref_summary_lto
*cur_summary_lto
)
1214 bool changed
= false;
1216 if (cur_summary
&& !cur_summary
->stores
->every_base
)
1218 cur_summary
->stores
->collapse ();
1222 && !cur_summary_lto
->stores
->every_base
)
1224 cur_summary_lto
->stores
->collapse ();
1231 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1232 If IGNORE_STORES is true ignore them.
1233 Return false if no useful summary can be produced. */
1236 process_fnspec (modref_summary
*cur_summary
,
1237 modref_summary_lto
*cur_summary_lto
,
1238 gcall
*call
, bool ignore_stores
)
1240 attr_fnspec fnspec
= gimple_call_fnspec (call
);
1241 int flags
= gimple_call_flags (call
);
1243 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
| ECF_PURE
))
1244 || (flags
& ECF_LOOPING_CONST_OR_PURE
)
1245 || (cfun
->can_throw_non_call_exceptions
1246 && stmt_could_throw_p (cfun
, call
)))
1250 cur_summary
->side_effects
= true;
1251 if (!ignore_nondeterminism_p (current_function_decl
, flags
))
1252 cur_summary
->nondeterministic
= true;
1254 if (cur_summary_lto
)
1256 cur_summary_lto
->side_effects
= true;
1257 if (!ignore_nondeterminism_p (current_function_decl
, flags
))
1258 cur_summary_lto
->nondeterministic
= true;
1261 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
1263 if (!fnspec
.known_p ())
1265 if (dump_file
&& gimple_call_builtin_p (call
, BUILT_IN_NORMAL
))
1266 fprintf (dump_file
, " Builtin with no fnspec: %s\n",
1267 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call
))));
1270 collapse_loads (cur_summary
, cur_summary_lto
);
1275 if (fnspec
.global_memory_read_p ())
1276 collapse_loads (cur_summary
, cur_summary_lto
);
1279 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1280 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1282 else if (!fnspec
.arg_specified_p (i
)
1283 || fnspec
.arg_maybe_read_p (i
))
1285 modref_parm_map map
= parm_map_for_arg
1286 (gimple_call_arg (call
, i
));
1288 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1290 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
1292 collapse_loads (cur_summary
, cur_summary_lto
);
1296 cur_summary
->loads
->insert (0, 0,
1297 get_access_for_fnspec (call
,
1301 if (cur_summary_lto
)
1302 cur_summary_lto
->loads
->insert (0, 0,
1303 get_access_for_fnspec (call
,
1311 if (fnspec
.global_memory_written_p ())
1312 collapse_stores (cur_summary
, cur_summary_lto
);
1315 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1316 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1318 else if (!fnspec
.arg_specified_p (i
)
1319 || fnspec
.arg_maybe_written_p (i
))
1321 modref_parm_map map
= parm_map_for_arg
1322 (gimple_call_arg (call
, i
));
1324 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1326 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
1328 collapse_stores (cur_summary
, cur_summary_lto
);
1332 cur_summary
->stores
->insert (0, 0,
1333 get_access_for_fnspec (call
,
1337 if (cur_summary_lto
)
1338 cur_summary_lto
->stores
->insert (0, 0,
1339 get_access_for_fnspec (call
,
1344 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
1347 cur_summary
->writes_errno
= true;
1348 if (cur_summary_lto
)
1349 cur_summary_lto
->writes_errno
= true;
1355 /* Analyze function call STMT in function F.
1356 Remember recursive calls in RECURSIVE_CALLS. */
1359 analyze_call (modref_summary
*cur_summary
, modref_summary_lto
*cur_summary_lto
,
1360 gcall
*stmt
, vec
<gimple
*> *recursive_calls
,
1361 bool always_executed
)
1363 /* Check flags on the function call. In certain cases, analysis can be
1365 int flags
= gimple_call_flags (stmt
);
1366 if ((flags
& (ECF_CONST
| ECF_NOVOPS
))
1367 && !(flags
& ECF_LOOPING_CONST_OR_PURE
))
1371 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1372 "except for args.\n");
1376 /* Pure functions do not affect global memory. Stores by functions which are
1377 noreturn and do not throw can safely be ignored. */
1378 bool ignore_stores
= ignore_stores_p (current_function_decl
, flags
);
1380 /* Next, we try to get the callee's function declaration. The goal is to
1381 merge their summary with ours. */
1382 tree callee
= gimple_call_fndecl (stmt
);
1384 /* Check if this is an indirect call. */
1388 fprintf (dump_file
, gimple_call_internal_p (stmt
)
1389 ? " - Internal call" : " - Indirect call.\n");
1390 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1392 /* We only need to handle internal calls in IPA mode. */
1393 gcc_checking_assert (!cur_summary_lto
);
1395 struct cgraph_node
*callee_node
= cgraph_node::get_create (callee
);
1397 /* If this is a recursive call, the target summary is the same as ours, so
1398 there's nothing to do. */
1399 if (recursive_call_p (current_function_decl
, callee
))
1401 recursive_calls
->safe_push (stmt
);
1403 cur_summary
->side_effects
= true;
1404 if (cur_summary_lto
)
1405 cur_summary_lto
->side_effects
= true;
1407 fprintf (dump_file
, " - Skipping recursive call.\n");
1411 gcc_assert (callee_node
!= NULL
);
1413 /* Get the function symbol and its availability. */
1414 enum availability avail
;
1415 callee_node
= callee_node
->function_symbol (&avail
);
1417 if (builtin_safe_for_const_function_p (&looping
, callee
))
1422 cur_summary
->side_effects
= true;
1423 if (cur_summary_lto
)
1424 cur_summary_lto
->side_effects
= true;
1427 fprintf (dump_file
, " - Bulitin is safe for const.\n");
1430 if (avail
<= AVAIL_INTERPOSABLE
)
1433 fprintf (dump_file
, " - Function availability <= AVAIL_INTERPOSABLE.\n");
1434 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1437 /* Get callee's modref summary. As above, if there's no summary, we either
1438 have to give up or, if stores are ignored, we can just purge loads. */
1439 modref_summary
*callee_summary
= optimization_summaries
->get (callee_node
);
1440 if (!callee_summary
)
1443 fprintf (dump_file
, " - No modref summary available for callee.\n");
1444 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1447 merge_call_side_effects (cur_summary
, stmt
, callee_summary
, ignore_stores
,
1448 callee_node
, false, always_executed
);
1453 /* Support analysis in non-lto and lto mode in parallel. */
1457 struct modref_summary
*nolto
;
1458 struct modref_summary_lto
*lto
;
1459 bool always_executed
;
1462 /* Helper for analyze_stmt. */
1465 analyze_load (gimple
*, tree
, tree op
, void *data
)
1467 modref_summary
*summary
= ((summary_ptrs
*)data
)->nolto
;
1468 modref_summary_lto
*summary_lto
= ((summary_ptrs
*)data
)->lto
;
1472 fprintf (dump_file
, " - Analyzing load: ");
1473 print_generic_expr (dump_file
, op
);
1474 fprintf (dump_file
, "\n");
1477 if (TREE_THIS_VOLATILE (op
)
1478 || (cfun
->can_throw_non_call_exceptions
1479 && tree_could_throw_p (op
)))
1482 fprintf (dump_file
, " (volatile or can throw; marking side effects) ");
1484 summary
->side_effects
= summary
->nondeterministic
= true;
1486 summary_lto
->side_effects
= summary_lto
->nondeterministic
= true;
1489 if (!record_access_p (op
))
1493 ao_ref_init (&r
, op
);
1494 modref_access_node a
= get_access (&r
);
1497 record_access (summary
->loads
, &r
, a
);
1499 record_access_lto (summary_lto
->loads
, &r
, a
);
1503 /* Helper for analyze_stmt. */
1506 analyze_store (gimple
*stmt
, tree
, tree op
, void *data
)
1508 modref_summary
*summary
= ((summary_ptrs
*)data
)->nolto
;
1509 modref_summary_lto
*summary_lto
= ((summary_ptrs
*)data
)->lto
;
1513 fprintf (dump_file
, " - Analyzing store: ");
1514 print_generic_expr (dump_file
, op
);
1515 fprintf (dump_file
, "\n");
1518 if (TREE_THIS_VOLATILE (op
)
1519 || (cfun
->can_throw_non_call_exceptions
1520 && tree_could_throw_p (op
)))
1523 fprintf (dump_file
, " (volatile or can throw; marking side effects) ");
1525 summary
->side_effects
= summary
->nondeterministic
= true;
1527 summary_lto
->side_effects
= summary_lto
->nondeterministic
= true;
1530 if (!record_access_p (op
))
1534 ao_ref_init (&r
, op
);
1535 modref_access_node a
= get_access (&r
);
1538 record_access (summary
->stores
, &r
, a
);
1540 record_access_lto (summary_lto
->stores
, &r
, a
);
1541 if (((summary_ptrs
*)data
)->always_executed
1542 && a
.useful_for_kill_p ()
1543 && (!cfun
->can_throw_non_call_exceptions
1544 || !stmt_could_throw_p (cfun
, stmt
)))
1547 fprintf (dump_file
, " - Recording kill\n");
1549 modref_access_node::insert_kill (summary
->kills
, a
, false);
1551 modref_access_node::insert_kill (summary_lto
->kills
, a
, false);
1556 /* Analyze statement STMT of function F.
1557 If IPA is true do not merge in side effects of calls. */
1560 analyze_stmt (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
1561 gimple
*stmt
, bool ipa
, vec
<gimple
*> *recursive_calls
,
1562 bool always_executed
)
1564 /* In general we can not ignore clobbers because they are barriers for code
1565 motion, however after inlining it is safe to do because local optimization
1566 passes do not consider clobbers from other functions.
1567 Similar logic is in ipa-pure-const.c. */
1568 if ((ipa
|| cfun
->after_inlining
) && gimple_clobber_p (stmt
))
1570 if (always_executed
&& record_access_p (gimple_assign_lhs (stmt
)))
1573 ao_ref_init (&r
, gimple_assign_lhs (stmt
));
1574 modref_access_node a
= get_access (&r
);
1575 if (a
.useful_for_kill_p ())
1578 fprintf (dump_file
, " - Recording kill\n");
1580 modref_access_node::insert_kill (summary
->kills
, a
, false);
1582 modref_access_node::insert_kill (summary_lto
->kills
, a
, false);
1588 struct summary_ptrs sums
= {summary
, summary_lto
, always_executed
};
1590 /* Analyze all loads and stores in STMT. */
1591 walk_stmt_load_store_ops (stmt
, &sums
,
1592 analyze_load
, analyze_store
);
1594 switch (gimple_code (stmt
))
1597 if (gimple_asm_volatile_p (as_a
<gasm
*> (stmt
)))
1600 summary
->side_effects
= summary
->nondeterministic
= true;
1602 summary_lto
->side_effects
= summary_lto
->nondeterministic
= true;
1604 if (cfun
->can_throw_non_call_exceptions
1605 && stmt_could_throw_p (cfun
, stmt
))
1608 summary
->side_effects
= true;
1610 summary_lto
->side_effects
= true;
1612 /* If the ASM statement does not read nor write memory, there's nothing
1613 to do. Otherwise just give up. */
1614 if (!gimple_asm_clobbers_memory_p (as_a
<gasm
*> (stmt
)))
1617 fprintf (dump_file
, " - Function contains GIMPLE_ASM statement "
1618 "which clobbers memory.\n");
1621 if (!ipa
|| gimple_call_internal_p (stmt
))
1622 return analyze_call (summary
, summary_lto
,
1623 as_a
<gcall
*> (stmt
), recursive_calls
,
1627 attr_fnspec fnspec
= gimple_call_fnspec (as_a
<gcall
*>(stmt
));
1629 if (fnspec
.known_p ()
1630 && (!fnspec
.global_memory_read_p ()
1631 || !fnspec
.global_memory_written_p ()))
1633 cgraph_edge
*e
= cgraph_node::get (current_function_decl
)->get_edge (stmt
);
1636 fnspec_summaries
->get_create (e
)->fnspec
= xstrdup (fnspec
.get_str ());
1638 fprintf (dump_file
, " Recorded fnspec %s\n", fnspec
.get_str ());
1644 if (cfun
->can_throw_non_call_exceptions
1645 && stmt_could_throw_p (cfun
, stmt
))
1648 summary
->side_effects
= true;
1650 summary_lto
->side_effects
= true;
1656 /* Remove summary of current function because during the function body
1657 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1661 remove_summary (bool lto
, bool nolto
, bool ipa
)
1663 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1665 optimization_summaries
->remove (fnode
);
1669 summaries
->remove (fnode
);
1671 summaries_lto
->remove (fnode
);
1672 remove_modref_edge_summaries (fnode
);
1676 " - modref done with result: not tracked.\n");
1679 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1682 memory_access_to (tree op
, tree ssa_name
)
1684 tree base
= get_base_address (op
);
1687 if (TREE_CODE (base
) != MEM_REF
&& TREE_CODE (base
) != TARGET_MEM_REF
)
1689 return TREE_OPERAND (base
, 0) == ssa_name
;
1692 /* Consider statement val = *arg.
1693 return EAF flags of ARG that can be determined from EAF flags of VAL
1694 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1695 all stores to VAL, i.e. when handling noreturn function. */
1698 deref_flags (int flags
, bool ignore_stores
)
1700 /* Dereference is also a direct read but dereferenced value does not
1701 yield any other direct use. */
1702 int ret
= EAF_NO_DIRECT_CLOBBER
| EAF_NO_DIRECT_ESCAPE
1703 | EAF_NOT_RETURNED_DIRECTLY
;
1704 /* If argument is unused just account for
1705 the read involved in dereference. */
1706 if (flags
& EAF_UNUSED
)
1707 ret
|= EAF_NO_INDIRECT_READ
| EAF_NO_INDIRECT_CLOBBER
1708 | EAF_NO_INDIRECT_ESCAPE
;
1711 /* Direct or indirect accesses leads to indirect accesses. */
1712 if (((flags
& EAF_NO_DIRECT_CLOBBER
)
1713 && (flags
& EAF_NO_INDIRECT_CLOBBER
))
1715 ret
|= EAF_NO_INDIRECT_CLOBBER
;
1716 if (((flags
& EAF_NO_DIRECT_ESCAPE
)
1717 && (flags
& EAF_NO_INDIRECT_ESCAPE
))
1719 ret
|= EAF_NO_INDIRECT_ESCAPE
;
1720 if ((flags
& EAF_NO_DIRECT_READ
)
1721 && (flags
& EAF_NO_INDIRECT_READ
))
1722 ret
|= EAF_NO_INDIRECT_READ
;
1723 if ((flags
& EAF_NOT_RETURNED_DIRECTLY
)
1724 && (flags
& EAF_NOT_RETURNED_INDIRECTLY
))
1725 ret
|= EAF_NOT_RETURNED_INDIRECTLY
;
1731 /* Description of an escape point. */
1735 /* Value escapes to this call. */
1737 /* Argument it escapes to. */
1739 /* Flags already known about the argument (this can save us from recording
1740 esape points if local analysis did good job already). */
1741 eaf_flags_t min_flags
;
1742 /* Does value escape directly or indiretly? */
1746 class modref_lattice
1749 /* EAF flags of the SSA name. */
1751 /* Used during DFS walk to mark names where final value was determined
1752 without need for dataflow. */
1754 /* Used during DFS walk to mark open vertices (for cycle detection). */
1756 /* Set during DFS walk for names that needs dataflow propagation. */
1758 /* Used during the iterative dataflow. */
1761 /* When doing IPA analysis we can not merge in callee escape points;
1762 Only remember them and do the merging at IPA propagation time. */
1763 vec
<escape_point
, va_heap
, vl_ptr
> escape_points
;
1765 /* Representation of a graph for dataaflow. This graph is built on-demand
1766 using modref_eaf_analysis::analyze_ssa and later solved by
1767 modref_eaf_analysis::propagate.
1768 Each edge represents the fact that flags of current lattice should be
1769 propagated to lattice of SSA_NAME. */
1770 struct propagate_edge
1775 vec
<propagate_edge
, va_heap
, vl_ptr
> propagate_to
;
1779 bool merge (const modref_lattice
&with
);
1780 bool merge (int flags
);
1781 bool merge_deref (const modref_lattice
&with
, bool ignore_stores
);
1782 bool merge_direct_load ();
1783 bool merge_direct_store ();
1784 bool add_escape_point (gcall
*call
, int arg
, int min_flags
, bool diret
);
1785 void dump (FILE *out
, int indent
= 0) const;
1788 /* Lattices are saved to vectors, so keep them PODs. */
1790 modref_lattice::init ()
1792 /* All flags we track. */
1793 int f
= EAF_NO_DIRECT_CLOBBER
| EAF_NO_INDIRECT_CLOBBER
1794 | EAF_NO_DIRECT_ESCAPE
| EAF_NO_INDIRECT_ESCAPE
1795 | EAF_NO_DIRECT_READ
| EAF_NO_INDIRECT_READ
1796 | EAF_NOT_RETURNED_DIRECTLY
| EAF_NOT_RETURNED_INDIRECTLY
1799 /* Check that eaf_flags_t is wide enough to hold all flags. */
1800 gcc_checking_assert (f
== flags
);
1805 /* Release memory. */
1807 modref_lattice::release ()
1809 escape_points
.release ();
1810 propagate_to
.release ();
1813 /* Dump lattice to OUT; indent with INDENT spaces. */
1816 modref_lattice::dump (FILE *out
, int indent
) const
1818 dump_eaf_flags (out
, flags
);
1819 if (escape_points
.length ())
1821 fprintf (out
, "%*sEscapes:\n", indent
, "");
1822 for (unsigned int i
= 0; i
< escape_points
.length (); i
++)
1824 fprintf (out
, "%*s Arg %i (%s) min flags", indent
, "",
1825 escape_points
[i
].arg
,
1826 escape_points
[i
].direct
? "direct" : "indirect");
1827 dump_eaf_flags (out
, escape_points
[i
].min_flags
, false);
1828 fprintf (out
, " in call ");
1829 print_gimple_stmt (out
, escape_points
[i
].call
, 0);
1834 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1838 modref_lattice::add_escape_point (gcall
*call
, int arg
, int min_flags
,
1844 /* If we already determined flags to be bad enough,
1845 we do not need to record. */
1846 if ((flags
& min_flags
) == flags
|| (min_flags
& EAF_UNUSED
))
1849 FOR_EACH_VEC_ELT (escape_points
, i
, ep
)
1850 if (ep
->call
== call
&& ep
->arg
== arg
&& ep
->direct
== direct
)
1852 if ((ep
->min_flags
& min_flags
) == min_flags
)
1854 ep
->min_flags
&= min_flags
;
1857 /* Give up if max escape points is met. */
1858 if ((int)escape_points
.length () > param_modref_max_escape_points
)
1861 fprintf (dump_file
, "--param modref-max-escape-points limit reached\n");
1865 escape_point new_ep
= {call
, arg
, min_flags
, direct
};
1866 escape_points
.safe_push (new_ep
);
1870 /* Merge in flags from F. */
1872 modref_lattice::merge (int f
)
1876 /* Check that flags seems sane: if function does not read the parameter
1877 it can not access it indirectly. */
1878 gcc_checking_assert (!(f
& EAF_NO_DIRECT_READ
)
1879 || ((f
& EAF_NO_INDIRECT_READ
)
1880 && (f
& EAF_NO_INDIRECT_CLOBBER
)
1881 && (f
& EAF_NO_INDIRECT_ESCAPE
)
1882 && (f
& EAF_NOT_RETURNED_INDIRECTLY
)));
1883 if ((flags
& f
) != flags
)
1886 /* Prune obvoiusly useless flags;
1887 We do not have ECF_FLAGS handy which is not big problem since
1888 we will do final flags cleanup before producing summary.
1889 Merging should be fast so it can work well with dataflow. */
1890 flags
= remove_useless_eaf_flags (flags
, 0, false);
1892 escape_points
.release ();
1898 /* Merge in WITH. Return true if anyting changed. */
1901 modref_lattice::merge (const modref_lattice
&with
)
1906 bool changed
= merge (with
.flags
);
1910 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
1911 changed
|= add_escape_point (with
.escape_points
[i
].call
,
1912 with
.escape_points
[i
].arg
,
1913 with
.escape_points
[i
].min_flags
,
1914 with
.escape_points
[i
].direct
);
1918 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1919 stores. Return true if anyting changed. */
1922 modref_lattice::merge_deref (const modref_lattice
&with
, bool ignore_stores
)
1927 bool changed
= merge (deref_flags (with
.flags
, ignore_stores
));
1931 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
1933 int min_flags
= with
.escape_points
[i
].min_flags
;
1935 if (with
.escape_points
[i
].direct
)
1936 min_flags
= deref_flags (min_flags
, ignore_stores
);
1937 else if (ignore_stores
)
1938 min_flags
|= ignore_stores_eaf_flags
;
1939 changed
|= add_escape_point (with
.escape_points
[i
].call
,
1940 with
.escape_points
[i
].arg
,
1947 /* Merge in flags for direct load. */
1950 modref_lattice::merge_direct_load ()
1952 return merge (~(EAF_UNUSED
| EAF_NO_DIRECT_READ
));
1955 /* Merge in flags for direct store. */
1958 modref_lattice::merge_direct_store ()
1960 return merge (~(EAF_UNUSED
| EAF_NO_DIRECT_CLOBBER
));
1963 /* Analyzer of EAF flags.
1964 This is genrally dataflow problem over the SSA graph, however we only
1965 care about flags of few selected ssa names (arguments, return slot and
1966 static chain). So we first call analyze_ssa_name on all relevant names
1967 and perform a DFS walk to discover SSA names where flags needs to be
1968 determined. For acyclic graphs we try to determine final flags during
1969 this walk. Once cycles or recursin depth is met we enlist SSA names
1970 for dataflow which is done by propagate call.
1972 After propagation the flags can be obtained using get_ssa_name_flags. */
1974 class modref_eaf_analysis
1977 /* Mark NAME as relevant for analysis. */
1978 void analyze_ssa_name (tree name
);
1979 /* Dataflow slover. */
1981 /* Return flags computed earlier for NAME. */
1982 int get_ssa_name_flags (tree name
)
1984 int version
= SSA_NAME_VERSION (name
);
1985 gcc_checking_assert (m_lattice
[version
].known
);
1986 return m_lattice
[version
].flags
;
1988 /* In IPA mode this will record all escape points
1989 determined for NAME to PARM_IDNEX. Flags are minimal
1991 void record_escape_points (tree name
, int parm_index
, int flags
);
1992 modref_eaf_analysis (bool ipa
)
1996 m_lattice
.safe_grow_cleared (num_ssa_names
, true);
1998 ~modref_eaf_analysis ()
2000 gcc_checking_assert (!m_depth
);
2001 if (m_ipa
|| m_names_to_propagate
.length ())
2002 for (unsigned int i
= 0; i
< num_ssa_names
; i
++)
2003 m_lattice
[i
].release ();
2006 /* If true, we produce analysis for IPA mode. In this case escape points ar
2009 /* Depth of recursion of analyze_ssa_name. */
2011 /* Propagation lattice for individual ssa names. */
2012 auto_vec
<modref_lattice
> m_lattice
;
2013 auto_vec
<tree
> m_deferred_names
;
2014 auto_vec
<int> m_names_to_propagate
;
2016 void merge_with_ssa_name (tree dest
, tree src
, bool deref
);
2017 void merge_call_lhs_flags (gcall
*call
, int arg
, tree name
, bool direct
,
2022 /* Call statements may return tgeir parameters. Consider argument number
2023 ARG of USE_STMT and determine flags that can needs to be cleared
2024 in case pointer possibly indirectly references from ARG I is returned.
2025 If DIRECT is true consider direct returns and if INDIRECT consider
2027 LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
2028 ARG is set to -1 for static chain. */
2031 modref_eaf_analysis::merge_call_lhs_flags (gcall
*call
, int arg
,
2032 tree name
, bool direct
,
2035 int index
= SSA_NAME_VERSION (name
);
2037 /* If value is not returned at all, do nothing. */
2038 if (!direct
&& !indirect
)
2041 /* If there is no return value, no flags are affected. */
2042 if (!gimple_call_lhs (call
))
2045 /* If we know that function returns given argument and it is not ARG
2046 we can still be happy. */
2049 int flags
= gimple_call_return_flags (call
);
2050 if ((flags
& ERF_RETURNS_ARG
)
2051 && (flags
& ERF_RETURN_ARG_MASK
) != arg
)
2055 /* If return value is SSA name determine its flags. */
2056 if (TREE_CODE (gimple_call_lhs (call
)) == SSA_NAME
)
2058 tree lhs
= gimple_call_lhs (call
);
2060 merge_with_ssa_name (name
, lhs
, false);
2062 merge_with_ssa_name (name
, lhs
, true);
2064 /* In the case of memory store we can do nothing. */
2066 m_lattice
[index
].merge (deref_flags (0, false));
2068 m_lattice
[index
].merge (0);
2071 /* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
2072 into flags for caller, update LATTICE of corresponding
2073 argument if needed. */
2076 callee_to_caller_flags (int call_flags
, bool ignore_stores
,
2077 modref_lattice
&lattice
)
2079 /* call_flags is about callee returning a value
2080 that is not the same as caller returning it. */
2081 call_flags
|= EAF_NOT_RETURNED_DIRECTLY
2082 | EAF_NOT_RETURNED_INDIRECTLY
;
2083 if (!ignore_stores
&& !(call_flags
& EAF_UNUSED
))
2085 /* If value escapes we are no longer able to track what happens
2086 with it because we can read it from the escaped location
2088 if (!(call_flags
& EAF_NO_DIRECT_ESCAPE
))
2090 else if (!(call_flags
& EAF_NO_INDIRECT_ESCAPE
))
2091 lattice
.merge (~(EAF_NOT_RETURNED_INDIRECTLY
2092 | EAF_NO_DIRECT_READ
2093 | EAF_NO_INDIRECT_READ
2094 | EAF_NO_INDIRECT_CLOBBER
2098 call_flags
|= ignore_stores_eaf_flags
;
2102 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
2103 LATTICE is an array of modref_lattices.
2104 DEPTH is a recursion depth used to make debug output prettier.
2105 If IPA is true we analyze for IPA propagation (and thus call escape points
2106 are processed later) */
2109 modref_eaf_analysis::analyze_ssa_name (tree name
)
2111 imm_use_iterator ui
;
2113 int index
= SSA_NAME_VERSION (name
);
2115 /* See if value is already computed. */
2116 if (m_lattice
[index
].known
|| m_lattice
[index
].do_dataflow
)
2118 if (m_lattice
[index
].open
)
2122 "%*sCycle in SSA graph\n",
2126 /* Recursion guard. */
2127 m_lattice
[index
].init ();
2128 if (m_depth
== param_modref_max_depth
)
2132 "%*sMax recursion depth reached; postponing\n",
2134 m_deferred_names
.safe_push (name
);
2141 "%*sAnalyzing flags of ssa name: ", m_depth
* 4, "");
2142 print_generic_expr (dump_file
, name
);
2143 fprintf (dump_file
, "\n");
2146 FOR_EACH_IMM_USE_STMT (use_stmt
, ui
, name
)
2148 if (m_lattice
[index
].flags
== 0)
2150 if (is_gimple_debug (use_stmt
))
2154 fprintf (dump_file
, "%*s Analyzing stmt: ", m_depth
* 4, "");
2155 print_gimple_stmt (dump_file
, use_stmt
, 0);
2157 /* If we see a direct non-debug use, clear unused bit.
2158 All dereferneces should be accounted below using deref_flags. */
2159 m_lattice
[index
].merge (~EAF_UNUSED
);
2161 /* Gimple return may load the return value.
2162 Returning name counts as an use by tree-ssa-structalias.c */
2163 if (greturn
*ret
= dyn_cast
<greturn
*> (use_stmt
))
2165 /* Returning through return slot is seen as memory write earlier. */
2166 if (DECL_RESULT (current_function_decl
)
2167 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl
)))
2169 else if (gimple_return_retval (ret
) == name
)
2170 m_lattice
[index
].merge (~(EAF_UNUSED
| EAF_NOT_RETURNED_DIRECTLY
2171 | EAF_NOT_RETURNED_DIRECTLY
));
2172 else if (memory_access_to (gimple_return_retval (ret
), name
))
2174 m_lattice
[index
].merge_direct_load ();
2175 m_lattice
[index
].merge (~(EAF_UNUSED
2176 | EAF_NOT_RETURNED_INDIRECTLY
));
2179 /* Account for LHS store, arg loads and flags from callee function. */
2180 else if (gcall
*call
= dyn_cast
<gcall
*> (use_stmt
))
2182 tree callee
= gimple_call_fndecl (call
);
2184 /* IPA PTA internally it treats calling a function as "writing" to
2185 the argument space of all functions the function pointer points to
2186 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
2187 is on since that would allow propagation of this from -fno-ipa-pta
2188 to -fipa-pta functions. */
2189 if (gimple_call_fn (use_stmt
) == name
)
2190 m_lattice
[index
].merge (~(EAF_NO_DIRECT_CLOBBER
| EAF_UNUSED
));
2192 /* Recursion would require bit of propagation; give up for now. */
2193 if (callee
&& !m_ipa
&& recursive_call_p (current_function_decl
,
2195 m_lattice
[index
].merge (0);
2198 int ecf_flags
= gimple_call_flags (call
);
2199 bool ignore_stores
= ignore_stores_p (current_function_decl
,
2201 bool ignore_retval
= ignore_retval_p (current_function_decl
,
2204 /* Handle *name = func (...). */
2205 if (gimple_call_lhs (call
)
2206 && memory_access_to (gimple_call_lhs (call
), name
))
2208 m_lattice
[index
].merge_direct_store ();
2209 /* Return slot optimization passes address of
2210 LHS to callee via hidden parameter and this
2211 may make LHS to escape. See PR 98499. */
2212 if (gimple_call_return_slot_opt_p (call
)
2213 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call
))))
2215 int call_flags
= gimple_call_retslot_flags (call
);
2216 bool isretslot
= false;
2218 if (DECL_RESULT (current_function_decl
)
2219 && DECL_BY_REFERENCE
2220 (DECL_RESULT (current_function_decl
)))
2221 isretslot
= ssa_default_def
2223 DECL_RESULT (current_function_decl
))
2226 /* Passing returnslot to return slot is special because
2227 not_returned and escape has same meaning.
2228 However passing arg to return slot is different. If
2229 the callee's return slot is returned it means that
2230 arg is written to itself which is an escape.
2231 Since we do not track the memory it is written to we
2232 need to give up on analysisng it. */
2235 if (!(call_flags
& (EAF_NOT_RETURNED_DIRECTLY
2237 m_lattice
[index
].merge (0);
2238 else gcc_checking_assert
2239 (call_flags
& (EAF_NOT_RETURNED_INDIRECTLY
2241 call_flags
= callee_to_caller_flags
2245 m_lattice
[index
].merge (call_flags
);
2249 if (gimple_call_chain (call
)
2250 && (gimple_call_chain (call
) == name
))
2252 int call_flags
= gimple_call_static_chain_flags (call
);
2253 if (!ignore_retval
&& !(call_flags
& EAF_UNUSED
))
2254 merge_call_lhs_flags
2256 !(call_flags
& EAF_NOT_RETURNED_DIRECTLY
),
2257 !(call_flags
& EAF_NOT_RETURNED_INDIRECTLY
));
2258 call_flags
= callee_to_caller_flags
2259 (call_flags
, ignore_stores
,
2261 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
2262 m_lattice
[index
].merge (call_flags
);
2265 /* Process internal functions and right away. */
2266 bool record_ipa
= m_ipa
&& !gimple_call_internal_p (call
);
2268 /* Handle all function parameters. */
2269 for (unsigned i
= 0;
2270 i
< gimple_call_num_args (call
)
2271 && m_lattice
[index
].flags
; i
++)
2272 /* Name is directly passed to the callee. */
2273 if (gimple_call_arg (call
, i
) == name
)
2275 int call_flags
= gimple_call_arg_flags (call
, i
);
2276 if (!ignore_retval
&& !(call_flags
& EAF_UNUSED
))
2277 merge_call_lhs_flags
2279 !(call_flags
& EAF_NOT_RETURNED_DIRECTLY
),
2280 !(call_flags
& EAF_NOT_RETURNED_INDIRECTLY
));
2281 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
2283 call_flags
= callee_to_caller_flags
2284 (call_flags
, ignore_stores
,
2287 m_lattice
[index
].merge (call_flags
);
2289 m_lattice
[index
].add_escape_point (call
, i
,
2293 /* Name is dereferenced and passed to a callee. */
2294 else if (memory_access_to (gimple_call_arg (call
, i
), name
))
2296 int call_flags
= deref_flags
2297 (gimple_call_arg_flags (call
, i
), ignore_stores
);
2298 if (!ignore_retval
&& !(call_flags
& EAF_UNUSED
)
2299 && !(call_flags
& EAF_NOT_RETURNED_DIRECTLY
)
2300 && !(call_flags
& EAF_NOT_RETURNED_INDIRECTLY
))
2301 merge_call_lhs_flags (call
, i
, name
, false, true);
2302 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
2303 m_lattice
[index
].merge_direct_load ();
2306 call_flags
= callee_to_caller_flags
2307 (call_flags
, ignore_stores
,
2310 m_lattice
[index
].merge (call_flags
);
2312 m_lattice
[index
].add_escape_point (call
, i
,
2318 else if (gimple_assign_load_p (use_stmt
))
2320 gassign
*assign
= as_a
<gassign
*> (use_stmt
);
2321 /* Memory to memory copy. */
2322 if (gimple_store_p (assign
))
2324 /* Handle *lhs = *name.
2326 We do not track memory locations, so assume that value
2327 is used arbitrarily. */
2328 if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
2329 m_lattice
[index
].merge (deref_flags (0, false));
2330 /* Handle *name = *exp. */
2331 else if (memory_access_to (gimple_assign_lhs (assign
), name
))
2332 m_lattice
[index
].merge_direct_store ();
2334 /* Handle lhs = *name. */
2335 else if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
2337 tree lhs
= gimple_assign_lhs (assign
);
2338 merge_with_ssa_name (name
, lhs
, true);
2341 else if (gimple_store_p (use_stmt
))
2343 gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
);
2345 /* Handle *lhs = name. */
2346 if (assign
&& gimple_assign_rhs1 (assign
) == name
)
2349 fprintf (dump_file
, "%*s ssa name saved to memory\n",
2351 m_lattice
[index
].merge (0);
2353 /* Handle *name = exp. */
2355 && memory_access_to (gimple_assign_lhs (assign
), name
))
2357 /* In general we can not ignore clobbers because they are
2358 barriers for code motion, however after inlining it is safe to
2359 do because local optimization passes do not consider clobbers
2360 from other functions.
2361 Similar logic is in ipa-pure-const.c. */
2362 if (!cfun
->after_inlining
|| !gimple_clobber_p (assign
))
2363 m_lattice
[index
].merge_direct_store ();
2365 /* ASM statements etc. */
2369 fprintf (dump_file
, "%*s Unhandled store\n", m_depth
* 4, "");
2370 m_lattice
[index
].merge (0);
2373 else if (gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
))
2375 enum tree_code code
= gimple_assign_rhs_code (assign
);
2377 /* See if operation is a merge as considered by
2378 tree-ssa-structalias.c:find_func_aliases. */
2379 if (!truth_value_p (code
)
2380 && code
!= POINTER_DIFF_EXPR
2381 && (code
!= POINTER_PLUS_EXPR
2382 || gimple_assign_rhs1 (assign
) == name
))
2384 tree lhs
= gimple_assign_lhs (assign
);
2385 merge_with_ssa_name (name
, lhs
, false);
2388 else if (gphi
*phi
= dyn_cast
<gphi
*> (use_stmt
))
2390 tree result
= gimple_phi_result (phi
);
2391 merge_with_ssa_name (name
, result
, false);
2393 /* Conditions are not considered escape points
2394 by tree-ssa-structalias. */
2395 else if (gimple_code (use_stmt
) == GIMPLE_COND
)
2400 fprintf (dump_file
, "%*s Unhandled stmt\n", m_depth
* 4, "");
2401 m_lattice
[index
].merge (0);
2406 fprintf (dump_file
, "%*s current flags of ", m_depth
* 4, "");
2407 print_generic_expr (dump_file
, name
);
2408 m_lattice
[index
].dump (dump_file
, m_depth
* 4 + 4);
2413 fprintf (dump_file
, "%*sflags of ssa name ", m_depth
* 4, "");
2414 print_generic_expr (dump_file
, name
);
2415 m_lattice
[index
].dump (dump_file
, m_depth
* 4 + 2);
2417 m_lattice
[index
].open
= false;
2418 if (!m_lattice
[index
].do_dataflow
)
2419 m_lattice
[index
].known
= true;
2422 /* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
2426 modref_eaf_analysis::merge_with_ssa_name (tree dest
, tree src
, bool deref
)
2428 int index
= SSA_NAME_VERSION (dest
);
2429 int src_index
= SSA_NAME_VERSION (src
);
2431 /* Merging lattice with itself is a no-op. */
2432 if (!deref
&& src
== dest
)
2436 analyze_ssa_name (src
);
2439 m_lattice
[index
].merge_deref (m_lattice
[src_index
], false);
2441 m_lattice
[index
].merge (m_lattice
[src_index
]);
2443 /* If we failed to produce final solution add an edge to the dataflow
2445 if (!m_lattice
[src_index
].known
)
2447 modref_lattice::propagate_edge e
= {index
, deref
};
2449 if (!m_lattice
[src_index
].propagate_to
.length ())
2450 m_names_to_propagate
.safe_push (src_index
);
2451 m_lattice
[src_index
].propagate_to
.safe_push (e
);
2452 m_lattice
[src_index
].changed
= true;
2453 m_lattice
[src_index
].do_dataflow
= true;
2456 "%*sWill propgate from ssa_name %i to %i%s\n",
2458 "", src_index
, index
, deref
? " (deref)" : "");
2462 /* In the case we deferred some SSA names, reprocess them. In the case some
2463 dataflow edges were introduced, do the actual iterative dataflow. */
2466 modref_eaf_analysis::propagate ()
2471 bool changed
= true;
2473 while (m_deferred_names
.length ())
2475 tree name
= m_deferred_names
.pop ();
2476 m_lattice
[SSA_NAME_VERSION (name
)].open
= false;
2478 fprintf (dump_file
, "Analyzing deferred SSA name\n");
2479 analyze_ssa_name (name
);
2482 if (!m_names_to_propagate
.length ())
2485 fprintf (dump_file
, "Propagating EAF flags\n");
2487 /* Compute reverse postorder. */
2494 auto_vec
<struct stack_entry
> stack
;
2495 int pos
= m_names_to_propagate
.length () - 1;
2497 rpo
.safe_grow (m_names_to_propagate
.length (), true);
2498 stack
.reserve_exact (m_names_to_propagate
.length ());
2500 /* We reuse known flag for RPO DFS walk bookeeping. */
2502 FOR_EACH_VEC_ELT (m_names_to_propagate
, i
, index
)
2503 gcc_assert (!m_lattice
[index
].known
&& m_lattice
[index
].changed
);
2505 FOR_EACH_VEC_ELT (m_names_to_propagate
, i
, index
)
2507 if (!m_lattice
[index
].known
)
2509 stack_entry e
= {index
, 0};
2511 stack
.quick_push (e
);
2512 m_lattice
[index
].known
= true;
2514 while (stack
.length ())
2517 int index1
= stack
.last ().name
;
2519 while (stack
.last ().pos
< m_lattice
[index1
].propagate_to
.length ())
2521 int index2
= m_lattice
[index1
]
2522 .propagate_to
[stack
.last ().pos
].ssa_name
;
2524 stack
.last ().pos
++;
2525 if (!m_lattice
[index2
].known
2526 && m_lattice
[index2
].propagate_to
.length ())
2528 stack_entry e
= {index2
, 0};
2530 stack
.quick_push (e
);
2531 m_lattice
[index2
].known
= true;
2537 && stack
.last ().pos
== m_lattice
[index1
].propagate_to
.length ())
2539 rpo
[pos
--] = index1
;
2545 /* Perform itrative dataflow. */
2551 fprintf (dump_file
, " iteration %i\n", iterations
);
2552 FOR_EACH_VEC_ELT (rpo
, i
, index
)
2554 if (m_lattice
[index
].changed
)
2558 m_lattice
[index
].changed
= false;
2560 fprintf (dump_file
, " Visiting ssa name %i\n", index
);
2561 for (j
= 0; j
< m_lattice
[index
].propagate_to
.length (); j
++)
2564 int target
= m_lattice
[index
].propagate_to
[j
].ssa_name
;
2565 bool deref
= m_lattice
[index
].propagate_to
[j
].deref
;
2568 fprintf (dump_file
, " Propagating flags of ssa name"
2570 index
, target
, deref
? " (deref)" : "");
2571 m_lattice
[target
].known
= true;
2572 if (!m_lattice
[index
].propagate_to
[j
].deref
)
2573 ch
= m_lattice
[target
].merge (m_lattice
[index
]);
2575 ch
= m_lattice
[target
].merge_deref (m_lattice
[index
],
2581 fprintf (dump_file
, " New lattice: ");
2582 m_lattice
[target
].dump (dump_file
);
2585 m_lattice
[target
].changed
= true;
2591 fprintf (dump_file
, "EAF flags propagated in %i iterations\n", iterations
);
2594 /* Record escape points of PARM_INDEX according to LATTICE. */
2597 modref_eaf_analysis::record_escape_points (tree name
, int parm_index
, int flags
)
2599 modref_lattice
&lattice
= m_lattice
[SSA_NAME_VERSION (name
)];
2601 if (lattice
.escape_points
.length ())
2605 cgraph_node
*node
= cgraph_node::get (current_function_decl
);
2608 FOR_EACH_VEC_ELT (lattice
.escape_points
, ip
, ep
)
2609 if ((ep
->min_flags
& flags
) != flags
)
2611 cgraph_edge
*e
= node
->get_edge (ep
->call
);
2612 struct escape_entry ee
= {parm_index
, ep
->arg
,
2613 ep
->min_flags
, ep
->direct
};
2615 escape_summaries
->get_create (e
)->esc
.safe_push (ee
);
2620 /* Determine EAF flags for function parameters
2621 and fill in SUMMARY/SUMMARY_LTO. If IPA is true work in IPA mode
2622 where we also collect scape points.
2623 PAST_FLAGS, PAST_RETSLOT_FLAGS, PAST_STATIC_CHAIN_FLAGS can be
2624 used to preserve flags from prevoius (IPA) run for cases where
2625 late optimizations changed code in a way we can no longer analyze
2629 analyze_parms (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
2630 bool ipa
, vec
<eaf_flags_t
> &past_flags
,
2631 int past_retslot_flags
, int past_static_chain_flags
)
2633 unsigned int parm_index
= 0;
2634 unsigned int count
= 0;
2635 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
2636 tree retslot
= NULL
;
2637 tree static_chain
= NULL
;
2639 /* If there is return slot, look up its SSA name. */
2640 if (DECL_RESULT (current_function_decl
)
2641 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl
)))
2642 retslot
= ssa_default_def (cfun
, DECL_RESULT (current_function_decl
));
2643 if (cfun
->static_chain_decl
)
2644 static_chain
= ssa_default_def (cfun
, cfun
->static_chain_decl
);
2646 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
2647 parm
= TREE_CHAIN (parm
))
2650 if (!count
&& !retslot
&& !static_chain
)
2653 modref_eaf_analysis
eaf_analysis (ipa
);
2655 /* Determine all SSA names we need to know flags for. */
2656 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
2657 parm
= TREE_CHAIN (parm
))
2659 tree name
= ssa_default_def (cfun
, parm
);
2661 eaf_analysis
.analyze_ssa_name (name
);
2664 eaf_analysis
.analyze_ssa_name (retslot
);
2666 eaf_analysis
.analyze_ssa_name (static_chain
);
2668 /* Do the dataflow. */
2669 eaf_analysis
.propagate ();
2671 tree attr
= lookup_attribute ("fn spec",
2673 (TREE_TYPE (current_function_decl
)));
2674 attr_fnspec
fnspec (attr
2675 ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr
)))
2679 /* Store results to summaries. */
2680 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
; parm_index
++,
2681 parm
= TREE_CHAIN (parm
))
2683 tree name
= ssa_default_def (cfun
, parm
);
2684 if (!name
|| has_zero_uses (name
))
2686 /* We do not track non-SSA parameters,
2687 but we want to track unused gimple_regs. */
2688 if (!is_gimple_reg (parm
))
2692 if (parm_index
>= summary
->arg_flags
.length ())
2693 summary
->arg_flags
.safe_grow_cleared (count
, true);
2694 summary
->arg_flags
[parm_index
] = EAF_UNUSED
;
2696 else if (summary_lto
)
2698 if (parm_index
>= summary_lto
->arg_flags
.length ())
2699 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
2700 summary_lto
->arg_flags
[parm_index
] = EAF_UNUSED
;
2704 int flags
= eaf_analysis
.get_ssa_name_flags (name
);
2705 int attr_flags
= fnspec
.arg_eaf_flags (parm_index
);
2707 if (dump_file
&& (flags
| attr_flags
) != flags
&& !(flags
& EAF_UNUSED
))
2710 " Flags for param %i combined with fnspec flags:",
2712 dump_eaf_flags (dump_file
, attr_flags
, false);
2713 fprintf (dump_file
, " determined: ");
2714 dump_eaf_flags (dump_file
, flags
, true);
2716 flags
|= attr_flags
;
2718 /* Eliminate useless flags so we do not end up storing unnecessary
2721 flags
= remove_useless_eaf_flags
2723 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
2724 if (past_flags
.length () > parm_index
)
2726 int past
= past_flags
[parm_index
];
2727 past
= remove_useless_eaf_flags
2729 VOID_TYPE_P (TREE_TYPE
2730 (TREE_TYPE (current_function_decl
))));
2731 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
2734 " Flags for param %i combined with IPA pass:",
2736 dump_eaf_flags (dump_file
, past
, false);
2737 fprintf (dump_file
, " determined: ");
2738 dump_eaf_flags (dump_file
, flags
, true);
2740 if (!(flags
& EAF_UNUSED
))
2748 if (parm_index
>= summary
->arg_flags
.length ())
2749 summary
->arg_flags
.safe_grow_cleared (count
, true);
2750 summary
->arg_flags
[parm_index
] = flags
;
2752 else if (summary_lto
)
2754 if (parm_index
>= summary_lto
->arg_flags
.length ())
2755 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
2756 summary_lto
->arg_flags
[parm_index
] = flags
;
2758 eaf_analysis
.record_escape_points (name
, parm_index
, flags
);
2763 int flags
= eaf_analysis
.get_ssa_name_flags (retslot
);
2764 int past
= past_retslot_flags
;
2766 flags
= remove_useless_eaf_flags (flags
, ecf_flags
, false);
2767 past
= remove_useless_eaf_flags
2769 VOID_TYPE_P (TREE_TYPE
2770 (TREE_TYPE (current_function_decl
))));
2771 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
2774 " Retslot flags combined with IPA pass:");
2775 dump_eaf_flags (dump_file
, past
, false);
2776 fprintf (dump_file
, " determined: ");
2777 dump_eaf_flags (dump_file
, flags
, true);
2779 if (!(flags
& EAF_UNUSED
))
2784 summary
->retslot_flags
= flags
;
2786 summary_lto
->retslot_flags
= flags
;
2787 eaf_analysis
.record_escape_points (retslot
,
2788 MODREF_RETSLOT_PARM
, flags
);
2793 int flags
= eaf_analysis
.get_ssa_name_flags (static_chain
);
2794 int past
= past_static_chain_flags
;
2796 flags
= remove_useless_eaf_flags (flags
, ecf_flags
, false);
2797 past
= remove_useless_eaf_flags
2799 VOID_TYPE_P (TREE_TYPE
2800 (TREE_TYPE (current_function_decl
))));
2801 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
2804 " Static chain flags combined with IPA pass:");
2805 dump_eaf_flags (dump_file
, past
, false);
2806 fprintf (dump_file
, " determined: ");
2807 dump_eaf_flags (dump_file
, flags
, true);
2809 if (!(flags
& EAF_UNUSED
))
2814 summary
->static_chain_flags
= flags
;
2816 summary_lto
->static_chain_flags
= flags
;
2817 eaf_analysis
.record_escape_points (static_chain
,
2818 MODREF_STATIC_CHAIN_PARM
,
2824 /* Analyze function F. IPA indicates whether we're running in local mode
2825 (false) or the IPA mode (true).
2826 Return true if fixup cfg is needed after the pass. */
2829 analyze_function (function
*f
, bool ipa
)
2831 bool fixup_cfg
= false;
2833 fprintf (dump_file
, "modref analyzing '%s' (ipa=%i)%s%s\n",
2834 function_name (f
), ipa
,
2835 TREE_READONLY (current_function_decl
) ? " (const)" : "",
2836 DECL_PURE_P (current_function_decl
) ? " (pure)" : "");
2838 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
2839 if (!flag_ipa_modref
2840 || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl
)))
2843 /* Compute no-LTO summaries when local optimization is going to happen. */
2844 bool nolto
= (!ipa
|| ((!flag_lto
|| flag_fat_lto_objects
) && !in_lto_p
)
2845 || (in_lto_p
&& !flag_wpa
2846 && flag_incremental_link
!= INCREMENTAL_LINK_LTO
));
2847 /* Compute LTO when LTO streaming is going to happen. */
2848 bool lto
= ipa
&& ((flag_lto
&& !in_lto_p
)
2850 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
2851 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
2853 modref_summary
*summary
= NULL
;
2854 modref_summary_lto
*summary_lto
= NULL
;
2856 bool past_flags_known
= false;
2857 auto_vec
<eaf_flags_t
> past_flags
;
2858 int past_retslot_flags
= 0;
2859 int past_static_chain_flags
= 0;
2861 /* Initialize the summary.
2862 If we run in local mode there is possibly pre-existing summary from
2863 IPA pass. Dump it so it is easy to compare if mod-ref info has
2867 if (!optimization_summaries
)
2868 optimization_summaries
= modref_summaries::create_ggc (symtab
);
2869 else /* Remove existing summary if we are re-running the pass. */
2873 = optimization_summaries
->get (cgraph_node::get (f
->decl
)))
2877 fprintf (dump_file
, "Past summary:\n");
2878 optimization_summaries
->get
2879 (cgraph_node::get (f
->decl
))->dump (dump_file
);
2880 past_flags
.reserve_exact (summary
->arg_flags
.length ());
2881 past_flags
.splice (summary
->arg_flags
);
2882 past_retslot_flags
= summary
->retslot_flags
;
2883 past_static_chain_flags
= summary
->static_chain_flags
;
2884 past_flags_known
= true;
2886 optimization_summaries
->remove (cgraph_node::get (f
->decl
));
2888 summary
= optimization_summaries
->get_create (cgraph_node::get (f
->decl
));
2889 gcc_checking_assert (nolto
&& !lto
);
2891 /* In IPA mode we analyze every function precisely once. Assert that. */
2897 summaries
= modref_summaries::create_ggc (symtab
);
2899 summaries
->remove (cgraph_node::get (f
->decl
));
2900 summary
= summaries
->get_create (cgraph_node::get (f
->decl
));
2905 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
2907 summaries_lto
->remove (cgraph_node::get (f
->decl
));
2908 summary_lto
= summaries_lto
->get_create (cgraph_node::get (f
->decl
));
2910 if (!fnspec_summaries
)
2911 fnspec_summaries
= new fnspec_summaries_t (symtab
);
2912 if (!escape_summaries
)
2913 escape_summaries
= new escape_summaries_t (symtab
);
2917 /* Create and initialize summary for F.
2918 Note that summaries may be already allocated from previous
2922 gcc_assert (!summary
->loads
);
2923 summary
->loads
= modref_records::create_ggc (param_modref_max_bases
,
2924 param_modref_max_refs
,
2925 param_modref_max_accesses
);
2926 gcc_assert (!summary
->stores
);
2927 summary
->stores
= modref_records::create_ggc (param_modref_max_bases
,
2928 param_modref_max_refs
,
2929 param_modref_max_accesses
);
2930 summary
->writes_errno
= false;
2931 summary
->side_effects
= false;
2932 summary
->nondeterministic
= false;
2933 summary
->calls_interposable
= false;
2937 gcc_assert (!summary_lto
->loads
);
2938 summary_lto
->loads
= modref_records_lto::create_ggc
2939 (param_modref_max_bases
,
2940 param_modref_max_refs
,
2941 param_modref_max_accesses
);
2942 gcc_assert (!summary_lto
->stores
);
2943 summary_lto
->stores
= modref_records_lto::create_ggc
2944 (param_modref_max_bases
,
2945 param_modref_max_refs
,
2946 param_modref_max_accesses
);
2947 summary_lto
->writes_errno
= false;
2948 summary_lto
->side_effects
= false;
2949 summary_lto
->nondeterministic
= false;
2950 summary_lto
->calls_interposable
= false;
2953 analyze_parms (summary
, summary_lto
, ipa
,
2954 past_flags
, past_retslot_flags
, past_static_chain_flags
);
2956 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
2957 auto_vec
<gimple
*, 32> recursive_calls
;
2959 /* Analyze each statement in each basic block of the function. If the
2960 statement cannot be analyzed (for any reason), the entire function cannot
2961 be analyzed by modref. */
2963 FOR_EACH_BB_FN (bb
, f
)
2965 gimple_stmt_iterator si
;
2966 bool always_executed
2967 = bb
== single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun
))->dest
;
2969 for (si
= gsi_start_nondebug_after_labels_bb (bb
);
2970 !gsi_end_p (si
); gsi_next_nondebug (&si
))
2972 if (!analyze_stmt (summary
, summary_lto
,
2973 gsi_stmt (si
), ipa
, &recursive_calls
,
2975 || ((!summary
|| !summary
->useful_p (ecf_flags
, false))
2977 || !summary_lto
->useful_p (ecf_flags
, false))))
2979 collapse_loads (summary
, summary_lto
);
2980 collapse_stores (summary
, summary_lto
);
2984 && stmt_can_throw_external (cfun
, gsi_stmt (si
)))
2985 always_executed
= false;
2989 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2990 This needs to be done after all other side effects are computed. */
2993 bool changed
= true;
2998 for (unsigned i
= 0; i
< recursive_calls
.length (); i
++)
3000 changed
|= merge_call_side_effects
3001 (summary
, recursive_calls
[i
], summary
,
3002 ignore_stores_p (current_function_decl
,
3004 (recursive_calls
[i
])),
3005 fnode
, !first
, false);
3006 if (!summary
->useful_p (ecf_flags
, false))
3008 remove_summary (lto
, nolto
, ipa
);
3015 if (summary
&& !summary
->side_effects
&& !finite_function_p ())
3016 summary
->side_effects
= true;
3017 if (summary_lto
&& !summary_lto
->side_effects
&& !finite_function_p ())
3018 summary_lto
->side_effects
= true;
3020 if (!ipa
&& flag_ipa_pure_const
)
3022 if (!summary
->stores
->every_base
&& !summary
->stores
->bases
3023 && !summary
->nondeterministic
)
3025 if (!summary
->loads
->every_base
&& !summary
->loads
->bases
3026 && !summary
->calls_interposable
)
3027 fixup_cfg
= ipa_make_function_const
3028 (cgraph_node::get (current_function_decl
),
3029 summary
->side_effects
, true);
3031 fixup_cfg
= ipa_make_function_pure
3032 (cgraph_node::get (current_function_decl
),
3033 summary
->side_effects
, true);
3036 if (summary
&& !summary
->useful_p (ecf_flags
))
3039 optimization_summaries
->remove (fnode
);
3041 summaries
->remove (fnode
);
3045 summary
->finalize (current_function_decl
);
3046 if (summary_lto
&& !summary_lto
->useful_p (ecf_flags
))
3048 summaries_lto
->remove (fnode
);
3052 if (ipa
&& !summary
&& !summary_lto
)
3053 remove_modref_edge_summaries (fnode
);
3057 fprintf (dump_file
, " - modref done with result: tracked.\n");
3059 summary
->dump (dump_file
);
3061 summary_lto
->dump (dump_file
);
3062 dump_modref_edge_summaries (dump_file
, fnode
, 2);
3063 /* To simplify debugging, compare IPA and local solutions. */
3064 if (past_flags_known
&& summary
)
3066 size_t len
= summary
->arg_flags
.length ();
3068 if (past_flags
.length () > len
)
3069 len
= past_flags
.length ();
3070 for (size_t i
= 0; i
< len
; i
++)
3072 int old_flags
= i
< past_flags
.length () ? past_flags
[i
] : 0;
3073 int new_flags
= i
< summary
->arg_flags
.length ()
3074 ? summary
->arg_flags
[i
] : 0;
3075 old_flags
= remove_useless_eaf_flags
3076 (old_flags
, flags_from_decl_or_type (current_function_decl
),
3077 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3078 if (old_flags
!= new_flags
)
3080 if ((old_flags
& ~new_flags
) == 0
3081 || (new_flags
& EAF_UNUSED
))
3082 fprintf (dump_file
, " Flags for param %i improved:",
3086 dump_eaf_flags (dump_file
, old_flags
, false);
3087 fprintf (dump_file
, " -> ");
3088 dump_eaf_flags (dump_file
, new_flags
, true);
3091 past_retslot_flags
= remove_useless_eaf_flags
3092 (past_retslot_flags
,
3093 flags_from_decl_or_type (current_function_decl
),
3094 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3095 if (past_retslot_flags
!= summary
->retslot_flags
)
3097 if ((past_retslot_flags
& ~summary
->retslot_flags
) == 0
3098 || (summary
->retslot_flags
& EAF_UNUSED
))
3099 fprintf (dump_file
, " Flags for retslot improved:");
3102 dump_eaf_flags (dump_file
, past_retslot_flags
, false);
3103 fprintf (dump_file
, " -> ");
3104 dump_eaf_flags (dump_file
, summary
->retslot_flags
, true);
3106 past_static_chain_flags
= remove_useless_eaf_flags
3107 (past_static_chain_flags
,
3108 flags_from_decl_or_type (current_function_decl
),
3109 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3110 if (past_static_chain_flags
!= summary
->static_chain_flags
)
3112 if ((past_static_chain_flags
& ~summary
->static_chain_flags
) == 0
3113 || (summary
->static_chain_flags
& EAF_UNUSED
))
3114 fprintf (dump_file
, " Flags for static chain improved:");
3117 dump_eaf_flags (dump_file
, past_static_chain_flags
, false);
3118 fprintf (dump_file
, " -> ");
3119 dump_eaf_flags (dump_file
, summary
->static_chain_flags
, true);
3122 else if (past_flags_known
&& !summary
)
3124 for (size_t i
= 0; i
< past_flags
.length (); i
++)
3126 int old_flags
= past_flags
[i
];
3127 old_flags
= remove_useless_eaf_flags
3128 (old_flags
, flags_from_decl_or_type (current_function_decl
),
3129 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3132 fprintf (dump_file
, " Flags for param %i worsened:",
3134 dump_eaf_flags (dump_file
, old_flags
, false);
3135 fprintf (dump_file
, " -> \n");
3138 past_retslot_flags
= remove_useless_eaf_flags
3139 (past_retslot_flags
,
3140 flags_from_decl_or_type (current_function_decl
),
3141 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3142 if (past_retslot_flags
)
3144 fprintf (dump_file
, " Flags for retslot worsened:");
3145 dump_eaf_flags (dump_file
, past_retslot_flags
, false);
3146 fprintf (dump_file
, " ->\n");
3148 past_static_chain_flags
= remove_useless_eaf_flags
3149 (past_static_chain_flags
,
3150 flags_from_decl_or_type (current_function_decl
),
3151 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3152 if (past_static_chain_flags
)
3154 fprintf (dump_file
, " Flags for static chain worsened:");
3155 dump_eaf_flags (dump_file
, past_static_chain_flags
, false);
3156 fprintf (dump_file
, " ->\n");
3163 /* Callback for generate_summary. */
3166 modref_generate (void)
3168 struct cgraph_node
*node
;
3169 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
3171 function
*f
= DECL_STRUCT_FUNCTION (node
->decl
);
3175 analyze_function (f
, true);
3180 } /* ANON namespace. */
3182 /* Debugging helper. */
3185 debug_eaf_flags (int flags
)
3187 dump_eaf_flags (stderr
, flags
, true);
3190 /* Called when a new function is inserted to callgraph late. */
3193 modref_summaries::insert (struct cgraph_node
*node
, modref_summary
*)
3195 /* Local passes ought to be executed by the pass manager. */
3196 if (this == optimization_summaries
)
3198 optimization_summaries
->remove (node
);
3201 if (!DECL_STRUCT_FUNCTION (node
->decl
)
3202 || !opt_for_fn (node
->decl
, flag_ipa_modref
))
3204 summaries
->remove (node
);
3207 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
3208 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
3212 /* Called when a new function is inserted to callgraph late. */
3215 modref_summaries_lto::insert (struct cgraph_node
*node
, modref_summary_lto
*)
3217 /* We do not support adding new function when IPA information is already
3218 propagated. This is done only by SIMD cloning that is not very
3220 if (!DECL_STRUCT_FUNCTION (node
->decl
)
3221 || !opt_for_fn (node
->decl
, flag_ipa_modref
)
3224 summaries_lto
->remove (node
);
3227 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
3228 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
3232 /* Called when new clone is inserted to callgraph late. */
3235 modref_summaries::duplicate (cgraph_node
*, cgraph_node
*dst
,
3236 modref_summary
*src_data
,
3237 modref_summary
*dst_data
)
3239 /* Do not duplicate optimization summaries; we do not handle parameter
3240 transforms on them. */
3241 if (this == optimization_summaries
)
3243 optimization_summaries
->remove (dst
);
3246 dst_data
->stores
= modref_records::create_ggc
3247 (src_data
->stores
->max_bases
,
3248 src_data
->stores
->max_refs
,
3249 src_data
->stores
->max_accesses
);
3250 dst_data
->stores
->copy_from (src_data
->stores
);
3251 dst_data
->loads
= modref_records::create_ggc
3252 (src_data
->loads
->max_bases
,
3253 src_data
->loads
->max_refs
,
3254 src_data
->loads
->max_accesses
);
3255 dst_data
->loads
->copy_from (src_data
->loads
);
3256 dst_data
->kills
.reserve_exact (src_data
->kills
.length ());
3257 dst_data
->kills
.splice (src_data
->kills
);
3258 dst_data
->writes_errno
= src_data
->writes_errno
;
3259 dst_data
->side_effects
= src_data
->side_effects
;
3260 dst_data
->nondeterministic
= src_data
->nondeterministic
;
3261 dst_data
->calls_interposable
= src_data
->calls_interposable
;
3262 if (src_data
->arg_flags
.length ())
3263 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
3264 dst_data
->retslot_flags
= src_data
->retslot_flags
;
3265 dst_data
->static_chain_flags
= src_data
->static_chain_flags
;
3268 /* Called when new clone is inserted to callgraph late. */
3271 modref_summaries_lto::duplicate (cgraph_node
*, cgraph_node
*,
3272 modref_summary_lto
*src_data
,
3273 modref_summary_lto
*dst_data
)
3275 /* Be sure that no further cloning happens after ipa-modref. If it does
3276 we will need to update signatures for possible param changes. */
3277 gcc_checking_assert (!((modref_summaries_lto
*)summaries_lto
)->propagated
);
3278 dst_data
->stores
= modref_records_lto::create_ggc
3279 (src_data
->stores
->max_bases
,
3280 src_data
->stores
->max_refs
,
3281 src_data
->stores
->max_accesses
);
3282 dst_data
->stores
->copy_from (src_data
->stores
);
3283 dst_data
->loads
= modref_records_lto::create_ggc
3284 (src_data
->loads
->max_bases
,
3285 src_data
->loads
->max_refs
,
3286 src_data
->loads
->max_accesses
);
3287 dst_data
->loads
->copy_from (src_data
->loads
);
3288 dst_data
->kills
.reserve_exact (src_data
->kills
.length ());
3289 dst_data
->kills
.splice (src_data
->kills
);
3290 dst_data
->writes_errno
= src_data
->writes_errno
;
3291 dst_data
->side_effects
= src_data
->side_effects
;
3292 dst_data
->nondeterministic
= src_data
->nondeterministic
;
3293 dst_data
->calls_interposable
= src_data
->calls_interposable
;
3294 if (src_data
->arg_flags
.length ())
3295 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
3296 dst_data
->retslot_flags
= src_data
->retslot_flags
;
3297 dst_data
->static_chain_flags
= src_data
->static_chain_flags
;
3302 /* Definition of the modref pass on GIMPLE. */
3303 const pass_data pass_data_modref
= {
3308 (PROP_cfg
| PROP_ssa
),
3315 class pass_modref
: public gimple_opt_pass
3318 pass_modref (gcc::context
*ctxt
)
3319 : gimple_opt_pass (pass_data_modref
, ctxt
) {}
3321 /* opt_pass methods: */
3324 return new pass_modref (m_ctxt
);
3326 virtual bool gate (function
*)
3328 return flag_ipa_modref
;
3330 virtual unsigned int execute (function
*);
3333 /* Encode TT to the output block OB using the summary streaming API. */
3336 write_modref_records (modref_records_lto
*tt
, struct output_block
*ob
)
3338 streamer_write_uhwi (ob
, tt
->max_bases
);
3339 streamer_write_uhwi (ob
, tt
->max_refs
);
3340 streamer_write_uhwi (ob
, tt
->max_accesses
);
3342 streamer_write_uhwi (ob
, tt
->every_base
);
3343 streamer_write_uhwi (ob
, vec_safe_length (tt
->bases
));
3344 for (auto base_node
: tt
->bases
)
3346 stream_write_tree (ob
, base_node
->base
, true);
3348 streamer_write_uhwi (ob
, base_node
->every_ref
);
3349 streamer_write_uhwi (ob
, vec_safe_length (base_node
->refs
));
3351 for (auto ref_node
: base_node
->refs
)
3353 stream_write_tree (ob
, ref_node
->ref
, true);
3354 streamer_write_uhwi (ob
, ref_node
->every_access
);
3355 streamer_write_uhwi (ob
, vec_safe_length (ref_node
->accesses
));
3357 for (auto access_node
: ref_node
->accesses
)
3358 access_node
.stream_out (ob
);
3363 /* Read a modref_tree from the input block IB using the data from DATA_IN.
3364 This assumes that the tree was encoded using write_modref_tree.
3365 Either nolto_ret or lto_ret is initialized by the tree depending whether
3366 LTO streaming is expected or not. */
3369 read_modref_records (lto_input_block
*ib
, struct data_in
*data_in
,
3370 modref_records
**nolto_ret
,
3371 modref_records_lto
**lto_ret
)
3373 size_t max_bases
= streamer_read_uhwi (ib
);
3374 size_t max_refs
= streamer_read_uhwi (ib
);
3375 size_t max_accesses
= streamer_read_uhwi (ib
);
3378 *lto_ret
= modref_records_lto::create_ggc (max_bases
, max_refs
,
3381 *nolto_ret
= modref_records::create_ggc (max_bases
, max_refs
,
3383 gcc_checking_assert (lto_ret
|| nolto_ret
);
3385 size_t every_base
= streamer_read_uhwi (ib
);
3386 size_t nbase
= streamer_read_uhwi (ib
);
3388 gcc_assert (!every_base
|| nbase
== 0);
3392 (*nolto_ret
)->collapse ();
3394 (*lto_ret
)->collapse ();
3396 for (size_t i
= 0; i
< nbase
; i
++)
3398 tree base_tree
= stream_read_tree (ib
, data_in
);
3399 modref_base_node
<alias_set_type
> *nolto_base_node
= NULL
;
3400 modref_base_node
<tree
> *lto_base_node
= NULL
;
3402 /* At stream in time we have LTO alias info. Check if we streamed in
3403 something obviously unnecessary. Do not glob types by alias sets;
3404 it is not 100% clear that ltrans types will get merged same way.
3405 Types may get refined based on ODR type conflicts. */
3406 if (base_tree
&& !get_alias_set (base_tree
))
3410 fprintf (dump_file
, "Streamed in alias set 0 type ");
3411 print_generic_expr (dump_file
, base_tree
);
3412 fprintf (dump_file
, "\n");
3418 nolto_base_node
= (*nolto_ret
)->insert_base (base_tree
3419 ? get_alias_set (base_tree
)
3422 lto_base_node
= (*lto_ret
)->insert_base (base_tree
, 0);
3423 size_t every_ref
= streamer_read_uhwi (ib
);
3424 size_t nref
= streamer_read_uhwi (ib
);
3426 gcc_assert (!every_ref
|| nref
== 0);
3429 if (nolto_base_node
)
3430 nolto_base_node
->collapse ();
3432 lto_base_node
->collapse ();
3434 for (size_t j
= 0; j
< nref
; j
++)
3436 tree ref_tree
= stream_read_tree (ib
, data_in
);
3438 if (ref_tree
&& !get_alias_set (ref_tree
))
3442 fprintf (dump_file
, "Streamed in alias set 0 type ");
3443 print_generic_expr (dump_file
, ref_tree
);
3444 fprintf (dump_file
, "\n");
3449 modref_ref_node
<alias_set_type
> *nolto_ref_node
= NULL
;
3450 modref_ref_node
<tree
> *lto_ref_node
= NULL
;
3452 if (nolto_base_node
)
3454 = nolto_base_node
->insert_ref (ref_tree
3455 ? get_alias_set (ref_tree
) : 0,
3458 lto_ref_node
= lto_base_node
->insert_ref (ref_tree
, max_refs
);
3460 size_t every_access
= streamer_read_uhwi (ib
);
3461 size_t naccesses
= streamer_read_uhwi (ib
);
3463 if (nolto_ref_node
&& every_access
)
3464 nolto_ref_node
->collapse ();
3465 if (lto_ref_node
&& every_access
)
3466 lto_ref_node
->collapse ();
3468 for (size_t k
= 0; k
< naccesses
; k
++)
3470 modref_access_node a
= modref_access_node::stream_in (ib
);
3472 nolto_ref_node
->insert_access (a
, max_accesses
, false);
3474 lto_ref_node
->insert_access (a
, max_accesses
, false);
3479 (*lto_ret
)->cleanup ();
3481 (*nolto_ret
)->cleanup ();
3484 /* Write ESUM to BP. */
3487 modref_write_escape_summary (struct bitpack_d
*bp
, escape_summary
*esum
)
3491 bp_pack_var_len_unsigned (bp
, 0);
3494 bp_pack_var_len_unsigned (bp
, esum
->esc
.length ());
3497 FOR_EACH_VEC_ELT (esum
->esc
, i
, ee
)
3499 bp_pack_var_len_int (bp
, ee
->parm_index
);
3500 bp_pack_var_len_unsigned (bp
, ee
->arg
);
3501 bp_pack_var_len_unsigned (bp
, ee
->min_flags
);
3502 bp_pack_value (bp
, ee
->direct
, 1);
3506 /* Read escape summary for E from BP. */
3509 modref_read_escape_summary (struct bitpack_d
*bp
, cgraph_edge
*e
)
3511 unsigned int n
= bp_unpack_var_len_unsigned (bp
);
3514 escape_summary
*esum
= escape_summaries
->get_create (e
);
3515 esum
->esc
.reserve_exact (n
);
3516 for (unsigned int i
= 0; i
< n
; i
++)
3519 ee
.parm_index
= bp_unpack_var_len_int (bp
);
3520 ee
.arg
= bp_unpack_var_len_unsigned (bp
);
3521 ee
.min_flags
= bp_unpack_var_len_unsigned (bp
);
3522 ee
.direct
= bp_unpack_value (bp
, 1);
3523 esum
->esc
.quick_push (ee
);
3527 /* Callback for write_summary. */
3532 struct output_block
*ob
= create_output_block (LTO_section_ipa_modref
);
3533 lto_symtab_encoder_t encoder
= ob
->decl_state
->symtab_node_encoder
;
3534 unsigned int count
= 0;
3539 streamer_write_uhwi (ob
, 0);
3540 streamer_write_char_stream (ob
->main_stream
, 0);
3541 produce_asm (ob
, NULL
);
3542 destroy_output_block (ob
);
3546 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
3548 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
3549 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
3550 modref_summary_lto
*r
;
3552 if (cnode
&& cnode
->definition
&& !cnode
->alias
3553 && (r
= summaries_lto
->get (cnode
))
3554 && r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
3557 streamer_write_uhwi (ob
, count
);
3559 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
3561 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
3562 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
3564 if (cnode
&& cnode
->definition
&& !cnode
->alias
)
3566 modref_summary_lto
*r
= summaries_lto
->get (cnode
);
3568 if (!r
|| !r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
3571 streamer_write_uhwi (ob
, lto_symtab_encoder_encode (encoder
, cnode
));
3573 streamer_write_uhwi (ob
, r
->arg_flags
.length ());
3574 for (unsigned int i
= 0; i
< r
->arg_flags
.length (); i
++)
3575 streamer_write_uhwi (ob
, r
->arg_flags
[i
]);
3576 streamer_write_uhwi (ob
, r
->retslot_flags
);
3577 streamer_write_uhwi (ob
, r
->static_chain_flags
);
3579 write_modref_records (r
->loads
, ob
);
3580 write_modref_records (r
->stores
, ob
);
3581 streamer_write_uhwi (ob
, r
->kills
.length ());
3582 for (auto kill
: r
->kills
)
3583 kill
.stream_out (ob
);
3585 struct bitpack_d bp
= bitpack_create (ob
->main_stream
);
3586 bp_pack_value (&bp
, r
->writes_errno
, 1);
3587 bp_pack_value (&bp
, r
->side_effects
, 1);
3588 bp_pack_value (&bp
, r
->nondeterministic
, 1);
3589 bp_pack_value (&bp
, r
->calls_interposable
, 1);
3592 for (cgraph_edge
*e
= cnode
->indirect_calls
;
3593 e
; e
= e
->next_callee
)
3595 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
3596 bp_pack_value (&bp
, sum
!= NULL
, 1);
3598 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
3599 class escape_summary
*esum
= escape_summaries
->get (e
);
3600 modref_write_escape_summary (&bp
,esum
);
3602 for (cgraph_edge
*e
= cnode
->callees
; e
; e
= e
->next_callee
)
3604 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
3605 bp_pack_value (&bp
, sum
!= NULL
, 1);
3607 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
3608 class escape_summary
*esum
= escape_summaries
->get (e
);
3609 modref_write_escape_summary (&bp
,esum
);
3612 streamer_write_bitpack (&bp
);
3615 streamer_write_char_stream (ob
->main_stream
, 0);
3616 produce_asm (ob
, NULL
);
3617 destroy_output_block (ob
);
3621 read_section (struct lto_file_decl_data
*file_data
, const char *data
,
3624 const struct lto_function_header
*header
3625 = (const struct lto_function_header
*) data
;
3626 const int cfg_offset
= sizeof (struct lto_function_header
);
3627 const int main_offset
= cfg_offset
+ header
->cfg_size
;
3628 const int string_offset
= main_offset
+ header
->main_size
;
3629 struct data_in
*data_in
;
3631 unsigned int f_count
;
3633 lto_input_block
ib ((const char *) data
+ main_offset
, header
->main_size
,
3634 file_data
->mode_table
);
3637 = lto_data_in_create (file_data
, (const char *) data
+ string_offset
,
3638 header
->string_size
, vNULL
);
3639 f_count
= streamer_read_uhwi (&ib
);
3640 for (i
= 0; i
< f_count
; i
++)
3642 struct cgraph_node
*node
;
3643 lto_symtab_encoder_t encoder
;
3645 unsigned int index
= streamer_read_uhwi (&ib
);
3646 encoder
= file_data
->symtab_node_encoder
;
3647 node
= dyn_cast
<cgraph_node
*> (lto_symtab_encoder_deref (encoder
,
3650 modref_summary
*modref_sum
= summaries
3651 ? summaries
->get_create (node
) : NULL
;
3652 modref_summary_lto
*modref_sum_lto
= summaries_lto
3653 ? summaries_lto
->get_create (node
)
3655 if (optimization_summaries
)
3656 modref_sum
= optimization_summaries
->get_create (node
);
3660 modref_sum
->writes_errno
= false;
3661 modref_sum
->side_effects
= false;
3662 modref_sum
->nondeterministic
= false;
3663 modref_sum
->calls_interposable
= false;
3667 modref_sum_lto
->writes_errno
= false;
3668 modref_sum_lto
->side_effects
= false;
3669 modref_sum_lto
->nondeterministic
= false;
3670 modref_sum_lto
->calls_interposable
= false;
3673 gcc_assert (!modref_sum
|| (!modref_sum
->loads
3674 && !modref_sum
->stores
));
3675 gcc_assert (!modref_sum_lto
|| (!modref_sum_lto
->loads
3676 && !modref_sum_lto
->stores
));
3677 unsigned int args
= streamer_read_uhwi (&ib
);
3678 if (args
&& modref_sum
)
3679 modref_sum
->arg_flags
.reserve_exact (args
);
3680 if (args
&& modref_sum_lto
)
3681 modref_sum_lto
->arg_flags
.reserve_exact (args
);
3682 for (unsigned int i
= 0; i
< args
; i
++)
3684 eaf_flags_t flags
= streamer_read_uhwi (&ib
);
3686 modref_sum
->arg_flags
.quick_push (flags
);
3688 modref_sum_lto
->arg_flags
.quick_push (flags
);
3690 eaf_flags_t flags
= streamer_read_uhwi (&ib
);
3692 modref_sum
->retslot_flags
= flags
;
3694 modref_sum_lto
->retslot_flags
= flags
;
3696 flags
= streamer_read_uhwi (&ib
);
3698 modref_sum
->static_chain_flags
= flags
;
3700 modref_sum_lto
->static_chain_flags
= flags
;
3702 read_modref_records (&ib
, data_in
,
3703 modref_sum
? &modref_sum
->loads
: NULL
,
3704 modref_sum_lto
? &modref_sum_lto
->loads
: NULL
);
3705 read_modref_records (&ib
, data_in
,
3706 modref_sum
? &modref_sum
->stores
: NULL
,
3707 modref_sum_lto
? &modref_sum_lto
->stores
: NULL
);
3708 int j
= streamer_read_uhwi (&ib
);
3709 if (j
&& modref_sum
)
3710 modref_sum
->kills
.reserve_exact (j
);
3711 if (j
&& modref_sum_lto
)
3712 modref_sum_lto
->kills
.reserve_exact (j
);
3713 for (int k
= 0; k
< j
; k
++)
3715 modref_access_node a
= modref_access_node::stream_in (&ib
);
3718 modref_sum
->kills
.quick_push (a
);
3720 modref_sum_lto
->kills
.quick_push (a
);
3722 struct bitpack_d bp
= streamer_read_bitpack (&ib
);
3723 if (bp_unpack_value (&bp
, 1))
3726 modref_sum
->writes_errno
= true;
3728 modref_sum_lto
->writes_errno
= true;
3730 if (bp_unpack_value (&bp
, 1))
3733 modref_sum
->side_effects
= true;
3735 modref_sum_lto
->side_effects
= true;
3737 if (bp_unpack_value (&bp
, 1))
3740 modref_sum
->nondeterministic
= true;
3742 modref_sum_lto
->nondeterministic
= true;
3744 if (bp_unpack_value (&bp
, 1))
3747 modref_sum
->calls_interposable
= true;
3749 modref_sum_lto
->calls_interposable
= true;
3753 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
3755 if (bp_unpack_value (&bp
, 1))
3757 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
3758 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
3760 modref_read_escape_summary (&bp
, e
);
3762 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
3764 if (bp_unpack_value (&bp
, 1))
3766 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
3767 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
3769 modref_read_escape_summary (&bp
, e
);
3773 modref_sum
->finalize (node
->decl
);
3776 fprintf (dump_file
, "Read modref for %s\n",
3777 node
->dump_name ());
3779 modref_sum
->dump (dump_file
);
3781 modref_sum_lto
->dump (dump_file
);
3782 dump_modref_edge_summaries (dump_file
, node
, 4);
3786 lto_free_section_data (file_data
, LTO_section_ipa_modref
, NULL
, data
,
3788 lto_data_in_delete (data_in
);
3791 /* Callback for read_summary. */
3796 struct lto_file_decl_data
**file_data_vec
= lto_get_file_decl_data ();
3797 struct lto_file_decl_data
*file_data
;
3800 gcc_checking_assert (!optimization_summaries
&& !summaries
&& !summaries_lto
);
3802 optimization_summaries
= modref_summaries::create_ggc (symtab
);
3805 if (flag_wpa
|| flag_incremental_link
== INCREMENTAL_LINK_LTO
)
3806 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
3808 || (flag_incremental_link
== INCREMENTAL_LINK_LTO
3809 && flag_fat_lto_objects
))
3810 summaries
= modref_summaries::create_ggc (symtab
);
3811 if (!fnspec_summaries
)
3812 fnspec_summaries
= new fnspec_summaries_t (symtab
);
3813 if (!escape_summaries
)
3814 escape_summaries
= new escape_summaries_t (symtab
);
3817 while ((file_data
= file_data_vec
[j
++]))
3820 const char *data
= lto_get_summary_section_data (file_data
,
3821 LTO_section_ipa_modref
,
3824 read_section (file_data
, data
, len
);
3826 /* Fatal error here. We do not want to support compiling ltrans units
3827 with different version of compiler or different flags than the WPA
3828 unit, so this should never happen. */
3829 fatal_error (input_location
,
3830 "IPA modref summary is missing in input file");
3834 /* Recompute arg_flags for param adjustments in INFO. */
3837 remap_arg_flags (auto_vec
<eaf_flags_t
> &arg_flags
, clone_info
*info
)
3839 auto_vec
<eaf_flags_t
> old
= arg_flags
.copy ();
3842 ipa_adjusted_param
*p
;
3844 arg_flags
.release ();
3846 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
3848 int o
= info
->param_adjustments
->get_original_index (i
);
3849 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
3853 arg_flags
.safe_grow_cleared (max
+ 1, true);
3854 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
3856 int o
= info
->param_adjustments
->get_original_index (i
);
3857 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
3858 arg_flags
[i
] = old
[o
];
3862 /* Update kills accrdoing to the parm map MAP. */
3865 remap_kills (vec
<modref_access_node
> &kills
, const vec
<int> &map
)
3867 for (size_t i
= 0; i
< kills
.length ();)
3868 if (kills
[i
].parm_index
>= 0)
3870 if (kills
[i
].parm_index
< (int)map
.length ()
3871 && map
[kills
[i
].parm_index
] != MODREF_UNKNOWN_PARM
)
3873 kills
[i
].parm_index
= map
[kills
[i
].parm_index
];
3877 kills
.unordered_remove (i
);
3883 /* If signature changed, update the summary. */
3886 update_signature (struct cgraph_node
*node
)
3888 clone_info
*info
= clone_info::get (node
);
3889 if (!info
|| !info
->param_adjustments
)
3892 modref_summary
*r
= optimization_summaries
3893 ? optimization_summaries
->get (node
) : NULL
;
3894 modref_summary_lto
*r_lto
= summaries_lto
3895 ? summaries_lto
->get (node
) : NULL
;
3900 fprintf (dump_file
, "Updating summary for %s from:\n",
3901 node
->dump_name ());
3903 r
->dump (dump_file
);
3905 r_lto
->dump (dump_file
);
3909 ipa_adjusted_param
*p
;
3911 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
3913 int idx
= info
->param_adjustments
->get_original_index (i
);
3918 auto_vec
<int, 32> map
;
3920 map
.reserve (max
+ 1);
3921 for (i
= 0; i
<= max
; i
++)
3922 map
.quick_push (MODREF_UNKNOWN_PARM
);
3923 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
3925 int idx
= info
->param_adjustments
->get_original_index (i
);
3931 r
->loads
->remap_params (&map
);
3932 r
->stores
->remap_params (&map
);
3933 remap_kills (r
->kills
, map
);
3934 if (r
->arg_flags
.length ())
3935 remap_arg_flags (r
->arg_flags
, info
);
3939 r_lto
->loads
->remap_params (&map
);
3940 r_lto
->stores
->remap_params (&map
);
3941 remap_kills (r_lto
->kills
, map
);
3942 if (r_lto
->arg_flags
.length ())
3943 remap_arg_flags (r_lto
->arg_flags
, info
);
3947 fprintf (dump_file
, "to:\n");
3949 r
->dump (dump_file
);
3951 r_lto
->dump (dump_file
);
3954 r
->finalize (node
->decl
);
3958 /* Definition of the modref IPA pass. */
3959 const pass_data pass_data_ipa_modref
=
3961 IPA_PASS
, /* type */
3962 "modref", /* name */
3963 OPTGROUP_IPA
, /* optinfo_flags */
3964 TV_IPA_MODREF
, /* tv_id */
3965 0, /* properties_required */
3966 0, /* properties_provided */
3967 0, /* properties_destroyed */
3968 0, /* todo_flags_start */
3969 ( TODO_dump_symtab
), /* todo_flags_finish */
3972 class pass_ipa_modref
: public ipa_opt_pass_d
3975 pass_ipa_modref (gcc::context
*ctxt
)
3976 : ipa_opt_pass_d (pass_data_ipa_modref
, ctxt
,
3977 modref_generate
, /* generate_summary */
3978 modref_write
, /* write_summary */
3979 modref_read
, /* read_summary */
3980 modref_write
, /* write_optimization_summary */
3981 modref_read
, /* read_optimization_summary */
3982 NULL
, /* stmt_fixup */
3983 0, /* function_transform_todo_flags_start */
3984 NULL
, /* function_transform */
3985 NULL
) /* variable_transform */
3988 /* opt_pass methods: */
3989 opt_pass
*clone () { return new pass_ipa_modref (m_ctxt
); }
3990 virtual bool gate (function
*)
3994 virtual unsigned int execute (function
*);
4000 unsigned int pass_modref::execute (function
*f
)
4002 if (analyze_function (f
, false))
4003 return execute_fixup_cfg ();
4008 make_pass_modref (gcc::context
*ctxt
)
4010 return new pass_modref (ctxt
);
4014 make_pass_ipa_modref (gcc::context
*ctxt
)
4016 return new pass_ipa_modref (ctxt
);
4021 /* Skip edges from and to nodes without ipa_pure_const enabled.
4022 Ignore not available symbols. */
4025 ignore_edge (struct cgraph_edge
*e
)
4027 /* We merge summaries of inline clones into summaries of functions they
4028 are inlined to. For that reason the complete function bodies must
4030 if (!e
->inline_failed
)
4032 enum availability avail
;
4033 cgraph_node
*callee
= e
->callee
->function_or_virtual_thunk_symbol
4034 (&avail
, e
->caller
);
4036 return (avail
<= AVAIL_INTERPOSABLE
4037 || ((!optimization_summaries
|| !optimization_summaries
->get (callee
))
4038 && (!summaries_lto
|| !summaries_lto
->get (callee
))));
4041 /* Compute parm_map for CALLEE_EDGE. */
4044 compute_parm_map (cgraph_edge
*callee_edge
, vec
<modref_parm_map
> *parm_map
)
4046 class ipa_edge_args
*args
;
4047 if (ipa_node_params_sum
4048 && !callee_edge
->call_stmt_cannot_inline_p
4049 && (args
= ipa_edge_args_sum
->get (callee_edge
)) != NULL
)
4051 int i
, count
= ipa_get_cs_argument_count (args
);
4052 class ipa_node_params
*caller_parms_info
, *callee_pi
;
4053 class ipa_call_summary
*es
4054 = ipa_call_summaries
->get (callee_edge
);
4056 = callee_edge
->callee
->function_or_virtual_thunk_symbol
4057 (NULL
, callee_edge
->caller
);
4060 = ipa_node_params_sum
->get (callee_edge
->caller
->inlined_to
4061 ? callee_edge
->caller
->inlined_to
4062 : callee_edge
->caller
);
4063 callee_pi
= ipa_node_params_sum
->get (callee
);
4065 (*parm_map
).safe_grow_cleared (count
, true);
4067 for (i
= 0; i
< count
; i
++)
4069 if (es
&& es
->param
[i
].points_to_local_or_readonly_memory
)
4071 (*parm_map
)[i
].parm_index
= MODREF_LOCAL_MEMORY_PARM
;
4075 struct ipa_jump_func
*jf
4076 = ipa_get_ith_jump_func (args
, i
);
4077 if (jf
&& callee_pi
)
4079 tree cst
= ipa_value_from_jfunc (caller_parms_info
,
4083 if (cst
&& points_to_local_or_readonly_memory_p (cst
))
4085 (*parm_map
)[i
].parm_index
= MODREF_LOCAL_MEMORY_PARM
;
4089 if (jf
&& jf
->type
== IPA_JF_PASS_THROUGH
)
4091 (*parm_map
)[i
].parm_index
4092 = ipa_get_jf_pass_through_formal_id (jf
);
4093 if (ipa_get_jf_pass_through_operation (jf
) == NOP_EXPR
)
4095 (*parm_map
)[i
].parm_offset_known
= true;
4096 (*parm_map
)[i
].parm_offset
= 0;
4098 else if (ipa_get_jf_pass_through_operation (jf
)
4099 == POINTER_PLUS_EXPR
4100 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf
),
4101 &(*parm_map
)[i
].parm_offset
))
4102 (*parm_map
)[i
].parm_offset_known
= true;
4104 (*parm_map
)[i
].parm_offset_known
= false;
4107 if (jf
&& jf
->type
== IPA_JF_ANCESTOR
)
4109 (*parm_map
)[i
].parm_index
= ipa_get_jf_ancestor_formal_id (jf
);
4110 (*parm_map
)[i
].parm_offset_known
= true;
4112 (!(ipa_get_jf_ancestor_offset (jf
) & (BITS_PER_UNIT
- 1)));
4113 (*parm_map
)[i
].parm_offset
4114 = ipa_get_jf_ancestor_offset (jf
) >> LOG2_BITS_PER_UNIT
;
4117 (*parm_map
)[i
].parm_index
= -1;
4121 fprintf (dump_file
, " Parm map: ");
4122 for (i
= 0; i
< count
; i
++)
4123 fprintf (dump_file
, " %i", (*parm_map
)[i
].parm_index
);
4124 fprintf (dump_file
, "\n");
4131 /* Map used to translate escape infos. */
4139 /* Update escape map for E. */
4142 update_escape_summary_1 (cgraph_edge
*e
,
4143 vec
<vec
<escape_map
>> &map
,
4146 escape_summary
*sum
= escape_summaries
->get (e
);
4149 auto_vec
<escape_entry
> old
= sum
->esc
.copy ();
4150 sum
->esc
.release ();
4154 FOR_EACH_VEC_ELT (old
, i
, ee
)
4157 struct escape_map
*em
;
4158 /* TODO: We do not have jump functions for return slots, so we
4159 never propagate them to outer function. */
4160 if (ee
->parm_index
>= (int)map
.length ()
4161 || ee
->parm_index
< 0)
4163 FOR_EACH_VEC_ELT (map
[ee
->parm_index
], j
, em
)
4165 int min_flags
= ee
->min_flags
;
4166 if (ee
->direct
&& !em
->direct
)
4167 min_flags
= deref_flags (min_flags
, ignore_stores
);
4168 struct escape_entry entry
= {em
->parm_index
, ee
->arg
,
4170 ee
->direct
& em
->direct
};
4171 sum
->esc
.safe_push (entry
);
4174 if (!sum
->esc
.length ())
4175 escape_summaries
->remove (e
);
4178 /* Update escape map fo NODE. */
4181 update_escape_summary (cgraph_node
*node
,
4182 vec
<vec
<escape_map
>> &map
,
4185 if (!escape_summaries
)
4187 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
4188 update_escape_summary_1 (e
, map
, ignore_stores
);
4189 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
4191 if (!e
->inline_failed
)
4192 update_escape_summary (e
->callee
, map
, ignore_stores
);
4194 update_escape_summary_1 (e
, map
, ignore_stores
);
4198 /* Get parameter type from DECL. This is only safe for special cases
4199 like builtins we create fnspec for because the type match is checked
4200 at fnspec creation time. */
4203 get_parm_type (tree decl
, unsigned int i
)
4205 tree t
= TYPE_ARG_TYPES (TREE_TYPE (decl
));
4207 for (unsigned int p
= 0; p
< i
; p
++)
4209 return TREE_VALUE (t
);
4212 /* Return access mode for argument I of call E with FNSPEC. */
4214 static modref_access_node
4215 get_access_for_fnspec (cgraph_edge
*e
, attr_fnspec
&fnspec
,
4216 unsigned int i
, modref_parm_map
&map
)
4218 tree size
= NULL_TREE
;
4219 unsigned int size_arg
;
4221 if (!fnspec
.arg_specified_p (i
))
4223 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
4225 cgraph_node
*node
= e
->caller
->inlined_to
4226 ? e
->caller
->inlined_to
: e
->caller
;
4227 ipa_node_params
*caller_parms_info
= ipa_node_params_sum
->get (node
);
4228 ipa_edge_args
*args
= ipa_edge_args_sum
->get (e
);
4229 struct ipa_jump_func
*jf
= ipa_get_ith_jump_func (args
, size_arg
);
4232 size
= ipa_value_from_jfunc (caller_parms_info
, jf
,
4233 get_parm_type (e
->callee
->decl
, size_arg
));
4235 else if (fnspec
.arg_access_size_given_by_type_p (i
))
4236 size
= TYPE_SIZE_UNIT (get_parm_type (e
->callee
->decl
, i
));
4237 modref_access_node a
= {0, -1, -1,
4238 map
.parm_offset
, map
.parm_index
,
4239 map
.parm_offset_known
, 0};
4240 poly_int64 size_hwi
;
4242 && poly_int_tree_p (size
, &size_hwi
)
4243 && coeffs_in_range_p (size_hwi
, 0,
4244 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
4247 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
4252 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
4253 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
4256 propagate_unknown_call (cgraph_node
*node
,
4257 cgraph_edge
*e
, int ecf_flags
,
4258 modref_summary
*cur_summary
,
4259 modref_summary_lto
*cur_summary_lto
,
4260 bool nontrivial_scc
)
4262 bool changed
= false;
4263 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
4264 auto_vec
<modref_parm_map
, 32> parm_map
;
4268 && builtin_safe_for_const_function_p (&looping
, e
->callee
->decl
))
4270 if (looping
&& cur_summary
&& !cur_summary
->side_effects
)
4272 cur_summary
->side_effects
= true;
4275 if (looping
&& cur_summary_lto
&& !cur_summary_lto
->side_effects
)
4277 cur_summary_lto
->side_effects
= true;
4283 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
| ECF_PURE
))
4284 || (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
)
4287 if (cur_summary
&& !cur_summary
->side_effects
)
4289 cur_summary
->side_effects
= true;
4292 if (cur_summary_lto
&& !cur_summary_lto
->side_effects
)
4294 cur_summary_lto
->side_effects
= true;
4297 if (cur_summary
&& !cur_summary
->nondeterministic
4298 && !ignore_nondeterminism_p (node
->decl
, ecf_flags
))
4300 cur_summary
->nondeterministic
= true;
4303 if (cur_summary_lto
&& !cur_summary_lto
->nondeterministic
4304 && !ignore_nondeterminism_p (node
->decl
, ecf_flags
))
4306 cur_summary_lto
->nondeterministic
= true;
4310 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
4314 && compute_parm_map (e
, &parm_map
))
4316 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
4318 gcc_checking_assert (fnspec
.known_p ());
4319 if (fnspec
.global_memory_read_p ())
4320 collapse_loads (cur_summary
, cur_summary_lto
);
4323 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
4324 for (unsigned i
= 0; i
< parm_map
.length () && t
;
4325 i
++, t
= TREE_CHAIN (t
))
4326 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
4328 else if (!fnspec
.arg_specified_p (i
)
4329 || fnspec
.arg_maybe_read_p (i
))
4331 modref_parm_map map
= parm_map
[i
];
4332 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
4334 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
4336 collapse_loads (cur_summary
, cur_summary_lto
);
4340 changed
|= cur_summary
->loads
->insert
4341 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4342 if (cur_summary_lto
)
4343 changed
|= cur_summary_lto
->loads
->insert
4344 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4347 if (ignore_stores_p (node
->decl
, ecf_flags
))
4349 else if (fnspec
.global_memory_written_p ())
4350 collapse_stores (cur_summary
, cur_summary_lto
);
4353 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
4354 for (unsigned i
= 0; i
< parm_map
.length () && t
;
4355 i
++, t
= TREE_CHAIN (t
))
4356 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
4358 else if (!fnspec
.arg_specified_p (i
)
4359 || fnspec
.arg_maybe_written_p (i
))
4361 modref_parm_map map
= parm_map
[i
];
4362 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
4364 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
4366 collapse_stores (cur_summary
, cur_summary_lto
);
4370 changed
|= cur_summary
->stores
->insert
4371 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4372 if (cur_summary_lto
)
4373 changed
|= cur_summary_lto
->stores
->insert
4374 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4377 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
4379 if (cur_summary
&& !cur_summary
->writes_errno
)
4381 cur_summary
->writes_errno
= true;
4384 if (cur_summary_lto
&& !cur_summary_lto
->writes_errno
)
4386 cur_summary_lto
->writes_errno
= true;
4393 fprintf (dump_file
, " collapsing loads\n");
4394 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
4395 if (!ignore_stores_p (node
->decl
, ecf_flags
))
4398 fprintf (dump_file
, " collapsing stores\n");
4399 changed
|= collapse_stores (cur_summary
, cur_summary_lto
);
4404 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
4405 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
4408 remove_useless_summaries (cgraph_node
*node
,
4409 modref_summary
**cur_summary_ptr
,
4410 modref_summary_lto
**cur_summary_lto_ptr
,
4413 if (*cur_summary_ptr
&& !(*cur_summary_ptr
)->useful_p (ecf_flags
, false))
4415 optimization_summaries
->remove (node
);
4416 *cur_summary_ptr
= NULL
;
4418 if (*cur_summary_lto_ptr
4419 && !(*cur_summary_lto_ptr
)->useful_p (ecf_flags
, false))
4421 summaries_lto
->remove (node
);
4422 *cur_summary_lto_ptr
= NULL
;
4426 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4427 and propagate loads/stores. */
4430 modref_propagate_in_scc (cgraph_node
*component_node
)
4432 bool changed
= true;
4439 = ((struct ipa_dfs_info
*) component_node
->aux
)->next_cycle
;
4441 for (struct cgraph_node
*cur
= component_node
; cur
;
4442 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4444 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
4445 modref_summary
*cur_summary
= optimization_summaries
4446 ? optimization_summaries
->get (node
)
4448 modref_summary_lto
*cur_summary_lto
= summaries_lto
4449 ? summaries_lto
->get (node
)
4452 if (!cur_summary
&& !cur_summary_lto
)
4455 int cur_ecf_flags
= flags_from_decl_or_type (node
->decl
);
4458 fprintf (dump_file
, " Processing %s%s%s\n",
4460 TREE_READONLY (cur
->decl
) ? " (const)" : "",
4461 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
4463 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
4466 fprintf (dump_file
, " Indirect call\n");
4467 if (propagate_unknown_call
4468 (node
, e
, e
->indirect_info
->ecf_flags
,
4469 cur_summary
, cur_summary_lto
,
4473 remove_useless_summaries (node
, &cur_summary
,
4476 if (!cur_summary
&& !cur_summary_lto
)
4481 if (!cur_summary
&& !cur_summary_lto
)
4484 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
4485 callee_edge
= callee_edge
->next_callee
)
4487 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
4488 modref_summary
*callee_summary
= NULL
;
4489 modref_summary_lto
*callee_summary_lto
= NULL
;
4490 struct cgraph_node
*callee
;
4492 if (!callee_edge
->inline_failed
4493 || ((flags
& (ECF_CONST
| ECF_NOVOPS
))
4494 && !(flags
& ECF_LOOPING_CONST_OR_PURE
)))
4497 /* Get the callee and its summary. */
4498 enum availability avail
;
4499 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
4502 /* It is not necessary to re-process calls outside of the
4506 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
4507 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
4511 fprintf (dump_file
, " Call to %s\n",
4512 callee_edge
->callee
->dump_name ());
4514 bool ignore_stores
= ignore_stores_p (cur
->decl
, flags
);
4516 if (avail
<= AVAIL_INTERPOSABLE
)
4519 fprintf (dump_file
, " Call target interposable"
4520 " or not available\n");
4521 changed
|= propagate_unknown_call
4522 (node
, callee_edge
, flags
,
4523 cur_summary
, cur_summary_lto
,
4525 if (!cur_summary
&& !cur_summary_lto
)
4530 /* We don't know anything about CALLEE, hence we cannot tell
4531 anything about the entire component. */
4534 && !(callee_summary
= optimization_summaries
->get (callee
)))
4537 fprintf (dump_file
, " No call target summary\n");
4538 changed
|= propagate_unknown_call
4539 (node
, callee_edge
, flags
,
4544 && !(callee_summary_lto
= summaries_lto
->get (callee
)))
4547 fprintf (dump_file
, " No call target summary\n");
4548 changed
|= propagate_unknown_call
4549 (node
, callee_edge
, flags
,
4550 NULL
, cur_summary_lto
,
4554 if (callee_summary
&& !cur_summary
->side_effects
4555 && (callee_summary
->side_effects
4556 || callee_edge
->recursive_p ()))
4558 cur_summary
->side_effects
= true;
4561 if (callee_summary_lto
&& !cur_summary_lto
->side_effects
4562 && (callee_summary_lto
->side_effects
4563 || callee_edge
->recursive_p ()))
4565 cur_summary_lto
->side_effects
= true;
4568 if (callee_summary
&& !cur_summary
->nondeterministic
4569 && callee_summary
->nondeterministic
4570 && !ignore_nondeterminism_p (cur
->decl
, flags
))
4572 cur_summary
->nondeterministic
= true;
4575 if (callee_summary_lto
&& !cur_summary_lto
->nondeterministic
4576 && callee_summary_lto
->nondeterministic
4577 && !ignore_nondeterminism_p (cur
->decl
, flags
))
4579 cur_summary_lto
->nondeterministic
= true;
4582 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
4585 /* We can not safely optimize based on summary of callee if it
4586 does not always bind to current def: it is possible that
4587 memory load was optimized out earlier which may not happen in
4588 the interposed variant. */
4589 if (!callee_edge
->binds_to_current_def_p ())
4591 if (cur_summary
&& !cur_summary
->calls_interposable
)
4593 cur_summary
->calls_interposable
= true;
4596 if (cur_summary_lto
&& !cur_summary_lto
->calls_interposable
)
4598 cur_summary_lto
->calls_interposable
= true;
4602 fprintf (dump_file
, " May not bind local;"
4603 " collapsing loads\n");
4607 auto_vec
<modref_parm_map
, 32> parm_map
;
4608 modref_parm_map chain_map
;
4609 /* TODO: Once we get jump functions for static chains we could
4611 chain_map
.parm_index
= MODREF_UNKNOWN_PARM
;
4613 compute_parm_map (callee_edge
, &parm_map
);
4615 /* Merge in callee's information. */
4618 changed
|= cur_summary
->loads
->merge
4619 (callee_summary
->loads
, &parm_map
,
4620 &chain_map
, !first
);
4623 changed
|= cur_summary
->stores
->merge
4624 (callee_summary
->stores
, &parm_map
,
4625 &chain_map
, !first
);
4626 if (!cur_summary
->writes_errno
4627 && callee_summary
->writes_errno
)
4629 cur_summary
->writes_errno
= true;
4634 if (callee_summary_lto
)
4636 changed
|= cur_summary_lto
->loads
->merge
4637 (callee_summary_lto
->loads
, &parm_map
,
4638 &chain_map
, !first
);
4641 changed
|= cur_summary_lto
->stores
->merge
4642 (callee_summary_lto
->stores
, &parm_map
,
4643 &chain_map
, !first
);
4644 if (!cur_summary_lto
->writes_errno
4645 && callee_summary_lto
->writes_errno
)
4647 cur_summary_lto
->writes_errno
= true;
4653 remove_useless_summaries (node
, &cur_summary
,
4656 if (!cur_summary
&& !cur_summary_lto
)
4658 if (dump_file
&& changed
)
4661 cur_summary
->dump (dump_file
);
4662 if (cur_summary_lto
)
4663 cur_summary_lto
->dump (dump_file
);
4664 dump_modref_edge_summaries (dump_file
, node
, 4);
4673 "Propagation finished in %i iterations\n", iteration
);
4674 bool pureconst
= false;
4675 for (struct cgraph_node
*cur
= component_node
; cur
;
4676 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4677 if (!cur
->inlined_to
&& opt_for_fn (cur
->decl
, flag_ipa_pure_const
))
4679 modref_summary
*summary
= optimization_summaries
4680 ? optimization_summaries
->get (cur
)
4682 modref_summary_lto
*summary_lto
= summaries_lto
4683 ? summaries_lto
->get (cur
)
4685 if (summary
&& !summary
->stores
->every_base
&& !summary
->stores
->bases
4686 && !summary
->nondeterministic
)
4688 if (!summary
->loads
->every_base
&& !summary
->loads
->bases
4689 && !summary
->calls_interposable
)
4690 pureconst
|= ipa_make_function_const
4691 (cur
, summary
->side_effects
, false);
4693 pureconst
|= ipa_make_function_pure
4694 (cur
, summary
->side_effects
, false);
4696 if (summary_lto
&& !summary_lto
->stores
->every_base
4697 && !summary_lto
->stores
->bases
&& !summary_lto
->nondeterministic
)
4699 if (!summary_lto
->loads
->every_base
&& !summary_lto
->loads
->bases
4700 && !summary_lto
->calls_interposable
)
4701 pureconst
|= ipa_make_function_const
4702 (cur
, summary_lto
->side_effects
, false);
4704 pureconst
|= ipa_make_function_pure
4705 (cur
, summary_lto
->side_effects
, false);
4711 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
4714 modref_propagate_dump_scc (cgraph_node
*component_node
)
4716 for (struct cgraph_node
*cur
= component_node
; cur
;
4717 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4718 if (!cur
->inlined_to
)
4720 modref_summary
*cur_summary
= optimization_summaries
4721 ? optimization_summaries
->get (cur
)
4723 modref_summary_lto
*cur_summary_lto
= summaries_lto
4724 ? summaries_lto
->get (cur
)
4727 fprintf (dump_file
, "Propagated modref for %s%s%s\n",
4729 TREE_READONLY (cur
->decl
) ? " (const)" : "",
4730 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
4731 if (optimization_summaries
)
4734 cur_summary
->dump (dump_file
);
4736 fprintf (dump_file
, " Not tracked\n");
4740 if (cur_summary_lto
)
4741 cur_summary_lto
->dump (dump_file
);
4743 fprintf (dump_file
, " Not tracked (lto)\n");
4748 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
4749 and SUMMARY_LTO to CUR_SUMMARY_LTO.
4750 Return true if something changed. */
4753 modref_merge_call_site_flags (escape_summary
*sum
,
4754 modref_summary
*cur_summary
,
4755 modref_summary_lto
*cur_summary_lto
,
4756 modref_summary
*summary
,
4757 modref_summary_lto
*summary_lto
,
4760 int caller_ecf_flags
,
4761 int callee_ecf_flags
,
4762 bool binds_to_current_def
)
4766 bool changed
= false;
4767 bool ignore_stores
= ignore_stores_p (caller
, callee_ecf_flags
);
4769 /* If we have no useful info to propagate. */
4770 if ((!cur_summary
|| !cur_summary
->arg_flags
.length ())
4771 && (!cur_summary_lto
|| !cur_summary_lto
->arg_flags
.length ()))
4774 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
4778 /* Returning the value is already accounted to at local propagation. */
4779 int implicit_flags
= EAF_NOT_RETURNED_DIRECTLY
4780 | EAF_NOT_RETURNED_INDIRECTLY
;
4782 if (summary
&& ee
->arg
< summary
->arg_flags
.length ())
4783 flags
= summary
->arg_flags
[ee
->arg
];
4785 && ee
->arg
< summary_lto
->arg_flags
.length ())
4786 flags_lto
= summary_lto
->arg_flags
[ee
->arg
];
4789 flags
= deref_flags (flags
, ignore_stores
);
4790 flags_lto
= deref_flags (flags_lto
, ignore_stores
);
4793 implicit_flags
|= ignore_stores_eaf_flags
;
4794 if (callee_ecf_flags
& ECF_PURE
)
4795 implicit_flags
|= implicit_pure_eaf_flags
;
4796 if (callee_ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
4797 implicit_flags
|= implicit_const_eaf_flags
;
4798 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
4801 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
4802 implicit_flags
|= fnspec
.arg_eaf_flags (ee
->arg
);
4805 implicit_flags
= deref_flags (implicit_flags
, ignore_stores
);
4806 flags
|= implicit_flags
;
4807 flags_lto
|= implicit_flags
;
4808 if (!binds_to_current_def
&& (flags
|| flags_lto
))
4810 flags
= interposable_eaf_flags (flags
, implicit_flags
);
4811 flags_lto
= interposable_eaf_flags (flags_lto
, implicit_flags
);
4813 if (!(flags
& EAF_UNUSED
)
4814 && cur_summary
&& ee
->parm_index
< (int)cur_summary
->arg_flags
.length ())
4816 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
4817 ? cur_summary
->retslot_flags
4818 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
4819 ? cur_summary
->static_chain_flags
4820 : cur_summary
->arg_flags
[ee
->parm_index
];
4821 if ((f
& flags
) != f
)
4823 f
= remove_useless_eaf_flags
4824 (f
& flags
, caller_ecf_flags
,
4825 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
4829 if (!(flags_lto
& EAF_UNUSED
)
4831 && ee
->parm_index
< (int)cur_summary_lto
->arg_flags
.length ())
4833 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
4834 ? cur_summary_lto
->retslot_flags
4835 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
4836 ? cur_summary_lto
->static_chain_flags
4837 : cur_summary_lto
->arg_flags
[ee
->parm_index
];
4838 if ((f
& flags_lto
) != f
)
4840 f
= remove_useless_eaf_flags
4841 (f
& flags_lto
, caller_ecf_flags
,
4842 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
4850 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4851 and propagate arg flags. */
4854 modref_propagate_flags_in_scc (cgraph_node
*component_node
)
4856 bool changed
= true;
4862 for (struct cgraph_node
*cur
= component_node
; cur
;
4863 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4865 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
4866 modref_summary
*cur_summary
= optimization_summaries
4867 ? optimization_summaries
->get (node
)
4869 modref_summary_lto
*cur_summary_lto
= summaries_lto
4870 ? summaries_lto
->get (node
)
4873 if (!cur_summary
&& !cur_summary_lto
)
4875 int caller_ecf_flags
= flags_from_decl_or_type (cur
->decl
);
4878 fprintf (dump_file
, " Processing %s%s%s\n",
4880 TREE_READONLY (cur
->decl
) ? " (const)" : "",
4881 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
4883 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
4885 escape_summary
*sum
= escape_summaries
->get (e
);
4887 if (!sum
|| (e
->indirect_info
->ecf_flags
4888 & (ECF_CONST
| ECF_NOVOPS
)))
4891 changed
|= modref_merge_call_site_flags
4892 (sum
, cur_summary
, cur_summary_lto
,
4897 e
->indirect_info
->ecf_flags
,
4901 if (!cur_summary
&& !cur_summary_lto
)
4904 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
4905 callee_edge
= callee_edge
->next_callee
)
4907 int ecf_flags
= flags_from_decl_or_type
4908 (callee_edge
->callee
->decl
);
4909 modref_summary
*callee_summary
= NULL
;
4910 modref_summary_lto
*callee_summary_lto
= NULL
;
4911 struct cgraph_node
*callee
;
4913 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)
4914 || !callee_edge
->inline_failed
)
4916 /* Get the callee and its summary. */
4917 enum availability avail
;
4918 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
4921 /* It is not necessary to re-process calls outside of the
4925 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
4926 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
4929 escape_summary
*sum
= escape_summaries
->get (callee_edge
);
4934 fprintf (dump_file
, " Call to %s\n",
4935 callee_edge
->callee
->dump_name ());
4937 if (avail
<= AVAIL_INTERPOSABLE
4938 || callee_edge
->call_stmt_cannot_inline_p
)
4943 callee_summary
= optimization_summaries
->get (callee
);
4944 if (cur_summary_lto
)
4945 callee_summary_lto
= summaries_lto
->get (callee
);
4947 changed
|= modref_merge_call_site_flags
4948 (sum
, cur_summary
, cur_summary_lto
,
4949 callee_summary
, callee_summary_lto
,
4954 callee
->binds_to_current_def_p ());
4955 if (dump_file
&& changed
)
4958 cur_summary
->dump (dump_file
);
4959 if (cur_summary_lto
)
4960 cur_summary_lto
->dump (dump_file
);
4968 "Propagation of flags finished in %i iterations\n", iteration
);
4971 } /* ANON namespace. */
4973 /* Call EDGE was inlined; merge summary from callee to the caller. */
4976 ipa_merge_modref_summary_after_inlining (cgraph_edge
*edge
)
4978 if (!summaries
&& !summaries_lto
)
4981 struct cgraph_node
*to
= (edge
->caller
->inlined_to
4982 ? edge
->caller
->inlined_to
: edge
->caller
);
4983 class modref_summary
*to_info
= summaries
? summaries
->get (to
) : NULL
;
4984 class modref_summary_lto
*to_info_lto
= summaries_lto
4985 ? summaries_lto
->get (to
) : NULL
;
4987 if (!to_info
&& !to_info_lto
)
4990 summaries
->remove (edge
->callee
);
4992 summaries_lto
->remove (edge
->callee
);
4993 remove_modref_edge_summaries (edge
->callee
);
4997 class modref_summary
*callee_info
= summaries
? summaries
->get (edge
->callee
)
4999 class modref_summary_lto
*callee_info_lto
5000 = summaries_lto
? summaries_lto
->get (edge
->callee
) : NULL
;
5001 int flags
= flags_from_decl_or_type (edge
->callee
->decl
);
5002 bool ignore_stores
= ignore_stores_p (edge
->caller
->decl
, flags
);
5004 if (!callee_info
&& to_info
)
5006 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5007 to_info
->loads
->collapse ();
5009 to_info
->stores
->collapse ();
5011 if (!callee_info_lto
&& to_info_lto
)
5013 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5014 to_info_lto
->loads
->collapse ();
5016 to_info_lto
->stores
->collapse ();
5018 if (callee_info
|| callee_info_lto
)
5020 auto_vec
<modref_parm_map
, 32> parm_map
;
5021 modref_parm_map chain_map
;
5022 /* TODO: Once we get jump functions for static chains we could
5024 chain_map
.parm_index
= MODREF_UNKNOWN_PARM
;
5026 compute_parm_map (edge
, &parm_map
);
5030 if (to_info
&& callee_info
)
5031 to_info
->stores
->merge (callee_info
->stores
, &parm_map
,
5033 if (to_info_lto
&& callee_info_lto
)
5034 to_info_lto
->stores
->merge (callee_info_lto
->stores
, &parm_map
,
5037 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5039 if (to_info
&& callee_info
)
5040 to_info
->loads
->merge (callee_info
->loads
, &parm_map
,
5042 if (to_info_lto
&& callee_info_lto
)
5043 to_info_lto
->loads
->merge (callee_info_lto
->loads
, &parm_map
,
5048 /* Now merge escape summaries.
5049 For every escape to the callee we need to merge calle flags
5050 and remap calees escapes. */
5051 class escape_summary
*sum
= escape_summaries
->get (edge
);
5052 int max_escape
= -1;
5056 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5057 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
5058 if ((int)ee
->arg
> max_escape
)
5059 max_escape
= ee
->arg
;
5061 auto_vec
<vec
<struct escape_map
>, 32> emap (max_escape
+ 1);
5062 emap
.safe_grow (max_escape
+ 1, true);
5063 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
5066 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5067 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
5069 bool needed
= false;
5070 /* TODO: We do not have jump functions for return slots, so we
5071 never propagate them to outer function. */
5072 if (ee
->parm_index
< 0)
5074 if (to_info
&& (int)to_info
->arg_flags
.length () > ee
->parm_index
)
5076 int flags
= callee_info
5077 && callee_info
->arg_flags
.length () > ee
->arg
5078 ? callee_info
->arg_flags
[ee
->arg
] : 0;
5080 flags
= deref_flags (flags
, ignore_stores
);
5081 else if (ignore_stores
)
5082 flags
|= ignore_stores_eaf_flags
;
5083 flags
|= ee
->min_flags
;
5084 to_info
->arg_flags
[ee
->parm_index
] &= flags
;
5085 if (to_info
->arg_flags
[ee
->parm_index
])
5089 && (int)to_info_lto
->arg_flags
.length () > ee
->parm_index
)
5091 int flags
= callee_info_lto
5092 && callee_info_lto
->arg_flags
.length () > ee
->arg
5093 ? callee_info_lto
->arg_flags
[ee
->arg
] : 0;
5095 flags
= deref_flags (flags
, ignore_stores
);
5096 else if (ignore_stores
)
5097 flags
|= ignore_stores_eaf_flags
;
5098 flags
|= ee
->min_flags
;
5099 to_info_lto
->arg_flags
[ee
->parm_index
] &= flags
;
5100 if (to_info_lto
->arg_flags
[ee
->parm_index
])
5103 struct escape_map entry
= {ee
->parm_index
, ee
->direct
};
5105 emap
[ee
->arg
].safe_push (entry
);
5107 update_escape_summary (edge
->callee
, emap
, ignore_stores
);
5108 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
5111 escape_summaries
->remove (edge
);
5115 if (to_info
&& !to_info
->useful_p (flags
))
5118 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
5120 summaries
->remove (to
);
5123 else if (to_info
&& dump_file
)
5126 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
5128 to_info
->dump (dump_file
);
5131 summaries
->remove (edge
->callee
);
5135 if (to_info_lto
&& !to_info_lto
->useful_p (flags
))
5138 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
5140 summaries_lto
->remove (to
);
5143 else if (to_info_lto
&& dump_file
)
5146 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
5148 to_info_lto
->dump (dump_file
);
5150 if (callee_info_lto
)
5151 summaries_lto
->remove (edge
->callee
);
5153 if (!to_info
&& !to_info_lto
)
5154 remove_modref_edge_summaries (to
);
5158 /* Run the IPA pass. This will take a function's summaries and calls and
5159 construct new summaries which represent a transitive closure. So that
5160 summary of an analyzed function contains information about the loads and
5161 stores that the function or any function that it calls does. */
5164 pass_ipa_modref::execute (function
*)
5166 if (!summaries
&& !summaries_lto
)
5168 bool pureconst
= false;
5170 if (optimization_summaries
)
5171 ggc_delete (optimization_summaries
);
5172 optimization_summaries
= summaries
;
5175 struct cgraph_node
**order
= XCNEWVEC (struct cgraph_node
*,
5176 symtab
->cgraph_count
);
5178 order_pos
= ipa_reduced_postorder (order
, true, ignore_edge
);
5181 /* Iterate over all strongly connected components in post-order. */
5182 for (i
= 0; i
< order_pos
; i
++)
5184 /* Get the component's representative. That's just any node in the
5185 component from which we can traverse the entire component. */
5186 struct cgraph_node
*component_node
= order
[i
];
5189 fprintf (dump_file
, "\n\nStart of SCC component\n");
5191 pureconst
|= modref_propagate_in_scc (component_node
);
5192 modref_propagate_flags_in_scc (component_node
);
5193 if (optimization_summaries
)
5194 for (struct cgraph_node
*cur
= component_node
; cur
;
5195 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
5196 if (modref_summary
*sum
= optimization_summaries
->get (cur
))
5197 sum
->finalize (cur
->decl
);
5199 modref_propagate_dump_scc (component_node
);
5202 FOR_EACH_FUNCTION (node
)
5203 update_signature (node
);
5205 ((modref_summaries_lto
*)summaries_lto
)->propagated
= true;
5206 ipa_free_postorder_info ();
5208 delete fnspec_summaries
;
5209 fnspec_summaries
= NULL
;
5210 delete escape_summaries
;
5211 escape_summaries
= NULL
;
5213 /* If we posibly made constructors const/pure we may need to remove
5215 return pureconst
? TODO_remove_functions
: 0;
5218 /* Summaries must stay alive until end of compilation. */
5221 ipa_modref_c_finalize ()
5223 if (optimization_summaries
)
5224 ggc_delete (optimization_summaries
);
5225 optimization_summaries
= NULL
;
5227 ggc_delete (summaries_lto
);
5228 summaries_lto
= NULL
;
5229 if (fnspec_summaries
)
5230 delete fnspec_summaries
;
5231 fnspec_summaries
= NULL
;
5232 if (escape_summaries
)
5233 delete escape_summaries
;
5234 escape_summaries
= NULL
;
5237 #include "gt-ipa-modref.h"