1 /* Search for references that a functions loads or stores.
2 Copyright (C) 2020 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/dtores
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;
839 fprintf (dump_file
, " - Merging side effects of %s with parm map:",
840 callee_node
->dump_name ());
842 /* We can not safely optimize based on summary of callee if it does
843 not always bind to current def: it is possible that memory load
844 was optimized out earlier which may not happen in the interposed
846 if (!callee_node
->binds_to_current_def_p ())
849 fprintf (dump_file
, " - May be interposed: collapsing loads.\n");
850 cur_summary
->loads
->collapse ();
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 fnspec_summaries
->get_create
1251 (cgraph_node::get (current_function_decl
)->get_edge (stmt
))
1252 ->fnspec
= xstrdup (fnspec
.get_str ());
1254 fprintf (dump_file
, " Recorded fnspec %s\n", fnspec
.get_str ());
1259 /* Nothing to do for other types of statements. */
1264 /* Remove summary of current function because during the function body
1265 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1269 remove_summary (bool lto
, bool nolto
, bool ipa
)
1271 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1273 optimization_summaries
->remove (fnode
);
1277 summaries
->remove (fnode
);
1279 summaries_lto
->remove (fnode
);
1280 remove_modref_edge_summaries (fnode
);
1284 " - modref done with result: not tracked.\n");
1287 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1290 memory_access_to (tree op
, tree ssa_name
)
1292 tree base
= get_base_address (op
);
1295 if (TREE_CODE (base
) != MEM_REF
&& TREE_CODE (base
) != TARGET_MEM_REF
)
1297 return TREE_OPERAND (base
, 0) == ssa_name
;
1300 /* Consider statement val = *arg.
1301 return EAF flags of ARG that can be determined from EAF flags of VAL
1302 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1303 all stores to VAL, i.e. when handling noreturn function. */
1306 deref_flags (int flags
, bool ignore_stores
)
1308 int ret
= EAF_NODIRECTESCAPE
;
1309 if (flags
& EAF_UNUSED
)
1310 ret
|= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
;
1313 if ((flags
& EAF_NOCLOBBER
) || ignore_stores
)
1314 ret
|= EAF_NOCLOBBER
;
1315 if ((flags
& EAF_NOESCAPE
) || ignore_stores
)
1316 ret
|= EAF_NOESCAPE
;
1323 /* Description of an escape point. */
1327 /* Value escapes to this call. */
1329 /* Argument it escapes to. */
1331 /* Flags already known about the argument (this can save us from recording
1332 esape points if local analysis did good job already). */
1334 /* Does value escape directly or indiretly? */
1338 class modref_lattice
1341 /* EAF flags of the SSA name. */
1343 /* DFS bookkkeeping: we don't do real dataflow yet. */
1347 /* When doing IPA analysis we can not merge in callee escape points;
1348 Only remember them and do the merging at IPA propagation time. */
1349 vec
<escape_point
, va_heap
, vl_ptr
> escape_points
;
1353 bool merge (const modref_lattice
&with
);
1354 bool merge (int flags
);
1355 bool merge_deref (const modref_lattice
&with
, bool ignore_stores
);
1356 bool merge_direct_load ();
1357 bool merge_direct_store ();
1358 bool add_escape_point (gcall
*call
, int arg
, int min_flags
, bool diret
);
1359 void dump (FILE *out
, int indent
= 0) const;
1362 /* Lattices are saved to vectors, so keep them PODs. */
1364 modref_lattice::init ()
1366 flags
= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_UNUSED
1367 | EAF_NODIRECTESCAPE
;
1372 /* Release memory. */
1374 modref_lattice::release ()
1376 escape_points
.release ();
1379 /* Dump lattice to OUT; indent with INDENT spaces. */
1382 modref_lattice::dump (FILE *out
, int indent
) const
1384 dump_eaf_flags (out
, flags
);
1385 if (escape_points
.length ())
1387 fprintf (out
, "%*sEscapes:\n", indent
, "");
1388 for (unsigned int i
= 0; i
< escape_points
.length (); i
++)
1390 fprintf (out
, "%*s Arg %i (%s) min flags", indent
, "",
1391 escape_points
[i
].arg
,
1392 escape_points
[i
].direct
? "direct" : "indirect");
1393 dump_eaf_flags (out
, flags
, false);
1394 fprintf (out
, " in call ");
1395 print_gimple_stmt (out
, escape_points
[i
].call
, 0);
1400 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1404 modref_lattice::add_escape_point (gcall
*call
, int arg
, int min_flags
,
1410 /* If we already determined flags to be bad enough,
1411 * we do not need to record. */
1412 if ((flags
& min_flags
) == flags
)
1415 FOR_EACH_VEC_ELT (escape_points
, i
, ep
)
1416 if (ep
->call
== call
&& ep
->arg
== arg
&& ep
->direct
== direct
)
1418 if ((ep
->min_flags
& min_flags
) == min_flags
)
1420 ep
->min_flags
&= min_flags
;
1423 /* Give up if max escape points is met. */
1424 if ((int)escape_points
.length () > param_modref_max_escape_points
)
1427 fprintf (dump_file
, "--param modref-max-escape-points limit reached\n");
1431 escape_point new_ep
= {call
, arg
, min_flags
, direct
};
1432 escape_points
.safe_push (new_ep
);
1436 /* Merge in flags from F. */
1438 modref_lattice::merge (int f
)
1442 if ((flags
& f
) != flags
)
1445 /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
1446 in tree-ssa-alias.c). Give up earlier. */
1447 if ((flags
& ~(EAF_DIRECT
| EAF_NOCLOBBER
)) == 0)
1450 escape_points
.release ();
1456 /* Merge in WITH. Return true if anyting changed. */
1459 modref_lattice::merge (const modref_lattice
&with
)
1464 bool changed
= merge (with
.flags
);
1468 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
1469 changed
|= add_escape_point (with
.escape_points
[i
].call
,
1470 with
.escape_points
[i
].arg
,
1471 with
.escape_points
[i
].min_flags
,
1472 with
.escape_points
[i
].direct
);
1476 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1477 stores. Return true if anyting changed. */
1480 modref_lattice::merge_deref (const modref_lattice
&with
, bool ignore_stores
)
1485 bool changed
= merge (deref_flags (with
.flags
, ignore_stores
));
1489 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
1490 changed
|= add_escape_point (with
.escape_points
[i
].call
,
1491 with
.escape_points
[i
].arg
,
1492 with
.escape_points
[i
].min_flags
,
1497 /* Merge in flags for direct load. */
1500 modref_lattice::merge_direct_load ()
1502 return merge (~EAF_UNUSED
);
1505 /* Merge in flags for direct store. */
1508 modref_lattice::merge_direct_store ()
1510 return merge (~(EAF_UNUSED
| EAF_NOCLOBBER
));
1513 } /* ANON namespace. */
1515 static void analyze_ssa_name_flags (tree name
,
1516 vec
<modref_lattice
> &lattice
,
1517 int depth
, bool ipa
);
1519 /* Call statements may return their parameters. Consider argument number
1520 ARG of USE_STMT and determine flags that can needs to be cleared
1521 in case pointer possibly indirectly references from ARG I is returned.
1522 LATTICE, DEPTH and ipa are same as in analyze_ssa_name_flags. */
1525 merge_call_lhs_flags (gcall
*call
, int arg
, int index
, bool deref
,
1526 vec
<modref_lattice
> &lattice
,
1527 int depth
, bool ipa
)
1529 /* If there is no return value, no flags are affected. */
1530 if (!gimple_call_lhs (call
))
1533 /* If we know that function returns given argument and it is not ARG
1534 we can still be happy. */
1535 int flags
= gimple_call_return_flags (call
);
1536 if ((flags
& ERF_RETURNS_ARG
)
1537 && (flags
& ERF_RETURN_ARG_MASK
) != arg
)
1540 /* If return value is SSA name determine its flags. */
1541 if (TREE_CODE (gimple_call_lhs (call
)) == SSA_NAME
)
1543 tree lhs
= gimple_call_lhs (call
);
1544 analyze_ssa_name_flags (lhs
, lattice
, depth
+ 1, ipa
);
1546 lattice
[index
].merge (lattice
[SSA_NAME_VERSION (lhs
)]);
1548 lattice
[index
].merge_deref (lattice
[SSA_NAME_VERSION (lhs
)], false);
1550 /* In the case of memory store we can do nothing. */
1552 lattice
[index
].merge (0);
1555 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
1556 LATTICE is an array of modref_lattices.
1557 DEPTH is a recursion depth used to make debug output prettier.
1558 If IPA is true we analyze for IPA propagation (and thus call escape points
1559 are processed later) */
1562 analyze_ssa_name_flags (tree name
, vec
<modref_lattice
> &lattice
, int depth
,
1565 imm_use_iterator ui
;
1567 int index
= SSA_NAME_VERSION (name
);
1569 /* See if value is already computed. */
1570 if (lattice
[index
].known
)
1572 if (lattice
[index
].open
)
1576 "%*sGiving up on a cycle in SSA graph\n", depth
* 4, "");
1579 if (depth
== param_modref_max_depth
)
1583 "%*sGiving up on max depth\n", depth
* 4, "");
1586 /* Recursion guard. */
1587 lattice
[index
].init ();
1592 "%*sAnalyzing flags of ssa name: ", depth
* 4, "");
1593 print_generic_expr (dump_file
, name
);
1594 fprintf (dump_file
, "\n");
1597 FOR_EACH_IMM_USE_STMT (use_stmt
, ui
, name
)
1599 if (lattice
[index
].flags
== 0)
1601 BREAK_FROM_IMM_USE_STMT (ui
);
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
);
1625 /* Recursion would require bit of propagation; give up for now. */
1626 if (callee
&& !ipa
&& recursive_call_p (current_function_decl
,
1628 lattice
[index
].merge (0);
1631 int ecf_flags
= gimple_call_flags (call
);
1632 bool ignore_stores
= ignore_stores_p (current_function_decl
,
1634 bool ignore_retval
= ignore_retval_p (current_function_decl
,
1637 /* Handle *name = func (...). */
1638 if (gimple_call_lhs (call
)
1639 && memory_access_to (gimple_call_lhs (call
), name
))
1640 lattice
[index
].merge_direct_store ();
1642 /* We do not track accesses to the static chain (we could)
1644 if (gimple_call_chain (call
)
1645 && (gimple_call_chain (call
) == name
))
1646 lattice
[index
].merge (0);
1648 /* Process internal functions and right away. */
1649 bool record_ipa
= ipa
&& !gimple_call_internal_p (call
);
1651 /* Handle all function parameters. */
1652 for (unsigned i
= 0;
1653 i
< gimple_call_num_args (call
) && lattice
[index
].flags
; i
++)
1654 /* Name is directly passed to the callee. */
1655 if (gimple_call_arg (call
, i
) == name
)
1657 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
1659 int call_flags
= gimple_call_arg_flags (call
, i
);
1661 call_flags
|= EAF_NOCLOBBER
| EAF_NOESCAPE
1662 | EAF_NODIRECTESCAPE
;
1665 lattice
[index
].merge (call_flags
);
1667 lattice
[index
].add_escape_point (call
, i
,
1671 merge_call_lhs_flags (call
, i
, index
, false,
1672 lattice
, depth
, ipa
);
1674 /* Name is dereferenced and passed to a callee. */
1675 else if (memory_access_to (gimple_call_arg (call
, i
), name
))
1677 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
1678 lattice
[index
].merge_direct_load ();
1681 int call_flags
= deref_flags
1682 (gimple_call_arg_flags (call
, i
), ignore_stores
);
1684 lattice
[index
].merge (call_flags
);
1686 lattice
[index
].add_escape_point (call
, i
,
1690 merge_call_lhs_flags (call
, i
, index
, true,
1691 lattice
, depth
, ipa
);
1695 else if (gimple_assign_load_p (use_stmt
))
1697 gassign
*assign
= as_a
<gassign
*> (use_stmt
);
1698 /* Memory to memory copy. */
1699 if (gimple_store_p (assign
))
1701 /* Handle *lhs = *name.
1703 We do not track memory locations, so assume that value
1704 is used arbitrarily. */
1705 if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
1706 lattice
[index
].merge (0);
1707 /* Handle *name = *exp. */
1708 else if (memory_access_to (gimple_assign_lhs (assign
), name
))
1709 lattice
[index
].merge_direct_store ();
1711 /* Handle lhs = *name. */
1712 else if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
1714 tree lhs
= gimple_assign_lhs (assign
);
1715 analyze_ssa_name_flags (lhs
, lattice
, depth
+ 1, ipa
);
1716 lattice
[index
].merge_deref (lattice
[SSA_NAME_VERSION (lhs
)],
1720 else if (gimple_store_p (use_stmt
))
1722 gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
);
1724 /* Handle *lhs = name. */
1725 if (assign
&& gimple_assign_rhs1 (assign
) == name
)
1728 fprintf (dump_file
, "%*s ssa name saved to memory\n",
1730 lattice
[index
].merge (0);
1732 /* Handle *name = exp. */
1734 && memory_access_to (gimple_assign_lhs (assign
), name
))
1736 /* In general we can not ignore clobbers because they are
1737 barriers for code motion, however after inlining it is safe to
1738 do because local optimization passes do not consider clobbers
1739 from other functions. Similar logic is in ipa-pure-const.c. */
1740 if (!cfun
->after_inlining
|| !gimple_clobber_p (assign
))
1741 lattice
[index
].merge_direct_store ();
1743 /* ASM statements etc. */
1747 fprintf (dump_file
, "%*s Unhandled store\n",
1749 lattice
[index
].merge (0);
1752 else if (gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
))
1754 enum tree_code code
= gimple_assign_rhs_code (assign
);
1756 /* See if operation is a merge as considered by
1757 tree-ssa-structalias.c:find_func_aliases. */
1758 if (!truth_value_p (code
)
1759 && code
!= POINTER_DIFF_EXPR
1760 && (code
!= POINTER_PLUS_EXPR
1761 || gimple_assign_rhs1 (assign
) == name
))
1763 tree lhs
= gimple_assign_lhs (assign
);
1764 analyze_ssa_name_flags (lhs
, lattice
, depth
+ 1, ipa
);
1765 lattice
[index
].merge (lattice
[SSA_NAME_VERSION (lhs
)]);
1768 else if (gphi
*phi
= dyn_cast
<gphi
*> (use_stmt
))
1770 tree result
= gimple_phi_result (phi
);
1771 analyze_ssa_name_flags (result
, lattice
, depth
+ 1, ipa
);
1772 lattice
[index
].merge (lattice
[SSA_NAME_VERSION (result
)]);
1774 /* Conditions are not considered escape points
1775 by tree-ssa-structalias. */
1776 else if (gimple_code (use_stmt
) == GIMPLE_COND
)
1781 fprintf (dump_file
, "%*s Unhandled stmt\n", depth
* 4, "");
1782 lattice
[index
].merge (0);
1787 fprintf (dump_file
, "%*s current flags of ", depth
* 4, "");
1788 print_generic_expr (dump_file
, name
);
1789 lattice
[index
].dump (dump_file
, depth
* 4 + 4);
1794 fprintf (dump_file
, "%*sflags of ssa name ", depth
* 4, "");
1795 print_generic_expr (dump_file
, name
);
1796 lattice
[index
].dump (dump_file
, depth
* 4 + 2);
1798 lattice
[index
].open
= false;
1799 lattice
[index
].known
= true;
1802 /* Determine EAF flags for function parameters. */
1805 analyze_parms (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
1808 unsigned int parm_index
= 0;
1809 unsigned int count
= 0;
1810 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
1812 /* For const functions we have nothing to gain by EAF flags. */
1813 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
1816 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
1817 parm
= TREE_CHAIN (parm
))
1823 auto_vec
<modref_lattice
> lattice
;
1824 lattice
.safe_grow_cleared (num_ssa_names
, true);
1826 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
; parm_index
++,
1827 parm
= TREE_CHAIN (parm
))
1829 tree name
= ssa_default_def (cfun
, parm
);
1830 if (!name
|| has_zero_uses (name
))
1832 /* We do not track non-SSA parameters,
1833 but we want to track unused gimple_regs. */
1834 if (!is_gimple_reg (parm
))
1838 if (parm_index
>= summary
->arg_flags
.length ())
1839 summary
->arg_flags
.safe_grow_cleared (count
, true);
1840 summary
->arg_flags
[parm_index
] = EAF_UNUSED
;
1842 else if (summary_lto
)
1844 if (parm_index
>= summary_lto
->arg_flags
.length ())
1845 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
1846 summary_lto
->arg_flags
[parm_index
] = EAF_UNUSED
;
1850 analyze_ssa_name_flags (name
, lattice
, 0, ipa
);
1851 int flags
= lattice
[SSA_NAME_VERSION (name
)].flags
;
1853 /* For pure functions we have implicit NOCLOBBER
1855 if (ecf_flags
& ECF_PURE
)
1856 flags
&= ~(EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_NODIRECTESCAPE
);
1862 if (parm_index
>= summary
->arg_flags
.length ())
1863 summary
->arg_flags
.safe_grow_cleared (count
, true);
1864 summary
->arg_flags
[parm_index
] = flags
;
1866 else if (summary_lto
)
1868 if (parm_index
>= summary_lto
->arg_flags
.length ())
1869 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
1870 summary_lto
->arg_flags
[parm_index
] = flags
;
1872 if (lattice
[SSA_NAME_VERSION (name
)].escape_points
.length ())
1876 cgraph_node
*node
= cgraph_node::get (current_function_decl
);
1878 gcc_checking_assert (ipa
);
1880 (lattice
[SSA_NAME_VERSION (name
)].escape_points
, ip
, ep
)
1881 if ((ep
->min_flags
& flags
) != flags
)
1883 cgraph_edge
*e
= node
->get_edge (ep
->call
);
1884 struct escape_entry ee
= {parm_index
, ep
->arg
,
1885 ep
->min_flags
, ep
->direct
};
1887 escape_summaries
->get_create (e
)->esc
.safe_push (ee
);
1893 for (unsigned int i
= 0; i
< num_ssa_names
; i
++)
1894 lattice
[i
].release ();
1897 /* Analyze function F. IPA indicates whether we're running in local mode
1898 (false) or the IPA mode (true). */
1901 analyze_function (function
*f
, bool ipa
)
1904 fprintf (dump_file
, "modref analyzing '%s' (ipa=%i)%s%s\n",
1905 function_name (f
), ipa
,
1906 TREE_READONLY (current_function_decl
) ? " (const)" : "",
1907 DECL_PURE_P (current_function_decl
) ? " (pure)" : "");
1909 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
1910 if (!flag_ipa_modref
)
1913 /* Compute no-LTO summaries when local optimization is going to happen. */
1914 bool nolto
= (!ipa
|| ((!flag_lto
|| flag_fat_lto_objects
) && !in_lto_p
)
1915 || (in_lto_p
&& !flag_wpa
1916 && flag_incremental_link
!= INCREMENTAL_LINK_LTO
));
1917 /* Compute LTO when LTO streaming is going to happen. */
1918 bool lto
= ipa
&& ((flag_lto
&& !in_lto_p
)
1920 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
1921 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1923 modref_summary
*summary
= NULL
;
1924 modref_summary_lto
*summary_lto
= NULL
;
1926 /* Initialize the summary.
1927 If we run in local mode there is possibly pre-existing summary from
1928 IPA pass. Dump it so it is easy to compare if mod-ref info has
1932 if (!optimization_summaries
)
1933 optimization_summaries
= modref_summaries::create_ggc (symtab
);
1934 else /* Remove existing summary if we are re-running the pass. */
1938 = optimization_summaries
->get (cgraph_node::get (f
->decl
)))
1942 fprintf (dump_file
, "Past summary:\n");
1943 optimization_summaries
->get
1944 (cgraph_node::get (f
->decl
))->dump (dump_file
);
1946 optimization_summaries
->remove (cgraph_node::get (f
->decl
));
1948 summary
= optimization_summaries
->get_create (cgraph_node::get (f
->decl
));
1949 gcc_checking_assert (nolto
&& !lto
);
1951 /* In IPA mode we analyze every function precisely once. Assert that. */
1957 summaries
= modref_summaries::create_ggc (symtab
);
1959 summaries
->remove (cgraph_node::get (f
->decl
));
1960 summary
= summaries
->get_create (cgraph_node::get (f
->decl
));
1965 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
1967 summaries_lto
->remove (cgraph_node::get (f
->decl
));
1968 summary_lto
= summaries_lto
->get_create (cgraph_node::get (f
->decl
));
1970 if (!fnspec_summaries
)
1971 fnspec_summaries
= new fnspec_summaries_t (symtab
);
1972 if (!escape_summaries
)
1973 escape_summaries
= new escape_summaries_t (symtab
);
1977 /* Create and initialize summary for F.
1978 Note that summaries may be already allocated from previous
1982 gcc_assert (!summary
->loads
);
1983 summary
->loads
= modref_records::create_ggc (param_modref_max_bases
,
1984 param_modref_max_refs
,
1985 param_modref_max_accesses
);
1986 gcc_assert (!summary
->stores
);
1987 summary
->stores
= modref_records::create_ggc (param_modref_max_bases
,
1988 param_modref_max_refs
,
1989 param_modref_max_accesses
);
1990 summary
->writes_errno
= false;
1994 gcc_assert (!summary_lto
->loads
);
1995 summary_lto
->loads
= modref_records_lto::create_ggc
1996 (param_modref_max_bases
,
1997 param_modref_max_refs
,
1998 param_modref_max_accesses
);
1999 gcc_assert (!summary_lto
->stores
);
2000 summary_lto
->stores
= modref_records_lto::create_ggc
2001 (param_modref_max_bases
,
2002 param_modref_max_refs
,
2003 param_modref_max_accesses
);
2004 summary_lto
->writes_errno
= false;
2007 analyze_parms (summary
, summary_lto
, ipa
);
2009 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
2010 auto_vec
<gimple
*, 32> recursive_calls
;
2012 /* Analyze each statement in each basic block of the function. If the
2013 statement cannot be analyzed (for any reason), the entire function cannot
2014 be analyzed by modref. */
2016 FOR_EACH_BB_FN (bb
, f
)
2018 gimple_stmt_iterator si
;
2019 for (si
= gsi_after_labels (bb
); !gsi_end_p (si
); gsi_next (&si
))
2021 if (!analyze_stmt (summary
, summary_lto
,
2022 gsi_stmt (si
), ipa
, &recursive_calls
)
2023 || ((!summary
|| !summary
->useful_p (ecf_flags
, false))
2025 || !summary_lto
->useful_p (ecf_flags
, false))))
2027 collapse_loads (summary
, summary_lto
);
2028 collapse_stores (summary
, summary_lto
);
2034 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2035 This needs to be done after all other side effects are computed. */
2038 bool changed
= true;
2042 for (unsigned i
= 0; i
< recursive_calls
.length (); i
++)
2044 changed
|= merge_call_side_effects
2045 (summary
, recursive_calls
[i
], summary
,
2046 ignore_stores_p (current_function_decl
,
2048 (recursive_calls
[i
])),
2050 if (!summary
->useful_p (ecf_flags
, false))
2052 remove_summary (lto
, nolto
, ipa
);
2058 if (summary
&& !summary
->useful_p (ecf_flags
))
2061 optimization_summaries
->remove (fnode
);
2063 summaries
->remove (fnode
);
2066 if (summary_lto
&& !summary_lto
->useful_p (ecf_flags
))
2068 summaries_lto
->remove (fnode
);
2071 if (ipa
&& !summary
&& !summary_lto
)
2072 remove_modref_edge_summaries (fnode
);
2076 fprintf (dump_file
, " - modref done with result: tracked.\n");
2078 summary
->dump (dump_file
);
2080 summary_lto
->dump (dump_file
);
2081 dump_modref_edge_summaries (dump_file
, fnode
, 2);
2085 /* Callback for generate_summary. */
2088 modref_generate (void)
2090 struct cgraph_node
*node
;
2091 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
2093 function
*f
= DECL_STRUCT_FUNCTION (node
->decl
);
2097 analyze_function (f
, true);
2102 /* Called when a new function is inserted to callgraph late. */
2105 modref_summaries::insert (struct cgraph_node
*node
, modref_summary
*)
2107 /* Local passes ought to be executed by the pass manager. */
2108 if (this == optimization_summaries
)
2110 optimization_summaries
->remove (node
);
2113 if (!DECL_STRUCT_FUNCTION (node
->decl
)
2114 || !opt_for_fn (node
->decl
, flag_ipa_modref
))
2116 summaries
->remove (node
);
2119 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
2120 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
2124 /* Called when a new function is inserted to callgraph late. */
2127 modref_summaries_lto::insert (struct cgraph_node
*node
, modref_summary_lto
*)
2129 /* We do not support adding new function when IPA information is already
2130 propagated. This is done only by SIMD cloning that is not very
2132 if (!DECL_STRUCT_FUNCTION (node
->decl
)
2133 || !opt_for_fn (node
->decl
, flag_ipa_modref
)
2136 summaries_lto
->remove (node
);
2139 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
2140 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
2144 /* Called when new clone is inserted to callgraph late. */
2147 modref_summaries::duplicate (cgraph_node
*, cgraph_node
*dst
,
2148 modref_summary
*src_data
,
2149 modref_summary
*dst_data
)
2151 /* Do not duplicate optimization summaries; we do not handle parameter
2152 transforms on them. */
2153 if (this == optimization_summaries
)
2155 optimization_summaries
->remove (dst
);
2158 dst_data
->stores
= modref_records::create_ggc
2159 (src_data
->stores
->max_bases
,
2160 src_data
->stores
->max_refs
,
2161 src_data
->stores
->max_accesses
);
2162 dst_data
->stores
->copy_from (src_data
->stores
);
2163 dst_data
->loads
= modref_records::create_ggc
2164 (src_data
->loads
->max_bases
,
2165 src_data
->loads
->max_refs
,
2166 src_data
->loads
->max_accesses
);
2167 dst_data
->loads
->copy_from (src_data
->loads
);
2168 dst_data
->writes_errno
= src_data
->writes_errno
;
2169 if (src_data
->arg_flags
.length ())
2170 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
2173 /* Called when new clone is inserted to callgraph late. */
2176 modref_summaries_lto::duplicate (cgraph_node
*, cgraph_node
*,
2177 modref_summary_lto
*src_data
,
2178 modref_summary_lto
*dst_data
)
2180 /* Be sure that no further cloning happens after ipa-modref. If it does
2181 we will need to update signatures for possible param changes. */
2182 gcc_checking_assert (!((modref_summaries_lto
*)summaries_lto
)->propagated
);
2183 dst_data
->stores
= modref_records_lto::create_ggc
2184 (src_data
->stores
->max_bases
,
2185 src_data
->stores
->max_refs
,
2186 src_data
->stores
->max_accesses
);
2187 dst_data
->stores
->copy_from (src_data
->stores
);
2188 dst_data
->loads
= modref_records_lto::create_ggc
2189 (src_data
->loads
->max_bases
,
2190 src_data
->loads
->max_refs
,
2191 src_data
->loads
->max_accesses
);
2192 dst_data
->loads
->copy_from (src_data
->loads
);
2193 dst_data
->writes_errno
= src_data
->writes_errno
;
2194 if (src_data
->arg_flags
.length ())
2195 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
2200 /* Definition of the modref pass on GIMPLE. */
2201 const pass_data pass_data_modref
= {
2206 (PROP_cfg
| PROP_ssa
),
2213 class pass_modref
: public gimple_opt_pass
2216 pass_modref (gcc::context
*ctxt
)
2217 : gimple_opt_pass (pass_data_modref
, ctxt
) {}
2219 /* opt_pass methods: */
2222 return new pass_modref (m_ctxt
);
2224 virtual bool gate (function
*)
2226 return flag_ipa_modref
;
2228 virtual unsigned int execute (function
*);
2231 /* Encode TT to the output block OB using the summary streaming API. */
2234 write_modref_records (modref_records_lto
*tt
, struct output_block
*ob
)
2236 streamer_write_uhwi (ob
, tt
->max_bases
);
2237 streamer_write_uhwi (ob
, tt
->max_refs
);
2238 streamer_write_uhwi (ob
, tt
->max_accesses
);
2240 streamer_write_uhwi (ob
, tt
->every_base
);
2241 streamer_write_uhwi (ob
, vec_safe_length (tt
->bases
));
2243 modref_base_node
<tree
> *base_node
;
2244 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, base_node
)
2246 stream_write_tree (ob
, base_node
->base
, true);
2248 streamer_write_uhwi (ob
, base_node
->every_ref
);
2249 streamer_write_uhwi (ob
, vec_safe_length (base_node
->refs
));
2252 modref_ref_node
<tree
> *ref_node
;
2253 FOR_EACH_VEC_SAFE_ELT (base_node
->refs
, j
, ref_node
)
2255 stream_write_tree (ob
, ref_node
->ref
, true);
2256 streamer_write_uhwi (ob
, ref_node
->every_access
);
2257 streamer_write_uhwi (ob
, vec_safe_length (ref_node
->accesses
));
2260 modref_access_node
*access_node
;
2261 FOR_EACH_VEC_SAFE_ELT (ref_node
->accesses
, k
, access_node
)
2263 streamer_write_hwi (ob
, access_node
->parm_index
);
2264 if (access_node
->parm_index
!= -1)
2266 streamer_write_uhwi (ob
, access_node
->parm_offset_known
);
2267 if (access_node
->parm_offset_known
)
2269 streamer_write_poly_int64 (ob
, access_node
->parm_offset
);
2270 streamer_write_poly_int64 (ob
, access_node
->offset
);
2271 streamer_write_poly_int64 (ob
, access_node
->size
);
2272 streamer_write_poly_int64 (ob
, access_node
->max_size
);
2280 /* Read a modref_tree from the input block IB using the data from DATA_IN.
2281 This assumes that the tree was encoded using write_modref_tree.
2282 Either nolto_ret or lto_ret is initialized by the tree depending whether
2283 LTO streaming is expected or not. */
2286 read_modref_records (lto_input_block
*ib
, struct data_in
*data_in
,
2287 modref_records
**nolto_ret
,
2288 modref_records_lto
**lto_ret
)
2290 size_t max_bases
= streamer_read_uhwi (ib
);
2291 size_t max_refs
= streamer_read_uhwi (ib
);
2292 size_t max_accesses
= streamer_read_uhwi (ib
);
2295 *lto_ret
= modref_records_lto::create_ggc (max_bases
, max_refs
,
2298 *nolto_ret
= modref_records::create_ggc (max_bases
, max_refs
,
2300 gcc_checking_assert (lto_ret
|| nolto_ret
);
2302 size_t every_base
= streamer_read_uhwi (ib
);
2303 size_t nbase
= streamer_read_uhwi (ib
);
2305 gcc_assert (!every_base
|| nbase
== 0);
2309 (*nolto_ret
)->collapse ();
2311 (*lto_ret
)->collapse ();
2313 for (size_t i
= 0; i
< nbase
; i
++)
2315 tree base_tree
= stream_read_tree (ib
, data_in
);
2316 modref_base_node
<alias_set_type
> *nolto_base_node
= NULL
;
2317 modref_base_node
<tree
> *lto_base_node
= NULL
;
2319 /* At stream in time we have LTO alias info. Check if we streamed in
2320 something obviously unnecessary. Do not glob types by alias sets;
2321 it is not 100% clear that ltrans types will get merged same way.
2322 Types may get refined based on ODR type conflicts. */
2323 if (base_tree
&& !get_alias_set (base_tree
))
2327 fprintf (dump_file
, "Streamed in alias set 0 type ");
2328 print_generic_expr (dump_file
, base_tree
);
2329 fprintf (dump_file
, "\n");
2335 nolto_base_node
= (*nolto_ret
)->insert_base (base_tree
2336 ? get_alias_set (base_tree
)
2339 lto_base_node
= (*lto_ret
)->insert_base (base_tree
);
2340 size_t every_ref
= streamer_read_uhwi (ib
);
2341 size_t nref
= streamer_read_uhwi (ib
);
2343 gcc_assert (!every_ref
|| nref
== 0);
2346 if (nolto_base_node
)
2347 nolto_base_node
->collapse ();
2349 lto_base_node
->collapse ();
2351 for (size_t j
= 0; j
< nref
; j
++)
2353 tree ref_tree
= stream_read_tree (ib
, data_in
);
2355 if (ref_tree
&& !get_alias_set (ref_tree
))
2359 fprintf (dump_file
, "Streamed in alias set 0 type ");
2360 print_generic_expr (dump_file
, ref_tree
);
2361 fprintf (dump_file
, "\n");
2366 modref_ref_node
<alias_set_type
> *nolto_ref_node
= NULL
;
2367 modref_ref_node
<tree
> *lto_ref_node
= NULL
;
2369 if (nolto_base_node
)
2371 = nolto_base_node
->insert_ref (ref_tree
2372 ? get_alias_set (ref_tree
) : 0,
2375 lto_ref_node
= lto_base_node
->insert_ref (ref_tree
, max_refs
);
2377 size_t every_access
= streamer_read_uhwi (ib
);
2378 size_t naccesses
= streamer_read_uhwi (ib
);
2381 nolto_ref_node
->every_access
= every_access
;
2383 lto_ref_node
->every_access
= every_access
;
2385 for (size_t k
= 0; k
< naccesses
; k
++)
2387 int parm_index
= streamer_read_hwi (ib
);
2388 bool parm_offset_known
= false;
2389 poly_int64 parm_offset
= 0;
2390 poly_int64 offset
= 0;
2391 poly_int64 size
= -1;
2392 poly_int64 max_size
= -1;
2394 if (parm_index
!= -1)
2396 parm_offset_known
= streamer_read_uhwi (ib
);
2397 if (parm_offset_known
)
2399 parm_offset
= streamer_read_poly_int64 (ib
);
2400 offset
= streamer_read_poly_int64 (ib
);
2401 size
= streamer_read_poly_int64 (ib
);
2402 max_size
= streamer_read_poly_int64 (ib
);
2405 modref_access_node a
= {offset
, size
, max_size
, parm_offset
,
2406 parm_index
, parm_offset_known
};
2408 nolto_ref_node
->insert_access (a
, max_accesses
);
2410 lto_ref_node
->insert_access (a
, max_accesses
);
2415 (*lto_ret
)->cleanup ();
2417 (*nolto_ret
)->cleanup ();
2420 /* Write ESUM to BP. */
2423 modref_write_escape_summary (struct bitpack_d
*bp
, escape_summary
*esum
)
2427 bp_pack_var_len_unsigned (bp
, 0);
2430 bp_pack_var_len_unsigned (bp
, esum
->esc
.length ());
2433 FOR_EACH_VEC_ELT (esum
->esc
, i
, ee
)
2435 bp_pack_var_len_unsigned (bp
, ee
->parm_index
);
2436 bp_pack_var_len_unsigned (bp
, ee
->arg
);
2437 bp_pack_var_len_unsigned (bp
, ee
->min_flags
);
2438 bp_pack_value (bp
, ee
->direct
, 1);
2442 /* Read escape summary for E from BP. */
2445 modref_read_escape_summary (struct bitpack_d
*bp
, cgraph_edge
*e
)
2447 unsigned int n
= bp_unpack_var_len_unsigned (bp
);
2450 escape_summary
*esum
= escape_summaries
->get_create (e
);
2451 esum
->esc
.reserve_exact (n
);
2452 for (unsigned int i
= 0; i
< n
; i
++)
2455 ee
.parm_index
= bp_unpack_var_len_unsigned (bp
);
2456 ee
.arg
= bp_unpack_var_len_unsigned (bp
);
2457 ee
.min_flags
= bp_unpack_var_len_unsigned (bp
);
2458 ee
.direct
= bp_unpack_value (bp
, 1);
2459 esum
->esc
.quick_push (ee
);
2463 /* Callback for write_summary. */
2468 struct output_block
*ob
= create_output_block (LTO_section_ipa_modref
);
2469 lto_symtab_encoder_t encoder
= ob
->decl_state
->symtab_node_encoder
;
2470 unsigned int count
= 0;
2475 streamer_write_uhwi (ob
, 0);
2476 streamer_write_char_stream (ob
->main_stream
, 0);
2477 produce_asm (ob
, NULL
);
2478 destroy_output_block (ob
);
2482 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
2484 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
2485 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
2486 modref_summary_lto
*r
;
2488 if (cnode
&& cnode
->definition
&& !cnode
->alias
2489 && (r
= summaries_lto
->get (cnode
))
2490 && r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
2493 streamer_write_uhwi (ob
, count
);
2495 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
2497 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
2498 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
2500 if (cnode
&& cnode
->definition
&& !cnode
->alias
)
2502 modref_summary_lto
*r
= summaries_lto
->get (cnode
);
2504 if (!r
|| !r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
2507 streamer_write_uhwi (ob
, lto_symtab_encoder_encode (encoder
, cnode
));
2509 streamer_write_uhwi (ob
, r
->arg_flags
.length ());
2510 for (unsigned int i
= 0; i
< r
->arg_flags
.length (); i
++)
2511 streamer_write_char_stream (ob
->main_stream
, r
->arg_flags
[i
]);
2513 write_modref_records (r
->loads
, ob
);
2514 write_modref_records (r
->stores
, ob
);
2516 struct bitpack_d bp
= bitpack_create (ob
->main_stream
);
2517 bp_pack_value (&bp
, r
->writes_errno
, 1);
2520 for (cgraph_edge
*e
= cnode
->indirect_calls
;
2521 e
; e
= e
->next_callee
)
2523 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
2524 bp_pack_value (&bp
, sum
!= NULL
, 1);
2526 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
2527 class escape_summary
*esum
= escape_summaries
->get (e
);
2528 modref_write_escape_summary (&bp
,esum
);
2530 for (cgraph_edge
*e
= cnode
->callees
; e
; e
= e
->next_callee
)
2532 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
2533 bp_pack_value (&bp
, sum
!= NULL
, 1);
2535 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
2536 class escape_summary
*esum
= escape_summaries
->get (e
);
2537 modref_write_escape_summary (&bp
,esum
);
2540 streamer_write_bitpack (&bp
);
2543 streamer_write_char_stream (ob
->main_stream
, 0);
2544 produce_asm (ob
, NULL
);
2545 destroy_output_block (ob
);
2549 read_section (struct lto_file_decl_data
*file_data
, const char *data
,
2552 const struct lto_function_header
*header
2553 = (const struct lto_function_header
*) data
;
2554 const int cfg_offset
= sizeof (struct lto_function_header
);
2555 const int main_offset
= cfg_offset
+ header
->cfg_size
;
2556 const int string_offset
= main_offset
+ header
->main_size
;
2557 struct data_in
*data_in
;
2559 unsigned int f_count
;
2561 lto_input_block
ib ((const char *) data
+ main_offset
, header
->main_size
,
2562 file_data
->mode_table
);
2565 = lto_data_in_create (file_data
, (const char *) data
+ string_offset
,
2566 header
->string_size
, vNULL
);
2567 f_count
= streamer_read_uhwi (&ib
);
2568 for (i
= 0; i
< f_count
; i
++)
2570 struct cgraph_node
*node
;
2571 lto_symtab_encoder_t encoder
;
2573 unsigned int index
= streamer_read_uhwi (&ib
);
2574 encoder
= file_data
->symtab_node_encoder
;
2575 node
= dyn_cast
<cgraph_node
*> (lto_symtab_encoder_deref (encoder
,
2578 modref_summary
*modref_sum
= summaries
2579 ? summaries
->get_create (node
) : NULL
;
2580 modref_summary_lto
*modref_sum_lto
= summaries_lto
2581 ? summaries_lto
->get_create (node
)
2583 if (optimization_summaries
)
2584 modref_sum
= optimization_summaries
->get_create (node
);
2587 modref_sum
->writes_errno
= false;
2589 modref_sum_lto
->writes_errno
= false;
2591 gcc_assert (!modref_sum
|| (!modref_sum
->loads
2592 && !modref_sum
->stores
));
2593 gcc_assert (!modref_sum_lto
|| (!modref_sum_lto
->loads
2594 && !modref_sum_lto
->stores
));
2595 unsigned int args
= streamer_read_uhwi (&ib
);
2596 if (args
&& modref_sum
)
2597 modref_sum
->arg_flags
.reserve_exact (args
);
2598 if (args
&& modref_sum_lto
)
2599 modref_sum_lto
->arg_flags
.reserve_exact (args
);
2600 for (unsigned int i
= 0; i
< args
; i
++)
2602 unsigned char flags
= streamer_read_uchar (&ib
);
2604 modref_sum
->arg_flags
.quick_push (flags
);
2606 modref_sum_lto
->arg_flags
.quick_push (flags
);
2608 read_modref_records (&ib
, data_in
,
2609 modref_sum
? &modref_sum
->loads
: NULL
,
2610 modref_sum_lto
? &modref_sum_lto
->loads
: NULL
);
2611 read_modref_records (&ib
, data_in
,
2612 modref_sum
? &modref_sum
->stores
: NULL
,
2613 modref_sum_lto
? &modref_sum_lto
->stores
: NULL
);
2614 struct bitpack_d bp
= streamer_read_bitpack (&ib
);
2615 if (bp_unpack_value (&bp
, 1))
2618 modref_sum
->writes_errno
= true;
2620 modref_sum_lto
->writes_errno
= true;
2624 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
2626 if (bp_unpack_value (&bp
, 1))
2628 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
2629 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
2631 modref_read_escape_summary (&bp
, e
);
2633 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
2635 if (bp_unpack_value (&bp
, 1))
2637 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
2638 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
2640 modref_read_escape_summary (&bp
, e
);
2645 fprintf (dump_file
, "Read modref for %s\n",
2646 node
->dump_name ());
2648 modref_sum
->dump (dump_file
);
2650 modref_sum_lto
->dump (dump_file
);
2651 dump_modref_edge_summaries (dump_file
, node
, 4);
2655 lto_free_section_data (file_data
, LTO_section_ipa_modref
, NULL
, data
,
2657 lto_data_in_delete (data_in
);
2660 /* Callback for read_summary. */
2665 struct lto_file_decl_data
**file_data_vec
= lto_get_file_decl_data ();
2666 struct lto_file_decl_data
*file_data
;
2669 gcc_checking_assert (!optimization_summaries
&& !summaries
&& !summaries_lto
);
2671 optimization_summaries
= modref_summaries::create_ggc (symtab
);
2674 if (flag_wpa
|| flag_incremental_link
== INCREMENTAL_LINK_LTO
)
2675 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
2677 || (flag_incremental_link
== INCREMENTAL_LINK_LTO
2678 && flag_fat_lto_objects
))
2679 summaries
= modref_summaries::create_ggc (symtab
);
2680 if (!fnspec_summaries
)
2681 fnspec_summaries
= new fnspec_summaries_t (symtab
);
2682 if (!escape_summaries
)
2683 escape_summaries
= new escape_summaries_t (symtab
);
2686 while ((file_data
= file_data_vec
[j
++]))
2689 const char *data
= lto_get_summary_section_data (file_data
,
2690 LTO_section_ipa_modref
,
2693 read_section (file_data
, data
, len
);
2695 /* Fatal error here. We do not want to support compiling ltrans units
2696 with different version of compiler or different flags than the WPA
2697 unit, so this should never happen. */
2698 fatal_error (input_location
,
2699 "IPA modref summary is missing in input file");
2703 /* Recompute arg_flags for param adjustments in INFO. */
2706 remap_arg_flags (auto_vec
<unsigned char> &arg_flags
, clone_info
*info
)
2708 auto_vec
<unsigned char> old
= arg_flags
.copy ();
2711 ipa_adjusted_param
*p
;
2713 arg_flags
.release ();
2715 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2717 int o
= info
->param_adjustments
->get_original_index (i
);
2718 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
2722 arg_flags
.safe_grow_cleared (max
+ 1, true);
2723 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2725 int o
= info
->param_adjustments
->get_original_index (i
);
2726 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
2727 arg_flags
[i
] = old
[o
];
2731 /* If signature changed, update the summary. */
2734 update_signature (struct cgraph_node
*node
)
2736 clone_info
*info
= clone_info::get (node
);
2737 if (!info
|| !info
->param_adjustments
)
2740 modref_summary
*r
= optimization_summaries
2741 ? optimization_summaries
->get (node
) : NULL
;
2742 modref_summary_lto
*r_lto
= summaries_lto
2743 ? summaries_lto
->get (node
) : NULL
;
2748 fprintf (dump_file
, "Updating summary for %s from:\n",
2749 node
->dump_name ());
2751 r
->dump (dump_file
);
2753 r_lto
->dump (dump_file
);
2757 ipa_adjusted_param
*p
;
2759 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2761 int idx
= info
->param_adjustments
->get_original_index (i
);
2766 auto_vec
<int, 32> map
;
2768 map
.reserve (max
+ 1);
2769 for (i
= 0; i
<= max
; i
++)
2770 map
.quick_push (-1);
2771 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2773 int idx
= info
->param_adjustments
->get_original_index (i
);
2779 r
->loads
->remap_params (&map
);
2780 r
->stores
->remap_params (&map
);
2781 if (r
->arg_flags
.length ())
2782 remap_arg_flags (r
->arg_flags
, info
);
2786 r_lto
->loads
->remap_params (&map
);
2787 r_lto
->stores
->remap_params (&map
);
2788 if (r_lto
->arg_flags
.length ())
2789 remap_arg_flags (r_lto
->arg_flags
, info
);
2793 fprintf (dump_file
, "to:\n");
2795 r
->dump (dump_file
);
2797 r_lto
->dump (dump_file
);
2802 /* Definition of the modref IPA pass. */
2803 const pass_data pass_data_ipa_modref
=
2805 IPA_PASS
, /* type */
2806 "modref", /* name */
2807 OPTGROUP_IPA
, /* optinfo_flags */
2808 TV_IPA_MODREF
, /* tv_id */
2809 0, /* properties_required */
2810 0, /* properties_provided */
2811 0, /* properties_destroyed */
2812 0, /* todo_flags_start */
2813 ( TODO_dump_symtab
), /* todo_flags_finish */
2816 class pass_ipa_modref
: public ipa_opt_pass_d
2819 pass_ipa_modref (gcc::context
*ctxt
)
2820 : ipa_opt_pass_d (pass_data_ipa_modref
, ctxt
,
2821 modref_generate
, /* generate_summary */
2822 modref_write
, /* write_summary */
2823 modref_read
, /* read_summary */
2824 modref_write
, /* write_optimization_summary */
2825 modref_read
, /* read_optimization_summary */
2826 NULL
, /* stmt_fixup */
2827 0, /* function_transform_todo_flags_start */
2828 NULL
, /* function_transform */
2829 NULL
) /* variable_transform */
2832 /* opt_pass methods: */
2833 opt_pass
*clone () { return new pass_ipa_modref (m_ctxt
); }
2834 virtual bool gate (function
*)
2838 virtual unsigned int execute (function
*);
2844 unsigned int pass_modref::execute (function
*f
)
2846 analyze_function (f
, false);
2851 make_pass_modref (gcc::context
*ctxt
)
2853 return new pass_modref (ctxt
);
2857 make_pass_ipa_modref (gcc::context
*ctxt
)
2859 return new pass_ipa_modref (ctxt
);
2862 /* Skip edges from and to nodes without ipa_pure_const enabled.
2863 Ignore not available symbols. */
2866 ignore_edge (struct cgraph_edge
*e
)
2868 /* We merge summaries of inline clones into summaries of functions they
2869 are inlined to. For that reason the complete function bodies must
2871 if (!e
->inline_failed
)
2873 enum availability avail
;
2874 cgraph_node
*callee
= e
->callee
->function_or_virtual_thunk_symbol
2875 (&avail
, e
->caller
);
2877 return (avail
<= AVAIL_INTERPOSABLE
2878 || ((!optimization_summaries
|| !optimization_summaries
->get (callee
))
2879 && (!summaries_lto
|| !summaries_lto
->get (callee
)))
2880 || flags_from_decl_or_type (e
->callee
->decl
)
2881 & (ECF_CONST
| ECF_NOVOPS
));
2884 /* Compute parm_map for CALLEE_EDGE. */
2887 compute_parm_map (cgraph_edge
*callee_edge
, vec
<modref_parm_map
> *parm_map
)
2889 class ipa_edge_args
*args
;
2890 if (ipa_node_params_sum
2891 && !callee_edge
->call_stmt_cannot_inline_p
2892 && (args
= IPA_EDGE_REF (callee_edge
)) != NULL
)
2894 int i
, count
= ipa_get_cs_argument_count (args
);
2895 class ipa_node_params
*caller_parms_info
, *callee_pi
;
2896 class ipa_call_summary
*es
2897 = ipa_call_summaries
->get (callee_edge
);
2899 = callee_edge
->callee
->function_or_virtual_thunk_symbol
2900 (NULL
, callee_edge
->caller
);
2902 caller_parms_info
= IPA_NODE_REF (callee_edge
->caller
->inlined_to
2903 ? callee_edge
->caller
->inlined_to
2904 : callee_edge
->caller
);
2905 callee_pi
= IPA_NODE_REF (callee
);
2907 (*parm_map
).safe_grow_cleared (count
, true);
2909 for (i
= 0; i
< count
; i
++)
2911 if (es
&& es
->param
[i
].points_to_local_or_readonly_memory
)
2913 (*parm_map
)[i
].parm_index
= -2;
2917 struct ipa_jump_func
*jf
2918 = ipa_get_ith_jump_func (args
, i
);
2919 if (jf
&& callee_pi
)
2921 tree cst
= ipa_value_from_jfunc (caller_parms_info
,
2925 if (cst
&& points_to_local_or_readonly_memory_p (cst
))
2927 (*parm_map
)[i
].parm_index
= -2;
2931 if (jf
&& jf
->type
== IPA_JF_PASS_THROUGH
)
2933 (*parm_map
)[i
].parm_index
2934 = ipa_get_jf_pass_through_formal_id (jf
);
2935 if (ipa_get_jf_pass_through_operation (jf
) == NOP_EXPR
)
2937 (*parm_map
)[i
].parm_offset_known
= true;
2938 (*parm_map
)[i
].parm_offset
= 0;
2940 else if (ipa_get_jf_pass_through_operation (jf
)
2941 == POINTER_PLUS_EXPR
2942 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf
),
2943 &(*parm_map
)[i
].parm_offset
))
2944 (*parm_map
)[i
].parm_offset_known
= true;
2946 (*parm_map
)[i
].parm_offset_known
= false;
2949 if (jf
&& jf
->type
== IPA_JF_ANCESTOR
)
2951 (*parm_map
)[i
].parm_index
= ipa_get_jf_ancestor_formal_id (jf
);
2952 (*parm_map
)[i
].parm_offset_known
= true;
2954 (!(ipa_get_jf_ancestor_offset (jf
) & (BITS_PER_UNIT
- 1)));
2955 (*parm_map
)[i
].parm_offset
2956 = ipa_get_jf_ancestor_offset (jf
) >> LOG2_BITS_PER_UNIT
;
2959 (*parm_map
)[i
].parm_index
= -1;
2963 fprintf (dump_file
, " Parm map: ");
2964 for (i
= 0; i
< count
; i
++)
2965 fprintf (dump_file
, " %i", (*parm_map
)[i
].parm_index
);
2966 fprintf (dump_file
, "\n");
2973 /* Map used to translate escape infos. */
2981 /* Update escape map fo E. */
2984 update_escape_summary_1 (cgraph_edge
*e
,
2985 vec
<vec
<escape_map
>> &map
)
2987 escape_summary
*sum
= escape_summaries
->get (e
);
2990 auto_vec
<escape_entry
> old
= sum
->esc
.copy ();
2991 sum
->esc
.release ();
2995 FOR_EACH_VEC_ELT (old
, i
, ee
)
2998 struct escape_map
*em
;
2999 if (ee
->parm_index
>= map
.length ())
3001 FOR_EACH_VEC_ELT (map
[ee
->parm_index
], j
, em
)
3003 struct escape_entry entry
= {em
->parm_index
, ee
->arg
,
3005 ee
->direct
& em
->direct
};
3006 sum
->esc
.safe_push (entry
);
3009 if (!sum
->esc
.length ())
3010 escape_summaries
->remove (e
);
3013 /* Update escape map fo NODE. */
3016 update_escape_summary (cgraph_node
*node
,
3017 vec
<vec
<escape_map
>> &map
)
3019 if (!escape_summaries
)
3021 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
3022 update_escape_summary_1 (e
, map
);
3023 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
3025 if (!e
->inline_failed
)
3026 update_escape_summary (e
->callee
, map
);
3028 update_escape_summary_1 (e
, map
);
3032 /* Call EDGE was inlined; merge summary from callee to the caller. */
3035 ipa_merge_modref_summary_after_inlining (cgraph_edge
*edge
)
3037 if (!summaries
&& !summaries_lto
)
3040 struct cgraph_node
*to
= (edge
->caller
->inlined_to
3041 ? edge
->caller
->inlined_to
: edge
->caller
);
3042 class modref_summary
*to_info
= summaries
? summaries
->get (to
) : NULL
;
3043 class modref_summary_lto
*to_info_lto
= summaries_lto
3044 ? summaries_lto
->get (to
) : NULL
;
3046 if (!to_info
&& !to_info_lto
)
3049 summaries
->remove (edge
->callee
);
3051 summaries_lto
->remove (edge
->callee
);
3052 remove_modref_edge_summaries (edge
->callee
);
3056 class modref_summary
*callee_info
= summaries
? summaries
->get (edge
->callee
)
3058 class modref_summary_lto
*callee_info_lto
3059 = summaries_lto
? summaries_lto
->get (edge
->callee
) : NULL
;
3060 int flags
= flags_from_decl_or_type (edge
->callee
->decl
);
3061 bool ignore_stores
= ignore_stores_p (edge
->caller
->decl
, flags
);
3063 if (!callee_info
&& to_info
)
3065 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3066 to_info
->loads
->collapse ();
3068 to_info
->stores
->collapse ();
3070 if (!callee_info_lto
&& to_info_lto
)
3072 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3073 to_info_lto
->loads
->collapse ();
3075 to_info_lto
->stores
->collapse ();
3077 if (callee_info
|| callee_info_lto
)
3079 auto_vec
<modref_parm_map
, 32> parm_map
;
3081 compute_parm_map (edge
, &parm_map
);
3085 if (to_info
&& callee_info
)
3086 to_info
->stores
->merge (callee_info
->stores
, &parm_map
);
3087 if (to_info_lto
&& callee_info_lto
)
3088 to_info_lto
->stores
->merge (callee_info_lto
->stores
, &parm_map
);
3090 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3092 if (to_info
&& callee_info
)
3093 to_info
->loads
->merge (callee_info
->loads
, &parm_map
);
3094 if (to_info_lto
&& callee_info_lto
)
3095 to_info_lto
->loads
->merge (callee_info_lto
->loads
, &parm_map
);
3099 /* Now merge escape summaries.
3100 For every escape to the callee we need to merge calle flags
3101 and remap calees escapes. */
3102 class escape_summary
*sum
= escape_summaries
->get (edge
);
3103 int max_escape
= -1;
3107 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3108 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3109 if ((int)ee
->arg
> max_escape
)
3110 max_escape
= ee
->arg
;
3112 auto_vec
<vec
<struct escape_map
>, 32> emap (max_escape
+ 1);
3113 emap
.safe_grow (max_escape
+ 1, true);
3114 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
3117 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3118 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3120 bool needed
= false;
3121 if (to_info
&& to_info
->arg_flags
.length () > ee
->parm_index
)
3123 int flags
= callee_info
3124 && callee_info
->arg_flags
.length () > ee
->arg
3125 ? callee_info
->arg_flags
[ee
->arg
] : 0;
3127 flags
= deref_flags (flags
, ignore_stores
);
3128 else if (ignore_stores
)
3129 flags
|= EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_NODIRECTESCAPE
;
3130 flags
|= ee
->min_flags
;
3131 to_info
->arg_flags
[ee
->parm_index
] &= flags
;
3132 if (to_info
->arg_flags
[ee
->parm_index
])
3135 if (to_info_lto
&& to_info_lto
->arg_flags
.length () > ee
->parm_index
)
3137 int flags
= callee_info_lto
3138 && callee_info_lto
->arg_flags
.length () > ee
->arg
3139 ? callee_info_lto
->arg_flags
[ee
->arg
] : 0;
3141 flags
= deref_flags (flags
, ignore_stores
);
3142 else if (ignore_stores
)
3143 flags
|= EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_NODIRECTESCAPE
;
3144 flags
|= ee
->min_flags
;
3145 to_info_lto
->arg_flags
[ee
->parm_index
] &= flags
;
3146 if (to_info_lto
->arg_flags
[ee
->parm_index
])
3149 struct escape_map entry
= {ee
->parm_index
, ee
->direct
};
3151 emap
[ee
->arg
].safe_push (entry
);
3153 update_escape_summary (edge
->callee
, emap
);
3154 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
3157 escape_summaries
->remove (edge
);
3161 if (to_info
&& !to_info
->useful_p (flags
))
3164 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
3166 summaries
->remove (to
);
3169 else if (to_info
&& dump_file
)
3172 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
3174 to_info
->dump (dump_file
);
3177 summaries
->remove (edge
->callee
);
3181 if (to_info_lto
&& !to_info_lto
->useful_p (flags
))
3184 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
3186 summaries_lto
->remove (to
);
3188 else if (to_info_lto
&& dump_file
)
3191 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
3193 to_info_lto
->dump (dump_file
);
3196 if (callee_info_lto
)
3197 summaries_lto
->remove (edge
->callee
);
3199 if (!to_info
&& !to_info_lto
)
3200 remove_modref_edge_summaries (to
);
3204 /* Get parameter type from DECL. This is only safe for special cases
3205 like builtins we create fnspec for because the type match is checked
3206 at fnspec creation time. */
3209 get_parm_type (tree decl
, unsigned int i
)
3211 tree t
= TYPE_ARG_TYPES (TREE_TYPE (decl
));
3213 for (unsigned int p
= 0; p
< i
; p
++)
3215 return TREE_VALUE (t
);
3218 /* Return access mode for argument I of call E with FNSPEC. */
3220 static modref_access_node
3221 get_access_for_fnspec (cgraph_edge
*e
, attr_fnspec
&fnspec
,
3222 unsigned int i
, modref_parm_map
&map
)
3224 tree size
= NULL_TREE
;
3225 unsigned int size_arg
;
3227 if (!fnspec
.arg_specified_p (i
))
3229 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
3231 cgraph_node
*node
= e
->caller
->inlined_to
3232 ? e
->caller
->inlined_to
: e
->caller
;
3233 class ipa_node_params
*caller_parms_info
= IPA_NODE_REF (node
);
3234 class ipa_edge_args
*args
= IPA_EDGE_REF (e
);
3235 struct ipa_jump_func
*jf
= ipa_get_ith_jump_func (args
, size_arg
);
3238 size
= ipa_value_from_jfunc (caller_parms_info
, jf
,
3239 get_parm_type (e
->callee
->decl
, size_arg
));
3241 else if (fnspec
.arg_access_size_given_by_type_p (i
))
3242 size
= TYPE_SIZE_UNIT (get_parm_type (e
->callee
->decl
, i
));
3243 modref_access_node a
= {0, -1, -1,
3244 map
.parm_offset
, map
.parm_index
,
3245 map
.parm_offset_known
};
3246 poly_int64 size_hwi
;
3248 && poly_int_tree_p (size
, &size_hwi
)
3249 && coeffs_in_range_p (size_hwi
, 0,
3250 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
3253 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
3258 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
3259 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
3262 propagate_unknown_call (cgraph_node
*node
,
3263 cgraph_edge
*e
, int ecf_flags
,
3264 modref_summary
*cur_summary
,
3265 modref_summary_lto
*cur_summary_lto
)
3267 bool changed
= false;
3268 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
3269 auto_vec
<modref_parm_map
, 32> parm_map
;
3271 && compute_parm_map (e
, &parm_map
))
3273 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
3275 gcc_checking_assert (fnspec
.known_p ());
3276 if (fnspec
.global_memory_read_p ())
3277 collapse_loads (cur_summary
, cur_summary_lto
);
3280 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
3281 for (unsigned i
= 0; i
< parm_map
.length () && t
;
3282 i
++, t
= TREE_CHAIN (t
))
3283 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
3285 else if (!fnspec
.arg_specified_p (i
)
3286 || fnspec
.arg_maybe_read_p (i
))
3288 modref_parm_map map
= parm_map
[i
];
3289 if (map
.parm_index
== -2)
3291 if (map
.parm_index
== -1)
3293 collapse_loads (cur_summary
, cur_summary_lto
);
3297 changed
|= cur_summary
->loads
->insert
3298 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3299 if (cur_summary_lto
)
3300 changed
|= cur_summary_lto
->loads
->insert
3301 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3304 if (ignore_stores_p (node
->decl
, ecf_flags
))
3306 else if (fnspec
.global_memory_written_p ())
3307 collapse_stores (cur_summary
, cur_summary_lto
);
3310 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
3311 for (unsigned i
= 0; i
< parm_map
.length () && t
;
3312 i
++, t
= TREE_CHAIN (t
))
3313 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
3315 else if (!fnspec
.arg_specified_p (i
)
3316 || fnspec
.arg_maybe_written_p (i
))
3318 modref_parm_map map
= parm_map
[i
];
3319 if (map
.parm_index
== -2)
3321 if (map
.parm_index
== -1)
3323 collapse_stores (cur_summary
, cur_summary_lto
);
3327 changed
|= cur_summary
->stores
->insert
3328 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3329 if (cur_summary_lto
)
3330 changed
|= cur_summary_lto
->stores
->insert
3331 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3334 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
3336 if (cur_summary
&& !cur_summary
->writes_errno
)
3338 cur_summary
->writes_errno
= true;
3341 if (cur_summary_lto
&& !cur_summary_lto
->writes_errno
)
3343 cur_summary_lto
->writes_errno
= true;
3350 fprintf (dump_file
, " collapsing loads\n");
3351 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
3352 if (!ignore_stores_p (node
->decl
, ecf_flags
))
3355 fprintf (dump_file
, " collapsing stores\n");
3356 changed
|= collapse_stores (cur_summary
, cur_summary_lto
);
3361 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
3362 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
3365 remove_useless_summaries (cgraph_node
*node
,
3366 modref_summary
**cur_summary_ptr
,
3367 modref_summary_lto
**cur_summary_lto_ptr
,
3370 if (*cur_summary_ptr
&& !(*cur_summary_ptr
)->useful_p (ecf_flags
, false))
3372 optimization_summaries
->remove (node
);
3373 *cur_summary_ptr
= NULL
;
3375 if (*cur_summary_lto_ptr
3376 && !(*cur_summary_lto_ptr
)->useful_p (ecf_flags
, false))
3378 summaries_lto
->remove (node
);
3379 *cur_summary_lto_ptr
= NULL
;
3383 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3384 and propagate loads/stores. */
3387 modref_propagate_in_scc (cgraph_node
*component_node
)
3389 bool changed
= true;
3395 for (struct cgraph_node
*cur
= component_node
; cur
;
3396 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3398 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
3399 modref_summary
*cur_summary
= optimization_summaries
3400 ? optimization_summaries
->get (node
)
3402 modref_summary_lto
*cur_summary_lto
= summaries_lto
3403 ? summaries_lto
->get (node
)
3406 if (!cur_summary
&& !cur_summary_lto
)
3409 int cur_ecf_flags
= flags_from_decl_or_type (node
->decl
);
3412 fprintf (dump_file
, " Processing %s%s%s\n",
3414 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3415 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3417 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
3419 if (e
->indirect_info
->ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
3422 fprintf (dump_file
, " Indirect call"
3423 "collapsing loads\n");
3424 if (propagate_unknown_call
3425 (node
, e
, e
->indirect_info
->ecf_flags
,
3426 cur_summary
, cur_summary_lto
))
3429 remove_useless_summaries (node
, &cur_summary
,
3432 if (!cur_summary
&& !cur_summary_lto
)
3437 if (!cur_summary
&& !cur_summary_lto
)
3440 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
3441 callee_edge
= callee_edge
->next_callee
)
3443 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
3444 modref_summary
*callee_summary
= NULL
;
3445 modref_summary_lto
*callee_summary_lto
= NULL
;
3446 struct cgraph_node
*callee
;
3448 if (flags
& (ECF_CONST
| ECF_NOVOPS
)
3449 || !callee_edge
->inline_failed
)
3452 /* Get the callee and its summary. */
3453 enum availability avail
;
3454 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
3457 /* It is not necessary to re-process calls outside of the
3461 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
3462 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
3466 fprintf (dump_file
, " Call to %s\n",
3467 callee_edge
->callee
->dump_name ());
3469 bool ignore_stores
= ignore_stores_p (cur
->decl
, flags
);
3471 if (avail
<= AVAIL_INTERPOSABLE
)
3474 fprintf (dump_file
, " Call target interposable"
3475 " or not available\n");
3476 changed
|= propagate_unknown_call
3477 (node
, callee_edge
, flags
,
3478 cur_summary
, cur_summary_lto
);
3479 if (!cur_summary
&& !cur_summary_lto
)
3484 /* We don't know anything about CALLEE, hence we cannot tell
3485 anything about the entire component. */
3488 && !(callee_summary
= optimization_summaries
->get (callee
)))
3491 fprintf (dump_file
, " No call target summary\n");
3492 changed
|= propagate_unknown_call
3493 (node
, callee_edge
, flags
,
3497 && !(callee_summary_lto
= summaries_lto
->get (callee
)))
3500 fprintf (dump_file
, " No call target summary\n");
3501 changed
|= propagate_unknown_call
3502 (node
, callee_edge
, flags
,
3503 NULL
, cur_summary_lto
);
3506 /* We can not safely optimize based on summary of callee if it
3507 does not always bind to current def: it is possible that
3508 memory load was optimized out earlier which may not happen in
3509 the interposed variant. */
3510 if (!callee_edge
->binds_to_current_def_p ())
3512 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
3514 fprintf (dump_file
, " May not bind local;"
3515 " collapsing loads\n");
3519 auto_vec
<modref_parm_map
, 32> parm_map
;
3521 compute_parm_map (callee_edge
, &parm_map
);
3523 /* Merge in callee's information. */
3526 changed
|= cur_summary
->loads
->merge
3527 (callee_summary
->loads
, &parm_map
);
3530 changed
|= cur_summary
->stores
->merge
3531 (callee_summary
->stores
, &parm_map
);
3532 if (!cur_summary
->writes_errno
3533 && callee_summary
->writes_errno
)
3535 cur_summary
->writes_errno
= true;
3540 if (callee_summary_lto
)
3542 changed
|= cur_summary_lto
->loads
->merge
3543 (callee_summary_lto
->loads
, &parm_map
);
3546 changed
|= cur_summary_lto
->stores
->merge
3547 (callee_summary_lto
->stores
, &parm_map
);
3548 if (!cur_summary_lto
->writes_errno
3549 && callee_summary_lto
->writes_errno
)
3551 cur_summary_lto
->writes_errno
= true;
3557 remove_useless_summaries (node
, &cur_summary
,
3560 if (!cur_summary
&& !cur_summary_lto
)
3562 if (dump_file
&& changed
)
3565 cur_summary
->dump (dump_file
);
3566 if (cur_summary_lto
)
3567 cur_summary_lto
->dump (dump_file
);
3568 dump_modref_edge_summaries (dump_file
, node
, 4);
3576 "Propagation finished in %i iterations\n", iteration
);
3579 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
3582 modref_propagate_dump_scc (cgraph_node
*component_node
)
3584 for (struct cgraph_node
*cur
= component_node
; cur
;
3585 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3586 if (!cur
->inlined_to
)
3588 modref_summary
*cur_summary
= optimization_summaries
3589 ? optimization_summaries
->get (cur
)
3591 modref_summary_lto
*cur_summary_lto
= summaries_lto
3592 ? summaries_lto
->get (cur
)
3595 fprintf (dump_file
, "Propagated modref for %s%s%s\n",
3597 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3598 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3599 if (optimization_summaries
)
3602 cur_summary
->dump (dump_file
);
3604 fprintf (dump_file
, " Not tracked\n");
3608 if (cur_summary_lto
)
3609 cur_summary_lto
->dump (dump_file
);
3611 fprintf (dump_file
, " Not tracked (lto)\n");
3616 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
3617 and SUMMARY_LTO to CUR_SUMMARY_LTO.
3618 Return true if something changed. */
3621 modref_merge_call_site_flags (escape_summary
*sum
,
3622 modref_summary
*cur_summary
,
3623 modref_summary_lto
*cur_summary_lto
,
3624 modref_summary
*summary
,
3625 modref_summary_lto
*summary_lto
,
3630 bool changed
= false;
3632 /* If we have no useful info to propagate. */
3633 if ((!cur_summary
|| !cur_summary
->arg_flags
.length ())
3634 && (!cur_summary_lto
|| !cur_summary_lto
->arg_flags
.length ()))
3637 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3642 if (summary
&& ee
->arg
< summary
->arg_flags
.length ())
3643 flags
= summary
->arg_flags
[ee
->arg
];
3645 && ee
->arg
< summary_lto
->arg_flags
.length ())
3646 flags_lto
= summary_lto
->arg_flags
[ee
->arg
];
3649 flags
= deref_flags (flags
, ignore_stores
);
3650 flags_lto
= deref_flags (flags_lto
, ignore_stores
);
3652 else if (ignore_stores
)
3654 flags
|= EAF_NOESCAPE
| EAF_NOCLOBBER
| EAF_NODIRECTESCAPE
;
3655 flags_lto
|= EAF_NOESCAPE
| EAF_NOCLOBBER
| EAF_NODIRECTESCAPE
;
3657 flags
|= ee
->min_flags
;
3658 flags_lto
|= ee
->min_flags
;
3659 if (!(flags
& EAF_UNUSED
)
3660 && cur_summary
&& ee
->parm_index
< cur_summary
->arg_flags
.length ())
3662 int f
= cur_summary
->arg_flags
[ee
->parm_index
];
3663 if ((f
& flags
) != f
)
3666 if ((f
& ~(EAF_DIRECT
| EAF_NOCLOBBER
)) == 0)
3668 cur_summary
->arg_flags
[ee
->parm_index
] = f
;
3672 if (!(flags_lto
& EAF_UNUSED
)
3674 && ee
->parm_index
< cur_summary_lto
->arg_flags
.length ())
3676 int f
= cur_summary_lto
->arg_flags
[ee
->parm_index
];
3677 if ((f
& flags_lto
) != f
)
3680 if ((f
& ~(EAF_DIRECT
| EAF_NOCLOBBER
)) == 0)
3682 cur_summary_lto
->arg_flags
[ee
->parm_index
] = f
;
3690 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3691 and propagate arg flags. */
3694 modref_propagate_flags_in_scc (cgraph_node
*component_node
)
3696 bool changed
= true;
3702 for (struct cgraph_node
*cur
= component_node
; cur
;
3703 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3705 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
3706 modref_summary
*cur_summary
= optimization_summaries
3707 ? optimization_summaries
->get (node
)
3709 modref_summary_lto
*cur_summary_lto
= summaries_lto
3710 ? summaries_lto
->get (node
)
3713 if (!cur_summary
&& !cur_summary_lto
)
3717 fprintf (dump_file
, " Processing %s%s%s\n",
3719 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3720 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3722 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
3724 escape_summary
*sum
= escape_summaries
->get (e
);
3726 if (!sum
|| (e
->indirect_info
->ecf_flags
3727 & (ECF_CONST
| ECF_NOVOPS
)))
3730 changed
|= modref_merge_call_site_flags
3731 (sum
, cur_summary
, cur_summary_lto
,
3732 NULL
, NULL
, ignore_stores_p (node
->decl
,
3733 e
->indirect_info
->ecf_flags
));
3736 if (!cur_summary
&& !cur_summary_lto
)
3739 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
3740 callee_edge
= callee_edge
->next_callee
)
3742 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
3743 modref_summary
*callee_summary
= NULL
;
3744 modref_summary_lto
*callee_summary_lto
= NULL
;
3745 struct cgraph_node
*callee
;
3747 if (flags
& (ECF_CONST
| ECF_NOVOPS
)
3748 || !callee_edge
->inline_failed
)
3750 /* Get the callee and its summary. */
3751 enum availability avail
;
3752 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
3755 /* It is not necessary to re-process calls outside of the
3759 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
3760 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
3763 escape_summary
*sum
= escape_summaries
->get (callee_edge
);
3768 fprintf (dump_file
, " Call to %s\n",
3769 callee_edge
->callee
->dump_name ());
3771 if (avail
<= AVAIL_INTERPOSABLE
3772 || callee_edge
->call_stmt_cannot_inline_p
)
3777 callee_summary
= optimization_summaries
->get (callee
);
3778 if (cur_summary_lto
)
3779 callee_summary_lto
= summaries_lto
->get (callee
);
3781 changed
|= modref_merge_call_site_flags
3782 (sum
, cur_summary
, cur_summary_lto
,
3783 callee_summary
, callee_summary_lto
,
3784 ignore_stores_p (node
->decl
, flags
));
3785 if (dump_file
&& changed
)
3788 cur_summary
->dump (dump_file
);
3789 if (cur_summary_lto
)
3790 cur_summary_lto
->dump (dump_file
);
3798 "Propagation of flags finished in %i iterations\n", iteration
);
3801 /* Run the IPA pass. This will take a function's summaries and calls and
3802 construct new summaries which represent a transitive closure. So that
3803 summary of an analyzed function contains information about the loads and
3804 stores that the function or any function that it calls does. */
3807 pass_ipa_modref::execute (function
*)
3809 if (!summaries
&& !summaries_lto
)
3812 if (optimization_summaries
)
3813 ggc_delete (optimization_summaries
);
3814 optimization_summaries
= summaries
;
3817 struct cgraph_node
**order
= XCNEWVEC (struct cgraph_node
*,
3818 symtab
->cgraph_count
);
3820 order_pos
= ipa_reduced_postorder (order
, true, ignore_edge
);
3823 /* Iterate over all strongly connected components in post-order. */
3824 for (i
= 0; i
< order_pos
; i
++)
3826 /* Get the component's representative. That's just any node in the
3827 component from which we can traverse the entire component. */
3828 struct cgraph_node
*component_node
= order
[i
];
3831 fprintf (dump_file
, "\n\nStart of SCC component\n");
3833 modref_propagate_in_scc (component_node
);
3834 modref_propagate_flags_in_scc (component_node
);
3836 modref_propagate_dump_scc (component_node
);
3839 FOR_EACH_FUNCTION (node
)
3840 update_signature (node
);
3842 ((modref_summaries_lto
*)summaries_lto
)->propagated
= true;
3843 ipa_free_postorder_info ();
3845 delete fnspec_summaries
;
3846 fnspec_summaries
= NULL
;
3847 delete escape_summaries
;
3848 escape_summaries
= NULL
;
3852 /* Summaries must stay alive until end of compilation. */
3855 ipa_modref_c_finalize ()
3857 if (optimization_summaries
)
3858 ggc_delete (optimization_summaries
);
3859 optimization_summaries
= NULL
;
3860 gcc_checking_assert (!summaries
);
3862 ggc_delete (summaries_lto
);
3863 summaries_lto
= NULL
;
3864 if (fnspec_summaries
)
3865 delete fnspec_summaries
;
3866 fnspec_summaries
= NULL
;
3867 if (escape_summaries
)
3868 delete escape_summaries
;
3869 escape_summaries
= NULL
;
3872 #include "gt-ipa-modref.h"