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"
94 /* We record fnspec specifiers for call edges since they depends on actual
113 /* Summary holding fnspec string for a given call. */
115 class fnspec_summaries_t
: public call_summary
<fnspec_summary
*>
118 fnspec_summaries_t (symbol_table
*symtab
)
119 : call_summary
<fnspec_summary
*> (symtab
) {}
120 /* Hook that is called by summary when an edge is duplicated. */
121 virtual void duplicate (cgraph_edge
*,
126 dst
->fnspec
= xstrdup (src
->fnspec
);
130 static fnspec_summaries_t
*fnspec_summaries
= NULL
;
132 /* Escape summary holds a vector of param indexes that escape to
136 /* Parameter that escapes at a given call. */
138 /* Argument it escapes to. */
140 /* Minimal flags known about the argument. */
141 eaf_flags_t min_flags
;
142 /* Does it escape directly or indirectly? */
146 /* Dump EAF flags. */
149 dump_eaf_flags (FILE *out
, int flags
, bool newline
= true)
151 if (flags
& EAF_DIRECT
)
152 fprintf (out
, " direct");
153 if (flags
& EAF_NOCLOBBER
)
154 fprintf (out
, " noclobber");
155 if (flags
& EAF_NOESCAPE
)
156 fprintf (out
, " noescape");
157 if (flags
& EAF_NODIRECTESCAPE
)
158 fprintf (out
, " nodirectescape");
159 if (flags
& EAF_UNUSED
)
160 fprintf (out
, " unused");
161 if (flags
& EAF_NOT_RETURNED
)
162 fprintf (out
, " not_returned");
163 if (flags
& EAF_NOT_RETURNED_DIRECTLY
)
164 fprintf (out
, " not_returned_directly");
165 if (flags
& EAF_NOREAD
)
166 fprintf (out
, " noread");
171 struct escape_summary
173 auto_vec
<escape_entry
> esc
;
174 void dump (FILE *out
)
176 for (unsigned int i
= 0; i
< esc
.length (); i
++)
178 fprintf (out
, " parm %i arg %i %s min:",
181 esc
[i
].direct
? "(direct)" : "(indirect)");
182 dump_eaf_flags (out
, esc
[i
].min_flags
, false);
188 class escape_summaries_t
: public call_summary
<escape_summary
*>
191 escape_summaries_t (symbol_table
*symtab
)
192 : call_summary
<escape_summary
*> (symtab
) {}
193 /* Hook that is called by summary when an edge is duplicated. */
194 virtual void duplicate (cgraph_edge
*,
199 dst
->esc
= src
->esc
.copy ();
203 static escape_summaries_t
*escape_summaries
= NULL
;
205 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
208 /* Class (from which there is one global instance) that holds modref summaries
209 for all analyzed functions. */
211 class GTY((user
)) modref_summaries
212 : public fast_function_summary
<modref_summary
*, va_gc
>
215 modref_summaries (symbol_table
*symtab
)
216 : fast_function_summary
<modref_summary
*, va_gc
> (symtab
) {}
217 virtual void insert (cgraph_node
*, modref_summary
*state
);
218 virtual void duplicate (cgraph_node
*src_node
,
219 cgraph_node
*dst_node
,
220 modref_summary
*src_data
,
221 modref_summary
*dst_data
);
222 static modref_summaries
*create_ggc (symbol_table
*symtab
)
224 return new (ggc_alloc_no_dtor
<modref_summaries
> ())
225 modref_summaries (symtab
);
229 class modref_summary_lto
;
231 /* Class (from which there is one global instance) that holds modref summaries
232 for all analyzed functions. */
234 class GTY((user
)) modref_summaries_lto
235 : public fast_function_summary
<modref_summary_lto
*, va_gc
>
238 modref_summaries_lto (symbol_table
*symtab
)
239 : fast_function_summary
<modref_summary_lto
*, va_gc
> (symtab
),
240 propagated (false) {}
241 virtual void insert (cgraph_node
*, modref_summary_lto
*state
);
242 virtual void duplicate (cgraph_node
*src_node
,
243 cgraph_node
*dst_node
,
244 modref_summary_lto
*src_data
,
245 modref_summary_lto
*dst_data
);
246 static modref_summaries_lto
*create_ggc (symbol_table
*symtab
)
248 return new (ggc_alloc_no_dtor
<modref_summaries_lto
> ())
249 modref_summaries_lto (symtab
);
254 /* Global variable holding all modref summaries
255 (from analysis to IPA propagation time). */
257 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
260 /* Global variable holding all modref optimization summaries
261 (from IPA propagation time or used by local optimization pass). */
263 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
264 *optimization_summaries
;
266 /* LTO summaries hold info from analysis to LTO streaming or from LTO
267 stream-in through propagation to LTO stream-out. */
269 static GTY(()) fast_function_summary
<modref_summary_lto
*, va_gc
>
272 /* Summary for a single function which this pass produces. */
274 modref_summary::modref_summary ()
275 : loads (NULL
), stores (NULL
), retslot_flags (0), static_chain_flags (0),
280 modref_summary::~modref_summary ()
288 /* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
289 useful to track. If returns_void is true moreover clear
292 remove_useless_eaf_flags (int eaf_flags
, int ecf_flags
, bool returns_void
)
294 if (ecf_flags
& ECF_NOVOPS
)
296 if (ecf_flags
& ECF_CONST
)
297 eaf_flags
&= ~implicit_const_eaf_flags
;
298 else if (ecf_flags
& ECF_PURE
)
299 eaf_flags
&= ~implicit_pure_eaf_flags
;
300 else if ((ecf_flags
& ECF_NORETURN
) || returns_void
)
301 eaf_flags
&= ~(EAF_NOT_RETURNED
| EAF_NOT_RETURNED_DIRECTLY
);
305 /* Return true if FLAGS holds some useful information. */
308 eaf_flags_useful_p (vec
<eaf_flags_t
> &flags
, int ecf_flags
)
310 for (unsigned i
= 0; i
< flags
.length (); i
++)
311 if (remove_useless_eaf_flags (flags
[i
], ecf_flags
, false))
316 /* Return true if summary is potentially useful for optimization.
317 If CHECK_FLAGS is false assume that arg_flags are useful. */
320 modref_summary::useful_p (int ecf_flags
, bool check_flags
)
322 if (ecf_flags
& ECF_NOVOPS
)
324 if (arg_flags
.length () && !check_flags
)
326 if (check_flags
&& eaf_flags_useful_p (arg_flags
, ecf_flags
))
328 arg_flags
.release ();
329 if (check_flags
&& remove_useless_eaf_flags (retslot_flags
, ecf_flags
, false))
332 && remove_useless_eaf_flags (static_chain_flags
, ecf_flags
, false))
334 if (ecf_flags
& ECF_CONST
)
336 if (loads
&& !loads
->every_base
)
338 if (ecf_flags
& ECF_PURE
)
340 return stores
&& !stores
->every_base
;
343 /* Return true if global memory is read
344 (that is loads summary contains global memory access). */
346 modref_summary::global_memory_read_p ()
350 return loads
->global_access_p ();
353 /* Return true if global memory is written. */
355 modref_summary::global_memory_written_p ()
359 return stores
->global_access_p ();
363 /* Single function summary used for LTO. */
365 typedef modref_tree
<tree
> modref_records_lto
;
366 struct GTY(()) modref_summary_lto
368 /* Load and stores in functions using types rather then alias sets.
370 This is necessary to make the information streamable for LTO but is also
371 more verbose and thus more likely to hit the limits. */
372 modref_records_lto
*loads
;
373 modref_records_lto
*stores
;
374 auto_vec
<eaf_flags_t
> GTY((skip
)) arg_flags
;
375 eaf_flags_t retslot_flags
;
376 eaf_flags_t static_chain_flags
;
379 modref_summary_lto ();
380 ~modref_summary_lto ();
382 bool useful_p (int ecf_flags
, bool check_flags
= true);
385 /* Summary for a single function which this pass produces. */
387 modref_summary_lto::modref_summary_lto ()
388 : loads (NULL
), stores (NULL
), retslot_flags (0), static_chain_flags (0),
393 modref_summary_lto::~modref_summary_lto ()
402 /* Return true if lto summary is potentially useful for optimization.
403 If CHECK_FLAGS is false assume that arg_flags are useful. */
406 modref_summary_lto::useful_p (int ecf_flags
, bool check_flags
)
408 if (ecf_flags
& ECF_NOVOPS
)
410 if (arg_flags
.length () && !check_flags
)
412 if (check_flags
&& eaf_flags_useful_p (arg_flags
, ecf_flags
))
414 arg_flags
.release ();
415 if (check_flags
&& remove_useless_eaf_flags (retslot_flags
, ecf_flags
, false))
418 && remove_useless_eaf_flags (static_chain_flags
, ecf_flags
, false))
420 if (ecf_flags
& ECF_CONST
)
422 if (loads
&& !loads
->every_base
)
424 if (ecf_flags
& ECF_PURE
)
426 return stores
&& !stores
->every_base
;
432 dump_access (modref_access_node
*a
, FILE *out
)
434 fprintf (out
, " access:");
435 if (a
->parm_index
!= -1)
437 fprintf (out
, " Parm %i", a
->parm_index
);
438 if (a
->parm_offset_known
)
440 fprintf (out
, " param offset:");
441 print_dec ((poly_int64_pod
)a
->parm_offset
, out
, SIGNED
);
444 if (a
->range_info_useful_p ())
446 fprintf (out
, " offset:");
447 print_dec ((poly_int64_pod
)a
->offset
, out
, SIGNED
);
448 fprintf (out
, " size:");
449 print_dec ((poly_int64_pod
)a
->size
, out
, SIGNED
);
450 fprintf (out
, " max_size:");
451 print_dec ((poly_int64_pod
)a
->max_size
, out
, SIGNED
);
453 fprintf (out
, " adjusted %i times", a
->adjustments
);
458 /* Dump records TT to OUT. */
461 dump_records (modref_records
*tt
, FILE *out
)
463 fprintf (out
, " Limits: %i bases, %i refs\n",
464 (int)tt
->max_bases
, (int)tt
->max_refs
);
467 fprintf (out
, " Every base\n");
471 modref_base_node
<alias_set_type
> *n
;
472 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
474 fprintf (out
, " Base %i: alias set %i\n", (int)i
, n
->base
);
477 fprintf (out
, " Every ref\n");
481 modref_ref_node
<alias_set_type
> *r
;
482 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
484 fprintf (out
, " Ref %i: alias set %i\n", (int)j
, r
->ref
);
487 fprintf (out
, " Every access\n");
491 modref_access_node
*a
;
492 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
493 dump_access (a
, out
);
498 /* Dump records TT to OUT. */
501 dump_lto_records (modref_records_lto
*tt
, FILE *out
)
503 fprintf (out
, " Limits: %i bases, %i refs\n",
504 (int)tt
->max_bases
, (int)tt
->max_refs
);
507 fprintf (out
, " Every base\n");
511 modref_base_node
<tree
> *n
;
512 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
514 fprintf (out
, " Base %i:", (int)i
);
515 print_generic_expr (dump_file
, n
->base
);
516 fprintf (out
, " (alias set %i)\n",
517 n
->base
? get_alias_set (n
->base
) : 0);
520 fprintf (out
, " Every ref\n");
524 modref_ref_node
<tree
> *r
;
525 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
527 fprintf (out
, " Ref %i:", (int)j
);
528 print_generic_expr (dump_file
, r
->ref
);
529 fprintf (out
, " (alias set %i)\n",
530 r
->ref
? get_alias_set (r
->ref
) : 0);
533 fprintf (out
, " Every access\n");
537 modref_access_node
*a
;
538 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
539 dump_access (a
, out
);
544 /* Dump all escape points of NODE to OUT. */
547 dump_modref_edge_summaries (FILE *out
, cgraph_node
*node
, int depth
)
550 if (!escape_summaries
)
552 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
554 class escape_summary
*sum
= escape_summaries
->get (e
);
557 fprintf (out
, "%*sIndirect call %i in %s escapes:",
558 depth
, "", i
, node
->dump_name ());
563 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
565 if (!e
->inline_failed
)
566 dump_modref_edge_summaries (out
, e
->callee
, depth
+ 1);
567 class escape_summary
*sum
= escape_summaries
->get (e
);
570 fprintf (out
, "%*sCall %s->%s escapes:", depth
, "",
571 node
->dump_name (), e
->callee
->dump_name ());
574 class fnspec_summary
*fsum
= fnspec_summaries
->get (e
);
577 fprintf (out
, "%*sCall %s->%s fnspec: %s\n", depth
, "",
578 node
->dump_name (), e
->callee
->dump_name (),
584 /* Remove all call edge summaries associated with NODE. */
587 remove_modref_edge_summaries (cgraph_node
*node
)
589 if (!escape_summaries
)
591 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
592 escape_summaries
->remove (e
);
593 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
595 if (!e
->inline_failed
)
596 remove_modref_edge_summaries (e
->callee
);
597 escape_summaries
->remove (e
);
598 fnspec_summaries
->remove (e
);
605 modref_summary::dump (FILE *out
)
609 fprintf (out
, " loads:\n");
610 dump_records (loads
, out
);
614 fprintf (out
, " stores:\n");
615 dump_records (stores
, out
);
618 fprintf (out
, " Writes errno\n");
619 if (arg_flags
.length ())
621 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
624 fprintf (out
, " parm %i flags:", i
);
625 dump_eaf_flags (out
, arg_flags
[i
]);
630 fprintf (out
, " Retslot flags:");
631 dump_eaf_flags (out
, retslot_flags
);
633 if (static_chain_flags
)
635 fprintf (out
, " Static chain flags:");
636 dump_eaf_flags (out
, static_chain_flags
);
643 modref_summary_lto::dump (FILE *out
)
645 fprintf (out
, " loads:\n");
646 dump_lto_records (loads
, out
);
647 fprintf (out
, " stores:\n");
648 dump_lto_records (stores
, out
);
650 fprintf (out
, " Writes errno\n");
651 if (arg_flags
.length ())
653 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
656 fprintf (out
, " parm %i flags:", i
);
657 dump_eaf_flags (out
, arg_flags
[i
]);
662 fprintf (out
, " Retslot flags:");
663 dump_eaf_flags (out
, retslot_flags
);
665 if (static_chain_flags
)
667 fprintf (out
, " Static chain flags:");
668 dump_eaf_flags (out
, static_chain_flags
);
672 /* Get function summary for FUNC if it exists, return NULL otherwise. */
675 get_modref_function_summary (cgraph_node
*func
)
677 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
678 if (!optimization_summaries
)
681 /* A single function body may be represented by multiple symbols with
682 different visibility. For example, if FUNC is an interposable alias,
683 we don't want to return anything, even if we have summary for the target
685 enum availability avail
;
686 func
= func
->function_or_virtual_thunk_symbol
687 (&avail
, current_function_decl
?
688 cgraph_node::get (current_function_decl
) : NULL
);
689 if (avail
<= AVAIL_INTERPOSABLE
)
692 modref_summary
*r
= optimization_summaries
->get (func
);
698 /* Construct modref_access_node from REF. */
699 static modref_access_node
700 get_access (ao_ref
*ref
)
704 base
= ao_ref_base (ref
);
705 modref_access_node a
= {ref
->offset
, ref
->size
, ref
->max_size
,
707 if (TREE_CODE (base
) == MEM_REF
|| TREE_CODE (base
) == TARGET_MEM_REF
)
710 base
= TREE_OPERAND (base
, 0);
711 if (TREE_CODE (base
) == SSA_NAME
712 && SSA_NAME_IS_DEFAULT_DEF (base
)
713 && TREE_CODE (SSA_NAME_VAR (base
)) == PARM_DECL
)
716 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
717 t
!= SSA_NAME_VAR (base
); t
= DECL_CHAIN (t
))
726 if (TREE_CODE (memref
) == MEM_REF
)
729 = wi::to_poly_wide (TREE_OPERAND
730 (memref
, 1)).to_shwi (&a
.parm_offset
);
733 a
.parm_offset_known
= false;
743 /* Record access into the modref_records data structure. */
746 record_access (modref_records
*tt
, ao_ref
*ref
)
748 alias_set_type base_set
= !flag_strict_aliasing
? 0
749 : ao_ref_base_alias_set (ref
);
750 alias_set_type ref_set
= !flag_strict_aliasing
? 0
751 : (ao_ref_alias_set (ref
));
752 modref_access_node a
= get_access (ref
);
755 fprintf (dump_file
, " - Recording base_set=%i ref_set=%i parm=%i\n",
756 base_set
, ref_set
, a
.parm_index
);
758 tt
->insert (base_set
, ref_set
, a
, false);
761 /* IPA version of record_access_tree. */
764 record_access_lto (modref_records_lto
*tt
, ao_ref
*ref
)
766 /* get_alias_set sometimes use different type to compute the alias set
767 than TREE_TYPE (base). Do same adjustments. */
768 tree base_type
= NULL_TREE
, ref_type
= NULL_TREE
;
769 if (flag_strict_aliasing
)
774 while (handled_component_p (base
))
775 base
= TREE_OPERAND (base
, 0);
777 base_type
= reference_alias_ptr_type_1 (&base
);
780 base_type
= TREE_TYPE (base
);
782 base_type
= TYPE_REF_CAN_ALIAS_ALL (base_type
)
783 ? NULL_TREE
: TREE_TYPE (base_type
);
785 tree ref_expr
= ref
->ref
;
786 ref_type
= reference_alias_ptr_type_1 (&ref_expr
);
789 ref_type
= TREE_TYPE (ref_expr
);
791 ref_type
= TYPE_REF_CAN_ALIAS_ALL (ref_type
)
792 ? NULL_TREE
: TREE_TYPE (ref_type
);
794 /* Sanity check that we are in sync with what get_alias_set does. */
795 gcc_checking_assert ((!base_type
&& !ao_ref_base_alias_set (ref
))
796 || get_alias_set (base_type
)
797 == ao_ref_base_alias_set (ref
));
798 gcc_checking_assert ((!ref_type
&& !ao_ref_alias_set (ref
))
799 || get_alias_set (ref_type
)
800 == ao_ref_alias_set (ref
));
802 /* Do not bother to record types that have no meaningful alias set.
803 Also skip variably modified types since these go to local streams. */
804 if (base_type
&& (!get_alias_set (base_type
)
805 || variably_modified_type_p (base_type
, NULL_TREE
)))
806 base_type
= NULL_TREE
;
807 if (ref_type
&& (!get_alias_set (ref_type
)
808 || variably_modified_type_p (ref_type
, NULL_TREE
)))
809 ref_type
= NULL_TREE
;
811 modref_access_node a
= get_access (ref
);
814 fprintf (dump_file
, " - Recording base type:");
815 print_generic_expr (dump_file
, base_type
);
816 fprintf (dump_file
, " (alias set %i) ref type:",
817 base_type
? get_alias_set (base_type
) : 0);
818 print_generic_expr (dump_file
, ref_type
);
819 fprintf (dump_file
, " (alias set %i) parm:%i\n",
820 ref_type
? get_alias_set (ref_type
) : 0,
824 tt
->insert (base_type
, ref_type
, a
, false);
827 /* Returns true if and only if we should store the access to EXPR.
828 Some accesses, e.g. loads from automatic variables, are not interesting. */
831 record_access_p (tree expr
)
833 if (refs_local_or_readonly_memory_p (expr
))
836 fprintf (dump_file
, " - Read-only or local, ignoring.\n");
842 /* Return true if ECF flags says that return value can be ignored. */
845 ignore_retval_p (tree caller
, int flags
)
847 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
848 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
853 /* Return true if ECF flags says that stores can be ignored. */
856 ignore_stores_p (tree caller
, int flags
)
858 if (flags
& (ECF_PURE
| ECF_CONST
| ECF_NOVOPS
))
860 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
861 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
866 /* Determine parm_map for argument I of STMT. */
869 parm_map_for_arg (gimple
*stmt
, int i
)
871 tree op
= gimple_call_arg (stmt
, i
);
874 struct modref_parm_map parm_map
;
876 parm_map
.parm_offset_known
= false;
877 parm_map
.parm_offset
= 0;
879 offset_known
= unadjusted_ptr_and_unit_offset (op
, &op
, &offset
);
880 if (TREE_CODE (op
) == SSA_NAME
881 && SSA_NAME_IS_DEFAULT_DEF (op
)
882 && TREE_CODE (SSA_NAME_VAR (op
)) == PARM_DECL
)
885 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
886 t
!= SSA_NAME_VAR (op
); t
= DECL_CHAIN (t
))
895 parm_map
.parm_index
= index
;
896 parm_map
.parm_offset_known
= offset_known
;
897 parm_map
.parm_offset
= offset
;
899 else if (points_to_local_or_readonly_memory_p (op
))
900 parm_map
.parm_index
= -2;
902 parm_map
.parm_index
= -1;
906 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
907 int CUR_SUMMARY. Return true if something changed.
908 If IGNORE_STORES is true, do not merge stores.
909 If RECORD_ADJUSTMENTS is true cap number of adjustments to
910 a given access to make dataflow finite. */
913 merge_call_side_effects (modref_summary
*cur_summary
,
914 gimple
*stmt
, modref_summary
*callee_summary
,
915 bool ignore_stores
, cgraph_node
*callee_node
,
916 bool record_adjustments
)
918 auto_vec
<modref_parm_map
, 32> parm_map
;
919 bool changed
= false;
921 /* We can not safely optimize based on summary of callee if it does
922 not always bind to current def: it is possible that memory load
923 was optimized out earlier which may not happen in the interposed
925 if (!callee_node
->binds_to_current_def_p ())
928 fprintf (dump_file
, " - May be interposed: collapsing loads.\n");
929 cur_summary
->loads
->collapse ();
933 fprintf (dump_file
, " - Merging side effects of %s with parm map:",
934 callee_node
->dump_name ());
936 parm_map
.safe_grow_cleared (gimple_call_num_args (stmt
), true);
937 for (unsigned i
= 0; i
< gimple_call_num_args (stmt
); i
++)
939 parm_map
[i
] = parm_map_for_arg (stmt
, i
);
942 fprintf (dump_file
, " %i", parm_map
[i
].parm_index
);
943 if (parm_map
[i
].parm_offset_known
)
945 fprintf (dump_file
, " offset:");
946 print_dec ((poly_int64_pod
)parm_map
[i
].parm_offset
,
952 fprintf (dump_file
, "\n");
954 /* Merge with callee's summary. */
955 changed
|= cur_summary
->loads
->merge (callee_summary
->loads
, &parm_map
,
959 changed
|= cur_summary
->stores
->merge (callee_summary
->stores
,
962 if (!cur_summary
->writes_errno
963 && callee_summary
->writes_errno
)
965 cur_summary
->writes_errno
= true;
972 /* Return access mode for argument I of call STMT with FNSPEC. */
974 static modref_access_node
975 get_access_for_fnspec (gcall
*call
, attr_fnspec
&fnspec
,
976 unsigned int i
, modref_parm_map
&map
)
978 tree size
= NULL_TREE
;
979 unsigned int size_arg
;
981 if (!fnspec
.arg_specified_p (i
))
983 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
984 size
= gimple_call_arg (call
, size_arg
);
985 else if (fnspec
.arg_access_size_given_by_type_p (i
))
987 tree callee
= gimple_call_fndecl (call
);
988 tree t
= TYPE_ARG_TYPES (TREE_TYPE (callee
));
990 for (unsigned int p
= 0; p
< i
; p
++)
992 size
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t
)));
994 modref_access_node a
= {0, -1, -1,
995 map
.parm_offset
, map
.parm_index
,
996 map
.parm_offset_known
, 0};
999 && poly_int_tree_p (size
, &size_hwi
)
1000 && coeffs_in_range_p (size_hwi
, 0,
1001 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
1004 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
1009 /* Collapse loads and return true if something changed. */
1012 collapse_loads (modref_summary
*cur_summary
,
1013 modref_summary_lto
*cur_summary_lto
)
1015 bool changed
= false;
1017 if (cur_summary
&& !cur_summary
->loads
->every_base
)
1019 cur_summary
->loads
->collapse ();
1023 && !cur_summary_lto
->loads
->every_base
)
1025 cur_summary_lto
->loads
->collapse ();
1031 /* Collapse loads and return true if something changed. */
1034 collapse_stores (modref_summary
*cur_summary
,
1035 modref_summary_lto
*cur_summary_lto
)
1037 bool changed
= false;
1039 if (cur_summary
&& !cur_summary
->stores
->every_base
)
1041 cur_summary
->stores
->collapse ();
1045 && !cur_summary_lto
->stores
->every_base
)
1047 cur_summary_lto
->stores
->collapse ();
1054 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1055 If IGNORE_STORES is true ignore them.
1056 Return false if no useful summary can be produced. */
1059 process_fnspec (modref_summary
*cur_summary
,
1060 modref_summary_lto
*cur_summary_lto
,
1061 gcall
*call
, bool ignore_stores
)
1063 attr_fnspec fnspec
= gimple_call_fnspec (call
);
1064 if (!fnspec
.known_p ())
1066 if (dump_file
&& gimple_call_builtin_p (call
, BUILT_IN_NORMAL
))
1067 fprintf (dump_file
, " Builtin with no fnspec: %s\n",
1068 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call
))));
1071 collapse_loads (cur_summary
, cur_summary_lto
);
1076 if (fnspec
.global_memory_read_p ())
1077 collapse_loads (cur_summary
, cur_summary_lto
);
1080 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1081 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1083 else if (!fnspec
.arg_specified_p (i
)
1084 || fnspec
.arg_maybe_read_p (i
))
1086 modref_parm_map map
= parm_map_for_arg (call
, i
);
1088 if (map
.parm_index
== -2)
1090 if (map
.parm_index
== -1)
1092 collapse_loads (cur_summary
, cur_summary_lto
);
1096 cur_summary
->loads
->insert (0, 0,
1097 get_access_for_fnspec (call
,
1101 if (cur_summary_lto
)
1102 cur_summary_lto
->loads
->insert (0, 0,
1103 get_access_for_fnspec (call
,
1111 if (fnspec
.global_memory_written_p ())
1112 collapse_stores (cur_summary
, cur_summary_lto
);
1115 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1116 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1118 else if (!fnspec
.arg_specified_p (i
)
1119 || fnspec
.arg_maybe_written_p (i
))
1121 modref_parm_map map
= parm_map_for_arg (call
, i
);
1123 if (map
.parm_index
== -2)
1125 if (map
.parm_index
== -1)
1127 collapse_stores (cur_summary
, cur_summary_lto
);
1131 cur_summary
->stores
->insert (0, 0,
1132 get_access_for_fnspec (call
,
1136 if (cur_summary_lto
)
1137 cur_summary_lto
->stores
->insert (0, 0,
1138 get_access_for_fnspec (call
,
1143 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
1146 cur_summary
->writes_errno
= true;
1147 if (cur_summary_lto
)
1148 cur_summary_lto
->writes_errno
= true;
1154 /* Analyze function call STMT in function F.
1155 Remember recursive calls in RECURSIVE_CALLS. */
1158 analyze_call (modref_summary
*cur_summary
, modref_summary_lto
*cur_summary_lto
,
1159 gcall
*stmt
, vec
<gimple
*> *recursive_calls
)
1161 /* Check flags on the function call. In certain cases, analysis can be
1163 int flags
= gimple_call_flags (stmt
);
1164 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
1168 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1169 "except for args.\n");
1173 /* Pure functions do not affect global memory. Stores by functions which are
1174 noreturn and do not throw can safely be ignored. */
1175 bool ignore_stores
= ignore_stores_p (current_function_decl
, flags
);
1177 /* Next, we try to get the callee's function declaration. The goal is to
1178 merge their summary with ours. */
1179 tree callee
= gimple_call_fndecl (stmt
);
1181 /* Check if this is an indirect call. */
1185 fprintf (dump_file
, gimple_call_internal_p (stmt
)
1186 ? " - Internal call" : " - Indirect call.\n");
1187 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1189 /* We only need to handle internal calls in IPA mode. */
1190 gcc_checking_assert (!cur_summary_lto
);
1192 struct cgraph_node
*callee_node
= cgraph_node::get_create (callee
);
1194 /* If this is a recursive call, the target summary is the same as ours, so
1195 there's nothing to do. */
1196 if (recursive_call_p (current_function_decl
, callee
))
1198 recursive_calls
->safe_push (stmt
);
1200 fprintf (dump_file
, " - Skipping recursive call.\n");
1204 gcc_assert (callee_node
!= NULL
);
1206 /* Get the function symbol and its availability. */
1207 enum availability avail
;
1208 callee_node
= callee_node
->function_symbol (&avail
);
1209 if (avail
<= AVAIL_INTERPOSABLE
)
1212 fprintf (dump_file
, " - Function availability <= AVAIL_INTERPOSABLE.\n");
1213 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1216 /* Get callee's modref summary. As above, if there's no summary, we either
1217 have to give up or, if stores are ignored, we can just purge loads. */
1218 modref_summary
*callee_summary
= optimization_summaries
->get (callee_node
);
1219 if (!callee_summary
)
1222 fprintf (dump_file
, " - No modref summary available for callee.\n");
1223 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1226 merge_call_side_effects (cur_summary
, stmt
, callee_summary
, ignore_stores
,
1227 callee_node
, false);
1232 /* Support analysis in non-lto and lto mode in parallel. */
1236 struct modref_summary
*nolto
;
1237 struct modref_summary_lto
*lto
;
1240 /* Helper for analyze_stmt. */
1243 analyze_load (gimple
*, tree
, tree op
, void *data
)
1245 modref_summary
*summary
= ((summary_ptrs
*)data
)->nolto
;
1246 modref_summary_lto
*summary_lto
= ((summary_ptrs
*)data
)->lto
;
1250 fprintf (dump_file
, " - Analyzing load: ");
1251 print_generic_expr (dump_file
, op
);
1252 fprintf (dump_file
, "\n");
1255 if (!record_access_p (op
))
1259 ao_ref_init (&r
, op
);
1262 record_access (summary
->loads
, &r
);
1264 record_access_lto (summary_lto
->loads
, &r
);
1268 /* Helper for analyze_stmt. */
1271 analyze_store (gimple
*, tree
, tree op
, void *data
)
1273 modref_summary
*summary
= ((summary_ptrs
*)data
)->nolto
;
1274 modref_summary_lto
*summary_lto
= ((summary_ptrs
*)data
)->lto
;
1278 fprintf (dump_file
, " - Analyzing store: ");
1279 print_generic_expr (dump_file
, op
);
1280 fprintf (dump_file
, "\n");
1283 if (!record_access_p (op
))
1287 ao_ref_init (&r
, op
);
1290 record_access (summary
->stores
, &r
);
1292 record_access_lto (summary_lto
->stores
, &r
);
1296 /* Analyze statement STMT of function F.
1297 If IPA is true do not merge in side effects of calls. */
1300 analyze_stmt (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
1301 gimple
*stmt
, bool ipa
, vec
<gimple
*> *recursive_calls
)
1303 /* In general we can not ignore clobbers because they are barriers for code
1304 motion, however after inlining it is safe to do because local optimization
1305 passes do not consider clobbers from other functions.
1306 Similar logic is in ipa-pure-const.c. */
1307 if ((ipa
|| cfun
->after_inlining
) && gimple_clobber_p (stmt
))
1310 struct summary_ptrs sums
= {summary
, summary_lto
};
1312 /* Analyze all loads and stores in STMT. */
1313 walk_stmt_load_store_ops (stmt
, &sums
,
1314 analyze_load
, analyze_store
);
1316 switch (gimple_code (stmt
))
1319 /* If the ASM statement does not read nor write memory, there's nothing
1320 to do. Otherwise just give up. */
1321 if (!gimple_asm_clobbers_memory_p (as_a
<gasm
*> (stmt
)))
1324 fprintf (dump_file
, " - Function contains GIMPLE_ASM statement "
1325 "which clobbers memory.\n");
1328 if (!ipa
|| gimple_call_internal_p (stmt
))
1329 return analyze_call (summary
, summary_lto
,
1330 as_a
<gcall
*> (stmt
), recursive_calls
);
1333 attr_fnspec fnspec
= gimple_call_fnspec (as_a
<gcall
*>(stmt
));
1335 if (fnspec
.known_p ()
1336 && (!fnspec
.global_memory_read_p ()
1337 || !fnspec
.global_memory_written_p ()))
1339 cgraph_edge
*e
= cgraph_node::get (current_function_decl
)->get_edge (stmt
);
1342 fnspec_summaries
->get_create (e
)->fnspec
= xstrdup (fnspec
.get_str ());
1344 fprintf (dump_file
, " Recorded fnspec %s\n", fnspec
.get_str ());
1350 /* Nothing to do for other types of statements. */
1355 /* Remove summary of current function because during the function body
1356 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1360 remove_summary (bool lto
, bool nolto
, bool ipa
)
1362 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1364 optimization_summaries
->remove (fnode
);
1368 summaries
->remove (fnode
);
1370 summaries_lto
->remove (fnode
);
1371 remove_modref_edge_summaries (fnode
);
1375 " - modref done with result: not tracked.\n");
1378 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1381 memory_access_to (tree op
, tree ssa_name
)
1383 tree base
= get_base_address (op
);
1386 if (TREE_CODE (base
) != MEM_REF
&& TREE_CODE (base
) != TARGET_MEM_REF
)
1388 return TREE_OPERAND (base
, 0) == ssa_name
;
1391 /* Consider statement val = *arg.
1392 return EAF flags of ARG that can be determined from EAF flags of VAL
1393 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1394 all stores to VAL, i.e. when handling noreturn function. */
1397 deref_flags (int flags
, bool ignore_stores
)
1399 int ret
= EAF_NODIRECTESCAPE
| EAF_NOT_RETURNED_DIRECTLY
;
1400 /* If argument is unused just account for
1401 the read involved in dereference. */
1402 if (flags
& EAF_UNUSED
)
1403 ret
|= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_NOT_RETURNED
;
1406 if ((flags
& EAF_NOCLOBBER
) || ignore_stores
)
1407 ret
|= EAF_NOCLOBBER
;
1408 if ((flags
& EAF_NOESCAPE
) || ignore_stores
)
1409 ret
|= EAF_NOESCAPE
;
1410 /* If the value dereferenced is not used for another load or store
1411 we can still consider ARG as used only directly.
1422 if ((flags
& (EAF_NOREAD
| EAF_NOT_RETURNED
| EAF_NOESCAPE
| EAF_DIRECT
))
1423 == (EAF_NOREAD
| EAF_NOT_RETURNED
| EAF_NOESCAPE
| EAF_DIRECT
)
1424 && ((flags
& EAF_NOCLOBBER
) || ignore_stores
))
1426 if (flags
& EAF_NOT_RETURNED
)
1427 ret
|= EAF_NOT_RETURNED
;
1433 /* Description of an escape point. */
1437 /* Extra hidden args we keep track of. */
1441 static_chain_arg
= -2
1443 /* Value escapes to this call. */
1445 /* Argument it escapes to. */
1447 /* Flags already known about the argument (this can save us from recording
1448 esape points if local analysis did good job already). */
1449 eaf_flags_t min_flags
;
1450 /* Does value escape directly or indiretly? */
1454 class modref_lattice
1457 /* EAF flags of the SSA name. */
1459 /* DFS bookkkeeping: we don't do real dataflow yet. */
1463 /* When doing IPA analysis we can not merge in callee escape points;
1464 Only remember them and do the merging at IPA propagation time. */
1465 vec
<escape_point
, va_heap
, vl_ptr
> escape_points
;
1469 bool merge (const modref_lattice
&with
);
1470 bool merge (int flags
);
1471 bool merge_deref (const modref_lattice
&with
, bool ignore_stores
);
1472 bool merge_direct_load ();
1473 bool merge_direct_store ();
1474 bool add_escape_point (gcall
*call
, int arg
, int min_flags
, bool diret
);
1475 void dump (FILE *out
, int indent
= 0) const;
1478 /* Lattices are saved to vectors, so keep them PODs. */
1480 modref_lattice::init ()
1482 /* All flags we track. */
1483 int f
= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_UNUSED
1484 | EAF_NODIRECTESCAPE
| EAF_NOT_RETURNED
|
1485 EAF_NOT_RETURNED_DIRECTLY
| EAF_NOREAD
;
1487 /* Check that eaf_flags_t is wide enough to hold all flags. */
1488 gcc_checking_assert (f
== flags
);
1493 /* Release memory. */
1495 modref_lattice::release ()
1497 escape_points
.release ();
1500 /* Dump lattice to OUT; indent with INDENT spaces. */
1503 modref_lattice::dump (FILE *out
, int indent
) const
1505 dump_eaf_flags (out
, flags
);
1506 if (escape_points
.length ())
1508 fprintf (out
, "%*sEscapes:\n", indent
, "");
1509 for (unsigned int i
= 0; i
< escape_points
.length (); i
++)
1511 fprintf (out
, "%*s Arg %i (%s) min flags", indent
, "",
1512 escape_points
[i
].arg
,
1513 escape_points
[i
].direct
? "direct" : "indirect");
1514 dump_eaf_flags (out
, escape_points
[i
].min_flags
, false);
1515 fprintf (out
, " in call ");
1516 print_gimple_stmt (out
, escape_points
[i
].call
, 0);
1521 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1525 modref_lattice::add_escape_point (gcall
*call
, int arg
, int min_flags
,
1531 /* If we already determined flags to be bad enough,
1532 we do not need to record. */
1533 if ((flags
& min_flags
) == flags
|| (min_flags
& EAF_UNUSED
))
1536 FOR_EACH_VEC_ELT (escape_points
, i
, ep
)
1537 if (ep
->call
== call
&& ep
->arg
== arg
&& ep
->direct
== direct
)
1539 if ((ep
->min_flags
& min_flags
) == min_flags
)
1541 ep
->min_flags
&= min_flags
;
1544 /* Give up if max escape points is met. */
1545 if ((int)escape_points
.length () > param_modref_max_escape_points
)
1548 fprintf (dump_file
, "--param modref-max-escape-points limit reached\n");
1552 escape_point new_ep
= {call
, arg
, min_flags
, direct
};
1553 escape_points
.safe_push (new_ep
);
1557 /* Merge in flags from F. */
1559 modref_lattice::merge (int f
)
1563 /* Noescape implies that value also does not escape directly.
1564 Fnspec machinery does set both so compensate for this. */
1565 if (f
& EAF_NOESCAPE
)
1566 f
|= EAF_NODIRECTESCAPE
;
1567 if (f
& EAF_NOT_RETURNED
)
1568 f
|= EAF_NOT_RETURNED_DIRECTLY
;
1569 if ((flags
& f
) != flags
)
1572 /* Prune obvoiusly useless flags;
1573 We do not have ECF_FLAGS handy which is not big problem since
1574 we will do final flags cleanup before producing summary.
1575 Merging should be fast so it can work well with dataflow. */
1576 flags
= remove_useless_eaf_flags (flags
, 0, false);
1578 escape_points
.release ();
1584 /* Merge in WITH. Return true if anyting changed. */
1587 modref_lattice::merge (const modref_lattice
&with
)
1592 bool changed
= merge (with
.flags
);
1596 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
1597 changed
|= add_escape_point (with
.escape_points
[i
].call
,
1598 with
.escape_points
[i
].arg
,
1599 with
.escape_points
[i
].min_flags
,
1600 with
.escape_points
[i
].direct
);
1604 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1605 stores. Return true if anyting changed. */
1608 modref_lattice::merge_deref (const modref_lattice
&with
, bool ignore_stores
)
1613 bool changed
= merge (deref_flags (with
.flags
, ignore_stores
));
1617 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
1619 int min_flags
= with
.escape_points
[i
].min_flags
;
1621 if (with
.escape_points
[i
].direct
)
1622 min_flags
= deref_flags (min_flags
, ignore_stores
);
1623 else if (ignore_stores
)
1624 min_flags
|= ignore_stores_eaf_flags
;
1625 changed
|= add_escape_point (with
.escape_points
[i
].call
,
1626 with
.escape_points
[i
].arg
,
1633 /* Merge in flags for direct load. */
1636 modref_lattice::merge_direct_load ()
1638 return merge (~(EAF_UNUSED
| EAF_NOREAD
));
1641 /* Merge in flags for direct store. */
1644 modref_lattice::merge_direct_store ()
1646 return merge (~(EAF_UNUSED
| EAF_NOCLOBBER
));
1649 /* Analyzer of EAF flags. */
1651 class modref_eaf_analysis
1654 /* Compute flags for NAME. */
1655 void analyze_ssa_name (tree name
);
1656 /* Return flags computed earlier for NAME. */
1657 int get_ssa_name_flags (tree name
)
1659 int version
= SSA_NAME_VERSION (name
);
1660 gcc_checking_assert (m_lattice
[version
].known
);
1661 return m_lattice
[version
].flags
;
1663 /* In IPA mode this will record all escape points
1664 determined for NAME to PARM_IDNEX. Flags are minimal
1666 void record_escape_points (tree name
, int parm_index
, int flags
);
1667 modref_eaf_analysis (bool ipa
)
1671 m_lattice
.safe_grow_cleared (num_ssa_names
, true);
1673 ~modref_eaf_analysis ()
1675 gcc_checking_assert (!m_depth
);
1677 for (unsigned int i
= 0; i
< num_ssa_names
; i
++)
1678 m_lattice
[i
].release ();
1681 /* If true, we produce analysis for IPA mode. In this case escape points ar
1684 /* Depth of recursion of analyze_ssa_name. */
1686 /* Propagation lattice for individual ssa names. */
1687 auto_vec
<modref_lattice
> m_lattice
;
1689 void merge_with_ssa_name (tree dest
, tree src
, bool deref
);
1690 void merge_call_lhs_flags (gcall
*call
, int arg
, tree name
, bool deref
);
1694 /* Call statements may return their parameters. Consider argument number
1695 ARG of USE_STMT and determine flags that can needs to be cleared
1696 in case pointer possibly indirectly references from ARG I is returned.
1697 LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
1698 ARG is set to -1 for static chain. */
1701 modref_eaf_analysis::merge_call_lhs_flags (gcall
*call
, int arg
,
1702 tree name
, bool deref
)
1704 int index
= SSA_NAME_VERSION (name
);
1706 /* If there is no return value, no flags are affected. */
1707 if (!gimple_call_lhs (call
))
1710 /* If we know that function returns given argument and it is not ARG
1711 we can still be happy. */
1714 int flags
= gimple_call_return_flags (call
);
1715 if ((flags
& ERF_RETURNS_ARG
)
1716 && (flags
& ERF_RETURN_ARG_MASK
) != arg
)
1720 /* If return value is SSA name determine its flags. */
1721 if (TREE_CODE (gimple_call_lhs (call
)) == SSA_NAME
)
1723 tree lhs
= gimple_call_lhs (call
);
1724 merge_with_ssa_name (name
, lhs
, deref
);
1726 /* In the case of memory store we can do nothing. */
1728 m_lattice
[index
].merge (deref_flags (0, false));
1730 m_lattice
[index
].merge (0);
1733 /* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
1734 into flags for caller, update LATTICE of corresponding
1735 argument if needed. */
1738 callee_to_caller_flags (int call_flags
, bool ignore_stores
,
1739 modref_lattice
&lattice
)
1741 /* call_flags is about callee returning a value
1742 that is not the same as caller returning it. */
1743 call_flags
|= EAF_NOT_RETURNED
1744 | EAF_NOT_RETURNED_DIRECTLY
;
1745 /* TODO: We miss return value propagation.
1746 Be conservative and if value escapes to memory
1747 also mark it as escaping. */
1748 if (!ignore_stores
&& !(call_flags
& EAF_UNUSED
))
1750 if (!(call_flags
& EAF_NOESCAPE
))
1751 lattice
.merge (~(EAF_NOT_RETURNED
| EAF_UNUSED
));
1752 if (!(call_flags
& (EAF_NODIRECTESCAPE
| EAF_NOESCAPE
)))
1753 lattice
.merge (~(EAF_NOT_RETURNED_DIRECTLY
1758 call_flags
|= ignore_stores_eaf_flags
;
1762 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
1763 LATTICE is an array of modref_lattices.
1764 DEPTH is a recursion depth used to make debug output prettier.
1765 If IPA is true we analyze for IPA propagation (and thus call escape points
1766 are processed later) */
1769 modref_eaf_analysis::analyze_ssa_name (tree name
)
1771 imm_use_iterator ui
;
1773 int index
= SSA_NAME_VERSION (name
);
1775 /* See if value is already computed. */
1776 if (m_lattice
[index
].known
)
1778 if (m_lattice
[index
].open
)
1782 "%*sGiving up on a cycle in SSA graph\n",
1786 if (m_depth
== param_modref_max_depth
)
1790 "%*sGiving up on max depth\n",
1794 /* Recursion guard. */
1795 m_lattice
[index
].init ();
1800 "%*sAnalyzing flags of ssa name: ", m_depth
* 4, "");
1801 print_generic_expr (dump_file
, name
);
1802 fprintf (dump_file
, "\n");
1805 FOR_EACH_IMM_USE_STMT (use_stmt
, ui
, name
)
1807 if (m_lattice
[index
].flags
== 0)
1809 if (is_gimple_debug (use_stmt
))
1813 fprintf (dump_file
, "%*s Analyzing stmt: ", m_depth
* 4, "");
1814 print_gimple_stmt (dump_file
, use_stmt
, 0);
1816 /* If we see a direct non-debug use, clear unused bit.
1817 All dereferneces should be accounted below using deref_flags. */
1818 m_lattice
[index
].merge (~EAF_UNUSED
);
1820 /* Gimple return may load the return value.
1821 Returning name counts as an use by tree-ssa-structalias.c */
1822 if (greturn
*ret
= dyn_cast
<greturn
*> (use_stmt
))
1824 /* Returning through return slot is seen as memory write earlier. */
1825 if (DECL_RESULT (current_function_decl
)
1826 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl
)))
1828 else if (gimple_return_retval (ret
) == name
)
1829 m_lattice
[index
].merge (~(EAF_UNUSED
| EAF_NOT_RETURNED
1830 | EAF_NOT_RETURNED_DIRECTLY
));
1831 else if (memory_access_to (gimple_return_retval (ret
), name
))
1833 m_lattice
[index
].merge_direct_load ();
1834 m_lattice
[index
].merge (~(EAF_UNUSED
| EAF_NOT_RETURNED
1835 | EAF_NOT_RETURNED_DIRECTLY
));
1838 /* Account for LHS store, arg loads and flags from callee function. */
1839 else if (gcall
*call
= dyn_cast
<gcall
*> (use_stmt
))
1841 tree callee
= gimple_call_fndecl (call
);
1843 /* IPA PTA internally it treats calling a function as "writing" to
1844 the argument space of all functions the function pointer points to
1845 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
1846 is on since that would allow propagation of this from -fno-ipa-pta
1847 to -fipa-pta functions. */
1848 if (gimple_call_fn (use_stmt
) == name
)
1849 m_lattice
[index
].merge (~(EAF_NOCLOBBER
| EAF_UNUSED
));
1851 /* Recursion would require bit of propagation; give up for now. */
1852 if (callee
&& !m_ipa
&& recursive_call_p (current_function_decl
,
1854 m_lattice
[index
].merge (0);
1857 int ecf_flags
= gimple_call_flags (call
);
1858 bool ignore_stores
= ignore_stores_p (current_function_decl
,
1860 bool ignore_retval
= ignore_retval_p (current_function_decl
,
1863 /* Handle *name = func (...). */
1864 if (gimple_call_lhs (call
)
1865 && memory_access_to (gimple_call_lhs (call
), name
))
1867 m_lattice
[index
].merge_direct_store ();
1868 /* Return slot optimization passes address of
1869 LHS to callee via hidden parameter and this
1870 may make LHS to escape. See PR 98499. */
1871 if (gimple_call_return_slot_opt_p (call
)
1872 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call
))))
1874 int call_flags
= gimple_call_retslot_flags (call
);
1875 bool isretslot
= false;
1877 if (DECL_RESULT (current_function_decl
)
1878 && DECL_BY_REFERENCE
1879 (DECL_RESULT (current_function_decl
)))
1880 isretslot
= ssa_default_def
1882 DECL_RESULT (current_function_decl
))
1885 /* Passing returnslot to return slot is special because
1886 not_returned and escape has same meaning.
1887 However passing arg to return slot is different. If
1888 the callee's return slot is returned it means that
1889 arg is written to itself which is an escape. */
1892 if (!(call_flags
& (EAF_NOT_RETURNED
| EAF_UNUSED
)))
1893 m_lattice
[index
].merge (~(EAF_NOESCAPE
1895 if (!(call_flags
& (EAF_NOT_RETURNED_DIRECTLY
1897 | EAF_NOT_RETURNED
)))
1898 m_lattice
[index
].merge (~(EAF_NODIRECTESCAPE
1901 call_flags
= callee_to_caller_flags
1905 m_lattice
[index
].merge (call_flags
);
1909 if (gimple_call_chain (call
)
1910 && (gimple_call_chain (call
) == name
))
1912 int call_flags
= gimple_call_static_chain_flags (call
);
1914 && !(call_flags
& (EAF_NOT_RETURNED
| EAF_UNUSED
)))
1915 merge_call_lhs_flags (call
, -1, name
, false);
1916 call_flags
= callee_to_caller_flags
1917 (call_flags
, ignore_stores
,
1919 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
1920 m_lattice
[index
].merge (call_flags
);
1923 /* Process internal functions and right away. */
1924 bool record_ipa
= m_ipa
&& !gimple_call_internal_p (call
);
1926 /* Handle all function parameters. */
1927 for (unsigned i
= 0;
1928 i
< gimple_call_num_args (call
)
1929 && m_lattice
[index
].flags
; i
++)
1930 /* Name is directly passed to the callee. */
1931 if (gimple_call_arg (call
, i
) == name
)
1933 int call_flags
= gimple_call_arg_flags (call
, i
);
1934 if (!ignore_retval
&& !(call_flags
1935 & (EAF_NOT_RETURNED
| EAF_UNUSED
)))
1936 merge_call_lhs_flags
1938 call_flags
& EAF_NOT_RETURNED_DIRECTLY
);
1939 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
1941 call_flags
= callee_to_caller_flags
1942 (call_flags
, ignore_stores
,
1945 m_lattice
[index
].merge (call_flags
);
1947 m_lattice
[index
].add_escape_point (call
, i
,
1951 /* Name is dereferenced and passed to a callee. */
1952 else if (memory_access_to (gimple_call_arg (call
, i
), name
))
1954 int call_flags
= deref_flags
1955 (gimple_call_arg_flags (call
, i
), ignore_stores
);
1957 && !(call_flags
& (EAF_NOT_RETURNED
| EAF_UNUSED
)))
1958 merge_call_lhs_flags (call
, i
, name
, true);
1959 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
1960 m_lattice
[index
].merge_direct_load ();
1963 call_flags
= callee_to_caller_flags
1964 (call_flags
, ignore_stores
,
1967 m_lattice
[index
].merge (call_flags
);
1969 m_lattice
[index
].add_escape_point (call
, i
,
1975 else if (gimple_assign_load_p (use_stmt
))
1977 gassign
*assign
= as_a
<gassign
*> (use_stmt
);
1978 /* Memory to memory copy. */
1979 if (gimple_store_p (assign
))
1981 /* Handle *lhs = *name.
1983 We do not track memory locations, so assume that value
1984 is used arbitrarily. */
1985 if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
1986 m_lattice
[index
].merge (deref_flags (0, false));
1987 /* Handle *name = *exp. */
1988 else if (memory_access_to (gimple_assign_lhs (assign
), name
))
1989 m_lattice
[index
].merge_direct_store ();
1991 /* Handle lhs = *name. */
1992 else if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
1994 tree lhs
= gimple_assign_lhs (assign
);
1995 merge_with_ssa_name (name
, lhs
, true);
1998 else if (gimple_store_p (use_stmt
))
2000 gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
);
2002 /* Handle *lhs = name. */
2003 if (assign
&& gimple_assign_rhs1 (assign
) == name
)
2006 fprintf (dump_file
, "%*s ssa name saved to memory\n",
2008 m_lattice
[index
].merge (0);
2010 /* Handle *name = exp. */
2012 && memory_access_to (gimple_assign_lhs (assign
), name
))
2014 /* In general we can not ignore clobbers because they are
2015 barriers for code motion, however after inlining it is safe to
2016 do because local optimization passes do not consider clobbers
2017 from other functions.
2018 Similar logic is in ipa-pure-const.c. */
2019 if (!cfun
->after_inlining
|| !gimple_clobber_p (assign
))
2020 m_lattice
[index
].merge_direct_store ();
2022 /* ASM statements etc. */
2026 fprintf (dump_file
, "%*s Unhandled store\n", m_depth
* 4, "");
2027 m_lattice
[index
].merge (0);
2030 else if (gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
))
2032 enum tree_code code
= gimple_assign_rhs_code (assign
);
2034 /* See if operation is a merge as considered by
2035 tree-ssa-structalias.c:find_func_aliases. */
2036 if (!truth_value_p (code
)
2037 && code
!= POINTER_DIFF_EXPR
2038 && (code
!= POINTER_PLUS_EXPR
2039 || gimple_assign_rhs1 (assign
) == name
))
2041 tree lhs
= gimple_assign_lhs (assign
);
2042 merge_with_ssa_name (name
, lhs
, false);
2045 else if (gphi
*phi
= dyn_cast
<gphi
*> (use_stmt
))
2047 tree result
= gimple_phi_result (phi
);
2048 merge_with_ssa_name (name
, result
, false);
2050 /* Conditions are not considered escape points
2051 by tree-ssa-structalias. */
2052 else if (gimple_code (use_stmt
) == GIMPLE_COND
)
2057 fprintf (dump_file
, "%*s Unhandled stmt\n", m_depth
* 4, "");
2058 m_lattice
[index
].merge (0);
2063 fprintf (dump_file
, "%*s current flags of ", m_depth
* 4, "");
2064 print_generic_expr (dump_file
, name
);
2065 m_lattice
[index
].dump (dump_file
, m_depth
* 4 + 4);
2070 fprintf (dump_file
, "%*sflags of ssa name ", m_depth
* 4, "");
2071 print_generic_expr (dump_file
, name
);
2072 m_lattice
[index
].dump (dump_file
, m_depth
* 4 + 2);
2074 m_lattice
[index
].open
= false;
2075 m_lattice
[index
].known
= true;
2078 /* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
2082 modref_eaf_analysis::merge_with_ssa_name (tree dest
, tree src
, bool deref
)
2084 int index
= SSA_NAME_VERSION (dest
);
2085 int src_index
= SSA_NAME_VERSION (src
);
2088 analyze_ssa_name (src
);
2091 m_lattice
[index
].merge_deref (m_lattice
[src_index
], false);
2093 m_lattice
[index
].merge (m_lattice
[src_index
]);
2096 /* Record escape points of PARM_INDEX according to LATTICE. */
2099 modref_eaf_analysis::record_escape_points (tree name
, int parm_index
, int flags
)
2101 modref_lattice
&lattice
= m_lattice
[SSA_NAME_VERSION (name
)];
2103 if (lattice
.escape_points
.length ())
2107 cgraph_node
*node
= cgraph_node::get (current_function_decl
);
2110 FOR_EACH_VEC_ELT (lattice
.escape_points
, ip
, ep
)
2111 if ((ep
->min_flags
& flags
) != flags
)
2113 cgraph_edge
*e
= node
->get_edge (ep
->call
);
2114 struct escape_entry ee
= {parm_index
, ep
->arg
,
2115 ep
->min_flags
, ep
->direct
};
2117 escape_summaries
->get_create (e
)->esc
.safe_push (ee
);
2122 /* Determine EAF flags for function parameters. */
2125 analyze_parms (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
2128 unsigned int parm_index
= 0;
2129 unsigned int count
= 0;
2130 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
2131 tree retslot
= NULL
;
2132 tree static_chain
= NULL
;
2134 /* For novops functions we have nothing to gain by EAF flags. */
2135 if (ecf_flags
& ECF_NOVOPS
)
2138 /* If there is return slot, look up its SSA name. */
2139 if (DECL_RESULT (current_function_decl
)
2140 && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl
)))
2141 retslot
= ssa_default_def (cfun
, DECL_RESULT (current_function_decl
));
2142 if (cfun
->static_chain_decl
)
2143 static_chain
= ssa_default_def (cfun
, cfun
->static_chain_decl
);
2145 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
2146 parm
= TREE_CHAIN (parm
))
2149 if (!count
&& !retslot
&& !static_chain
)
2152 modref_eaf_analysis
eaf_analysis (ipa
);
2154 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
; parm_index
++,
2155 parm
= TREE_CHAIN (parm
))
2157 tree name
= ssa_default_def (cfun
, parm
);
2158 if (!name
|| has_zero_uses (name
))
2160 /* We do not track non-SSA parameters,
2161 but we want to track unused gimple_regs. */
2162 if (!is_gimple_reg (parm
))
2166 if (parm_index
>= summary
->arg_flags
.length ())
2167 summary
->arg_flags
.safe_grow_cleared (count
, true);
2168 summary
->arg_flags
[parm_index
] = EAF_UNUSED
;
2170 else if (summary_lto
)
2172 if (parm_index
>= summary_lto
->arg_flags
.length ())
2173 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
2174 summary_lto
->arg_flags
[parm_index
] = EAF_UNUSED
;
2178 eaf_analysis
.analyze_ssa_name (name
);
2179 int flags
= eaf_analysis
.get_ssa_name_flags (name
);
2181 /* Eliminate useless flags so we do not end up storing unnecessary
2184 flags
= remove_useless_eaf_flags
2186 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
2192 if (parm_index
>= summary
->arg_flags
.length ())
2193 summary
->arg_flags
.safe_grow_cleared (count
, true);
2194 summary
->arg_flags
[parm_index
] = flags
;
2196 else if (summary_lto
)
2198 if (parm_index
>= summary_lto
->arg_flags
.length ())
2199 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
2200 summary_lto
->arg_flags
[parm_index
] = flags
;
2202 eaf_analysis
.record_escape_points (name
, parm_index
, flags
);
2207 eaf_analysis
.analyze_ssa_name (retslot
);
2208 int flags
= eaf_analysis
.get_ssa_name_flags (retslot
);
2210 flags
= remove_useless_eaf_flags (flags
, ecf_flags
, false);
2214 summary
->retslot_flags
= flags
;
2216 summary_lto
->retslot_flags
= flags
;
2217 eaf_analysis
.record_escape_points (retslot
,
2218 escape_point::retslot_arg
, flags
);
2223 eaf_analysis
.analyze_ssa_name (static_chain
);
2224 int flags
= eaf_analysis
.get_ssa_name_flags (static_chain
);
2226 flags
= remove_useless_eaf_flags (flags
, ecf_flags
, false);
2230 summary
->static_chain_flags
= flags
;
2232 summary_lto
->static_chain_flags
= flags
;
2233 eaf_analysis
.record_escape_points (static_chain
,
2234 escape_point::static_chain_arg
,
2240 /* Analyze function F. IPA indicates whether we're running in local mode
2241 (false) or the IPA mode (true). */
2244 analyze_function (function
*f
, bool ipa
)
2247 fprintf (dump_file
, "modref analyzing '%s' (ipa=%i)%s%s\n",
2248 function_name (f
), ipa
,
2249 TREE_READONLY (current_function_decl
) ? " (const)" : "",
2250 DECL_PURE_P (current_function_decl
) ? " (pure)" : "");
2252 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
2253 if (!flag_ipa_modref
2254 || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl
)))
2257 /* Compute no-LTO summaries when local optimization is going to happen. */
2258 bool nolto
= (!ipa
|| ((!flag_lto
|| flag_fat_lto_objects
) && !in_lto_p
)
2259 || (in_lto_p
&& !flag_wpa
2260 && flag_incremental_link
!= INCREMENTAL_LINK_LTO
));
2261 /* Compute LTO when LTO streaming is going to happen. */
2262 bool lto
= ipa
&& ((flag_lto
&& !in_lto_p
)
2264 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
2265 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
2267 modref_summary
*summary
= NULL
;
2268 modref_summary_lto
*summary_lto
= NULL
;
2270 /* Initialize the summary.
2271 If we run in local mode there is possibly pre-existing summary from
2272 IPA pass. Dump it so it is easy to compare if mod-ref info has
2276 if (!optimization_summaries
)
2277 optimization_summaries
= modref_summaries::create_ggc (symtab
);
2278 else /* Remove existing summary if we are re-running the pass. */
2282 = optimization_summaries
->get (cgraph_node::get (f
->decl
)))
2286 fprintf (dump_file
, "Past summary:\n");
2287 optimization_summaries
->get
2288 (cgraph_node::get (f
->decl
))->dump (dump_file
);
2290 optimization_summaries
->remove (cgraph_node::get (f
->decl
));
2292 summary
= optimization_summaries
->get_create (cgraph_node::get (f
->decl
));
2293 gcc_checking_assert (nolto
&& !lto
);
2295 /* In IPA mode we analyze every function precisely once. Assert that. */
2301 summaries
= modref_summaries::create_ggc (symtab
);
2303 summaries
->remove (cgraph_node::get (f
->decl
));
2304 summary
= summaries
->get_create (cgraph_node::get (f
->decl
));
2309 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
2311 summaries_lto
->remove (cgraph_node::get (f
->decl
));
2312 summary_lto
= summaries_lto
->get_create (cgraph_node::get (f
->decl
));
2314 if (!fnspec_summaries
)
2315 fnspec_summaries
= new fnspec_summaries_t (symtab
);
2316 if (!escape_summaries
)
2317 escape_summaries
= new escape_summaries_t (symtab
);
2321 /* Create and initialize summary for F.
2322 Note that summaries may be already allocated from previous
2326 gcc_assert (!summary
->loads
);
2327 summary
->loads
= modref_records::create_ggc (param_modref_max_bases
,
2328 param_modref_max_refs
,
2329 param_modref_max_accesses
);
2330 gcc_assert (!summary
->stores
);
2331 summary
->stores
= modref_records::create_ggc (param_modref_max_bases
,
2332 param_modref_max_refs
,
2333 param_modref_max_accesses
);
2334 summary
->writes_errno
= false;
2338 gcc_assert (!summary_lto
->loads
);
2339 summary_lto
->loads
= modref_records_lto::create_ggc
2340 (param_modref_max_bases
,
2341 param_modref_max_refs
,
2342 param_modref_max_accesses
);
2343 gcc_assert (!summary_lto
->stores
);
2344 summary_lto
->stores
= modref_records_lto::create_ggc
2345 (param_modref_max_bases
,
2346 param_modref_max_refs
,
2347 param_modref_max_accesses
);
2348 summary_lto
->writes_errno
= false;
2351 analyze_parms (summary
, summary_lto
, ipa
);
2353 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
2354 auto_vec
<gimple
*, 32> recursive_calls
;
2356 /* Analyze each statement in each basic block of the function. If the
2357 statement cannot be analyzed (for any reason), the entire function cannot
2358 be analyzed by modref. */
2360 FOR_EACH_BB_FN (bb
, f
)
2362 gimple_stmt_iterator si
;
2363 for (si
= gsi_start_nondebug_after_labels_bb (bb
);
2364 !gsi_end_p (si
); gsi_next_nondebug (&si
))
2366 if (!analyze_stmt (summary
, summary_lto
,
2367 gsi_stmt (si
), ipa
, &recursive_calls
)
2368 || ((!summary
|| !summary
->useful_p (ecf_flags
, false))
2370 || !summary_lto
->useful_p (ecf_flags
, false))))
2372 collapse_loads (summary
, summary_lto
);
2373 collapse_stores (summary
, summary_lto
);
2379 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2380 This needs to be done after all other side effects are computed. */
2383 bool changed
= true;
2388 for (unsigned i
= 0; i
< recursive_calls
.length (); i
++)
2390 changed
|= merge_call_side_effects
2391 (summary
, recursive_calls
[i
], summary
,
2392 ignore_stores_p (current_function_decl
,
2394 (recursive_calls
[i
])),
2396 if (!summary
->useful_p (ecf_flags
, false))
2398 remove_summary (lto
, nolto
, ipa
);
2405 if (summary
&& !summary
->useful_p (ecf_flags
))
2408 optimization_summaries
->remove (fnode
);
2410 summaries
->remove (fnode
);
2413 if (summary_lto
&& !summary_lto
->useful_p (ecf_flags
))
2415 summaries_lto
->remove (fnode
);
2418 if (ipa
&& !summary
&& !summary_lto
)
2419 remove_modref_edge_summaries (fnode
);
2423 fprintf (dump_file
, " - modref done with result: tracked.\n");
2425 summary
->dump (dump_file
);
2427 summary_lto
->dump (dump_file
);
2428 dump_modref_edge_summaries (dump_file
, fnode
, 2);
2432 /* Callback for generate_summary. */
2435 modref_generate (void)
2437 struct cgraph_node
*node
;
2438 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
2440 function
*f
= DECL_STRUCT_FUNCTION (node
->decl
);
2444 analyze_function (f
, true);
2449 } /* ANON namespace. */
2451 /* Called when a new function is inserted to callgraph late. */
2454 modref_summaries::insert (struct cgraph_node
*node
, modref_summary
*)
2456 /* Local passes ought to be executed by the pass manager. */
2457 if (this == optimization_summaries
)
2459 optimization_summaries
->remove (node
);
2462 if (!DECL_STRUCT_FUNCTION (node
->decl
)
2463 || !opt_for_fn (node
->decl
, flag_ipa_modref
))
2465 summaries
->remove (node
);
2468 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
2469 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
2473 /* Called when a new function is inserted to callgraph late. */
2476 modref_summaries_lto::insert (struct cgraph_node
*node
, modref_summary_lto
*)
2478 /* We do not support adding new function when IPA information is already
2479 propagated. This is done only by SIMD cloning that is not very
2481 if (!DECL_STRUCT_FUNCTION (node
->decl
)
2482 || !opt_for_fn (node
->decl
, flag_ipa_modref
)
2485 summaries_lto
->remove (node
);
2488 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
2489 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
2493 /* Called when new clone is inserted to callgraph late. */
2496 modref_summaries::duplicate (cgraph_node
*, cgraph_node
*dst
,
2497 modref_summary
*src_data
,
2498 modref_summary
*dst_data
)
2500 /* Do not duplicate optimization summaries; we do not handle parameter
2501 transforms on them. */
2502 if (this == optimization_summaries
)
2504 optimization_summaries
->remove (dst
);
2507 dst_data
->stores
= modref_records::create_ggc
2508 (src_data
->stores
->max_bases
,
2509 src_data
->stores
->max_refs
,
2510 src_data
->stores
->max_accesses
);
2511 dst_data
->stores
->copy_from (src_data
->stores
);
2512 dst_data
->loads
= modref_records::create_ggc
2513 (src_data
->loads
->max_bases
,
2514 src_data
->loads
->max_refs
,
2515 src_data
->loads
->max_accesses
);
2516 dst_data
->loads
->copy_from (src_data
->loads
);
2517 dst_data
->writes_errno
= src_data
->writes_errno
;
2518 if (src_data
->arg_flags
.length ())
2519 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
2520 dst_data
->retslot_flags
= src_data
->retslot_flags
;
2521 dst_data
->static_chain_flags
= src_data
->static_chain_flags
;
2524 /* Called when new clone is inserted to callgraph late. */
2527 modref_summaries_lto::duplicate (cgraph_node
*, cgraph_node
*,
2528 modref_summary_lto
*src_data
,
2529 modref_summary_lto
*dst_data
)
2531 /* Be sure that no further cloning happens after ipa-modref. If it does
2532 we will need to update signatures for possible param changes. */
2533 gcc_checking_assert (!((modref_summaries_lto
*)summaries_lto
)->propagated
);
2534 dst_data
->stores
= modref_records_lto::create_ggc
2535 (src_data
->stores
->max_bases
,
2536 src_data
->stores
->max_refs
,
2537 src_data
->stores
->max_accesses
);
2538 dst_data
->stores
->copy_from (src_data
->stores
);
2539 dst_data
->loads
= modref_records_lto::create_ggc
2540 (src_data
->loads
->max_bases
,
2541 src_data
->loads
->max_refs
,
2542 src_data
->loads
->max_accesses
);
2543 dst_data
->loads
->copy_from (src_data
->loads
);
2544 dst_data
->writes_errno
= src_data
->writes_errno
;
2545 if (src_data
->arg_flags
.length ())
2546 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
2547 dst_data
->retslot_flags
= src_data
->retslot_flags
;
2548 dst_data
->static_chain_flags
= src_data
->static_chain_flags
;
2553 /* Definition of the modref pass on GIMPLE. */
2554 const pass_data pass_data_modref
= {
2559 (PROP_cfg
| PROP_ssa
),
2566 class pass_modref
: public gimple_opt_pass
2569 pass_modref (gcc::context
*ctxt
)
2570 : gimple_opt_pass (pass_data_modref
, ctxt
) {}
2572 /* opt_pass methods: */
2575 return new pass_modref (m_ctxt
);
2577 virtual bool gate (function
*)
2579 return flag_ipa_modref
;
2581 virtual unsigned int execute (function
*);
2584 /* Encode TT to the output block OB using the summary streaming API. */
2587 write_modref_records (modref_records_lto
*tt
, struct output_block
*ob
)
2589 streamer_write_uhwi (ob
, tt
->max_bases
);
2590 streamer_write_uhwi (ob
, tt
->max_refs
);
2591 streamer_write_uhwi (ob
, tt
->max_accesses
);
2593 streamer_write_uhwi (ob
, tt
->every_base
);
2594 streamer_write_uhwi (ob
, vec_safe_length (tt
->bases
));
2596 modref_base_node
<tree
> *base_node
;
2597 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, base_node
)
2599 stream_write_tree (ob
, base_node
->base
, true);
2601 streamer_write_uhwi (ob
, base_node
->every_ref
);
2602 streamer_write_uhwi (ob
, vec_safe_length (base_node
->refs
));
2605 modref_ref_node
<tree
> *ref_node
;
2606 FOR_EACH_VEC_SAFE_ELT (base_node
->refs
, j
, ref_node
)
2608 stream_write_tree (ob
, ref_node
->ref
, true);
2609 streamer_write_uhwi (ob
, ref_node
->every_access
);
2610 streamer_write_uhwi (ob
, vec_safe_length (ref_node
->accesses
));
2613 modref_access_node
*access_node
;
2614 FOR_EACH_VEC_SAFE_ELT (ref_node
->accesses
, k
, access_node
)
2616 streamer_write_hwi (ob
, access_node
->parm_index
);
2617 if (access_node
->parm_index
!= -1)
2619 streamer_write_uhwi (ob
, access_node
->parm_offset_known
);
2620 if (access_node
->parm_offset_known
)
2622 streamer_write_poly_int64 (ob
, access_node
->parm_offset
);
2623 streamer_write_poly_int64 (ob
, access_node
->offset
);
2624 streamer_write_poly_int64 (ob
, access_node
->size
);
2625 streamer_write_poly_int64 (ob
, access_node
->max_size
);
2633 /* Read a modref_tree from the input block IB using the data from DATA_IN.
2634 This assumes that the tree was encoded using write_modref_tree.
2635 Either nolto_ret or lto_ret is initialized by the tree depending whether
2636 LTO streaming is expected or not. */
2639 read_modref_records (lto_input_block
*ib
, struct data_in
*data_in
,
2640 modref_records
**nolto_ret
,
2641 modref_records_lto
**lto_ret
)
2643 size_t max_bases
= streamer_read_uhwi (ib
);
2644 size_t max_refs
= streamer_read_uhwi (ib
);
2645 size_t max_accesses
= streamer_read_uhwi (ib
);
2648 *lto_ret
= modref_records_lto::create_ggc (max_bases
, max_refs
,
2651 *nolto_ret
= modref_records::create_ggc (max_bases
, max_refs
,
2653 gcc_checking_assert (lto_ret
|| nolto_ret
);
2655 size_t every_base
= streamer_read_uhwi (ib
);
2656 size_t nbase
= streamer_read_uhwi (ib
);
2658 gcc_assert (!every_base
|| nbase
== 0);
2662 (*nolto_ret
)->collapse ();
2664 (*lto_ret
)->collapse ();
2666 for (size_t i
= 0; i
< nbase
; i
++)
2668 tree base_tree
= stream_read_tree (ib
, data_in
);
2669 modref_base_node
<alias_set_type
> *nolto_base_node
= NULL
;
2670 modref_base_node
<tree
> *lto_base_node
= NULL
;
2672 /* At stream in time we have LTO alias info. Check if we streamed in
2673 something obviously unnecessary. Do not glob types by alias sets;
2674 it is not 100% clear that ltrans types will get merged same way.
2675 Types may get refined based on ODR type conflicts. */
2676 if (base_tree
&& !get_alias_set (base_tree
))
2680 fprintf (dump_file
, "Streamed in alias set 0 type ");
2681 print_generic_expr (dump_file
, base_tree
);
2682 fprintf (dump_file
, "\n");
2688 nolto_base_node
= (*nolto_ret
)->insert_base (base_tree
2689 ? get_alias_set (base_tree
)
2692 lto_base_node
= (*lto_ret
)->insert_base (base_tree
, 0);
2693 size_t every_ref
= streamer_read_uhwi (ib
);
2694 size_t nref
= streamer_read_uhwi (ib
);
2696 gcc_assert (!every_ref
|| nref
== 0);
2699 if (nolto_base_node
)
2700 nolto_base_node
->collapse ();
2702 lto_base_node
->collapse ();
2704 for (size_t j
= 0; j
< nref
; j
++)
2706 tree ref_tree
= stream_read_tree (ib
, data_in
);
2708 if (ref_tree
&& !get_alias_set (ref_tree
))
2712 fprintf (dump_file
, "Streamed in alias set 0 type ");
2713 print_generic_expr (dump_file
, ref_tree
);
2714 fprintf (dump_file
, "\n");
2719 modref_ref_node
<alias_set_type
> *nolto_ref_node
= NULL
;
2720 modref_ref_node
<tree
> *lto_ref_node
= NULL
;
2722 if (nolto_base_node
)
2724 = nolto_base_node
->insert_ref (ref_tree
2725 ? get_alias_set (ref_tree
) : 0,
2728 lto_ref_node
= lto_base_node
->insert_ref (ref_tree
, max_refs
);
2730 size_t every_access
= streamer_read_uhwi (ib
);
2731 size_t naccesses
= streamer_read_uhwi (ib
);
2734 nolto_ref_node
->every_access
= every_access
;
2736 lto_ref_node
->every_access
= every_access
;
2738 for (size_t k
= 0; k
< naccesses
; k
++)
2740 int parm_index
= streamer_read_hwi (ib
);
2741 bool parm_offset_known
= false;
2742 poly_int64 parm_offset
= 0;
2743 poly_int64 offset
= 0;
2744 poly_int64 size
= -1;
2745 poly_int64 max_size
= -1;
2747 if (parm_index
!= -1)
2749 parm_offset_known
= streamer_read_uhwi (ib
);
2750 if (parm_offset_known
)
2752 parm_offset
= streamer_read_poly_int64 (ib
);
2753 offset
= streamer_read_poly_int64 (ib
);
2754 size
= streamer_read_poly_int64 (ib
);
2755 max_size
= streamer_read_poly_int64 (ib
);
2758 modref_access_node a
= {offset
, size
, max_size
, parm_offset
,
2759 parm_index
, parm_offset_known
, false};
2761 nolto_ref_node
->insert_access (a
, max_accesses
, false);
2763 lto_ref_node
->insert_access (a
, max_accesses
, false);
2768 (*lto_ret
)->cleanup ();
2770 (*nolto_ret
)->cleanup ();
2773 /* Write ESUM to BP. */
2776 modref_write_escape_summary (struct bitpack_d
*bp
, escape_summary
*esum
)
2780 bp_pack_var_len_unsigned (bp
, 0);
2783 bp_pack_var_len_unsigned (bp
, esum
->esc
.length ());
2786 FOR_EACH_VEC_ELT (esum
->esc
, i
, ee
)
2788 bp_pack_var_len_int (bp
, ee
->parm_index
);
2789 bp_pack_var_len_unsigned (bp
, ee
->arg
);
2790 bp_pack_var_len_unsigned (bp
, ee
->min_flags
);
2791 bp_pack_value (bp
, ee
->direct
, 1);
2795 /* Read escape summary for E from BP. */
2798 modref_read_escape_summary (struct bitpack_d
*bp
, cgraph_edge
*e
)
2800 unsigned int n
= bp_unpack_var_len_unsigned (bp
);
2803 escape_summary
*esum
= escape_summaries
->get_create (e
);
2804 esum
->esc
.reserve_exact (n
);
2805 for (unsigned int i
= 0; i
< n
; i
++)
2808 ee
.parm_index
= bp_unpack_var_len_int (bp
);
2809 ee
.arg
= bp_unpack_var_len_unsigned (bp
);
2810 ee
.min_flags
= bp_unpack_var_len_unsigned (bp
);
2811 ee
.direct
= bp_unpack_value (bp
, 1);
2812 esum
->esc
.quick_push (ee
);
2816 /* Callback for write_summary. */
2821 struct output_block
*ob
= create_output_block (LTO_section_ipa_modref
);
2822 lto_symtab_encoder_t encoder
= ob
->decl_state
->symtab_node_encoder
;
2823 unsigned int count
= 0;
2828 streamer_write_uhwi (ob
, 0);
2829 streamer_write_char_stream (ob
->main_stream
, 0);
2830 produce_asm (ob
, NULL
);
2831 destroy_output_block (ob
);
2835 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
2837 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
2838 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
2839 modref_summary_lto
*r
;
2841 if (cnode
&& cnode
->definition
&& !cnode
->alias
2842 && (r
= summaries_lto
->get (cnode
))
2843 && r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
2846 streamer_write_uhwi (ob
, count
);
2848 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
2850 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
2851 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
2853 if (cnode
&& cnode
->definition
&& !cnode
->alias
)
2855 modref_summary_lto
*r
= summaries_lto
->get (cnode
);
2857 if (!r
|| !r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
2860 streamer_write_uhwi (ob
, lto_symtab_encoder_encode (encoder
, cnode
));
2862 streamer_write_uhwi (ob
, r
->arg_flags
.length ());
2863 for (unsigned int i
= 0; i
< r
->arg_flags
.length (); i
++)
2864 streamer_write_uhwi (ob
, r
->arg_flags
[i
]);
2865 streamer_write_uhwi (ob
, r
->retslot_flags
);
2866 streamer_write_uhwi (ob
, r
->static_chain_flags
);
2868 write_modref_records (r
->loads
, ob
);
2869 write_modref_records (r
->stores
, ob
);
2871 struct bitpack_d bp
= bitpack_create (ob
->main_stream
);
2872 bp_pack_value (&bp
, r
->writes_errno
, 1);
2875 for (cgraph_edge
*e
= cnode
->indirect_calls
;
2876 e
; e
= e
->next_callee
)
2878 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
2879 bp_pack_value (&bp
, sum
!= NULL
, 1);
2881 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
2882 class escape_summary
*esum
= escape_summaries
->get (e
);
2883 modref_write_escape_summary (&bp
,esum
);
2885 for (cgraph_edge
*e
= cnode
->callees
; e
; e
= e
->next_callee
)
2887 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
2888 bp_pack_value (&bp
, sum
!= NULL
, 1);
2890 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
2891 class escape_summary
*esum
= escape_summaries
->get (e
);
2892 modref_write_escape_summary (&bp
,esum
);
2895 streamer_write_bitpack (&bp
);
2898 streamer_write_char_stream (ob
->main_stream
, 0);
2899 produce_asm (ob
, NULL
);
2900 destroy_output_block (ob
);
2904 read_section (struct lto_file_decl_data
*file_data
, const char *data
,
2907 const struct lto_function_header
*header
2908 = (const struct lto_function_header
*) data
;
2909 const int cfg_offset
= sizeof (struct lto_function_header
);
2910 const int main_offset
= cfg_offset
+ header
->cfg_size
;
2911 const int string_offset
= main_offset
+ header
->main_size
;
2912 struct data_in
*data_in
;
2914 unsigned int f_count
;
2916 lto_input_block
ib ((const char *) data
+ main_offset
, header
->main_size
,
2917 file_data
->mode_table
);
2920 = lto_data_in_create (file_data
, (const char *) data
+ string_offset
,
2921 header
->string_size
, vNULL
);
2922 f_count
= streamer_read_uhwi (&ib
);
2923 for (i
= 0; i
< f_count
; i
++)
2925 struct cgraph_node
*node
;
2926 lto_symtab_encoder_t encoder
;
2928 unsigned int index
= streamer_read_uhwi (&ib
);
2929 encoder
= file_data
->symtab_node_encoder
;
2930 node
= dyn_cast
<cgraph_node
*> (lto_symtab_encoder_deref (encoder
,
2933 modref_summary
*modref_sum
= summaries
2934 ? summaries
->get_create (node
) : NULL
;
2935 modref_summary_lto
*modref_sum_lto
= summaries_lto
2936 ? summaries_lto
->get_create (node
)
2938 if (optimization_summaries
)
2939 modref_sum
= optimization_summaries
->get_create (node
);
2942 modref_sum
->writes_errno
= false;
2944 modref_sum_lto
->writes_errno
= false;
2946 gcc_assert (!modref_sum
|| (!modref_sum
->loads
2947 && !modref_sum
->stores
));
2948 gcc_assert (!modref_sum_lto
|| (!modref_sum_lto
->loads
2949 && !modref_sum_lto
->stores
));
2950 unsigned int args
= streamer_read_uhwi (&ib
);
2951 if (args
&& modref_sum
)
2952 modref_sum
->arg_flags
.reserve_exact (args
);
2953 if (args
&& modref_sum_lto
)
2954 modref_sum_lto
->arg_flags
.reserve_exact (args
);
2955 for (unsigned int i
= 0; i
< args
; i
++)
2957 eaf_flags_t flags
= streamer_read_uhwi (&ib
);
2959 modref_sum
->arg_flags
.quick_push (flags
);
2961 modref_sum_lto
->arg_flags
.quick_push (flags
);
2963 eaf_flags_t flags
= streamer_read_uhwi (&ib
);
2965 modref_sum
->retslot_flags
= flags
;
2967 modref_sum_lto
->retslot_flags
= flags
;
2969 flags
= streamer_read_uhwi (&ib
);
2971 modref_sum
->static_chain_flags
= flags
;
2973 modref_sum_lto
->static_chain_flags
= flags
;
2975 read_modref_records (&ib
, data_in
,
2976 modref_sum
? &modref_sum
->loads
: NULL
,
2977 modref_sum_lto
? &modref_sum_lto
->loads
: NULL
);
2978 read_modref_records (&ib
, data_in
,
2979 modref_sum
? &modref_sum
->stores
: NULL
,
2980 modref_sum_lto
? &modref_sum_lto
->stores
: NULL
);
2981 struct bitpack_d bp
= streamer_read_bitpack (&ib
);
2982 if (bp_unpack_value (&bp
, 1))
2985 modref_sum
->writes_errno
= true;
2987 modref_sum_lto
->writes_errno
= true;
2991 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
2993 if (bp_unpack_value (&bp
, 1))
2995 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
2996 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
2998 modref_read_escape_summary (&bp
, e
);
3000 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
3002 if (bp_unpack_value (&bp
, 1))
3004 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
3005 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
3007 modref_read_escape_summary (&bp
, e
);
3012 fprintf (dump_file
, "Read modref for %s\n",
3013 node
->dump_name ());
3015 modref_sum
->dump (dump_file
);
3017 modref_sum_lto
->dump (dump_file
);
3018 dump_modref_edge_summaries (dump_file
, node
, 4);
3022 lto_free_section_data (file_data
, LTO_section_ipa_modref
, NULL
, data
,
3024 lto_data_in_delete (data_in
);
3027 /* Callback for read_summary. */
3032 struct lto_file_decl_data
**file_data_vec
= lto_get_file_decl_data ();
3033 struct lto_file_decl_data
*file_data
;
3036 gcc_checking_assert (!optimization_summaries
&& !summaries
&& !summaries_lto
);
3038 optimization_summaries
= modref_summaries::create_ggc (symtab
);
3041 if (flag_wpa
|| flag_incremental_link
== INCREMENTAL_LINK_LTO
)
3042 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
3044 || (flag_incremental_link
== INCREMENTAL_LINK_LTO
3045 && flag_fat_lto_objects
))
3046 summaries
= modref_summaries::create_ggc (symtab
);
3047 if (!fnspec_summaries
)
3048 fnspec_summaries
= new fnspec_summaries_t (symtab
);
3049 if (!escape_summaries
)
3050 escape_summaries
= new escape_summaries_t (symtab
);
3053 while ((file_data
= file_data_vec
[j
++]))
3056 const char *data
= lto_get_summary_section_data (file_data
,
3057 LTO_section_ipa_modref
,
3060 read_section (file_data
, data
, len
);
3062 /* Fatal error here. We do not want to support compiling ltrans units
3063 with different version of compiler or different flags than the WPA
3064 unit, so this should never happen. */
3065 fatal_error (input_location
,
3066 "IPA modref summary is missing in input file");
3070 /* Recompute arg_flags for param adjustments in INFO. */
3073 remap_arg_flags (auto_vec
<eaf_flags_t
> &arg_flags
, clone_info
*info
)
3075 auto_vec
<eaf_flags_t
> old
= arg_flags
.copy ();
3078 ipa_adjusted_param
*p
;
3080 arg_flags
.release ();
3082 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
3084 int o
= info
->param_adjustments
->get_original_index (i
);
3085 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
3089 arg_flags
.safe_grow_cleared (max
+ 1, true);
3090 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
3092 int o
= info
->param_adjustments
->get_original_index (i
);
3093 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
3094 arg_flags
[i
] = old
[o
];
3098 /* If signature changed, update the summary. */
3101 update_signature (struct cgraph_node
*node
)
3103 clone_info
*info
= clone_info::get (node
);
3104 if (!info
|| !info
->param_adjustments
)
3107 modref_summary
*r
= optimization_summaries
3108 ? optimization_summaries
->get (node
) : NULL
;
3109 modref_summary_lto
*r_lto
= summaries_lto
3110 ? summaries_lto
->get (node
) : NULL
;
3115 fprintf (dump_file
, "Updating summary for %s from:\n",
3116 node
->dump_name ());
3118 r
->dump (dump_file
);
3120 r_lto
->dump (dump_file
);
3124 ipa_adjusted_param
*p
;
3126 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
3128 int idx
= info
->param_adjustments
->get_original_index (i
);
3133 auto_vec
<int, 32> map
;
3135 map
.reserve (max
+ 1);
3136 for (i
= 0; i
<= max
; i
++)
3137 map
.quick_push (-1);
3138 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
3140 int idx
= info
->param_adjustments
->get_original_index (i
);
3146 r
->loads
->remap_params (&map
);
3147 r
->stores
->remap_params (&map
);
3148 if (r
->arg_flags
.length ())
3149 remap_arg_flags (r
->arg_flags
, info
);
3153 r_lto
->loads
->remap_params (&map
);
3154 r_lto
->stores
->remap_params (&map
);
3155 if (r_lto
->arg_flags
.length ())
3156 remap_arg_flags (r_lto
->arg_flags
, info
);
3160 fprintf (dump_file
, "to:\n");
3162 r
->dump (dump_file
);
3164 r_lto
->dump (dump_file
);
3169 /* Definition of the modref IPA pass. */
3170 const pass_data pass_data_ipa_modref
=
3172 IPA_PASS
, /* type */
3173 "modref", /* name */
3174 OPTGROUP_IPA
, /* optinfo_flags */
3175 TV_IPA_MODREF
, /* tv_id */
3176 0, /* properties_required */
3177 0, /* properties_provided */
3178 0, /* properties_destroyed */
3179 0, /* todo_flags_start */
3180 ( TODO_dump_symtab
), /* todo_flags_finish */
3183 class pass_ipa_modref
: public ipa_opt_pass_d
3186 pass_ipa_modref (gcc::context
*ctxt
)
3187 : ipa_opt_pass_d (pass_data_ipa_modref
, ctxt
,
3188 modref_generate
, /* generate_summary */
3189 modref_write
, /* write_summary */
3190 modref_read
, /* read_summary */
3191 modref_write
, /* write_optimization_summary */
3192 modref_read
, /* read_optimization_summary */
3193 NULL
, /* stmt_fixup */
3194 0, /* function_transform_todo_flags_start */
3195 NULL
, /* function_transform */
3196 NULL
) /* variable_transform */
3199 /* opt_pass methods: */
3200 opt_pass
*clone () { return new pass_ipa_modref (m_ctxt
); }
3201 virtual bool gate (function
*)
3205 virtual unsigned int execute (function
*);
3211 unsigned int pass_modref::execute (function
*f
)
3213 analyze_function (f
, false);
3218 make_pass_modref (gcc::context
*ctxt
)
3220 return new pass_modref (ctxt
);
3224 make_pass_ipa_modref (gcc::context
*ctxt
)
3226 return new pass_ipa_modref (ctxt
);
3231 /* Skip edges from and to nodes without ipa_pure_const enabled.
3232 Ignore not available symbols. */
3235 ignore_edge (struct cgraph_edge
*e
)
3237 /* We merge summaries of inline clones into summaries of functions they
3238 are inlined to. For that reason the complete function bodies must
3240 if (!e
->inline_failed
)
3242 enum availability avail
;
3243 cgraph_node
*callee
= e
->callee
->function_or_virtual_thunk_symbol
3244 (&avail
, e
->caller
);
3246 return (avail
<= AVAIL_INTERPOSABLE
3247 || ((!optimization_summaries
|| !optimization_summaries
->get (callee
))
3248 && (!summaries_lto
|| !summaries_lto
->get (callee
)))
3249 || flags_from_decl_or_type (e
->callee
->decl
)
3250 & (ECF_CONST
| ECF_NOVOPS
));
3253 /* Compute parm_map for CALLEE_EDGE. */
3256 compute_parm_map (cgraph_edge
*callee_edge
, vec
<modref_parm_map
> *parm_map
)
3258 class ipa_edge_args
*args
;
3259 if (ipa_node_params_sum
3260 && !callee_edge
->call_stmt_cannot_inline_p
3261 && (args
= ipa_edge_args_sum
->get (callee_edge
)) != NULL
)
3263 int i
, count
= ipa_get_cs_argument_count (args
);
3264 class ipa_node_params
*caller_parms_info
, *callee_pi
;
3265 class ipa_call_summary
*es
3266 = ipa_call_summaries
->get (callee_edge
);
3268 = callee_edge
->callee
->function_or_virtual_thunk_symbol
3269 (NULL
, callee_edge
->caller
);
3272 = ipa_node_params_sum
->get (callee_edge
->caller
->inlined_to
3273 ? callee_edge
->caller
->inlined_to
3274 : callee_edge
->caller
);
3275 callee_pi
= ipa_node_params_sum
->get (callee
);
3277 (*parm_map
).safe_grow_cleared (count
, true);
3279 for (i
= 0; i
< count
; i
++)
3281 if (es
&& es
->param
[i
].points_to_local_or_readonly_memory
)
3283 (*parm_map
)[i
].parm_index
= -2;
3287 struct ipa_jump_func
*jf
3288 = ipa_get_ith_jump_func (args
, i
);
3289 if (jf
&& callee_pi
)
3291 tree cst
= ipa_value_from_jfunc (caller_parms_info
,
3295 if (cst
&& points_to_local_or_readonly_memory_p (cst
))
3297 (*parm_map
)[i
].parm_index
= -2;
3301 if (jf
&& jf
->type
== IPA_JF_PASS_THROUGH
)
3303 (*parm_map
)[i
].parm_index
3304 = ipa_get_jf_pass_through_formal_id (jf
);
3305 if (ipa_get_jf_pass_through_operation (jf
) == NOP_EXPR
)
3307 (*parm_map
)[i
].parm_offset_known
= true;
3308 (*parm_map
)[i
].parm_offset
= 0;
3310 else if (ipa_get_jf_pass_through_operation (jf
)
3311 == POINTER_PLUS_EXPR
3312 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf
),
3313 &(*parm_map
)[i
].parm_offset
))
3314 (*parm_map
)[i
].parm_offset_known
= true;
3316 (*parm_map
)[i
].parm_offset_known
= false;
3319 if (jf
&& jf
->type
== IPA_JF_ANCESTOR
)
3321 (*parm_map
)[i
].parm_index
= ipa_get_jf_ancestor_formal_id (jf
);
3322 (*parm_map
)[i
].parm_offset_known
= true;
3324 (!(ipa_get_jf_ancestor_offset (jf
) & (BITS_PER_UNIT
- 1)));
3325 (*parm_map
)[i
].parm_offset
3326 = ipa_get_jf_ancestor_offset (jf
) >> LOG2_BITS_PER_UNIT
;
3329 (*parm_map
)[i
].parm_index
= -1;
3333 fprintf (dump_file
, " Parm map: ");
3334 for (i
= 0; i
< count
; i
++)
3335 fprintf (dump_file
, " %i", (*parm_map
)[i
].parm_index
);
3336 fprintf (dump_file
, "\n");
3343 /* Map used to translate escape infos. */
3351 /* Update escape map for E. */
3354 update_escape_summary_1 (cgraph_edge
*e
,
3355 vec
<vec
<escape_map
>> &map
,
3358 escape_summary
*sum
= escape_summaries
->get (e
);
3361 auto_vec
<escape_entry
> old
= sum
->esc
.copy ();
3362 sum
->esc
.release ();
3366 FOR_EACH_VEC_ELT (old
, i
, ee
)
3369 struct escape_map
*em
;
3370 /* TODO: We do not have jump functions for return slots, so we
3371 never propagate them to outer function. */
3372 if (ee
->parm_index
>= (int)map
.length ()
3373 || ee
->parm_index
< 0)
3375 FOR_EACH_VEC_ELT (map
[ee
->parm_index
], j
, em
)
3377 int min_flags
= ee
->min_flags
;
3378 if (ee
->direct
&& !em
->direct
)
3379 min_flags
= deref_flags (min_flags
, ignore_stores
);
3380 struct escape_entry entry
= {em
->parm_index
, ee
->arg
,
3382 ee
->direct
& em
->direct
};
3383 sum
->esc
.safe_push (entry
);
3386 if (!sum
->esc
.length ())
3387 escape_summaries
->remove (e
);
3390 /* Update escape map fo NODE. */
3393 update_escape_summary (cgraph_node
*node
,
3394 vec
<vec
<escape_map
>> &map
,
3397 if (!escape_summaries
)
3399 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
3400 update_escape_summary_1 (e
, map
, ignore_stores
);
3401 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
3403 if (!e
->inline_failed
)
3404 update_escape_summary (e
->callee
, map
, ignore_stores
);
3406 update_escape_summary_1 (e
, map
, ignore_stores
);
3410 /* Get parameter type from DECL. This is only safe for special cases
3411 like builtins we create fnspec for because the type match is checked
3412 at fnspec creation time. */
3415 get_parm_type (tree decl
, unsigned int i
)
3417 tree t
= TYPE_ARG_TYPES (TREE_TYPE (decl
));
3419 for (unsigned int p
= 0; p
< i
; p
++)
3421 return TREE_VALUE (t
);
3424 /* Return access mode for argument I of call E with FNSPEC. */
3426 static modref_access_node
3427 get_access_for_fnspec (cgraph_edge
*e
, attr_fnspec
&fnspec
,
3428 unsigned int i
, modref_parm_map
&map
)
3430 tree size
= NULL_TREE
;
3431 unsigned int size_arg
;
3433 if (!fnspec
.arg_specified_p (i
))
3435 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
3437 cgraph_node
*node
= e
->caller
->inlined_to
3438 ? e
->caller
->inlined_to
: e
->caller
;
3439 ipa_node_params
*caller_parms_info
= ipa_node_params_sum
->get (node
);
3440 ipa_edge_args
*args
= ipa_edge_args_sum
->get (e
);
3441 struct ipa_jump_func
*jf
= ipa_get_ith_jump_func (args
, size_arg
);
3444 size
= ipa_value_from_jfunc (caller_parms_info
, jf
,
3445 get_parm_type (e
->callee
->decl
, size_arg
));
3447 else if (fnspec
.arg_access_size_given_by_type_p (i
))
3448 size
= TYPE_SIZE_UNIT (get_parm_type (e
->callee
->decl
, i
));
3449 modref_access_node a
= {0, -1, -1,
3450 map
.parm_offset
, map
.parm_index
,
3451 map
.parm_offset_known
, 0};
3452 poly_int64 size_hwi
;
3454 && poly_int_tree_p (size
, &size_hwi
)
3455 && coeffs_in_range_p (size_hwi
, 0,
3456 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
3459 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
3464 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
3465 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
3468 propagate_unknown_call (cgraph_node
*node
,
3469 cgraph_edge
*e
, int ecf_flags
,
3470 modref_summary
*cur_summary
,
3471 modref_summary_lto
*cur_summary_lto
)
3473 bool changed
= false;
3474 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
3475 auto_vec
<modref_parm_map
, 32> parm_map
;
3477 && compute_parm_map (e
, &parm_map
))
3479 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
3481 gcc_checking_assert (fnspec
.known_p ());
3482 if (fnspec
.global_memory_read_p ())
3483 collapse_loads (cur_summary
, cur_summary_lto
);
3486 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
3487 for (unsigned i
= 0; i
< parm_map
.length () && t
;
3488 i
++, t
= TREE_CHAIN (t
))
3489 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
3491 else if (!fnspec
.arg_specified_p (i
)
3492 || fnspec
.arg_maybe_read_p (i
))
3494 modref_parm_map map
= parm_map
[i
];
3495 if (map
.parm_index
== -2)
3497 if (map
.parm_index
== -1)
3499 collapse_loads (cur_summary
, cur_summary_lto
);
3503 changed
|= cur_summary
->loads
->insert
3504 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
), false);
3505 if (cur_summary_lto
)
3506 changed
|= cur_summary_lto
->loads
->insert
3507 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
), false);
3510 if (ignore_stores_p (node
->decl
, ecf_flags
))
3512 else if (fnspec
.global_memory_written_p ())
3513 collapse_stores (cur_summary
, cur_summary_lto
);
3516 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
3517 for (unsigned i
= 0; i
< parm_map
.length () && t
;
3518 i
++, t
= TREE_CHAIN (t
))
3519 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
3521 else if (!fnspec
.arg_specified_p (i
)
3522 || fnspec
.arg_maybe_written_p (i
))
3524 modref_parm_map map
= parm_map
[i
];
3525 if (map
.parm_index
== -2)
3527 if (map
.parm_index
== -1)
3529 collapse_stores (cur_summary
, cur_summary_lto
);
3533 changed
|= cur_summary
->stores
->insert
3534 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
), false);
3535 if (cur_summary_lto
)
3536 changed
|= cur_summary_lto
->stores
->insert
3537 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
), false);
3540 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
3542 if (cur_summary
&& !cur_summary
->writes_errno
)
3544 cur_summary
->writes_errno
= true;
3547 if (cur_summary_lto
&& !cur_summary_lto
->writes_errno
)
3549 cur_summary_lto
->writes_errno
= true;
3556 fprintf (dump_file
, " collapsing loads\n");
3557 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
3558 if (!ignore_stores_p (node
->decl
, ecf_flags
))
3561 fprintf (dump_file
, " collapsing stores\n");
3562 changed
|= collapse_stores (cur_summary
, cur_summary_lto
);
3567 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
3568 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
3571 remove_useless_summaries (cgraph_node
*node
,
3572 modref_summary
**cur_summary_ptr
,
3573 modref_summary_lto
**cur_summary_lto_ptr
,
3576 if (*cur_summary_ptr
&& !(*cur_summary_ptr
)->useful_p (ecf_flags
, false))
3578 optimization_summaries
->remove (node
);
3579 *cur_summary_ptr
= NULL
;
3581 if (*cur_summary_lto_ptr
3582 && !(*cur_summary_lto_ptr
)->useful_p (ecf_flags
, false))
3584 summaries_lto
->remove (node
);
3585 *cur_summary_lto_ptr
= NULL
;
3589 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3590 and propagate loads/stores. */
3593 modref_propagate_in_scc (cgraph_node
*component_node
)
3595 bool changed
= true;
3602 for (struct cgraph_node
*cur
= component_node
; cur
;
3603 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3605 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
3606 modref_summary
*cur_summary
= optimization_summaries
3607 ? optimization_summaries
->get (node
)
3609 modref_summary_lto
*cur_summary_lto
= summaries_lto
3610 ? summaries_lto
->get (node
)
3613 if (!cur_summary
&& !cur_summary_lto
)
3616 int cur_ecf_flags
= flags_from_decl_or_type (node
->decl
);
3619 fprintf (dump_file
, " Processing %s%s%s\n",
3621 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3622 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3624 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
3626 if (e
->indirect_info
->ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
3629 fprintf (dump_file
, " Indirect call"
3630 "collapsing loads\n");
3631 if (propagate_unknown_call
3632 (node
, e
, e
->indirect_info
->ecf_flags
,
3633 cur_summary
, cur_summary_lto
))
3636 remove_useless_summaries (node
, &cur_summary
,
3639 if (!cur_summary
&& !cur_summary_lto
)
3644 if (!cur_summary
&& !cur_summary_lto
)
3647 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
3648 callee_edge
= callee_edge
->next_callee
)
3650 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
3651 modref_summary
*callee_summary
= NULL
;
3652 modref_summary_lto
*callee_summary_lto
= NULL
;
3653 struct cgraph_node
*callee
;
3655 if (flags
& (ECF_CONST
| ECF_NOVOPS
)
3656 || !callee_edge
->inline_failed
)
3659 /* Get the callee and its summary. */
3660 enum availability avail
;
3661 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
3664 /* It is not necessary to re-process calls outside of the
3668 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
3669 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
3673 fprintf (dump_file
, " Call to %s\n",
3674 callee_edge
->callee
->dump_name ());
3676 bool ignore_stores
= ignore_stores_p (cur
->decl
, flags
);
3678 if (avail
<= AVAIL_INTERPOSABLE
)
3681 fprintf (dump_file
, " Call target interposable"
3682 " or not available\n");
3683 changed
|= propagate_unknown_call
3684 (node
, callee_edge
, flags
,
3685 cur_summary
, cur_summary_lto
);
3686 if (!cur_summary
&& !cur_summary_lto
)
3691 /* We don't know anything about CALLEE, hence we cannot tell
3692 anything about the entire component. */
3695 && !(callee_summary
= optimization_summaries
->get (callee
)))
3698 fprintf (dump_file
, " No call target summary\n");
3699 changed
|= propagate_unknown_call
3700 (node
, callee_edge
, flags
,
3704 && !(callee_summary_lto
= summaries_lto
->get (callee
)))
3707 fprintf (dump_file
, " No call target summary\n");
3708 changed
|= propagate_unknown_call
3709 (node
, callee_edge
, flags
,
3710 NULL
, cur_summary_lto
);
3713 /* We can not safely optimize based on summary of callee if it
3714 does not always bind to current def: it is possible that
3715 memory load was optimized out earlier which may not happen in
3716 the interposed variant. */
3717 if (!callee_edge
->binds_to_current_def_p ())
3719 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
3721 fprintf (dump_file
, " May not bind local;"
3722 " collapsing loads\n");
3726 auto_vec
<modref_parm_map
, 32> parm_map
;
3728 compute_parm_map (callee_edge
, &parm_map
);
3730 /* Merge in callee's information. */
3733 changed
|= cur_summary
->loads
->merge
3734 (callee_summary
->loads
, &parm_map
, !first
);
3737 changed
|= cur_summary
->stores
->merge
3738 (callee_summary
->stores
, &parm_map
,
3740 if (!cur_summary
->writes_errno
3741 && callee_summary
->writes_errno
)
3743 cur_summary
->writes_errno
= true;
3748 if (callee_summary_lto
)
3750 changed
|= cur_summary_lto
->loads
->merge
3751 (callee_summary_lto
->loads
, &parm_map
,
3755 changed
|= cur_summary_lto
->stores
->merge
3756 (callee_summary_lto
->stores
, &parm_map
,
3758 if (!cur_summary_lto
->writes_errno
3759 && callee_summary_lto
->writes_errno
)
3761 cur_summary_lto
->writes_errno
= true;
3767 remove_useless_summaries (node
, &cur_summary
,
3770 if (!cur_summary
&& !cur_summary_lto
)
3772 if (dump_file
&& changed
)
3775 cur_summary
->dump (dump_file
);
3776 if (cur_summary_lto
)
3777 cur_summary_lto
->dump (dump_file
);
3778 dump_modref_edge_summaries (dump_file
, node
, 4);
3787 "Propagation finished in %i iterations\n", iteration
);
3790 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
3793 modref_propagate_dump_scc (cgraph_node
*component_node
)
3795 for (struct cgraph_node
*cur
= component_node
; cur
;
3796 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3797 if (!cur
->inlined_to
)
3799 modref_summary
*cur_summary
= optimization_summaries
3800 ? optimization_summaries
->get (cur
)
3802 modref_summary_lto
*cur_summary_lto
= summaries_lto
3803 ? summaries_lto
->get (cur
)
3806 fprintf (dump_file
, "Propagated modref for %s%s%s\n",
3808 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3809 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3810 if (optimization_summaries
)
3813 cur_summary
->dump (dump_file
);
3815 fprintf (dump_file
, " Not tracked\n");
3819 if (cur_summary_lto
)
3820 cur_summary_lto
->dump (dump_file
);
3822 fprintf (dump_file
, " Not tracked (lto)\n");
3827 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
3828 and SUMMARY_LTO to CUR_SUMMARY_LTO.
3829 Return true if something changed. */
3832 modref_merge_call_site_flags (escape_summary
*sum
,
3833 modref_summary
*cur_summary
,
3834 modref_summary_lto
*cur_summary_lto
,
3835 modref_summary
*summary
,
3836 modref_summary_lto
*summary_lto
,
3842 bool changed
= false;
3843 bool ignore_stores
= ignore_stores_p (caller
, ecf_flags
);
3845 /* If we have no useful info to propagate. */
3846 if ((!cur_summary
|| !cur_summary
->arg_flags
.length ())
3847 && (!cur_summary_lto
|| !cur_summary_lto
->arg_flags
.length ()))
3850 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3855 if (summary
&& ee
->arg
< summary
->arg_flags
.length ())
3856 flags
= summary
->arg_flags
[ee
->arg
];
3858 && ee
->arg
< summary_lto
->arg_flags
.length ())
3859 flags_lto
= summary_lto
->arg_flags
[ee
->arg
];
3862 flags
= deref_flags (flags
, ignore_stores
);
3863 flags_lto
= deref_flags (flags_lto
, ignore_stores
);
3865 else if (ignore_stores
)
3867 flags
|= ignore_stores_eaf_flags
;
3868 flags_lto
|= ignore_stores_eaf_flags
;
3870 /* Returning the value is already accounted to at local propagation. */
3871 flags
|= ee
->min_flags
| EAF_NOT_RETURNED
| EAF_NOT_RETURNED_DIRECTLY
;
3872 flags_lto
|= ee
->min_flags
| EAF_NOT_RETURNED
| EAF_NOT_RETURNED_DIRECTLY
;
3873 /* Noescape implies that value also does not escape directly.
3874 Fnspec machinery does set both so compensate for this. */
3875 if (flags
& EAF_NOESCAPE
)
3876 flags
|= EAF_NODIRECTESCAPE
;
3877 if (flags_lto
& EAF_NOESCAPE
)
3878 flags_lto
|= EAF_NODIRECTESCAPE
;
3879 if (flags
& EAF_NOT_RETURNED
)
3880 flags
|= EAF_NOT_RETURNED_DIRECTLY
;
3881 if (flags_lto
& EAF_NOT_RETURNED
)
3882 flags_lto
|= EAF_NOT_RETURNED_DIRECTLY
;
3883 if (!(flags
& EAF_UNUSED
)
3884 && cur_summary
&& ee
->parm_index
< (int)cur_summary
->arg_flags
.length ())
3886 eaf_flags_t
&f
= ee
->parm_index
== escape_point::retslot_arg
3887 ? cur_summary
->retslot_flags
3888 : ee
->parm_index
== escape_point::static_chain_arg
3889 ? cur_summary
->static_chain_flags
3890 : cur_summary
->arg_flags
[ee
->parm_index
];
3891 if ((f
& flags
) != f
)
3893 f
= remove_useless_eaf_flags
3894 (f
& flags
, ecf_flags
,
3895 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
3899 if (!(flags_lto
& EAF_UNUSED
)
3901 && ee
->parm_index
< (int)cur_summary_lto
->arg_flags
.length ())
3903 eaf_flags_t
&f
= ee
->parm_index
== escape_point::retslot_arg
3904 ? cur_summary_lto
->retslot_flags
3905 : ee
->parm_index
== escape_point::static_chain_arg
3906 ? cur_summary_lto
->static_chain_flags
3907 : cur_summary_lto
->arg_flags
[ee
->parm_index
];
3908 if ((f
& flags_lto
) != f
)
3910 f
= remove_useless_eaf_flags
3911 (f
& flags_lto
, ecf_flags
,
3912 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
3920 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3921 and propagate arg flags. */
3924 modref_propagate_flags_in_scc (cgraph_node
*component_node
)
3926 bool changed
= true;
3932 for (struct cgraph_node
*cur
= component_node
; cur
;
3933 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3935 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
3936 modref_summary
*cur_summary
= optimization_summaries
3937 ? optimization_summaries
->get (node
)
3939 modref_summary_lto
*cur_summary_lto
= summaries_lto
3940 ? summaries_lto
->get (node
)
3943 if (!cur_summary
&& !cur_summary_lto
)
3947 fprintf (dump_file
, " Processing %s%s%s\n",
3949 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3950 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3952 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
3954 escape_summary
*sum
= escape_summaries
->get (e
);
3956 if (!sum
|| (e
->indirect_info
->ecf_flags
3957 & (ECF_CONST
| ECF_NOVOPS
)))
3960 changed
|= modref_merge_call_site_flags
3961 (sum
, cur_summary
, cur_summary_lto
,
3963 node
->decl
, e
->indirect_info
->ecf_flags
);
3966 if (!cur_summary
&& !cur_summary_lto
)
3969 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
3970 callee_edge
= callee_edge
->next_callee
)
3972 int ecf_flags
= flags_from_decl_or_type
3973 (callee_edge
->callee
->decl
);
3974 modref_summary
*callee_summary
= NULL
;
3975 modref_summary_lto
*callee_summary_lto
= NULL
;
3976 struct cgraph_node
*callee
;
3978 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)
3979 || !callee_edge
->inline_failed
)
3981 /* Get the callee and its summary. */
3982 enum availability avail
;
3983 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
3986 /* It is not necessary to re-process calls outside of the
3990 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
3991 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
3994 escape_summary
*sum
= escape_summaries
->get (callee_edge
);
3999 fprintf (dump_file
, " Call to %s\n",
4000 callee_edge
->callee
->dump_name ());
4002 if (avail
<= AVAIL_INTERPOSABLE
4003 || callee_edge
->call_stmt_cannot_inline_p
)
4008 callee_summary
= optimization_summaries
->get (callee
);
4009 if (cur_summary_lto
)
4010 callee_summary_lto
= summaries_lto
->get (callee
);
4012 changed
|= modref_merge_call_site_flags
4013 (sum
, cur_summary
, cur_summary_lto
,
4014 callee_summary
, callee_summary_lto
,
4015 node
->decl
, ecf_flags
);
4016 if (dump_file
&& changed
)
4019 cur_summary
->dump (dump_file
);
4020 if (cur_summary_lto
)
4021 cur_summary_lto
->dump (dump_file
);
4029 "Propagation of flags finished in %i iterations\n", iteration
);
4032 } /* ANON namespace. */
4034 /* Call EDGE was inlined; merge summary from callee to the caller. */
4037 ipa_merge_modref_summary_after_inlining (cgraph_edge
*edge
)
4039 if (!summaries
&& !summaries_lto
)
4042 struct cgraph_node
*to
= (edge
->caller
->inlined_to
4043 ? edge
->caller
->inlined_to
: edge
->caller
);
4044 class modref_summary
*to_info
= summaries
? summaries
->get (to
) : NULL
;
4045 class modref_summary_lto
*to_info_lto
= summaries_lto
4046 ? summaries_lto
->get (to
) : NULL
;
4048 if (!to_info
&& !to_info_lto
)
4051 summaries
->remove (edge
->callee
);
4053 summaries_lto
->remove (edge
->callee
);
4054 remove_modref_edge_summaries (edge
->callee
);
4058 class modref_summary
*callee_info
= summaries
? summaries
->get (edge
->callee
)
4060 class modref_summary_lto
*callee_info_lto
4061 = summaries_lto
? summaries_lto
->get (edge
->callee
) : NULL
;
4062 int flags
= flags_from_decl_or_type (edge
->callee
->decl
);
4063 bool ignore_stores
= ignore_stores_p (edge
->caller
->decl
, flags
);
4065 if (!callee_info
&& to_info
)
4067 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
4068 to_info
->loads
->collapse ();
4070 to_info
->stores
->collapse ();
4072 if (!callee_info_lto
&& to_info_lto
)
4074 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
4075 to_info_lto
->loads
->collapse ();
4077 to_info_lto
->stores
->collapse ();
4079 if (callee_info
|| callee_info_lto
)
4081 auto_vec
<modref_parm_map
, 32> parm_map
;
4083 compute_parm_map (edge
, &parm_map
);
4087 if (to_info
&& callee_info
)
4088 to_info
->stores
->merge (callee_info
->stores
, &parm_map
, false);
4089 if (to_info_lto
&& callee_info_lto
)
4090 to_info_lto
->stores
->merge (callee_info_lto
->stores
, &parm_map
,
4093 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
4095 if (to_info
&& callee_info
)
4096 to_info
->loads
->merge (callee_info
->loads
, &parm_map
, false);
4097 if (to_info_lto
&& callee_info_lto
)
4098 to_info_lto
->loads
->merge (callee_info_lto
->loads
, &parm_map
,
4103 /* Now merge escape summaries.
4104 For every escape to the callee we need to merge calle flags
4105 and remap calees escapes. */
4106 class escape_summary
*sum
= escape_summaries
->get (edge
);
4107 int max_escape
= -1;
4111 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
4112 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
4113 if ((int)ee
->arg
> max_escape
)
4114 max_escape
= ee
->arg
;
4116 auto_vec
<vec
<struct escape_map
>, 32> emap (max_escape
+ 1);
4117 emap
.safe_grow (max_escape
+ 1, true);
4118 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
4121 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
4122 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
4124 bool needed
= false;
4125 /* TODO: We do not have jump functions for return slots, so we
4126 never propagate them to outer function. */
4127 if (ee
->parm_index
< 0)
4129 if (to_info
&& (int)to_info
->arg_flags
.length () > ee
->parm_index
)
4131 int flags
= callee_info
4132 && callee_info
->arg_flags
.length () > ee
->arg
4133 ? callee_info
->arg_flags
[ee
->arg
] : 0;
4135 flags
= deref_flags (flags
, ignore_stores
);
4136 else if (ignore_stores
)
4137 flags
|= ignore_stores_eaf_flags
;
4138 flags
|= ee
->min_flags
;
4139 to_info
->arg_flags
[ee
->parm_index
] &= flags
;
4140 if (to_info
->arg_flags
[ee
->parm_index
])
4144 && (int)to_info_lto
->arg_flags
.length () > ee
->parm_index
)
4146 int flags
= callee_info_lto
4147 && callee_info_lto
->arg_flags
.length () > ee
->arg
4148 ? callee_info_lto
->arg_flags
[ee
->arg
] : 0;
4150 flags
= deref_flags (flags
, ignore_stores
);
4151 else if (ignore_stores
)
4152 flags
|= ignore_stores_eaf_flags
;
4153 flags
|= ee
->min_flags
;
4154 to_info_lto
->arg_flags
[ee
->parm_index
] &= flags
;
4155 if (to_info_lto
->arg_flags
[ee
->parm_index
])
4158 struct escape_map entry
= {ee
->parm_index
, ee
->direct
};
4160 emap
[ee
->arg
].safe_push (entry
);
4162 update_escape_summary (edge
->callee
, emap
, ignore_stores
);
4163 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
4166 escape_summaries
->remove (edge
);
4170 if (to_info
&& !to_info
->useful_p (flags
))
4173 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
4175 summaries
->remove (to
);
4178 else if (to_info
&& dump_file
)
4181 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
4183 to_info
->dump (dump_file
);
4186 summaries
->remove (edge
->callee
);
4190 if (to_info_lto
&& !to_info_lto
->useful_p (flags
))
4193 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
4195 summaries_lto
->remove (to
);
4197 else if (to_info_lto
&& dump_file
)
4200 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
4202 to_info_lto
->dump (dump_file
);
4205 if (callee_info_lto
)
4206 summaries_lto
->remove (edge
->callee
);
4208 if (!to_info
&& !to_info_lto
)
4209 remove_modref_edge_summaries (to
);
4213 /* Run the IPA pass. This will take a function's summaries and calls and
4214 construct new summaries which represent a transitive closure. So that
4215 summary of an analyzed function contains information about the loads and
4216 stores that the function or any function that it calls does. */
4219 pass_ipa_modref::execute (function
*)
4221 if (!summaries
&& !summaries_lto
)
4224 if (optimization_summaries
)
4225 ggc_delete (optimization_summaries
);
4226 optimization_summaries
= summaries
;
4229 struct cgraph_node
**order
= XCNEWVEC (struct cgraph_node
*,
4230 symtab
->cgraph_count
);
4232 order_pos
= ipa_reduced_postorder (order
, true, ignore_edge
);
4235 /* Iterate over all strongly connected components in post-order. */
4236 for (i
= 0; i
< order_pos
; i
++)
4238 /* Get the component's representative. That's just any node in the
4239 component from which we can traverse the entire component. */
4240 struct cgraph_node
*component_node
= order
[i
];
4243 fprintf (dump_file
, "\n\nStart of SCC component\n");
4245 modref_propagate_in_scc (component_node
);
4246 modref_propagate_flags_in_scc (component_node
);
4248 modref_propagate_dump_scc (component_node
);
4251 FOR_EACH_FUNCTION (node
)
4252 update_signature (node
);
4254 ((modref_summaries_lto
*)summaries_lto
)->propagated
= true;
4255 ipa_free_postorder_info ();
4257 delete fnspec_summaries
;
4258 fnspec_summaries
= NULL
;
4259 delete escape_summaries
;
4260 escape_summaries
= NULL
;
4264 /* Summaries must stay alive until end of compilation. */
4267 ipa_modref_c_finalize ()
4269 if (optimization_summaries
)
4270 ggc_delete (optimization_summaries
);
4271 optimization_summaries
= NULL
;
4272 gcc_checking_assert (!summaries
4273 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
4275 ggc_delete (summaries_lto
);
4276 summaries_lto
= NULL
;
4277 if (fnspec_summaries
)
4278 delete fnspec_summaries
;
4279 fnspec_summaries
= NULL
;
4280 if (escape_summaries
)
4281 delete escape_summaries
;
4282 escape_summaries
= NULL
;
4285 #include "gt-ipa-modref.h"