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"
91 /* We record fnspec specifiers for call edges since they depends on actual
110 /* Summary holding fnspec string for a given call. */
112 class fnspec_summaries_t
: public call_summary
<fnspec_summary
*>
115 fnspec_summaries_t (symbol_table
*symtab
)
116 : call_summary
<fnspec_summary
*> (symtab
) {}
117 /* Hook that is called by summary when an edge is duplicated. */
118 virtual void duplicate (cgraph_edge
*,
123 dst
->fnspec
= xstrdup (src
->fnspec
);
127 static fnspec_summaries_t
*fnspec_summaries
= NULL
;
129 /* Escape summary holds a vector of param indexes that escape to
133 /* Parameter that escapes at a given call. */
134 unsigned int parm_index
;
135 /* Argument it escapes to. */
137 /* Minimal flags known about the argument. */
139 /* Does it escape directly or indirectly? */
143 /* Dump EAF flags. */
146 dump_eaf_flags (FILE *out
, int flags
, bool newline
= true)
148 if (flags
& EAF_DIRECT
)
149 fprintf (out
, " direct");
150 if (flags
& EAF_NOCLOBBER
)
151 fprintf (out
, " noclobber");
152 if (flags
& EAF_NOESCAPE
)
153 fprintf (out
, " noescape");
154 if (flags
& EAF_NODIRECTESCAPE
)
155 fprintf (out
, " nodirectescape");
156 if (flags
& EAF_UNUSED
)
157 fprintf (out
, " unused");
162 struct escape_summary
164 auto_vec
<escape_entry
> esc
;
165 void dump (FILE *out
)
167 for (unsigned int i
= 0; i
< esc
.length (); i
++)
169 fprintf (out
, " parm %i arg %i %s min:",
172 esc
[i
].direct
? "(direct)" : "(indirect)");
173 dump_eaf_flags (out
, esc
[i
].min_flags
, false);
179 class escape_summaries_t
: public call_summary
<escape_summary
*>
182 escape_summaries_t (symbol_table
*symtab
)
183 : call_summary
<escape_summary
*> (symtab
) {}
184 /* Hook that is called by summary when an edge is duplicated. */
185 virtual void duplicate (cgraph_edge
*,
190 dst
->esc
= src
->esc
.copy ();
194 static escape_summaries_t
*escape_summaries
= NULL
;
196 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
199 /* Class (from which there is one global instance) that holds modref summaries
200 for all analyzed functions. */
202 class GTY((user
)) modref_summaries
203 : public fast_function_summary
<modref_summary
*, va_gc
>
206 modref_summaries (symbol_table
*symtab
)
207 : fast_function_summary
<modref_summary
*, va_gc
> (symtab
) {}
208 virtual void insert (cgraph_node
*, modref_summary
*state
);
209 virtual void duplicate (cgraph_node
*src_node
,
210 cgraph_node
*dst_node
,
211 modref_summary
*src_data
,
212 modref_summary
*dst_data
);
213 static modref_summaries
*create_ggc (symbol_table
*symtab
)
215 return new (ggc_alloc_no_dtor
<modref_summaries
> ())
216 modref_summaries (symtab
);
220 class modref_summary_lto
;
222 /* Class (from which there is one global instance) that holds modref summaries
223 for all analyzed functions. */
225 class GTY((user
)) modref_summaries_lto
226 : public fast_function_summary
<modref_summary_lto
*, va_gc
>
229 modref_summaries_lto (symbol_table
*symtab
)
230 : fast_function_summary
<modref_summary_lto
*, va_gc
> (symtab
),
231 propagated (false) {}
232 virtual void insert (cgraph_node
*, modref_summary_lto
*state
);
233 virtual void duplicate (cgraph_node
*src_node
,
234 cgraph_node
*dst_node
,
235 modref_summary_lto
*src_data
,
236 modref_summary_lto
*dst_data
);
237 static modref_summaries_lto
*create_ggc (symbol_table
*symtab
)
239 return new (ggc_alloc_no_dtor
<modref_summaries_lto
> ())
240 modref_summaries_lto (symtab
);
245 /* Global variable holding all modref summaries
246 (from analysis to IPA propagation time). */
248 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
251 /* Global variable holding all modref optimization summaries
252 (from IPA propagation time or used by local optimization pass). */
254 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
255 *optimization_summaries
;
257 /* LTO summaries hold info from analysis to LTO streaming or from LTO
258 stream-in through propagation to LTO stream-out. */
260 static GTY(()) fast_function_summary
<modref_summary_lto
*, va_gc
>
263 /* Summary for a single function which this pass produces. */
265 modref_summary::modref_summary ()
266 : loads (NULL
), stores (NULL
), writes_errno (NULL
)
270 modref_summary::~modref_summary ()
278 /* Return true if FLAGS holds some useful information. */
281 eaf_flags_useful_p (vec
<unsigned char> &flags
, int ecf_flags
)
283 for (unsigned i
= 0; i
< flags
.length (); i
++)
284 if (ecf_flags
& ECF_PURE
)
286 if (flags
[i
] & (EAF_UNUSED
| EAF_DIRECT
))
297 /* Return true if summary is potentially useful for optimization.
298 If CHECK_FLAGS is false assume that arg_flags are useful. */
301 modref_summary::useful_p (int ecf_flags
, bool check_flags
)
303 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
305 if (arg_flags
.length () && !check_flags
)
307 if (check_flags
&& eaf_flags_useful_p (arg_flags
, ecf_flags
))
309 arg_flags
.release ();
310 if (loads
&& !loads
->every_base
)
312 if (ecf_flags
& ECF_PURE
)
314 return stores
&& !stores
->every_base
;
317 /* Single function summary used for LTO. */
319 typedef modref_tree
<tree
> modref_records_lto
;
320 struct GTY(()) modref_summary_lto
322 /* Load and stores in functions using types rather then alias sets.
324 This is necessary to make the information streamable for LTO but is also
325 more verbose and thus more likely to hit the limits. */
326 modref_records_lto
*loads
;
327 modref_records_lto
*stores
;
328 auto_vec
<unsigned char> GTY((skip
)) arg_flags
;
331 modref_summary_lto ();
332 ~modref_summary_lto ();
334 bool useful_p (int ecf_flags
, bool check_flags
= true);
337 /* Summary for a single function which this pass produces. */
339 modref_summary_lto::modref_summary_lto ()
340 : loads (NULL
), stores (NULL
), writes_errno (NULL
)
344 modref_summary_lto::~modref_summary_lto ()
353 /* Return true if lto summary is potentially useful for optimization.
354 If CHECK_FLAGS is false assume that arg_flags are useful. */
357 modref_summary_lto::useful_p (int ecf_flags
, bool check_flags
)
359 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
361 if (arg_flags
.length () && !check_flags
)
363 if (check_flags
&& eaf_flags_useful_p (arg_flags
, ecf_flags
))
365 arg_flags
.release ();
366 if (loads
&& !loads
->every_base
)
368 if (ecf_flags
& ECF_PURE
)
370 return stores
&& !stores
->every_base
;
376 dump_access (modref_access_node
*a
, FILE *out
)
378 fprintf (out
, " access:");
379 if (a
->parm_index
!= -1)
381 fprintf (out
, " Parm %i", a
->parm_index
);
382 if (a
->parm_offset_known
)
384 fprintf (out
, " param offset:");
385 print_dec ((poly_int64_pod
)a
->parm_offset
, out
, SIGNED
);
388 if (a
->range_info_useful_p ())
390 fprintf (out
, " offset:");
391 print_dec ((poly_int64_pod
)a
->offset
, out
, SIGNED
);
392 fprintf (out
, " size:");
393 print_dec ((poly_int64_pod
)a
->size
, out
, SIGNED
);
394 fprintf (out
, " max_size:");
395 print_dec ((poly_int64_pod
)a
->max_size
, out
, SIGNED
);
400 /* Dump records TT to OUT. */
403 dump_records (modref_records
*tt
, FILE *out
)
405 fprintf (out
, " Limits: %i bases, %i refs\n",
406 (int)tt
->max_bases
, (int)tt
->max_refs
);
409 fprintf (out
, " Every base\n");
413 modref_base_node
<alias_set_type
> *n
;
414 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
416 fprintf (out
, " Base %i: alias set %i\n", (int)i
, n
->base
);
419 fprintf (out
, " Every ref\n");
423 modref_ref_node
<alias_set_type
> *r
;
424 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
426 fprintf (out
, " Ref %i: alias set %i\n", (int)j
, r
->ref
);
429 fprintf (out
, " Every access\n");
433 modref_access_node
*a
;
434 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
435 dump_access (a
, out
);
440 /* Dump records TT to OUT. */
443 dump_lto_records (modref_records_lto
*tt
, FILE *out
)
445 fprintf (out
, " Limits: %i bases, %i refs\n",
446 (int)tt
->max_bases
, (int)tt
->max_refs
);
449 fprintf (out
, " Every base\n");
453 modref_base_node
<tree
> *n
;
454 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
456 fprintf (out
, " Base %i:", (int)i
);
457 print_generic_expr (dump_file
, n
->base
);
458 fprintf (out
, " (alias set %i)\n",
459 n
->base
? get_alias_set (n
->base
) : 0);
462 fprintf (out
, " Every ref\n");
466 modref_ref_node
<tree
> *r
;
467 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
469 fprintf (out
, " Ref %i:", (int)j
);
470 print_generic_expr (dump_file
, r
->ref
);
471 fprintf (out
, " (alias set %i)\n",
472 r
->ref
? get_alias_set (r
->ref
) : 0);
475 fprintf (out
, " Every access\n");
479 modref_access_node
*a
;
480 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
481 dump_access (a
, out
);
486 /* Dump all escape points of NODE to OUT. */
489 dump_modref_edge_summaries (FILE *out
, cgraph_node
*node
, int depth
)
492 if (!escape_summaries
)
494 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
496 class escape_summary
*sum
= escape_summaries
->get (e
);
499 fprintf (out
, "%*sIndirect call %i in %s escapes:",
500 depth
, "", i
, node
->dump_name ());
505 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
507 if (!e
->inline_failed
)
508 dump_modref_edge_summaries (out
, e
->callee
, depth
+ 1);
509 class escape_summary
*sum
= escape_summaries
->get (e
);
512 fprintf (out
, "%*sCall %s->%s escapes:", depth
, "",
513 node
->dump_name (), e
->callee
->dump_name ());
516 class fnspec_summary
*fsum
= fnspec_summaries
->get (e
);
519 fprintf (out
, "%*sCall %s->%s fnspec: %s\n", depth
, "",
520 node
->dump_name (), e
->callee
->dump_name (),
526 /* Remove all call edge summaries associated with NODE. */
529 remove_modref_edge_summaries (cgraph_node
*node
)
531 if (!escape_summaries
)
533 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
534 escape_summaries
->remove (e
);
535 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
537 if (!e
->inline_failed
)
538 remove_modref_edge_summaries (e
->callee
);
539 escape_summaries
->remove (e
);
540 fnspec_summaries
->remove (e
);
547 modref_summary::dump (FILE *out
)
551 fprintf (out
, " loads:\n");
552 dump_records (loads
, out
);
556 fprintf (out
, " stores:\n");
557 dump_records (stores
, out
);
560 fprintf (out
, " Writes errno\n");
561 if (arg_flags
.length ())
563 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
566 fprintf (out
, " parm %i flags:", i
);
567 dump_eaf_flags (out
, arg_flags
[i
]);
575 modref_summary_lto::dump (FILE *out
)
577 fprintf (out
, " loads:\n");
578 dump_lto_records (loads
, out
);
579 fprintf (out
, " stores:\n");
580 dump_lto_records (stores
, out
);
582 fprintf (out
, " Writes errno\n");
583 if (arg_flags
.length ())
585 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
588 fprintf (out
, " parm %i flags:", i
);
589 dump_eaf_flags (out
, arg_flags
[i
]);
594 /* Get function summary for FUNC if it exists, return NULL otherwise. */
597 get_modref_function_summary (cgraph_node
*func
)
599 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
600 if (!optimization_summaries
)
603 /* A single function body may be represented by multiple symbols with
604 different visibility. For example, if FUNC is an interposable alias,
605 we don't want to return anything, even if we have summary for the target
607 enum availability avail
;
608 func
= func
->function_or_virtual_thunk_symbol
609 (&avail
, current_function_decl
?
610 cgraph_node::get (current_function_decl
) : NULL
);
611 if (avail
<= AVAIL_INTERPOSABLE
)
614 modref_summary
*r
= optimization_summaries
->get (func
);
618 /* Construct modref_access_node from REF. */
619 static modref_access_node
620 get_access (ao_ref
*ref
)
624 base
= ao_ref_base (ref
);
625 modref_access_node a
= {ref
->offset
, ref
->size
, ref
->max_size
,
627 if (TREE_CODE (base
) == MEM_REF
|| TREE_CODE (base
) == TARGET_MEM_REF
)
630 base
= TREE_OPERAND (base
, 0);
631 if (TREE_CODE (base
) == SSA_NAME
632 && SSA_NAME_IS_DEFAULT_DEF (base
)
633 && TREE_CODE (SSA_NAME_VAR (base
)) == PARM_DECL
)
636 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
637 t
!= SSA_NAME_VAR (base
); t
= DECL_CHAIN (t
))
646 if (TREE_CODE (memref
) == MEM_REF
)
649 = wi::to_poly_wide (TREE_OPERAND
650 (memref
, 1)).to_shwi (&a
.parm_offset
);
653 a
.parm_offset_known
= false;
663 /* Record access into the modref_records data structure. */
666 record_access (modref_records
*tt
, ao_ref
*ref
)
668 alias_set_type base_set
= !flag_strict_aliasing
? 0
669 : ao_ref_base_alias_set (ref
);
670 alias_set_type ref_set
= !flag_strict_aliasing
? 0
671 : (ao_ref_alias_set (ref
));
672 modref_access_node a
= get_access (ref
);
675 fprintf (dump_file
, " - Recording base_set=%i ref_set=%i parm=%i\n",
676 base_set
, ref_set
, a
.parm_index
);
678 tt
->insert (base_set
, ref_set
, a
);
681 /* IPA version of record_access_tree. */
684 record_access_lto (modref_records_lto
*tt
, ao_ref
*ref
)
686 /* get_alias_set sometimes use different type to compute the alias set
687 than TREE_TYPE (base). Do same adjustments. */
688 tree base_type
= NULL_TREE
, ref_type
= NULL_TREE
;
689 if (flag_strict_aliasing
)
694 while (handled_component_p (base
))
695 base
= TREE_OPERAND (base
, 0);
697 base_type
= reference_alias_ptr_type_1 (&base
);
700 base_type
= TREE_TYPE (base
);
702 base_type
= TYPE_REF_CAN_ALIAS_ALL (base_type
)
703 ? NULL_TREE
: TREE_TYPE (base_type
);
705 tree ref_expr
= ref
->ref
;
706 ref_type
= reference_alias_ptr_type_1 (&ref_expr
);
709 ref_type
= TREE_TYPE (ref_expr
);
711 ref_type
= TYPE_REF_CAN_ALIAS_ALL (ref_type
)
712 ? NULL_TREE
: TREE_TYPE (ref_type
);
714 /* Sanity check that we are in sync with what get_alias_set does. */
715 gcc_checking_assert ((!base_type
&& !ao_ref_base_alias_set (ref
))
716 || get_alias_set (base_type
)
717 == ao_ref_base_alias_set (ref
));
718 gcc_checking_assert ((!ref_type
&& !ao_ref_alias_set (ref
))
719 || get_alias_set (ref_type
)
720 == ao_ref_alias_set (ref
));
722 /* Do not bother to record types that have no meaningful alias set.
723 Also skip variably modified types since these go to local streams. */
724 if (base_type
&& (!get_alias_set (base_type
)
725 || variably_modified_type_p (base_type
, NULL_TREE
)))
726 base_type
= NULL_TREE
;
727 if (ref_type
&& (!get_alias_set (ref_type
)
728 || variably_modified_type_p (ref_type
, NULL_TREE
)))
729 ref_type
= NULL_TREE
;
731 modref_access_node a
= get_access (ref
);
734 fprintf (dump_file
, " - Recording base type:");
735 print_generic_expr (dump_file
, base_type
);
736 fprintf (dump_file
, " (alias set %i) ref type:",
737 base_type
? get_alias_set (base_type
) : 0);
738 print_generic_expr (dump_file
, ref_type
);
739 fprintf (dump_file
, " (alias set %i) parm:%i\n",
740 ref_type
? get_alias_set (ref_type
) : 0,
744 tt
->insert (base_type
, ref_type
, a
);
747 /* Returns true if and only if we should store the access to EXPR.
748 Some accesses, e.g. loads from automatic variables, are not interesting. */
751 record_access_p (tree expr
)
753 if (refs_local_or_readonly_memory_p (expr
))
756 fprintf (dump_file
, " - Read-only or local, ignoring.\n");
762 /* Return true if ECF flags says that return value can be ignored. */
765 ignore_retval_p (tree caller
, int flags
)
767 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
768 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
773 /* Return true if ECF flags says that stores can be ignored. */
776 ignore_stores_p (tree caller
, int flags
)
778 if (flags
& (ECF_PURE
| ECF_CONST
| ECF_NOVOPS
))
780 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
781 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
786 /* Determine parm_map for argument I of STMT. */
789 parm_map_for_arg (gimple
*stmt
, int i
)
791 tree op
= gimple_call_arg (stmt
, i
);
794 struct modref_parm_map parm_map
;
796 parm_map
.parm_offset_known
= false;
797 parm_map
.parm_offset
= 0;
799 offset_known
= unadjusted_ptr_and_unit_offset (op
, &op
, &offset
);
800 if (TREE_CODE (op
) == SSA_NAME
801 && SSA_NAME_IS_DEFAULT_DEF (op
)
802 && TREE_CODE (SSA_NAME_VAR (op
)) == PARM_DECL
)
805 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
806 t
!= SSA_NAME_VAR (op
); t
= DECL_CHAIN (t
))
815 parm_map
.parm_index
= index
;
816 parm_map
.parm_offset_known
= offset_known
;
817 parm_map
.parm_offset
= offset
;
819 else if (points_to_local_or_readonly_memory_p (op
))
820 parm_map
.parm_index
= -2;
822 parm_map
.parm_index
= -1;
826 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
827 int CUR_SUMMARY. Return true if something changed.
828 If IGNORE_STORES is true, do not merge stores. */
831 merge_call_side_effects (modref_summary
*cur_summary
,
832 gimple
*stmt
, modref_summary
*callee_summary
,
833 bool ignore_stores
, cgraph_node
*callee_node
)
835 auto_vec
<modref_parm_map
, 32> parm_map
;
836 bool changed
= false;
838 /* We can not safely optimize based on summary of callee if it does
839 not always bind to current def: it is possible that memory load
840 was optimized out earlier which may not happen in the interposed
842 if (!callee_node
->binds_to_current_def_p ())
845 fprintf (dump_file
, " - May be interposed: collapsing loads.\n");
846 cur_summary
->loads
->collapse ();
850 fprintf (dump_file
, " - Merging side effects of %s with parm map:",
851 callee_node
->dump_name ());
853 parm_map
.safe_grow_cleared (gimple_call_num_args (stmt
), true);
854 for (unsigned i
= 0; i
< gimple_call_num_args (stmt
); i
++)
856 parm_map
[i
] = parm_map_for_arg (stmt
, i
);
859 fprintf (dump_file
, " %i", parm_map
[i
].parm_index
);
860 if (parm_map
[i
].parm_offset_known
)
862 fprintf (dump_file
, " offset:");
863 print_dec ((poly_int64_pod
)parm_map
[i
].parm_offset
,
869 fprintf (dump_file
, "\n");
871 /* Merge with callee's summary. */
872 changed
|= cur_summary
->loads
->merge (callee_summary
->loads
, &parm_map
);
875 changed
|= cur_summary
->stores
->merge (callee_summary
->stores
,
877 if (!cur_summary
->writes_errno
878 && callee_summary
->writes_errno
)
880 cur_summary
->writes_errno
= true;
887 /* Return access mode for argument I of call STMT with FNSPEC. */
889 static modref_access_node
890 get_access_for_fnspec (gcall
*call
, attr_fnspec
&fnspec
,
891 unsigned int i
, modref_parm_map
&map
)
893 tree size
= NULL_TREE
;
894 unsigned int size_arg
;
896 if (!fnspec
.arg_specified_p (i
))
898 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
899 size
= gimple_call_arg (call
, size_arg
);
900 else if (fnspec
.arg_access_size_given_by_type_p (i
))
902 tree callee
= gimple_call_fndecl (call
);
903 tree t
= TYPE_ARG_TYPES (TREE_TYPE (callee
));
905 for (unsigned int p
= 0; p
< i
; p
++)
907 size
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t
)));
909 modref_access_node a
= {0, -1, -1,
910 map
.parm_offset
, map
.parm_index
,
911 map
.parm_offset_known
};
914 && poly_int_tree_p (size
, &size_hwi
)
915 && coeffs_in_range_p (size_hwi
, 0,
916 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
919 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
924 /* Collapse loads and return true if something changed. */
927 collapse_loads (modref_summary
*cur_summary
,
928 modref_summary_lto
*cur_summary_lto
)
930 bool changed
= false;
932 if (cur_summary
&& !cur_summary
->loads
->every_base
)
934 cur_summary
->loads
->collapse ();
938 && !cur_summary_lto
->loads
->every_base
)
940 cur_summary_lto
->loads
->collapse ();
946 /* Collapse loads and return true if something changed. */
949 collapse_stores (modref_summary
*cur_summary
,
950 modref_summary_lto
*cur_summary_lto
)
952 bool changed
= false;
954 if (cur_summary
&& !cur_summary
->stores
->every_base
)
956 cur_summary
->stores
->collapse ();
960 && !cur_summary_lto
->stores
->every_base
)
962 cur_summary_lto
->stores
->collapse ();
969 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
970 If IGNORE_STORES is true ignore them.
971 Return false if no useful summary can be produced. */
974 process_fnspec (modref_summary
*cur_summary
,
975 modref_summary_lto
*cur_summary_lto
,
976 gcall
*call
, bool ignore_stores
)
978 attr_fnspec fnspec
= gimple_call_fnspec (call
);
979 if (!fnspec
.known_p ())
981 if (dump_file
&& gimple_call_builtin_p (call
, BUILT_IN_NORMAL
))
982 fprintf (dump_file
, " Builtin with no fnspec: %s\n",
983 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call
))));
986 collapse_loads (cur_summary
, cur_summary_lto
);
991 if (fnspec
.global_memory_read_p ())
992 collapse_loads (cur_summary
, cur_summary_lto
);
995 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
996 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
998 else if (!fnspec
.arg_specified_p (i
)
999 || fnspec
.arg_maybe_read_p (i
))
1001 modref_parm_map map
= parm_map_for_arg (call
, i
);
1003 if (map
.parm_index
== -2)
1005 if (map
.parm_index
== -1)
1007 collapse_loads (cur_summary
, cur_summary_lto
);
1011 cur_summary
->loads
->insert (0, 0,
1012 get_access_for_fnspec (call
,
1015 if (cur_summary_lto
)
1016 cur_summary_lto
->loads
->insert (0, 0,
1017 get_access_for_fnspec (call
,
1024 if (fnspec
.global_memory_written_p ())
1025 collapse_stores (cur_summary
, cur_summary_lto
);
1028 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1029 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1031 else if (!fnspec
.arg_specified_p (i
)
1032 || fnspec
.arg_maybe_written_p (i
))
1034 modref_parm_map map
= parm_map_for_arg (call
, i
);
1036 if (map
.parm_index
== -2)
1038 if (map
.parm_index
== -1)
1040 collapse_stores (cur_summary
, cur_summary_lto
);
1044 cur_summary
->stores
->insert (0, 0,
1045 get_access_for_fnspec (call
,
1048 if (cur_summary_lto
)
1049 cur_summary_lto
->stores
->insert (0, 0,
1050 get_access_for_fnspec (call
,
1054 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
1057 cur_summary
->writes_errno
= true;
1058 if (cur_summary_lto
)
1059 cur_summary_lto
->writes_errno
= true;
1065 /* Analyze function call STMT in function F.
1066 Remember recursive calls in RECURSIVE_CALLS. */
1069 analyze_call (modref_summary
*cur_summary
, modref_summary_lto
*cur_summary_lto
,
1070 gcall
*stmt
, vec
<gimple
*> *recursive_calls
)
1072 /* Check flags on the function call. In certain cases, analysis can be
1074 int flags
= gimple_call_flags (stmt
);
1075 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
1079 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1080 "except for args.\n");
1084 /* Pure functions do not affect global memory. Stores by functions which are
1085 noreturn and do not throw can safely be ignored. */
1086 bool ignore_stores
= ignore_stores_p (current_function_decl
, flags
);
1088 /* Next, we try to get the callee's function declaration. The goal is to
1089 merge their summary with ours. */
1090 tree callee
= gimple_call_fndecl (stmt
);
1092 /* Check if this is an indirect call. */
1096 fprintf (dump_file
, gimple_call_internal_p (stmt
)
1097 ? " - Internal call" : " - Indirect call.\n");
1098 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1100 /* We only need to handle internal calls in IPA mode. */
1101 gcc_checking_assert (!cur_summary_lto
);
1103 struct cgraph_node
*callee_node
= cgraph_node::get_create (callee
);
1105 /* If this is a recursive call, the target summary is the same as ours, so
1106 there's nothing to do. */
1107 if (recursive_call_p (current_function_decl
, callee
))
1109 recursive_calls
->safe_push (stmt
);
1111 fprintf (dump_file
, " - Skipping recursive call.\n");
1115 gcc_assert (callee_node
!= NULL
);
1117 /* Get the function symbol and its availability. */
1118 enum availability avail
;
1119 callee_node
= callee_node
->function_symbol (&avail
);
1120 if (avail
<= AVAIL_INTERPOSABLE
)
1123 fprintf (dump_file
, " - Function availability <= AVAIL_INTERPOSABLE.\n");
1124 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1127 /* Get callee's modref summary. As above, if there's no summary, we either
1128 have to give up or, if stores are ignored, we can just purge loads. */
1129 modref_summary
*callee_summary
= optimization_summaries
->get (callee_node
);
1130 if (!callee_summary
)
1133 fprintf (dump_file
, " - No modref summary available for callee.\n");
1134 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1137 merge_call_side_effects (cur_summary
, stmt
, callee_summary
, ignore_stores
,
1143 /* Support analysis in non-lto and lto mode in parallel. */
1147 struct modref_summary
*nolto
;
1148 struct modref_summary_lto
*lto
;
1151 /* Helper for analyze_stmt. */
1154 analyze_load (gimple
*, tree
, tree op
, void *data
)
1156 modref_summary
*summary
= ((summary_ptrs
*)data
)->nolto
;
1157 modref_summary_lto
*summary_lto
= ((summary_ptrs
*)data
)->lto
;
1161 fprintf (dump_file
, " - Analyzing load: ");
1162 print_generic_expr (dump_file
, op
);
1163 fprintf (dump_file
, "\n");
1166 if (!record_access_p (op
))
1170 ao_ref_init (&r
, op
);
1173 record_access (summary
->loads
, &r
);
1175 record_access_lto (summary_lto
->loads
, &r
);
1179 /* Helper for analyze_stmt. */
1182 analyze_store (gimple
*, tree
, tree op
, void *data
)
1184 modref_summary
*summary
= ((summary_ptrs
*)data
)->nolto
;
1185 modref_summary_lto
*summary_lto
= ((summary_ptrs
*)data
)->lto
;
1189 fprintf (dump_file
, " - Analyzing store: ");
1190 print_generic_expr (dump_file
, op
);
1191 fprintf (dump_file
, "\n");
1194 if (!record_access_p (op
))
1198 ao_ref_init (&r
, op
);
1201 record_access (summary
->stores
, &r
);
1203 record_access_lto (summary_lto
->stores
, &r
);
1207 /* Analyze statement STMT of function F.
1208 If IPA is true do not merge in side effects of calls. */
1211 analyze_stmt (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
1212 gimple
*stmt
, bool ipa
, vec
<gimple
*> *recursive_calls
)
1214 /* In general we can not ignore clobbers because they are barriers for code
1215 motion, however after inlining it is safe to do because local optimization
1216 passes do not consider clobbers from other functions.
1217 Similar logic is in ipa-pure-const.c. */
1218 if ((ipa
|| cfun
->after_inlining
) && gimple_clobber_p (stmt
))
1221 struct summary_ptrs sums
= {summary
, summary_lto
};
1223 /* Analyze all loads and stores in STMT. */
1224 walk_stmt_load_store_ops (stmt
, &sums
,
1225 analyze_load
, analyze_store
);
1227 switch (gimple_code (stmt
))
1230 /* If the ASM statement does not read nor write memory, there's nothing
1231 to do. Otherwise just give up. */
1232 if (!gimple_asm_clobbers_memory_p (as_a
<gasm
*> (stmt
)))
1235 fprintf (dump_file
, " - Function contains GIMPLE_ASM statement "
1236 "which clobbers memory.\n");
1239 if (!ipa
|| gimple_call_internal_p (stmt
))
1240 return analyze_call (summary
, summary_lto
,
1241 as_a
<gcall
*> (stmt
), recursive_calls
);
1244 attr_fnspec fnspec
= gimple_call_fnspec (as_a
<gcall
*>(stmt
));
1246 if (fnspec
.known_p ()
1247 && (!fnspec
.global_memory_read_p ()
1248 || !fnspec
.global_memory_written_p ()))
1250 cgraph_edge
*e
= cgraph_node::get (current_function_decl
)->get_edge (stmt
);
1253 fnspec_summaries
->get_create (e
)->fnspec
= xstrdup (fnspec
.get_str ());
1255 fprintf (dump_file
, " Recorded fnspec %s\n", fnspec
.get_str ());
1261 /* Nothing to do for other types of statements. */
1266 /* Remove summary of current function because during the function body
1267 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1271 remove_summary (bool lto
, bool nolto
, bool ipa
)
1273 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1275 optimization_summaries
->remove (fnode
);
1279 summaries
->remove (fnode
);
1281 summaries_lto
->remove (fnode
);
1282 remove_modref_edge_summaries (fnode
);
1286 " - modref done with result: not tracked.\n");
1289 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1292 memory_access_to (tree op
, tree ssa_name
)
1294 tree base
= get_base_address (op
);
1297 if (TREE_CODE (base
) != MEM_REF
&& TREE_CODE (base
) != TARGET_MEM_REF
)
1299 return TREE_OPERAND (base
, 0) == ssa_name
;
1302 /* Consider statement val = *arg.
1303 return EAF flags of ARG that can be determined from EAF flags of VAL
1304 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1305 all stores to VAL, i.e. when handling noreturn function. */
1308 deref_flags (int flags
, bool ignore_stores
)
1310 int ret
= EAF_NODIRECTESCAPE
;
1311 if (flags
& EAF_UNUSED
)
1312 ret
|= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
;
1315 if ((flags
& EAF_NOCLOBBER
) || ignore_stores
)
1316 ret
|= EAF_NOCLOBBER
;
1317 if ((flags
& EAF_NOESCAPE
) || ignore_stores
)
1318 ret
|= EAF_NOESCAPE
;
1325 /* Description of an escape point. */
1329 /* Value escapes to this call. */
1331 /* Argument it escapes to. */
1333 /* Flags already known about the argument (this can save us from recording
1334 esape points if local analysis did good job already). */
1336 /* Does value escape directly or indiretly? */
1340 class modref_lattice
1343 /* EAF flags of the SSA name. */
1345 /* DFS bookkkeeping: we don't do real dataflow yet. */
1349 /* When doing IPA analysis we can not merge in callee escape points;
1350 Only remember them and do the merging at IPA propagation time. */
1351 vec
<escape_point
, va_heap
, vl_ptr
> escape_points
;
1355 bool merge (const modref_lattice
&with
);
1356 bool merge (int flags
);
1357 bool merge_deref (const modref_lattice
&with
, bool ignore_stores
);
1358 bool merge_direct_load ();
1359 bool merge_direct_store ();
1360 bool add_escape_point (gcall
*call
, int arg
, int min_flags
, bool diret
);
1361 void dump (FILE *out
, int indent
= 0) const;
1364 /* Lattices are saved to vectors, so keep them PODs. */
1366 modref_lattice::init ()
1368 flags
= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_UNUSED
1369 | EAF_NODIRECTESCAPE
;
1374 /* Release memory. */
1376 modref_lattice::release ()
1378 escape_points
.release ();
1381 /* Dump lattice to OUT; indent with INDENT spaces. */
1384 modref_lattice::dump (FILE *out
, int indent
) const
1386 dump_eaf_flags (out
, flags
);
1387 if (escape_points
.length ())
1389 fprintf (out
, "%*sEscapes:\n", indent
, "");
1390 for (unsigned int i
= 0; i
< escape_points
.length (); i
++)
1392 fprintf (out
, "%*s Arg %i (%s) min flags", indent
, "",
1393 escape_points
[i
].arg
,
1394 escape_points
[i
].direct
? "direct" : "indirect");
1395 dump_eaf_flags (out
, flags
, false);
1396 fprintf (out
, " in call ");
1397 print_gimple_stmt (out
, escape_points
[i
].call
, 0);
1402 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1406 modref_lattice::add_escape_point (gcall
*call
, int arg
, int min_flags
,
1412 /* If we already determined flags to be bad enough,
1413 * we do not need to record. */
1414 if ((flags
& min_flags
) == flags
)
1417 FOR_EACH_VEC_ELT (escape_points
, i
, ep
)
1418 if (ep
->call
== call
&& ep
->arg
== arg
&& ep
->direct
== direct
)
1420 if ((ep
->min_flags
& min_flags
) == min_flags
)
1422 ep
->min_flags
&= min_flags
;
1425 /* Give up if max escape points is met. */
1426 if ((int)escape_points
.length () > param_modref_max_escape_points
)
1429 fprintf (dump_file
, "--param modref-max-escape-points limit reached\n");
1433 escape_point new_ep
= {call
, arg
, min_flags
, direct
};
1434 escape_points
.safe_push (new_ep
);
1438 /* Merge in flags from F. */
1440 modref_lattice::merge (int f
)
1444 if ((flags
& f
) != flags
)
1447 /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
1448 in tree-ssa-alias.c). Give up earlier. */
1449 if ((flags
& ~(EAF_DIRECT
| EAF_NOCLOBBER
)) == 0)
1452 escape_points
.release ();
1458 /* Merge in WITH. Return true if anyting changed. */
1461 modref_lattice::merge (const modref_lattice
&with
)
1466 bool changed
= merge (with
.flags
);
1470 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
1471 changed
|= add_escape_point (with
.escape_points
[i
].call
,
1472 with
.escape_points
[i
].arg
,
1473 with
.escape_points
[i
].min_flags
,
1474 with
.escape_points
[i
].direct
);
1478 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1479 stores. Return true if anyting changed. */
1482 modref_lattice::merge_deref (const modref_lattice
&with
, bool ignore_stores
)
1487 bool changed
= merge (deref_flags (with
.flags
, ignore_stores
));
1491 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
1492 changed
|= add_escape_point (with
.escape_points
[i
].call
,
1493 with
.escape_points
[i
].arg
,
1494 with
.escape_points
[i
].min_flags
,
1499 /* Merge in flags for direct load. */
1502 modref_lattice::merge_direct_load ()
1504 return merge (~EAF_UNUSED
);
1507 /* Merge in flags for direct store. */
1510 modref_lattice::merge_direct_store ()
1512 return merge (~(EAF_UNUSED
| EAF_NOCLOBBER
));
1515 } /* ANON namespace. */
1517 static void analyze_ssa_name_flags (tree name
,
1518 vec
<modref_lattice
> &lattice
,
1519 int depth
, bool ipa
);
1521 /* Call statements may return their parameters. Consider argument number
1522 ARG of USE_STMT and determine flags that can needs to be cleared
1523 in case pointer possibly indirectly references from ARG I is returned.
1524 LATTICE, DEPTH and ipa are same as in analyze_ssa_name_flags. */
1527 merge_call_lhs_flags (gcall
*call
, int arg
, int index
, bool deref
,
1528 vec
<modref_lattice
> &lattice
,
1529 int depth
, bool ipa
)
1531 /* If there is no return value, no flags are affected. */
1532 if (!gimple_call_lhs (call
))
1535 /* If we know that function returns given argument and it is not ARG
1536 we can still be happy. */
1537 int flags
= gimple_call_return_flags (call
);
1538 if ((flags
& ERF_RETURNS_ARG
)
1539 && (flags
& ERF_RETURN_ARG_MASK
) != arg
)
1542 /* If return value is SSA name determine its flags. */
1543 if (TREE_CODE (gimple_call_lhs (call
)) == SSA_NAME
)
1545 tree lhs
= gimple_call_lhs (call
);
1546 analyze_ssa_name_flags (lhs
, lattice
, depth
+ 1, ipa
);
1548 lattice
[index
].merge_deref (lattice
[SSA_NAME_VERSION (lhs
)], false);
1550 lattice
[index
].merge (lattice
[SSA_NAME_VERSION (lhs
)]);
1552 /* In the case of memory store we can do nothing. */
1554 lattice
[index
].merge (0);
1557 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
1558 LATTICE is an array of modref_lattices.
1559 DEPTH is a recursion depth used to make debug output prettier.
1560 If IPA is true we analyze for IPA propagation (and thus call escape points
1561 are processed later) */
1564 analyze_ssa_name_flags (tree name
, vec
<modref_lattice
> &lattice
, int depth
,
1567 imm_use_iterator ui
;
1569 int index
= SSA_NAME_VERSION (name
);
1571 /* See if value is already computed. */
1572 if (lattice
[index
].known
)
1574 if (lattice
[index
].open
)
1578 "%*sGiving up on a cycle in SSA graph\n", depth
* 4, "");
1581 if (depth
== param_modref_max_depth
)
1585 "%*sGiving up on max depth\n", depth
* 4, "");
1588 /* Recursion guard. */
1589 lattice
[index
].init ();
1594 "%*sAnalyzing flags of ssa name: ", depth
* 4, "");
1595 print_generic_expr (dump_file
, name
);
1596 fprintf (dump_file
, "\n");
1599 FOR_EACH_IMM_USE_STMT (use_stmt
, ui
, name
)
1601 if (lattice
[index
].flags
== 0)
1603 if (is_gimple_debug (use_stmt
))
1607 fprintf (dump_file
, "%*s Analyzing stmt: ", depth
* 4, "");
1608 print_gimple_stmt (dump_file
, use_stmt
, 0);
1611 /* Gimple return may load the return value.
1612 Returning name counts as an use by tree-ssa-structalias.c */
1613 if (greturn
*ret
= dyn_cast
<greturn
*> (use_stmt
))
1615 if (gimple_return_retval (ret
) == name
)
1616 lattice
[index
].merge (~EAF_UNUSED
);
1617 else if (memory_access_to (gimple_return_retval (ret
), name
))
1618 lattice
[index
].merge_direct_load ();
1620 /* Account for LHS store, arg loads and flags from callee function. */
1621 else if (gcall
*call
= dyn_cast
<gcall
*> (use_stmt
))
1623 tree callee
= gimple_call_fndecl (call
);
1624 /* Return slot optimization would require bit of propagation;
1626 if (gimple_call_return_slot_opt_p (call
)
1627 && gimple_call_lhs (call
) != NULL_TREE
1628 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call
))))
1631 fprintf (dump_file
, "%*s Unhandled return slot opt\n",
1633 lattice
[index
].merge (0);
1635 /* Recursion would require bit of propagation; give up for now. */
1636 else if (callee
&& !ipa
&& recursive_call_p (current_function_decl
,
1638 lattice
[index
].merge (0);
1641 int ecf_flags
= gimple_call_flags (call
);
1642 bool ignore_stores
= ignore_stores_p (current_function_decl
,
1644 bool ignore_retval
= ignore_retval_p (current_function_decl
,
1647 /* Handle *name = func (...). */
1648 if (gimple_call_lhs (call
)
1649 && memory_access_to (gimple_call_lhs (call
), name
))
1650 lattice
[index
].merge_direct_store ();
1652 /* We do not track accesses to the static chain (we could)
1654 if (gimple_call_chain (call
)
1655 && (gimple_call_chain (call
) == name
))
1656 lattice
[index
].merge (0);
1658 /* Process internal functions and right away. */
1659 bool record_ipa
= ipa
&& !gimple_call_internal_p (call
);
1661 /* Handle all function parameters. */
1662 for (unsigned i
= 0;
1663 i
< gimple_call_num_args (call
) && lattice
[index
].flags
; i
++)
1664 /* Name is directly passed to the callee. */
1665 if (gimple_call_arg (call
, i
) == name
)
1667 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
1669 int call_flags
= gimple_call_arg_flags (call
, i
);
1671 call_flags
|= EAF_NOCLOBBER
| EAF_NOESCAPE
1672 | EAF_NODIRECTESCAPE
;
1675 lattice
[index
].merge (call_flags
);
1677 lattice
[index
].add_escape_point (call
, i
,
1681 merge_call_lhs_flags (call
, i
, index
, false,
1682 lattice
, depth
, ipa
);
1684 /* Name is dereferenced and passed to a callee. */
1685 else if (memory_access_to (gimple_call_arg (call
, i
), name
))
1687 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
1688 lattice
[index
].merge_direct_load ();
1691 int call_flags
= deref_flags
1692 (gimple_call_arg_flags (call
, i
), ignore_stores
);
1694 lattice
[index
].merge (call_flags
);
1696 lattice
[index
].add_escape_point (call
, i
,
1700 merge_call_lhs_flags (call
, i
, index
, true,
1701 lattice
, depth
, ipa
);
1705 else if (gimple_assign_load_p (use_stmt
))
1707 gassign
*assign
= as_a
<gassign
*> (use_stmt
);
1708 /* Memory to memory copy. */
1709 if (gimple_store_p (assign
))
1711 /* Handle *lhs = *name.
1713 We do not track memory locations, so assume that value
1714 is used arbitrarily. */
1715 if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
1716 lattice
[index
].merge (0);
1717 /* Handle *name = *exp. */
1718 else if (memory_access_to (gimple_assign_lhs (assign
), name
))
1719 lattice
[index
].merge_direct_store ();
1721 /* Handle lhs = *name. */
1722 else if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
1724 tree lhs
= gimple_assign_lhs (assign
);
1725 analyze_ssa_name_flags (lhs
, lattice
, depth
+ 1, ipa
);
1726 lattice
[index
].merge_deref (lattice
[SSA_NAME_VERSION (lhs
)],
1730 else if (gimple_store_p (use_stmt
))
1732 gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
);
1734 /* Handle *lhs = name. */
1735 if (assign
&& gimple_assign_rhs1 (assign
) == name
)
1738 fprintf (dump_file
, "%*s ssa name saved to memory\n",
1740 lattice
[index
].merge (0);
1742 /* Handle *name = exp. */
1744 && memory_access_to (gimple_assign_lhs (assign
), name
))
1746 /* In general we can not ignore clobbers because they are
1747 barriers for code motion, however after inlining it is safe to
1748 do because local optimization passes do not consider clobbers
1749 from other functions. Similar logic is in ipa-pure-const.c. */
1750 if (!cfun
->after_inlining
|| !gimple_clobber_p (assign
))
1751 lattice
[index
].merge_direct_store ();
1753 /* ASM statements etc. */
1757 fprintf (dump_file
, "%*s Unhandled store\n",
1759 lattice
[index
].merge (0);
1762 else if (gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
))
1764 enum tree_code code
= gimple_assign_rhs_code (assign
);
1766 /* See if operation is a merge as considered by
1767 tree-ssa-structalias.c:find_func_aliases. */
1768 if (!truth_value_p (code
)
1769 && code
!= POINTER_DIFF_EXPR
1770 && (code
!= POINTER_PLUS_EXPR
1771 || gimple_assign_rhs1 (assign
) == name
))
1773 tree lhs
= gimple_assign_lhs (assign
);
1774 analyze_ssa_name_flags (lhs
, lattice
, depth
+ 1, ipa
);
1775 lattice
[index
].merge (lattice
[SSA_NAME_VERSION (lhs
)]);
1778 else if (gphi
*phi
= dyn_cast
<gphi
*> (use_stmt
))
1780 tree result
= gimple_phi_result (phi
);
1781 analyze_ssa_name_flags (result
, lattice
, depth
+ 1, ipa
);
1782 lattice
[index
].merge (lattice
[SSA_NAME_VERSION (result
)]);
1784 /* Conditions are not considered escape points
1785 by tree-ssa-structalias. */
1786 else if (gimple_code (use_stmt
) == GIMPLE_COND
)
1791 fprintf (dump_file
, "%*s Unhandled stmt\n", depth
* 4, "");
1792 lattice
[index
].merge (0);
1797 fprintf (dump_file
, "%*s current flags of ", depth
* 4, "");
1798 print_generic_expr (dump_file
, name
);
1799 lattice
[index
].dump (dump_file
, depth
* 4 + 4);
1804 fprintf (dump_file
, "%*sflags of ssa name ", depth
* 4, "");
1805 print_generic_expr (dump_file
, name
);
1806 lattice
[index
].dump (dump_file
, depth
* 4 + 2);
1808 lattice
[index
].open
= false;
1809 lattice
[index
].known
= true;
1812 /* Determine EAF flags for function parameters. */
1815 analyze_parms (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
1818 unsigned int parm_index
= 0;
1819 unsigned int count
= 0;
1820 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
1822 /* For const functions we have nothing to gain by EAF flags. */
1823 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
1826 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
1827 parm
= TREE_CHAIN (parm
))
1833 auto_vec
<modref_lattice
> lattice
;
1834 lattice
.safe_grow_cleared (num_ssa_names
, true);
1836 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
; parm_index
++,
1837 parm
= TREE_CHAIN (parm
))
1839 tree name
= ssa_default_def (cfun
, parm
);
1840 if (!name
|| has_zero_uses (name
))
1842 /* We do not track non-SSA parameters,
1843 but we want to track unused gimple_regs. */
1844 if (!is_gimple_reg (parm
))
1848 if (parm_index
>= summary
->arg_flags
.length ())
1849 summary
->arg_flags
.safe_grow_cleared (count
, true);
1850 summary
->arg_flags
[parm_index
] = EAF_UNUSED
;
1852 else if (summary_lto
)
1854 if (parm_index
>= summary_lto
->arg_flags
.length ())
1855 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
1856 summary_lto
->arg_flags
[parm_index
] = EAF_UNUSED
;
1860 analyze_ssa_name_flags (name
, lattice
, 0, ipa
);
1861 int flags
= lattice
[SSA_NAME_VERSION (name
)].flags
;
1863 /* For pure functions we have implicit NOCLOBBER
1865 if (ecf_flags
& ECF_PURE
)
1866 flags
&= ~(EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_NODIRECTESCAPE
);
1872 if (parm_index
>= summary
->arg_flags
.length ())
1873 summary
->arg_flags
.safe_grow_cleared (count
, true);
1874 summary
->arg_flags
[parm_index
] = flags
;
1876 else if (summary_lto
)
1878 if (parm_index
>= summary_lto
->arg_flags
.length ())
1879 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
1880 summary_lto
->arg_flags
[parm_index
] = flags
;
1882 if (lattice
[SSA_NAME_VERSION (name
)].escape_points
.length ())
1886 cgraph_node
*node
= cgraph_node::get (current_function_decl
);
1888 gcc_checking_assert (ipa
);
1890 (lattice
[SSA_NAME_VERSION (name
)].escape_points
, ip
, ep
)
1891 if ((ep
->min_flags
& flags
) != flags
)
1893 cgraph_edge
*e
= node
->get_edge (ep
->call
);
1894 struct escape_entry ee
= {parm_index
, ep
->arg
,
1895 ep
->min_flags
, ep
->direct
};
1897 escape_summaries
->get_create (e
)->esc
.safe_push (ee
);
1903 for (unsigned int i
= 0; i
< num_ssa_names
; i
++)
1904 lattice
[i
].release ();
1907 /* Analyze function F. IPA indicates whether we're running in local mode
1908 (false) or the IPA mode (true). */
1911 analyze_function (function
*f
, bool ipa
)
1914 fprintf (dump_file
, "modref analyzing '%s' (ipa=%i)%s%s\n",
1915 function_name (f
), ipa
,
1916 TREE_READONLY (current_function_decl
) ? " (const)" : "",
1917 DECL_PURE_P (current_function_decl
) ? " (pure)" : "");
1919 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
1920 if (!flag_ipa_modref
)
1923 /* Compute no-LTO summaries when local optimization is going to happen. */
1924 bool nolto
= (!ipa
|| ((!flag_lto
|| flag_fat_lto_objects
) && !in_lto_p
)
1925 || (in_lto_p
&& !flag_wpa
1926 && flag_incremental_link
!= INCREMENTAL_LINK_LTO
));
1927 /* Compute LTO when LTO streaming is going to happen. */
1928 bool lto
= ipa
&& ((flag_lto
&& !in_lto_p
)
1930 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
1931 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1933 modref_summary
*summary
= NULL
;
1934 modref_summary_lto
*summary_lto
= NULL
;
1936 /* Initialize the summary.
1937 If we run in local mode there is possibly pre-existing summary from
1938 IPA pass. Dump it so it is easy to compare if mod-ref info has
1942 if (!optimization_summaries
)
1943 optimization_summaries
= modref_summaries::create_ggc (symtab
);
1944 else /* Remove existing summary if we are re-running the pass. */
1948 = optimization_summaries
->get (cgraph_node::get (f
->decl
)))
1952 fprintf (dump_file
, "Past summary:\n");
1953 optimization_summaries
->get
1954 (cgraph_node::get (f
->decl
))->dump (dump_file
);
1956 optimization_summaries
->remove (cgraph_node::get (f
->decl
));
1958 summary
= optimization_summaries
->get_create (cgraph_node::get (f
->decl
));
1959 gcc_checking_assert (nolto
&& !lto
);
1961 /* In IPA mode we analyze every function precisely once. Assert that. */
1967 summaries
= modref_summaries::create_ggc (symtab
);
1969 summaries
->remove (cgraph_node::get (f
->decl
));
1970 summary
= summaries
->get_create (cgraph_node::get (f
->decl
));
1975 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
1977 summaries_lto
->remove (cgraph_node::get (f
->decl
));
1978 summary_lto
= summaries_lto
->get_create (cgraph_node::get (f
->decl
));
1980 if (!fnspec_summaries
)
1981 fnspec_summaries
= new fnspec_summaries_t (symtab
);
1982 if (!escape_summaries
)
1983 escape_summaries
= new escape_summaries_t (symtab
);
1987 /* Create and initialize summary for F.
1988 Note that summaries may be already allocated from previous
1992 gcc_assert (!summary
->loads
);
1993 summary
->loads
= modref_records::create_ggc (param_modref_max_bases
,
1994 param_modref_max_refs
,
1995 param_modref_max_accesses
);
1996 gcc_assert (!summary
->stores
);
1997 summary
->stores
= modref_records::create_ggc (param_modref_max_bases
,
1998 param_modref_max_refs
,
1999 param_modref_max_accesses
);
2000 summary
->writes_errno
= false;
2004 gcc_assert (!summary_lto
->loads
);
2005 summary_lto
->loads
= modref_records_lto::create_ggc
2006 (param_modref_max_bases
,
2007 param_modref_max_refs
,
2008 param_modref_max_accesses
);
2009 gcc_assert (!summary_lto
->stores
);
2010 summary_lto
->stores
= modref_records_lto::create_ggc
2011 (param_modref_max_bases
,
2012 param_modref_max_refs
,
2013 param_modref_max_accesses
);
2014 summary_lto
->writes_errno
= false;
2017 analyze_parms (summary
, summary_lto
, ipa
);
2019 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
2020 auto_vec
<gimple
*, 32> recursive_calls
;
2022 /* Analyze each statement in each basic block of the function. If the
2023 statement cannot be analyzed (for any reason), the entire function cannot
2024 be analyzed by modref. */
2026 FOR_EACH_BB_FN (bb
, f
)
2028 gimple_stmt_iterator si
;
2029 for (si
= gsi_after_labels (bb
); !gsi_end_p (si
); gsi_next (&si
))
2031 if (!analyze_stmt (summary
, summary_lto
,
2032 gsi_stmt (si
), ipa
, &recursive_calls
)
2033 || ((!summary
|| !summary
->useful_p (ecf_flags
, false))
2035 || !summary_lto
->useful_p (ecf_flags
, false))))
2037 collapse_loads (summary
, summary_lto
);
2038 collapse_stores (summary
, summary_lto
);
2044 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2045 This needs to be done after all other side effects are computed. */
2048 bool changed
= true;
2052 for (unsigned i
= 0; i
< recursive_calls
.length (); i
++)
2054 changed
|= merge_call_side_effects
2055 (summary
, recursive_calls
[i
], summary
,
2056 ignore_stores_p (current_function_decl
,
2058 (recursive_calls
[i
])),
2060 if (!summary
->useful_p (ecf_flags
, false))
2062 remove_summary (lto
, nolto
, ipa
);
2068 if (summary
&& !summary
->useful_p (ecf_flags
))
2071 optimization_summaries
->remove (fnode
);
2073 summaries
->remove (fnode
);
2076 if (summary_lto
&& !summary_lto
->useful_p (ecf_flags
))
2078 summaries_lto
->remove (fnode
);
2081 if (ipa
&& !summary
&& !summary_lto
)
2082 remove_modref_edge_summaries (fnode
);
2086 fprintf (dump_file
, " - modref done with result: tracked.\n");
2088 summary
->dump (dump_file
);
2090 summary_lto
->dump (dump_file
);
2091 dump_modref_edge_summaries (dump_file
, fnode
, 2);
2095 /* Callback for generate_summary. */
2098 modref_generate (void)
2100 struct cgraph_node
*node
;
2101 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
2103 function
*f
= DECL_STRUCT_FUNCTION (node
->decl
);
2107 analyze_function (f
, true);
2112 /* Called when a new function is inserted to callgraph late. */
2115 modref_summaries::insert (struct cgraph_node
*node
, modref_summary
*)
2117 /* Local passes ought to be executed by the pass manager. */
2118 if (this == optimization_summaries
)
2120 optimization_summaries
->remove (node
);
2123 if (!DECL_STRUCT_FUNCTION (node
->decl
)
2124 || !opt_for_fn (node
->decl
, flag_ipa_modref
))
2126 summaries
->remove (node
);
2129 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
2130 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
2134 /* Called when a new function is inserted to callgraph late. */
2137 modref_summaries_lto::insert (struct cgraph_node
*node
, modref_summary_lto
*)
2139 /* We do not support adding new function when IPA information is already
2140 propagated. This is done only by SIMD cloning that is not very
2142 if (!DECL_STRUCT_FUNCTION (node
->decl
)
2143 || !opt_for_fn (node
->decl
, flag_ipa_modref
)
2146 summaries_lto
->remove (node
);
2149 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
2150 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
2154 /* Called when new clone is inserted to callgraph late. */
2157 modref_summaries::duplicate (cgraph_node
*, cgraph_node
*dst
,
2158 modref_summary
*src_data
,
2159 modref_summary
*dst_data
)
2161 /* Do not duplicate optimization summaries; we do not handle parameter
2162 transforms on them. */
2163 if (this == optimization_summaries
)
2165 optimization_summaries
->remove (dst
);
2168 dst_data
->stores
= modref_records::create_ggc
2169 (src_data
->stores
->max_bases
,
2170 src_data
->stores
->max_refs
,
2171 src_data
->stores
->max_accesses
);
2172 dst_data
->stores
->copy_from (src_data
->stores
);
2173 dst_data
->loads
= modref_records::create_ggc
2174 (src_data
->loads
->max_bases
,
2175 src_data
->loads
->max_refs
,
2176 src_data
->loads
->max_accesses
);
2177 dst_data
->loads
->copy_from (src_data
->loads
);
2178 dst_data
->writes_errno
= src_data
->writes_errno
;
2179 if (src_data
->arg_flags
.length ())
2180 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
2183 /* Called when new clone is inserted to callgraph late. */
2186 modref_summaries_lto::duplicate (cgraph_node
*, cgraph_node
*,
2187 modref_summary_lto
*src_data
,
2188 modref_summary_lto
*dst_data
)
2190 /* Be sure that no further cloning happens after ipa-modref. If it does
2191 we will need to update signatures for possible param changes. */
2192 gcc_checking_assert (!((modref_summaries_lto
*)summaries_lto
)->propagated
);
2193 dst_data
->stores
= modref_records_lto::create_ggc
2194 (src_data
->stores
->max_bases
,
2195 src_data
->stores
->max_refs
,
2196 src_data
->stores
->max_accesses
);
2197 dst_data
->stores
->copy_from (src_data
->stores
);
2198 dst_data
->loads
= modref_records_lto::create_ggc
2199 (src_data
->loads
->max_bases
,
2200 src_data
->loads
->max_refs
,
2201 src_data
->loads
->max_accesses
);
2202 dst_data
->loads
->copy_from (src_data
->loads
);
2203 dst_data
->writes_errno
= src_data
->writes_errno
;
2204 if (src_data
->arg_flags
.length ())
2205 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
2210 /* Definition of the modref pass on GIMPLE. */
2211 const pass_data pass_data_modref
= {
2216 (PROP_cfg
| PROP_ssa
),
2223 class pass_modref
: public gimple_opt_pass
2226 pass_modref (gcc::context
*ctxt
)
2227 : gimple_opt_pass (pass_data_modref
, ctxt
) {}
2229 /* opt_pass methods: */
2232 return new pass_modref (m_ctxt
);
2234 virtual bool gate (function
*)
2236 return flag_ipa_modref
;
2238 virtual unsigned int execute (function
*);
2241 /* Encode TT to the output block OB using the summary streaming API. */
2244 write_modref_records (modref_records_lto
*tt
, struct output_block
*ob
)
2246 streamer_write_uhwi (ob
, tt
->max_bases
);
2247 streamer_write_uhwi (ob
, tt
->max_refs
);
2248 streamer_write_uhwi (ob
, tt
->max_accesses
);
2250 streamer_write_uhwi (ob
, tt
->every_base
);
2251 streamer_write_uhwi (ob
, vec_safe_length (tt
->bases
));
2253 modref_base_node
<tree
> *base_node
;
2254 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, base_node
)
2256 stream_write_tree (ob
, base_node
->base
, true);
2258 streamer_write_uhwi (ob
, base_node
->every_ref
);
2259 streamer_write_uhwi (ob
, vec_safe_length (base_node
->refs
));
2262 modref_ref_node
<tree
> *ref_node
;
2263 FOR_EACH_VEC_SAFE_ELT (base_node
->refs
, j
, ref_node
)
2265 stream_write_tree (ob
, ref_node
->ref
, true);
2266 streamer_write_uhwi (ob
, ref_node
->every_access
);
2267 streamer_write_uhwi (ob
, vec_safe_length (ref_node
->accesses
));
2270 modref_access_node
*access_node
;
2271 FOR_EACH_VEC_SAFE_ELT (ref_node
->accesses
, k
, access_node
)
2273 streamer_write_hwi (ob
, access_node
->parm_index
);
2274 if (access_node
->parm_index
!= -1)
2276 streamer_write_uhwi (ob
, access_node
->parm_offset_known
);
2277 if (access_node
->parm_offset_known
)
2279 streamer_write_poly_int64 (ob
, access_node
->parm_offset
);
2280 streamer_write_poly_int64 (ob
, access_node
->offset
);
2281 streamer_write_poly_int64 (ob
, access_node
->size
);
2282 streamer_write_poly_int64 (ob
, access_node
->max_size
);
2290 /* Read a modref_tree from the input block IB using the data from DATA_IN.
2291 This assumes that the tree was encoded using write_modref_tree.
2292 Either nolto_ret or lto_ret is initialized by the tree depending whether
2293 LTO streaming is expected or not. */
2296 read_modref_records (lto_input_block
*ib
, struct data_in
*data_in
,
2297 modref_records
**nolto_ret
,
2298 modref_records_lto
**lto_ret
)
2300 size_t max_bases
= streamer_read_uhwi (ib
);
2301 size_t max_refs
= streamer_read_uhwi (ib
);
2302 size_t max_accesses
= streamer_read_uhwi (ib
);
2305 *lto_ret
= modref_records_lto::create_ggc (max_bases
, max_refs
,
2308 *nolto_ret
= modref_records::create_ggc (max_bases
, max_refs
,
2310 gcc_checking_assert (lto_ret
|| nolto_ret
);
2312 size_t every_base
= streamer_read_uhwi (ib
);
2313 size_t nbase
= streamer_read_uhwi (ib
);
2315 gcc_assert (!every_base
|| nbase
== 0);
2319 (*nolto_ret
)->collapse ();
2321 (*lto_ret
)->collapse ();
2323 for (size_t i
= 0; i
< nbase
; i
++)
2325 tree base_tree
= stream_read_tree (ib
, data_in
);
2326 modref_base_node
<alias_set_type
> *nolto_base_node
= NULL
;
2327 modref_base_node
<tree
> *lto_base_node
= NULL
;
2329 /* At stream in time we have LTO alias info. Check if we streamed in
2330 something obviously unnecessary. Do not glob types by alias sets;
2331 it is not 100% clear that ltrans types will get merged same way.
2332 Types may get refined based on ODR type conflicts. */
2333 if (base_tree
&& !get_alias_set (base_tree
))
2337 fprintf (dump_file
, "Streamed in alias set 0 type ");
2338 print_generic_expr (dump_file
, base_tree
);
2339 fprintf (dump_file
, "\n");
2345 nolto_base_node
= (*nolto_ret
)->insert_base (base_tree
2346 ? get_alias_set (base_tree
)
2349 lto_base_node
= (*lto_ret
)->insert_base (base_tree
);
2350 size_t every_ref
= streamer_read_uhwi (ib
);
2351 size_t nref
= streamer_read_uhwi (ib
);
2353 gcc_assert (!every_ref
|| nref
== 0);
2356 if (nolto_base_node
)
2357 nolto_base_node
->collapse ();
2359 lto_base_node
->collapse ();
2361 for (size_t j
= 0; j
< nref
; j
++)
2363 tree ref_tree
= stream_read_tree (ib
, data_in
);
2365 if (ref_tree
&& !get_alias_set (ref_tree
))
2369 fprintf (dump_file
, "Streamed in alias set 0 type ");
2370 print_generic_expr (dump_file
, ref_tree
);
2371 fprintf (dump_file
, "\n");
2376 modref_ref_node
<alias_set_type
> *nolto_ref_node
= NULL
;
2377 modref_ref_node
<tree
> *lto_ref_node
= NULL
;
2379 if (nolto_base_node
)
2381 = nolto_base_node
->insert_ref (ref_tree
2382 ? get_alias_set (ref_tree
) : 0,
2385 lto_ref_node
= lto_base_node
->insert_ref (ref_tree
, max_refs
);
2387 size_t every_access
= streamer_read_uhwi (ib
);
2388 size_t naccesses
= streamer_read_uhwi (ib
);
2391 nolto_ref_node
->every_access
= every_access
;
2393 lto_ref_node
->every_access
= every_access
;
2395 for (size_t k
= 0; k
< naccesses
; k
++)
2397 int parm_index
= streamer_read_hwi (ib
);
2398 bool parm_offset_known
= false;
2399 poly_int64 parm_offset
= 0;
2400 poly_int64 offset
= 0;
2401 poly_int64 size
= -1;
2402 poly_int64 max_size
= -1;
2404 if (parm_index
!= -1)
2406 parm_offset_known
= streamer_read_uhwi (ib
);
2407 if (parm_offset_known
)
2409 parm_offset
= streamer_read_poly_int64 (ib
);
2410 offset
= streamer_read_poly_int64 (ib
);
2411 size
= streamer_read_poly_int64 (ib
);
2412 max_size
= streamer_read_poly_int64 (ib
);
2415 modref_access_node a
= {offset
, size
, max_size
, parm_offset
,
2416 parm_index
, parm_offset_known
};
2418 nolto_ref_node
->insert_access (a
, max_accesses
);
2420 lto_ref_node
->insert_access (a
, max_accesses
);
2425 (*lto_ret
)->cleanup ();
2427 (*nolto_ret
)->cleanup ();
2430 /* Write ESUM to BP. */
2433 modref_write_escape_summary (struct bitpack_d
*bp
, escape_summary
*esum
)
2437 bp_pack_var_len_unsigned (bp
, 0);
2440 bp_pack_var_len_unsigned (bp
, esum
->esc
.length ());
2443 FOR_EACH_VEC_ELT (esum
->esc
, i
, ee
)
2445 bp_pack_var_len_unsigned (bp
, ee
->parm_index
);
2446 bp_pack_var_len_unsigned (bp
, ee
->arg
);
2447 bp_pack_var_len_unsigned (bp
, ee
->min_flags
);
2448 bp_pack_value (bp
, ee
->direct
, 1);
2452 /* Read escape summary for E from BP. */
2455 modref_read_escape_summary (struct bitpack_d
*bp
, cgraph_edge
*e
)
2457 unsigned int n
= bp_unpack_var_len_unsigned (bp
);
2460 escape_summary
*esum
= escape_summaries
->get_create (e
);
2461 esum
->esc
.reserve_exact (n
);
2462 for (unsigned int i
= 0; i
< n
; i
++)
2465 ee
.parm_index
= bp_unpack_var_len_unsigned (bp
);
2466 ee
.arg
= bp_unpack_var_len_unsigned (bp
);
2467 ee
.min_flags
= bp_unpack_var_len_unsigned (bp
);
2468 ee
.direct
= bp_unpack_value (bp
, 1);
2469 esum
->esc
.quick_push (ee
);
2473 /* Callback for write_summary. */
2478 struct output_block
*ob
= create_output_block (LTO_section_ipa_modref
);
2479 lto_symtab_encoder_t encoder
= ob
->decl_state
->symtab_node_encoder
;
2480 unsigned int count
= 0;
2485 streamer_write_uhwi (ob
, 0);
2486 streamer_write_char_stream (ob
->main_stream
, 0);
2487 produce_asm (ob
, NULL
);
2488 destroy_output_block (ob
);
2492 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
2494 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
2495 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
2496 modref_summary_lto
*r
;
2498 if (cnode
&& cnode
->definition
&& !cnode
->alias
2499 && (r
= summaries_lto
->get (cnode
))
2500 && r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
2503 streamer_write_uhwi (ob
, count
);
2505 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
2507 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
2508 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
2510 if (cnode
&& cnode
->definition
&& !cnode
->alias
)
2512 modref_summary_lto
*r
= summaries_lto
->get (cnode
);
2514 if (!r
|| !r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
2517 streamer_write_uhwi (ob
, lto_symtab_encoder_encode (encoder
, cnode
));
2519 streamer_write_uhwi (ob
, r
->arg_flags
.length ());
2520 for (unsigned int i
= 0; i
< r
->arg_flags
.length (); i
++)
2521 streamer_write_char_stream (ob
->main_stream
, r
->arg_flags
[i
]);
2523 write_modref_records (r
->loads
, ob
);
2524 write_modref_records (r
->stores
, ob
);
2526 struct bitpack_d bp
= bitpack_create (ob
->main_stream
);
2527 bp_pack_value (&bp
, r
->writes_errno
, 1);
2530 for (cgraph_edge
*e
= cnode
->indirect_calls
;
2531 e
; e
= e
->next_callee
)
2533 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
2534 bp_pack_value (&bp
, sum
!= NULL
, 1);
2536 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
2537 class escape_summary
*esum
= escape_summaries
->get (e
);
2538 modref_write_escape_summary (&bp
,esum
);
2540 for (cgraph_edge
*e
= cnode
->callees
; e
; e
= e
->next_callee
)
2542 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
2543 bp_pack_value (&bp
, sum
!= NULL
, 1);
2545 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
2546 class escape_summary
*esum
= escape_summaries
->get (e
);
2547 modref_write_escape_summary (&bp
,esum
);
2550 streamer_write_bitpack (&bp
);
2553 streamer_write_char_stream (ob
->main_stream
, 0);
2554 produce_asm (ob
, NULL
);
2555 destroy_output_block (ob
);
2559 read_section (struct lto_file_decl_data
*file_data
, const char *data
,
2562 const struct lto_function_header
*header
2563 = (const struct lto_function_header
*) data
;
2564 const int cfg_offset
= sizeof (struct lto_function_header
);
2565 const int main_offset
= cfg_offset
+ header
->cfg_size
;
2566 const int string_offset
= main_offset
+ header
->main_size
;
2567 struct data_in
*data_in
;
2569 unsigned int f_count
;
2571 lto_input_block
ib ((const char *) data
+ main_offset
, header
->main_size
,
2572 file_data
->mode_table
);
2575 = lto_data_in_create (file_data
, (const char *) data
+ string_offset
,
2576 header
->string_size
, vNULL
);
2577 f_count
= streamer_read_uhwi (&ib
);
2578 for (i
= 0; i
< f_count
; i
++)
2580 struct cgraph_node
*node
;
2581 lto_symtab_encoder_t encoder
;
2583 unsigned int index
= streamer_read_uhwi (&ib
);
2584 encoder
= file_data
->symtab_node_encoder
;
2585 node
= dyn_cast
<cgraph_node
*> (lto_symtab_encoder_deref (encoder
,
2588 modref_summary
*modref_sum
= summaries
2589 ? summaries
->get_create (node
) : NULL
;
2590 modref_summary_lto
*modref_sum_lto
= summaries_lto
2591 ? summaries_lto
->get_create (node
)
2593 if (optimization_summaries
)
2594 modref_sum
= optimization_summaries
->get_create (node
);
2597 modref_sum
->writes_errno
= false;
2599 modref_sum_lto
->writes_errno
= false;
2601 gcc_assert (!modref_sum
|| (!modref_sum
->loads
2602 && !modref_sum
->stores
));
2603 gcc_assert (!modref_sum_lto
|| (!modref_sum_lto
->loads
2604 && !modref_sum_lto
->stores
));
2605 unsigned int args
= streamer_read_uhwi (&ib
);
2606 if (args
&& modref_sum
)
2607 modref_sum
->arg_flags
.reserve_exact (args
);
2608 if (args
&& modref_sum_lto
)
2609 modref_sum_lto
->arg_flags
.reserve_exact (args
);
2610 for (unsigned int i
= 0; i
< args
; i
++)
2612 unsigned char flags
= streamer_read_uchar (&ib
);
2614 modref_sum
->arg_flags
.quick_push (flags
);
2616 modref_sum_lto
->arg_flags
.quick_push (flags
);
2618 read_modref_records (&ib
, data_in
,
2619 modref_sum
? &modref_sum
->loads
: NULL
,
2620 modref_sum_lto
? &modref_sum_lto
->loads
: NULL
);
2621 read_modref_records (&ib
, data_in
,
2622 modref_sum
? &modref_sum
->stores
: NULL
,
2623 modref_sum_lto
? &modref_sum_lto
->stores
: NULL
);
2624 struct bitpack_d bp
= streamer_read_bitpack (&ib
);
2625 if (bp_unpack_value (&bp
, 1))
2628 modref_sum
->writes_errno
= true;
2630 modref_sum_lto
->writes_errno
= true;
2634 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
2636 if (bp_unpack_value (&bp
, 1))
2638 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
2639 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
2641 modref_read_escape_summary (&bp
, e
);
2643 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
2645 if (bp_unpack_value (&bp
, 1))
2647 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
2648 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
2650 modref_read_escape_summary (&bp
, e
);
2655 fprintf (dump_file
, "Read modref for %s\n",
2656 node
->dump_name ());
2658 modref_sum
->dump (dump_file
);
2660 modref_sum_lto
->dump (dump_file
);
2661 dump_modref_edge_summaries (dump_file
, node
, 4);
2665 lto_free_section_data (file_data
, LTO_section_ipa_modref
, NULL
, data
,
2667 lto_data_in_delete (data_in
);
2670 /* Callback for read_summary. */
2675 struct lto_file_decl_data
**file_data_vec
= lto_get_file_decl_data ();
2676 struct lto_file_decl_data
*file_data
;
2679 gcc_checking_assert (!optimization_summaries
&& !summaries
&& !summaries_lto
);
2681 optimization_summaries
= modref_summaries::create_ggc (symtab
);
2684 if (flag_wpa
|| flag_incremental_link
== INCREMENTAL_LINK_LTO
)
2685 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
2687 || (flag_incremental_link
== INCREMENTAL_LINK_LTO
2688 && flag_fat_lto_objects
))
2689 summaries
= modref_summaries::create_ggc (symtab
);
2690 if (!fnspec_summaries
)
2691 fnspec_summaries
= new fnspec_summaries_t (symtab
);
2692 if (!escape_summaries
)
2693 escape_summaries
= new escape_summaries_t (symtab
);
2696 while ((file_data
= file_data_vec
[j
++]))
2699 const char *data
= lto_get_summary_section_data (file_data
,
2700 LTO_section_ipa_modref
,
2703 read_section (file_data
, data
, len
);
2705 /* Fatal error here. We do not want to support compiling ltrans units
2706 with different version of compiler or different flags than the WPA
2707 unit, so this should never happen. */
2708 fatal_error (input_location
,
2709 "IPA modref summary is missing in input file");
2713 /* Recompute arg_flags for param adjustments in INFO. */
2716 remap_arg_flags (auto_vec
<unsigned char> &arg_flags
, clone_info
*info
)
2718 auto_vec
<unsigned char> old
= arg_flags
.copy ();
2721 ipa_adjusted_param
*p
;
2723 arg_flags
.release ();
2725 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2727 int o
= info
->param_adjustments
->get_original_index (i
);
2728 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
2732 arg_flags
.safe_grow_cleared (max
+ 1, true);
2733 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2735 int o
= info
->param_adjustments
->get_original_index (i
);
2736 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
2737 arg_flags
[i
] = old
[o
];
2741 /* If signature changed, update the summary. */
2744 update_signature (struct cgraph_node
*node
)
2746 clone_info
*info
= clone_info::get (node
);
2747 if (!info
|| !info
->param_adjustments
)
2750 modref_summary
*r
= optimization_summaries
2751 ? optimization_summaries
->get (node
) : NULL
;
2752 modref_summary_lto
*r_lto
= summaries_lto
2753 ? summaries_lto
->get (node
) : NULL
;
2758 fprintf (dump_file
, "Updating summary for %s from:\n",
2759 node
->dump_name ());
2761 r
->dump (dump_file
);
2763 r_lto
->dump (dump_file
);
2767 ipa_adjusted_param
*p
;
2769 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2771 int idx
= info
->param_adjustments
->get_original_index (i
);
2776 auto_vec
<int, 32> map
;
2778 map
.reserve (max
+ 1);
2779 for (i
= 0; i
<= max
; i
++)
2780 map
.quick_push (-1);
2781 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2783 int idx
= info
->param_adjustments
->get_original_index (i
);
2789 r
->loads
->remap_params (&map
);
2790 r
->stores
->remap_params (&map
);
2791 if (r
->arg_flags
.length ())
2792 remap_arg_flags (r
->arg_flags
, info
);
2796 r_lto
->loads
->remap_params (&map
);
2797 r_lto
->stores
->remap_params (&map
);
2798 if (r_lto
->arg_flags
.length ())
2799 remap_arg_flags (r_lto
->arg_flags
, info
);
2803 fprintf (dump_file
, "to:\n");
2805 r
->dump (dump_file
);
2807 r_lto
->dump (dump_file
);
2812 /* Definition of the modref IPA pass. */
2813 const pass_data pass_data_ipa_modref
=
2815 IPA_PASS
, /* type */
2816 "modref", /* name */
2817 OPTGROUP_IPA
, /* optinfo_flags */
2818 TV_IPA_MODREF
, /* tv_id */
2819 0, /* properties_required */
2820 0, /* properties_provided */
2821 0, /* properties_destroyed */
2822 0, /* todo_flags_start */
2823 ( TODO_dump_symtab
), /* todo_flags_finish */
2826 class pass_ipa_modref
: public ipa_opt_pass_d
2829 pass_ipa_modref (gcc::context
*ctxt
)
2830 : ipa_opt_pass_d (pass_data_ipa_modref
, ctxt
,
2831 modref_generate
, /* generate_summary */
2832 modref_write
, /* write_summary */
2833 modref_read
, /* read_summary */
2834 modref_write
, /* write_optimization_summary */
2835 modref_read
, /* read_optimization_summary */
2836 NULL
, /* stmt_fixup */
2837 0, /* function_transform_todo_flags_start */
2838 NULL
, /* function_transform */
2839 NULL
) /* variable_transform */
2842 /* opt_pass methods: */
2843 opt_pass
*clone () { return new pass_ipa_modref (m_ctxt
); }
2844 virtual bool gate (function
*)
2848 virtual unsigned int execute (function
*);
2854 unsigned int pass_modref::execute (function
*f
)
2856 analyze_function (f
, false);
2861 make_pass_modref (gcc::context
*ctxt
)
2863 return new pass_modref (ctxt
);
2867 make_pass_ipa_modref (gcc::context
*ctxt
)
2869 return new pass_ipa_modref (ctxt
);
2872 /* Skip edges from and to nodes without ipa_pure_const enabled.
2873 Ignore not available symbols. */
2876 ignore_edge (struct cgraph_edge
*e
)
2878 /* We merge summaries of inline clones into summaries of functions they
2879 are inlined to. For that reason the complete function bodies must
2881 if (!e
->inline_failed
)
2883 enum availability avail
;
2884 cgraph_node
*callee
= e
->callee
->function_or_virtual_thunk_symbol
2885 (&avail
, e
->caller
);
2887 return (avail
<= AVAIL_INTERPOSABLE
2888 || ((!optimization_summaries
|| !optimization_summaries
->get (callee
))
2889 && (!summaries_lto
|| !summaries_lto
->get (callee
)))
2890 || flags_from_decl_or_type (e
->callee
->decl
)
2891 & (ECF_CONST
| ECF_NOVOPS
));
2894 /* Compute parm_map for CALLEE_EDGE. */
2897 compute_parm_map (cgraph_edge
*callee_edge
, vec
<modref_parm_map
> *parm_map
)
2899 class ipa_edge_args
*args
;
2900 if (ipa_node_params_sum
2901 && !callee_edge
->call_stmt_cannot_inline_p
2902 && (args
= ipa_edge_args_sum
->get (callee_edge
)) != NULL
)
2904 int i
, count
= ipa_get_cs_argument_count (args
);
2905 class ipa_node_params
*caller_parms_info
, *callee_pi
;
2906 class ipa_call_summary
*es
2907 = ipa_call_summaries
->get (callee_edge
);
2909 = callee_edge
->callee
->function_or_virtual_thunk_symbol
2910 (NULL
, callee_edge
->caller
);
2913 = ipa_node_params_sum
->get (callee_edge
->caller
->inlined_to
2914 ? callee_edge
->caller
->inlined_to
2915 : callee_edge
->caller
);
2916 callee_pi
= ipa_node_params_sum
->get (callee
);
2918 (*parm_map
).safe_grow_cleared (count
, true);
2920 for (i
= 0; i
< count
; i
++)
2922 if (es
&& es
->param
[i
].points_to_local_or_readonly_memory
)
2924 (*parm_map
)[i
].parm_index
= -2;
2928 struct ipa_jump_func
*jf
2929 = ipa_get_ith_jump_func (args
, i
);
2930 if (jf
&& callee_pi
)
2932 tree cst
= ipa_value_from_jfunc (caller_parms_info
,
2936 if (cst
&& points_to_local_or_readonly_memory_p (cst
))
2938 (*parm_map
)[i
].parm_index
= -2;
2942 if (jf
&& jf
->type
== IPA_JF_PASS_THROUGH
)
2944 (*parm_map
)[i
].parm_index
2945 = ipa_get_jf_pass_through_formal_id (jf
);
2946 if (ipa_get_jf_pass_through_operation (jf
) == NOP_EXPR
)
2948 (*parm_map
)[i
].parm_offset_known
= true;
2949 (*parm_map
)[i
].parm_offset
= 0;
2951 else if (ipa_get_jf_pass_through_operation (jf
)
2952 == POINTER_PLUS_EXPR
2953 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf
),
2954 &(*parm_map
)[i
].parm_offset
))
2955 (*parm_map
)[i
].parm_offset_known
= true;
2957 (*parm_map
)[i
].parm_offset_known
= false;
2960 if (jf
&& jf
->type
== IPA_JF_ANCESTOR
)
2962 (*parm_map
)[i
].parm_index
= ipa_get_jf_ancestor_formal_id (jf
);
2963 (*parm_map
)[i
].parm_offset_known
= true;
2965 (!(ipa_get_jf_ancestor_offset (jf
) & (BITS_PER_UNIT
- 1)));
2966 (*parm_map
)[i
].parm_offset
2967 = ipa_get_jf_ancestor_offset (jf
) >> LOG2_BITS_PER_UNIT
;
2970 (*parm_map
)[i
].parm_index
= -1;
2974 fprintf (dump_file
, " Parm map: ");
2975 for (i
= 0; i
< count
; i
++)
2976 fprintf (dump_file
, " %i", (*parm_map
)[i
].parm_index
);
2977 fprintf (dump_file
, "\n");
2984 /* Map used to translate escape infos. */
2992 /* Update escape map fo E. */
2995 update_escape_summary_1 (cgraph_edge
*e
,
2996 vec
<vec
<escape_map
>> &map
)
2998 escape_summary
*sum
= escape_summaries
->get (e
);
3001 auto_vec
<escape_entry
> old
= sum
->esc
.copy ();
3002 sum
->esc
.release ();
3006 FOR_EACH_VEC_ELT (old
, i
, ee
)
3009 struct escape_map
*em
;
3010 if (ee
->parm_index
>= map
.length ())
3012 FOR_EACH_VEC_ELT (map
[ee
->parm_index
], j
, em
)
3014 struct escape_entry entry
= {em
->parm_index
, ee
->arg
,
3016 ee
->direct
& em
->direct
};
3017 sum
->esc
.safe_push (entry
);
3020 if (!sum
->esc
.length ())
3021 escape_summaries
->remove (e
);
3024 /* Update escape map fo NODE. */
3027 update_escape_summary (cgraph_node
*node
,
3028 vec
<vec
<escape_map
>> &map
)
3030 if (!escape_summaries
)
3032 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
3033 update_escape_summary_1 (e
, map
);
3034 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
3036 if (!e
->inline_failed
)
3037 update_escape_summary (e
->callee
, map
);
3039 update_escape_summary_1 (e
, map
);
3043 /* Call EDGE was inlined; merge summary from callee to the caller. */
3046 ipa_merge_modref_summary_after_inlining (cgraph_edge
*edge
)
3048 if (!summaries
&& !summaries_lto
)
3051 struct cgraph_node
*to
= (edge
->caller
->inlined_to
3052 ? edge
->caller
->inlined_to
: edge
->caller
);
3053 class modref_summary
*to_info
= summaries
? summaries
->get (to
) : NULL
;
3054 class modref_summary_lto
*to_info_lto
= summaries_lto
3055 ? summaries_lto
->get (to
) : NULL
;
3057 if (!to_info
&& !to_info_lto
)
3060 summaries
->remove (edge
->callee
);
3062 summaries_lto
->remove (edge
->callee
);
3063 remove_modref_edge_summaries (edge
->callee
);
3067 class modref_summary
*callee_info
= summaries
? summaries
->get (edge
->callee
)
3069 class modref_summary_lto
*callee_info_lto
3070 = summaries_lto
? summaries_lto
->get (edge
->callee
) : NULL
;
3071 int flags
= flags_from_decl_or_type (edge
->callee
->decl
);
3072 bool ignore_stores
= ignore_stores_p (edge
->caller
->decl
, flags
);
3074 if (!callee_info
&& to_info
)
3076 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3077 to_info
->loads
->collapse ();
3079 to_info
->stores
->collapse ();
3081 if (!callee_info_lto
&& to_info_lto
)
3083 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3084 to_info_lto
->loads
->collapse ();
3086 to_info_lto
->stores
->collapse ();
3088 if (callee_info
|| callee_info_lto
)
3090 auto_vec
<modref_parm_map
, 32> parm_map
;
3092 compute_parm_map (edge
, &parm_map
);
3096 if (to_info
&& callee_info
)
3097 to_info
->stores
->merge (callee_info
->stores
, &parm_map
);
3098 if (to_info_lto
&& callee_info_lto
)
3099 to_info_lto
->stores
->merge (callee_info_lto
->stores
, &parm_map
);
3101 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3103 if (to_info
&& callee_info
)
3104 to_info
->loads
->merge (callee_info
->loads
, &parm_map
);
3105 if (to_info_lto
&& callee_info_lto
)
3106 to_info_lto
->loads
->merge (callee_info_lto
->loads
, &parm_map
);
3110 /* Now merge escape summaries.
3111 For every escape to the callee we need to merge calle flags
3112 and remap calees escapes. */
3113 class escape_summary
*sum
= escape_summaries
->get (edge
);
3114 int max_escape
= -1;
3118 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3119 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3120 if ((int)ee
->arg
> max_escape
)
3121 max_escape
= ee
->arg
;
3123 auto_vec
<vec
<struct escape_map
>, 32> emap (max_escape
+ 1);
3124 emap
.safe_grow (max_escape
+ 1, true);
3125 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
3128 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3129 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3131 bool needed
= false;
3132 if (to_info
&& to_info
->arg_flags
.length () > ee
->parm_index
)
3134 int flags
= callee_info
3135 && callee_info
->arg_flags
.length () > ee
->arg
3136 ? callee_info
->arg_flags
[ee
->arg
] : 0;
3138 flags
= deref_flags (flags
, ignore_stores
);
3139 else if (ignore_stores
)
3140 flags
|= EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_NODIRECTESCAPE
;
3141 flags
|= ee
->min_flags
;
3142 to_info
->arg_flags
[ee
->parm_index
] &= flags
;
3143 if (to_info
->arg_flags
[ee
->parm_index
])
3146 if (to_info_lto
&& to_info_lto
->arg_flags
.length () > ee
->parm_index
)
3148 int flags
= callee_info_lto
3149 && callee_info_lto
->arg_flags
.length () > ee
->arg
3150 ? callee_info_lto
->arg_flags
[ee
->arg
] : 0;
3152 flags
= deref_flags (flags
, ignore_stores
);
3153 else if (ignore_stores
)
3154 flags
|= EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_NODIRECTESCAPE
;
3155 flags
|= ee
->min_flags
;
3156 to_info_lto
->arg_flags
[ee
->parm_index
] &= flags
;
3157 if (to_info_lto
->arg_flags
[ee
->parm_index
])
3160 struct escape_map entry
= {ee
->parm_index
, ee
->direct
};
3162 emap
[ee
->arg
].safe_push (entry
);
3164 update_escape_summary (edge
->callee
, emap
);
3165 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
3168 escape_summaries
->remove (edge
);
3172 if (to_info
&& !to_info
->useful_p (flags
))
3175 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
3177 summaries
->remove (to
);
3180 else if (to_info
&& dump_file
)
3183 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
3185 to_info
->dump (dump_file
);
3188 summaries
->remove (edge
->callee
);
3192 if (to_info_lto
&& !to_info_lto
->useful_p (flags
))
3195 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
3197 summaries_lto
->remove (to
);
3199 else if (to_info_lto
&& dump_file
)
3202 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
3204 to_info_lto
->dump (dump_file
);
3207 if (callee_info_lto
)
3208 summaries_lto
->remove (edge
->callee
);
3210 if (!to_info
&& !to_info_lto
)
3211 remove_modref_edge_summaries (to
);
3215 /* Get parameter type from DECL. This is only safe for special cases
3216 like builtins we create fnspec for because the type match is checked
3217 at fnspec creation time. */
3220 get_parm_type (tree decl
, unsigned int i
)
3222 tree t
= TYPE_ARG_TYPES (TREE_TYPE (decl
));
3224 for (unsigned int p
= 0; p
< i
; p
++)
3226 return TREE_VALUE (t
);
3229 /* Return access mode for argument I of call E with FNSPEC. */
3231 static modref_access_node
3232 get_access_for_fnspec (cgraph_edge
*e
, attr_fnspec
&fnspec
,
3233 unsigned int i
, modref_parm_map
&map
)
3235 tree size
= NULL_TREE
;
3236 unsigned int size_arg
;
3238 if (!fnspec
.arg_specified_p (i
))
3240 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
3242 cgraph_node
*node
= e
->caller
->inlined_to
3243 ? e
->caller
->inlined_to
: e
->caller
;
3244 ipa_node_params
*caller_parms_info
= ipa_node_params_sum
->get (node
);
3245 ipa_edge_args
*args
= ipa_edge_args_sum
->get (e
);
3246 struct ipa_jump_func
*jf
= ipa_get_ith_jump_func (args
, size_arg
);
3249 size
= ipa_value_from_jfunc (caller_parms_info
, jf
,
3250 get_parm_type (e
->callee
->decl
, size_arg
));
3252 else if (fnspec
.arg_access_size_given_by_type_p (i
))
3253 size
= TYPE_SIZE_UNIT (get_parm_type (e
->callee
->decl
, i
));
3254 modref_access_node a
= {0, -1, -1,
3255 map
.parm_offset
, map
.parm_index
,
3256 map
.parm_offset_known
};
3257 poly_int64 size_hwi
;
3259 && poly_int_tree_p (size
, &size_hwi
)
3260 && coeffs_in_range_p (size_hwi
, 0,
3261 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
3264 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
3269 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
3270 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
3273 propagate_unknown_call (cgraph_node
*node
,
3274 cgraph_edge
*e
, int ecf_flags
,
3275 modref_summary
*cur_summary
,
3276 modref_summary_lto
*cur_summary_lto
)
3278 bool changed
= false;
3279 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
3280 auto_vec
<modref_parm_map
, 32> parm_map
;
3282 && compute_parm_map (e
, &parm_map
))
3284 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
3286 gcc_checking_assert (fnspec
.known_p ());
3287 if (fnspec
.global_memory_read_p ())
3288 collapse_loads (cur_summary
, cur_summary_lto
);
3291 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
3292 for (unsigned i
= 0; i
< parm_map
.length () && t
;
3293 i
++, t
= TREE_CHAIN (t
))
3294 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
3296 else if (!fnspec
.arg_specified_p (i
)
3297 || fnspec
.arg_maybe_read_p (i
))
3299 modref_parm_map map
= parm_map
[i
];
3300 if (map
.parm_index
== -2)
3302 if (map
.parm_index
== -1)
3304 collapse_loads (cur_summary
, cur_summary_lto
);
3308 changed
|= cur_summary
->loads
->insert
3309 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3310 if (cur_summary_lto
)
3311 changed
|= cur_summary_lto
->loads
->insert
3312 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3315 if (ignore_stores_p (node
->decl
, ecf_flags
))
3317 else if (fnspec
.global_memory_written_p ())
3318 collapse_stores (cur_summary
, cur_summary_lto
);
3321 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
3322 for (unsigned i
= 0; i
< parm_map
.length () && t
;
3323 i
++, t
= TREE_CHAIN (t
))
3324 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
3326 else if (!fnspec
.arg_specified_p (i
)
3327 || fnspec
.arg_maybe_written_p (i
))
3329 modref_parm_map map
= parm_map
[i
];
3330 if (map
.parm_index
== -2)
3332 if (map
.parm_index
== -1)
3334 collapse_stores (cur_summary
, cur_summary_lto
);
3338 changed
|= cur_summary
->stores
->insert
3339 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3340 if (cur_summary_lto
)
3341 changed
|= cur_summary_lto
->stores
->insert
3342 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3345 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
3347 if (cur_summary
&& !cur_summary
->writes_errno
)
3349 cur_summary
->writes_errno
= true;
3352 if (cur_summary_lto
&& !cur_summary_lto
->writes_errno
)
3354 cur_summary_lto
->writes_errno
= true;
3361 fprintf (dump_file
, " collapsing loads\n");
3362 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
3363 if (!ignore_stores_p (node
->decl
, ecf_flags
))
3366 fprintf (dump_file
, " collapsing stores\n");
3367 changed
|= collapse_stores (cur_summary
, cur_summary_lto
);
3372 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
3373 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
3376 remove_useless_summaries (cgraph_node
*node
,
3377 modref_summary
**cur_summary_ptr
,
3378 modref_summary_lto
**cur_summary_lto_ptr
,
3381 if (*cur_summary_ptr
&& !(*cur_summary_ptr
)->useful_p (ecf_flags
, false))
3383 optimization_summaries
->remove (node
);
3384 *cur_summary_ptr
= NULL
;
3386 if (*cur_summary_lto_ptr
3387 && !(*cur_summary_lto_ptr
)->useful_p (ecf_flags
, false))
3389 summaries_lto
->remove (node
);
3390 *cur_summary_lto_ptr
= NULL
;
3394 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3395 and propagate loads/stores. */
3398 modref_propagate_in_scc (cgraph_node
*component_node
)
3400 bool changed
= true;
3406 for (struct cgraph_node
*cur
= component_node
; cur
;
3407 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3409 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
3410 modref_summary
*cur_summary
= optimization_summaries
3411 ? optimization_summaries
->get (node
)
3413 modref_summary_lto
*cur_summary_lto
= summaries_lto
3414 ? summaries_lto
->get (node
)
3417 if (!cur_summary
&& !cur_summary_lto
)
3420 int cur_ecf_flags
= flags_from_decl_or_type (node
->decl
);
3423 fprintf (dump_file
, " Processing %s%s%s\n",
3425 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3426 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3428 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
3430 if (e
->indirect_info
->ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
3433 fprintf (dump_file
, " Indirect call"
3434 "collapsing loads\n");
3435 if (propagate_unknown_call
3436 (node
, e
, e
->indirect_info
->ecf_flags
,
3437 cur_summary
, cur_summary_lto
))
3440 remove_useless_summaries (node
, &cur_summary
,
3443 if (!cur_summary
&& !cur_summary_lto
)
3448 if (!cur_summary
&& !cur_summary_lto
)
3451 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
3452 callee_edge
= callee_edge
->next_callee
)
3454 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
3455 modref_summary
*callee_summary
= NULL
;
3456 modref_summary_lto
*callee_summary_lto
= NULL
;
3457 struct cgraph_node
*callee
;
3459 if (flags
& (ECF_CONST
| ECF_NOVOPS
)
3460 || !callee_edge
->inline_failed
)
3463 /* Get the callee and its summary. */
3464 enum availability avail
;
3465 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
3468 /* It is not necessary to re-process calls outside of the
3472 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
3473 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
3477 fprintf (dump_file
, " Call to %s\n",
3478 callee_edge
->callee
->dump_name ());
3480 bool ignore_stores
= ignore_stores_p (cur
->decl
, flags
);
3482 if (avail
<= AVAIL_INTERPOSABLE
)
3485 fprintf (dump_file
, " Call target interposable"
3486 " or not available\n");
3487 changed
|= propagate_unknown_call
3488 (node
, callee_edge
, flags
,
3489 cur_summary
, cur_summary_lto
);
3490 if (!cur_summary
&& !cur_summary_lto
)
3495 /* We don't know anything about CALLEE, hence we cannot tell
3496 anything about the entire component. */
3499 && !(callee_summary
= optimization_summaries
->get (callee
)))
3502 fprintf (dump_file
, " No call target summary\n");
3503 changed
|= propagate_unknown_call
3504 (node
, callee_edge
, flags
,
3508 && !(callee_summary_lto
= summaries_lto
->get (callee
)))
3511 fprintf (dump_file
, " No call target summary\n");
3512 changed
|= propagate_unknown_call
3513 (node
, callee_edge
, flags
,
3514 NULL
, cur_summary_lto
);
3517 /* We can not safely optimize based on summary of callee if it
3518 does not always bind to current def: it is possible that
3519 memory load was optimized out earlier which may not happen in
3520 the interposed variant. */
3521 if (!callee_edge
->binds_to_current_def_p ())
3523 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
3525 fprintf (dump_file
, " May not bind local;"
3526 " collapsing loads\n");
3530 auto_vec
<modref_parm_map
, 32> parm_map
;
3532 compute_parm_map (callee_edge
, &parm_map
);
3534 /* Merge in callee's information. */
3537 changed
|= cur_summary
->loads
->merge
3538 (callee_summary
->loads
, &parm_map
);
3541 changed
|= cur_summary
->stores
->merge
3542 (callee_summary
->stores
, &parm_map
);
3543 if (!cur_summary
->writes_errno
3544 && callee_summary
->writes_errno
)
3546 cur_summary
->writes_errno
= true;
3551 if (callee_summary_lto
)
3553 changed
|= cur_summary_lto
->loads
->merge
3554 (callee_summary_lto
->loads
, &parm_map
);
3557 changed
|= cur_summary_lto
->stores
->merge
3558 (callee_summary_lto
->stores
, &parm_map
);
3559 if (!cur_summary_lto
->writes_errno
3560 && callee_summary_lto
->writes_errno
)
3562 cur_summary_lto
->writes_errno
= true;
3568 remove_useless_summaries (node
, &cur_summary
,
3571 if (!cur_summary
&& !cur_summary_lto
)
3573 if (dump_file
&& changed
)
3576 cur_summary
->dump (dump_file
);
3577 if (cur_summary_lto
)
3578 cur_summary_lto
->dump (dump_file
);
3579 dump_modref_edge_summaries (dump_file
, node
, 4);
3587 "Propagation finished in %i iterations\n", iteration
);
3590 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
3593 modref_propagate_dump_scc (cgraph_node
*component_node
)
3595 for (struct cgraph_node
*cur
= component_node
; cur
;
3596 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3597 if (!cur
->inlined_to
)
3599 modref_summary
*cur_summary
= optimization_summaries
3600 ? optimization_summaries
->get (cur
)
3602 modref_summary_lto
*cur_summary_lto
= summaries_lto
3603 ? summaries_lto
->get (cur
)
3606 fprintf (dump_file
, "Propagated modref for %s%s%s\n",
3608 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3609 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3610 if (optimization_summaries
)
3613 cur_summary
->dump (dump_file
);
3615 fprintf (dump_file
, " Not tracked\n");
3619 if (cur_summary_lto
)
3620 cur_summary_lto
->dump (dump_file
);
3622 fprintf (dump_file
, " Not tracked (lto)\n");
3627 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
3628 and SUMMARY_LTO to CUR_SUMMARY_LTO.
3629 Return true if something changed. */
3632 modref_merge_call_site_flags (escape_summary
*sum
,
3633 modref_summary
*cur_summary
,
3634 modref_summary_lto
*cur_summary_lto
,
3635 modref_summary
*summary
,
3636 modref_summary_lto
*summary_lto
,
3641 bool changed
= false;
3643 /* If we have no useful info to propagate. */
3644 if ((!cur_summary
|| !cur_summary
->arg_flags
.length ())
3645 && (!cur_summary_lto
|| !cur_summary_lto
->arg_flags
.length ()))
3648 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3653 if (summary
&& ee
->arg
< summary
->arg_flags
.length ())
3654 flags
= summary
->arg_flags
[ee
->arg
];
3656 && ee
->arg
< summary_lto
->arg_flags
.length ())
3657 flags_lto
= summary_lto
->arg_flags
[ee
->arg
];
3660 flags
= deref_flags (flags
, ignore_stores
);
3661 flags_lto
= deref_flags (flags_lto
, ignore_stores
);
3663 else if (ignore_stores
)
3665 flags
|= EAF_NOESCAPE
| EAF_NOCLOBBER
| EAF_NODIRECTESCAPE
;
3666 flags_lto
|= EAF_NOESCAPE
| EAF_NOCLOBBER
| EAF_NODIRECTESCAPE
;
3668 flags
|= ee
->min_flags
;
3669 flags_lto
|= ee
->min_flags
;
3670 if (!(flags
& EAF_UNUSED
)
3671 && cur_summary
&& ee
->parm_index
< cur_summary
->arg_flags
.length ())
3673 int f
= cur_summary
->arg_flags
[ee
->parm_index
];
3674 if ((f
& flags
) != f
)
3677 if ((f
& ~(EAF_DIRECT
| EAF_NOCLOBBER
)) == 0)
3679 cur_summary
->arg_flags
[ee
->parm_index
] = f
;
3683 if (!(flags_lto
& EAF_UNUSED
)
3685 && ee
->parm_index
< cur_summary_lto
->arg_flags
.length ())
3687 int f
= cur_summary_lto
->arg_flags
[ee
->parm_index
];
3688 if ((f
& flags_lto
) != f
)
3691 if ((f
& ~(EAF_DIRECT
| EAF_NOCLOBBER
)) == 0)
3693 cur_summary_lto
->arg_flags
[ee
->parm_index
] = f
;
3701 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3702 and propagate arg flags. */
3705 modref_propagate_flags_in_scc (cgraph_node
*component_node
)
3707 bool changed
= true;
3713 for (struct cgraph_node
*cur
= component_node
; cur
;
3714 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3716 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
3717 modref_summary
*cur_summary
= optimization_summaries
3718 ? optimization_summaries
->get (node
)
3720 modref_summary_lto
*cur_summary_lto
= summaries_lto
3721 ? summaries_lto
->get (node
)
3724 if (!cur_summary
&& !cur_summary_lto
)
3728 fprintf (dump_file
, " Processing %s%s%s\n",
3730 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3731 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3733 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
3735 escape_summary
*sum
= escape_summaries
->get (e
);
3737 if (!sum
|| (e
->indirect_info
->ecf_flags
3738 & (ECF_CONST
| ECF_NOVOPS
)))
3741 changed
|= modref_merge_call_site_flags
3742 (sum
, cur_summary
, cur_summary_lto
,
3743 NULL
, NULL
, ignore_stores_p (node
->decl
,
3744 e
->indirect_info
->ecf_flags
));
3747 if (!cur_summary
&& !cur_summary_lto
)
3750 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
3751 callee_edge
= callee_edge
->next_callee
)
3753 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
3754 modref_summary
*callee_summary
= NULL
;
3755 modref_summary_lto
*callee_summary_lto
= NULL
;
3756 struct cgraph_node
*callee
;
3758 if (flags
& (ECF_CONST
| ECF_NOVOPS
)
3759 || !callee_edge
->inline_failed
)
3761 /* Get the callee and its summary. */
3762 enum availability avail
;
3763 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
3766 /* It is not necessary to re-process calls outside of the
3770 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
3771 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
3774 escape_summary
*sum
= escape_summaries
->get (callee_edge
);
3779 fprintf (dump_file
, " Call to %s\n",
3780 callee_edge
->callee
->dump_name ());
3782 if (avail
<= AVAIL_INTERPOSABLE
3783 || callee_edge
->call_stmt_cannot_inline_p
)
3788 callee_summary
= optimization_summaries
->get (callee
);
3789 if (cur_summary_lto
)
3790 callee_summary_lto
= summaries_lto
->get (callee
);
3792 changed
|= modref_merge_call_site_flags
3793 (sum
, cur_summary
, cur_summary_lto
,
3794 callee_summary
, callee_summary_lto
,
3795 ignore_stores_p (node
->decl
, flags
));
3796 if (dump_file
&& changed
)
3799 cur_summary
->dump (dump_file
);
3800 if (cur_summary_lto
)
3801 cur_summary_lto
->dump (dump_file
);
3809 "Propagation of flags finished in %i iterations\n", iteration
);
3812 /* Run the IPA pass. This will take a function's summaries and calls and
3813 construct new summaries which represent a transitive closure. So that
3814 summary of an analyzed function contains information about the loads and
3815 stores that the function or any function that it calls does. */
3818 pass_ipa_modref::execute (function
*)
3820 if (!summaries
&& !summaries_lto
)
3823 if (optimization_summaries
)
3824 ggc_delete (optimization_summaries
);
3825 optimization_summaries
= summaries
;
3828 struct cgraph_node
**order
= XCNEWVEC (struct cgraph_node
*,
3829 symtab
->cgraph_count
);
3831 order_pos
= ipa_reduced_postorder (order
, true, ignore_edge
);
3834 /* Iterate over all strongly connected components in post-order. */
3835 for (i
= 0; i
< order_pos
; i
++)
3837 /* Get the component's representative. That's just any node in the
3838 component from which we can traverse the entire component. */
3839 struct cgraph_node
*component_node
= order
[i
];
3842 fprintf (dump_file
, "\n\nStart of SCC component\n");
3844 modref_propagate_in_scc (component_node
);
3845 modref_propagate_flags_in_scc (component_node
);
3847 modref_propagate_dump_scc (component_node
);
3850 FOR_EACH_FUNCTION (node
)
3851 update_signature (node
);
3853 ((modref_summaries_lto
*)summaries_lto
)->propagated
= true;
3854 ipa_free_postorder_info ();
3856 delete fnspec_summaries
;
3857 fnspec_summaries
= NULL
;
3858 delete escape_summaries
;
3859 escape_summaries
= NULL
;
3863 /* Summaries must stay alive until end of compilation. */
3866 ipa_modref_c_finalize ()
3868 if (optimization_summaries
)
3869 ggc_delete (optimization_summaries
);
3870 optimization_summaries
= NULL
;
3871 gcc_checking_assert (!summaries
3872 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
3874 ggc_delete (summaries_lto
);
3875 summaries_lto
= NULL
;
3876 if (fnspec_summaries
)
3877 delete fnspec_summaries
;
3878 fnspec_summaries
= NULL
;
3879 if (escape_summaries
)
3880 delete escape_summaries
;
3881 escape_summaries
= NULL
;
3884 #include "gt-ipa-modref.h"