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_UNUSED
)
155 fprintf (out
, " unused");
160 struct escape_summary
162 auto_vec
<escape_entry
> esc
;
163 void dump (FILE *out
)
165 for (unsigned int i
= 0; i
< esc
.length (); i
++)
167 fprintf (out
, " parm %i arg %i %s min:",
170 esc
[i
].direct
? "(direct)" : "(indirect)");
171 dump_eaf_flags (out
, esc
[i
].min_flags
, false);
177 class escape_summaries_t
: public call_summary
<escape_summary
*>
180 escape_summaries_t (symbol_table
*symtab
)
181 : call_summary
<escape_summary
*> (symtab
) {}
182 /* Hook that is called by summary when an edge is duplicated. */
183 virtual void duplicate (cgraph_edge
*,
188 dst
->esc
= src
->esc
.copy ();
192 static escape_summaries_t
*escape_summaries
= NULL
;
194 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
197 /* Class (from which there is one global instance) that holds modref summaries
198 for all analyzed functions. */
200 class GTY((user
)) modref_summaries
201 : public fast_function_summary
<modref_summary
*, va_gc
>
204 modref_summaries (symbol_table
*symtab
)
205 : fast_function_summary
<modref_summary
*, va_gc
> (symtab
) {}
206 virtual void insert (cgraph_node
*, modref_summary
*state
);
207 virtual void duplicate (cgraph_node
*src_node
,
208 cgraph_node
*dst_node
,
209 modref_summary
*src_data
,
210 modref_summary
*dst_data
);
211 static modref_summaries
*create_ggc (symbol_table
*symtab
)
213 return new (ggc_alloc_no_dtor
<modref_summaries
> ())
214 modref_summaries (symtab
);
218 class modref_summary_lto
;
220 /* Class (from which there is one global instance) that holds modref summaries
221 for all analyzed functions. */
223 class GTY((user
)) modref_summaries_lto
224 : public fast_function_summary
<modref_summary_lto
*, va_gc
>
227 modref_summaries_lto (symbol_table
*symtab
)
228 : fast_function_summary
<modref_summary_lto
*, va_gc
> (symtab
),
229 propagated (false) {}
230 virtual void insert (cgraph_node
*, modref_summary_lto
*state
);
231 virtual void duplicate (cgraph_node
*src_node
,
232 cgraph_node
*dst_node
,
233 modref_summary_lto
*src_data
,
234 modref_summary_lto
*dst_data
);
235 static modref_summaries_lto
*create_ggc (symbol_table
*symtab
)
237 return new (ggc_alloc_no_dtor
<modref_summaries_lto
> ())
238 modref_summaries_lto (symtab
);
243 /* Global variable holding all modref summaries
244 (from analysis to IPA propagation time). */
246 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
249 /* Global variable holding all modref optimization summaries
250 (from IPA propagation time or used by local optimization pass). */
252 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
253 *optimization_summaries
;
255 /* LTO summaries hold info from analysis to LTO streaming or from LTO
256 stream-in through propagation to LTO stream-out. */
258 static GTY(()) fast_function_summary
<modref_summary_lto
*, va_gc
>
261 /* Summary for a single function which this pass produces. */
263 modref_summary::modref_summary ()
264 : loads (NULL
), stores (NULL
), writes_errno (NULL
)
268 modref_summary::~modref_summary ()
276 /* Return true if FLAGS holds some useful information. */
279 eaf_flags_useful_p (vec
<unsigned char> &flags
, int ecf_flags
)
281 for (unsigned i
= 0; i
< flags
.length (); i
++)
282 if (ecf_flags
& ECF_PURE
)
284 if (flags
[i
] & (EAF_UNUSED
| EAF_DIRECT
))
295 /* Return true if summary is potentially useful for optimization.
296 If CHECK_FLAGS is false assume that arg_flags are useful. */
299 modref_summary::useful_p (int ecf_flags
, bool check_flags
)
301 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
303 if (arg_flags
.length () && !check_flags
)
305 if (check_flags
&& eaf_flags_useful_p (arg_flags
, ecf_flags
))
307 arg_flags
.release ();
308 if (loads
&& !loads
->every_base
)
310 if (ecf_flags
& ECF_PURE
)
312 return stores
&& !stores
->every_base
;
315 /* Single function summary used for LTO. */
317 typedef modref_tree
<tree
> modref_records_lto
;
318 struct GTY(()) modref_summary_lto
320 /* Load and stores in functions using types rather then alias sets.
322 This is necessary to make the information streamable for LTO but is also
323 more verbose and thus more likely to hit the limits. */
324 modref_records_lto
*loads
;
325 modref_records_lto
*stores
;
326 auto_vec
<unsigned char> GTY((skip
)) arg_flags
;
329 modref_summary_lto ();
330 ~modref_summary_lto ();
332 bool useful_p (int ecf_flags
, bool check_flags
= true);
335 /* Summary for a single function which this pass produces. */
337 modref_summary_lto::modref_summary_lto ()
338 : loads (NULL
), stores (NULL
), writes_errno (NULL
)
342 modref_summary_lto::~modref_summary_lto ()
351 /* Return true if lto summary is potentially useful for optimization.
352 If CHECK_FLAGS is false assume that arg_flags are useful. */
355 modref_summary_lto::useful_p (int ecf_flags
, bool check_flags
)
357 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
359 if (arg_flags
.length () && !check_flags
)
361 if (check_flags
&& eaf_flags_useful_p (arg_flags
, ecf_flags
))
363 arg_flags
.release ();
364 if (loads
&& !loads
->every_base
)
366 if (ecf_flags
& ECF_PURE
)
368 return stores
&& !stores
->every_base
;
374 dump_access (modref_access_node
*a
, FILE *out
)
376 fprintf (out
, " access:");
377 if (a
->parm_index
!= -1)
379 fprintf (out
, " Parm %i", a
->parm_index
);
380 if (a
->parm_offset_known
)
382 fprintf (out
, " param offset:");
383 print_dec ((poly_int64_pod
)a
->parm_offset
, out
, SIGNED
);
386 if (a
->range_info_useful_p ())
388 fprintf (out
, " offset:");
389 print_dec ((poly_int64_pod
)a
->offset
, out
, SIGNED
);
390 fprintf (out
, " size:");
391 print_dec ((poly_int64_pod
)a
->size
, out
, SIGNED
);
392 fprintf (out
, " max_size:");
393 print_dec ((poly_int64_pod
)a
->max_size
, out
, SIGNED
);
398 /* Dump records TT to OUT. */
401 dump_records (modref_records
*tt
, FILE *out
)
403 fprintf (out
, " Limits: %i bases, %i refs\n",
404 (int)tt
->max_bases
, (int)tt
->max_refs
);
407 fprintf (out
, " Every base\n");
411 modref_base_node
<alias_set_type
> *n
;
412 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
414 fprintf (out
, " Base %i: alias set %i\n", (int)i
, n
->base
);
417 fprintf (out
, " Every ref\n");
421 modref_ref_node
<alias_set_type
> *r
;
422 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
424 fprintf (out
, " Ref %i: alias set %i\n", (int)j
, r
->ref
);
427 fprintf (out
, " Every access\n");
431 modref_access_node
*a
;
432 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
433 dump_access (a
, out
);
438 /* Dump records TT to OUT. */
441 dump_lto_records (modref_records_lto
*tt
, FILE *out
)
443 fprintf (out
, " Limits: %i bases, %i refs\n",
444 (int)tt
->max_bases
, (int)tt
->max_refs
);
447 fprintf (out
, " Every base\n");
451 modref_base_node
<tree
> *n
;
452 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
454 fprintf (out
, " Base %i:", (int)i
);
455 print_generic_expr (dump_file
, n
->base
);
456 fprintf (out
, " (alias set %i)\n",
457 n
->base
? get_alias_set (n
->base
) : 0);
460 fprintf (out
, " Every ref\n");
464 modref_ref_node
<tree
> *r
;
465 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
467 fprintf (out
, " Ref %i:", (int)j
);
468 print_generic_expr (dump_file
, r
->ref
);
469 fprintf (out
, " (alias set %i)\n",
470 r
->ref
? get_alias_set (r
->ref
) : 0);
473 fprintf (out
, " Every access\n");
477 modref_access_node
*a
;
478 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
479 dump_access (a
, out
);
484 /* Dump all escape points of NODE to OUT. */
487 dump_modref_edge_summaries (FILE *out
, cgraph_node
*node
, int depth
)
490 if (!escape_summaries
)
492 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
494 class escape_summary
*sum
= escape_summaries
->get (e
);
497 fprintf (out
, "%*sIndirect call %i in %s escapes:",
498 depth
, "", i
, node
->dump_name ());
503 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
505 if (!e
->inline_failed
)
506 dump_modref_edge_summaries (out
, e
->callee
, depth
+ 1);
507 class escape_summary
*sum
= escape_summaries
->get (e
);
510 fprintf (out
, "%*sCall %s->%s escapes:", depth
, "",
511 node
->dump_name (), e
->callee
->dump_name ());
514 class fnspec_summary
*fsum
= fnspec_summaries
->get (e
);
517 fprintf (out
, "%*sCall %s->%s fnspec: %s\n", depth
, "",
518 node
->dump_name (), e
->callee
->dump_name (),
524 /* Remove all call edge summaries associated with NODE. */
527 remove_modref_edge_summaries (cgraph_node
*node
)
529 if (!escape_summaries
)
531 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
532 escape_summaries
->remove (e
);
533 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
535 if (!e
->inline_failed
)
536 remove_modref_edge_summaries (e
->callee
);
537 escape_summaries
->remove (e
);
538 fnspec_summaries
->remove (e
);
545 modref_summary::dump (FILE *out
)
549 fprintf (out
, " loads:\n");
550 dump_records (loads
, out
);
554 fprintf (out
, " stores:\n");
555 dump_records (stores
, out
);
558 fprintf (out
, " Writes errno\n");
559 if (arg_flags
.length ())
561 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
564 fprintf (out
, " parm %i flags:", i
);
565 dump_eaf_flags (out
, arg_flags
[i
]);
573 modref_summary_lto::dump (FILE *out
)
575 fprintf (out
, " loads:\n");
576 dump_lto_records (loads
, out
);
577 fprintf (out
, " stores:\n");
578 dump_lto_records (stores
, out
);
580 fprintf (out
, " Writes errno\n");
581 if (arg_flags
.length ())
583 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
586 fprintf (out
, " parm %i flags:", i
);
587 dump_eaf_flags (out
, arg_flags
[i
]);
592 /* Get function summary for FUNC if it exists, return NULL otherwise. */
595 get_modref_function_summary (cgraph_node
*func
)
597 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
598 if (!optimization_summaries
)
601 /* A single function body may be represented by multiple symbols with
602 different visibility. For example, if FUNC is an interposable alias,
603 we don't want to return anything, even if we have summary for the target
605 enum availability avail
;
606 func
= func
->function_or_virtual_thunk_symbol
607 (&avail
, current_function_decl
?
608 cgraph_node::get (current_function_decl
) : NULL
);
609 if (avail
<= AVAIL_INTERPOSABLE
)
612 modref_summary
*r
= optimization_summaries
->get (func
);
616 /* Construct modref_access_node from REF. */
617 static modref_access_node
618 get_access (ao_ref
*ref
)
622 base
= ao_ref_base (ref
);
623 modref_access_node a
= {ref
->offset
, ref
->size
, ref
->max_size
,
625 if (TREE_CODE (base
) == MEM_REF
|| TREE_CODE (base
) == TARGET_MEM_REF
)
628 base
= TREE_OPERAND (base
, 0);
629 if (TREE_CODE (base
) == SSA_NAME
630 && SSA_NAME_IS_DEFAULT_DEF (base
)
631 && TREE_CODE (SSA_NAME_VAR (base
)) == PARM_DECL
)
634 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
635 t
!= SSA_NAME_VAR (base
); t
= DECL_CHAIN (t
))
644 if (TREE_CODE (memref
) == MEM_REF
)
647 = wi::to_poly_wide (TREE_OPERAND
648 (memref
, 1)).to_shwi (&a
.parm_offset
);
651 a
.parm_offset_known
= false;
661 /* Record access into the modref_records data structure. */
664 record_access (modref_records
*tt
, ao_ref
*ref
)
666 alias_set_type base_set
= !flag_strict_aliasing
? 0
667 : ao_ref_base_alias_set (ref
);
668 alias_set_type ref_set
= !flag_strict_aliasing
? 0
669 : (ao_ref_alias_set (ref
));
670 modref_access_node a
= get_access (ref
);
673 fprintf (dump_file
, " - Recording base_set=%i ref_set=%i parm=%i\n",
674 base_set
, ref_set
, a
.parm_index
);
676 tt
->insert (base_set
, ref_set
, a
);
679 /* IPA version of record_access_tree. */
682 record_access_lto (modref_records_lto
*tt
, ao_ref
*ref
)
684 /* get_alias_set sometimes use different type to compute the alias set
685 than TREE_TYPE (base). Do same adjustments. */
686 tree base_type
= NULL_TREE
, ref_type
= NULL_TREE
;
687 if (flag_strict_aliasing
)
692 while (handled_component_p (base
))
693 base
= TREE_OPERAND (base
, 0);
695 base_type
= reference_alias_ptr_type_1 (&base
);
698 base_type
= TREE_TYPE (base
);
700 base_type
= TYPE_REF_CAN_ALIAS_ALL (base_type
)
701 ? NULL_TREE
: TREE_TYPE (base_type
);
703 tree ref_expr
= ref
->ref
;
704 ref_type
= reference_alias_ptr_type_1 (&ref_expr
);
707 ref_type
= TREE_TYPE (ref_expr
);
709 ref_type
= TYPE_REF_CAN_ALIAS_ALL (ref_type
)
710 ? NULL_TREE
: TREE_TYPE (ref_type
);
712 /* Sanity check that we are in sync with what get_alias_set does. */
713 gcc_checking_assert ((!base_type
&& !ao_ref_base_alias_set (ref
))
714 || get_alias_set (base_type
)
715 == ao_ref_base_alias_set (ref
));
716 gcc_checking_assert ((!ref_type
&& !ao_ref_alias_set (ref
))
717 || get_alias_set (ref_type
)
718 == ao_ref_alias_set (ref
));
720 /* Do not bother to record types that have no meaningful alias set.
721 Also skip variably modified types since these go to local streams. */
722 if (base_type
&& (!get_alias_set (base_type
)
723 || variably_modified_type_p (base_type
, NULL_TREE
)))
724 base_type
= NULL_TREE
;
725 if (ref_type
&& (!get_alias_set (ref_type
)
726 || variably_modified_type_p (ref_type
, NULL_TREE
)))
727 ref_type
= NULL_TREE
;
729 modref_access_node a
= get_access (ref
);
732 fprintf (dump_file
, " - Recording base type:");
733 print_generic_expr (dump_file
, base_type
);
734 fprintf (dump_file
, " (alias set %i) ref type:",
735 base_type
? get_alias_set (base_type
) : 0);
736 print_generic_expr (dump_file
, ref_type
);
737 fprintf (dump_file
, " (alias set %i) parm:%i\n",
738 ref_type
? get_alias_set (ref_type
) : 0,
742 tt
->insert (base_type
, ref_type
, a
);
745 /* Returns true if and only if we should store the access to EXPR.
746 Some accesses, e.g. loads from automatic variables, are not interesting. */
749 record_access_p (tree expr
)
751 if (refs_local_or_readonly_memory_p (expr
))
754 fprintf (dump_file
, " - Read-only or local, ignoring.\n");
760 /* Return true if ECF flags says that return value can be ignored. */
763 ignore_retval_p (tree caller
, int flags
)
765 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
766 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
771 /* Return true if ECF flags says that stores can be ignored. */
774 ignore_stores_p (tree caller
, int flags
)
776 if (flags
& (ECF_PURE
| ECF_CONST
| ECF_NOVOPS
))
778 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
779 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
784 /* Determine parm_map for argument I of STMT. */
787 parm_map_for_arg (gimple
*stmt
, int i
)
789 tree op
= gimple_call_arg (stmt
, i
);
792 struct modref_parm_map parm_map
;
794 parm_map
.parm_offset_known
= false;
795 parm_map
.parm_offset
= 0;
797 offset_known
= unadjusted_ptr_and_unit_offset (op
, &op
, &offset
);
798 if (TREE_CODE (op
) == SSA_NAME
799 && SSA_NAME_IS_DEFAULT_DEF (op
)
800 && TREE_CODE (SSA_NAME_VAR (op
)) == PARM_DECL
)
803 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
804 t
!= SSA_NAME_VAR (op
); t
= DECL_CHAIN (t
))
813 parm_map
.parm_index
= index
;
814 parm_map
.parm_offset_known
= offset_known
;
815 parm_map
.parm_offset
= offset
;
817 else if (points_to_local_or_readonly_memory_p (op
))
818 parm_map
.parm_index
= -2;
820 parm_map
.parm_index
= -1;
824 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
825 int CUR_SUMMARY. Return true if something changed.
826 If IGNORE_STORES is true, do not merge stores. */
829 merge_call_side_effects (modref_summary
*cur_summary
,
830 gimple
*stmt
, modref_summary
*callee_summary
,
831 bool ignore_stores
, cgraph_node
*callee_node
)
833 auto_vec
<modref_parm_map
, 32> parm_map
;
834 bool changed
= false;
837 fprintf (dump_file
, " - Merging side effects of %s with parm map:",
838 callee_node
->dump_name ());
840 /* We can not safely optimize based on summary of callee if it does
841 not always bind to current def: it is possible that memory load
842 was optimized out earlier which may not happen in the interposed
844 if (!callee_node
->binds_to_current_def_p ())
847 fprintf (dump_file
, " - May be interposed: collapsing loads.\n");
848 cur_summary
->loads
->collapse ();
851 parm_map
.safe_grow_cleared (gimple_call_num_args (stmt
), true);
852 for (unsigned i
= 0; i
< gimple_call_num_args (stmt
); i
++)
854 parm_map
[i
] = parm_map_for_arg (stmt
, i
);
857 fprintf (dump_file
, " %i", parm_map
[i
].parm_index
);
858 if (parm_map
[i
].parm_offset_known
)
860 fprintf (dump_file
, " offset:");
861 print_dec ((poly_int64_pod
)parm_map
[i
].parm_offset
,
867 fprintf (dump_file
, "\n");
869 /* Merge with callee's summary. */
870 changed
|= cur_summary
->loads
->merge (callee_summary
->loads
, &parm_map
);
873 changed
|= cur_summary
->stores
->merge (callee_summary
->stores
,
875 if (!cur_summary
->writes_errno
876 && callee_summary
->writes_errno
)
878 cur_summary
->writes_errno
= true;
885 /* Return access mode for argument I of call STMT with FNSPEC. */
887 static modref_access_node
888 get_access_for_fnspec (gcall
*call
, attr_fnspec
&fnspec
,
889 unsigned int i
, modref_parm_map
&map
)
891 tree size
= NULL_TREE
;
892 unsigned int size_arg
;
894 if (!fnspec
.arg_specified_p (i
))
896 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
897 size
= gimple_call_arg (call
, size_arg
);
898 else if (fnspec
.arg_access_size_given_by_type_p (i
))
900 tree callee
= gimple_call_fndecl (call
);
901 tree t
= TYPE_ARG_TYPES (TREE_TYPE (callee
));
903 for (unsigned int p
= 0; p
< i
; p
++)
905 size
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t
)));
907 modref_access_node a
= {0, -1, -1,
908 map
.parm_offset
, map
.parm_index
,
909 map
.parm_offset_known
};
912 && poly_int_tree_p (size
, &size_hwi
)
913 && coeffs_in_range_p (size_hwi
, 0,
914 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
917 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
922 /* Collapse loads and return true if something changed. */
925 collapse_loads (modref_summary
*cur_summary
,
926 modref_summary_lto
*cur_summary_lto
)
928 bool changed
= false;
930 if (cur_summary
&& !cur_summary
->loads
->every_base
)
932 cur_summary
->loads
->collapse ();
936 && !cur_summary_lto
->loads
->every_base
)
938 cur_summary_lto
->loads
->collapse ();
944 /* Collapse loads and return true if something changed. */
947 collapse_stores (modref_summary
*cur_summary
,
948 modref_summary_lto
*cur_summary_lto
)
950 bool changed
= false;
952 if (cur_summary
&& !cur_summary
->stores
->every_base
)
954 cur_summary
->stores
->collapse ();
958 && !cur_summary_lto
->stores
->every_base
)
960 cur_summary_lto
->stores
->collapse ();
967 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
968 If IGNORE_STORES is true ignore them.
969 Return false if no useful summary can be produced. */
972 process_fnspec (modref_summary
*cur_summary
,
973 modref_summary_lto
*cur_summary_lto
,
974 gcall
*call
, bool ignore_stores
)
976 attr_fnspec fnspec
= gimple_call_fnspec (call
);
977 if (!fnspec
.known_p ())
979 if (dump_file
&& gimple_call_builtin_p (call
, BUILT_IN_NORMAL
))
980 fprintf (dump_file
, " Builtin with no fnspec: %s\n",
981 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call
))));
984 collapse_loads (cur_summary
, cur_summary_lto
);
989 if (fnspec
.global_memory_read_p ())
990 collapse_loads (cur_summary
, cur_summary_lto
);
993 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
994 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
996 else if (!fnspec
.arg_specified_p (i
)
997 || fnspec
.arg_maybe_read_p (i
))
999 modref_parm_map map
= parm_map_for_arg (call
, i
);
1001 if (map
.parm_index
== -2)
1003 if (map
.parm_index
== -1)
1005 collapse_loads (cur_summary
, cur_summary_lto
);
1009 cur_summary
->loads
->insert (0, 0,
1010 get_access_for_fnspec (call
,
1013 if (cur_summary_lto
)
1014 cur_summary_lto
->loads
->insert (0, 0,
1015 get_access_for_fnspec (call
,
1022 if (fnspec
.global_memory_written_p ())
1023 collapse_stores (cur_summary
, cur_summary_lto
);
1026 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1027 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1029 else if (!fnspec
.arg_specified_p (i
)
1030 || fnspec
.arg_maybe_written_p (i
))
1032 modref_parm_map map
= parm_map_for_arg (call
, i
);
1034 if (map
.parm_index
== -2)
1036 if (map
.parm_index
== -1)
1038 collapse_stores (cur_summary
, cur_summary_lto
);
1042 cur_summary
->stores
->insert (0, 0,
1043 get_access_for_fnspec (call
,
1046 if (cur_summary_lto
)
1047 cur_summary_lto
->stores
->insert (0, 0,
1048 get_access_for_fnspec (call
,
1052 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
1055 cur_summary
->writes_errno
= true;
1056 if (cur_summary_lto
)
1057 cur_summary_lto
->writes_errno
= true;
1063 /* Analyze function call STMT in function F.
1064 Remember recursive calls in RECURSIVE_CALLS. */
1067 analyze_call (modref_summary
*cur_summary
, modref_summary_lto
*cur_summary_lto
,
1068 gcall
*stmt
, vec
<gimple
*> *recursive_calls
)
1070 /* Check flags on the function call. In certain cases, analysis can be
1072 int flags
= gimple_call_flags (stmt
);
1073 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
1077 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1078 "except for args.\n");
1082 /* Pure functions do not affect global memory. Stores by functions which are
1083 noreturn and do not throw can safely be ignored. */
1084 bool ignore_stores
= ignore_stores_p (current_function_decl
, flags
);
1086 /* Next, we try to get the callee's function declaration. The goal is to
1087 merge their summary with ours. */
1088 tree callee
= gimple_call_fndecl (stmt
);
1090 /* Check if this is an indirect call. */
1094 fprintf (dump_file
, gimple_call_internal_p (stmt
)
1095 ? " - Internal call" : " - Indirect call.\n");
1096 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1098 /* We only need to handle internal calls in IPA mode. */
1099 gcc_checking_assert (!cur_summary_lto
);
1101 struct cgraph_node
*callee_node
= cgraph_node::get_create (callee
);
1103 /* If this is a recursive call, the target summary is the same as ours, so
1104 there's nothing to do. */
1105 if (recursive_call_p (current_function_decl
, callee
))
1107 recursive_calls
->safe_push (stmt
);
1109 fprintf (dump_file
, " - Skipping recursive call.\n");
1113 gcc_assert (callee_node
!= NULL
);
1115 /* Get the function symbol and its availability. */
1116 enum availability avail
;
1117 callee_node
= callee_node
->function_symbol (&avail
);
1118 if (avail
<= AVAIL_INTERPOSABLE
)
1121 fprintf (dump_file
, " - Function availability <= AVAIL_INTERPOSABLE.\n");
1122 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1125 /* Get callee's modref summary. As above, if there's no summary, we either
1126 have to give up or, if stores are ignored, we can just purge loads. */
1127 modref_summary
*callee_summary
= optimization_summaries
->get (callee_node
);
1128 if (!callee_summary
)
1131 fprintf (dump_file
, " - No modref summary available for callee.\n");
1132 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1135 merge_call_side_effects (cur_summary
, stmt
, callee_summary
, ignore_stores
,
1141 /* Support analysis in non-lto and lto mode in parallel. */
1145 struct modref_summary
*nolto
;
1146 struct modref_summary_lto
*lto
;
1149 /* Helper for analyze_stmt. */
1152 analyze_load (gimple
*, tree
, tree op
, void *data
)
1154 modref_summary
*summary
= ((summary_ptrs
*)data
)->nolto
;
1155 modref_summary_lto
*summary_lto
= ((summary_ptrs
*)data
)->lto
;
1159 fprintf (dump_file
, " - Analyzing load: ");
1160 print_generic_expr (dump_file
, op
);
1161 fprintf (dump_file
, "\n");
1164 if (!record_access_p (op
))
1168 ao_ref_init (&r
, op
);
1171 record_access (summary
->loads
, &r
);
1173 record_access_lto (summary_lto
->loads
, &r
);
1177 /* Helper for analyze_stmt. */
1180 analyze_store (gimple
*, tree
, tree op
, void *data
)
1182 modref_summary
*summary
= ((summary_ptrs
*)data
)->nolto
;
1183 modref_summary_lto
*summary_lto
= ((summary_ptrs
*)data
)->lto
;
1187 fprintf (dump_file
, " - Analyzing store: ");
1188 print_generic_expr (dump_file
, op
);
1189 fprintf (dump_file
, "\n");
1192 if (!record_access_p (op
))
1196 ao_ref_init (&r
, op
);
1199 record_access (summary
->stores
, &r
);
1201 record_access_lto (summary_lto
->stores
, &r
);
1205 /* Analyze statement STMT of function F.
1206 If IPA is true do not merge in side effects of calls. */
1209 analyze_stmt (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
1210 gimple
*stmt
, bool ipa
, vec
<gimple
*> *recursive_calls
)
1212 /* In general we can not ignore clobbers because they are barriers for code
1213 motion, however after inlining it is safe to do because local optimization
1214 passes do not consider clobbers from other functions.
1215 Similar logic is in ipa-pure-const.c. */
1216 if ((ipa
|| cfun
->after_inlining
) && gimple_clobber_p (stmt
))
1219 struct summary_ptrs sums
= {summary
, summary_lto
};
1221 /* Analyze all loads and stores in STMT. */
1222 walk_stmt_load_store_ops (stmt
, &sums
,
1223 analyze_load
, analyze_store
);
1225 switch (gimple_code (stmt
))
1228 /* If the ASM statement does not read nor write memory, there's nothing
1229 to do. Otherwise just give up. */
1230 if (!gimple_asm_clobbers_memory_p (as_a
<gasm
*> (stmt
)))
1233 fprintf (dump_file
, " - Function contains GIMPLE_ASM statement "
1234 "which clobbers memory.\n");
1237 if (!ipa
|| gimple_call_internal_p (stmt
))
1238 return analyze_call (summary
, summary_lto
,
1239 as_a
<gcall
*> (stmt
), recursive_calls
);
1242 attr_fnspec fnspec
= gimple_call_fnspec (as_a
<gcall
*>(stmt
));
1244 if (fnspec
.known_p ()
1245 && (!fnspec
.global_memory_read_p ()
1246 || !fnspec
.global_memory_written_p ()))
1248 fnspec_summaries
->get_create
1249 (cgraph_node::get (current_function_decl
)->get_edge (stmt
))
1250 ->fnspec
= xstrdup (fnspec
.get_str ());
1252 fprintf (dump_file
, " Recorded fnspec %s\n", fnspec
.get_str ());
1257 /* Nothing to do for other types of statements. */
1262 /* Remove summary of current function because during the function body
1263 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1267 remove_summary (bool lto
, bool nolto
, bool ipa
)
1269 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1271 optimization_summaries
->remove (fnode
);
1275 summaries
->remove (fnode
);
1277 summaries_lto
->remove (fnode
);
1278 remove_modref_edge_summaries (fnode
);
1282 " - modref done with result: not tracked.\n");
1285 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1288 memory_access_to (tree op
, tree ssa_name
)
1290 tree base
= get_base_address (op
);
1293 if (TREE_CODE (base
) != MEM_REF
&& TREE_CODE (base
) != TARGET_MEM_REF
)
1295 return TREE_OPERAND (base
, 0) == ssa_name
;
1298 /* Consider statement val = *arg.
1299 return EAF flags of ARG that can be determined from EAF flags of VAL
1300 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1301 all stores to VAL, i.e. when handling noreturn function. */
1304 deref_flags (int flags
, bool ignore_stores
)
1307 if (flags
& EAF_UNUSED
)
1308 ret
|= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
;
1311 if ((flags
& EAF_NOCLOBBER
) || ignore_stores
)
1312 ret
|= EAF_NOCLOBBER
;
1313 if ((flags
& EAF_NOESCAPE
) || ignore_stores
)
1314 ret
|= EAF_NOESCAPE
;
1321 /* Description of an escape point. */
1325 /* Value escapes to this call. */
1327 /* Argument it escapes to. */
1329 /* Flags already known about the argument (this can save us from recording
1330 esape points if local analysis did good job already). */
1332 /* Does value escape directly or indiretly? */
1336 class modref_lattice
1339 /* EAF flags of the SSA name. */
1341 /* DFS bookkkeeping: we don't do real dataflow yet. */
1345 /* When doing IPA analysis we can not merge in callee escape points;
1346 Only remember them and do the merging at IPA propagation time. */
1347 vec
<escape_point
, va_heap
, vl_ptr
> escape_points
;
1351 bool merge (const modref_lattice
&with
);
1352 bool merge (int flags
);
1353 bool merge_deref (const modref_lattice
&with
, bool ignore_stores
);
1354 bool merge_direct_load ();
1355 bool merge_direct_store ();
1356 bool add_escape_point (gcall
*call
, int arg
, int min_flags
, bool diret
);
1357 void dump (FILE *out
, int indent
= 0) const;
1360 /* Lattices are saved to vectors, so keep them PODs. */
1362 modref_lattice::init ()
1364 flags
= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_UNUSED
;
1369 /* Release memory. */
1371 modref_lattice::release ()
1373 escape_points
.release ();
1376 /* Dump lattice to OUT; indent with INDENT spaces. */
1379 modref_lattice::dump (FILE *out
, int indent
) const
1381 dump_eaf_flags (out
, flags
);
1382 if (escape_points
.length ())
1384 fprintf (out
, "%*sEscapes:\n", indent
, "");
1385 for (unsigned int i
= 0; i
< escape_points
.length (); i
++)
1387 fprintf (out
, "%*s Arg %i (%s) min flags", indent
, "",
1388 escape_points
[i
].arg
,
1389 escape_points
[i
].direct
? "direct" : "indirect");
1390 dump_eaf_flags (out
, flags
, false);
1391 fprintf (out
, " in call ");
1392 print_gimple_stmt (out
, escape_points
[i
].call
, 0);
1397 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1401 modref_lattice::add_escape_point (gcall
*call
, int arg
, int min_flags
,
1407 /* If we already determined flags to be bad enough,
1408 * we do not need to record. */
1409 if ((flags
& min_flags
) == flags
)
1412 FOR_EACH_VEC_ELT (escape_points
, i
, ep
)
1413 if (ep
->call
== call
&& ep
->arg
== arg
&& ep
->direct
== direct
)
1415 if ((ep
->min_flags
& min_flags
) == min_flags
)
1417 ep
->min_flags
&= min_flags
;
1420 /* Give up if max escape points is met. */
1421 if ((int)escape_points
.length () > param_modref_max_escape_points
)
1424 fprintf (dump_file
, "--param modref-max-escape-points limit reached\n");
1428 escape_point new_ep
= {call
, arg
, min_flags
, direct
};
1429 escape_points
.safe_push (new_ep
);
1433 /* Merge in flags from F. */
1435 modref_lattice::merge (int f
)
1437 if ((flags
& f
) != flags
)
1440 /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
1441 in tree-ssa-alias.c). Give up earlier. */
1442 if ((flags
& ~(EAF_DIRECT
| EAF_NOCLOBBER
)) == 0)
1445 escape_points
.release ();
1451 /* Merge in WITH. Return true if anyting changed. */
1454 modref_lattice::merge (const modref_lattice
&with
)
1459 bool changed
= merge (with
.flags
);
1463 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
1464 changed
|= add_escape_point (with
.escape_points
[i
].call
,
1465 with
.escape_points
[i
].arg
,
1466 with
.escape_points
[i
].min_flags
,
1467 with
.escape_points
[i
].direct
);
1471 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1472 stores. Return true if anyting changed. */
1475 modref_lattice::merge_deref (const modref_lattice
&with
, bool ignore_stores
)
1480 bool changed
= merge (deref_flags (with
.flags
, ignore_stores
));
1484 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
1485 changed
|= add_escape_point (with
.escape_points
[i
].call
,
1486 with
.escape_points
[i
].arg
,
1487 with
.escape_points
[i
].min_flags
,
1492 /* Merge in flags for direct load. */
1495 modref_lattice::merge_direct_load ()
1497 return merge (~EAF_UNUSED
);
1500 /* Merge in flags for direct store. */
1503 modref_lattice::merge_direct_store ()
1505 return merge (~(EAF_UNUSED
| EAF_NOCLOBBER
));
1508 } /* ANON namespace. */
1510 static void analyze_ssa_name_flags (tree name
,
1511 vec
<modref_lattice
> &lattice
,
1512 int depth
, bool ipa
);
1514 /* Call statements may return their parameters. Consider argument number
1515 ARG of USE_STMT and determine flags that can needs to be cleared
1516 in case pointer possibly indirectly references from ARG I is returned.
1517 LATTICE, DEPTH and ipa are same as in analyze_ssa_name_flags. */
1520 merge_call_lhs_flags (gcall
*call
, int arg
, int index
, bool deref
,
1521 vec
<modref_lattice
> &lattice
,
1522 int depth
, bool ipa
)
1524 /* If there is no return value, no flags are affected. */
1525 if (!gimple_call_lhs (call
))
1528 /* If we know that function returns given argument and it is not ARG
1529 we can still be happy. */
1530 int flags
= gimple_call_return_flags (call
);
1531 if ((flags
& ERF_RETURNS_ARG
)
1532 && (flags
& ERF_RETURN_ARG_MASK
) != arg
)
1535 /* If return value is SSA name determine its flags. */
1536 if (TREE_CODE (gimple_call_lhs (call
)) == SSA_NAME
)
1538 tree lhs
= gimple_call_lhs (call
);
1539 analyze_ssa_name_flags (lhs
, lattice
, depth
+ 1, ipa
);
1541 lattice
[index
].merge (lattice
[SSA_NAME_VERSION (lhs
)]);
1543 lattice
[index
].merge_deref (lattice
[SSA_NAME_VERSION (lhs
)], false);
1545 /* In the case of memory store we can do nothing. */
1547 lattice
[index
].merge (0);
1550 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
1551 LATTICE is an array of modref_lattices.
1552 DEPTH is a recursion depth used to make debug output prettier.
1553 If IPA is true we analyze for IPA propagation (and thus call escape points
1554 are processed later) */
1557 analyze_ssa_name_flags (tree name
, vec
<modref_lattice
> &lattice
, int depth
,
1560 imm_use_iterator ui
;
1562 int index
= SSA_NAME_VERSION (name
);
1564 /* See if value is already computed. */
1565 if (lattice
[index
].known
)
1567 if (lattice
[index
].open
)
1571 "%*sGiving up on a cycle in SSA graph\n", depth
* 4, "");
1574 if (depth
== param_modref_max_depth
)
1578 "%*sGiving up on max depth\n", depth
* 4, "");
1581 /* Recursion guard. */
1582 lattice
[index
].init ();
1587 "%*sAnalyzing flags of ssa name: ", depth
* 4, "");
1588 print_generic_expr (dump_file
, name
);
1589 fprintf (dump_file
, "\n");
1592 FOR_EACH_IMM_USE_STMT (use_stmt
, ui
, name
)
1594 if (lattice
[index
].flags
== 0)
1596 BREAK_FROM_IMM_USE_STMT (ui
);
1598 if (is_gimple_debug (use_stmt
))
1602 fprintf (dump_file
, "%*s Analyzing stmt:", depth
* 4, "");
1603 print_gimple_stmt (dump_file
, use_stmt
, 0);
1606 /* Gimple return may load the return value.
1607 Returning name counts as an use by tree-ssa-structalias.c */
1608 if (greturn
*ret
= dyn_cast
<greturn
*> (use_stmt
))
1610 if (gimple_return_retval (ret
) == name
)
1611 lattice
[index
].merge (~EAF_UNUSED
);
1612 else if (memory_access_to (gimple_return_retval (ret
), name
))
1613 lattice
[index
].merge_direct_load ();
1615 /* Account for LHS store, arg loads and flags from callee function. */
1616 else if (gcall
*call
= dyn_cast
<gcall
*> (use_stmt
))
1618 tree callee
= gimple_call_fndecl (call
);
1620 /* Recursion would require bit of propagation; give up for now. */
1621 if (callee
&& !ipa
&& recursive_call_p (current_function_decl
,
1623 lattice
[index
].merge (0);
1626 int ecf_flags
= gimple_call_flags (call
);
1627 bool ignore_stores
= ignore_stores_p (current_function_decl
,
1629 bool ignore_retval
= ignore_retval_p (current_function_decl
,
1632 /* Handle *name = func (...). */
1633 if (gimple_call_lhs (call
)
1634 && memory_access_to (gimple_call_lhs (call
), name
))
1635 lattice
[index
].merge_direct_store ();
1637 /* We do not track accesses to the static chain (we could)
1639 if (gimple_call_chain (call
)
1640 && (gimple_call_chain (call
) == name
))
1641 lattice
[index
].merge (0);
1643 /* Process internal functions and right away. */
1644 bool record_ipa
= ipa
&& !gimple_call_internal_p (call
);
1646 /* Handle all function parameters. */
1647 for (unsigned i
= 0;
1648 i
< gimple_call_num_args (call
) && lattice
[index
].flags
; i
++)
1649 /* Name is directly passed to the callee. */
1650 if (gimple_call_arg (call
, i
) == name
)
1652 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
1654 int call_flags
= gimple_call_arg_flags (call
, i
);
1656 call_flags
|= EAF_NOCLOBBER
| EAF_NOESCAPE
;
1659 lattice
[index
].merge (call_flags
);
1661 lattice
[index
].add_escape_point (call
, i
,
1665 merge_call_lhs_flags (call
, i
, index
, false,
1666 lattice
, depth
, ipa
);
1668 /* Name is dereferenced and passed to a callee. */
1669 else if (memory_access_to (gimple_call_arg (call
, i
), name
))
1671 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
1672 lattice
[index
].merge_direct_load ();
1675 int call_flags
= deref_flags
1676 (gimple_call_arg_flags (call
, i
), ignore_stores
);
1678 lattice
[index
].merge (call_flags
);
1680 lattice
[index
].add_escape_point (call
, i
,
1684 merge_call_lhs_flags (call
, i
, index
, true,
1685 lattice
, depth
, ipa
);
1689 else if (gimple_assign_load_p (use_stmt
))
1691 gassign
*assign
= as_a
<gassign
*> (use_stmt
);
1692 /* Memory to memory copy. */
1693 if (gimple_store_p (assign
))
1695 /* Handle *lhs = *name.
1697 We do not track memory locations, so assume that value
1698 is used arbitrarily. */
1699 if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
1700 lattice
[index
].merge (0);
1701 /* Handle *name = *exp. */
1702 else if (memory_access_to (gimple_assign_lhs (assign
), name
))
1703 lattice
[index
].merge_direct_store ();
1705 /* Handle lhs = *name. */
1706 else if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
1708 tree lhs
= gimple_assign_lhs (assign
);
1709 analyze_ssa_name_flags (lhs
, lattice
, depth
+ 1, ipa
);
1710 lattice
[index
].merge_deref (lattice
[SSA_NAME_VERSION (lhs
)],
1714 else if (gimple_store_p (use_stmt
))
1716 gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
);
1718 /* Handle *lhs = name. */
1719 if (assign
&& gimple_assign_rhs1 (assign
) == name
)
1722 fprintf (dump_file
, "%*s ssa name saved to memory\n",
1724 lattice
[index
].merge (0);
1726 /* Handle *name = exp. */
1728 && memory_access_to (gimple_assign_lhs (assign
), name
))
1730 /* In general we can not ignore clobbers because they are
1731 barriers for code motion, however after inlining it is safe to
1732 do because local optimization passes do not consider clobbers
1733 from other functions. Similar logic is in ipa-pure-const.c. */
1734 if (!cfun
->after_inlining
|| !gimple_clobber_p (assign
))
1735 lattice
[index
].merge_direct_store ();
1737 /* ASM statements etc. */
1741 fprintf (dump_file
, "%*s Unhandled store\n",
1743 lattice
[index
].merge (0);
1746 else if (gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
))
1748 enum tree_code code
= gimple_assign_rhs_code (assign
);
1750 /* See if operation is a merge as considered by
1751 tree-ssa-structalias.c:find_func_aliases. */
1752 if (!truth_value_p (code
)
1753 && code
!= POINTER_DIFF_EXPR
1754 && (code
!= POINTER_PLUS_EXPR
1755 || gimple_assign_rhs1 (assign
) == name
))
1757 tree lhs
= gimple_assign_lhs (assign
);
1758 analyze_ssa_name_flags (lhs
, lattice
, depth
+ 1, ipa
);
1759 lattice
[index
].merge (lattice
[SSA_NAME_VERSION (lhs
)]);
1762 else if (gphi
*phi
= dyn_cast
<gphi
*> (use_stmt
))
1764 tree result
= gimple_phi_result (phi
);
1765 analyze_ssa_name_flags (result
, lattice
, depth
+ 1, ipa
);
1766 lattice
[index
].merge (lattice
[SSA_NAME_VERSION (result
)]);
1768 /* Conditions are not considered escape points
1769 by tree-ssa-structalias. */
1770 else if (gimple_code (use_stmt
) == GIMPLE_COND
)
1775 fprintf (dump_file
, "%*s Unhandled stmt\n", depth
* 4, "");
1776 lattice
[index
].merge (0);
1781 fprintf (dump_file
, "%*s current flags of ", depth
* 4, "");
1782 print_generic_expr (dump_file
, name
);
1783 lattice
[index
].dump (dump_file
, depth
* 4 + 4);
1788 fprintf (dump_file
, "%*sflags of ssa name ", depth
* 4, "");
1789 print_generic_expr (dump_file
, name
);
1790 lattice
[index
].dump (dump_file
, depth
* 4 + 2);
1792 lattice
[index
].open
= false;
1793 lattice
[index
].known
= true;
1796 /* Determine EAF flags for function parameters. */
1799 analyze_parms (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
1802 unsigned int parm_index
= 0;
1803 unsigned int count
= 0;
1804 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
1806 /* For const functions we have nothing to gain by EAF flags. */
1807 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
1810 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
1811 parm
= TREE_CHAIN (parm
))
1817 auto_vec
<modref_lattice
> lattice
;
1818 lattice
.safe_grow_cleared (num_ssa_names
, true);
1820 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
; parm_index
++,
1821 parm
= TREE_CHAIN (parm
))
1823 tree name
= ssa_default_def (cfun
, parm
);
1826 analyze_ssa_name_flags (name
, lattice
, 0, ipa
);
1827 int flags
= lattice
[SSA_NAME_VERSION (name
)].flags
;
1829 /* For pure functions we have implicit NOCLOBBER
1831 if (ecf_flags
& ECF_PURE
)
1832 flags
&= ~(EAF_NOCLOBBER
| EAF_NOESCAPE
);
1838 if (parm_index
>= summary
->arg_flags
.length ())
1839 summary
->arg_flags
.safe_grow_cleared (count
, true);
1840 summary
->arg_flags
[parm_index
] = flags
;
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
] = flags
;
1848 if (lattice
[SSA_NAME_VERSION (name
)].escape_points
.length ())
1852 cgraph_node
*node
= cgraph_node::get (current_function_decl
);
1854 gcc_checking_assert (ipa
);
1856 (lattice
[SSA_NAME_VERSION (name
)].escape_points
, ip
, ep
)
1857 if ((ep
->min_flags
& flags
) != flags
)
1859 cgraph_edge
*e
= node
->get_edge (ep
->call
);
1860 struct escape_entry ee
= {parm_index
, ep
->arg
,
1861 ep
->min_flags
, ep
->direct
};
1863 escape_summaries
->get_create (e
)->esc
.safe_push (ee
);
1869 for (unsigned int i
= 0; i
< num_ssa_names
; i
++)
1870 lattice
[i
].release ();
1873 /* Analyze function F. IPA indicates whether we're running in local mode
1874 (false) or the IPA mode (true). */
1877 analyze_function (function
*f
, bool ipa
)
1880 fprintf (dump_file
, "modref analyzing '%s' (ipa=%i)%s%s\n",
1881 function_name (f
), ipa
,
1882 TREE_READONLY (current_function_decl
) ? " (const)" : "",
1883 DECL_PURE_P (current_function_decl
) ? " (pure)" : "");
1885 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
1886 if (!flag_ipa_modref
)
1889 /* Compute no-LTO summaries when local optimization is going to happen. */
1890 bool nolto
= (!ipa
|| ((!flag_lto
|| flag_fat_lto_objects
) && !in_lto_p
)
1891 || (in_lto_p
&& !flag_wpa
1892 && flag_incremental_link
!= INCREMENTAL_LINK_LTO
));
1893 /* Compute LTO when LTO streaming is going to happen. */
1894 bool lto
= ipa
&& ((flag_lto
&& !in_lto_p
)
1896 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
1897 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1899 modref_summary
*summary
= NULL
;
1900 modref_summary_lto
*summary_lto
= NULL
;
1902 /* Initialize the summary.
1903 If we run in local mode there is possibly pre-existing summary from
1904 IPA pass. Dump it so it is easy to compare if mod-ref info has
1908 if (!optimization_summaries
)
1909 optimization_summaries
= modref_summaries::create_ggc (symtab
);
1910 else /* Remove existing summary if we are re-running the pass. */
1914 = optimization_summaries
->get (cgraph_node::get (f
->decl
)))
1918 fprintf (dump_file
, "Past summary:\n");
1919 optimization_summaries
->get
1920 (cgraph_node::get (f
->decl
))->dump (dump_file
);
1922 optimization_summaries
->remove (cgraph_node::get (f
->decl
));
1924 summary
= optimization_summaries
->get_create (cgraph_node::get (f
->decl
));
1925 gcc_checking_assert (nolto
&& !lto
);
1927 /* In IPA mode we analyze every function precisely once. Assert that. */
1933 summaries
= modref_summaries::create_ggc (symtab
);
1935 summaries
->remove (cgraph_node::get (f
->decl
));
1936 summary
= summaries
->get_create (cgraph_node::get (f
->decl
));
1941 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
1943 summaries_lto
->remove (cgraph_node::get (f
->decl
));
1944 summary_lto
= summaries_lto
->get_create (cgraph_node::get (f
->decl
));
1946 if (!fnspec_summaries
)
1947 fnspec_summaries
= new fnspec_summaries_t (symtab
);
1948 if (!escape_summaries
)
1949 escape_summaries
= new escape_summaries_t (symtab
);
1953 /* Create and initialize summary for F.
1954 Note that summaries may be already allocated from previous
1958 gcc_assert (!summary
->loads
);
1959 summary
->loads
= modref_records::create_ggc (param_modref_max_bases
,
1960 param_modref_max_refs
,
1961 param_modref_max_accesses
);
1962 gcc_assert (!summary
->stores
);
1963 summary
->stores
= modref_records::create_ggc (param_modref_max_bases
,
1964 param_modref_max_refs
,
1965 param_modref_max_accesses
);
1966 summary
->writes_errno
= false;
1970 gcc_assert (!summary_lto
->loads
);
1971 summary_lto
->loads
= modref_records_lto::create_ggc
1972 (param_modref_max_bases
,
1973 param_modref_max_refs
,
1974 param_modref_max_accesses
);
1975 gcc_assert (!summary_lto
->stores
);
1976 summary_lto
->stores
= modref_records_lto::create_ggc
1977 (param_modref_max_bases
,
1978 param_modref_max_refs
,
1979 param_modref_max_accesses
);
1980 summary_lto
->writes_errno
= false;
1983 analyze_parms (summary
, summary_lto
, ipa
);
1985 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
1986 auto_vec
<gimple
*, 32> recursive_calls
;
1988 /* Analyze each statement in each basic block of the function. If the
1989 statement cannot be analyzed (for any reason), the entire function cannot
1990 be analyzed by modref. */
1992 FOR_EACH_BB_FN (bb
, f
)
1994 gimple_stmt_iterator si
;
1995 for (si
= gsi_after_labels (bb
); !gsi_end_p (si
); gsi_next (&si
))
1997 if (!analyze_stmt (summary
, summary_lto
,
1998 gsi_stmt (si
), ipa
, &recursive_calls
)
1999 || ((!summary
|| !summary
->useful_p (ecf_flags
, false))
2001 || !summary_lto
->useful_p (ecf_flags
, false))))
2003 collapse_loads (summary
, summary_lto
);
2004 collapse_stores (summary
, summary_lto
);
2010 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2011 This needs to be done after all other side effects are computed. */
2014 bool changed
= true;
2018 for (unsigned i
= 0; i
< recursive_calls
.length (); i
++)
2020 changed
|= merge_call_side_effects
2021 (summary
, recursive_calls
[i
], summary
,
2022 ignore_stores_p (current_function_decl
,
2024 (recursive_calls
[i
])),
2026 if (!summary
->useful_p (ecf_flags
, false))
2028 remove_summary (lto
, nolto
, ipa
);
2034 if (summary
&& !summary
->useful_p (ecf_flags
))
2037 optimization_summaries
->remove (fnode
);
2039 summaries
->remove (fnode
);
2042 if (summary_lto
&& !summary_lto
->useful_p (ecf_flags
))
2044 summaries_lto
->remove (fnode
);
2047 if (ipa
&& !summary
&& !summary_lto
)
2048 remove_modref_edge_summaries (fnode
);
2052 fprintf (dump_file
, " - modref done with result: tracked.\n");
2054 summary
->dump (dump_file
);
2056 summary_lto
->dump (dump_file
);
2057 dump_modref_edge_summaries (dump_file
, fnode
, 2);
2061 /* Callback for generate_summary. */
2064 modref_generate (void)
2066 struct cgraph_node
*node
;
2067 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
2069 function
*f
= DECL_STRUCT_FUNCTION (node
->decl
);
2073 analyze_function (f
, true);
2078 /* Called when a new function is inserted to callgraph late. */
2081 modref_summaries::insert (struct cgraph_node
*node
, modref_summary
*)
2083 /* Local passes ought to be executed by the pass manager. */
2084 if (this == optimization_summaries
)
2086 optimization_summaries
->remove (node
);
2089 if (!DECL_STRUCT_FUNCTION (node
->decl
)
2090 || !opt_for_fn (node
->decl
, flag_ipa_modref
))
2092 summaries
->remove (node
);
2095 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
2096 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
2100 /* Called when a new function is inserted to callgraph late. */
2103 modref_summaries_lto::insert (struct cgraph_node
*node
, modref_summary_lto
*)
2105 /* We do not support adding new function when IPA information is already
2106 propagated. This is done only by SIMD cloning that is not very
2108 if (!DECL_STRUCT_FUNCTION (node
->decl
)
2109 || !opt_for_fn (node
->decl
, flag_ipa_modref
)
2112 summaries_lto
->remove (node
);
2115 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
2116 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
2120 /* Called when new clone is inserted to callgraph late. */
2123 modref_summaries::duplicate (cgraph_node
*, cgraph_node
*dst
,
2124 modref_summary
*src_data
,
2125 modref_summary
*dst_data
)
2127 /* Do not duplicate optimization summaries; we do not handle parameter
2128 transforms on them. */
2129 if (this == optimization_summaries
)
2131 optimization_summaries
->remove (dst
);
2134 dst_data
->stores
= modref_records::create_ggc
2135 (src_data
->stores
->max_bases
,
2136 src_data
->stores
->max_refs
,
2137 src_data
->stores
->max_accesses
);
2138 dst_data
->stores
->copy_from (src_data
->stores
);
2139 dst_data
->loads
= modref_records::create_ggc
2140 (src_data
->loads
->max_bases
,
2141 src_data
->loads
->max_refs
,
2142 src_data
->loads
->max_accesses
);
2143 dst_data
->loads
->copy_from (src_data
->loads
);
2144 dst_data
->writes_errno
= src_data
->writes_errno
;
2147 /* Called when new clone is inserted to callgraph late. */
2150 modref_summaries_lto::duplicate (cgraph_node
*, cgraph_node
*,
2151 modref_summary_lto
*src_data
,
2152 modref_summary_lto
*dst_data
)
2154 /* Be sure that no further cloning happens after ipa-modref. If it does
2155 we will need to update signatures for possible param changes. */
2156 gcc_checking_assert (!((modref_summaries_lto
*)summaries_lto
)->propagated
);
2157 dst_data
->stores
= modref_records_lto::create_ggc
2158 (src_data
->stores
->max_bases
,
2159 src_data
->stores
->max_refs
,
2160 src_data
->stores
->max_accesses
);
2161 dst_data
->stores
->copy_from (src_data
->stores
);
2162 dst_data
->loads
= modref_records_lto::create_ggc
2163 (src_data
->loads
->max_bases
,
2164 src_data
->loads
->max_refs
,
2165 src_data
->loads
->max_accesses
);
2166 dst_data
->loads
->copy_from (src_data
->loads
);
2167 dst_data
->writes_errno
= src_data
->writes_errno
;
2172 /* Definition of the modref pass on GIMPLE. */
2173 const pass_data pass_data_modref
= {
2178 (PROP_cfg
| PROP_ssa
),
2185 class pass_modref
: public gimple_opt_pass
2188 pass_modref (gcc::context
*ctxt
)
2189 : gimple_opt_pass (pass_data_modref
, ctxt
) {}
2191 /* opt_pass methods: */
2194 return new pass_modref (m_ctxt
);
2196 virtual bool gate (function
*)
2198 return flag_ipa_modref
;
2200 virtual unsigned int execute (function
*);
2203 /* Encode TT to the output block OB using the summary streaming API. */
2206 write_modref_records (modref_records_lto
*tt
, struct output_block
*ob
)
2208 streamer_write_uhwi (ob
, tt
->max_bases
);
2209 streamer_write_uhwi (ob
, tt
->max_refs
);
2210 streamer_write_uhwi (ob
, tt
->max_accesses
);
2212 streamer_write_uhwi (ob
, tt
->every_base
);
2213 streamer_write_uhwi (ob
, vec_safe_length (tt
->bases
));
2215 modref_base_node
<tree
> *base_node
;
2216 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, base_node
)
2218 stream_write_tree (ob
, base_node
->base
, true);
2220 streamer_write_uhwi (ob
, base_node
->every_ref
);
2221 streamer_write_uhwi (ob
, vec_safe_length (base_node
->refs
));
2224 modref_ref_node
<tree
> *ref_node
;
2225 FOR_EACH_VEC_SAFE_ELT (base_node
->refs
, j
, ref_node
)
2227 stream_write_tree (ob
, ref_node
->ref
, true);
2228 streamer_write_uhwi (ob
, ref_node
->every_access
);
2229 streamer_write_uhwi (ob
, vec_safe_length (ref_node
->accesses
));
2232 modref_access_node
*access_node
;
2233 FOR_EACH_VEC_SAFE_ELT (ref_node
->accesses
, k
, access_node
)
2235 streamer_write_hwi (ob
, access_node
->parm_index
);
2236 if (access_node
->parm_index
!= -1)
2238 streamer_write_uhwi (ob
, access_node
->parm_offset_known
);
2239 if (access_node
->parm_offset_known
)
2241 streamer_write_poly_int64 (ob
, access_node
->parm_offset
);
2242 streamer_write_poly_int64 (ob
, access_node
->offset
);
2243 streamer_write_poly_int64 (ob
, access_node
->size
);
2244 streamer_write_poly_int64 (ob
, access_node
->max_size
);
2252 /* Read a modref_tree from the input block IB using the data from DATA_IN.
2253 This assumes that the tree was encoded using write_modref_tree.
2254 Either nolto_ret or lto_ret is initialized by the tree depending whether
2255 LTO streaming is expected or not. */
2258 read_modref_records (lto_input_block
*ib
, struct data_in
*data_in
,
2259 modref_records
**nolto_ret
,
2260 modref_records_lto
**lto_ret
)
2262 size_t max_bases
= streamer_read_uhwi (ib
);
2263 size_t max_refs
= streamer_read_uhwi (ib
);
2264 size_t max_accesses
= streamer_read_uhwi (ib
);
2267 *lto_ret
= modref_records_lto::create_ggc (max_bases
, max_refs
,
2270 *nolto_ret
= modref_records::create_ggc (max_bases
, max_refs
,
2272 gcc_checking_assert (lto_ret
|| nolto_ret
);
2274 size_t every_base
= streamer_read_uhwi (ib
);
2275 size_t nbase
= streamer_read_uhwi (ib
);
2277 gcc_assert (!every_base
|| nbase
== 0);
2281 (*nolto_ret
)->collapse ();
2283 (*lto_ret
)->collapse ();
2285 for (size_t i
= 0; i
< nbase
; i
++)
2287 tree base_tree
= stream_read_tree (ib
, data_in
);
2288 modref_base_node
<alias_set_type
> *nolto_base_node
= NULL
;
2289 modref_base_node
<tree
> *lto_base_node
= NULL
;
2291 /* At stream in time we have LTO alias info. Check if we streamed in
2292 something obviously unnecessary. Do not glob types by alias sets;
2293 it is not 100% clear that ltrans types will get merged same way.
2294 Types may get refined based on ODR type conflicts. */
2295 if (base_tree
&& !get_alias_set (base_tree
))
2299 fprintf (dump_file
, "Streamed in alias set 0 type ");
2300 print_generic_expr (dump_file
, base_tree
);
2301 fprintf (dump_file
, "\n");
2307 nolto_base_node
= (*nolto_ret
)->insert_base (base_tree
2308 ? get_alias_set (base_tree
)
2311 lto_base_node
= (*lto_ret
)->insert_base (base_tree
);
2312 size_t every_ref
= streamer_read_uhwi (ib
);
2313 size_t nref
= streamer_read_uhwi (ib
);
2315 gcc_assert (!every_ref
|| nref
== 0);
2318 if (nolto_base_node
)
2319 nolto_base_node
->collapse ();
2321 lto_base_node
->collapse ();
2323 for (size_t j
= 0; j
< nref
; j
++)
2325 tree ref_tree
= stream_read_tree (ib
, data_in
);
2327 if (ref_tree
&& !get_alias_set (ref_tree
))
2331 fprintf (dump_file
, "Streamed in alias set 0 type ");
2332 print_generic_expr (dump_file
, ref_tree
);
2333 fprintf (dump_file
, "\n");
2338 modref_ref_node
<alias_set_type
> *nolto_ref_node
= NULL
;
2339 modref_ref_node
<tree
> *lto_ref_node
= NULL
;
2341 if (nolto_base_node
)
2343 = nolto_base_node
->insert_ref (ref_tree
2344 ? get_alias_set (ref_tree
) : 0,
2347 lto_ref_node
= lto_base_node
->insert_ref (ref_tree
, max_refs
);
2349 size_t every_access
= streamer_read_uhwi (ib
);
2350 size_t naccesses
= streamer_read_uhwi (ib
);
2353 nolto_ref_node
->every_access
= every_access
;
2355 lto_ref_node
->every_access
= every_access
;
2357 for (size_t k
= 0; k
< naccesses
; k
++)
2359 int parm_index
= streamer_read_hwi (ib
);
2360 bool parm_offset_known
= false;
2361 poly_int64 parm_offset
= 0;
2362 poly_int64 offset
= 0;
2363 poly_int64 size
= -1;
2364 poly_int64 max_size
= -1;
2366 if (parm_index
!= -1)
2368 parm_offset_known
= streamer_read_uhwi (ib
);
2369 if (parm_offset_known
)
2371 parm_offset
= streamer_read_poly_int64 (ib
);
2372 offset
= streamer_read_poly_int64 (ib
);
2373 size
= streamer_read_poly_int64 (ib
);
2374 max_size
= streamer_read_poly_int64 (ib
);
2377 modref_access_node a
= {offset
, size
, max_size
, parm_offset
,
2378 parm_index
, parm_offset_known
};
2380 nolto_ref_node
->insert_access (a
, max_accesses
);
2382 lto_ref_node
->insert_access (a
, max_accesses
);
2387 (*lto_ret
)->cleanup ();
2389 (*nolto_ret
)->cleanup ();
2392 /* Write ESUM to BP. */
2395 modref_write_escape_summary (struct bitpack_d
*bp
, escape_summary
*esum
)
2399 bp_pack_var_len_unsigned (bp
, 0);
2402 bp_pack_var_len_unsigned (bp
, esum
->esc
.length ());
2405 FOR_EACH_VEC_ELT (esum
->esc
, i
, ee
)
2407 bp_pack_var_len_unsigned (bp
, ee
->parm_index
);
2408 bp_pack_var_len_unsigned (bp
, ee
->arg
);
2409 bp_pack_var_len_unsigned (bp
, ee
->min_flags
);
2410 bp_pack_value (bp
, ee
->direct
, 1);
2414 /* Read escape summary for E from BP. */
2417 modref_read_escape_summary (struct bitpack_d
*bp
, cgraph_edge
*e
)
2419 unsigned int n
= bp_unpack_var_len_unsigned (bp
);
2422 escape_summary
*esum
= escape_summaries
->get_create (e
);
2423 esum
->esc
.reserve_exact (n
);
2424 for (unsigned int i
= 0; i
< n
; i
++)
2427 ee
.parm_index
= bp_unpack_var_len_unsigned (bp
);
2428 ee
.arg
= bp_unpack_var_len_unsigned (bp
);
2429 ee
.min_flags
= bp_unpack_var_len_unsigned (bp
);
2430 ee
.direct
= bp_unpack_value (bp
, 1);
2431 esum
->esc
.quick_push (ee
);
2435 /* Callback for write_summary. */
2440 struct output_block
*ob
= create_output_block (LTO_section_ipa_modref
);
2441 lto_symtab_encoder_t encoder
= ob
->decl_state
->symtab_node_encoder
;
2442 unsigned int count
= 0;
2447 streamer_write_uhwi (ob
, 0);
2448 streamer_write_char_stream (ob
->main_stream
, 0);
2449 produce_asm (ob
, NULL
);
2450 destroy_output_block (ob
);
2454 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
2456 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
2457 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
2458 modref_summary_lto
*r
;
2460 if (cnode
&& cnode
->definition
&& !cnode
->alias
2461 && (r
= summaries_lto
->get (cnode
))
2462 && r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
2465 streamer_write_uhwi (ob
, count
);
2467 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
2469 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
2470 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
2472 if (cnode
&& cnode
->definition
&& !cnode
->alias
)
2474 modref_summary_lto
*r
= summaries_lto
->get (cnode
);
2476 if (!r
|| !r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
2479 streamer_write_uhwi (ob
, lto_symtab_encoder_encode (encoder
, cnode
));
2481 streamer_write_uhwi (ob
, r
->arg_flags
.length ());
2482 for (unsigned int i
= 0; i
< r
->arg_flags
.length (); i
++)
2483 streamer_write_char_stream (ob
->main_stream
, r
->arg_flags
[i
]);
2485 write_modref_records (r
->loads
, ob
);
2486 write_modref_records (r
->stores
, ob
);
2488 struct bitpack_d bp
= bitpack_create (ob
->main_stream
);
2489 bp_pack_value (&bp
, r
->writes_errno
, 1);
2492 for (cgraph_edge
*e
= cnode
->indirect_calls
;
2493 e
; e
= e
->next_callee
)
2495 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
2496 bp_pack_value (&bp
, sum
!= NULL
, 1);
2498 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
2499 class escape_summary
*esum
= escape_summaries
->get (e
);
2500 modref_write_escape_summary (&bp
,esum
);
2502 for (cgraph_edge
*e
= cnode
->callees
; e
; e
= e
->next_callee
)
2504 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
2505 bp_pack_value (&bp
, sum
!= NULL
, 1);
2507 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
2508 class escape_summary
*esum
= escape_summaries
->get (e
);
2509 modref_write_escape_summary (&bp
,esum
);
2512 streamer_write_bitpack (&bp
);
2515 streamer_write_char_stream (ob
->main_stream
, 0);
2516 produce_asm (ob
, NULL
);
2517 destroy_output_block (ob
);
2521 read_section (struct lto_file_decl_data
*file_data
, const char *data
,
2524 const struct lto_function_header
*header
2525 = (const struct lto_function_header
*) data
;
2526 const int cfg_offset
= sizeof (struct lto_function_header
);
2527 const int main_offset
= cfg_offset
+ header
->cfg_size
;
2528 const int string_offset
= main_offset
+ header
->main_size
;
2529 struct data_in
*data_in
;
2531 unsigned int f_count
;
2533 lto_input_block
ib ((const char *) data
+ main_offset
, header
->main_size
,
2534 file_data
->mode_table
);
2537 = lto_data_in_create (file_data
, (const char *) data
+ string_offset
,
2538 header
->string_size
, vNULL
);
2539 f_count
= streamer_read_uhwi (&ib
);
2540 for (i
= 0; i
< f_count
; i
++)
2542 struct cgraph_node
*node
;
2543 lto_symtab_encoder_t encoder
;
2545 unsigned int index
= streamer_read_uhwi (&ib
);
2546 encoder
= file_data
->symtab_node_encoder
;
2547 node
= dyn_cast
<cgraph_node
*> (lto_symtab_encoder_deref (encoder
,
2550 modref_summary
*modref_sum
= summaries
2551 ? summaries
->get_create (node
) : NULL
;
2552 modref_summary_lto
*modref_sum_lto
= summaries_lto
2553 ? summaries_lto
->get_create (node
)
2555 if (optimization_summaries
)
2556 modref_sum
= optimization_summaries
->get_create (node
);
2559 modref_sum
->writes_errno
= false;
2561 modref_sum_lto
->writes_errno
= false;
2563 gcc_assert (!modref_sum
|| (!modref_sum
->loads
2564 && !modref_sum
->stores
));
2565 gcc_assert (!modref_sum_lto
|| (!modref_sum_lto
->loads
2566 && !modref_sum_lto
->stores
));
2567 unsigned int args
= streamer_read_uhwi (&ib
);
2568 if (args
&& modref_sum
)
2569 modref_sum
->arg_flags
.reserve_exact (args
);
2570 if (args
&& modref_sum_lto
)
2571 modref_sum_lto
->arg_flags
.reserve_exact (args
);
2572 for (unsigned int i
= 0; i
< args
; i
++)
2574 unsigned char flags
= streamer_read_uchar (&ib
);
2576 modref_sum
->arg_flags
.quick_push (flags
);
2578 modref_sum_lto
->arg_flags
.quick_push (flags
);
2580 read_modref_records (&ib
, data_in
,
2581 modref_sum
? &modref_sum
->loads
: NULL
,
2582 modref_sum_lto
? &modref_sum_lto
->loads
: NULL
);
2583 read_modref_records (&ib
, data_in
,
2584 modref_sum
? &modref_sum
->stores
: NULL
,
2585 modref_sum_lto
? &modref_sum_lto
->stores
: NULL
);
2586 struct bitpack_d bp
= streamer_read_bitpack (&ib
);
2587 if (bp_unpack_value (&bp
, 1))
2590 modref_sum
->writes_errno
= true;
2592 modref_sum_lto
->writes_errno
= true;
2596 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
2598 if (bp_unpack_value (&bp
, 1))
2600 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
2601 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
2603 modref_read_escape_summary (&bp
, e
);
2605 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
2607 if (bp_unpack_value (&bp
, 1))
2609 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
2610 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
2612 modref_read_escape_summary (&bp
, e
);
2617 fprintf (dump_file
, "Read modref for %s\n",
2618 node
->dump_name ());
2620 modref_sum
->dump (dump_file
);
2622 modref_sum_lto
->dump (dump_file
);
2623 dump_modref_edge_summaries (dump_file
, node
, 4);
2627 lto_free_section_data (file_data
, LTO_section_ipa_modref
, NULL
, data
,
2629 lto_data_in_delete (data_in
);
2632 /* Callback for read_summary. */
2637 struct lto_file_decl_data
**file_data_vec
= lto_get_file_decl_data ();
2638 struct lto_file_decl_data
*file_data
;
2641 gcc_checking_assert (!optimization_summaries
&& !summaries
&& !summaries_lto
);
2643 optimization_summaries
= modref_summaries::create_ggc (symtab
);
2646 if (flag_wpa
|| flag_incremental_link
== INCREMENTAL_LINK_LTO
)
2647 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
2649 || (flag_incremental_link
== INCREMENTAL_LINK_LTO
2650 && flag_fat_lto_objects
))
2651 summaries
= modref_summaries::create_ggc (symtab
);
2652 if (!fnspec_summaries
)
2653 fnspec_summaries
= new fnspec_summaries_t (symtab
);
2654 if (!escape_summaries
)
2655 escape_summaries
= new escape_summaries_t (symtab
);
2658 while ((file_data
= file_data_vec
[j
++]))
2661 const char *data
= lto_get_summary_section_data (file_data
,
2662 LTO_section_ipa_modref
,
2665 read_section (file_data
, data
, len
);
2667 /* Fatal error here. We do not want to support compiling ltrans units
2668 with different version of compiler or different flags than the WPA
2669 unit, so this should never happen. */
2670 fatal_error (input_location
,
2671 "IPA modref summary is missing in input file");
2675 /* Recompute arg_flags for param adjustments in INFO. */
2678 remap_arg_flags (auto_vec
<unsigned char> &arg_flags
, clone_info
*info
)
2680 auto_vec
<unsigned char> old
= arg_flags
.copy ();
2683 ipa_adjusted_param
*p
;
2685 arg_flags
.release ();
2687 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2689 int o
= info
->param_adjustments
->get_original_index (i
);
2690 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
2694 arg_flags
.safe_grow_cleared (max
+ 1, true);
2695 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2697 int o
= info
->param_adjustments
->get_original_index (i
);
2698 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
2699 arg_flags
[i
] = old
[o
];
2703 /* If signature changed, update the summary. */
2706 update_signature (struct cgraph_node
*node
)
2708 clone_info
*info
= clone_info::get (node
);
2709 if (!info
|| !info
->param_adjustments
)
2712 modref_summary
*r
= optimization_summaries
2713 ? optimization_summaries
->get (node
) : NULL
;
2714 modref_summary_lto
*r_lto
= summaries_lto
2715 ? summaries_lto
->get (node
) : NULL
;
2720 fprintf (dump_file
, "Updating summary for %s from:\n",
2721 node
->dump_name ());
2723 r
->dump (dump_file
);
2725 r_lto
->dump (dump_file
);
2729 ipa_adjusted_param
*p
;
2731 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2733 int idx
= info
->param_adjustments
->get_original_index (i
);
2738 auto_vec
<int, 32> map
;
2740 map
.reserve (max
+ 1);
2741 for (i
= 0; i
<= max
; i
++)
2742 map
.quick_push (-1);
2743 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2745 int idx
= info
->param_adjustments
->get_original_index (i
);
2751 r
->loads
->remap_params (&map
);
2752 r
->stores
->remap_params (&map
);
2753 if (r
->arg_flags
.length ())
2754 remap_arg_flags (r
->arg_flags
, info
);
2758 r_lto
->loads
->remap_params (&map
);
2759 r_lto
->stores
->remap_params (&map
);
2760 if (r_lto
->arg_flags
.length ())
2761 remap_arg_flags (r_lto
->arg_flags
, info
);
2765 fprintf (dump_file
, "to:\n");
2767 r
->dump (dump_file
);
2769 r_lto
->dump (dump_file
);
2774 /* Definition of the modref IPA pass. */
2775 const pass_data pass_data_ipa_modref
=
2777 IPA_PASS
, /* type */
2778 "modref", /* name */
2779 OPTGROUP_IPA
, /* optinfo_flags */
2780 TV_IPA_MODREF
, /* tv_id */
2781 0, /* properties_required */
2782 0, /* properties_provided */
2783 0, /* properties_destroyed */
2784 0, /* todo_flags_start */
2785 ( TODO_dump_symtab
), /* todo_flags_finish */
2788 class pass_ipa_modref
: public ipa_opt_pass_d
2791 pass_ipa_modref (gcc::context
*ctxt
)
2792 : ipa_opt_pass_d (pass_data_ipa_modref
, ctxt
,
2793 modref_generate
, /* generate_summary */
2794 modref_write
, /* write_summary */
2795 modref_read
, /* read_summary */
2796 modref_write
, /* write_optimization_summary */
2797 modref_read
, /* read_optimization_summary */
2798 NULL
, /* stmt_fixup */
2799 0, /* function_transform_todo_flags_start */
2800 NULL
, /* function_transform */
2801 NULL
) /* variable_transform */
2804 /* opt_pass methods: */
2805 opt_pass
*clone () { return new pass_ipa_modref (m_ctxt
); }
2806 virtual bool gate (function
*)
2810 virtual unsigned int execute (function
*);
2816 unsigned int pass_modref::execute (function
*f
)
2818 analyze_function (f
, false);
2823 make_pass_modref (gcc::context
*ctxt
)
2825 return new pass_modref (ctxt
);
2829 make_pass_ipa_modref (gcc::context
*ctxt
)
2831 return new pass_ipa_modref (ctxt
);
2834 /* Skip edges from and to nodes without ipa_pure_const enabled.
2835 Ignore not available symbols. */
2838 ignore_edge (struct cgraph_edge
*e
)
2840 /* We merge summaries of inline clones into summaries of functions they
2841 are inlined to. For that reason the complete function bodies must
2843 if (!e
->inline_failed
)
2845 enum availability avail
;
2846 cgraph_node
*callee
= e
->callee
->function_or_virtual_thunk_symbol
2847 (&avail
, e
->caller
);
2849 return (avail
<= AVAIL_INTERPOSABLE
2850 || ((!optimization_summaries
|| !optimization_summaries
->get (callee
))
2851 && (!summaries_lto
|| !summaries_lto
->get (callee
)))
2852 || flags_from_decl_or_type (e
->callee
->decl
)
2853 & (ECF_CONST
| ECF_NOVOPS
));
2856 /* Compute parm_map for CALLEE_EDGE. */
2859 compute_parm_map (cgraph_edge
*callee_edge
, vec
<modref_parm_map
> *parm_map
)
2861 class ipa_edge_args
*args
;
2862 if (ipa_node_params_sum
2863 && !callee_edge
->call_stmt_cannot_inline_p
2864 && (args
= IPA_EDGE_REF (callee_edge
)) != NULL
)
2866 int i
, count
= ipa_get_cs_argument_count (args
);
2867 class ipa_node_params
*caller_parms_info
, *callee_pi
;
2868 class ipa_call_summary
*es
2869 = ipa_call_summaries
->get (callee_edge
);
2871 = callee_edge
->callee
->function_or_virtual_thunk_symbol
2872 (NULL
, callee_edge
->caller
);
2874 caller_parms_info
= IPA_NODE_REF (callee_edge
->caller
->inlined_to
2875 ? callee_edge
->caller
->inlined_to
2876 : callee_edge
->caller
);
2877 callee_pi
= IPA_NODE_REF (callee
);
2879 (*parm_map
).safe_grow_cleared (count
, true);
2881 for (i
= 0; i
< count
; i
++)
2883 if (es
&& es
->param
[i
].points_to_local_or_readonly_memory
)
2885 (*parm_map
)[i
].parm_index
= -2;
2889 struct ipa_jump_func
*jf
2890 = ipa_get_ith_jump_func (args
, i
);
2891 if (jf
&& callee_pi
)
2893 tree cst
= ipa_value_from_jfunc (caller_parms_info
,
2897 if (cst
&& points_to_local_or_readonly_memory_p (cst
))
2899 (*parm_map
)[i
].parm_index
= -2;
2903 if (jf
&& jf
->type
== IPA_JF_PASS_THROUGH
)
2905 (*parm_map
)[i
].parm_index
2906 = ipa_get_jf_pass_through_formal_id (jf
);
2907 if (ipa_get_jf_pass_through_operation (jf
) == NOP_EXPR
)
2909 (*parm_map
)[i
].parm_offset_known
= true;
2910 (*parm_map
)[i
].parm_offset
= 0;
2912 else if (ipa_get_jf_pass_through_operation (jf
)
2913 == POINTER_PLUS_EXPR
2914 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf
),
2915 &(*parm_map
)[i
].parm_offset
))
2916 (*parm_map
)[i
].parm_offset_known
= true;
2918 (*parm_map
)[i
].parm_offset_known
= false;
2921 if (jf
&& jf
->type
== IPA_JF_ANCESTOR
)
2923 (*parm_map
)[i
].parm_index
= ipa_get_jf_ancestor_formal_id (jf
);
2924 (*parm_map
)[i
].parm_offset_known
= true;
2926 (!(ipa_get_jf_ancestor_offset (jf
) & (BITS_PER_UNIT
- 1)));
2927 (*parm_map
)[i
].parm_offset
2928 = ipa_get_jf_ancestor_offset (jf
) >> LOG2_BITS_PER_UNIT
;
2931 (*parm_map
)[i
].parm_index
= -1;
2935 fprintf (dump_file
, " Parm map: ");
2936 for (i
= 0; i
< count
; i
++)
2937 fprintf (dump_file
, " %i", (*parm_map
)[i
].parm_index
);
2938 fprintf (dump_file
, "\n");
2945 /* Map used to translate escape infos. */
2953 /* Update escape map fo E. */
2956 update_escape_summary_1 (cgraph_edge
*e
,
2957 vec
<vec
<escape_map
>> &map
)
2959 escape_summary
*sum
= escape_summaries
->get (e
);
2962 auto_vec
<escape_entry
> old
= sum
->esc
.copy ();
2963 sum
->esc
.release ();
2967 FOR_EACH_VEC_ELT (old
, i
, ee
)
2970 struct escape_map
*em
;
2971 if (ee
->parm_index
>= map
.length ())
2973 FOR_EACH_VEC_ELT (map
[ee
->parm_index
], j
, em
)
2975 struct escape_entry entry
= {em
->parm_index
, ee
->arg
,
2977 ee
->direct
& em
->direct
};
2978 sum
->esc
.safe_push (entry
);
2981 if (!sum
->esc
.length ())
2982 escape_summaries
->remove (e
);
2985 /* Update escape map fo NODE. */
2988 update_escape_summary (cgraph_node
*node
,
2989 vec
<vec
<escape_map
>> &map
)
2991 if (!escape_summaries
)
2993 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
2994 update_escape_summary_1 (e
, map
);
2995 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
2997 if (!e
->inline_failed
)
2998 update_escape_summary (e
->callee
, map
);
3000 update_escape_summary_1 (e
, map
);
3004 /* Call EDGE was inlined; merge summary from callee to the caller. */
3007 ipa_merge_modref_summary_after_inlining (cgraph_edge
*edge
)
3009 if (!summaries
&& !summaries_lto
)
3012 struct cgraph_node
*to
= (edge
->caller
->inlined_to
3013 ? edge
->caller
->inlined_to
: edge
->caller
);
3014 class modref_summary
*to_info
= summaries
? summaries
->get (to
) : NULL
;
3015 class modref_summary_lto
*to_info_lto
= summaries_lto
3016 ? summaries_lto
->get (to
) : NULL
;
3018 if (!to_info
&& !to_info_lto
)
3021 summaries
->remove (edge
->callee
);
3023 summaries_lto
->remove (edge
->callee
);
3024 remove_modref_edge_summaries (edge
->callee
);
3028 class modref_summary
*callee_info
= summaries
? summaries
->get (edge
->callee
)
3030 class modref_summary_lto
*callee_info_lto
3031 = summaries_lto
? summaries_lto
->get (edge
->callee
) : NULL
;
3032 int flags
= flags_from_decl_or_type (edge
->callee
->decl
);
3033 bool ignore_stores
= ignore_stores_p (edge
->caller
->decl
, flags
);
3035 if (!callee_info
&& to_info
)
3037 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3038 to_info
->loads
->collapse ();
3040 to_info
->stores
->collapse ();
3042 if (!callee_info_lto
&& to_info_lto
)
3044 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3045 to_info_lto
->loads
->collapse ();
3047 to_info_lto
->stores
->collapse ();
3049 if (callee_info
|| callee_info_lto
)
3051 auto_vec
<modref_parm_map
, 32> parm_map
;
3053 compute_parm_map (edge
, &parm_map
);
3057 if (to_info
&& callee_info
)
3058 to_info
->stores
->merge (callee_info
->stores
, &parm_map
);
3059 if (to_info_lto
&& callee_info_lto
)
3060 to_info_lto
->stores
->merge (callee_info_lto
->stores
, &parm_map
);
3062 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3064 if (to_info
&& callee_info
)
3065 to_info
->loads
->merge (callee_info
->loads
, &parm_map
);
3066 if (to_info_lto
&& callee_info_lto
)
3067 to_info_lto
->loads
->merge (callee_info_lto
->loads
, &parm_map
);
3071 /* Now merge escape summaries.
3072 For every escape to the callee we need to merge calle flags
3073 and remap calees escapes. */
3074 class escape_summary
*sum
= escape_summaries
->get (edge
);
3075 int max_escape
= -1;
3079 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3080 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3081 if ((int)ee
->arg
> max_escape
)
3082 max_escape
= ee
->arg
;
3084 auto_vec
<vec
<struct escape_map
>, 32> emap (max_escape
+ 1);
3085 emap
.safe_grow (max_escape
+ 1, true);
3086 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
3089 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3090 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3092 bool needed
= false;
3093 if (to_info
&& to_info
->arg_flags
.length () > ee
->parm_index
)
3095 int flags
= callee_info
3096 && callee_info
->arg_flags
.length () > ee
->arg
3097 ? callee_info
->arg_flags
[ee
->arg
] : 0;
3099 flags
= deref_flags (flags
, ignore_stores
);
3100 else if (ignore_stores
)
3101 flags
|= EAF_NOCLOBBER
| EAF_NOESCAPE
;
3102 flags
|= ee
->min_flags
;
3103 to_info
->arg_flags
[ee
->parm_index
] &= flags
;
3104 if (to_info
->arg_flags
[ee
->parm_index
])
3107 if (to_info_lto
&& to_info_lto
->arg_flags
.length () > ee
->parm_index
)
3109 int flags
= callee_info_lto
3110 && callee_info_lto
->arg_flags
.length () > ee
->arg
3111 ? callee_info_lto
->arg_flags
[ee
->arg
] : 0;
3113 flags
= deref_flags (flags
, ignore_stores
);
3114 else if (ignore_stores
)
3115 flags
|= EAF_NOCLOBBER
| EAF_NOESCAPE
;
3116 flags
|= ee
->min_flags
;
3117 to_info_lto
->arg_flags
[ee
->parm_index
] &= flags
;
3118 if (to_info_lto
->arg_flags
[ee
->parm_index
])
3121 struct escape_map entry
= {ee
->parm_index
, ee
->direct
};
3123 emap
[ee
->arg
].safe_push (entry
);
3125 update_escape_summary (edge
->callee
, emap
);
3126 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
3129 escape_summaries
->remove (edge
);
3133 if (to_info
&& !to_info
->useful_p (flags
))
3136 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
3138 summaries
->remove (to
);
3141 else if (to_info
&& dump_file
)
3144 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
3146 to_info
->dump (dump_file
);
3149 summaries
->remove (edge
->callee
);
3153 if (to_info_lto
&& !to_info_lto
->useful_p (flags
))
3156 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
3158 summaries_lto
->remove (to
);
3160 else if (to_info_lto
&& dump_file
)
3163 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
3165 to_info_lto
->dump (dump_file
);
3168 if (callee_info_lto
)
3169 summaries_lto
->remove (edge
->callee
);
3171 if (!to_info
&& !to_info_lto
)
3172 remove_modref_edge_summaries (to
);
3176 /* Get parameter type from DECL. This is only safe for special cases
3177 like builtins we create fnspec for because the type match is checked
3178 at fnspec creation time. */
3181 get_parm_type (tree decl
, unsigned int i
)
3183 tree t
= TYPE_ARG_TYPES (TREE_TYPE (decl
));
3185 for (unsigned int p
= 0; p
< i
; p
++)
3187 return TREE_VALUE (t
);
3190 /* Return access mode for argument I of call E with FNSPEC. */
3192 static modref_access_node
3193 get_access_for_fnspec (cgraph_edge
*e
, attr_fnspec
&fnspec
,
3194 unsigned int i
, modref_parm_map
&map
)
3196 tree size
= NULL_TREE
;
3197 unsigned int size_arg
;
3199 if (!fnspec
.arg_specified_p (i
))
3201 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
3203 cgraph_node
*node
= e
->caller
->inlined_to
3204 ? e
->caller
->inlined_to
: e
->caller
;
3205 class ipa_node_params
*caller_parms_info
= IPA_NODE_REF (node
);
3206 class ipa_edge_args
*args
= IPA_EDGE_REF (e
);
3207 struct ipa_jump_func
*jf
= ipa_get_ith_jump_func (args
, size_arg
);
3210 size
= ipa_value_from_jfunc (caller_parms_info
, jf
,
3211 get_parm_type (e
->callee
->decl
, size_arg
));
3213 else if (fnspec
.arg_access_size_given_by_type_p (i
))
3214 size
= TYPE_SIZE_UNIT (get_parm_type (e
->callee
->decl
, i
));
3215 modref_access_node a
= {0, -1, -1,
3216 map
.parm_offset
, map
.parm_index
,
3217 map
.parm_offset_known
};
3218 poly_int64 size_hwi
;
3220 && poly_int_tree_p (size
, &size_hwi
)
3221 && coeffs_in_range_p (size_hwi
, 0,
3222 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
3225 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
3230 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
3231 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
3234 propagate_unknown_call (cgraph_node
*node
,
3235 cgraph_edge
*e
, int ecf_flags
,
3236 modref_summary
*cur_summary
,
3237 modref_summary_lto
*cur_summary_lto
)
3239 bool changed
= false;
3240 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
3241 auto_vec
<modref_parm_map
, 32> parm_map
;
3243 && compute_parm_map (e
, &parm_map
))
3245 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
3247 gcc_checking_assert (fnspec
.known_p ());
3248 if (fnspec
.global_memory_read_p ())
3249 collapse_loads (cur_summary
, cur_summary_lto
);
3252 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
3253 for (unsigned i
= 0; i
< parm_map
.length () && t
;
3254 i
++, t
= TREE_CHAIN (t
))
3255 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
3257 else if (!fnspec
.arg_specified_p (i
)
3258 || fnspec
.arg_maybe_read_p (i
))
3260 modref_parm_map map
= parm_map
[i
];
3261 if (map
.parm_index
== -2)
3263 if (map
.parm_index
== -1)
3265 collapse_loads (cur_summary
, cur_summary_lto
);
3269 changed
|= cur_summary
->loads
->insert
3270 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3271 if (cur_summary_lto
)
3272 changed
|= cur_summary_lto
->loads
->insert
3273 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3276 if (ignore_stores_p (node
->decl
, ecf_flags
))
3278 else if (fnspec
.global_memory_written_p ())
3279 collapse_stores (cur_summary
, cur_summary_lto
);
3282 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
3283 for (unsigned i
= 0; i
< parm_map
.length () && t
;
3284 i
++, t
= TREE_CHAIN (t
))
3285 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
3287 else if (!fnspec
.arg_specified_p (i
)
3288 || fnspec
.arg_maybe_written_p (i
))
3290 modref_parm_map map
= parm_map
[i
];
3291 if (map
.parm_index
== -2)
3293 if (map
.parm_index
== -1)
3295 collapse_stores (cur_summary
, cur_summary_lto
);
3299 changed
|= cur_summary
->stores
->insert
3300 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3301 if (cur_summary_lto
)
3302 changed
|= cur_summary_lto
->stores
->insert
3303 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
3306 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
3308 if (cur_summary
&& !cur_summary
->writes_errno
)
3310 cur_summary
->writes_errno
= true;
3313 if (cur_summary_lto
&& !cur_summary_lto
->writes_errno
)
3315 cur_summary_lto
->writes_errno
= true;
3322 fprintf (dump_file
, " collapsing loads\n");
3323 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
3324 if (!ignore_stores_p (node
->decl
, ecf_flags
))
3327 fprintf (dump_file
, " collapsing stores\n");
3328 changed
|= collapse_stores (cur_summary
, cur_summary_lto
);
3333 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
3334 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
3337 remove_useless_summaries (cgraph_node
*node
,
3338 modref_summary
**cur_summary_ptr
,
3339 modref_summary_lto
**cur_summary_lto_ptr
,
3342 if (*cur_summary_ptr
&& !(*cur_summary_ptr
)->useful_p (ecf_flags
, false))
3344 optimization_summaries
->remove (node
);
3345 *cur_summary_ptr
= NULL
;
3347 if (*cur_summary_lto_ptr
3348 && !(*cur_summary_lto_ptr
)->useful_p (ecf_flags
, false))
3350 summaries_lto
->remove (node
);
3351 *cur_summary_lto_ptr
= NULL
;
3355 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3356 and propagate loads/stores. */
3359 modref_propagate_in_scc (cgraph_node
*component_node
)
3361 bool changed
= true;
3367 for (struct cgraph_node
*cur
= component_node
; cur
;
3368 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3370 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
3371 modref_summary
*cur_summary
= optimization_summaries
3372 ? optimization_summaries
->get (node
)
3374 modref_summary_lto
*cur_summary_lto
= summaries_lto
3375 ? summaries_lto
->get (node
)
3378 if (!cur_summary
&& !cur_summary_lto
)
3381 int cur_ecf_flags
= flags_from_decl_or_type (node
->decl
);
3384 fprintf (dump_file
, " Processing %s%s%s\n",
3386 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3387 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3389 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
3391 if (e
->indirect_info
->ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
3394 fprintf (dump_file
, " Indirect call"
3395 "collapsing loads\n");
3396 if (propagate_unknown_call
3397 (node
, e
, e
->indirect_info
->ecf_flags
,
3398 cur_summary
, cur_summary_lto
))
3401 remove_useless_summaries (node
, &cur_summary
,
3404 if (!cur_summary
&& !cur_summary_lto
)
3409 if (!cur_summary
&& !cur_summary_lto
)
3412 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
3413 callee_edge
= callee_edge
->next_callee
)
3415 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
3416 modref_summary
*callee_summary
= NULL
;
3417 modref_summary_lto
*callee_summary_lto
= NULL
;
3418 struct cgraph_node
*callee
;
3420 if (flags
& (ECF_CONST
| ECF_NOVOPS
)
3421 || !callee_edge
->inline_failed
)
3424 /* Get the callee and its summary. */
3425 enum availability avail
;
3426 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
3429 /* It is not necessary to re-process calls outside of the
3433 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
3434 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
3438 fprintf (dump_file
, " Call to %s\n",
3439 callee_edge
->callee
->dump_name ());
3441 bool ignore_stores
= ignore_stores_p (cur
->decl
, flags
);
3443 if (avail
<= AVAIL_INTERPOSABLE
)
3446 fprintf (dump_file
, " Call target interposable"
3447 " or not available\n");
3448 changed
|= propagate_unknown_call
3449 (node
, callee_edge
, flags
,
3450 cur_summary
, cur_summary_lto
);
3451 if (!cur_summary
&& !cur_summary_lto
)
3456 /* We don't know anything about CALLEE, hence we cannot tell
3457 anything about the entire component. */
3460 && !(callee_summary
= optimization_summaries
->get (callee
)))
3463 fprintf (dump_file
, " No call target summary\n");
3464 changed
|= propagate_unknown_call
3465 (node
, callee_edge
, flags
,
3469 && !(callee_summary_lto
= summaries_lto
->get (callee
)))
3472 fprintf (dump_file
, " No call target summary\n");
3473 changed
|= propagate_unknown_call
3474 (node
, callee_edge
, flags
,
3475 NULL
, cur_summary_lto
);
3478 /* We can not safely optimize based on summary of callee if it
3479 does not always bind to current def: it is possible that
3480 memory load was optimized out earlier which may not happen in
3481 the interposed variant. */
3482 if (!callee_edge
->binds_to_current_def_p ())
3484 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
3486 fprintf (dump_file
, " May not bind local;"
3487 " collapsing loads\n");
3491 auto_vec
<modref_parm_map
, 32> parm_map
;
3493 compute_parm_map (callee_edge
, &parm_map
);
3495 /* Merge in callee's information. */
3498 changed
|= cur_summary
->loads
->merge
3499 (callee_summary
->loads
, &parm_map
);
3502 changed
|= cur_summary
->stores
->merge
3503 (callee_summary
->stores
, &parm_map
);
3504 if (!cur_summary
->writes_errno
3505 && callee_summary
->writes_errno
)
3507 cur_summary
->writes_errno
= true;
3512 if (callee_summary_lto
)
3514 changed
|= cur_summary_lto
->loads
->merge
3515 (callee_summary_lto
->loads
, &parm_map
);
3518 changed
|= cur_summary_lto
->stores
->merge
3519 (callee_summary_lto
->stores
, &parm_map
);
3520 if (!cur_summary_lto
->writes_errno
3521 && callee_summary_lto
->writes_errno
)
3523 cur_summary_lto
->writes_errno
= true;
3529 remove_useless_summaries (node
, &cur_summary
,
3532 if (!cur_summary
&& !cur_summary_lto
)
3534 if (dump_file
&& changed
)
3537 cur_summary
->dump (dump_file
);
3538 if (cur_summary_lto
)
3539 cur_summary_lto
->dump (dump_file
);
3540 dump_modref_edge_summaries (dump_file
, node
, 4);
3548 "Propagation finished in %i iterations\n", iteration
);
3551 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
3554 modref_propagate_dump_scc (cgraph_node
*component_node
)
3556 for (struct cgraph_node
*cur
= component_node
; cur
;
3557 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3558 if (!cur
->inlined_to
)
3560 modref_summary
*cur_summary
= optimization_summaries
3561 ? optimization_summaries
->get (cur
)
3563 modref_summary_lto
*cur_summary_lto
= summaries_lto
3564 ? summaries_lto
->get (cur
)
3567 fprintf (dump_file
, "Propagated modref for %s%s%s\n",
3569 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3570 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3571 if (optimization_summaries
)
3574 cur_summary
->dump (dump_file
);
3576 fprintf (dump_file
, " Not tracked\n");
3580 if (cur_summary_lto
)
3581 cur_summary_lto
->dump (dump_file
);
3583 fprintf (dump_file
, " Not tracked (lto)\n");
3588 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
3589 and SUMMARY_LTO to CUR_SUMMARY_LTO.
3590 Return true if something changed. */
3593 modref_merge_call_site_flags (escape_summary
*sum
,
3594 modref_summary
*cur_summary
,
3595 modref_summary_lto
*cur_summary_lto
,
3596 modref_summary
*summary
,
3597 modref_summary_lto
*summary_lto
,
3602 bool changed
= false;
3604 /* If we have no useful info to propagate. */
3605 if ((!cur_summary
|| !cur_summary
->arg_flags
.length ())
3606 && (!cur_summary_lto
|| !cur_summary_lto
->arg_flags
.length ()))
3609 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3614 if (summary
&& ee
->arg
< summary
->arg_flags
.length ())
3615 flags
= summary
->arg_flags
[ee
->arg
];
3617 && ee
->arg
< summary_lto
->arg_flags
.length ())
3618 flags_lto
= summary_lto
->arg_flags
[ee
->arg
];
3621 flags
= deref_flags (flags
, ignore_stores
);
3622 flags_lto
= deref_flags (flags_lto
, ignore_stores
);
3624 else if (ignore_stores
)
3626 flags
|= EAF_NOESCAPE
| EAF_NOCLOBBER
;
3627 flags_lto
|= EAF_NOESCAPE
| EAF_NOCLOBBER
;
3629 flags
|= ee
->min_flags
;
3630 flags_lto
|= ee
->min_flags
;
3631 if (cur_summary
&& ee
->parm_index
< cur_summary
->arg_flags
.length ())
3633 int f
= cur_summary
->arg_flags
[ee
->parm_index
];
3634 if ((f
& flags
) != f
)
3637 if ((f
& ~(EAF_DIRECT
| EAF_NOCLOBBER
)) == 0)
3639 cur_summary
->arg_flags
[ee
->parm_index
] = f
;
3644 && ee
->parm_index
< cur_summary_lto
->arg_flags
.length ())
3646 int f
= cur_summary_lto
->arg_flags
[ee
->parm_index
];
3647 if ((f
& flags_lto
) != f
)
3650 if ((f
& ~(EAF_DIRECT
| EAF_NOCLOBBER
)) == 0)
3652 cur_summary_lto
->arg_flags
[ee
->parm_index
] = f
;
3660 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3661 and propagate arg flags. */
3664 modref_propagate_flags_in_scc (cgraph_node
*component_node
)
3666 bool changed
= true;
3672 for (struct cgraph_node
*cur
= component_node
; cur
;
3673 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3675 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
3676 modref_summary
*cur_summary
= optimization_summaries
3677 ? optimization_summaries
->get (node
)
3679 modref_summary_lto
*cur_summary_lto
= summaries_lto
3680 ? summaries_lto
->get (node
)
3683 if (!cur_summary
&& !cur_summary_lto
)
3687 fprintf (dump_file
, " Processing %s%s%s\n",
3689 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3690 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3692 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
3694 escape_summary
*sum
= escape_summaries
->get (e
);
3696 if (!sum
|| (e
->indirect_info
->ecf_flags
3697 & (ECF_CONST
| ECF_NOVOPS
)))
3700 changed
|= modref_merge_call_site_flags
3701 (sum
, cur_summary
, cur_summary_lto
,
3702 NULL
, NULL
, ignore_stores_p (node
->decl
,
3703 e
->indirect_info
->ecf_flags
));
3706 if (!cur_summary
&& !cur_summary_lto
)
3709 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
3710 callee_edge
= callee_edge
->next_callee
)
3712 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
3713 modref_summary
*callee_summary
= NULL
;
3714 modref_summary_lto
*callee_summary_lto
= NULL
;
3715 struct cgraph_node
*callee
;
3717 if (flags
& (ECF_CONST
| ECF_NOVOPS
)
3718 || !callee_edge
->inline_failed
)
3720 /* Get the callee and its summary. */
3721 enum availability avail
;
3722 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
3725 /* It is not necessary to re-process calls outside of the
3729 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
3730 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
3733 escape_summary
*sum
= escape_summaries
->get (callee_edge
);
3738 fprintf (dump_file
, " Call to %s\n",
3739 callee_edge
->callee
->dump_name ());
3741 if (avail
<= AVAIL_INTERPOSABLE
3742 || callee_edge
->call_stmt_cannot_inline_p
)
3747 callee_summary
= optimization_summaries
->get (callee
);
3748 if (cur_summary_lto
)
3749 callee_summary_lto
= summaries_lto
->get (callee
);
3751 changed
|= modref_merge_call_site_flags
3752 (sum
, cur_summary
, cur_summary_lto
,
3753 callee_summary
, callee_summary_lto
,
3754 ignore_stores_p (node
->decl
, flags
));
3755 if (dump_file
&& changed
)
3758 cur_summary
->dump (dump_file
);
3759 if (cur_summary_lto
)
3760 cur_summary_lto
->dump (dump_file
);
3768 "Propagation of flags finished in %i iterations\n", iteration
);
3771 /* Run the IPA pass. This will take a function's summaries and calls and
3772 construct new summaries which represent a transitive closure. So that
3773 summary of an analyzed function contains information about the loads and
3774 stores that the function or any function that it calls does. */
3777 pass_ipa_modref::execute (function
*)
3779 if (!summaries
&& !summaries_lto
)
3782 if (optimization_summaries
)
3783 ggc_delete (optimization_summaries
);
3784 optimization_summaries
= summaries
;
3787 struct cgraph_node
**order
= XCNEWVEC (struct cgraph_node
*,
3788 symtab
->cgraph_count
);
3790 order_pos
= ipa_reduced_postorder (order
, true, ignore_edge
);
3793 /* Iterate over all strongly connected components in post-order. */
3794 for (i
= 0; i
< order_pos
; i
++)
3796 /* Get the component's representative. That's just any node in the
3797 component from which we can traverse the entire component. */
3798 struct cgraph_node
*component_node
= order
[i
];
3801 fprintf (dump_file
, "\n\nStart of SCC component\n");
3803 modref_propagate_in_scc (component_node
);
3804 modref_propagate_flags_in_scc (component_node
);
3806 modref_propagate_dump_scc (component_node
);
3809 FOR_EACH_FUNCTION (node
)
3810 update_signature (node
);
3812 ((modref_summaries_lto
*)summaries_lto
)->propagated
= true;
3813 ipa_free_postorder_info ();
3815 delete fnspec_summaries
;
3816 fnspec_summaries
= NULL
;
3817 delete escape_summaries
;
3818 escape_summaries
= NULL
;
3822 /* Summaries must stay alive until end of compilation. */
3825 ipa_modref_c_finalize ()
3827 if (optimization_summaries
)
3828 ggc_delete (optimization_summaries
);
3829 optimization_summaries
= NULL
;
3830 gcc_checking_assert (!summaries
);
3832 ggc_delete (summaries_lto
);
3833 summaries_lto
= NULL
;
3834 if (fnspec_summaries
)
3835 delete fnspec_summaries
;
3836 fnspec_summaries
= NULL
;
3837 if (escape_summaries
)
3838 delete escape_summaries
;
3839 escape_summaries
= NULL
;
3842 #include "gt-ipa-modref.h"