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 (lattice
[SSA_NAME_VERSION (lhs
)]);
1550 lattice
[index
].merge_deref (lattice
[SSA_NAME_VERSION (lhs
)], false);
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 optiomization 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_REF (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
);
2912 caller_parms_info
= IPA_NODE_REF (callee_edge
->caller
->inlined_to
2913 ? callee_edge
->caller
->inlined_to
2914 : callee_edge
->caller
);
2915 callee_pi
= IPA_NODE_REF (callee
);
2917 (*parm_map
).safe_grow_cleared (count
, true);
2919 for (i
= 0; i
< count
; i
++)
2921 if (es
&& es
->param
[i
].points_to_local_or_readonly_memory
)
2923 (*parm_map
)[i
].parm_index
= -2;
2927 struct ipa_jump_func
*jf
2928 = ipa_get_ith_jump_func (args
, i
);
2929 if (jf
&& callee_pi
)
2931 tree cst
= ipa_value_from_jfunc (caller_parms_info
,
2935 if (cst
&& points_to_local_or_readonly_memory_p (cst
))
2937 (*parm_map
)[i
].parm_index
= -2;
2941 if (jf
&& jf
->type
== IPA_JF_PASS_THROUGH
)
2943 (*parm_map
)[i
].parm_index
2944 = ipa_get_jf_pass_through_formal_id (jf
);
2945 if (ipa_get_jf_pass_through_operation (jf
) == NOP_EXPR
)
2947 (*parm_map
)[i
].parm_offset_known
= true;
2948 (*parm_map
)[i
].parm_offset
= 0;
2950 else if (ipa_get_jf_pass_through_operation (jf
)
2951 == POINTER_PLUS_EXPR
2952 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf
),
2953 &(*parm_map
)[i
].parm_offset
))
2954 (*parm_map
)[i
].parm_offset_known
= true;
2956 (*parm_map
)[i
].parm_offset_known
= false;
2959 if (jf
&& jf
->type
== IPA_JF_ANCESTOR
)
2961 (*parm_map
)[i
].parm_index
= ipa_get_jf_ancestor_formal_id (jf
);
2962 (*parm_map
)[i
].parm_offset_known
= true;
2964 (!(ipa_get_jf_ancestor_offset (jf
) & (BITS_PER_UNIT
- 1)));
2965 (*parm_map
)[i
].parm_offset
2966 = ipa_get_jf_ancestor_offset (jf
) >> LOG2_BITS_PER_UNIT
;
2969 (*parm_map
)[i
].parm_index
= -1;
2973 fprintf (dump_file
, " Parm map: ");
2974 for (i
= 0; i
< count
; i
++)
2975 fprintf (dump_file
, " %i", (*parm_map
)[i
].parm_index
);
2976 fprintf (dump_file
, "\n");
2983 /* Map used to translate escape infos. */
2991 /* Update escape map fo E. */
2994 update_escape_summary_1 (cgraph_edge
*e
,
2995 vec
<vec
<escape_map
>> &map
)
2997 escape_summary
*sum
= escape_summaries
->get (e
);
3000 auto_vec
<escape_entry
> old
= sum
->esc
.copy ();
3001 sum
->esc
.release ();
3005 FOR_EACH_VEC_ELT (old
, i
, ee
)
3008 struct escape_map
*em
;
3009 if (ee
->parm_index
>= map
.length ())
3011 FOR_EACH_VEC_ELT (map
[ee
->parm_index
], j
, em
)
3013 struct escape_entry entry
= {em
->parm_index
, ee
->arg
,
3015 ee
->direct
& em
->direct
};
3016 sum
->esc
.safe_push (entry
);
3019 if (!sum
->esc
.length ())
3020 escape_summaries
->remove (e
);
3023 /* Update escape map fo NODE. */
3026 update_escape_summary (cgraph_node
*node
,
3027 vec
<vec
<escape_map
>> &map
)
3029 if (!escape_summaries
)
3031 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
3032 update_escape_summary_1 (e
, map
);
3033 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
3035 if (!e
->inline_failed
)
3036 update_escape_summary (e
->callee
, map
);
3038 update_escape_summary_1 (e
, map
);
3042 /* Call EDGE was inlined; merge summary from callee to the caller. */
3045 ipa_merge_modref_summary_after_inlining (cgraph_edge
*edge
)
3047 if (!summaries
&& !summaries_lto
)
3050 struct cgraph_node
*to
= (edge
->caller
->inlined_to
3051 ? edge
->caller
->inlined_to
: edge
->caller
);
3052 class modref_summary
*to_info
= summaries
? summaries
->get (to
) : NULL
;
3053 class modref_summary_lto
*to_info_lto
= summaries_lto
3054 ? summaries_lto
->get (to
) : NULL
;
3056 if (!to_info
&& !to_info_lto
)
3059 summaries
->remove (edge
->callee
);
3061 summaries_lto
->remove (edge
->callee
);
3062 remove_modref_edge_summaries (edge
->callee
);
3066 class modref_summary
*callee_info
= summaries
? summaries
->get (edge
->callee
)
3068 class modref_summary_lto
*callee_info_lto
3069 = summaries_lto
? summaries_lto
->get (edge
->callee
) : NULL
;
3070 int flags
= flags_from_decl_or_type (edge
->callee
->decl
);
3071 bool ignore_stores
= ignore_stores_p (edge
->caller
->decl
, flags
);
3073 if (!callee_info
&& to_info
)
3075 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3076 to_info
->loads
->collapse ();
3078 to_info
->stores
->collapse ();
3080 if (!callee_info_lto
&& to_info_lto
)
3082 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3083 to_info_lto
->loads
->collapse ();
3085 to_info_lto
->stores
->collapse ();
3087 if (callee_info
|| callee_info_lto
)
3089 auto_vec
<modref_parm_map
, 32> parm_map
;
3091 compute_parm_map (edge
, &parm_map
);
3095 if (to_info
&& callee_info
)
3096 to_info
->stores
->merge (callee_info
->stores
, &parm_map
);
3097 if (to_info_lto
&& callee_info_lto
)
3098 to_info_lto
->stores
->merge (callee_info_lto
->stores
, &parm_map
);
3100 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3102 if (to_info
&& callee_info
)
3103 to_info
->loads
->merge (callee_info
->loads
, &parm_map
);
3104 if (to_info_lto
&& callee_info_lto
)
3105 to_info_lto
->loads
->merge (callee_info_lto
->loads
, &parm_map
);
3109 /* Now merge escape summaries.
3110 For every escape to the callee we need to merge calle flags
3111 and remap calees escapes. */
3112 class escape_summary
*sum
= escape_summaries
->get (edge
);
3113 int max_escape
= -1;
3117 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3118 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3119 if ((int)ee
->arg
> max_escape
)
3120 max_escape
= ee
->arg
;
3122 auto_vec
<vec
<struct escape_map
>, 32> emap (max_escape
+ 1);
3123 emap
.safe_grow (max_escape
+ 1, true);
3124 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
3127 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3128 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3130 bool needed
= false;
3131 if (to_info
&& to_info
->arg_flags
.length () > ee
->parm_index
)
3133 int flags
= callee_info
3134 && callee_info
->arg_flags
.length () > ee
->arg
3135 ? callee_info
->arg_flags
[ee
->arg
] : 0;
3137 flags
= deref_flags (flags
, ignore_stores
);
3138 else if (ignore_stores
)
3139 flags
|= EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_NODIRECTESCAPE
;
3140 flags
|= ee
->min_flags
;
3141 to_info
->arg_flags
[ee
->parm_index
] &= flags
;
3142 if (to_info
->arg_flags
[ee
->parm_index
])
3145 if (to_info_lto
&& to_info_lto
->arg_flags
.length () > ee
->parm_index
)
3147 int flags
= callee_info_lto
3148 && callee_info_lto
->arg_flags
.length () > ee
->arg
3149 ? callee_info_lto
->arg_flags
[ee
->arg
] : 0;
3151 flags
= deref_flags (flags
, ignore_stores
);
3152 else if (ignore_stores
)
3153 flags
|= EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_NODIRECTESCAPE
;
3154 flags
|= ee
->min_flags
;
3155 to_info_lto
->arg_flags
[ee
->parm_index
] &= flags
;
3156 if (to_info_lto
->arg_flags
[ee
->parm_index
])
3159 struct escape_map entry
= {ee
->parm_index
, ee
->direct
};
3161 emap
[ee
->arg
].safe_push (entry
);
3163 update_escape_summary (edge
->callee
, emap
);
3164 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
3167 escape_summaries
->remove (edge
);
3171 if (to_info
&& !to_info
->useful_p (flags
))
3174 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
3176 summaries
->remove (to
);
3179 else if (to_info
&& dump_file
)
3182 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
3184 to_info
->dump (dump_file
);
3187 summaries
->remove (edge
->callee
);
3191 if (to_info_lto
&& !to_info_lto
->useful_p (flags
))
3194 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
3196 summaries_lto
->remove (to
);
3198 else if (to_info_lto
&& dump_file
)
3201 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
3203 to_info_lto
->dump (dump_file
);
3206 if (callee_info_lto
)
3207 summaries_lto
->remove (edge
->callee
);
3209 if (!to_info
&& !to_info_lto
)
3210 remove_modref_edge_summaries (to
);
3214 /* Get parameter type from DECL. This is only safe for special cases
3215 like builtins we create fnspec for because the type match is checked
3216 at fnspec creation time. */
3219 get_parm_type (tree decl
, unsigned int i
)
3221 tree t
= TYPE_ARG_TYPES (TREE_TYPE (decl
));
3223 for (unsigned int p
= 0; p
< i
; p
++)
3225 return TREE_VALUE (t
);
3228 /* Return access mode for argument I of call E with FNSPEC. */
3230 static modref_access_node
3231 get_access_for_fnspec (cgraph_edge
*e
, attr_fnspec
&fnspec
,
3232 unsigned int i
, modref_parm_map
&map
)
3234 tree size
= NULL_TREE
;
3235 unsigned int size_arg
;
3237 if (!fnspec
.arg_specified_p (i
))
3239 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
3241 cgraph_node
*node
= e
->caller
->inlined_to
3242 ? e
->caller
->inlined_to
: e
->caller
;
3243 class ipa_node_params
*caller_parms_info
= IPA_NODE_REF (node
);
3244 class ipa_edge_args
*args
= IPA_EDGE_REF (e
);
3245 struct ipa_jump_func
*jf
= ipa_get_ith_jump_func (args
, size_arg
);
3248 size
= ipa_value_from_jfunc (caller_parms_info
, jf
,
3249 get_parm_type (e
->callee
->decl
, size_arg
));
3251 else if (fnspec
.arg_access_size_given_by_type_p (i
))
3252 size
= TYPE_SIZE_UNIT (get_parm_type (e
->callee
->decl
, i
));
3253 modref_access_node a
= {0, -1, -1,
3254 map
.parm_offset
, map
.parm_index
,
3255 map
.parm_offset_known
};
3256 poly_int64 size_hwi
;
3258 && poly_int_tree_p (size
, &size_hwi
)
3259 && coeffs_in_range_p (size_hwi
, 0,
3260 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
3263 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
3268 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
3269 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
3272 propagate_unknown_call (cgraph_node
*node
,
3273 cgraph_edge
*e
, int ecf_flags
,
3274 modref_summary
*cur_summary
,
3275 modref_summary_lto
*cur_summary_lto
)
3277 bool changed
= false;
3278 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
3279 auto_vec
<modref_parm_map
, 32> parm_map
;
3281 && compute_parm_map (e
, &parm_map
))
3283 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
3285 gcc_checking_assert (fnspec
.known_p ());
3286 if (fnspec
.global_memory_read_p ())
3287 collapse_loads (cur_summary
, cur_summary_lto
);
3290 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
3291 for (unsigned i
= 0; i
< parm_map
.length () && t
;
3292 i
++, t
= TREE_CHAIN (t
))
3293 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
3295 else if (!fnspec
.arg_specified_p (i
)
3296 || fnspec
.arg_maybe_read_p (i
))
3298 modref_parm_map map
= parm_map
[i
];
3299 if (map
.parm_index
== -2)
3301 if (map
.parm_index
== -1)
3303 collapse_loads (cur_summary
, cur_summary_lto
);
3307 changed
|= cur_summary
->loads
->insert
3308 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3309 if (cur_summary_lto
)
3310 changed
|= cur_summary_lto
->loads
->insert
3311 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3314 if (ignore_stores_p (node
->decl
, ecf_flags
))
3316 else if (fnspec
.global_memory_written_p ())
3317 collapse_stores (cur_summary
, cur_summary_lto
);
3320 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
3321 for (unsigned i
= 0; i
< parm_map
.length () && t
;
3322 i
++, t
= TREE_CHAIN (t
))
3323 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
3325 else if (!fnspec
.arg_specified_p (i
)
3326 || fnspec
.arg_maybe_written_p (i
))
3328 modref_parm_map map
= parm_map
[i
];
3329 if (map
.parm_index
== -2)
3331 if (map
.parm_index
== -1)
3333 collapse_stores (cur_summary
, cur_summary_lto
);
3337 changed
|= cur_summary
->stores
->insert
3338 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3339 if (cur_summary_lto
)
3340 changed
|= cur_summary_lto
->stores
->insert
3341 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3344 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
3346 if (cur_summary
&& !cur_summary
->writes_errno
)
3348 cur_summary
->writes_errno
= true;
3351 if (cur_summary_lto
&& !cur_summary_lto
->writes_errno
)
3353 cur_summary_lto
->writes_errno
= true;
3360 fprintf (dump_file
, " collapsing loads\n");
3361 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
3362 if (!ignore_stores_p (node
->decl
, ecf_flags
))
3365 fprintf (dump_file
, " collapsing stores\n");
3366 changed
|= collapse_stores (cur_summary
, cur_summary_lto
);
3371 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
3372 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
3375 remove_useless_summaries (cgraph_node
*node
,
3376 modref_summary
**cur_summary_ptr
,
3377 modref_summary_lto
**cur_summary_lto_ptr
,
3380 if (*cur_summary_ptr
&& !(*cur_summary_ptr
)->useful_p (ecf_flags
, false))
3382 optimization_summaries
->remove (node
);
3383 *cur_summary_ptr
= NULL
;
3385 if (*cur_summary_lto_ptr
3386 && !(*cur_summary_lto_ptr
)->useful_p (ecf_flags
, false))
3388 summaries_lto
->remove (node
);
3389 *cur_summary_lto_ptr
= NULL
;
3393 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3394 and propagate loads/stores. */
3397 modref_propagate_in_scc (cgraph_node
*component_node
)
3399 bool changed
= true;
3405 for (struct cgraph_node
*cur
= component_node
; cur
;
3406 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3408 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
3409 modref_summary
*cur_summary
= optimization_summaries
3410 ? optimization_summaries
->get (node
)
3412 modref_summary_lto
*cur_summary_lto
= summaries_lto
3413 ? summaries_lto
->get (node
)
3416 if (!cur_summary
&& !cur_summary_lto
)
3419 int cur_ecf_flags
= flags_from_decl_or_type (node
->decl
);
3422 fprintf (dump_file
, " Processing %s%s%s\n",
3424 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3425 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3427 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
3429 if (e
->indirect_info
->ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
3432 fprintf (dump_file
, " Indirect call"
3433 "collapsing loads\n");
3434 if (propagate_unknown_call
3435 (node
, e
, e
->indirect_info
->ecf_flags
,
3436 cur_summary
, cur_summary_lto
))
3439 remove_useless_summaries (node
, &cur_summary
,
3442 if (!cur_summary
&& !cur_summary_lto
)
3447 if (!cur_summary
&& !cur_summary_lto
)
3450 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
3451 callee_edge
= callee_edge
->next_callee
)
3453 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
3454 modref_summary
*callee_summary
= NULL
;
3455 modref_summary_lto
*callee_summary_lto
= NULL
;
3456 struct cgraph_node
*callee
;
3458 if (flags
& (ECF_CONST
| ECF_NOVOPS
)
3459 || !callee_edge
->inline_failed
)
3462 /* Get the callee and its summary. */
3463 enum availability avail
;
3464 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
3467 /* It is not necessary to re-process calls outside of the
3471 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
3472 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
3476 fprintf (dump_file
, " Call to %s\n",
3477 callee_edge
->callee
->dump_name ());
3479 bool ignore_stores
= ignore_stores_p (cur
->decl
, flags
);
3481 if (avail
<= AVAIL_INTERPOSABLE
)
3484 fprintf (dump_file
, " Call target interposable"
3485 " or not available\n");
3486 changed
|= propagate_unknown_call
3487 (node
, callee_edge
, flags
,
3488 cur_summary
, cur_summary_lto
);
3489 if (!cur_summary
&& !cur_summary_lto
)
3494 /* We don't know anything about CALLEE, hence we cannot tell
3495 anything about the entire component. */
3498 && !(callee_summary
= optimization_summaries
->get (callee
)))
3501 fprintf (dump_file
, " No call target summary\n");
3502 changed
|= propagate_unknown_call
3503 (node
, callee_edge
, flags
,
3507 && !(callee_summary_lto
= summaries_lto
->get (callee
)))
3510 fprintf (dump_file
, " No call target summary\n");
3511 changed
|= propagate_unknown_call
3512 (node
, callee_edge
, flags
,
3513 NULL
, cur_summary_lto
);
3516 /* We can not safely optimize based on summary of callee if it
3517 does not always bind to current def: it is possible that
3518 memory load was optimized out earlier which may not happen in
3519 the interposed variant. */
3520 if (!callee_edge
->binds_to_current_def_p ())
3522 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
3524 fprintf (dump_file
, " May not bind local;"
3525 " collapsing loads\n");
3529 auto_vec
<modref_parm_map
, 32> parm_map
;
3531 compute_parm_map (callee_edge
, &parm_map
);
3533 /* Merge in callee's information. */
3536 changed
|= cur_summary
->loads
->merge
3537 (callee_summary
->loads
, &parm_map
);
3540 changed
|= cur_summary
->stores
->merge
3541 (callee_summary
->stores
, &parm_map
);
3542 if (!cur_summary
->writes_errno
3543 && callee_summary
->writes_errno
)
3545 cur_summary
->writes_errno
= true;
3550 if (callee_summary_lto
)
3552 changed
|= cur_summary_lto
->loads
->merge
3553 (callee_summary_lto
->loads
, &parm_map
);
3556 changed
|= cur_summary_lto
->stores
->merge
3557 (callee_summary_lto
->stores
, &parm_map
);
3558 if (!cur_summary_lto
->writes_errno
3559 && callee_summary_lto
->writes_errno
)
3561 cur_summary_lto
->writes_errno
= true;
3567 remove_useless_summaries (node
, &cur_summary
,
3570 if (!cur_summary
&& !cur_summary_lto
)
3572 if (dump_file
&& changed
)
3575 cur_summary
->dump (dump_file
);
3576 if (cur_summary_lto
)
3577 cur_summary_lto
->dump (dump_file
);
3578 dump_modref_edge_summaries (dump_file
, node
, 4);
3586 "Propagation finished in %i iterations\n", iteration
);
3589 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
3592 modref_propagate_dump_scc (cgraph_node
*component_node
)
3594 for (struct cgraph_node
*cur
= component_node
; cur
;
3595 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3596 if (!cur
->inlined_to
)
3598 modref_summary
*cur_summary
= optimization_summaries
3599 ? optimization_summaries
->get (cur
)
3601 modref_summary_lto
*cur_summary_lto
= summaries_lto
3602 ? summaries_lto
->get (cur
)
3605 fprintf (dump_file
, "Propagated modref for %s%s%s\n",
3607 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3608 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3609 if (optimization_summaries
)
3612 cur_summary
->dump (dump_file
);
3614 fprintf (dump_file
, " Not tracked\n");
3618 if (cur_summary_lto
)
3619 cur_summary_lto
->dump (dump_file
);
3621 fprintf (dump_file
, " Not tracked (lto)\n");
3626 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
3627 and SUMMARY_LTO to CUR_SUMMARY_LTO.
3628 Return true if something changed. */
3631 modref_merge_call_site_flags (escape_summary
*sum
,
3632 modref_summary
*cur_summary
,
3633 modref_summary_lto
*cur_summary_lto
,
3634 modref_summary
*summary
,
3635 modref_summary_lto
*summary_lto
,
3640 bool changed
= false;
3642 /* If we have no useful info to propagate. */
3643 if ((!cur_summary
|| !cur_summary
->arg_flags
.length ())
3644 && (!cur_summary_lto
|| !cur_summary_lto
->arg_flags
.length ()))
3647 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3652 if (summary
&& ee
->arg
< summary
->arg_flags
.length ())
3653 flags
= summary
->arg_flags
[ee
->arg
];
3655 && ee
->arg
< summary_lto
->arg_flags
.length ())
3656 flags_lto
= summary_lto
->arg_flags
[ee
->arg
];
3659 flags
= deref_flags (flags
, ignore_stores
);
3660 flags_lto
= deref_flags (flags_lto
, ignore_stores
);
3662 else if (ignore_stores
)
3664 flags
|= EAF_NOESCAPE
| EAF_NOCLOBBER
| EAF_NODIRECTESCAPE
;
3665 flags_lto
|= EAF_NOESCAPE
| EAF_NOCLOBBER
| EAF_NODIRECTESCAPE
;
3667 flags
|= ee
->min_flags
;
3668 flags_lto
|= ee
->min_flags
;
3669 if (!(flags
& EAF_UNUSED
)
3670 && cur_summary
&& ee
->parm_index
< cur_summary
->arg_flags
.length ())
3672 int f
= cur_summary
->arg_flags
[ee
->parm_index
];
3673 if ((f
& flags
) != f
)
3676 if ((f
& ~(EAF_DIRECT
| EAF_NOCLOBBER
)) == 0)
3678 cur_summary
->arg_flags
[ee
->parm_index
] = f
;
3682 if (!(flags_lto
& EAF_UNUSED
)
3684 && ee
->parm_index
< cur_summary_lto
->arg_flags
.length ())
3686 int f
= cur_summary_lto
->arg_flags
[ee
->parm_index
];
3687 if ((f
& flags_lto
) != f
)
3690 if ((f
& ~(EAF_DIRECT
| EAF_NOCLOBBER
)) == 0)
3692 cur_summary_lto
->arg_flags
[ee
->parm_index
] = f
;
3700 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3701 and propagate arg flags. */
3704 modref_propagate_flags_in_scc (cgraph_node
*component_node
)
3706 bool changed
= true;
3712 for (struct cgraph_node
*cur
= component_node
; cur
;
3713 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3715 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
3716 modref_summary
*cur_summary
= optimization_summaries
3717 ? optimization_summaries
->get (node
)
3719 modref_summary_lto
*cur_summary_lto
= summaries_lto
3720 ? summaries_lto
->get (node
)
3723 if (!cur_summary
&& !cur_summary_lto
)
3727 fprintf (dump_file
, " Processing %s%s%s\n",
3729 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3730 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3732 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
3734 escape_summary
*sum
= escape_summaries
->get (e
);
3736 if (!sum
|| (e
->indirect_info
->ecf_flags
3737 & (ECF_CONST
| ECF_NOVOPS
)))
3740 changed
|= modref_merge_call_site_flags
3741 (sum
, cur_summary
, cur_summary_lto
,
3742 NULL
, NULL
, ignore_stores_p (node
->decl
,
3743 e
->indirect_info
->ecf_flags
));
3746 if (!cur_summary
&& !cur_summary_lto
)
3749 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
3750 callee_edge
= callee_edge
->next_callee
)
3752 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
3753 modref_summary
*callee_summary
= NULL
;
3754 modref_summary_lto
*callee_summary_lto
= NULL
;
3755 struct cgraph_node
*callee
;
3757 if (flags
& (ECF_CONST
| ECF_NOVOPS
)
3758 || !callee_edge
->inline_failed
)
3760 /* Get the callee and its summary. */
3761 enum availability avail
;
3762 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
3765 /* It is not necessary to re-process calls outside of the
3769 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
3770 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
3773 escape_summary
*sum
= escape_summaries
->get (callee_edge
);
3778 fprintf (dump_file
, " Call to %s\n",
3779 callee_edge
->callee
->dump_name ());
3781 if (avail
<= AVAIL_INTERPOSABLE
3782 || callee_edge
->call_stmt_cannot_inline_p
)
3787 callee_summary
= optimization_summaries
->get (callee
);
3788 if (cur_summary_lto
)
3789 callee_summary_lto
= summaries_lto
->get (callee
);
3791 changed
|= modref_merge_call_site_flags
3792 (sum
, cur_summary
, cur_summary_lto
,
3793 callee_summary
, callee_summary_lto
,
3794 ignore_stores_p (node
->decl
, flags
));
3795 if (dump_file
&& changed
)
3798 cur_summary
->dump (dump_file
);
3799 if (cur_summary_lto
)
3800 cur_summary_lto
->dump (dump_file
);
3808 "Propagation of flags finished in %i iterations\n", iteration
);
3811 /* Run the IPA pass. This will take a function's summaries and calls and
3812 construct new summaries which represent a transitive closure. So that
3813 summary of an analyzed function contains information about the loads and
3814 stores that the function or any function that it calls does. */
3817 pass_ipa_modref::execute (function
*)
3819 if (!summaries
&& !summaries_lto
)
3822 if (optimization_summaries
)
3823 ggc_delete (optimization_summaries
);
3824 optimization_summaries
= summaries
;
3827 struct cgraph_node
**order
= XCNEWVEC (struct cgraph_node
*,
3828 symtab
->cgraph_count
);
3830 order_pos
= ipa_reduced_postorder (order
, true, ignore_edge
);
3833 /* Iterate over all strongly connected components in post-order. */
3834 for (i
= 0; i
< order_pos
; i
++)
3836 /* Get the component's representative. That's just any node in the
3837 component from which we can traverse the entire component. */
3838 struct cgraph_node
*component_node
= order
[i
];
3841 fprintf (dump_file
, "\n\nStart of SCC component\n");
3843 modref_propagate_in_scc (component_node
);
3844 modref_propagate_flags_in_scc (component_node
);
3846 modref_propagate_dump_scc (component_node
);
3849 FOR_EACH_FUNCTION (node
)
3850 update_signature (node
);
3852 ((modref_summaries_lto
*)summaries_lto
)->propagated
= true;
3853 ipa_free_postorder_info ();
3855 delete fnspec_summaries
;
3856 fnspec_summaries
= NULL
;
3857 delete escape_summaries
;
3858 escape_summaries
= NULL
;
3862 /* Summaries must stay alive until end of compilation. */
3865 ipa_modref_c_finalize ()
3867 if (optimization_summaries
)
3868 ggc_delete (optimization_summaries
);
3869 optimization_summaries
= NULL
;
3870 gcc_checking_assert (!summaries
);
3872 ggc_delete (summaries_lto
);
3873 summaries_lto
= NULL
;
3874 if (fnspec_summaries
)
3875 delete fnspec_summaries
;
3876 fnspec_summaries
= NULL
;
3877 if (escape_summaries
)
3878 delete escape_summaries
;
3879 escape_summaries
= NULL
;
3882 #include "gt-ipa-modref.h"