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
)
428 fprintf (out
, " Every base\n");
432 modref_base_node
<alias_set_type
> *n
;
433 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
435 fprintf (out
, " Base %i: alias set %i\n", (int)i
, n
->base
);
438 fprintf (out
, " Every ref\n");
442 modref_ref_node
<alias_set_type
> *r
;
443 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
445 fprintf (out
, " Ref %i: alias set %i\n", (int)j
, r
->ref
);
448 fprintf (out
, " Every access\n");
452 modref_access_node
*a
;
453 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
455 fprintf (out
, " access:");
462 /* Dump records TT to OUT. */
465 dump_lto_records (modref_records_lto
*tt
, FILE *out
)
469 fprintf (out
, " Every base\n");
473 modref_base_node
<tree
> *n
;
474 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
476 fprintf (out
, " Base %i:", (int)i
);
477 print_generic_expr (dump_file
, n
->base
);
478 fprintf (out
, " (alias set %i)\n",
479 n
->base
? get_alias_set (n
->base
) : 0);
482 fprintf (out
, " Every ref\n");
486 modref_ref_node
<tree
> *r
;
487 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
489 fprintf (out
, " Ref %i:", (int)j
);
490 print_generic_expr (dump_file
, r
->ref
);
491 fprintf (out
, " (alias set %i)\n",
492 r
->ref
? get_alias_set (r
->ref
) : 0);
495 fprintf (out
, " Every access\n");
499 modref_access_node
*a
;
500 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
502 fprintf (out
, " access:");
509 /* Dump all escape points of NODE to OUT. */
512 dump_modref_edge_summaries (FILE *out
, cgraph_node
*node
, int depth
)
515 if (!escape_summaries
)
517 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
519 class escape_summary
*sum
= escape_summaries
->get (e
);
522 fprintf (out
, "%*sIndirect call %i in %s escapes:",
523 depth
, "", i
, node
->dump_name ());
528 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
530 if (!e
->inline_failed
)
531 dump_modref_edge_summaries (out
, e
->callee
, depth
+ 1);
532 class escape_summary
*sum
= escape_summaries
->get (e
);
535 fprintf (out
, "%*sCall %s->%s escapes:", depth
, "",
536 node
->dump_name (), e
->callee
->dump_name ());
539 class fnspec_summary
*fsum
= fnspec_summaries
->get (e
);
542 fprintf (out
, "%*sCall %s->%s fnspec: %s\n", depth
, "",
543 node
->dump_name (), e
->callee
->dump_name (),
549 /* Remove all call edge summaries associated with NODE. */
552 remove_modref_edge_summaries (cgraph_node
*node
)
554 if (!escape_summaries
)
556 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
557 escape_summaries
->remove (e
);
558 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
560 if (!e
->inline_failed
)
561 remove_modref_edge_summaries (e
->callee
);
562 escape_summaries
->remove (e
);
563 fnspec_summaries
->remove (e
);
570 modref_summary::dump (FILE *out
)
574 fprintf (out
, " loads:\n");
575 dump_records (loads
, out
);
579 fprintf (out
, " stores:\n");
580 dump_records (stores
, out
);
584 fprintf (out
, " kills:\n");
585 for (auto kill
: kills
)
592 fprintf (out
, " Writes errno\n");
594 fprintf (out
, " Side effects\n");
595 if (nondeterministic
)
596 fprintf (out
, " Nondeterministic\n");
597 if (calls_interposable
)
598 fprintf (out
, " Calls interposable\n");
599 if (global_memory_read
)
600 fprintf (out
, " Global memory read\n");
601 if (global_memory_written
)
602 fprintf (out
, " Global memory written\n");
604 fprintf (out
, " Try dse\n");
605 if (arg_flags
.length ())
607 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
610 fprintf (out
, " parm %i flags:", i
);
611 dump_eaf_flags (out
, arg_flags
[i
]);
616 fprintf (out
, " Retslot flags:");
617 dump_eaf_flags (out
, retslot_flags
);
619 if (static_chain_flags
)
621 fprintf (out
, " Static chain flags:");
622 dump_eaf_flags (out
, static_chain_flags
);
629 modref_summary_lto::dump (FILE *out
)
631 fprintf (out
, " loads:\n");
632 dump_lto_records (loads
, out
);
633 fprintf (out
, " stores:\n");
634 dump_lto_records (stores
, out
);
637 fprintf (out
, " kills:\n");
638 for (auto kill
: kills
)
645 fprintf (out
, " Writes errno\n");
647 fprintf (out
, " Side effects\n");
648 if (nondeterministic
)
649 fprintf (out
, " Nondeterministic\n");
650 if (calls_interposable
)
651 fprintf (out
, " Calls interposable\n");
652 if (arg_flags
.length ())
654 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
657 fprintf (out
, " parm %i flags:", i
);
658 dump_eaf_flags (out
, arg_flags
[i
]);
663 fprintf (out
, " Retslot flags:");
664 dump_eaf_flags (out
, retslot_flags
);
666 if (static_chain_flags
)
668 fprintf (out
, " Static chain flags:");
669 dump_eaf_flags (out
, static_chain_flags
);
673 /* Called after summary is produced and before it is used by local analysis.
674 Can be called multiple times in case summary needs to update signature.
675 FUN is decl of function summary is attached to. */
677 modref_summary::finalize (tree fun
)
679 global_memory_read
= !loads
|| loads
->global_access_p ();
680 global_memory_written
= !stores
|| stores
->global_access_p ();
682 /* We can do DSE if we know function has no side effects and
683 we can analyse all stores. Disable dse if there are too many
685 if (side_effects
|| global_memory_written
|| writes_errno
)
691 int num_tests
= 0, max_tests
692 = opt_for_fn (fun
, param_modref_max_tests
);
693 modref_base_node
<alias_set_type
> *base_node
;
694 modref_ref_node
<alias_set_type
> *ref_node
;
695 modref_access_node
*access_node
;
696 FOR_EACH_VEC_SAFE_ELT (stores
->bases
, i
, base_node
)
698 if (base_node
->every_ref
)
703 FOR_EACH_VEC_SAFE_ELT (base_node
->refs
, j
, ref_node
)
705 if (base_node
->every_ref
)
710 FOR_EACH_VEC_SAFE_ELT (ref_node
->accesses
, k
, access_node
)
711 if (num_tests
++ > max_tests
712 || !access_node
->parm_offset_known
)
726 /* Get function summary for FUNC if it exists, return NULL otherwise. */
729 get_modref_function_summary (cgraph_node
*func
)
731 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
732 if (!optimization_summaries
)
735 /* A single function body may be represented by multiple symbols with
736 different visibility. For example, if FUNC is an interposable alias,
737 we don't want to return anything, even if we have summary for the target
739 enum availability avail
;
740 func
= func
->function_or_virtual_thunk_symbol
741 (&avail
, current_function_decl
?
742 cgraph_node::get (current_function_decl
) : NULL
);
743 if (avail
<= AVAIL_INTERPOSABLE
)
746 modref_summary
*r
= optimization_summaries
->get (func
);
750 /* Get function summary for CALL if it exists, return NULL otherwise.
751 If non-null set interposed to indicate whether function may not
752 bind to current def. In this case sometimes loads from function
753 needs to be ignored. */
756 get_modref_function_summary (gcall
*call
, bool *interposed
)
758 tree callee
= gimple_call_fndecl (call
);
761 struct cgraph_node
*node
= cgraph_node::get (callee
);
764 modref_summary
*r
= get_modref_function_summary (node
);
766 *interposed
= r
->calls_interposable
767 || !node
->binds_to_current_def_p ();
774 /* Return true if ECF flags says that nondeterminsm can be ignored. */
777 ignore_nondeterminism_p (tree caller
, int flags
)
779 if (flags
& (ECF_CONST
| ECF_PURE
))
781 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
782 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
787 /* Return true if ECF flags says that return value can be ignored. */
790 ignore_retval_p (tree caller
, int flags
)
792 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
793 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
798 /* Return true if ECF flags says that stores can be ignored. */
801 ignore_stores_p (tree caller
, int flags
)
803 if (flags
& (ECF_PURE
| ECF_CONST
| ECF_NOVOPS
))
805 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
806 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
811 /* Determine parm_map for PTR which is supposed to be a pointer. */
814 parm_map_for_ptr (tree op
)
818 struct modref_parm_map parm_map
;
821 parm_map
.parm_offset_known
= false;
822 parm_map
.parm_offset
= 0;
824 offset_known
= unadjusted_ptr_and_unit_offset (op
, &op
, &offset
);
825 if (TREE_CODE (op
) == SSA_NAME
826 && SSA_NAME_IS_DEFAULT_DEF (op
)
827 && TREE_CODE (SSA_NAME_VAR (op
)) == PARM_DECL
)
831 if (cfun
->static_chain_decl
832 && op
== ssa_default_def (cfun
, cfun
->static_chain_decl
))
833 index
= MODREF_STATIC_CHAIN_PARM
;
835 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
836 t
!= SSA_NAME_VAR (op
); t
= DECL_CHAIN (t
))
838 parm_map
.parm_index
= index
;
839 parm_map
.parm_offset_known
= offset_known
;
840 parm_map
.parm_offset
= offset
;
842 else if (points_to_local_or_readonly_memory_p (op
))
843 parm_map
.parm_index
= MODREF_LOCAL_MEMORY_PARM
;
844 /* Memory allocated in the function is not visible to caller before the
845 call and thus we do not need to record it as load/stores/kills. */
846 else if (TREE_CODE (op
) == SSA_NAME
847 && (call
= dyn_cast
<gcall
*>(SSA_NAME_DEF_STMT (op
))) != NULL
848 && gimple_call_flags (call
) & ECF_MALLOC
)
849 parm_map
.parm_index
= MODREF_LOCAL_MEMORY_PARM
;
851 parm_map
.parm_index
= MODREF_UNKNOWN_PARM
;
855 /* Analyze memory accesses (loads, stores and kills) performed
856 by the function. Set also side_effects, calls_interposable
857 and nondeterminism flags. */
859 class modref_access_analysis
862 modref_access_analysis (bool ipa
, modref_summary
*summary
,
863 modref_summary_lto
*summary_lto
)
864 : m_summary (summary
), m_summary_lto (summary_lto
), m_ipa (ipa
)
869 bool set_side_effects ();
870 bool set_nondeterministic ();
871 static modref_access_node
get_access (ao_ref
*ref
);
872 static void record_access (modref_records
*, ao_ref
*, modref_access_node
&);
873 static void record_access_lto (modref_records_lto
*, ao_ref
*,
874 modref_access_node
&a
);
875 bool record_access_p (tree
);
876 bool record_unknown_load ();
877 bool record_unknown_store ();
878 bool merge_call_side_effects (gimple
*, modref_summary
*,
879 cgraph_node
*, bool);
880 modref_access_node
get_access_for_fnspec (gcall
*, attr_fnspec
&,
881 unsigned int, modref_parm_map
&);
882 void process_fnspec (gcall
*);
883 void analyze_call (gcall
*);
884 static bool analyze_load (gimple
*, tree
, tree
, void *);
885 static bool analyze_store (gimple
*, tree
, tree
, void *);
886 void analyze_stmt (gimple
*, bool);
889 /* Summary being computed.
890 We work eitehr with m_summary or m_summary_lto. Never on both. */
891 modref_summary
*m_summary
;
892 modref_summary_lto
*m_summary_lto
;
893 /* Recursive calls needs simplisitc dataflow after analysis finished.
894 Collect all calls into this vector during analysis and later process
895 them in propagate. */
896 auto_vec
<gimple
*, 32> m_recursive_calls
;
897 /* ECF flags of function being analysed. */
899 /* True if IPA propagation will be done later. */
901 /* Set true if statement currently analysed is known to be
902 executed each time function is called. */
903 bool m_always_executed
;
906 /* Set side_effects flag and return if someting changed. */
909 modref_access_analysis::set_side_effects ()
911 bool changed
= false;
913 if (m_summary
&& !m_summary
->side_effects
)
915 m_summary
->side_effects
= true;
918 if (m_summary_lto
&& !m_summary_lto
->side_effects
)
920 m_summary_lto
->side_effects
= true;
926 /* Set nondeterministic flag and return if someting changed. */
929 modref_access_analysis::set_nondeterministic ()
931 bool changed
= false;
933 if (m_summary
&& !m_summary
->nondeterministic
)
935 m_summary
->side_effects
= m_summary
->nondeterministic
= true;
938 if (m_summary_lto
&& !m_summary_lto
->nondeterministic
)
940 m_summary_lto
->side_effects
= m_summary_lto
->nondeterministic
= true;
946 /* Construct modref_access_node from REF. */
949 modref_access_analysis::get_access (ao_ref
*ref
)
953 base
= ao_ref_base (ref
);
954 modref_access_node a
= {ref
->offset
, ref
->size
, ref
->max_size
,
955 0, MODREF_UNKNOWN_PARM
, false, 0};
956 if (TREE_CODE (base
) == MEM_REF
|| TREE_CODE (base
) == TARGET_MEM_REF
)
959 modref_parm_map m
= parm_map_for_ptr (TREE_OPERAND (base
, 0));
961 a
.parm_index
= m
.parm_index
;
962 if (a
.parm_index
!= MODREF_UNKNOWN_PARM
&& TREE_CODE (memref
) == MEM_REF
)
965 = wi::to_poly_wide (TREE_OPERAND
966 (memref
, 1)).to_shwi (&a
.parm_offset
);
967 if (a
.parm_offset_known
&& m
.parm_offset_known
)
968 a
.parm_offset
+= m
.parm_offset
;
970 a
.parm_offset_known
= false;
974 a
.parm_index
= MODREF_UNKNOWN_PARM
;
978 /* Record access into the modref_records data structure. */
981 modref_access_analysis::record_access (modref_records
*tt
,
983 modref_access_node
&a
)
985 alias_set_type base_set
= !flag_strict_aliasing
? 0
986 : ao_ref_base_alias_set (ref
);
987 alias_set_type ref_set
= !flag_strict_aliasing
? 0
988 : (ao_ref_alias_set (ref
));
991 fprintf (dump_file
, " - Recording base_set=%i ref_set=%i ",
995 tt
->insert (current_function_decl
, base_set
, ref_set
, a
, false);
998 /* IPA version of record_access_tree. */
1001 modref_access_analysis::record_access_lto (modref_records_lto
*tt
, ao_ref
*ref
,
1002 modref_access_node
&a
)
1004 /* get_alias_set sometimes use different type to compute the alias set
1005 than TREE_TYPE (base). Do same adjustments. */
1006 tree base_type
= NULL_TREE
, ref_type
= NULL_TREE
;
1007 if (flag_strict_aliasing
)
1012 while (handled_component_p (base
))
1013 base
= TREE_OPERAND (base
, 0);
1015 base_type
= reference_alias_ptr_type_1 (&base
);
1018 base_type
= TREE_TYPE (base
);
1020 base_type
= TYPE_REF_CAN_ALIAS_ALL (base_type
)
1021 ? NULL_TREE
: TREE_TYPE (base_type
);
1023 tree ref_expr
= ref
->ref
;
1024 ref_type
= reference_alias_ptr_type_1 (&ref_expr
);
1027 ref_type
= TREE_TYPE (ref_expr
);
1029 ref_type
= TYPE_REF_CAN_ALIAS_ALL (ref_type
)
1030 ? NULL_TREE
: TREE_TYPE (ref_type
);
1032 /* Sanity check that we are in sync with what get_alias_set does. */
1033 gcc_checking_assert ((!base_type
&& !ao_ref_base_alias_set (ref
))
1034 || get_alias_set (base_type
)
1035 == ao_ref_base_alias_set (ref
));
1036 gcc_checking_assert ((!ref_type
&& !ao_ref_alias_set (ref
))
1037 || get_alias_set (ref_type
)
1038 == ao_ref_alias_set (ref
));
1040 /* Do not bother to record types that have no meaningful alias set.
1041 Also skip variably modified types since these go to local streams. */
1042 if (base_type
&& (!get_alias_set (base_type
)
1043 || variably_modified_type_p (base_type
, NULL_TREE
)))
1044 base_type
= NULL_TREE
;
1045 if (ref_type
&& (!get_alias_set (ref_type
)
1046 || variably_modified_type_p (ref_type
, NULL_TREE
)))
1047 ref_type
= NULL_TREE
;
1051 fprintf (dump_file
, " - Recording base type:");
1052 print_generic_expr (dump_file
, base_type
);
1053 fprintf (dump_file
, " (alias set %i) ref type:",
1054 base_type
? get_alias_set (base_type
) : 0);
1055 print_generic_expr (dump_file
, ref_type
);
1056 fprintf (dump_file
, " (alias set %i) ",
1057 ref_type
? get_alias_set (ref_type
) : 0);
1061 tt
->insert (current_function_decl
, base_type
, ref_type
, a
, false);
1064 /* Returns true if and only if we should store the access to EXPR.
1065 Some accesses, e.g. loads from automatic variables, are not interesting. */
1068 modref_access_analysis::record_access_p (tree expr
)
1070 if (TREE_THIS_VOLATILE (expr
))
1073 fprintf (dump_file
, " (volatile; marking nondeterministic) ");
1074 set_nondeterministic ();
1076 if (cfun
->can_throw_non_call_exceptions
1077 && tree_could_throw_p (expr
))
1080 fprintf (dump_file
, " (can throw; marking side effects) ");
1081 set_side_effects ();
1084 if (refs_local_or_readonly_memory_p (expr
))
1087 fprintf (dump_file
, " - Read-only or local, ignoring.\n");
1093 /* Collapse loads and return true if something changed. */
1096 modref_access_analysis::record_unknown_load ()
1098 bool changed
= false;
1100 if (m_summary
&& !m_summary
->loads
->every_base
)
1102 m_summary
->loads
->collapse ();
1105 if (m_summary_lto
&& !m_summary_lto
->loads
->every_base
)
1107 m_summary_lto
->loads
->collapse ();
1113 /* Collapse loads and return true if something changed. */
1116 modref_access_analysis::record_unknown_store ()
1118 bool changed
= false;
1120 if (m_summary
&& !m_summary
->stores
->every_base
)
1122 m_summary
->stores
->collapse ();
1125 if (m_summary_lto
&& !m_summary_lto
->stores
->every_base
)
1127 m_summary_lto
->stores
->collapse ();
1133 /* Merge side effects of call STMT to function with CALLEE_SUMMARY.
1134 Return true if something changed.
1135 If IGNORE_STORES is true, do not merge stores.
1136 If RECORD_ADJUSTMENTS is true cap number of adjustments to
1137 a given access to make dataflow finite. */
1140 modref_access_analysis::merge_call_side_effects
1141 (gimple
*stmt
, modref_summary
*callee_summary
,
1142 cgraph_node
*callee_node
, bool record_adjustments
)
1144 int flags
= gimple_call_flags (stmt
);
1146 /* Nothing to do for non-looping cont functions. */
1147 if ((flags
& (ECF_CONST
| ECF_NOVOPS
))
1148 && !(flags
& ECF_LOOPING_CONST_OR_PURE
))
1151 bool changed
= false;
1154 fprintf (dump_file
, " - Merging side effects of %s\n",
1155 callee_node
->dump_name ());
1157 /* Merge side effects and non-determinism.
1158 PURE/CONST flags makes functions deterministic and if there is
1159 no LOOPING_CONST_OR_PURE they also have no side effects. */
1160 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
| ECF_PURE
))
1161 || (flags
& ECF_LOOPING_CONST_OR_PURE
))
1163 if (!m_summary
->side_effects
&& callee_summary
->side_effects
)
1166 fprintf (dump_file
, " - merging side effects.\n");
1167 m_summary
->side_effects
= true;
1170 if (!m_summary
->nondeterministic
&& callee_summary
->nondeterministic
1171 && !ignore_nondeterminism_p (current_function_decl
, flags
))
1174 fprintf (dump_file
, " - merging nondeterministic.\n");
1175 m_summary
->nondeterministic
= true;
1180 /* For const functions we are done. */
1181 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
1184 /* Merge calls_interposable flags. */
1185 if (!m_summary
->calls_interposable
&& callee_summary
->calls_interposable
)
1188 fprintf (dump_file
, " - merging calls interposable.\n");
1189 m_summary
->calls_interposable
= true;
1193 if (!callee_node
->binds_to_current_def_p () && !m_summary
->calls_interposable
)
1196 fprintf (dump_file
, " - May be interposed.\n");
1197 m_summary
->calls_interposable
= true;
1201 /* Now merge the actual load, store and kill vectors. For this we need
1202 to compute map translating new parameters to old. */
1204 fprintf (dump_file
, " Parm map:");
1206 auto_vec
<modref_parm_map
, 32> parm_map
;
1207 parm_map
.safe_grow_cleared (gimple_call_num_args (stmt
), true);
1208 for (unsigned i
= 0; i
< gimple_call_num_args (stmt
); i
++)
1210 parm_map
[i
] = parm_map_for_ptr (gimple_call_arg (stmt
, i
));
1213 fprintf (dump_file
, " %i", parm_map
[i
].parm_index
);
1214 if (parm_map
[i
].parm_offset_known
)
1216 fprintf (dump_file
, " offset:");
1217 print_dec ((poly_int64_pod
)parm_map
[i
].parm_offset
,
1223 modref_parm_map chain_map
;
1224 if (gimple_call_chain (stmt
))
1226 chain_map
= parm_map_for_ptr (gimple_call_chain (stmt
));
1229 fprintf (dump_file
, "static chain %i", chain_map
.parm_index
);
1230 if (chain_map
.parm_offset_known
)
1232 fprintf (dump_file
, " offset:");
1233 print_dec ((poly_int64_pod
)chain_map
.parm_offset
,
1239 fprintf (dump_file
, "\n");
1241 /* Kills can me merged in only if we know the function is going to be
1243 if (m_always_executed
1244 && callee_summary
->kills
.length ()
1245 && (!cfun
->can_throw_non_call_exceptions
1246 || !stmt_could_throw_p (cfun
, stmt
)))
1248 /* Watch for self recursive updates. */
1249 auto_vec
<modref_access_node
, 32> saved_kills
;
1251 saved_kills
.reserve_exact (callee_summary
->kills
.length ());
1252 saved_kills
.splice (callee_summary
->kills
);
1253 for (auto kill
: saved_kills
)
1255 if (kill
.parm_index
>= (int)parm_map
.length ())
1258 = kill
.parm_index
== MODREF_STATIC_CHAIN_PARM
1260 : parm_map
[kill
.parm_index
];
1261 if (m
.parm_index
== MODREF_LOCAL_MEMORY_PARM
1262 || m
.parm_index
== MODREF_UNKNOWN_PARM
1263 || m
.parm_index
== MODREF_RETSLOT_PARM
1264 || !m
.parm_offset_known
)
1266 modref_access_node n
= kill
;
1267 n
.parm_index
= m
.parm_index
;
1268 n
.parm_offset
+= m
.parm_offset
;
1269 if (modref_access_node::insert_kill (m_summary
->kills
, n
,
1270 record_adjustments
))
1275 /* Merge in loads. */
1276 changed
|= m_summary
->loads
->merge (current_function_decl
,
1277 callee_summary
->loads
,
1278 &parm_map
, &chain_map
,
1279 record_adjustments
);
1280 /* Merge in stores. */
1281 if (!ignore_stores_p (current_function_decl
, flags
))
1283 changed
|= m_summary
->stores
->merge (current_function_decl
,
1284 callee_summary
->stores
,
1285 &parm_map
, &chain_map
,
1286 record_adjustments
);
1287 if (!m_summary
->writes_errno
1288 && callee_summary
->writes_errno
)
1290 m_summary
->writes_errno
= true;
1297 /* Return access mode for argument I of call STMT with FNSPEC. */
1300 modref_access_analysis::get_access_for_fnspec (gcall
*call
, attr_fnspec
&fnspec
,
1302 modref_parm_map
&map
)
1304 tree size
= NULL_TREE
;
1305 unsigned int size_arg
;
1307 if (!fnspec
.arg_specified_p (i
))
1309 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
1310 size
= gimple_call_arg (call
, size_arg
);
1311 else if (fnspec
.arg_access_size_given_by_type_p (i
))
1313 tree callee
= gimple_call_fndecl (call
);
1314 tree t
= TYPE_ARG_TYPES (TREE_TYPE (callee
));
1316 for (unsigned int p
= 0; p
< i
; p
++)
1318 size
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t
)));
1320 modref_access_node a
= {0, -1, -1,
1321 map
.parm_offset
, map
.parm_index
,
1322 map
.parm_offset_known
, 0};
1323 poly_int64 size_hwi
;
1325 && poly_int_tree_p (size
, &size_hwi
)
1326 && coeffs_in_range_p (size_hwi
, 0,
1327 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
1330 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
1335 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1336 If IGNORE_STORES is true ignore them.
1337 Return false if no useful summary can be produced. */
1340 modref_access_analysis::process_fnspec (gcall
*call
)
1342 int flags
= gimple_call_flags (call
);
1344 /* PURE/CONST flags makes functions deterministic and if there is
1345 no LOOPING_CONST_OR_PURE they also have no side effects. */
1346 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
| ECF_PURE
))
1347 || (flags
& ECF_LOOPING_CONST_OR_PURE
)
1348 || (cfun
->can_throw_non_call_exceptions
1349 && stmt_could_throw_p (cfun
, call
)))
1351 set_side_effects ();
1352 if (!ignore_nondeterminism_p (current_function_decl
, flags
))
1353 set_nondeterministic ();
1356 /* For const functions we are done. */
1357 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
1360 attr_fnspec fnspec
= gimple_call_fnspec (call
);
1361 /* If there is no fnpec we know nothing about loads & stores. */
1362 if (!fnspec
.known_p ())
1364 if (dump_file
&& gimple_call_builtin_p (call
, BUILT_IN_NORMAL
))
1365 fprintf (dump_file
, " Builtin with no fnspec: %s\n",
1366 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call
))));
1367 record_unknown_load ();
1368 if (!ignore_stores_p (current_function_decl
, flags
))
1369 record_unknown_store ();
1372 /* Process fnspec. */
1373 if (fnspec
.global_memory_read_p ())
1374 record_unknown_load ();
1377 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1378 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1380 else if (!fnspec
.arg_specified_p (i
)
1381 || fnspec
.arg_maybe_read_p (i
))
1383 modref_parm_map map
= parm_map_for_ptr
1384 (gimple_call_arg (call
, i
));
1386 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1388 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
1390 record_unknown_load ();
1393 modref_access_node a
= get_access_for_fnspec (call
, fnspec
, i
, map
);
1394 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1397 m_summary
->loads
->insert (current_function_decl
, 0, 0, a
, false);
1399 m_summary_lto
->loads
->insert (current_function_decl
, 0, 0, a
,
1403 if (ignore_stores_p (current_function_decl
, flags
))
1405 if (fnspec
.global_memory_written_p ())
1406 record_unknown_store ();
1409 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1410 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1412 else if (!fnspec
.arg_specified_p (i
)
1413 || fnspec
.arg_maybe_written_p (i
))
1415 modref_parm_map map
= parm_map_for_ptr
1416 (gimple_call_arg (call
, i
));
1418 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1420 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
1422 record_unknown_store ();
1425 modref_access_node a
= get_access_for_fnspec (call
, fnspec
, i
, map
);
1426 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1429 m_summary
->stores
->insert (current_function_decl
, 0, 0, a
, false);
1431 m_summary_lto
->stores
->insert (current_function_decl
,
1434 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
1437 m_summary
->writes_errno
= true;
1439 m_summary_lto
->writes_errno
= true;
1444 /* Analyze function call STMT in function F.
1445 Remember recursive calls in RECURSIVE_CALLS. */
1448 modref_access_analysis::analyze_call (gcall
*stmt
)
1450 /* Check flags on the function call. In certain cases, analysis can be
1452 int flags
= gimple_call_flags (stmt
);
1454 if ((flags
& (ECF_CONST
| ECF_NOVOPS
))
1455 && !(flags
& ECF_LOOPING_CONST_OR_PURE
))
1459 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1460 "except for args.\n");
1464 /* Next, we try to get the callee's function declaration. The goal is to
1465 merge their summary with ours. */
1466 tree callee
= gimple_call_fndecl (stmt
);
1468 /* Check if this is an indirect call. */
1472 fprintf (dump_file
, gimple_call_internal_p (stmt
)
1473 ? " - Internal call" : " - Indirect call.\n");
1474 process_fnspec (stmt
);
1477 /* We only need to handle internal calls in IPA mode. */
1478 gcc_checking_assert (!m_summary_lto
&& !m_ipa
);
1480 struct cgraph_node
*callee_node
= cgraph_node::get_create (callee
);
1482 /* If this is a recursive call, the target summary is the same as ours, so
1483 there's nothing to do. */
1484 if (recursive_call_p (current_function_decl
, callee
))
1486 m_recursive_calls
.safe_push (stmt
);
1487 set_side_effects ();
1489 fprintf (dump_file
, " - Skipping recursive call.\n");
1493 gcc_assert (callee_node
!= NULL
);
1495 /* Get the function symbol and its availability. */
1496 enum availability avail
;
1497 callee_node
= callee_node
->function_symbol (&avail
);
1499 if (builtin_safe_for_const_function_p (&looping
, callee
))
1502 set_side_effects ();
1504 fprintf (dump_file
, " - Builtin is safe for const.\n");
1507 if (avail
<= AVAIL_INTERPOSABLE
)
1511 " - Function availability <= AVAIL_INTERPOSABLE.\n");
1512 process_fnspec (stmt
);
1516 /* Get callee's modref summary. As above, if there's no summary, we either
1517 have to give up or, if stores are ignored, we can just purge loads. */
1518 modref_summary
*callee_summary
= optimization_summaries
->get (callee_node
);
1519 if (!callee_summary
)
1522 fprintf (dump_file
, " - No modref summary available for callee.\n");
1523 process_fnspec (stmt
);
1527 merge_call_side_effects (stmt
, callee_summary
, callee_node
, false);
1532 /* Helper for analyze_stmt. */
1535 modref_access_analysis::analyze_load (gimple
*, tree
, tree op
, void *data
)
1537 modref_access_analysis
*t
= (modref_access_analysis
*)data
;
1541 fprintf (dump_file
, " - Analyzing load: ");
1542 print_generic_expr (dump_file
, op
);
1543 fprintf (dump_file
, "\n");
1546 if (!t
->record_access_p (op
))
1550 ao_ref_init (&r
, op
);
1551 modref_access_node a
= get_access (&r
);
1552 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1556 t
->record_access (t
->m_summary
->loads
, &r
, a
);
1557 if (t
->m_summary_lto
)
1558 t
->record_access_lto (t
->m_summary_lto
->loads
, &r
, a
);
1562 /* Helper for analyze_stmt. */
1565 modref_access_analysis::analyze_store (gimple
*stmt
, tree
, tree op
, void *data
)
1567 modref_access_analysis
*t
= (modref_access_analysis
*)data
;
1571 fprintf (dump_file
, " - Analyzing store: ");
1572 print_generic_expr (dump_file
, op
);
1573 fprintf (dump_file
, "\n");
1576 if (!t
->record_access_p (op
))
1580 ao_ref_init (&r
, op
);
1581 modref_access_node a
= get_access (&r
);
1582 if (a
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
1586 t
->record_access (t
->m_summary
->stores
, &r
, a
);
1587 if (t
->m_summary_lto
)
1588 t
->record_access_lto (t
->m_summary_lto
->stores
, &r
, a
);
1589 if (t
->m_always_executed
1590 && a
.useful_for_kill_p ()
1591 && (!cfun
->can_throw_non_call_exceptions
1592 || !stmt_could_throw_p (cfun
, stmt
)))
1595 fprintf (dump_file
, " - Recording kill\n");
1597 modref_access_node::insert_kill (t
->m_summary
->kills
, a
, false);
1598 if (t
->m_summary_lto
)
1599 modref_access_node::insert_kill (t
->m_summary_lto
->kills
, a
, false);
1604 /* Analyze statement STMT of function F.
1605 If IPA is true do not merge in side effects of calls. */
1608 modref_access_analysis::analyze_stmt (gimple
*stmt
, bool always_executed
)
1610 m_always_executed
= always_executed
;
1611 /* In general we can not ignore clobbers because they are barriers for code
1612 motion, however after inlining it is safe to do because local optimization
1613 passes do not consider clobbers from other functions.
1614 Similar logic is in ipa-pure-const.c. */
1615 if ((m_ipa
|| cfun
->after_inlining
) && gimple_clobber_p (stmt
))
1617 if (always_executed
&& record_access_p (gimple_assign_lhs (stmt
)))
1620 ao_ref_init (&r
, gimple_assign_lhs (stmt
));
1621 modref_access_node a
= get_access (&r
);
1622 if (a
.useful_for_kill_p ())
1625 fprintf (dump_file
, " - Recording kill\n");
1627 modref_access_node::insert_kill (m_summary
->kills
, a
, false);
1629 modref_access_node::insert_kill (m_summary_lto
->kills
,
1636 /* Analyze all loads and stores in STMT. */
1637 walk_stmt_load_store_ops (stmt
, this,
1638 analyze_load
, analyze_store
);
1640 switch (gimple_code (stmt
))
1643 if (gimple_asm_volatile_p (as_a
<gasm
*> (stmt
)))
1644 set_nondeterministic ();
1645 if (cfun
->can_throw_non_call_exceptions
1646 && stmt_could_throw_p (cfun
, stmt
))
1647 set_side_effects ();
1648 /* If the ASM statement does not read nor write memory, there's nothing
1649 to do. Otherwise just give up. */
1650 if (!gimple_asm_clobbers_memory_p (as_a
<gasm
*> (stmt
)))
1653 fprintf (dump_file
, " - Function contains GIMPLE_ASM statement "
1654 "which clobbers memory.\n");
1655 record_unknown_load ();
1656 record_unknown_store ();
1659 if (!m_ipa
|| gimple_call_internal_p (stmt
))
1660 analyze_call (as_a
<gcall
*> (stmt
));
1663 attr_fnspec fnspec
= gimple_call_fnspec (as_a
<gcall
*>(stmt
));
1665 if (fnspec
.known_p ()
1666 && (!fnspec
.global_memory_read_p ()
1667 || !fnspec
.global_memory_written_p ()))
1669 cgraph_edge
*e
= cgraph_node::get
1670 (current_function_decl
)->get_edge (stmt
);
1673 fnspec_summaries
->get_create (e
)->fnspec
1674 = xstrdup (fnspec
.get_str ());
1676 fprintf (dump_file
, " Recorded fnspec %s\n",
1683 if (cfun
->can_throw_non_call_exceptions
1684 && stmt_could_throw_p (cfun
, stmt
))
1685 set_side_effects ();
1690 /* Propagate load/stres acress recursive calls. */
1693 modref_access_analysis::propagate ()
1695 if (m_ipa
&& m_summary
)
1698 bool changed
= true;
1700 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1702 m_always_executed
= false;
1703 while (changed
&& m_summary
->useful_p (m_ecf_flags
, false))
1706 for (unsigned i
= 0; i
< m_recursive_calls
.length (); i
++)
1708 changed
|= merge_call_side_effects (m_recursive_calls
[i
], m_summary
,
1715 /* Analyze function. */
1718 modref_access_analysis::analyze ()
1720 m_ecf_flags
= flags_from_decl_or_type (current_function_decl
);
1721 bool summary_useful
= true;
1723 /* Analyze each statement in each basic block of the function. If the
1724 statement cannot be analyzed (for any reason), the entire function cannot
1725 be analyzed by modref. */
1727 FOR_EACH_BB_FN (bb
, cfun
)
1729 gimple_stmt_iterator si
;
1730 bool always_executed
1731 = bb
== single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun
))->dest
;
1733 for (si
= gsi_start_nondebug_after_labels_bb (bb
);
1734 !gsi_end_p (si
); gsi_next_nondebug (&si
))
1736 analyze_stmt (gsi_stmt (si
), always_executed
);
1738 /* Avoid doing useles work. */
1739 if ((!m_summary
|| !m_summary
->useful_p (m_ecf_flags
, false))
1741 || !m_summary_lto
->useful_p (m_ecf_flags
, false)))
1743 summary_useful
= false;
1747 && stmt_can_throw_external (cfun
, gsi_stmt (si
)))
1748 always_executed
= false;
1750 if (!summary_useful
)
1753 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
1754 This needs to be done after all other side effects are computed. */
1759 if (m_summary
&& !m_summary
->side_effects
&& !finite_function_p ())
1760 m_summary
->side_effects
= true;
1761 if (m_summary_lto
&& !m_summary_lto
->side_effects
1762 && !finite_function_p ())
1763 m_summary_lto
->side_effects
= true;
1767 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1770 memory_access_to (tree op
, tree ssa_name
)
1772 tree base
= get_base_address (op
);
1775 if (TREE_CODE (base
) != MEM_REF
&& TREE_CODE (base
) != TARGET_MEM_REF
)
1777 return TREE_OPERAND (base
, 0) == ssa_name
;
1780 /* Consider statement val = *arg.
1781 return EAF flags of ARG that can be determined from EAF flags of VAL
1782 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1783 all stores to VAL, i.e. when handling noreturn function. */
1786 deref_flags (int flags
, bool ignore_stores
)
1788 /* Dereference is also a direct read but dereferenced value does not
1789 yield any other direct use. */
1790 int ret
= EAF_NO_DIRECT_CLOBBER
| EAF_NO_DIRECT_ESCAPE
1791 | EAF_NOT_RETURNED_DIRECTLY
;
1792 /* If argument is unused just account for
1793 the read involved in dereference. */
1794 if (flags
& EAF_UNUSED
)
1795 ret
|= EAF_NO_INDIRECT_READ
| EAF_NO_INDIRECT_CLOBBER
1796 | EAF_NO_INDIRECT_ESCAPE
;
1799 /* Direct or indirect accesses leads to indirect accesses. */
1800 if (((flags
& EAF_NO_DIRECT_CLOBBER
)
1801 && (flags
& EAF_NO_INDIRECT_CLOBBER
))
1803 ret
|= EAF_NO_INDIRECT_CLOBBER
;
1804 if (((flags
& EAF_NO_DIRECT_ESCAPE
)
1805 && (flags
& EAF_NO_INDIRECT_ESCAPE
))
1807 ret
|= EAF_NO_INDIRECT_ESCAPE
;
1808 if ((flags
& EAF_NO_DIRECT_READ
)
1809 && (flags
& EAF_NO_INDIRECT_READ
))
1810 ret
|= EAF_NO_INDIRECT_READ
;
1811 if ((flags
& EAF_NOT_RETURNED_DIRECTLY
)
1812 && (flags
& EAF_NOT_RETURNED_INDIRECTLY
))
1813 ret
|= EAF_NOT_RETURNED_INDIRECTLY
;
1819 /* Description of an escape point: a call which affects flags of a given
1824 /* Value escapes to this call. */
1826 /* Argument it escapes to. */
1828 /* Flags already known about the argument (this can save us from recording
1829 esape points if local analysis did good job already). */
1830 eaf_flags_t min_flags
;
1831 /* Does value escape directly or indiretly? */
1835 /* Lattice used during the eaf flags analsysis dataflow. For a given SSA name
1836 we aim to compute its flags and escape points. We also use the lattice
1837 to dynamically build dataflow graph to propagate on. */
1839 class modref_lattice
1842 /* EAF flags of the SSA name. */
1844 /* Used during DFS walk to mark names where final value was determined
1845 without need for dataflow. */
1847 /* Used during DFS walk to mark open vertices (for cycle detection). */
1849 /* Set during DFS walk for names that needs dataflow propagation. */
1851 /* Used during the iterative dataflow. */
1854 /* When doing IPA analysis we can not merge in callee escape points;
1855 Only remember them and do the merging at IPA propagation time. */
1856 vec
<escape_point
, va_heap
, vl_ptr
> escape_points
;
1858 /* Representation of a graph for dataaflow. This graph is built on-demand
1859 using modref_eaf_analysis::analyze_ssa and later solved by
1860 modref_eaf_analysis::propagate.
1861 Each edge represents the fact that flags of current lattice should be
1862 propagated to lattice of SSA_NAME. */
1863 struct propagate_edge
1868 vec
<propagate_edge
, va_heap
, vl_ptr
> propagate_to
;
1872 bool merge (const modref_lattice
&with
);
1873 bool merge (int flags
);
1874 bool merge_deref (const modref_lattice
&with
, bool ignore_stores
);
1875 bool merge_direct_load ();
1876 bool merge_direct_store ();
1877 bool add_escape_point (gcall
*call
, int arg
, int min_flags
, bool diret
);
1878 void dump (FILE *out
, int indent
= 0) const;
1881 /* Lattices are saved to vectors, so keep them PODs. */
1883 modref_lattice::init ()
1885 /* All flags we track. */
1886 int f
= EAF_NO_DIRECT_CLOBBER
| EAF_NO_INDIRECT_CLOBBER
1887 | EAF_NO_DIRECT_ESCAPE
| EAF_NO_INDIRECT_ESCAPE
1888 | EAF_NO_DIRECT_READ
| EAF_NO_INDIRECT_READ
1889 | EAF_NOT_RETURNED_DIRECTLY
| EAF_NOT_RETURNED_INDIRECTLY
1892 /* Check that eaf_flags_t is wide enough to hold all flags. */
1893 gcc_checking_assert (f
== flags
);
1898 /* Release memory. */
1900 modref_lattice::release ()
1902 escape_points
.release ();
1903 propagate_to
.release ();
1906 /* Dump lattice to OUT; indent with INDENT spaces. */
1909 modref_lattice::dump (FILE *out
, int indent
) const
1911 dump_eaf_flags (out
, flags
);
1912 if (escape_points
.length ())
1914 fprintf (out
, "%*sEscapes:\n", indent
, "");
1915 for (unsigned int i
= 0; i
< escape_points
.length (); i
++)
1917 fprintf (out
, "%*s Arg %i (%s) min flags", indent
, "",
1918 escape_points
[i
].arg
,
1919 escape_points
[i
].direct
? "direct" : "indirect");
1920 dump_eaf_flags (out
, escape_points
[i
].min_flags
, false);
1921 fprintf (out
, " in call ");
1922 print_gimple_stmt (out
, escape_points
[i
].call
, 0);
1927 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1931 modref_lattice::add_escape_point (gcall
*call
, int arg
, int min_flags
,
1937 /* If we already determined flags to be bad enough,
1938 we do not need to record. */
1939 if ((flags
& min_flags
) == flags
|| (min_flags
& EAF_UNUSED
))
1942 FOR_EACH_VEC_ELT (escape_points
, i
, ep
)
1943 if (ep
->call
== call
&& ep
->arg
== arg
&& ep
->direct
== direct
)
1945 if ((ep
->min_flags
& min_flags
) == min_flags
)
1947 ep
->min_flags
&= min_flags
;
1950 /* Give up if max escape points is met. */
1951 if ((int)escape_points
.length () > param_modref_max_escape_points
)
1954 fprintf (dump_file
, "--param modref-max-escape-points limit reached\n");
1958 escape_point new_ep
= {call
, arg
, min_flags
, direct
};
1959 escape_points
.safe_push (new_ep
);
1963 /* Merge in flags from F. */
1965 modref_lattice::merge (int f
)
1969 /* Check that flags seems sane: if function does not read the parameter
1970 it can not access it indirectly. */
1971 gcc_checking_assert (!(f
& EAF_NO_DIRECT_READ
)
1972 || ((f
& EAF_NO_INDIRECT_READ
)
1973 && (f
& EAF_NO_INDIRECT_CLOBBER
)
1974 && (f
& EAF_NO_INDIRECT_ESCAPE
)
1975 && (f
& EAF_NOT_RETURNED_INDIRECTLY
)));
1976 if ((flags
& f
) != flags
)
1979 /* Prune obvoiusly useless flags;
1980 We do not have ECF_FLAGS handy which is not big problem since
1981 we will do final flags cleanup before producing summary.
1982 Merging should be fast so it can work well with dataflow. */
1983 flags
= remove_useless_eaf_flags (flags
, 0, false);
1985 escape_points
.release ();
1991 /* Merge in WITH. Return true if anyting changed. */
1994 modref_lattice::merge (const modref_lattice
&with
)
1999 bool changed
= merge (with
.flags
);
2003 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
2004 changed
|= add_escape_point (with
.escape_points
[i
].call
,
2005 with
.escape_points
[i
].arg
,
2006 with
.escape_points
[i
].min_flags
,
2007 with
.escape_points
[i
].direct
);
2011 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
2012 stores. Return true if anyting changed. */
2015 modref_lattice::merge_deref (const modref_lattice
&with
, bool ignore_stores
)
2020 bool changed
= merge (deref_flags (with
.flags
, ignore_stores
));
2024 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
2026 int min_flags
= with
.escape_points
[i
].min_flags
;
2028 if (with
.escape_points
[i
].direct
)
2029 min_flags
= deref_flags (min_flags
, ignore_stores
);
2030 else if (ignore_stores
)
2031 min_flags
|= ignore_stores_eaf_flags
;
2032 changed
|= add_escape_point (with
.escape_points
[i
].call
,
2033 with
.escape_points
[i
].arg
,
2040 /* Merge in flags for direct load. */
2043 modref_lattice::merge_direct_load ()
2045 return merge (~(EAF_UNUSED
| EAF_NO_DIRECT_READ
));
2048 /* Merge in flags for direct store. */
2051 modref_lattice::merge_direct_store ()
2053 return merge (~(EAF_UNUSED
| EAF_NO_DIRECT_CLOBBER
));
2056 /* Analyzer of EAF flags.
2057 This is genrally dataflow problem over the SSA graph, however we only
2058 care about flags of few selected ssa names (arguments, return slot and
2059 static chain). So we first call analyze_ssa_name on all relevant names
2060 and perform a DFS walk to discover SSA names where flags needs to be
2061 determined. For acyclic graphs we try to determine final flags during
2062 this walk. Once cycles or recursin depth is met we enlist SSA names
2063 for dataflow which is done by propagate call.
2065 After propagation the flags can be obtained using get_ssa_name_flags. */
2067 class modref_eaf_analysis
2070 /* Mark NAME as relevant for analysis. */
2071 void analyze_ssa_name (tree name
);
2072 /* Dataflow slover. */
2074 /* Return flags computed earlier for NAME. */
2075 int get_ssa_name_flags (tree name
)
2077 int version
= SSA_NAME_VERSION (name
);
2078 gcc_checking_assert (m_lattice
[version
].known
);
2079 return m_lattice
[version
].flags
;
2081 /* In IPA mode this will record all escape points
2082 determined for NAME to PARM_IDNEX. Flags are minimal
2084 void record_escape_points (tree name
, int parm_index
, int flags
);
2085 modref_eaf_analysis (bool ipa
)
2089 m_lattice
.safe_grow_cleared (num_ssa_names
, true);
2091 ~modref_eaf_analysis ()
2093 gcc_checking_assert (!m_depth
);
2094 if (m_ipa
|| m_names_to_propagate
.length ())
2095 for (unsigned int i
= 0; i
< num_ssa_names
; i
++)
2096 m_lattice
[i
].release ();
2099 /* If true, we produce analysis for IPA mode. In this case escape points ar
2102 /* Depth of recursion of analyze_ssa_name. */
2104 /* Propagation lattice for individual ssa names. */
2105 auto_vec
<modref_lattice
> m_lattice
;
2106 auto_vec
<tree
> m_deferred_names
;
2107 auto_vec
<int> m_names_to_propagate
;
2109 void merge_with_ssa_name (tree dest
, tree src
, bool deref
);
2110 void merge_call_lhs_flags (gcall
*call
, int arg
, tree name
, bool direct
,
2115 /* Call statements may return tgeir parameters. Consider argument number
2116 ARG of USE_STMT and determine flags that can needs to be cleared
2117 in case pointer possibly indirectly references from ARG I is returned.
2118 If DIRECT is true consider direct returns and if INDIRECT consider
2120 LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
2121 ARG is set to -1 for static chain. */
2124 modref_eaf_analysis::merge_call_lhs_flags (gcall
*call
, int arg
,
2125 tree name
, bool direct
,
2128 int index
= SSA_NAME_VERSION (name
);
2129 bool returned_directly
= false;
2131 /* If there is no return value, no flags are affected. */
2132 if (!gimple_call_lhs (call
))
2135 /* If we know that function returns given argument and it is not ARG
2136 we can still be happy. */
2139 int flags
= gimple_call_return_flags (call
);
2140 if (flags
& ERF_RETURNS_ARG
)
2142 if ((flags
& ERF_RETURN_ARG_MASK
) == arg
)
2143 returned_directly
= true;
2148 /* Make ERF_RETURNS_ARG overwrite EAF_UNUSED. */
2149 if (returned_directly
)
2154 /* If value is not returned at all, do nothing. */
2155 else if (!direct
&& !indirect
)
2158 /* If return value is SSA name determine its flags. */
2159 if (TREE_CODE (gimple_call_lhs (call
)) == SSA_NAME
)
2161 tree lhs
= gimple_call_lhs (call
);
2163 merge_with_ssa_name (name
, lhs
, false);
2165 merge_with_ssa_name (name
, lhs
, true);
2167 /* In the case of memory store we can do nothing. */
2169 m_lattice
[index
].merge (deref_flags (0, false));
2171 m_lattice
[index
].merge (0);
2174 /* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
2175 into flags for caller, update LATTICE of corresponding
2176 argument if needed. */
2179 callee_to_caller_flags (int call_flags
, bool ignore_stores
,
2180 modref_lattice
&lattice
)
2182 /* call_flags is about callee returning a value
2183 that is not the same as caller returning it. */
2184 call_flags
|= EAF_NOT_RETURNED_DIRECTLY
2185 | EAF_NOT_RETURNED_INDIRECTLY
;
2186 if (!ignore_stores
&& !(call_flags
& EAF_UNUSED
))
2188 /* If value escapes we are no longer able to track what happens
2189 with it because we can read it from the escaped location
2191 if (!(call_flags
& EAF_NO_DIRECT_ESCAPE
))
2193 else if (!(call_flags
& EAF_NO_INDIRECT_ESCAPE
))
2194 lattice
.merge (~(EAF_NOT_RETURNED_INDIRECTLY
2195 | EAF_NO_DIRECT_READ
2196 | EAF_NO_INDIRECT_READ
2197 | EAF_NO_INDIRECT_CLOBBER
2201 call_flags
|= ignore_stores_eaf_flags
;
2205 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
2206 LATTICE is an array of modref_lattices.
2207 DEPTH is a recursion depth used to make debug output prettier.
2208 If IPA is true we analyze for IPA propagation (and thus call escape points
2209 are processed later) */
2212 modref_eaf_analysis::analyze_ssa_name (tree name
)
2214 imm_use_iterator ui
;
2216 int index
= SSA_NAME_VERSION (name
);
2218 /* See if value is already computed. */
2219 if (m_lattice
[index
].known
|| m_lattice
[index
].do_dataflow
)
2221 if (m_lattice
[index
].open
)
2225 "%*sCycle in SSA graph\n",
2229 /* Recursion guard. */
2230 m_lattice
[index
].init ();
2231 if (m_depth
== param_modref_max_depth
)
2235 "%*sMax recursion depth reached; postponing\n",
2237 m_deferred_names
.safe_push (name
);
2244 "%*sAnalyzing flags of ssa name: ", m_depth
* 4, "");
2245 print_generic_expr (dump_file
, name
);
2246 fprintf (dump_file
, "\n");
2249 FOR_EACH_IMM_USE_STMT (use_stmt
, ui
, name
)
2251 if (m_lattice
[index
].flags
== 0)
2253 if (is_gimple_debug (use_stmt
))
2257 fprintf (dump_file
, "%*s Analyzing stmt: ", m_depth
* 4, "");
2258 print_gimple_stmt (dump_file
, use_stmt
, 0);
2260 /* If we see a direct non-debug use, clear unused bit.
2261 All dereferneces should be accounted below using deref_flags. */
2262 m_lattice
[index
].merge (~EAF_UNUSED
);
2264 /* Gimple return may load the return value.
2265 Returning name counts as an use by tree-ssa-structalias.c */
2266 if (greturn
*ret
= dyn_cast
<greturn
*> (use_stmt
))
2268 /* Returning through return slot is seen as memory write earlier. */
2269 if (DECL_RESULT (current_function_decl
)
2270 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl
)))
2272 else if (gimple_return_retval (ret
) == name
)
2273 m_lattice
[index
].merge (~(EAF_UNUSED
| EAF_NOT_RETURNED_DIRECTLY
2274 | EAF_NOT_RETURNED_DIRECTLY
));
2275 else if (memory_access_to (gimple_return_retval (ret
), name
))
2277 m_lattice
[index
].merge_direct_load ();
2278 m_lattice
[index
].merge (~(EAF_UNUSED
2279 | EAF_NOT_RETURNED_INDIRECTLY
));
2282 /* Account for LHS store, arg loads and flags from callee function. */
2283 else if (gcall
*call
= dyn_cast
<gcall
*> (use_stmt
))
2285 tree callee
= gimple_call_fndecl (call
);
2287 /* IPA PTA internally it treats calling a function as "writing" to
2288 the argument space of all functions the function pointer points to
2289 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
2290 is on since that would allow propagation of this from -fno-ipa-pta
2291 to -fipa-pta functions. */
2292 if (gimple_call_fn (use_stmt
) == name
)
2293 m_lattice
[index
].merge (~(EAF_NO_DIRECT_CLOBBER
| EAF_UNUSED
));
2295 /* Recursion would require bit of propagation; give up for now. */
2296 if (callee
&& !m_ipa
&& recursive_call_p (current_function_decl
,
2298 m_lattice
[index
].merge (0);
2301 int ecf_flags
= gimple_call_flags (call
);
2302 bool ignore_stores
= ignore_stores_p (current_function_decl
,
2304 bool ignore_retval
= ignore_retval_p (current_function_decl
,
2307 /* Handle *name = func (...). */
2308 if (gimple_call_lhs (call
)
2309 && memory_access_to (gimple_call_lhs (call
), name
))
2311 m_lattice
[index
].merge_direct_store ();
2312 /* Return slot optimization passes address of
2313 LHS to callee via hidden parameter and this
2314 may make LHS to escape. See PR 98499. */
2315 if (gimple_call_return_slot_opt_p (call
)
2316 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call
))))
2318 int call_flags
= gimple_call_retslot_flags (call
);
2319 bool isretslot
= false;
2321 if (DECL_RESULT (current_function_decl
)
2322 && DECL_BY_REFERENCE
2323 (DECL_RESULT (current_function_decl
)))
2324 isretslot
= ssa_default_def
2326 DECL_RESULT (current_function_decl
))
2329 /* Passing returnslot to return slot is special because
2330 not_returned and escape has same meaning.
2331 However passing arg to return slot is different. If
2332 the callee's return slot is returned it means that
2333 arg is written to itself which is an escape.
2334 Since we do not track the memory it is written to we
2335 need to give up on analysisng it. */
2338 if (!(call_flags
& (EAF_NOT_RETURNED_DIRECTLY
2340 m_lattice
[index
].merge (0);
2341 else gcc_checking_assert
2342 (call_flags
& (EAF_NOT_RETURNED_INDIRECTLY
2344 call_flags
= callee_to_caller_flags
2348 m_lattice
[index
].merge (call_flags
);
2352 if (gimple_call_chain (call
)
2353 && (gimple_call_chain (call
) == name
))
2355 int call_flags
= gimple_call_static_chain_flags (call
);
2356 if (!ignore_retval
&& !(call_flags
& EAF_UNUSED
))
2357 merge_call_lhs_flags
2359 !(call_flags
& EAF_NOT_RETURNED_DIRECTLY
),
2360 !(call_flags
& EAF_NOT_RETURNED_INDIRECTLY
));
2361 call_flags
= callee_to_caller_flags
2362 (call_flags
, ignore_stores
,
2364 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
2365 m_lattice
[index
].merge (call_flags
);
2368 /* Process internal functions and right away. */
2369 bool record_ipa
= m_ipa
&& !gimple_call_internal_p (call
);
2371 /* Handle all function parameters. */
2372 for (unsigned i
= 0;
2373 i
< gimple_call_num_args (call
)
2374 && m_lattice
[index
].flags
; i
++)
2375 /* Name is directly passed to the callee. */
2376 if (gimple_call_arg (call
, i
) == name
)
2378 int call_flags
= gimple_call_arg_flags (call
, i
);
2380 merge_call_lhs_flags
2382 !(call_flags
& (EAF_NOT_RETURNED_DIRECTLY
2384 !(call_flags
& (EAF_NOT_RETURNED_INDIRECTLY
2386 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
2388 call_flags
= callee_to_caller_flags
2389 (call_flags
, ignore_stores
,
2392 m_lattice
[index
].merge (call_flags
);
2394 m_lattice
[index
].add_escape_point (call
, i
,
2398 /* Name is dereferenced and passed to a callee. */
2399 else if (memory_access_to (gimple_call_arg (call
, i
), name
))
2401 int call_flags
= deref_flags
2402 (gimple_call_arg_flags (call
, i
), ignore_stores
);
2403 if (!ignore_retval
&& !(call_flags
& EAF_UNUSED
)
2404 && !(call_flags
& EAF_NOT_RETURNED_DIRECTLY
)
2405 && !(call_flags
& EAF_NOT_RETURNED_INDIRECTLY
))
2406 merge_call_lhs_flags (call
, i
, name
, false, true);
2407 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
2408 m_lattice
[index
].merge_direct_load ();
2411 call_flags
= callee_to_caller_flags
2412 (call_flags
, ignore_stores
,
2415 m_lattice
[index
].merge (call_flags
);
2417 m_lattice
[index
].add_escape_point (call
, i
,
2423 else if (gimple_assign_load_p (use_stmt
))
2425 gassign
*assign
= as_a
<gassign
*> (use_stmt
);
2426 /* Memory to memory copy. */
2427 if (gimple_store_p (assign
))
2429 /* Handle *lhs = *name.
2431 We do not track memory locations, so assume that value
2432 is used arbitrarily. */
2433 if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
2434 m_lattice
[index
].merge (deref_flags (0, false));
2435 /* Handle *name = *exp. */
2436 else if (memory_access_to (gimple_assign_lhs (assign
), name
))
2437 m_lattice
[index
].merge_direct_store ();
2439 /* Handle lhs = *name. */
2440 else if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
2442 tree lhs
= gimple_assign_lhs (assign
);
2443 merge_with_ssa_name (name
, lhs
, true);
2446 else if (gimple_store_p (use_stmt
))
2448 gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
);
2450 /* Handle *lhs = name. */
2451 if (assign
&& gimple_assign_rhs1 (assign
) == name
)
2454 fprintf (dump_file
, "%*s ssa name saved to memory\n",
2456 m_lattice
[index
].merge (0);
2458 /* Handle *name = exp. */
2460 && memory_access_to (gimple_assign_lhs (assign
), name
))
2462 /* In general we can not ignore clobbers because they are
2463 barriers for code motion, however after inlining it is safe to
2464 do because local optimization passes do not consider clobbers
2465 from other functions.
2466 Similar logic is in ipa-pure-const.c. */
2467 if (!cfun
->after_inlining
|| !gimple_clobber_p (assign
))
2468 m_lattice
[index
].merge_direct_store ();
2470 /* ASM statements etc. */
2474 fprintf (dump_file
, "%*s Unhandled store\n", m_depth
* 4, "");
2475 m_lattice
[index
].merge (0);
2478 else if (gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
))
2480 enum tree_code code
= gimple_assign_rhs_code (assign
);
2482 /* See if operation is a merge as considered by
2483 tree-ssa-structalias.c:find_func_aliases. */
2484 if (!truth_value_p (code
)
2485 && code
!= POINTER_DIFF_EXPR
2486 && (code
!= POINTER_PLUS_EXPR
2487 || gimple_assign_rhs1 (assign
) == name
))
2489 tree lhs
= gimple_assign_lhs (assign
);
2490 merge_with_ssa_name (name
, lhs
, false);
2493 else if (gphi
*phi
= dyn_cast
<gphi
*> (use_stmt
))
2495 tree result
= gimple_phi_result (phi
);
2496 merge_with_ssa_name (name
, result
, false);
2498 /* Conditions are not considered escape points
2499 by tree-ssa-structalias. */
2500 else if (gimple_code (use_stmt
) == GIMPLE_COND
)
2505 fprintf (dump_file
, "%*s Unhandled stmt\n", m_depth
* 4, "");
2506 m_lattice
[index
].merge (0);
2511 fprintf (dump_file
, "%*s current flags of ", m_depth
* 4, "");
2512 print_generic_expr (dump_file
, name
);
2513 m_lattice
[index
].dump (dump_file
, m_depth
* 4 + 4);
2518 fprintf (dump_file
, "%*sflags of ssa name ", m_depth
* 4, "");
2519 print_generic_expr (dump_file
, name
);
2520 m_lattice
[index
].dump (dump_file
, m_depth
* 4 + 2);
2522 m_lattice
[index
].open
= false;
2523 if (!m_lattice
[index
].do_dataflow
)
2524 m_lattice
[index
].known
= true;
2527 /* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
2531 modref_eaf_analysis::merge_with_ssa_name (tree dest
, tree src
, bool deref
)
2533 int index
= SSA_NAME_VERSION (dest
);
2534 int src_index
= SSA_NAME_VERSION (src
);
2536 /* Merging lattice with itself is a no-op. */
2537 if (!deref
&& src
== dest
)
2541 analyze_ssa_name (src
);
2544 m_lattice
[index
].merge_deref (m_lattice
[src_index
], false);
2546 m_lattice
[index
].merge (m_lattice
[src_index
]);
2548 /* If we failed to produce final solution add an edge to the dataflow
2550 if (!m_lattice
[src_index
].known
)
2552 modref_lattice::propagate_edge e
= {index
, deref
};
2554 if (!m_lattice
[src_index
].propagate_to
.length ())
2555 m_names_to_propagate
.safe_push (src_index
);
2556 m_lattice
[src_index
].propagate_to
.safe_push (e
);
2557 m_lattice
[src_index
].changed
= true;
2558 m_lattice
[src_index
].do_dataflow
= true;
2561 "%*sWill propgate from ssa_name %i to %i%s\n",
2563 "", src_index
, index
, deref
? " (deref)" : "");
2567 /* In the case we deferred some SSA names, reprocess them. In the case some
2568 dataflow edges were introduced, do the actual iterative dataflow. */
2571 modref_eaf_analysis::propagate ()
2576 bool changed
= true;
2578 while (m_deferred_names
.length ())
2580 tree name
= m_deferred_names
.pop ();
2581 m_lattice
[SSA_NAME_VERSION (name
)].open
= false;
2583 fprintf (dump_file
, "Analyzing deferred SSA name\n");
2584 analyze_ssa_name (name
);
2587 if (!m_names_to_propagate
.length ())
2590 fprintf (dump_file
, "Propagating EAF flags\n");
2592 /* Compute reverse postorder. */
2599 auto_vec
<struct stack_entry
> stack
;
2600 int pos
= m_names_to_propagate
.length () - 1;
2602 rpo
.safe_grow (m_names_to_propagate
.length (), true);
2603 stack
.reserve_exact (m_names_to_propagate
.length ());
2605 /* We reuse known flag for RPO DFS walk bookeeping. */
2607 FOR_EACH_VEC_ELT (m_names_to_propagate
, i
, index
)
2608 gcc_assert (!m_lattice
[index
].known
&& m_lattice
[index
].changed
);
2610 FOR_EACH_VEC_ELT (m_names_to_propagate
, i
, index
)
2612 if (!m_lattice
[index
].known
)
2614 stack_entry e
= {index
, 0};
2616 stack
.quick_push (e
);
2617 m_lattice
[index
].known
= true;
2619 while (stack
.length ())
2622 int index1
= stack
.last ().name
;
2624 while (stack
.last ().pos
< m_lattice
[index1
].propagate_to
.length ())
2626 int index2
= m_lattice
[index1
]
2627 .propagate_to
[stack
.last ().pos
].ssa_name
;
2629 stack
.last ().pos
++;
2630 if (!m_lattice
[index2
].known
2631 && m_lattice
[index2
].propagate_to
.length ())
2633 stack_entry e
= {index2
, 0};
2635 stack
.quick_push (e
);
2636 m_lattice
[index2
].known
= true;
2642 && stack
.last ().pos
== m_lattice
[index1
].propagate_to
.length ())
2644 rpo
[pos
--] = index1
;
2650 /* Perform itrative dataflow. */
2656 fprintf (dump_file
, " iteration %i\n", iterations
);
2657 FOR_EACH_VEC_ELT (rpo
, i
, index
)
2659 if (m_lattice
[index
].changed
)
2663 m_lattice
[index
].changed
= false;
2665 fprintf (dump_file
, " Visiting ssa name %i\n", index
);
2666 for (j
= 0; j
< m_lattice
[index
].propagate_to
.length (); j
++)
2669 int target
= m_lattice
[index
].propagate_to
[j
].ssa_name
;
2670 bool deref
= m_lattice
[index
].propagate_to
[j
].deref
;
2673 fprintf (dump_file
, " Propagating flags of ssa name"
2675 index
, target
, deref
? " (deref)" : "");
2676 m_lattice
[target
].known
= true;
2677 if (!m_lattice
[index
].propagate_to
[j
].deref
)
2678 ch
= m_lattice
[target
].merge (m_lattice
[index
]);
2680 ch
= m_lattice
[target
].merge_deref (m_lattice
[index
],
2686 fprintf (dump_file
, " New lattice: ");
2687 m_lattice
[target
].dump (dump_file
);
2690 m_lattice
[target
].changed
= true;
2696 fprintf (dump_file
, "EAF flags propagated in %i iterations\n", iterations
);
2699 /* Record escape points of PARM_INDEX according to LATTICE. */
2702 modref_eaf_analysis::record_escape_points (tree name
, int parm_index
, int flags
)
2704 modref_lattice
&lattice
= m_lattice
[SSA_NAME_VERSION (name
)];
2706 if (lattice
.escape_points
.length ())
2710 cgraph_node
*node
= cgraph_node::get (current_function_decl
);
2713 FOR_EACH_VEC_ELT (lattice
.escape_points
, ip
, ep
)
2714 if ((ep
->min_flags
& flags
) != flags
)
2716 cgraph_edge
*e
= node
->get_edge (ep
->call
);
2717 struct escape_entry ee
= {parm_index
, ep
->arg
,
2718 ep
->min_flags
, ep
->direct
};
2720 escape_summaries
->get_create (e
)->esc
.safe_push (ee
);
2725 /* Determine EAF flags for function parameters
2726 and fill in SUMMARY/SUMMARY_LTO. If IPA is true work in IPA mode
2727 where we also collect scape points.
2728 PAST_FLAGS, PAST_RETSLOT_FLAGS, PAST_STATIC_CHAIN_FLAGS can be
2729 used to preserve flags from prevoius (IPA) run for cases where
2730 late optimizations changed code in a way we can no longer analyze
2734 analyze_parms (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
2735 bool ipa
, vec
<eaf_flags_t
> &past_flags
,
2736 int past_retslot_flags
, int past_static_chain_flags
)
2738 unsigned int parm_index
= 0;
2739 unsigned int count
= 0;
2740 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
2741 tree retslot
= NULL
;
2742 tree static_chain
= NULL
;
2744 /* If there is return slot, look up its SSA name. */
2745 if (DECL_RESULT (current_function_decl
)
2746 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl
)))
2747 retslot
= ssa_default_def (cfun
, DECL_RESULT (current_function_decl
));
2748 if (cfun
->static_chain_decl
)
2749 static_chain
= ssa_default_def (cfun
, cfun
->static_chain_decl
);
2751 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
2752 parm
= TREE_CHAIN (parm
))
2755 if (!count
&& !retslot
&& !static_chain
)
2758 modref_eaf_analysis
eaf_analysis (ipa
);
2760 /* Determine all SSA names we need to know flags for. */
2761 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
2762 parm
= TREE_CHAIN (parm
))
2764 tree name
= ssa_default_def (cfun
, parm
);
2766 eaf_analysis
.analyze_ssa_name (name
);
2769 eaf_analysis
.analyze_ssa_name (retslot
);
2771 eaf_analysis
.analyze_ssa_name (static_chain
);
2773 /* Do the dataflow. */
2774 eaf_analysis
.propagate ();
2776 tree attr
= lookup_attribute ("fn spec",
2778 (TREE_TYPE (current_function_decl
)));
2779 attr_fnspec
fnspec (attr
2780 ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr
)))
2784 /* Store results to summaries. */
2785 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
; parm_index
++,
2786 parm
= TREE_CHAIN (parm
))
2788 tree name
= ssa_default_def (cfun
, parm
);
2789 if (!name
|| has_zero_uses (name
))
2791 /* We do not track non-SSA parameters,
2792 but we want to track unused gimple_regs. */
2793 if (!is_gimple_reg (parm
))
2797 if (parm_index
>= summary
->arg_flags
.length ())
2798 summary
->arg_flags
.safe_grow_cleared (count
, true);
2799 summary
->arg_flags
[parm_index
] = EAF_UNUSED
;
2801 else if (summary_lto
)
2803 if (parm_index
>= summary_lto
->arg_flags
.length ())
2804 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
2805 summary_lto
->arg_flags
[parm_index
] = EAF_UNUSED
;
2809 int flags
= eaf_analysis
.get_ssa_name_flags (name
);
2810 int attr_flags
= fnspec
.arg_eaf_flags (parm_index
);
2812 if (dump_file
&& (flags
| attr_flags
) != flags
&& !(flags
& EAF_UNUSED
))
2815 " Flags for param %i combined with fnspec flags:",
2817 dump_eaf_flags (dump_file
, attr_flags
, false);
2818 fprintf (dump_file
, " determined: ");
2819 dump_eaf_flags (dump_file
, flags
, true);
2821 flags
|= attr_flags
;
2823 /* Eliminate useless flags so we do not end up storing unnecessary
2826 flags
= remove_useless_eaf_flags
2828 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
2829 if (past_flags
.length () > parm_index
)
2831 int past
= past_flags
[parm_index
];
2832 past
= remove_useless_eaf_flags
2834 VOID_TYPE_P (TREE_TYPE
2835 (TREE_TYPE (current_function_decl
))));
2836 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
2839 " Flags for param %i combined with IPA pass:",
2841 dump_eaf_flags (dump_file
, past
, false);
2842 fprintf (dump_file
, " determined: ");
2843 dump_eaf_flags (dump_file
, flags
, true);
2845 if (!(flags
& EAF_UNUSED
))
2853 if (parm_index
>= summary
->arg_flags
.length ())
2854 summary
->arg_flags
.safe_grow_cleared (count
, true);
2855 summary
->arg_flags
[parm_index
] = flags
;
2857 else if (summary_lto
)
2859 if (parm_index
>= summary_lto
->arg_flags
.length ())
2860 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
2861 summary_lto
->arg_flags
[parm_index
] = flags
;
2863 eaf_analysis
.record_escape_points (name
, parm_index
, flags
);
2868 int flags
= eaf_analysis
.get_ssa_name_flags (retslot
);
2869 int past
= past_retslot_flags
;
2871 flags
= remove_useless_eaf_flags (flags
, ecf_flags
, false);
2872 past
= remove_useless_eaf_flags
2874 VOID_TYPE_P (TREE_TYPE
2875 (TREE_TYPE (current_function_decl
))));
2876 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
2879 " Retslot flags combined with IPA pass:");
2880 dump_eaf_flags (dump_file
, past
, false);
2881 fprintf (dump_file
, " determined: ");
2882 dump_eaf_flags (dump_file
, flags
, true);
2884 if (!(flags
& EAF_UNUSED
))
2889 summary
->retslot_flags
= flags
;
2891 summary_lto
->retslot_flags
= flags
;
2892 eaf_analysis
.record_escape_points (retslot
,
2893 MODREF_RETSLOT_PARM
, flags
);
2898 int flags
= eaf_analysis
.get_ssa_name_flags (static_chain
);
2899 int past
= past_static_chain_flags
;
2901 flags
= remove_useless_eaf_flags (flags
, ecf_flags
, false);
2902 past
= remove_useless_eaf_flags
2904 VOID_TYPE_P (TREE_TYPE
2905 (TREE_TYPE (current_function_decl
))));
2906 if (dump_file
&& (flags
| past
) != flags
&& !(flags
& EAF_UNUSED
))
2909 " Static chain flags combined with IPA pass:");
2910 dump_eaf_flags (dump_file
, past
, false);
2911 fprintf (dump_file
, " determined: ");
2912 dump_eaf_flags (dump_file
, flags
, true);
2914 if (!(flags
& EAF_UNUSED
))
2919 summary
->static_chain_flags
= flags
;
2921 summary_lto
->static_chain_flags
= flags
;
2922 eaf_analysis
.record_escape_points (static_chain
,
2923 MODREF_STATIC_CHAIN_PARM
,
2929 /* Analyze function F. IPA indicates whether we're running in local mode
2930 (false) or the IPA mode (true).
2931 Return true if fixup cfg is needed after the pass. */
2934 analyze_function (function
*f
, bool ipa
)
2936 bool fixup_cfg
= false;
2938 fprintf (dump_file
, "modref analyzing '%s' (ipa=%i)%s%s\n",
2939 function_name (f
), ipa
,
2940 TREE_READONLY (current_function_decl
) ? " (const)" : "",
2941 DECL_PURE_P (current_function_decl
) ? " (pure)" : "");
2943 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
2944 if (!flag_ipa_modref
2945 || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl
)))
2948 /* Compute no-LTO summaries when local optimization is going to happen. */
2949 bool nolto
= (!ipa
|| ((!flag_lto
|| flag_fat_lto_objects
) && !in_lto_p
)
2950 || (in_lto_p
&& !flag_wpa
2951 && flag_incremental_link
!= INCREMENTAL_LINK_LTO
));
2952 /* Compute LTO when LTO streaming is going to happen. */
2953 bool lto
= ipa
&& ((flag_lto
&& !in_lto_p
)
2955 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
2956 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
2958 modref_summary
*summary
= NULL
;
2959 modref_summary_lto
*summary_lto
= NULL
;
2961 bool past_flags_known
= false;
2962 auto_vec
<eaf_flags_t
> past_flags
;
2963 int past_retslot_flags
= 0;
2964 int past_static_chain_flags
= 0;
2966 /* Initialize the summary.
2967 If we run in local mode there is possibly pre-existing summary from
2968 IPA pass. Dump it so it is easy to compare if mod-ref info has
2972 if (!optimization_summaries
)
2973 optimization_summaries
= modref_summaries::create_ggc (symtab
);
2974 else /* Remove existing summary if we are re-running the pass. */
2976 summary
= optimization_summaries
->get (fnode
);
2982 fprintf (dump_file
, "Past summary:\n");
2983 optimization_summaries
->get (fnode
)->dump (dump_file
);
2985 past_flags
.reserve_exact (summary
->arg_flags
.length ());
2986 past_flags
.splice (summary
->arg_flags
);
2987 past_retslot_flags
= summary
->retslot_flags
;
2988 past_static_chain_flags
= summary
->static_chain_flags
;
2989 past_flags_known
= true;
2991 optimization_summaries
->remove (fnode
);
2993 summary
= optimization_summaries
->get_create (fnode
);
2994 gcc_checking_assert (nolto
&& !lto
);
2996 /* In IPA mode we analyze every function precisely once. Assert that. */
3002 summaries
= modref_summaries::create_ggc (symtab
);
3004 summaries
->remove (fnode
);
3005 summary
= summaries
->get_create (fnode
);
3010 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
3012 summaries_lto
->remove (fnode
);
3013 summary_lto
= summaries_lto
->get_create (fnode
);
3015 if (!fnspec_summaries
)
3016 fnspec_summaries
= new fnspec_summaries_t (symtab
);
3017 if (!escape_summaries
)
3018 escape_summaries
= new escape_summaries_t (symtab
);
3022 /* Create and initialize summary for F.
3023 Note that summaries may be already allocated from previous
3027 gcc_assert (!summary
->loads
);
3028 summary
->loads
= modref_records::create_ggc ();
3029 gcc_assert (!summary
->stores
);
3030 summary
->stores
= modref_records::create_ggc ();
3031 summary
->writes_errno
= false;
3032 summary
->side_effects
= false;
3033 summary
->nondeterministic
= false;
3034 summary
->calls_interposable
= false;
3038 gcc_assert (!summary_lto
->loads
);
3039 summary_lto
->loads
= modref_records_lto::create_ggc ();
3040 gcc_assert (!summary_lto
->stores
);
3041 summary_lto
->stores
= modref_records_lto::create_ggc ();
3042 summary_lto
->writes_errno
= false;
3043 summary_lto
->side_effects
= false;
3044 summary_lto
->nondeterministic
= false;
3045 summary_lto
->calls_interposable
= false;
3048 analyze_parms (summary
, summary_lto
, ipa
,
3049 past_flags
, past_retslot_flags
, past_static_chain_flags
);
3052 modref_access_analysis
analyzer (ipa
, summary
, summary_lto
);
3053 analyzer
.analyze ();
3056 if (!ipa
&& flag_ipa_pure_const
)
3058 if (!summary
->stores
->every_base
&& !summary
->stores
->bases
3059 && !summary
->nondeterministic
)
3061 if (!summary
->loads
->every_base
&& !summary
->loads
->bases
3062 && !summary
->calls_interposable
)
3063 fixup_cfg
= ipa_make_function_const (fnode
,
3064 summary
->side_effects
, true);
3066 fixup_cfg
= ipa_make_function_pure (fnode
,
3067 summary
->side_effects
, true);
3070 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
3071 if (summary
&& !summary
->useful_p (ecf_flags
))
3074 optimization_summaries
->remove (fnode
);
3076 summaries
->remove (fnode
);
3080 summary
->finalize (current_function_decl
);
3081 if (summary_lto
&& !summary_lto
->useful_p (ecf_flags
))
3083 summaries_lto
->remove (fnode
);
3087 if (ipa
&& !summary
&& !summary_lto
)
3088 remove_modref_edge_summaries (fnode
);
3092 fprintf (dump_file
, " - modref done with result: tracked.\n");
3094 summary
->dump (dump_file
);
3096 summary_lto
->dump (dump_file
);
3097 dump_modref_edge_summaries (dump_file
, fnode
, 2);
3098 /* To simplify debugging, compare IPA and local solutions. */
3099 if (past_flags_known
&& summary
)
3101 size_t len
= summary
->arg_flags
.length ();
3103 if (past_flags
.length () > len
)
3104 len
= past_flags
.length ();
3105 for (size_t i
= 0; i
< len
; i
++)
3107 int old_flags
= i
< past_flags
.length () ? past_flags
[i
] : 0;
3108 int new_flags
= i
< summary
->arg_flags
.length ()
3109 ? summary
->arg_flags
[i
] : 0;
3110 old_flags
= remove_useless_eaf_flags
3111 (old_flags
, flags_from_decl_or_type (current_function_decl
),
3112 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3113 if (old_flags
!= new_flags
)
3115 if ((old_flags
& ~new_flags
) == 0
3116 || (new_flags
& EAF_UNUSED
))
3117 fprintf (dump_file
, " Flags for param %i improved:",
3121 dump_eaf_flags (dump_file
, old_flags
, false);
3122 fprintf (dump_file
, " -> ");
3123 dump_eaf_flags (dump_file
, new_flags
, true);
3126 past_retslot_flags
= remove_useless_eaf_flags
3127 (past_retslot_flags
,
3128 flags_from_decl_or_type (current_function_decl
),
3129 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3130 if (past_retslot_flags
!= summary
->retslot_flags
)
3132 if ((past_retslot_flags
& ~summary
->retslot_flags
) == 0
3133 || (summary
->retslot_flags
& EAF_UNUSED
))
3134 fprintf (dump_file
, " Flags for retslot improved:");
3137 dump_eaf_flags (dump_file
, past_retslot_flags
, false);
3138 fprintf (dump_file
, " -> ");
3139 dump_eaf_flags (dump_file
, summary
->retslot_flags
, true);
3141 past_static_chain_flags
= remove_useless_eaf_flags
3142 (past_static_chain_flags
,
3143 flags_from_decl_or_type (current_function_decl
),
3144 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3145 if (past_static_chain_flags
!= summary
->static_chain_flags
)
3147 if ((past_static_chain_flags
& ~summary
->static_chain_flags
) == 0
3148 || (summary
->static_chain_flags
& EAF_UNUSED
))
3149 fprintf (dump_file
, " Flags for static chain improved:");
3152 dump_eaf_flags (dump_file
, past_static_chain_flags
, false);
3153 fprintf (dump_file
, " -> ");
3154 dump_eaf_flags (dump_file
, summary
->static_chain_flags
, true);
3157 else if (past_flags_known
&& !summary
)
3159 for (size_t i
= 0; i
< past_flags
.length (); i
++)
3161 int old_flags
= past_flags
[i
];
3162 old_flags
= remove_useless_eaf_flags
3163 (old_flags
, flags_from_decl_or_type (current_function_decl
),
3164 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3167 fprintf (dump_file
, " Flags for param %i worsened:",
3169 dump_eaf_flags (dump_file
, old_flags
, false);
3170 fprintf (dump_file
, " -> \n");
3173 past_retslot_flags
= remove_useless_eaf_flags
3174 (past_retslot_flags
,
3175 flags_from_decl_or_type (current_function_decl
),
3176 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3177 if (past_retslot_flags
)
3179 fprintf (dump_file
, " Flags for retslot worsened:");
3180 dump_eaf_flags (dump_file
, past_retslot_flags
, false);
3181 fprintf (dump_file
, " ->\n");
3183 past_static_chain_flags
= remove_useless_eaf_flags
3184 (past_static_chain_flags
,
3185 flags_from_decl_or_type (current_function_decl
),
3186 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
3187 if (past_static_chain_flags
)
3189 fprintf (dump_file
, " Flags for static chain worsened:");
3190 dump_eaf_flags (dump_file
, past_static_chain_flags
, false);
3191 fprintf (dump_file
, " ->\n");
3198 /* Callback for generate_summary. */
3201 modref_generate (void)
3203 struct cgraph_node
*node
;
3204 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
3206 function
*f
= DECL_STRUCT_FUNCTION (node
->decl
);
3210 analyze_function (f
, true);
3215 } /* ANON namespace. */
3217 /* Debugging helper. */
3220 debug_eaf_flags (int flags
)
3222 dump_eaf_flags (stderr
, flags
, true);
3225 /* Called when a new function is inserted to callgraph late. */
3228 modref_summaries::insert (struct cgraph_node
*node
, modref_summary
*)
3230 /* Local passes ought to be executed by the pass manager. */
3231 if (this == optimization_summaries
)
3233 optimization_summaries
->remove (node
);
3236 if (!DECL_STRUCT_FUNCTION (node
->decl
)
3237 || !opt_for_fn (node
->decl
, flag_ipa_modref
))
3239 summaries
->remove (node
);
3242 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
3243 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
3247 /* Called when a new function is inserted to callgraph late. */
3250 modref_summaries_lto::insert (struct cgraph_node
*node
, modref_summary_lto
*)
3252 /* We do not support adding new function when IPA information is already
3253 propagated. This is done only by SIMD cloning that is not very
3255 if (!DECL_STRUCT_FUNCTION (node
->decl
)
3256 || !opt_for_fn (node
->decl
, flag_ipa_modref
)
3259 summaries_lto
->remove (node
);
3262 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
3263 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
3267 /* Called when new clone is inserted to callgraph late. */
3270 modref_summaries::duplicate (cgraph_node
*, cgraph_node
*dst
,
3271 modref_summary
*src_data
,
3272 modref_summary
*dst_data
)
3274 /* Do not duplicate optimization summaries; we do not handle parameter
3275 transforms on them. */
3276 if (this == optimization_summaries
)
3278 optimization_summaries
->remove (dst
);
3281 dst_data
->stores
= modref_records::create_ggc ();
3282 dst_data
->stores
->copy_from (src_data
->stores
);
3283 dst_data
->loads
= modref_records::create_ggc ();
3284 dst_data
->loads
->copy_from (src_data
->loads
);
3285 dst_data
->kills
.reserve_exact (src_data
->kills
.length ());
3286 dst_data
->kills
.splice (src_data
->kills
);
3287 dst_data
->writes_errno
= src_data
->writes_errno
;
3288 dst_data
->side_effects
= src_data
->side_effects
;
3289 dst_data
->nondeterministic
= src_data
->nondeterministic
;
3290 dst_data
->calls_interposable
= src_data
->calls_interposable
;
3291 if (src_data
->arg_flags
.length ())
3292 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
3293 dst_data
->retslot_flags
= src_data
->retslot_flags
;
3294 dst_data
->static_chain_flags
= src_data
->static_chain_flags
;
3297 /* Called when new clone is inserted to callgraph late. */
3300 modref_summaries_lto::duplicate (cgraph_node
*, cgraph_node
*,
3301 modref_summary_lto
*src_data
,
3302 modref_summary_lto
*dst_data
)
3304 /* Be sure that no further cloning happens after ipa-modref. If it does
3305 we will need to update signatures for possible param changes. */
3306 gcc_checking_assert (!((modref_summaries_lto
*)summaries_lto
)->propagated
);
3307 dst_data
->stores
= modref_records_lto::create_ggc ();
3308 dst_data
->stores
->copy_from (src_data
->stores
);
3309 dst_data
->loads
= modref_records_lto::create_ggc ();
3310 dst_data
->loads
->copy_from (src_data
->loads
);
3311 dst_data
->kills
.reserve_exact (src_data
->kills
.length ());
3312 dst_data
->kills
.splice (src_data
->kills
);
3313 dst_data
->writes_errno
= src_data
->writes_errno
;
3314 dst_data
->side_effects
= src_data
->side_effects
;
3315 dst_data
->nondeterministic
= src_data
->nondeterministic
;
3316 dst_data
->calls_interposable
= src_data
->calls_interposable
;
3317 if (src_data
->arg_flags
.length ())
3318 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
3319 dst_data
->retslot_flags
= src_data
->retslot_flags
;
3320 dst_data
->static_chain_flags
= src_data
->static_chain_flags
;
3325 /* Definition of the modref pass on GIMPLE. */
3326 const pass_data pass_data_modref
= {
3331 (PROP_cfg
| PROP_ssa
),
3338 class pass_modref
: public gimple_opt_pass
3341 pass_modref (gcc::context
*ctxt
)
3342 : gimple_opt_pass (pass_data_modref
, ctxt
) {}
3344 /* opt_pass methods: */
3347 return new pass_modref (m_ctxt
);
3349 virtual bool gate (function
*)
3351 return flag_ipa_modref
;
3353 virtual unsigned int execute (function
*);
3356 /* Encode TT to the output block OB using the summary streaming API. */
3359 write_modref_records (modref_records_lto
*tt
, struct output_block
*ob
)
3361 streamer_write_uhwi (ob
, tt
->every_base
);
3362 streamer_write_uhwi (ob
, vec_safe_length (tt
->bases
));
3363 for (auto base_node
: tt
->bases
)
3365 stream_write_tree (ob
, base_node
->base
, true);
3367 streamer_write_uhwi (ob
, base_node
->every_ref
);
3368 streamer_write_uhwi (ob
, vec_safe_length (base_node
->refs
));
3370 for (auto ref_node
: base_node
->refs
)
3372 stream_write_tree (ob
, ref_node
->ref
, true);
3373 streamer_write_uhwi (ob
, ref_node
->every_access
);
3374 streamer_write_uhwi (ob
, vec_safe_length (ref_node
->accesses
));
3376 for (auto access_node
: ref_node
->accesses
)
3377 access_node
.stream_out (ob
);
3382 /* Read a modref_tree from the input block IB using the data from DATA_IN.
3383 This assumes that the tree was encoded using write_modref_tree.
3384 Either nolto_ret or lto_ret is initialized by the tree depending whether
3385 LTO streaming is expected or not. */
3388 read_modref_records (tree decl
,
3389 lto_input_block
*ib
, struct data_in
*data_in
,
3390 modref_records
**nolto_ret
,
3391 modref_records_lto
**lto_ret
)
3393 size_t max_bases
= opt_for_fn (decl
, param_modref_max_bases
);
3394 size_t max_refs
= opt_for_fn (decl
, param_modref_max_refs
);
3395 size_t max_accesses
= opt_for_fn (decl
, param_modref_max_accesses
);
3398 *lto_ret
= modref_records_lto::create_ggc ();
3400 *nolto_ret
= modref_records::create_ggc ();
3401 gcc_checking_assert (lto_ret
|| nolto_ret
);
3403 size_t every_base
= streamer_read_uhwi (ib
);
3404 size_t nbase
= streamer_read_uhwi (ib
);
3406 gcc_assert (!every_base
|| nbase
== 0);
3410 (*nolto_ret
)->collapse ();
3412 (*lto_ret
)->collapse ();
3414 for (size_t i
= 0; i
< nbase
; i
++)
3416 tree base_tree
= stream_read_tree (ib
, data_in
);
3417 modref_base_node
<alias_set_type
> *nolto_base_node
= NULL
;
3418 modref_base_node
<tree
> *lto_base_node
= NULL
;
3420 /* At stream in time we have LTO alias info. Check if we streamed in
3421 something obviously unnecessary. Do not glob types by alias sets;
3422 it is not 100% clear that ltrans types will get merged same way.
3423 Types may get refined based on ODR type conflicts. */
3424 if (base_tree
&& !get_alias_set (base_tree
))
3428 fprintf (dump_file
, "Streamed in alias set 0 type ");
3429 print_generic_expr (dump_file
, base_tree
);
3430 fprintf (dump_file
, "\n");
3436 nolto_base_node
= (*nolto_ret
)->insert_base (base_tree
3437 ? get_alias_set (base_tree
)
3440 lto_base_node
= (*lto_ret
)->insert_base (base_tree
, 0, max_bases
);
3441 size_t every_ref
= streamer_read_uhwi (ib
);
3442 size_t nref
= streamer_read_uhwi (ib
);
3444 gcc_assert (!every_ref
|| nref
== 0);
3447 if (nolto_base_node
)
3448 nolto_base_node
->collapse ();
3450 lto_base_node
->collapse ();
3452 for (size_t j
= 0; j
< nref
; j
++)
3454 tree ref_tree
= stream_read_tree (ib
, data_in
);
3456 if (ref_tree
&& !get_alias_set (ref_tree
))
3460 fprintf (dump_file
, "Streamed in alias set 0 type ");
3461 print_generic_expr (dump_file
, ref_tree
);
3462 fprintf (dump_file
, "\n");
3467 modref_ref_node
<alias_set_type
> *nolto_ref_node
= NULL
;
3468 modref_ref_node
<tree
> *lto_ref_node
= NULL
;
3470 if (nolto_base_node
)
3472 = nolto_base_node
->insert_ref (ref_tree
3473 ? get_alias_set (ref_tree
) : 0,
3476 lto_ref_node
= lto_base_node
->insert_ref (ref_tree
, max_refs
);
3478 size_t every_access
= streamer_read_uhwi (ib
);
3479 size_t naccesses
= streamer_read_uhwi (ib
);
3481 if (nolto_ref_node
&& every_access
)
3482 nolto_ref_node
->collapse ();
3483 if (lto_ref_node
&& every_access
)
3484 lto_ref_node
->collapse ();
3486 for (size_t k
= 0; k
< naccesses
; k
++)
3488 modref_access_node a
= modref_access_node::stream_in (ib
);
3490 nolto_ref_node
->insert_access (a
, max_accesses
, false);
3492 lto_ref_node
->insert_access (a
, max_accesses
, false);
3497 (*lto_ret
)->cleanup ();
3499 (*nolto_ret
)->cleanup ();
3502 /* Write ESUM to BP. */
3505 modref_write_escape_summary (struct bitpack_d
*bp
, escape_summary
*esum
)
3509 bp_pack_var_len_unsigned (bp
, 0);
3512 bp_pack_var_len_unsigned (bp
, esum
->esc
.length ());
3515 FOR_EACH_VEC_ELT (esum
->esc
, i
, ee
)
3517 bp_pack_var_len_int (bp
, ee
->parm_index
);
3518 bp_pack_var_len_unsigned (bp
, ee
->arg
);
3519 bp_pack_var_len_unsigned (bp
, ee
->min_flags
);
3520 bp_pack_value (bp
, ee
->direct
, 1);
3524 /* Read escape summary for E from BP. */
3527 modref_read_escape_summary (struct bitpack_d
*bp
, cgraph_edge
*e
)
3529 unsigned int n
= bp_unpack_var_len_unsigned (bp
);
3532 escape_summary
*esum
= escape_summaries
->get_create (e
);
3533 esum
->esc
.reserve_exact (n
);
3534 for (unsigned int i
= 0; i
< n
; i
++)
3537 ee
.parm_index
= bp_unpack_var_len_int (bp
);
3538 ee
.arg
= bp_unpack_var_len_unsigned (bp
);
3539 ee
.min_flags
= bp_unpack_var_len_unsigned (bp
);
3540 ee
.direct
= bp_unpack_value (bp
, 1);
3541 esum
->esc
.quick_push (ee
);
3545 /* Callback for write_summary. */
3550 struct output_block
*ob
= create_output_block (LTO_section_ipa_modref
);
3551 lto_symtab_encoder_t encoder
= ob
->decl_state
->symtab_node_encoder
;
3552 unsigned int count
= 0;
3557 streamer_write_uhwi (ob
, 0);
3558 streamer_write_char_stream (ob
->main_stream
, 0);
3559 produce_asm (ob
, NULL
);
3560 destroy_output_block (ob
);
3564 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
3566 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
3567 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
3568 modref_summary_lto
*r
;
3570 if (cnode
&& cnode
->definition
&& !cnode
->alias
3571 && (r
= summaries_lto
->get (cnode
))
3572 && r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
3575 streamer_write_uhwi (ob
, count
);
3577 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
3579 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
3580 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
3582 if (cnode
&& cnode
->definition
&& !cnode
->alias
)
3584 modref_summary_lto
*r
= summaries_lto
->get (cnode
);
3586 if (!r
|| !r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
3589 streamer_write_uhwi (ob
, lto_symtab_encoder_encode (encoder
, cnode
));
3591 streamer_write_uhwi (ob
, r
->arg_flags
.length ());
3592 for (unsigned int i
= 0; i
< r
->arg_flags
.length (); i
++)
3593 streamer_write_uhwi (ob
, r
->arg_flags
[i
]);
3594 streamer_write_uhwi (ob
, r
->retslot_flags
);
3595 streamer_write_uhwi (ob
, r
->static_chain_flags
);
3597 write_modref_records (r
->loads
, ob
);
3598 write_modref_records (r
->stores
, ob
);
3599 streamer_write_uhwi (ob
, r
->kills
.length ());
3600 for (auto kill
: r
->kills
)
3601 kill
.stream_out (ob
);
3603 struct bitpack_d bp
= bitpack_create (ob
->main_stream
);
3604 bp_pack_value (&bp
, r
->writes_errno
, 1);
3605 bp_pack_value (&bp
, r
->side_effects
, 1);
3606 bp_pack_value (&bp
, r
->nondeterministic
, 1);
3607 bp_pack_value (&bp
, r
->calls_interposable
, 1);
3610 for (cgraph_edge
*e
= cnode
->indirect_calls
;
3611 e
; e
= e
->next_callee
)
3613 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
3614 bp_pack_value (&bp
, sum
!= NULL
, 1);
3616 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
3617 class escape_summary
*esum
= escape_summaries
->get (e
);
3618 modref_write_escape_summary (&bp
,esum
);
3620 for (cgraph_edge
*e
= cnode
->callees
; e
; e
= e
->next_callee
)
3622 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
3623 bp_pack_value (&bp
, sum
!= NULL
, 1);
3625 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
3626 class escape_summary
*esum
= escape_summaries
->get (e
);
3627 modref_write_escape_summary (&bp
,esum
);
3630 streamer_write_bitpack (&bp
);
3633 streamer_write_char_stream (ob
->main_stream
, 0);
3634 produce_asm (ob
, NULL
);
3635 destroy_output_block (ob
);
3639 read_section (struct lto_file_decl_data
*file_data
, const char *data
,
3642 const struct lto_function_header
*header
3643 = (const struct lto_function_header
*) data
;
3644 const int cfg_offset
= sizeof (struct lto_function_header
);
3645 const int main_offset
= cfg_offset
+ header
->cfg_size
;
3646 const int string_offset
= main_offset
+ header
->main_size
;
3647 struct data_in
*data_in
;
3649 unsigned int f_count
;
3651 lto_input_block
ib ((const char *) data
+ main_offset
, header
->main_size
,
3652 file_data
->mode_table
);
3655 = lto_data_in_create (file_data
, (const char *) data
+ string_offset
,
3656 header
->string_size
, vNULL
);
3657 f_count
= streamer_read_uhwi (&ib
);
3658 for (i
= 0; i
< f_count
; i
++)
3660 struct cgraph_node
*node
;
3661 lto_symtab_encoder_t encoder
;
3663 unsigned int index
= streamer_read_uhwi (&ib
);
3664 encoder
= file_data
->symtab_node_encoder
;
3665 node
= dyn_cast
<cgraph_node
*> (lto_symtab_encoder_deref (encoder
,
3668 modref_summary
*modref_sum
= summaries
3669 ? summaries
->get_create (node
) : NULL
;
3670 modref_summary_lto
*modref_sum_lto
= summaries_lto
3671 ? summaries_lto
->get_create (node
)
3673 if (optimization_summaries
)
3674 modref_sum
= optimization_summaries
->get_create (node
);
3678 modref_sum
->writes_errno
= false;
3679 modref_sum
->side_effects
= false;
3680 modref_sum
->nondeterministic
= false;
3681 modref_sum
->calls_interposable
= false;
3685 modref_sum_lto
->writes_errno
= false;
3686 modref_sum_lto
->side_effects
= false;
3687 modref_sum_lto
->nondeterministic
= false;
3688 modref_sum_lto
->calls_interposable
= false;
3691 gcc_assert (!modref_sum
|| (!modref_sum
->loads
3692 && !modref_sum
->stores
));
3693 gcc_assert (!modref_sum_lto
|| (!modref_sum_lto
->loads
3694 && !modref_sum_lto
->stores
));
3695 unsigned int args
= streamer_read_uhwi (&ib
);
3696 if (args
&& modref_sum
)
3697 modref_sum
->arg_flags
.reserve_exact (args
);
3698 if (args
&& modref_sum_lto
)
3699 modref_sum_lto
->arg_flags
.reserve_exact (args
);
3700 for (unsigned int i
= 0; i
< args
; i
++)
3702 eaf_flags_t flags
= streamer_read_uhwi (&ib
);
3704 modref_sum
->arg_flags
.quick_push (flags
);
3706 modref_sum_lto
->arg_flags
.quick_push (flags
);
3708 eaf_flags_t flags
= streamer_read_uhwi (&ib
);
3710 modref_sum
->retslot_flags
= flags
;
3712 modref_sum_lto
->retslot_flags
= flags
;
3714 flags
= streamer_read_uhwi (&ib
);
3716 modref_sum
->static_chain_flags
= flags
;
3718 modref_sum_lto
->static_chain_flags
= flags
;
3720 read_modref_records (node
->decl
, &ib
, data_in
,
3721 modref_sum
? &modref_sum
->loads
: NULL
,
3722 modref_sum_lto
? &modref_sum_lto
->loads
: NULL
);
3723 read_modref_records (node
->decl
, &ib
, data_in
,
3724 modref_sum
? &modref_sum
->stores
: NULL
,
3725 modref_sum_lto
? &modref_sum_lto
->stores
: NULL
);
3726 int j
= streamer_read_uhwi (&ib
);
3727 if (j
&& modref_sum
)
3728 modref_sum
->kills
.reserve_exact (j
);
3729 if (j
&& modref_sum_lto
)
3730 modref_sum_lto
->kills
.reserve_exact (j
);
3731 for (int k
= 0; k
< j
; k
++)
3733 modref_access_node a
= modref_access_node::stream_in (&ib
);
3736 modref_sum
->kills
.quick_push (a
);
3738 modref_sum_lto
->kills
.quick_push (a
);
3740 struct bitpack_d bp
= streamer_read_bitpack (&ib
);
3741 if (bp_unpack_value (&bp
, 1))
3744 modref_sum
->writes_errno
= true;
3746 modref_sum_lto
->writes_errno
= true;
3748 if (bp_unpack_value (&bp
, 1))
3751 modref_sum
->side_effects
= true;
3753 modref_sum_lto
->side_effects
= true;
3755 if (bp_unpack_value (&bp
, 1))
3758 modref_sum
->nondeterministic
= true;
3760 modref_sum_lto
->nondeterministic
= true;
3762 if (bp_unpack_value (&bp
, 1))
3765 modref_sum
->calls_interposable
= true;
3767 modref_sum_lto
->calls_interposable
= true;
3771 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
3773 if (bp_unpack_value (&bp
, 1))
3775 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
3776 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
3778 modref_read_escape_summary (&bp
, e
);
3780 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
3782 if (bp_unpack_value (&bp
, 1))
3784 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
3785 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
3787 modref_read_escape_summary (&bp
, e
);
3791 modref_sum
->finalize (node
->decl
);
3794 fprintf (dump_file
, "Read modref for %s\n",
3795 node
->dump_name ());
3797 modref_sum
->dump (dump_file
);
3799 modref_sum_lto
->dump (dump_file
);
3800 dump_modref_edge_summaries (dump_file
, node
, 4);
3804 lto_free_section_data (file_data
, LTO_section_ipa_modref
, NULL
, data
,
3806 lto_data_in_delete (data_in
);
3809 /* Callback for read_summary. */
3814 struct lto_file_decl_data
**file_data_vec
= lto_get_file_decl_data ();
3815 struct lto_file_decl_data
*file_data
;
3818 gcc_checking_assert (!optimization_summaries
&& !summaries
&& !summaries_lto
);
3820 optimization_summaries
= modref_summaries::create_ggc (symtab
);
3823 if (flag_wpa
|| flag_incremental_link
== INCREMENTAL_LINK_LTO
)
3824 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
3826 || (flag_incremental_link
== INCREMENTAL_LINK_LTO
3827 && flag_fat_lto_objects
))
3828 summaries
= modref_summaries::create_ggc (symtab
);
3829 if (!fnspec_summaries
)
3830 fnspec_summaries
= new fnspec_summaries_t (symtab
);
3831 if (!escape_summaries
)
3832 escape_summaries
= new escape_summaries_t (symtab
);
3835 while ((file_data
= file_data_vec
[j
++]))
3838 const char *data
= lto_get_summary_section_data (file_data
,
3839 LTO_section_ipa_modref
,
3842 read_section (file_data
, data
, len
);
3844 /* Fatal error here. We do not want to support compiling ltrans units
3845 with different version of compiler or different flags than the WPA
3846 unit, so this should never happen. */
3847 fatal_error (input_location
,
3848 "IPA modref summary is missing in input file");
3852 /* Recompute arg_flags for param adjustments in INFO. */
3855 remap_arg_flags (auto_vec
<eaf_flags_t
> &arg_flags
, clone_info
*info
)
3857 auto_vec
<eaf_flags_t
> old
= arg_flags
.copy ();
3860 ipa_adjusted_param
*p
;
3862 arg_flags
.release ();
3864 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
3866 int o
= info
->param_adjustments
->get_original_index (i
);
3867 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
3871 arg_flags
.safe_grow_cleared (max
+ 1, true);
3872 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
3874 int o
= info
->param_adjustments
->get_original_index (i
);
3875 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
3876 arg_flags
[i
] = old
[o
];
3880 /* Update kills accrdoing to the parm map MAP. */
3883 remap_kills (vec
<modref_access_node
> &kills
, const vec
<int> &map
)
3885 for (size_t i
= 0; i
< kills
.length ();)
3886 if (kills
[i
].parm_index
>= 0)
3888 if (kills
[i
].parm_index
< (int)map
.length ()
3889 && map
[kills
[i
].parm_index
] != MODREF_UNKNOWN_PARM
)
3891 kills
[i
].parm_index
= map
[kills
[i
].parm_index
];
3895 kills
.unordered_remove (i
);
3901 /* If signature changed, update the summary. */
3904 update_signature (struct cgraph_node
*node
)
3906 clone_info
*info
= clone_info::get (node
);
3907 if (!info
|| !info
->param_adjustments
)
3910 modref_summary
*r
= optimization_summaries
3911 ? optimization_summaries
->get (node
) : NULL
;
3912 modref_summary_lto
*r_lto
= summaries_lto
3913 ? summaries_lto
->get (node
) : NULL
;
3918 fprintf (dump_file
, "Updating summary for %s from:\n",
3919 node
->dump_name ());
3921 r
->dump (dump_file
);
3923 r_lto
->dump (dump_file
);
3927 ipa_adjusted_param
*p
;
3929 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
3931 int idx
= info
->param_adjustments
->get_original_index (i
);
3936 auto_vec
<int, 32> map
;
3938 map
.reserve (max
+ 1);
3939 for (i
= 0; i
<= max
; i
++)
3940 map
.quick_push (MODREF_UNKNOWN_PARM
);
3941 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
3943 int idx
= info
->param_adjustments
->get_original_index (i
);
3949 r
->loads
->remap_params (&map
);
3950 r
->stores
->remap_params (&map
);
3951 remap_kills (r
->kills
, map
);
3952 if (r
->arg_flags
.length ())
3953 remap_arg_flags (r
->arg_flags
, info
);
3957 r_lto
->loads
->remap_params (&map
);
3958 r_lto
->stores
->remap_params (&map
);
3959 remap_kills (r_lto
->kills
, map
);
3960 if (r_lto
->arg_flags
.length ())
3961 remap_arg_flags (r_lto
->arg_flags
, info
);
3965 fprintf (dump_file
, "to:\n");
3967 r
->dump (dump_file
);
3969 r_lto
->dump (dump_file
);
3972 r
->finalize (node
->decl
);
3976 /* Definition of the modref IPA pass. */
3977 const pass_data pass_data_ipa_modref
=
3979 IPA_PASS
, /* type */
3980 "modref", /* name */
3981 OPTGROUP_IPA
, /* optinfo_flags */
3982 TV_IPA_MODREF
, /* tv_id */
3983 0, /* properties_required */
3984 0, /* properties_provided */
3985 0, /* properties_destroyed */
3986 0, /* todo_flags_start */
3987 ( TODO_dump_symtab
), /* todo_flags_finish */
3990 class pass_ipa_modref
: public ipa_opt_pass_d
3993 pass_ipa_modref (gcc::context
*ctxt
)
3994 : ipa_opt_pass_d (pass_data_ipa_modref
, ctxt
,
3995 modref_generate
, /* generate_summary */
3996 modref_write
, /* write_summary */
3997 modref_read
, /* read_summary */
3998 modref_write
, /* write_optimization_summary */
3999 modref_read
, /* read_optimization_summary */
4000 NULL
, /* stmt_fixup */
4001 0, /* function_transform_todo_flags_start */
4002 NULL
, /* function_transform */
4003 NULL
) /* variable_transform */
4006 /* opt_pass methods: */
4007 opt_pass
*clone () { return new pass_ipa_modref (m_ctxt
); }
4008 virtual bool gate (function
*)
4012 virtual unsigned int execute (function
*);
4018 unsigned int pass_modref::execute (function
*f
)
4020 if (analyze_function (f
, false))
4021 return execute_fixup_cfg ();
4026 make_pass_modref (gcc::context
*ctxt
)
4028 return new pass_modref (ctxt
);
4032 make_pass_ipa_modref (gcc::context
*ctxt
)
4034 return new pass_ipa_modref (ctxt
);
4039 /* Skip edges from and to nodes without ipa_pure_const enabled.
4040 Ignore not available symbols. */
4043 ignore_edge (struct cgraph_edge
*e
)
4045 /* We merge summaries of inline clones into summaries of functions they
4046 are inlined to. For that reason the complete function bodies must
4048 if (!e
->inline_failed
)
4050 enum availability avail
;
4051 cgraph_node
*callee
= e
->callee
->function_or_virtual_thunk_symbol
4052 (&avail
, e
->caller
);
4054 return (avail
<= AVAIL_INTERPOSABLE
4055 || ((!optimization_summaries
|| !optimization_summaries
->get (callee
))
4056 && (!summaries_lto
|| !summaries_lto
->get (callee
))));
4059 /* Compute parm_map for CALLEE_EDGE. */
4062 compute_parm_map (cgraph_edge
*callee_edge
, vec
<modref_parm_map
> *parm_map
)
4064 class ipa_edge_args
*args
;
4065 if (ipa_node_params_sum
4066 && !callee_edge
->call_stmt_cannot_inline_p
4067 && (args
= ipa_edge_args_sum
->get (callee_edge
)) != NULL
)
4069 int i
, count
= ipa_get_cs_argument_count (args
);
4070 class ipa_node_params
*caller_parms_info
, *callee_pi
;
4071 class ipa_call_summary
*es
4072 = ipa_call_summaries
->get (callee_edge
);
4074 = callee_edge
->callee
->function_or_virtual_thunk_symbol
4075 (NULL
, callee_edge
->caller
);
4078 = ipa_node_params_sum
->get (callee_edge
->caller
->inlined_to
4079 ? callee_edge
->caller
->inlined_to
4080 : callee_edge
->caller
);
4081 callee_pi
= ipa_node_params_sum
->get (callee
);
4083 (*parm_map
).safe_grow_cleared (count
, true);
4085 for (i
= 0; i
< count
; i
++)
4087 if (es
&& es
->param
[i
].points_to_local_or_readonly_memory
)
4089 (*parm_map
)[i
].parm_index
= MODREF_LOCAL_MEMORY_PARM
;
4093 struct ipa_jump_func
*jf
4094 = ipa_get_ith_jump_func (args
, i
);
4095 if (jf
&& callee_pi
)
4097 tree cst
= ipa_value_from_jfunc (caller_parms_info
,
4101 if (cst
&& points_to_local_or_readonly_memory_p (cst
))
4103 (*parm_map
)[i
].parm_index
= MODREF_LOCAL_MEMORY_PARM
;
4107 if (jf
&& jf
->type
== IPA_JF_PASS_THROUGH
)
4109 (*parm_map
)[i
].parm_index
4110 = ipa_get_jf_pass_through_formal_id (jf
);
4111 if (ipa_get_jf_pass_through_operation (jf
) == NOP_EXPR
)
4113 (*parm_map
)[i
].parm_offset_known
= true;
4114 (*parm_map
)[i
].parm_offset
= 0;
4116 else if (ipa_get_jf_pass_through_operation (jf
)
4117 == POINTER_PLUS_EXPR
4118 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf
),
4119 &(*parm_map
)[i
].parm_offset
))
4120 (*parm_map
)[i
].parm_offset_known
= true;
4122 (*parm_map
)[i
].parm_offset_known
= false;
4125 if (jf
&& jf
->type
== IPA_JF_ANCESTOR
)
4127 (*parm_map
)[i
].parm_index
= ipa_get_jf_ancestor_formal_id (jf
);
4128 (*parm_map
)[i
].parm_offset_known
= true;
4130 (!(ipa_get_jf_ancestor_offset (jf
) & (BITS_PER_UNIT
- 1)));
4131 (*parm_map
)[i
].parm_offset
4132 = ipa_get_jf_ancestor_offset (jf
) >> LOG2_BITS_PER_UNIT
;
4135 (*parm_map
)[i
].parm_index
= -1;
4139 fprintf (dump_file
, " Parm map: ");
4140 for (i
= 0; i
< count
; i
++)
4141 fprintf (dump_file
, " %i", (*parm_map
)[i
].parm_index
);
4142 fprintf (dump_file
, "\n");
4149 /* Map used to translate escape infos. */
4157 /* Update escape map for E. */
4160 update_escape_summary_1 (cgraph_edge
*e
,
4161 vec
<vec
<escape_map
>> &map
,
4164 escape_summary
*sum
= escape_summaries
->get (e
);
4167 auto_vec
<escape_entry
> old
= sum
->esc
.copy ();
4168 sum
->esc
.release ();
4172 FOR_EACH_VEC_ELT (old
, i
, ee
)
4175 struct escape_map
*em
;
4176 /* TODO: We do not have jump functions for return slots, so we
4177 never propagate them to outer function. */
4178 if (ee
->parm_index
>= (int)map
.length ()
4179 || ee
->parm_index
< 0)
4181 FOR_EACH_VEC_ELT (map
[ee
->parm_index
], j
, em
)
4183 int min_flags
= ee
->min_flags
;
4184 if (ee
->direct
&& !em
->direct
)
4185 min_flags
= deref_flags (min_flags
, ignore_stores
);
4186 struct escape_entry entry
= {em
->parm_index
, ee
->arg
,
4188 ee
->direct
& em
->direct
};
4189 sum
->esc
.safe_push (entry
);
4192 if (!sum
->esc
.length ())
4193 escape_summaries
->remove (e
);
4196 /* Update escape map fo NODE. */
4199 update_escape_summary (cgraph_node
*node
,
4200 vec
<vec
<escape_map
>> &map
,
4203 if (!escape_summaries
)
4205 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
4206 update_escape_summary_1 (e
, map
, ignore_stores
);
4207 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
4209 if (!e
->inline_failed
)
4210 update_escape_summary (e
->callee
, map
, ignore_stores
);
4212 update_escape_summary_1 (e
, map
, ignore_stores
);
4216 /* Get parameter type from DECL. This is only safe for special cases
4217 like builtins we create fnspec for because the type match is checked
4218 at fnspec creation time. */
4221 get_parm_type (tree decl
, unsigned int i
)
4223 tree t
= TYPE_ARG_TYPES (TREE_TYPE (decl
));
4225 for (unsigned int p
= 0; p
< i
; p
++)
4227 return TREE_VALUE (t
);
4230 /* Return access mode for argument I of call E with FNSPEC. */
4232 static modref_access_node
4233 get_access_for_fnspec (cgraph_edge
*e
, attr_fnspec
&fnspec
,
4234 unsigned int i
, modref_parm_map
&map
)
4236 tree size
= NULL_TREE
;
4237 unsigned int size_arg
;
4239 if (!fnspec
.arg_specified_p (i
))
4241 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
4243 cgraph_node
*node
= e
->caller
->inlined_to
4244 ? e
->caller
->inlined_to
: e
->caller
;
4245 ipa_node_params
*caller_parms_info
= ipa_node_params_sum
->get (node
);
4246 ipa_edge_args
*args
= ipa_edge_args_sum
->get (e
);
4247 struct ipa_jump_func
*jf
= ipa_get_ith_jump_func (args
, size_arg
);
4250 size
= ipa_value_from_jfunc (caller_parms_info
, jf
,
4251 get_parm_type (e
->callee
->decl
, size_arg
));
4253 else if (fnspec
.arg_access_size_given_by_type_p (i
))
4254 size
= TYPE_SIZE_UNIT (get_parm_type (e
->callee
->decl
, i
));
4255 modref_access_node a
= {0, -1, -1,
4256 map
.parm_offset
, map
.parm_index
,
4257 map
.parm_offset_known
, 0};
4258 poly_int64 size_hwi
;
4260 && poly_int_tree_p (size
, &size_hwi
)
4261 && coeffs_in_range_p (size_hwi
, 0,
4262 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
4265 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
4270 /* Collapse loads and return true if something changed. */
4272 collapse_loads (modref_summary
*cur_summary
,
4273 modref_summary_lto
*cur_summary_lto
)
4275 bool changed
= false;
4277 if (cur_summary
&& !cur_summary
->loads
->every_base
)
4279 cur_summary
->loads
->collapse ();
4283 && !cur_summary_lto
->loads
->every_base
)
4285 cur_summary_lto
->loads
->collapse ();
4291 /* Collapse loads and return true if something changed. */
4294 collapse_stores (modref_summary
*cur_summary
,
4295 modref_summary_lto
*cur_summary_lto
)
4297 bool changed
= false;
4299 if (cur_summary
&& !cur_summary
->stores
->every_base
)
4301 cur_summary
->stores
->collapse ();
4305 && !cur_summary_lto
->stores
->every_base
)
4307 cur_summary_lto
->stores
->collapse ();
4313 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
4314 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
4317 propagate_unknown_call (cgraph_node
*node
,
4318 cgraph_edge
*e
, int ecf_flags
,
4319 modref_summary
*cur_summary
,
4320 modref_summary_lto
*cur_summary_lto
,
4321 bool nontrivial_scc
)
4323 bool changed
= false;
4324 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
4325 auto_vec
<modref_parm_map
, 32> parm_map
;
4329 && builtin_safe_for_const_function_p (&looping
, e
->callee
->decl
))
4331 if (looping
&& cur_summary
&& !cur_summary
->side_effects
)
4333 cur_summary
->side_effects
= true;
4336 if (looping
&& cur_summary_lto
&& !cur_summary_lto
->side_effects
)
4338 cur_summary_lto
->side_effects
= true;
4344 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
| ECF_PURE
))
4345 || (ecf_flags
& ECF_LOOPING_CONST_OR_PURE
)
4348 if (cur_summary
&& !cur_summary
->side_effects
)
4350 cur_summary
->side_effects
= true;
4353 if (cur_summary_lto
&& !cur_summary_lto
->side_effects
)
4355 cur_summary_lto
->side_effects
= true;
4358 if (cur_summary
&& !cur_summary
->nondeterministic
4359 && !ignore_nondeterminism_p (node
->decl
, ecf_flags
))
4361 cur_summary
->nondeterministic
= true;
4364 if (cur_summary_lto
&& !cur_summary_lto
->nondeterministic
4365 && !ignore_nondeterminism_p (node
->decl
, ecf_flags
))
4367 cur_summary_lto
->nondeterministic
= true;
4371 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
4375 && compute_parm_map (e
, &parm_map
))
4377 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
4379 gcc_checking_assert (fnspec
.known_p ());
4380 if (fnspec
.global_memory_read_p ())
4381 collapse_loads (cur_summary
, cur_summary_lto
);
4384 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
4385 for (unsigned i
= 0; i
< parm_map
.length () && t
;
4386 i
++, t
= TREE_CHAIN (t
))
4387 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
4389 else if (!fnspec
.arg_specified_p (i
)
4390 || fnspec
.arg_maybe_read_p (i
))
4392 modref_parm_map map
= parm_map
[i
];
4393 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
4395 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
4397 collapse_loads (cur_summary
, cur_summary_lto
);
4401 changed
|= cur_summary
->loads
->insert
4403 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4404 if (cur_summary_lto
)
4405 changed
|= cur_summary_lto
->loads
->insert
4407 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4410 if (ignore_stores_p (node
->decl
, ecf_flags
))
4412 else if (fnspec
.global_memory_written_p ())
4413 collapse_stores (cur_summary
, cur_summary_lto
);
4416 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
4417 for (unsigned i
= 0; i
< parm_map
.length () && t
;
4418 i
++, t
= TREE_CHAIN (t
))
4419 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
4421 else if (!fnspec
.arg_specified_p (i
)
4422 || fnspec
.arg_maybe_written_p (i
))
4424 modref_parm_map map
= parm_map
[i
];
4425 if (map
.parm_index
== MODREF_LOCAL_MEMORY_PARM
)
4427 if (map
.parm_index
== MODREF_UNKNOWN_PARM
)
4429 collapse_stores (cur_summary
, cur_summary_lto
);
4433 changed
|= cur_summary
->stores
->insert
4435 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4436 if (cur_summary_lto
)
4437 changed
|= cur_summary_lto
->stores
->insert
4439 get_access_for_fnspec (e
, fnspec
, i
, map
), false);
4442 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
4444 if (cur_summary
&& !cur_summary
->writes_errno
)
4446 cur_summary
->writes_errno
= true;
4449 if (cur_summary_lto
&& !cur_summary_lto
->writes_errno
)
4451 cur_summary_lto
->writes_errno
= true;
4458 fprintf (dump_file
, " collapsing loads\n");
4459 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
4460 if (!ignore_stores_p (node
->decl
, ecf_flags
))
4463 fprintf (dump_file
, " collapsing stores\n");
4464 changed
|= collapse_stores (cur_summary
, cur_summary_lto
);
4469 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
4470 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
4473 remove_useless_summaries (cgraph_node
*node
,
4474 modref_summary
**cur_summary_ptr
,
4475 modref_summary_lto
**cur_summary_lto_ptr
,
4478 if (*cur_summary_ptr
&& !(*cur_summary_ptr
)->useful_p (ecf_flags
, false))
4480 optimization_summaries
->remove (node
);
4481 *cur_summary_ptr
= NULL
;
4483 if (*cur_summary_lto_ptr
4484 && !(*cur_summary_lto_ptr
)->useful_p (ecf_flags
, false))
4486 summaries_lto
->remove (node
);
4487 *cur_summary_lto_ptr
= NULL
;
4491 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4492 and propagate loads/stores. */
4495 modref_propagate_in_scc (cgraph_node
*component_node
)
4497 bool changed
= true;
4504 = ((struct ipa_dfs_info
*) component_node
->aux
)->next_cycle
;
4506 for (struct cgraph_node
*cur
= component_node
; cur
;
4507 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4509 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
4510 modref_summary
*cur_summary
= optimization_summaries
4511 ? optimization_summaries
->get (node
)
4513 modref_summary_lto
*cur_summary_lto
= summaries_lto
4514 ? summaries_lto
->get (node
)
4517 if (!cur_summary
&& !cur_summary_lto
)
4520 int cur_ecf_flags
= flags_from_decl_or_type (node
->decl
);
4523 fprintf (dump_file
, " Processing %s%s%s\n",
4525 TREE_READONLY (cur
->decl
) ? " (const)" : "",
4526 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
4528 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
4531 fprintf (dump_file
, " Indirect call\n");
4532 if (propagate_unknown_call
4533 (node
, e
, e
->indirect_info
->ecf_flags
,
4534 cur_summary
, cur_summary_lto
,
4538 remove_useless_summaries (node
, &cur_summary
,
4541 if (!cur_summary
&& !cur_summary_lto
)
4546 if (!cur_summary
&& !cur_summary_lto
)
4549 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
4550 callee_edge
= callee_edge
->next_callee
)
4552 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
4553 modref_summary
*callee_summary
= NULL
;
4554 modref_summary_lto
*callee_summary_lto
= NULL
;
4555 struct cgraph_node
*callee
;
4557 if (!callee_edge
->inline_failed
4558 || ((flags
& (ECF_CONST
| ECF_NOVOPS
))
4559 && !(flags
& ECF_LOOPING_CONST_OR_PURE
)))
4562 /* Get the callee and its summary. */
4563 enum availability avail
;
4564 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
4567 /* It is not necessary to re-process calls outside of the
4571 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
4572 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
4576 fprintf (dump_file
, " Call to %s\n",
4577 callee_edge
->callee
->dump_name ());
4579 bool ignore_stores
= ignore_stores_p (cur
->decl
, flags
);
4581 if (avail
<= AVAIL_INTERPOSABLE
)
4584 fprintf (dump_file
, " Call target interposable"
4585 " or not available\n");
4586 changed
|= propagate_unknown_call
4587 (node
, callee_edge
, flags
,
4588 cur_summary
, cur_summary_lto
,
4590 if (!cur_summary
&& !cur_summary_lto
)
4595 /* We don't know anything about CALLEE, hence we cannot tell
4596 anything about the entire component. */
4599 && !(callee_summary
= optimization_summaries
->get (callee
)))
4602 fprintf (dump_file
, " No call target summary\n");
4603 changed
|= propagate_unknown_call
4604 (node
, callee_edge
, flags
,
4609 && !(callee_summary_lto
= summaries_lto
->get (callee
)))
4612 fprintf (dump_file
, " No call target summary\n");
4613 changed
|= propagate_unknown_call
4614 (node
, callee_edge
, flags
,
4615 NULL
, cur_summary_lto
,
4619 if (callee_summary
&& !cur_summary
->side_effects
4620 && (callee_summary
->side_effects
4621 || callee_edge
->recursive_p ()))
4623 cur_summary
->side_effects
= true;
4626 if (callee_summary_lto
&& !cur_summary_lto
->side_effects
4627 && (callee_summary_lto
->side_effects
4628 || callee_edge
->recursive_p ()))
4630 cur_summary_lto
->side_effects
= true;
4633 if (callee_summary
&& !cur_summary
->nondeterministic
4634 && callee_summary
->nondeterministic
4635 && !ignore_nondeterminism_p (cur
->decl
, flags
))
4637 cur_summary
->nondeterministic
= true;
4640 if (callee_summary_lto
&& !cur_summary_lto
->nondeterministic
4641 && callee_summary_lto
->nondeterministic
4642 && !ignore_nondeterminism_p (cur
->decl
, flags
))
4644 cur_summary_lto
->nondeterministic
= true;
4647 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
4650 /* We can not safely optimize based on summary of callee if it
4651 does not always bind to current def: it is possible that
4652 memory load was optimized out earlier which may not happen in
4653 the interposed variant. */
4654 if (!callee_edge
->binds_to_current_def_p ())
4656 if (cur_summary
&& !cur_summary
->calls_interposable
)
4658 cur_summary
->calls_interposable
= true;
4661 if (cur_summary_lto
&& !cur_summary_lto
->calls_interposable
)
4663 cur_summary_lto
->calls_interposable
= true;
4667 fprintf (dump_file
, " May not bind local;"
4668 " collapsing loads\n");
4672 auto_vec
<modref_parm_map
, 32> parm_map
;
4673 modref_parm_map chain_map
;
4674 /* TODO: Once we get jump functions for static chains we could
4676 chain_map
.parm_index
= MODREF_UNKNOWN_PARM
;
4678 compute_parm_map (callee_edge
, &parm_map
);
4680 /* Merge in callee's information. */
4683 changed
|= cur_summary
->loads
->merge
4684 (node
->decl
, callee_summary
->loads
,
4685 &parm_map
, &chain_map
, !first
);
4688 changed
|= cur_summary
->stores
->merge
4689 (node
->decl
, callee_summary
->stores
,
4690 &parm_map
, &chain_map
, !first
);
4691 if (!cur_summary
->writes_errno
4692 && callee_summary
->writes_errno
)
4694 cur_summary
->writes_errno
= true;
4699 if (callee_summary_lto
)
4701 changed
|= cur_summary_lto
->loads
->merge
4702 (node
->decl
, callee_summary_lto
->loads
,
4703 &parm_map
, &chain_map
, !first
);
4706 changed
|= cur_summary_lto
->stores
->merge
4707 (node
->decl
, callee_summary_lto
->stores
,
4708 &parm_map
, &chain_map
, !first
);
4709 if (!cur_summary_lto
->writes_errno
4710 && callee_summary_lto
->writes_errno
)
4712 cur_summary_lto
->writes_errno
= true;
4718 remove_useless_summaries (node
, &cur_summary
,
4721 if (!cur_summary
&& !cur_summary_lto
)
4723 if (dump_file
&& changed
)
4726 cur_summary
->dump (dump_file
);
4727 if (cur_summary_lto
)
4728 cur_summary_lto
->dump (dump_file
);
4729 dump_modref_edge_summaries (dump_file
, node
, 4);
4738 "Propagation finished in %i iterations\n", iteration
);
4739 bool pureconst
= false;
4740 for (struct cgraph_node
*cur
= component_node
; cur
;
4741 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4742 if (!cur
->inlined_to
&& opt_for_fn (cur
->decl
, flag_ipa_pure_const
))
4744 modref_summary
*summary
= optimization_summaries
4745 ? optimization_summaries
->get (cur
)
4747 modref_summary_lto
*summary_lto
= summaries_lto
4748 ? summaries_lto
->get (cur
)
4750 if (summary
&& !summary
->stores
->every_base
&& !summary
->stores
->bases
4751 && !summary
->nondeterministic
)
4753 if (!summary
->loads
->every_base
&& !summary
->loads
->bases
4754 && !summary
->calls_interposable
)
4755 pureconst
|= ipa_make_function_const
4756 (cur
, summary
->side_effects
, false);
4758 pureconst
|= ipa_make_function_pure
4759 (cur
, summary
->side_effects
, false);
4761 if (summary_lto
&& !summary_lto
->stores
->every_base
4762 && !summary_lto
->stores
->bases
&& !summary_lto
->nondeterministic
)
4764 if (!summary_lto
->loads
->every_base
&& !summary_lto
->loads
->bases
4765 && !summary_lto
->calls_interposable
)
4766 pureconst
|= ipa_make_function_const
4767 (cur
, summary_lto
->side_effects
, false);
4769 pureconst
|= ipa_make_function_pure
4770 (cur
, summary_lto
->side_effects
, false);
4776 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
4779 modref_propagate_dump_scc (cgraph_node
*component_node
)
4781 for (struct cgraph_node
*cur
= component_node
; cur
;
4782 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4783 if (!cur
->inlined_to
)
4785 modref_summary
*cur_summary
= optimization_summaries
4786 ? optimization_summaries
->get (cur
)
4788 modref_summary_lto
*cur_summary_lto
= summaries_lto
4789 ? summaries_lto
->get (cur
)
4792 fprintf (dump_file
, "Propagated modref for %s%s%s\n",
4794 TREE_READONLY (cur
->decl
) ? " (const)" : "",
4795 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
4796 if (optimization_summaries
)
4799 cur_summary
->dump (dump_file
);
4801 fprintf (dump_file
, " Not tracked\n");
4805 if (cur_summary_lto
)
4806 cur_summary_lto
->dump (dump_file
);
4808 fprintf (dump_file
, " Not tracked (lto)\n");
4813 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
4814 and SUMMARY_LTO to CUR_SUMMARY_LTO.
4815 Return true if something changed. */
4818 modref_merge_call_site_flags (escape_summary
*sum
,
4819 modref_summary
*cur_summary
,
4820 modref_summary_lto
*cur_summary_lto
,
4821 modref_summary
*summary
,
4822 modref_summary_lto
*summary_lto
,
4825 int caller_ecf_flags
,
4826 int callee_ecf_flags
,
4827 bool binds_to_current_def
)
4831 bool changed
= false;
4832 bool ignore_stores
= ignore_stores_p (caller
, callee_ecf_flags
);
4834 /* If we have no useful info to propagate. */
4835 if ((!cur_summary
|| !cur_summary
->arg_flags
.length ())
4836 && (!cur_summary_lto
|| !cur_summary_lto
->arg_flags
.length ()))
4839 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
4843 /* Returning the value is already accounted to at local propagation. */
4844 int implicit_flags
= EAF_NOT_RETURNED_DIRECTLY
4845 | EAF_NOT_RETURNED_INDIRECTLY
;
4847 if (summary
&& ee
->arg
< summary
->arg_flags
.length ())
4848 flags
= summary
->arg_flags
[ee
->arg
];
4850 && ee
->arg
< summary_lto
->arg_flags
.length ())
4851 flags_lto
= summary_lto
->arg_flags
[ee
->arg
];
4854 flags
= deref_flags (flags
, ignore_stores
);
4855 flags_lto
= deref_flags (flags_lto
, ignore_stores
);
4858 implicit_flags
|= ignore_stores_eaf_flags
;
4859 if (callee_ecf_flags
& ECF_PURE
)
4860 implicit_flags
|= implicit_pure_eaf_flags
;
4861 if (callee_ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
4862 implicit_flags
|= implicit_const_eaf_flags
;
4863 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
4866 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
4867 implicit_flags
|= fnspec
.arg_eaf_flags (ee
->arg
);
4870 implicit_flags
= deref_flags (implicit_flags
, ignore_stores
);
4871 flags
|= implicit_flags
;
4872 flags_lto
|= implicit_flags
;
4873 if (!binds_to_current_def
&& (flags
|| flags_lto
))
4875 flags
= interposable_eaf_flags (flags
, implicit_flags
);
4876 flags_lto
= interposable_eaf_flags (flags_lto
, implicit_flags
);
4878 if (!(flags
& EAF_UNUSED
)
4879 && cur_summary
&& ee
->parm_index
< (int)cur_summary
->arg_flags
.length ())
4881 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
4882 ? cur_summary
->retslot_flags
4883 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
4884 ? cur_summary
->static_chain_flags
4885 : cur_summary
->arg_flags
[ee
->parm_index
];
4886 if ((f
& flags
) != f
)
4888 f
= remove_useless_eaf_flags
4889 (f
& flags
, caller_ecf_flags
,
4890 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
4894 if (!(flags_lto
& EAF_UNUSED
)
4896 && ee
->parm_index
< (int)cur_summary_lto
->arg_flags
.length ())
4898 eaf_flags_t
&f
= ee
->parm_index
== MODREF_RETSLOT_PARM
4899 ? cur_summary_lto
->retslot_flags
4900 : ee
->parm_index
== MODREF_STATIC_CHAIN_PARM
4901 ? cur_summary_lto
->static_chain_flags
4902 : cur_summary_lto
->arg_flags
[ee
->parm_index
];
4903 if ((f
& flags_lto
) != f
)
4905 f
= remove_useless_eaf_flags
4906 (f
& flags_lto
, caller_ecf_flags
,
4907 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
4915 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
4916 and propagate arg flags. */
4919 modref_propagate_flags_in_scc (cgraph_node
*component_node
)
4921 bool changed
= true;
4927 for (struct cgraph_node
*cur
= component_node
; cur
;
4928 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
4930 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
4931 modref_summary
*cur_summary
= optimization_summaries
4932 ? optimization_summaries
->get (node
)
4934 modref_summary_lto
*cur_summary_lto
= summaries_lto
4935 ? summaries_lto
->get (node
)
4938 if (!cur_summary
&& !cur_summary_lto
)
4940 int caller_ecf_flags
= flags_from_decl_or_type (cur
->decl
);
4943 fprintf (dump_file
, " Processing %s%s%s\n",
4945 TREE_READONLY (cur
->decl
) ? " (const)" : "",
4946 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
4948 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
4950 escape_summary
*sum
= escape_summaries
->get (e
);
4952 if (!sum
|| (e
->indirect_info
->ecf_flags
4953 & (ECF_CONST
| ECF_NOVOPS
)))
4956 changed
|= modref_merge_call_site_flags
4957 (sum
, cur_summary
, cur_summary_lto
,
4962 e
->indirect_info
->ecf_flags
,
4966 if (!cur_summary
&& !cur_summary_lto
)
4969 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
4970 callee_edge
= callee_edge
->next_callee
)
4972 int ecf_flags
= flags_from_decl_or_type
4973 (callee_edge
->callee
->decl
);
4974 modref_summary
*callee_summary
= NULL
;
4975 modref_summary_lto
*callee_summary_lto
= NULL
;
4976 struct cgraph_node
*callee
;
4978 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)
4979 || !callee_edge
->inline_failed
)
4981 /* Get the callee and its summary. */
4982 enum availability avail
;
4983 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
4986 /* It is not necessary to re-process calls outside of the
4990 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
4991 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
4994 escape_summary
*sum
= escape_summaries
->get (callee_edge
);
4999 fprintf (dump_file
, " Call to %s\n",
5000 callee_edge
->callee
->dump_name ());
5002 if (avail
<= AVAIL_INTERPOSABLE
5003 || callee_edge
->call_stmt_cannot_inline_p
)
5008 callee_summary
= optimization_summaries
->get (callee
);
5009 if (cur_summary_lto
)
5010 callee_summary_lto
= summaries_lto
->get (callee
);
5012 changed
|= modref_merge_call_site_flags
5013 (sum
, cur_summary
, cur_summary_lto
,
5014 callee_summary
, callee_summary_lto
,
5019 callee
->binds_to_current_def_p ());
5020 if (dump_file
&& changed
)
5023 cur_summary
->dump (dump_file
);
5024 if (cur_summary_lto
)
5025 cur_summary_lto
->dump (dump_file
);
5033 "Propagation of flags finished in %i iterations\n", iteration
);
5036 } /* ANON namespace. */
5038 /* Call EDGE was inlined; merge summary from callee to the caller. */
5041 ipa_merge_modref_summary_after_inlining (cgraph_edge
*edge
)
5043 if (!summaries
&& !summaries_lto
)
5046 struct cgraph_node
*to
= (edge
->caller
->inlined_to
5047 ? edge
->caller
->inlined_to
: edge
->caller
);
5048 class modref_summary
*to_info
= summaries
? summaries
->get (to
) : NULL
;
5049 class modref_summary_lto
*to_info_lto
= summaries_lto
5050 ? summaries_lto
->get (to
) : NULL
;
5052 if (!to_info
&& !to_info_lto
)
5055 summaries
->remove (edge
->callee
);
5057 summaries_lto
->remove (edge
->callee
);
5058 remove_modref_edge_summaries (edge
->callee
);
5062 class modref_summary
*callee_info
= summaries
? summaries
->get (edge
->callee
)
5064 class modref_summary_lto
*callee_info_lto
5065 = summaries_lto
? summaries_lto
->get (edge
->callee
) : NULL
;
5066 int flags
= flags_from_decl_or_type (edge
->callee
->decl
);
5067 bool ignore_stores
= ignore_stores_p (edge
->caller
->decl
, flags
);
5069 if (!callee_info
&& to_info
)
5071 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5072 to_info
->loads
->collapse ();
5074 to_info
->stores
->collapse ();
5076 if (!callee_info_lto
&& to_info_lto
)
5078 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5079 to_info_lto
->loads
->collapse ();
5081 to_info_lto
->stores
->collapse ();
5083 if (callee_info
|| callee_info_lto
)
5085 auto_vec
<modref_parm_map
, 32> parm_map
;
5086 modref_parm_map chain_map
;
5087 /* TODO: Once we get jump functions for static chains we could
5088 compute parm_index. */
5090 compute_parm_map (edge
, &parm_map
);
5094 if (to_info
&& callee_info
)
5095 to_info
->stores
->merge (to
->decl
, callee_info
->stores
, &parm_map
,
5097 if (to_info_lto
&& callee_info_lto
)
5098 to_info_lto
->stores
->merge (to
->decl
, callee_info_lto
->stores
,
5099 &parm_map
, &chain_map
, false);
5101 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5103 if (to_info
&& callee_info
)
5104 to_info
->loads
->merge (to
->decl
, callee_info
->loads
, &parm_map
,
5106 if (to_info_lto
&& callee_info_lto
)
5107 to_info_lto
->loads
->merge (to
->decl
, callee_info_lto
->loads
,
5108 &parm_map
, &chain_map
, false);
5112 /* Now merge escape summaries.
5113 For every escape to the callee we need to merge calle flags
5114 and remap calees escapes. */
5115 class escape_summary
*sum
= escape_summaries
->get (edge
);
5116 int max_escape
= -1;
5120 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5121 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
5122 if ((int)ee
->arg
> max_escape
)
5123 max_escape
= ee
->arg
;
5125 auto_vec
<vec
<struct escape_map
>, 32> emap (max_escape
+ 1);
5126 emap
.safe_grow (max_escape
+ 1, true);
5127 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
5130 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
5131 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
5133 bool needed
= false;
5134 /* TODO: We do not have jump functions for return slots, so we
5135 never propagate them to outer function. */
5136 if (ee
->parm_index
< 0)
5138 if (to_info
&& (int)to_info
->arg_flags
.length () > ee
->parm_index
)
5140 int flags
= callee_info
5141 && callee_info
->arg_flags
.length () > ee
->arg
5142 ? callee_info
->arg_flags
[ee
->arg
] : 0;
5144 flags
= deref_flags (flags
, ignore_stores
);
5145 else if (ignore_stores
)
5146 flags
|= ignore_stores_eaf_flags
;
5147 flags
|= ee
->min_flags
;
5148 to_info
->arg_flags
[ee
->parm_index
] &= flags
;
5149 if (to_info
->arg_flags
[ee
->parm_index
])
5153 && (int)to_info_lto
->arg_flags
.length () > ee
->parm_index
)
5155 int flags
= callee_info_lto
5156 && callee_info_lto
->arg_flags
.length () > ee
->arg
5157 ? callee_info_lto
->arg_flags
[ee
->arg
] : 0;
5159 flags
= deref_flags (flags
, ignore_stores
);
5160 else if (ignore_stores
)
5161 flags
|= ignore_stores_eaf_flags
;
5162 flags
|= ee
->min_flags
;
5163 to_info_lto
->arg_flags
[ee
->parm_index
] &= flags
;
5164 if (to_info_lto
->arg_flags
[ee
->parm_index
])
5167 struct escape_map entry
= {ee
->parm_index
, ee
->direct
};
5169 emap
[ee
->arg
].safe_push (entry
);
5171 update_escape_summary (edge
->callee
, emap
, ignore_stores
);
5172 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
5175 escape_summaries
->remove (edge
);
5179 if (to_info
&& !to_info
->useful_p (flags
))
5182 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
5184 summaries
->remove (to
);
5187 else if (to_info
&& dump_file
)
5190 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
5192 to_info
->dump (dump_file
);
5195 summaries
->remove (edge
->callee
);
5199 if (to_info_lto
&& !to_info_lto
->useful_p (flags
))
5202 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
5204 summaries_lto
->remove (to
);
5207 else if (to_info_lto
&& dump_file
)
5210 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
5212 to_info_lto
->dump (dump_file
);
5214 if (callee_info_lto
)
5215 summaries_lto
->remove (edge
->callee
);
5217 if (!to_info
&& !to_info_lto
)
5218 remove_modref_edge_summaries (to
);
5222 /* Run the IPA pass. This will take a function's summaries and calls and
5223 construct new summaries which represent a transitive closure. So that
5224 summary of an analyzed function contains information about the loads and
5225 stores that the function or any function that it calls does. */
5228 pass_ipa_modref::execute (function
*)
5230 if (!summaries
&& !summaries_lto
)
5232 bool pureconst
= false;
5234 if (optimization_summaries
)
5235 ggc_delete (optimization_summaries
);
5236 optimization_summaries
= summaries
;
5239 struct cgraph_node
**order
= XCNEWVEC (struct cgraph_node
*,
5240 symtab
->cgraph_count
);
5242 order_pos
= ipa_reduced_postorder (order
, true, ignore_edge
);
5245 /* Iterate over all strongly connected components in post-order. */
5246 for (i
= 0; i
< order_pos
; i
++)
5248 /* Get the component's representative. That's just any node in the
5249 component from which we can traverse the entire component. */
5250 struct cgraph_node
*component_node
= order
[i
];
5253 fprintf (dump_file
, "\n\nStart of SCC component\n");
5255 pureconst
|= modref_propagate_in_scc (component_node
);
5256 modref_propagate_flags_in_scc (component_node
);
5257 if (optimization_summaries
)
5258 for (struct cgraph_node
*cur
= component_node
; cur
;
5259 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
5260 if (modref_summary
*sum
= optimization_summaries
->get (cur
))
5261 sum
->finalize (cur
->decl
);
5263 modref_propagate_dump_scc (component_node
);
5266 FOR_EACH_FUNCTION (node
)
5267 update_signature (node
);
5269 ((modref_summaries_lto
*)summaries_lto
)->propagated
= true;
5270 ipa_free_postorder_info ();
5272 delete fnspec_summaries
;
5273 fnspec_summaries
= NULL
;
5274 delete escape_summaries
;
5275 escape_summaries
= NULL
;
5277 /* If we posibly made constructors const/pure we may need to remove
5279 return pureconst
? TODO_remove_functions
: 0;
5282 /* Summaries must stay alive until end of compilation. */
5285 ipa_modref_c_finalize ()
5287 if (optimization_summaries
)
5288 ggc_delete (optimization_summaries
);
5289 optimization_summaries
= NULL
;
5291 ggc_delete (summaries_lto
);
5292 summaries_lto
= NULL
;
5293 if (fnspec_summaries
)
5294 delete fnspec_summaries
;
5295 fnspec_summaries
= NULL
;
5296 if (escape_summaries
)
5297 delete escape_summaries
;
5298 escape_summaries
= NULL
;
5301 #include "gt-ipa-modref.h"