1 /* Search for references that a functions loads or stores.
2 Copyright (C) 2020-2021 Free Software Foundation, Inc.
3 Contributed by David Cepelik and Jan Hubicka
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 /* Mod/ref pass records summary about loads and stores performed by the
22 function. This is later used by alias analysis to disambiguate memory
23 accesses across function calls.
25 This file contains a tree pass and an IPA pass. Both performs the same
26 analysis however tree pass is executed during early and late optimization
27 passes to propagate info downwards in the compilation order. IPA pass
28 propagates across the callgraph and is able to handle recursion and works on
29 whole program during link-time analysis.
31 LTO mode differs from the local mode by not recording alias sets but types
32 that are translated to alias sets later. This is necessary in order stream
33 the information because the alias sets are rebuild at stream-in time and may
34 not correspond to ones seen during analysis. For this reason part of
35 analysis is duplicated.
37 The following information is computed
38 1) load/store access tree described in ipa-modref-tree.h
39 This is used by tree-ssa-alias to disambiguate load/stores
40 2) EAF flags used by points-to analysis (in tree-ssa-structlias).
41 and defined in tree-core.h.
42 and stored to optimization_summaries.
44 There are multiple summaries computed and used during the propagation:
45 - summaries holds summaries from analysis to IPA propagation
47 - summaries_lto is same as summaries but holds them in a format
48 that can be streamed (as described above).
49 - fnspec_summary holds fnspec strings for call. This is
50 necessary because gimple_call_fnspec performs additional
51 analysis except for looking callee fndecl.
52 - escape_summary holds escape points for given call edge.
53 That is a vector recording what function parmaeters
54 may escape to a function call (and with what parameter index). */
58 #include "coretypes.h"
62 #include "alloc-pool.h"
63 #include "tree-pass.h"
64 #include "gimple-iterator.h"
67 #include "ipa-utils.h"
68 #include "symbol-summary.h"
69 #include "gimple-pretty-print.h"
70 #include "gimple-walk.h"
71 #include "print-tree.h"
72 #include "tree-streamer.h"
75 #include "ipa-modref-tree.h"
76 #include "ipa-modref.h"
77 #include "value-range.h"
79 #include "ipa-fnsummary.h"
80 #include "attr-fnspec.h"
81 #include "symtab-clones.h"
82 #include "gimple-ssa.h"
83 #include "tree-phinodes.h"
84 #include "tree-ssa-operands.h"
85 #include "ssa-iterators.h"
86 #include "stringpool.h"
87 #include "tree-ssanames.h"
92 /* We record fnspec specifiers for call edges since they depends on actual
111 /* Summary holding fnspec string for a given call. */
113 class fnspec_summaries_t
: public call_summary
<fnspec_summary
*>
116 fnspec_summaries_t (symbol_table
*symtab
)
117 : call_summary
<fnspec_summary
*> (symtab
) {}
118 /* Hook that is called by summary when an edge is duplicated. */
119 virtual void duplicate (cgraph_edge
*,
124 dst
->fnspec
= xstrdup (src
->fnspec
);
128 static fnspec_summaries_t
*fnspec_summaries
= NULL
;
130 /* Escape summary holds a vector of param indexes that escape to
134 /* Parameter that escapes at a given call. */
135 unsigned int parm_index
;
136 /* Argument it escapes to. */
138 /* Minimal flags known about the argument. */
139 eaf_flags_t min_flags
;
140 /* Does it escape directly or indirectly? */
144 /* Dump EAF flags. */
147 dump_eaf_flags (FILE *out
, int flags
, bool newline
= true)
149 if (flags
& EAF_DIRECT
)
150 fprintf (out
, " direct");
151 if (flags
& EAF_NOCLOBBER
)
152 fprintf (out
, " noclobber");
153 if (flags
& EAF_NOESCAPE
)
154 fprintf (out
, " noescape");
155 if (flags
& EAF_NODIRECTESCAPE
)
156 fprintf (out
, " nodirectescape");
157 if (flags
& EAF_UNUSED
)
158 fprintf (out
, " unused");
159 if (flags
& EAF_NOT_RETURNED
)
160 fprintf (out
, " not_returned");
161 if (flags
& EAF_NOREAD
)
162 fprintf (out
, " noread");
167 struct escape_summary
169 auto_vec
<escape_entry
> esc
;
170 void dump (FILE *out
)
172 for (unsigned int i
= 0; i
< esc
.length (); i
++)
174 fprintf (out
, " parm %i arg %i %s min:",
177 esc
[i
].direct
? "(direct)" : "(indirect)");
178 dump_eaf_flags (out
, esc
[i
].min_flags
, false);
184 class escape_summaries_t
: public call_summary
<escape_summary
*>
187 escape_summaries_t (symbol_table
*symtab
)
188 : call_summary
<escape_summary
*> (symtab
) {}
189 /* Hook that is called by summary when an edge is duplicated. */
190 virtual void duplicate (cgraph_edge
*,
195 dst
->esc
= src
->esc
.copy ();
199 static escape_summaries_t
*escape_summaries
= NULL
;
201 } /* ANON namespace: GTY annotated summaries can not be anonymous. */
204 /* Class (from which there is one global instance) that holds modref summaries
205 for all analyzed functions. */
207 class GTY((user
)) modref_summaries
208 : public fast_function_summary
<modref_summary
*, va_gc
>
211 modref_summaries (symbol_table
*symtab
)
212 : fast_function_summary
<modref_summary
*, va_gc
> (symtab
) {}
213 virtual void insert (cgraph_node
*, modref_summary
*state
);
214 virtual void duplicate (cgraph_node
*src_node
,
215 cgraph_node
*dst_node
,
216 modref_summary
*src_data
,
217 modref_summary
*dst_data
);
218 static modref_summaries
*create_ggc (symbol_table
*symtab
)
220 return new (ggc_alloc_no_dtor
<modref_summaries
> ())
221 modref_summaries (symtab
);
225 class modref_summary_lto
;
227 /* Class (from which there is one global instance) that holds modref summaries
228 for all analyzed functions. */
230 class GTY((user
)) modref_summaries_lto
231 : public fast_function_summary
<modref_summary_lto
*, va_gc
>
234 modref_summaries_lto (symbol_table
*symtab
)
235 : fast_function_summary
<modref_summary_lto
*, va_gc
> (symtab
),
236 propagated (false) {}
237 virtual void insert (cgraph_node
*, modref_summary_lto
*state
);
238 virtual void duplicate (cgraph_node
*src_node
,
239 cgraph_node
*dst_node
,
240 modref_summary_lto
*src_data
,
241 modref_summary_lto
*dst_data
);
242 static modref_summaries_lto
*create_ggc (symbol_table
*symtab
)
244 return new (ggc_alloc_no_dtor
<modref_summaries_lto
> ())
245 modref_summaries_lto (symtab
);
250 /* Global variable holding all modref summaries
251 (from analysis to IPA propagation time). */
253 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
256 /* Global variable holding all modref optimization summaries
257 (from IPA propagation time or used by local optimization pass). */
259 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
260 *optimization_summaries
;
262 /* LTO summaries hold info from analysis to LTO streaming or from LTO
263 stream-in through propagation to LTO stream-out. */
265 static GTY(()) fast_function_summary
<modref_summary_lto
*, va_gc
>
268 /* Summary for a single function which this pass produces. */
270 modref_summary::modref_summary ()
271 : loads (NULL
), stores (NULL
), writes_errno (NULL
)
275 modref_summary::~modref_summary ()
283 /* All flags that are implied by the ECF_CONST functions. */
284 const int implicit_const_eaf_flags
= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
285 | EAF_NODIRECTESCAPE
| EAF_NOREAD
;
286 /* All flags that are implied by the ECF_PURE function. */
287 const int implicit_pure_eaf_flags
= EAF_NOCLOBBER
| EAF_NOESCAPE
288 | EAF_NODIRECTESCAPE
;
289 /* All flags implied when we know we can ignore stores (i.e. when handling
290 call to noreturn). */
291 const int ignore_stores_eaf_flags
= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
292 | EAF_NODIRECTESCAPE
;
294 /* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
295 useful to track. If returns_void is true moreover clear
298 remove_useless_eaf_flags (int eaf_flags
, int ecf_flags
, bool returns_void
)
300 if (ecf_flags
& ECF_NOVOPS
)
302 if (ecf_flags
& ECF_CONST
)
303 eaf_flags
&= ~implicit_const_eaf_flags
;
304 else if (ecf_flags
& ECF_PURE
)
305 eaf_flags
&= ~implicit_pure_eaf_flags
;
306 else if ((ecf_flags
& ECF_NORETURN
) || returns_void
)
307 eaf_flags
&= ~EAF_NOT_RETURNED
;
308 /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
309 in tree-ssa-alias.c). Give up earlier. */
310 if ((eaf_flags
& ~(EAF_DIRECT
| EAF_NOCLOBBER
)) == 0)
315 /* Return true if FLAGS holds some useful information. */
318 eaf_flags_useful_p (vec
<eaf_flags_t
> &flags
, int ecf_flags
)
320 for (unsigned i
= 0; i
< flags
.length (); i
++)
321 if (remove_useless_eaf_flags (flags
[i
], ecf_flags
, false))
326 /* Return true if summary is potentially useful for optimization.
327 If CHECK_FLAGS is false assume that arg_flags are useful. */
330 modref_summary::useful_p (int ecf_flags
, bool check_flags
)
332 if (ecf_flags
& ECF_NOVOPS
)
334 if (arg_flags
.length () && !check_flags
)
336 if (check_flags
&& eaf_flags_useful_p (arg_flags
, ecf_flags
))
338 arg_flags
.release ();
339 if (ecf_flags
& ECF_CONST
)
341 if (loads
&& !loads
->every_base
)
343 if (ecf_flags
& ECF_PURE
)
345 return stores
&& !stores
->every_base
;
348 /* Single function summary used for LTO. */
350 typedef modref_tree
<tree
> modref_records_lto
;
351 struct GTY(()) modref_summary_lto
353 /* Load and stores in functions using types rather then alias sets.
355 This is necessary to make the information streamable for LTO but is also
356 more verbose and thus more likely to hit the limits. */
357 modref_records_lto
*loads
;
358 modref_records_lto
*stores
;
359 auto_vec
<eaf_flags_t
> GTY((skip
)) arg_flags
;
362 modref_summary_lto ();
363 ~modref_summary_lto ();
365 bool useful_p (int ecf_flags
, bool check_flags
= true);
368 /* Summary for a single function which this pass produces. */
370 modref_summary_lto::modref_summary_lto ()
371 : loads (NULL
), stores (NULL
), writes_errno (NULL
)
375 modref_summary_lto::~modref_summary_lto ()
384 /* Return true if lto summary is potentially useful for optimization.
385 If CHECK_FLAGS is false assume that arg_flags are useful. */
388 modref_summary_lto::useful_p (int ecf_flags
, bool check_flags
)
390 if (ecf_flags
& ECF_NOVOPS
)
392 if (arg_flags
.length () && !check_flags
)
394 if (check_flags
&& eaf_flags_useful_p (arg_flags
, ecf_flags
))
396 arg_flags
.release ();
397 if (ecf_flags
& ECF_CONST
)
399 if (loads
&& !loads
->every_base
)
401 if (ecf_flags
& ECF_PURE
)
403 return stores
&& !stores
->every_base
;
409 dump_access (modref_access_node
*a
, FILE *out
)
411 fprintf (out
, " access:");
412 if (a
->parm_index
!= -1)
414 fprintf (out
, " Parm %i", a
->parm_index
);
415 if (a
->parm_offset_known
)
417 fprintf (out
, " param offset:");
418 print_dec ((poly_int64_pod
)a
->parm_offset
, out
, SIGNED
);
421 if (a
->range_info_useful_p ())
423 fprintf (out
, " offset:");
424 print_dec ((poly_int64_pod
)a
->offset
, out
, SIGNED
);
425 fprintf (out
, " size:");
426 print_dec ((poly_int64_pod
)a
->size
, out
, SIGNED
);
427 fprintf (out
, " max_size:");
428 print_dec ((poly_int64_pod
)a
->max_size
, out
, SIGNED
);
430 fprintf (out
, " adjusted %i times", a
->adjustments
);
435 /* Dump records TT to OUT. */
438 dump_records (modref_records
*tt
, FILE *out
)
440 fprintf (out
, " Limits: %i bases, %i refs\n",
441 (int)tt
->max_bases
, (int)tt
->max_refs
);
444 fprintf (out
, " Every base\n");
448 modref_base_node
<alias_set_type
> *n
;
449 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
451 fprintf (out
, " Base %i: alias set %i\n", (int)i
, n
->base
);
454 fprintf (out
, " Every ref\n");
458 modref_ref_node
<alias_set_type
> *r
;
459 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
461 fprintf (out
, " Ref %i: alias set %i\n", (int)j
, r
->ref
);
464 fprintf (out
, " Every access\n");
468 modref_access_node
*a
;
469 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
470 dump_access (a
, out
);
475 /* Dump records TT to OUT. */
478 dump_lto_records (modref_records_lto
*tt
, FILE *out
)
480 fprintf (out
, " Limits: %i bases, %i refs\n",
481 (int)tt
->max_bases
, (int)tt
->max_refs
);
484 fprintf (out
, " Every base\n");
488 modref_base_node
<tree
> *n
;
489 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
491 fprintf (out
, " Base %i:", (int)i
);
492 print_generic_expr (dump_file
, n
->base
);
493 fprintf (out
, " (alias set %i)\n",
494 n
->base
? get_alias_set (n
->base
) : 0);
497 fprintf (out
, " Every ref\n");
501 modref_ref_node
<tree
> *r
;
502 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
504 fprintf (out
, " Ref %i:", (int)j
);
505 print_generic_expr (dump_file
, r
->ref
);
506 fprintf (out
, " (alias set %i)\n",
507 r
->ref
? get_alias_set (r
->ref
) : 0);
510 fprintf (out
, " Every access\n");
514 modref_access_node
*a
;
515 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
516 dump_access (a
, out
);
521 /* Dump all escape points of NODE to OUT. */
524 dump_modref_edge_summaries (FILE *out
, cgraph_node
*node
, int depth
)
527 if (!escape_summaries
)
529 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
531 class escape_summary
*sum
= escape_summaries
->get (e
);
534 fprintf (out
, "%*sIndirect call %i in %s escapes:",
535 depth
, "", i
, node
->dump_name ());
540 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
542 if (!e
->inline_failed
)
543 dump_modref_edge_summaries (out
, e
->callee
, depth
+ 1);
544 class escape_summary
*sum
= escape_summaries
->get (e
);
547 fprintf (out
, "%*sCall %s->%s escapes:", depth
, "",
548 node
->dump_name (), e
->callee
->dump_name ());
551 class fnspec_summary
*fsum
= fnspec_summaries
->get (e
);
554 fprintf (out
, "%*sCall %s->%s fnspec: %s\n", depth
, "",
555 node
->dump_name (), e
->callee
->dump_name (),
561 /* Remove all call edge summaries associated with NODE. */
564 remove_modref_edge_summaries (cgraph_node
*node
)
566 if (!escape_summaries
)
568 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
569 escape_summaries
->remove (e
);
570 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
572 if (!e
->inline_failed
)
573 remove_modref_edge_summaries (e
->callee
);
574 escape_summaries
->remove (e
);
575 fnspec_summaries
->remove (e
);
582 modref_summary::dump (FILE *out
)
586 fprintf (out
, " loads:\n");
587 dump_records (loads
, out
);
591 fprintf (out
, " stores:\n");
592 dump_records (stores
, out
);
595 fprintf (out
, " Writes errno\n");
596 if (arg_flags
.length ())
598 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
601 fprintf (out
, " parm %i flags:", i
);
602 dump_eaf_flags (out
, arg_flags
[i
]);
610 modref_summary_lto::dump (FILE *out
)
612 fprintf (out
, " loads:\n");
613 dump_lto_records (loads
, out
);
614 fprintf (out
, " stores:\n");
615 dump_lto_records (stores
, out
);
617 fprintf (out
, " Writes errno\n");
618 if (arg_flags
.length ())
620 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
623 fprintf (out
, " parm %i flags:", i
);
624 dump_eaf_flags (out
, arg_flags
[i
]);
629 /* Get function summary for FUNC if it exists, return NULL otherwise. */
632 get_modref_function_summary (cgraph_node
*func
)
634 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
635 if (!optimization_summaries
)
638 /* A single function body may be represented by multiple symbols with
639 different visibility. For example, if FUNC is an interposable alias,
640 we don't want to return anything, even if we have summary for the target
642 enum availability avail
;
643 func
= func
->function_or_virtual_thunk_symbol
644 (&avail
, current_function_decl
?
645 cgraph_node::get (current_function_decl
) : NULL
);
646 if (avail
<= AVAIL_INTERPOSABLE
)
649 modref_summary
*r
= optimization_summaries
->get (func
);
653 /* Construct modref_access_node from REF. */
654 static modref_access_node
655 get_access (ao_ref
*ref
)
659 base
= ao_ref_base (ref
);
660 modref_access_node a
= {ref
->offset
, ref
->size
, ref
->max_size
,
662 if (TREE_CODE (base
) == MEM_REF
|| TREE_CODE (base
) == TARGET_MEM_REF
)
665 base
= TREE_OPERAND (base
, 0);
666 if (TREE_CODE (base
) == SSA_NAME
667 && SSA_NAME_IS_DEFAULT_DEF (base
)
668 && TREE_CODE (SSA_NAME_VAR (base
)) == PARM_DECL
)
671 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
672 t
!= SSA_NAME_VAR (base
); t
= DECL_CHAIN (t
))
681 if (TREE_CODE (memref
) == MEM_REF
)
684 = wi::to_poly_wide (TREE_OPERAND
685 (memref
, 1)).to_shwi (&a
.parm_offset
);
688 a
.parm_offset_known
= false;
698 /* Record access into the modref_records data structure. */
701 record_access (modref_records
*tt
, ao_ref
*ref
)
703 alias_set_type base_set
= !flag_strict_aliasing
? 0
704 : ao_ref_base_alias_set (ref
);
705 alias_set_type ref_set
= !flag_strict_aliasing
? 0
706 : (ao_ref_alias_set (ref
));
707 modref_access_node a
= get_access (ref
);
710 fprintf (dump_file
, " - Recording base_set=%i ref_set=%i parm=%i\n",
711 base_set
, ref_set
, a
.parm_index
);
713 tt
->insert (base_set
, ref_set
, a
, false);
716 /* IPA version of record_access_tree. */
719 record_access_lto (modref_records_lto
*tt
, ao_ref
*ref
)
721 /* get_alias_set sometimes use different type to compute the alias set
722 than TREE_TYPE (base). Do same adjustments. */
723 tree base_type
= NULL_TREE
, ref_type
= NULL_TREE
;
724 if (flag_strict_aliasing
)
729 while (handled_component_p (base
))
730 base
= TREE_OPERAND (base
, 0);
732 base_type
= reference_alias_ptr_type_1 (&base
);
735 base_type
= TREE_TYPE (base
);
737 base_type
= TYPE_REF_CAN_ALIAS_ALL (base_type
)
738 ? NULL_TREE
: TREE_TYPE (base_type
);
740 tree ref_expr
= ref
->ref
;
741 ref_type
= reference_alias_ptr_type_1 (&ref_expr
);
744 ref_type
= TREE_TYPE (ref_expr
);
746 ref_type
= TYPE_REF_CAN_ALIAS_ALL (ref_type
)
747 ? NULL_TREE
: TREE_TYPE (ref_type
);
749 /* Sanity check that we are in sync with what get_alias_set does. */
750 gcc_checking_assert ((!base_type
&& !ao_ref_base_alias_set (ref
))
751 || get_alias_set (base_type
)
752 == ao_ref_base_alias_set (ref
));
753 gcc_checking_assert ((!ref_type
&& !ao_ref_alias_set (ref
))
754 || get_alias_set (ref_type
)
755 == ao_ref_alias_set (ref
));
757 /* Do not bother to record types that have no meaningful alias set.
758 Also skip variably modified types since these go to local streams. */
759 if (base_type
&& (!get_alias_set (base_type
)
760 || variably_modified_type_p (base_type
, NULL_TREE
)))
761 base_type
= NULL_TREE
;
762 if (ref_type
&& (!get_alias_set (ref_type
)
763 || variably_modified_type_p (ref_type
, NULL_TREE
)))
764 ref_type
= NULL_TREE
;
766 modref_access_node a
= get_access (ref
);
769 fprintf (dump_file
, " - Recording base type:");
770 print_generic_expr (dump_file
, base_type
);
771 fprintf (dump_file
, " (alias set %i) ref type:",
772 base_type
? get_alias_set (base_type
) : 0);
773 print_generic_expr (dump_file
, ref_type
);
774 fprintf (dump_file
, " (alias set %i) parm:%i\n",
775 ref_type
? get_alias_set (ref_type
) : 0,
779 tt
->insert (base_type
, ref_type
, a
, false);
782 /* Returns true if and only if we should store the access to EXPR.
783 Some accesses, e.g. loads from automatic variables, are not interesting. */
786 record_access_p (tree expr
)
788 if (refs_local_or_readonly_memory_p (expr
))
791 fprintf (dump_file
, " - Read-only or local, ignoring.\n");
797 /* Return true if ECF flags says that return value can be ignored. */
800 ignore_retval_p (tree caller
, int flags
)
802 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
803 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
808 /* Return true if ECF flags says that stores can be ignored. */
811 ignore_stores_p (tree caller
, int flags
)
813 if (flags
& (ECF_PURE
| ECF_CONST
| ECF_NOVOPS
))
815 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
816 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
821 /* Determine parm_map for argument I of STMT. */
824 parm_map_for_arg (gimple
*stmt
, int i
)
826 tree op
= gimple_call_arg (stmt
, i
);
829 struct modref_parm_map parm_map
;
831 parm_map
.parm_offset_known
= false;
832 parm_map
.parm_offset
= 0;
834 offset_known
= unadjusted_ptr_and_unit_offset (op
, &op
, &offset
);
835 if (TREE_CODE (op
) == SSA_NAME
836 && SSA_NAME_IS_DEFAULT_DEF (op
)
837 && TREE_CODE (SSA_NAME_VAR (op
)) == PARM_DECL
)
840 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
841 t
!= SSA_NAME_VAR (op
); t
= DECL_CHAIN (t
))
850 parm_map
.parm_index
= index
;
851 parm_map
.parm_offset_known
= offset_known
;
852 parm_map
.parm_offset
= offset
;
854 else if (points_to_local_or_readonly_memory_p (op
))
855 parm_map
.parm_index
= -2;
857 parm_map
.parm_index
= -1;
861 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
862 int CUR_SUMMARY. Return true if something changed.
863 If IGNORE_STORES is true, do not merge stores.
864 If RECORD_ADJUSTMENTS is true cap number of adjustments to
865 a given access to make dataflow finite. */
868 merge_call_side_effects (modref_summary
*cur_summary
,
869 gimple
*stmt
, modref_summary
*callee_summary
,
870 bool ignore_stores
, cgraph_node
*callee_node
,
871 bool record_adjustments
)
873 auto_vec
<modref_parm_map
, 32> parm_map
;
874 bool changed
= false;
876 /* We can not safely optimize based on summary of callee if it does
877 not always bind to current def: it is possible that memory load
878 was optimized out earlier which may not happen in the interposed
880 if (!callee_node
->binds_to_current_def_p ())
883 fprintf (dump_file
, " - May be interposed: collapsing loads.\n");
884 cur_summary
->loads
->collapse ();
888 fprintf (dump_file
, " - Merging side effects of %s with parm map:",
889 callee_node
->dump_name ());
891 parm_map
.safe_grow_cleared (gimple_call_num_args (stmt
), true);
892 for (unsigned i
= 0; i
< gimple_call_num_args (stmt
); i
++)
894 parm_map
[i
] = parm_map_for_arg (stmt
, i
);
897 fprintf (dump_file
, " %i", parm_map
[i
].parm_index
);
898 if (parm_map
[i
].parm_offset_known
)
900 fprintf (dump_file
, " offset:");
901 print_dec ((poly_int64_pod
)parm_map
[i
].parm_offset
,
907 fprintf (dump_file
, "\n");
909 /* Merge with callee's summary. */
910 changed
|= cur_summary
->loads
->merge (callee_summary
->loads
, &parm_map
,
914 changed
|= cur_summary
->stores
->merge (callee_summary
->stores
,
917 if (!cur_summary
->writes_errno
918 && callee_summary
->writes_errno
)
920 cur_summary
->writes_errno
= true;
927 /* Return access mode for argument I of call STMT with FNSPEC. */
929 static modref_access_node
930 get_access_for_fnspec (gcall
*call
, attr_fnspec
&fnspec
,
931 unsigned int i
, modref_parm_map
&map
)
933 tree size
= NULL_TREE
;
934 unsigned int size_arg
;
936 if (!fnspec
.arg_specified_p (i
))
938 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
939 size
= gimple_call_arg (call
, size_arg
);
940 else if (fnspec
.arg_access_size_given_by_type_p (i
))
942 tree callee
= gimple_call_fndecl (call
);
943 tree t
= TYPE_ARG_TYPES (TREE_TYPE (callee
));
945 for (unsigned int p
= 0; p
< i
; p
++)
947 size
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t
)));
949 modref_access_node a
= {0, -1, -1,
950 map
.parm_offset
, map
.parm_index
,
951 map
.parm_offset_known
, 0};
954 && poly_int_tree_p (size
, &size_hwi
)
955 && coeffs_in_range_p (size_hwi
, 0,
956 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
959 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
964 /* Collapse loads and return true if something changed. */
967 collapse_loads (modref_summary
*cur_summary
,
968 modref_summary_lto
*cur_summary_lto
)
970 bool changed
= false;
972 if (cur_summary
&& !cur_summary
->loads
->every_base
)
974 cur_summary
->loads
->collapse ();
978 && !cur_summary_lto
->loads
->every_base
)
980 cur_summary_lto
->loads
->collapse ();
986 /* Collapse loads and return true if something changed. */
989 collapse_stores (modref_summary
*cur_summary
,
990 modref_summary_lto
*cur_summary_lto
)
992 bool changed
= false;
994 if (cur_summary
&& !cur_summary
->stores
->every_base
)
996 cur_summary
->stores
->collapse ();
1000 && !cur_summary_lto
->stores
->every_base
)
1002 cur_summary_lto
->stores
->collapse ();
1009 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
1010 If IGNORE_STORES is true ignore them.
1011 Return false if no useful summary can be produced. */
1014 process_fnspec (modref_summary
*cur_summary
,
1015 modref_summary_lto
*cur_summary_lto
,
1016 gcall
*call
, bool ignore_stores
)
1018 attr_fnspec fnspec
= gimple_call_fnspec (call
);
1019 if (!fnspec
.known_p ())
1021 if (dump_file
&& gimple_call_builtin_p (call
, BUILT_IN_NORMAL
))
1022 fprintf (dump_file
, " Builtin with no fnspec: %s\n",
1023 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call
))));
1026 collapse_loads (cur_summary
, cur_summary_lto
);
1031 if (fnspec
.global_memory_read_p ())
1032 collapse_loads (cur_summary
, cur_summary_lto
);
1035 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1036 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1038 else if (!fnspec
.arg_specified_p (i
)
1039 || fnspec
.arg_maybe_read_p (i
))
1041 modref_parm_map map
= parm_map_for_arg (call
, i
);
1043 if (map
.parm_index
== -2)
1045 if (map
.parm_index
== -1)
1047 collapse_loads (cur_summary
, cur_summary_lto
);
1051 cur_summary
->loads
->insert (0, 0,
1052 get_access_for_fnspec (call
,
1056 if (cur_summary_lto
)
1057 cur_summary_lto
->loads
->insert (0, 0,
1058 get_access_for_fnspec (call
,
1066 if (fnspec
.global_memory_written_p ())
1067 collapse_stores (cur_summary
, cur_summary_lto
);
1070 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
1071 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
1073 else if (!fnspec
.arg_specified_p (i
)
1074 || fnspec
.arg_maybe_written_p (i
))
1076 modref_parm_map map
= parm_map_for_arg (call
, i
);
1078 if (map
.parm_index
== -2)
1080 if (map
.parm_index
== -1)
1082 collapse_stores (cur_summary
, cur_summary_lto
);
1086 cur_summary
->stores
->insert (0, 0,
1087 get_access_for_fnspec (call
,
1091 if (cur_summary_lto
)
1092 cur_summary_lto
->stores
->insert (0, 0,
1093 get_access_for_fnspec (call
,
1098 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
1101 cur_summary
->writes_errno
= true;
1102 if (cur_summary_lto
)
1103 cur_summary_lto
->writes_errno
= true;
1109 /* Analyze function call STMT in function F.
1110 Remember recursive calls in RECURSIVE_CALLS. */
1113 analyze_call (modref_summary
*cur_summary
, modref_summary_lto
*cur_summary_lto
,
1114 gcall
*stmt
, vec
<gimple
*> *recursive_calls
)
1116 /* Check flags on the function call. In certain cases, analysis can be
1118 int flags
= gimple_call_flags (stmt
);
1119 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
1123 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
1124 "except for args.\n");
1128 /* Pure functions do not affect global memory. Stores by functions which are
1129 noreturn and do not throw can safely be ignored. */
1130 bool ignore_stores
= ignore_stores_p (current_function_decl
, flags
);
1132 /* Next, we try to get the callee's function declaration. The goal is to
1133 merge their summary with ours. */
1134 tree callee
= gimple_call_fndecl (stmt
);
1136 /* Check if this is an indirect call. */
1140 fprintf (dump_file
, gimple_call_internal_p (stmt
)
1141 ? " - Internal call" : " - Indirect call.\n");
1142 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1144 /* We only need to handle internal calls in IPA mode. */
1145 gcc_checking_assert (!cur_summary_lto
);
1147 struct cgraph_node
*callee_node
= cgraph_node::get_create (callee
);
1149 /* If this is a recursive call, the target summary is the same as ours, so
1150 there's nothing to do. */
1151 if (recursive_call_p (current_function_decl
, callee
))
1153 recursive_calls
->safe_push (stmt
);
1155 fprintf (dump_file
, " - Skipping recursive call.\n");
1159 gcc_assert (callee_node
!= NULL
);
1161 /* Get the function symbol and its availability. */
1162 enum availability avail
;
1163 callee_node
= callee_node
->function_symbol (&avail
);
1164 if (avail
<= AVAIL_INTERPOSABLE
)
1167 fprintf (dump_file
, " - Function availability <= AVAIL_INTERPOSABLE.\n");
1168 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1171 /* Get callee's modref summary. As above, if there's no summary, we either
1172 have to give up or, if stores are ignored, we can just purge loads. */
1173 modref_summary
*callee_summary
= optimization_summaries
->get (callee_node
);
1174 if (!callee_summary
)
1177 fprintf (dump_file
, " - No modref summary available for callee.\n");
1178 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
1181 merge_call_side_effects (cur_summary
, stmt
, callee_summary
, ignore_stores
,
1182 callee_node
, false);
1187 /* Support analysis in non-lto and lto mode in parallel. */
1191 struct modref_summary
*nolto
;
1192 struct modref_summary_lto
*lto
;
1195 /* Helper for analyze_stmt. */
1198 analyze_load (gimple
*, tree
, tree op
, void *data
)
1200 modref_summary
*summary
= ((summary_ptrs
*)data
)->nolto
;
1201 modref_summary_lto
*summary_lto
= ((summary_ptrs
*)data
)->lto
;
1205 fprintf (dump_file
, " - Analyzing load: ");
1206 print_generic_expr (dump_file
, op
);
1207 fprintf (dump_file
, "\n");
1210 if (!record_access_p (op
))
1214 ao_ref_init (&r
, op
);
1217 record_access (summary
->loads
, &r
);
1219 record_access_lto (summary_lto
->loads
, &r
);
1223 /* Helper for analyze_stmt. */
1226 analyze_store (gimple
*, tree
, tree op
, void *data
)
1228 modref_summary
*summary
= ((summary_ptrs
*)data
)->nolto
;
1229 modref_summary_lto
*summary_lto
= ((summary_ptrs
*)data
)->lto
;
1233 fprintf (dump_file
, " - Analyzing store: ");
1234 print_generic_expr (dump_file
, op
);
1235 fprintf (dump_file
, "\n");
1238 if (!record_access_p (op
))
1242 ao_ref_init (&r
, op
);
1245 record_access (summary
->stores
, &r
);
1247 record_access_lto (summary_lto
->stores
, &r
);
1251 /* Analyze statement STMT of function F.
1252 If IPA is true do not merge in side effects of calls. */
1255 analyze_stmt (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
1256 gimple
*stmt
, bool ipa
, vec
<gimple
*> *recursive_calls
)
1258 /* In general we can not ignore clobbers because they are barriers for code
1259 motion, however after inlining it is safe to do because local optimization
1260 passes do not consider clobbers from other functions.
1261 Similar logic is in ipa-pure-const.c. */
1262 if ((ipa
|| cfun
->after_inlining
) && gimple_clobber_p (stmt
))
1265 struct summary_ptrs sums
= {summary
, summary_lto
};
1267 /* Analyze all loads and stores in STMT. */
1268 walk_stmt_load_store_ops (stmt
, &sums
,
1269 analyze_load
, analyze_store
);
1271 switch (gimple_code (stmt
))
1274 /* If the ASM statement does not read nor write memory, there's nothing
1275 to do. Otherwise just give up. */
1276 if (!gimple_asm_clobbers_memory_p (as_a
<gasm
*> (stmt
)))
1279 fprintf (dump_file
, " - Function contains GIMPLE_ASM statement "
1280 "which clobbers memory.\n");
1283 if (!ipa
|| gimple_call_internal_p (stmt
))
1284 return analyze_call (summary
, summary_lto
,
1285 as_a
<gcall
*> (stmt
), recursive_calls
);
1288 attr_fnspec fnspec
= gimple_call_fnspec (as_a
<gcall
*>(stmt
));
1290 if (fnspec
.known_p ()
1291 && (!fnspec
.global_memory_read_p ()
1292 || !fnspec
.global_memory_written_p ()))
1294 cgraph_edge
*e
= cgraph_node::get (current_function_decl
)->get_edge (stmt
);
1297 fnspec_summaries
->get_create (e
)->fnspec
= xstrdup (fnspec
.get_str ());
1299 fprintf (dump_file
, " Recorded fnspec %s\n", fnspec
.get_str ());
1305 /* Nothing to do for other types of statements. */
1310 /* Remove summary of current function because during the function body
1311 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1315 remove_summary (bool lto
, bool nolto
, bool ipa
)
1317 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1319 optimization_summaries
->remove (fnode
);
1323 summaries
->remove (fnode
);
1325 summaries_lto
->remove (fnode
);
1326 remove_modref_edge_summaries (fnode
);
1330 " - modref done with result: not tracked.\n");
1333 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1336 memory_access_to (tree op
, tree ssa_name
)
1338 tree base
= get_base_address (op
);
1341 if (TREE_CODE (base
) != MEM_REF
&& TREE_CODE (base
) != TARGET_MEM_REF
)
1343 return TREE_OPERAND (base
, 0) == ssa_name
;
1346 /* Consider statement val = *arg.
1347 return EAF flags of ARG that can be determined from EAF flags of VAL
1348 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1349 all stores to VAL, i.e. when handling noreturn function. */
1352 deref_flags (int flags
, bool ignore_stores
)
1354 int ret
= EAF_NODIRECTESCAPE
;
1355 /* If argument is unused just account for
1356 the read involved in dereference. */
1357 if (flags
& EAF_UNUSED
)
1358 ret
|= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_NOT_RETURNED
;
1361 if ((flags
& EAF_NOCLOBBER
) || ignore_stores
)
1362 ret
|= EAF_NOCLOBBER
;
1363 if ((flags
& EAF_NOESCAPE
) || ignore_stores
)
1364 ret
|= EAF_NOESCAPE
;
1365 /* If the value dereferenced is not used for another load or store
1366 we can still consider ARG as used only directly.
1377 if ((flags
& (EAF_NOREAD
| EAF_NOT_RETURNED
| EAF_NOESCAPE
| EAF_DIRECT
))
1378 == (EAF_NOREAD
| EAF_NOT_RETURNED
| EAF_NOESCAPE
| EAF_DIRECT
)
1379 && ((flags
& EAF_NOCLOBBER
) || ignore_stores
))
1381 if (flags
& EAF_NOT_RETURNED
)
1382 ret
|= EAF_NOT_RETURNED
;
1389 /* Description of an escape point. */
1393 /* Value escapes to this call. */
1395 /* Argument it escapes to. */
1397 /* Flags already known about the argument (this can save us from recording
1398 esape points if local analysis did good job already). */
1399 eaf_flags_t min_flags
;
1400 /* Does value escape directly or indiretly? */
1404 class modref_lattice
1407 /* EAF flags of the SSA name. */
1409 /* DFS bookkkeeping: we don't do real dataflow yet. */
1413 /* When doing IPA analysis we can not merge in callee escape points;
1414 Only remember them and do the merging at IPA propagation time. */
1415 vec
<escape_point
, va_heap
, vl_ptr
> escape_points
;
1419 bool merge (const modref_lattice
&with
);
1420 bool merge (int flags
);
1421 bool merge_deref (const modref_lattice
&with
, bool ignore_stores
);
1422 bool merge_direct_load ();
1423 bool merge_direct_store ();
1424 bool add_escape_point (gcall
*call
, int arg
, int min_flags
, bool diret
);
1425 void dump (FILE *out
, int indent
= 0) const;
1428 /* Lattices are saved to vectors, so keep them PODs. */
1430 modref_lattice::init ()
1432 /* All flags we track. */
1433 int f
= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_UNUSED
1434 | EAF_NODIRECTESCAPE
| EAF_NOT_RETURNED
| EAF_NOREAD
;
1436 /* Check that eaf_flags_t is wide enough to hold all flags. */
1437 gcc_checking_assert (f
== flags
);
1442 /* Release memory. */
1444 modref_lattice::release ()
1446 escape_points
.release ();
1449 /* Dump lattice to OUT; indent with INDENT spaces. */
1452 modref_lattice::dump (FILE *out
, int indent
) const
1454 dump_eaf_flags (out
, flags
);
1455 if (escape_points
.length ())
1457 fprintf (out
, "%*sEscapes:\n", indent
, "");
1458 for (unsigned int i
= 0; i
< escape_points
.length (); i
++)
1460 fprintf (out
, "%*s Arg %i (%s) min flags", indent
, "",
1461 escape_points
[i
].arg
,
1462 escape_points
[i
].direct
? "direct" : "indirect");
1463 dump_eaf_flags (out
, escape_points
[i
].min_flags
, false);
1464 fprintf (out
, " in call ");
1465 print_gimple_stmt (out
, escape_points
[i
].call
, 0);
1470 /* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
1474 modref_lattice::add_escape_point (gcall
*call
, int arg
, int min_flags
,
1480 /* If we already determined flags to be bad enough,
1481 we do not need to record. */
1482 if ((flags
& min_flags
) == flags
|| (min_flags
& EAF_UNUSED
))
1485 FOR_EACH_VEC_ELT (escape_points
, i
, ep
)
1486 if (ep
->call
== call
&& ep
->arg
== arg
&& ep
->direct
== direct
)
1488 if ((ep
->min_flags
& min_flags
) == min_flags
)
1490 ep
->min_flags
&= min_flags
;
1493 /* Give up if max escape points is met. */
1494 if ((int)escape_points
.length () > param_modref_max_escape_points
)
1497 fprintf (dump_file
, "--param modref-max-escape-points limit reached\n");
1501 escape_point new_ep
= {call
, arg
, min_flags
, direct
};
1502 escape_points
.safe_push (new_ep
);
1506 /* Merge in flags from F. */
1508 modref_lattice::merge (int f
)
1512 /* Noescape implies that value also does not escape directly.
1513 Fnspec machinery does set both so compensate for this. */
1514 if (f
& EAF_NOESCAPE
)
1515 f
|= EAF_NODIRECTESCAPE
;
1516 if ((flags
& f
) != flags
)
1519 /* Prune obvoiusly useless flags;
1520 We do not have ECF_FLAGS handy which is not big problem since
1521 we will do final flags cleanup before producing summary.
1522 Merging should be fast so it can work well with dataflow. */
1523 flags
= remove_useless_eaf_flags (flags
, 0, false);
1525 escape_points
.release ();
1531 /* Merge in WITH. Return true if anyting changed. */
1534 modref_lattice::merge (const modref_lattice
&with
)
1539 bool changed
= merge (with
.flags
);
1543 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
1544 changed
|= add_escape_point (with
.escape_points
[i
].call
,
1545 with
.escape_points
[i
].arg
,
1546 with
.escape_points
[i
].min_flags
,
1547 with
.escape_points
[i
].direct
);
1551 /* Merge in deref of WITH. If IGNORE_STORES is true do not consider
1552 stores. Return true if anyting changed. */
1555 modref_lattice::merge_deref (const modref_lattice
&with
, bool ignore_stores
)
1560 bool changed
= merge (deref_flags (with
.flags
, ignore_stores
));
1564 for (unsigned int i
= 0; i
< with
.escape_points
.length (); i
++)
1566 int min_flags
= with
.escape_points
[i
].min_flags
;
1568 if (with
.escape_points
[i
].direct
)
1569 min_flags
= deref_flags (min_flags
, ignore_stores
);
1570 else if (ignore_stores
)
1571 min_flags
|= ignore_stores_eaf_flags
;
1572 changed
|= add_escape_point (with
.escape_points
[i
].call
,
1573 with
.escape_points
[i
].arg
,
1580 /* Merge in flags for direct load. */
1583 modref_lattice::merge_direct_load ()
1585 return merge (~(EAF_UNUSED
| EAF_NOREAD
));
1588 /* Merge in flags for direct store. */
1591 modref_lattice::merge_direct_store ()
1593 return merge (~(EAF_UNUSED
| EAF_NOCLOBBER
));
1596 } /* ANON namespace. */
1598 static void analyze_ssa_name_flags (tree name
,
1599 vec
<modref_lattice
> &lattice
,
1600 int depth
, bool ipa
);
1602 /* Call statements may return their parameters. Consider argument number
1603 ARG of USE_STMT and determine flags that can needs to be cleared
1604 in case pointer possibly indirectly references from ARG I is returned.
1605 LATTICE, DEPTH and ipa are same as in analyze_ssa_name_flags. */
1608 merge_call_lhs_flags (gcall
*call
, int arg
, int index
, bool deref
,
1609 vec
<modref_lattice
> &lattice
,
1610 int depth
, bool ipa
)
1612 /* If there is no return value, no flags are affected. */
1613 if (!gimple_call_lhs (call
))
1616 /* If we know that function returns given argument and it is not ARG
1617 we can still be happy. */
1618 int flags
= gimple_call_return_flags (call
);
1619 if ((flags
& ERF_RETURNS_ARG
)
1620 && (flags
& ERF_RETURN_ARG_MASK
) != arg
)
1623 if (gimple_call_arg_flags (call
, arg
) & (EAF_NOT_RETURNED
| EAF_UNUSED
))
1626 /* If return value is SSA name determine its flags. */
1627 if (TREE_CODE (gimple_call_lhs (call
)) == SSA_NAME
)
1629 tree lhs
= gimple_call_lhs (call
);
1630 analyze_ssa_name_flags (lhs
, lattice
, depth
+ 1, ipa
);
1632 lattice
[index
].merge_deref (lattice
[SSA_NAME_VERSION (lhs
)], false);
1634 lattice
[index
].merge (lattice
[SSA_NAME_VERSION (lhs
)]);
1636 /* In the case of memory store we can do nothing. */
1638 lattice
[index
].merge (0);
1641 /* Analyze EAF flags for SSA name NAME and store result to LATTICE.
1642 LATTICE is an array of modref_lattices.
1643 DEPTH is a recursion depth used to make debug output prettier.
1644 If IPA is true we analyze for IPA propagation (and thus call escape points
1645 are processed later) */
1648 analyze_ssa_name_flags (tree name
, vec
<modref_lattice
> &lattice
, int depth
,
1651 imm_use_iterator ui
;
1653 int index
= SSA_NAME_VERSION (name
);
1655 /* See if value is already computed. */
1656 if (lattice
[index
].known
)
1658 if (lattice
[index
].open
)
1662 "%*sGiving up on a cycle in SSA graph\n", depth
* 4, "");
1665 if (depth
== param_modref_max_depth
)
1669 "%*sGiving up on max depth\n", depth
* 4, "");
1672 /* Recursion guard. */
1673 lattice
[index
].init ();
1678 "%*sAnalyzing flags of ssa name: ", depth
* 4, "");
1679 print_generic_expr (dump_file
, name
);
1680 fprintf (dump_file
, "\n");
1683 FOR_EACH_IMM_USE_STMT (use_stmt
, ui
, name
)
1685 if (lattice
[index
].flags
== 0)
1687 if (is_gimple_debug (use_stmt
))
1691 fprintf (dump_file
, "%*s Analyzing stmt: ", depth
* 4, "");
1692 print_gimple_stmt (dump_file
, use_stmt
, 0);
1694 /* If we see a direct non-debug use, clear unused bit.
1695 All dereferneces should be accounted below using deref_flags. */
1696 lattice
[index
].merge (~EAF_UNUSED
);
1698 /* Gimple return may load the return value.
1699 Returning name counts as an use by tree-ssa-structalias.c */
1700 if (greturn
*ret
= dyn_cast
<greturn
*> (use_stmt
))
1702 if (gimple_return_retval (ret
) == name
)
1703 lattice
[index
].merge (~(EAF_UNUSED
| EAF_NOT_RETURNED
));
1704 else if (memory_access_to (gimple_return_retval (ret
), name
))
1706 lattice
[index
].merge_direct_load ();
1707 lattice
[index
].merge (~(EAF_UNUSED
| EAF_NOT_RETURNED
));
1710 /* Account for LHS store, arg loads and flags from callee function. */
1711 else if (gcall
*call
= dyn_cast
<gcall
*> (use_stmt
))
1713 tree callee
= gimple_call_fndecl (call
);
1715 /* IPA PTA internally it treats calling a function as "writing" to
1716 the argument space of all functions the function pointer points to
1717 (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
1718 is on since that would allow propagation of this from -fno-ipa-pta
1719 to -fipa-pta functions. */
1720 if (gimple_call_fn (use_stmt
) == name
)
1721 lattice
[index
].merge (~(EAF_NOCLOBBER
| EAF_UNUSED
));
1723 /* Recursion would require bit of propagation; give up for now. */
1724 if (callee
&& !ipa
&& recursive_call_p (current_function_decl
,
1726 lattice
[index
].merge (0);
1729 int ecf_flags
= gimple_call_flags (call
);
1730 bool ignore_stores
= ignore_stores_p (current_function_decl
,
1732 bool ignore_retval
= ignore_retval_p (current_function_decl
,
1735 /* Handle *name = func (...). */
1736 if (gimple_call_lhs (call
)
1737 && memory_access_to (gimple_call_lhs (call
), name
))
1739 lattice
[index
].merge_direct_store ();
1740 /* Return slot optimization passes address of
1741 LHS to callee via hidden parameter and this
1742 may make LHS to escape. See PR 98499. */
1743 if (gimple_call_return_slot_opt_p (call
)
1744 && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call
))))
1745 lattice
[index
].merge (EAF_NOREAD
| EAF_DIRECT
);
1748 /* We do not track accesses to the static chain (we could)
1750 if (gimple_call_chain (call
)
1751 && (gimple_call_chain (call
) == name
))
1752 lattice
[index
].merge (0);
1754 /* Process internal functions and right away. */
1755 bool record_ipa
= ipa
&& !gimple_call_internal_p (call
);
1757 /* Handle all function parameters. */
1758 for (unsigned i
= 0;
1759 i
< gimple_call_num_args (call
) && lattice
[index
].flags
; i
++)
1760 /* Name is directly passed to the callee. */
1761 if (gimple_call_arg (call
, i
) == name
)
1763 if (!(ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)))
1765 int call_flags
= gimple_call_arg_flags (call
, i
)
1768 call_flags
|= ignore_stores_eaf_flags
;
1771 lattice
[index
].merge (call_flags
);
1773 lattice
[index
].add_escape_point (call
, i
,
1777 merge_call_lhs_flags (call
, i
, index
, false,
1778 lattice
, depth
, ipa
);
1780 /* Name is dereferenced and passed to a callee. */
1781 else if (memory_access_to (gimple_call_arg (call
, i
), name
))
1783 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
1784 lattice
[index
].merge_direct_load ();
1787 int call_flags
= deref_flags
1788 (gimple_call_arg_flags (call
, i
)
1789 | EAF_NOT_RETURNED
, ignore_stores
);
1791 lattice
[index
].merge (call_flags
);
1793 lattice
[index
].add_escape_point (call
, i
,
1797 merge_call_lhs_flags (call
, i
, index
, true,
1798 lattice
, depth
, ipa
);
1802 else if (gimple_assign_load_p (use_stmt
))
1804 gassign
*assign
= as_a
<gassign
*> (use_stmt
);
1805 /* Memory to memory copy. */
1806 if (gimple_store_p (assign
))
1808 /* Handle *lhs = *name.
1810 We do not track memory locations, so assume that value
1811 is used arbitrarily. */
1812 if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
1813 lattice
[index
].merge (0);
1814 /* Handle *name = *exp. */
1815 else if (memory_access_to (gimple_assign_lhs (assign
), name
))
1816 lattice
[index
].merge_direct_store ();
1818 /* Handle lhs = *name. */
1819 else if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
1821 tree lhs
= gimple_assign_lhs (assign
);
1822 analyze_ssa_name_flags (lhs
, lattice
, depth
+ 1, ipa
);
1823 lattice
[index
].merge_deref (lattice
[SSA_NAME_VERSION (lhs
)],
1827 else if (gimple_store_p (use_stmt
))
1829 gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
);
1831 /* Handle *lhs = name. */
1832 if (assign
&& gimple_assign_rhs1 (assign
) == name
)
1835 fprintf (dump_file
, "%*s ssa name saved to memory\n",
1837 lattice
[index
].merge (0);
1839 /* Handle *name = exp. */
1841 && memory_access_to (gimple_assign_lhs (assign
), name
))
1843 /* In general we can not ignore clobbers because they are
1844 barriers for code motion, however after inlining it is safe to
1845 do because local optimization passes do not consider clobbers
1846 from other functions. Similar logic is in ipa-pure-const.c. */
1847 if (!cfun
->after_inlining
|| !gimple_clobber_p (assign
))
1848 lattice
[index
].merge_direct_store ();
1850 /* ASM statements etc. */
1854 fprintf (dump_file
, "%*s Unhandled store\n",
1856 lattice
[index
].merge (0);
1859 else if (gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
))
1861 enum tree_code code
= gimple_assign_rhs_code (assign
);
1863 /* See if operation is a merge as considered by
1864 tree-ssa-structalias.c:find_func_aliases. */
1865 if (!truth_value_p (code
)
1866 && code
!= POINTER_DIFF_EXPR
1867 && (code
!= POINTER_PLUS_EXPR
1868 || gimple_assign_rhs1 (assign
) == name
))
1870 tree lhs
= gimple_assign_lhs (assign
);
1871 analyze_ssa_name_flags (lhs
, lattice
, depth
+ 1, ipa
);
1872 lattice
[index
].merge (lattice
[SSA_NAME_VERSION (lhs
)]);
1875 else if (gphi
*phi
= dyn_cast
<gphi
*> (use_stmt
))
1877 tree result
= gimple_phi_result (phi
);
1878 analyze_ssa_name_flags (result
, lattice
, depth
+ 1, ipa
);
1879 lattice
[index
].merge (lattice
[SSA_NAME_VERSION (result
)]);
1881 /* Conditions are not considered escape points
1882 by tree-ssa-structalias. */
1883 else if (gimple_code (use_stmt
) == GIMPLE_COND
)
1888 fprintf (dump_file
, "%*s Unhandled stmt\n", depth
* 4, "");
1889 lattice
[index
].merge (0);
1894 fprintf (dump_file
, "%*s current flags of ", depth
* 4, "");
1895 print_generic_expr (dump_file
, name
);
1896 lattice
[index
].dump (dump_file
, depth
* 4 + 4);
1901 fprintf (dump_file
, "%*sflags of ssa name ", depth
* 4, "");
1902 print_generic_expr (dump_file
, name
);
1903 lattice
[index
].dump (dump_file
, depth
* 4 + 2);
1905 lattice
[index
].open
= false;
1906 lattice
[index
].known
= true;
1909 /* Determine EAF flags for function parameters. */
1912 analyze_parms (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
1915 unsigned int parm_index
= 0;
1916 unsigned int count
= 0;
1917 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
1919 /* For novops functions we have nothing to gain by EAF flags. */
1920 if (ecf_flags
& ECF_NOVOPS
)
1923 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
1924 parm
= TREE_CHAIN (parm
))
1930 auto_vec
<modref_lattice
> lattice
;
1931 lattice
.safe_grow_cleared (num_ssa_names
, true);
1933 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
; parm_index
++,
1934 parm
= TREE_CHAIN (parm
))
1936 tree name
= ssa_default_def (cfun
, parm
);
1937 if (!name
|| has_zero_uses (name
))
1939 /* We do not track non-SSA parameters,
1940 but we want to track unused gimple_regs. */
1941 if (!is_gimple_reg (parm
))
1945 if (parm_index
>= summary
->arg_flags
.length ())
1946 summary
->arg_flags
.safe_grow_cleared (count
, true);
1947 summary
->arg_flags
[parm_index
] = EAF_UNUSED
;
1949 else if (summary_lto
)
1951 if (parm_index
>= summary_lto
->arg_flags
.length ())
1952 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
1953 summary_lto
->arg_flags
[parm_index
] = EAF_UNUSED
;
1957 analyze_ssa_name_flags (name
, lattice
, 0, ipa
);
1958 int flags
= lattice
[SSA_NAME_VERSION (name
)].flags
;
1960 /* Eliminate useless flags so we do not end up storing unnecessary
1963 flags
= remove_useless_eaf_flags
1965 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl
))));
1971 if (parm_index
>= summary
->arg_flags
.length ())
1972 summary
->arg_flags
.safe_grow_cleared (count
, true);
1973 summary
->arg_flags
[parm_index
] = flags
;
1975 else if (summary_lto
)
1977 if (parm_index
>= summary_lto
->arg_flags
.length ())
1978 summary_lto
->arg_flags
.safe_grow_cleared (count
, true);
1979 summary_lto
->arg_flags
[parm_index
] = flags
;
1981 if (lattice
[SSA_NAME_VERSION (name
)].escape_points
.length ())
1985 cgraph_node
*node
= cgraph_node::get (current_function_decl
);
1987 gcc_checking_assert (ipa
);
1989 (lattice
[SSA_NAME_VERSION (name
)].escape_points
, ip
, ep
)
1990 if ((ep
->min_flags
& flags
) != flags
)
1992 cgraph_edge
*e
= node
->get_edge (ep
->call
);
1993 struct escape_entry ee
= {parm_index
, ep
->arg
,
1994 ep
->min_flags
, ep
->direct
};
1996 escape_summaries
->get_create (e
)->esc
.safe_push (ee
);
2002 for (unsigned int i
= 0; i
< num_ssa_names
; i
++)
2003 lattice
[i
].release ();
2006 /* Analyze function F. IPA indicates whether we're running in local mode
2007 (false) or the IPA mode (true). */
2010 analyze_function (function
*f
, bool ipa
)
2013 fprintf (dump_file
, "modref analyzing '%s' (ipa=%i)%s%s\n",
2014 function_name (f
), ipa
,
2015 TREE_READONLY (current_function_decl
) ? " (const)" : "",
2016 DECL_PURE_P (current_function_decl
) ? " (pure)" : "");
2018 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
2019 if (!flag_ipa_modref
)
2022 /* Compute no-LTO summaries when local optimization is going to happen. */
2023 bool nolto
= (!ipa
|| ((!flag_lto
|| flag_fat_lto_objects
) && !in_lto_p
)
2024 || (in_lto_p
&& !flag_wpa
2025 && flag_incremental_link
!= INCREMENTAL_LINK_LTO
));
2026 /* Compute LTO when LTO streaming is going to happen. */
2027 bool lto
= ipa
&& ((flag_lto
&& !in_lto_p
)
2029 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
2030 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
2032 modref_summary
*summary
= NULL
;
2033 modref_summary_lto
*summary_lto
= NULL
;
2035 /* Initialize the summary.
2036 If we run in local mode there is possibly pre-existing summary from
2037 IPA pass. Dump it so it is easy to compare if mod-ref info has
2041 if (!optimization_summaries
)
2042 optimization_summaries
= modref_summaries::create_ggc (symtab
);
2043 else /* Remove existing summary if we are re-running the pass. */
2047 = optimization_summaries
->get (cgraph_node::get (f
->decl
)))
2051 fprintf (dump_file
, "Past summary:\n");
2052 optimization_summaries
->get
2053 (cgraph_node::get (f
->decl
))->dump (dump_file
);
2055 optimization_summaries
->remove (cgraph_node::get (f
->decl
));
2057 summary
= optimization_summaries
->get_create (cgraph_node::get (f
->decl
));
2058 gcc_checking_assert (nolto
&& !lto
);
2060 /* In IPA mode we analyze every function precisely once. Assert that. */
2066 summaries
= modref_summaries::create_ggc (symtab
);
2068 summaries
->remove (cgraph_node::get (f
->decl
));
2069 summary
= summaries
->get_create (cgraph_node::get (f
->decl
));
2074 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
2076 summaries_lto
->remove (cgraph_node::get (f
->decl
));
2077 summary_lto
= summaries_lto
->get_create (cgraph_node::get (f
->decl
));
2079 if (!fnspec_summaries
)
2080 fnspec_summaries
= new fnspec_summaries_t (symtab
);
2081 if (!escape_summaries
)
2082 escape_summaries
= new escape_summaries_t (symtab
);
2086 /* Create and initialize summary for F.
2087 Note that summaries may be already allocated from previous
2091 gcc_assert (!summary
->loads
);
2092 summary
->loads
= modref_records::create_ggc (param_modref_max_bases
,
2093 param_modref_max_refs
,
2094 param_modref_max_accesses
);
2095 gcc_assert (!summary
->stores
);
2096 summary
->stores
= modref_records::create_ggc (param_modref_max_bases
,
2097 param_modref_max_refs
,
2098 param_modref_max_accesses
);
2099 summary
->writes_errno
= false;
2103 gcc_assert (!summary_lto
->loads
);
2104 summary_lto
->loads
= modref_records_lto::create_ggc
2105 (param_modref_max_bases
,
2106 param_modref_max_refs
,
2107 param_modref_max_accesses
);
2108 gcc_assert (!summary_lto
->stores
);
2109 summary_lto
->stores
= modref_records_lto::create_ggc
2110 (param_modref_max_bases
,
2111 param_modref_max_refs
,
2112 param_modref_max_accesses
);
2113 summary_lto
->writes_errno
= false;
2116 analyze_parms (summary
, summary_lto
, ipa
);
2118 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
2119 auto_vec
<gimple
*, 32> recursive_calls
;
2121 /* Analyze each statement in each basic block of the function. If the
2122 statement cannot be analyzed (for any reason), the entire function cannot
2123 be analyzed by modref. */
2125 FOR_EACH_BB_FN (bb
, f
)
2127 gimple_stmt_iterator si
;
2128 for (si
= gsi_start_nondebug_after_labels_bb (bb
);
2129 !gsi_end_p (si
); gsi_next_nondebug (&si
))
2131 if (!analyze_stmt (summary
, summary_lto
,
2132 gsi_stmt (si
), ipa
, &recursive_calls
)
2133 || ((!summary
|| !summary
->useful_p (ecf_flags
, false))
2135 || !summary_lto
->useful_p (ecf_flags
, false))))
2137 collapse_loads (summary
, summary_lto
);
2138 collapse_stores (summary
, summary_lto
);
2144 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
2145 This needs to be done after all other side effects are computed. */
2148 bool changed
= true;
2153 for (unsigned i
= 0; i
< recursive_calls
.length (); i
++)
2155 changed
|= merge_call_side_effects
2156 (summary
, recursive_calls
[i
], summary
,
2157 ignore_stores_p (current_function_decl
,
2159 (recursive_calls
[i
])),
2161 if (!summary
->useful_p (ecf_flags
, false))
2163 remove_summary (lto
, nolto
, ipa
);
2170 if (summary
&& !summary
->useful_p (ecf_flags
))
2173 optimization_summaries
->remove (fnode
);
2175 summaries
->remove (fnode
);
2178 if (summary_lto
&& !summary_lto
->useful_p (ecf_flags
))
2180 summaries_lto
->remove (fnode
);
2183 if (ipa
&& !summary
&& !summary_lto
)
2184 remove_modref_edge_summaries (fnode
);
2188 fprintf (dump_file
, " - modref done with result: tracked.\n");
2190 summary
->dump (dump_file
);
2192 summary_lto
->dump (dump_file
);
2193 dump_modref_edge_summaries (dump_file
, fnode
, 2);
2197 /* Callback for generate_summary. */
2200 modref_generate (void)
2202 struct cgraph_node
*node
;
2203 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
2205 function
*f
= DECL_STRUCT_FUNCTION (node
->decl
);
2209 analyze_function (f
, true);
2214 /* Called when a new function is inserted to callgraph late. */
2217 modref_summaries::insert (struct cgraph_node
*node
, modref_summary
*)
2219 /* Local passes ought to be executed by the pass manager. */
2220 if (this == optimization_summaries
)
2222 optimization_summaries
->remove (node
);
2225 if (!DECL_STRUCT_FUNCTION (node
->decl
)
2226 || !opt_for_fn (node
->decl
, flag_ipa_modref
))
2228 summaries
->remove (node
);
2231 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
2232 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
2236 /* Called when a new function is inserted to callgraph late. */
2239 modref_summaries_lto::insert (struct cgraph_node
*node
, modref_summary_lto
*)
2241 /* We do not support adding new function when IPA information is already
2242 propagated. This is done only by SIMD cloning that is not very
2244 if (!DECL_STRUCT_FUNCTION (node
->decl
)
2245 || !opt_for_fn (node
->decl
, flag_ipa_modref
)
2248 summaries_lto
->remove (node
);
2251 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
2252 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
2256 /* Called when new clone is inserted to callgraph late. */
2259 modref_summaries::duplicate (cgraph_node
*, cgraph_node
*dst
,
2260 modref_summary
*src_data
,
2261 modref_summary
*dst_data
)
2263 /* Do not duplicate optimization summaries; we do not handle parameter
2264 transforms on them. */
2265 if (this == optimization_summaries
)
2267 optimization_summaries
->remove (dst
);
2270 dst_data
->stores
= modref_records::create_ggc
2271 (src_data
->stores
->max_bases
,
2272 src_data
->stores
->max_refs
,
2273 src_data
->stores
->max_accesses
);
2274 dst_data
->stores
->copy_from (src_data
->stores
);
2275 dst_data
->loads
= modref_records::create_ggc
2276 (src_data
->loads
->max_bases
,
2277 src_data
->loads
->max_refs
,
2278 src_data
->loads
->max_accesses
);
2279 dst_data
->loads
->copy_from (src_data
->loads
);
2280 dst_data
->writes_errno
= src_data
->writes_errno
;
2281 if (src_data
->arg_flags
.length ())
2282 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
2285 /* Called when new clone is inserted to callgraph late. */
2288 modref_summaries_lto::duplicate (cgraph_node
*, cgraph_node
*,
2289 modref_summary_lto
*src_data
,
2290 modref_summary_lto
*dst_data
)
2292 /* Be sure that no further cloning happens after ipa-modref. If it does
2293 we will need to update signatures for possible param changes. */
2294 gcc_checking_assert (!((modref_summaries_lto
*)summaries_lto
)->propagated
);
2295 dst_data
->stores
= modref_records_lto::create_ggc
2296 (src_data
->stores
->max_bases
,
2297 src_data
->stores
->max_refs
,
2298 src_data
->stores
->max_accesses
);
2299 dst_data
->stores
->copy_from (src_data
->stores
);
2300 dst_data
->loads
= modref_records_lto::create_ggc
2301 (src_data
->loads
->max_bases
,
2302 src_data
->loads
->max_refs
,
2303 src_data
->loads
->max_accesses
);
2304 dst_data
->loads
->copy_from (src_data
->loads
);
2305 dst_data
->writes_errno
= src_data
->writes_errno
;
2306 if (src_data
->arg_flags
.length ())
2307 dst_data
->arg_flags
= src_data
->arg_flags
.copy ();
2312 /* Definition of the modref pass on GIMPLE. */
2313 const pass_data pass_data_modref
= {
2318 (PROP_cfg
| PROP_ssa
),
2325 class pass_modref
: public gimple_opt_pass
2328 pass_modref (gcc::context
*ctxt
)
2329 : gimple_opt_pass (pass_data_modref
, ctxt
) {}
2331 /* opt_pass methods: */
2334 return new pass_modref (m_ctxt
);
2336 virtual bool gate (function
*)
2338 return flag_ipa_modref
;
2340 virtual unsigned int execute (function
*);
2343 /* Encode TT to the output block OB using the summary streaming API. */
2346 write_modref_records (modref_records_lto
*tt
, struct output_block
*ob
)
2348 streamer_write_uhwi (ob
, tt
->max_bases
);
2349 streamer_write_uhwi (ob
, tt
->max_refs
);
2350 streamer_write_uhwi (ob
, tt
->max_accesses
);
2352 streamer_write_uhwi (ob
, tt
->every_base
);
2353 streamer_write_uhwi (ob
, vec_safe_length (tt
->bases
));
2355 modref_base_node
<tree
> *base_node
;
2356 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, base_node
)
2358 stream_write_tree (ob
, base_node
->base
, true);
2360 streamer_write_uhwi (ob
, base_node
->every_ref
);
2361 streamer_write_uhwi (ob
, vec_safe_length (base_node
->refs
));
2364 modref_ref_node
<tree
> *ref_node
;
2365 FOR_EACH_VEC_SAFE_ELT (base_node
->refs
, j
, ref_node
)
2367 stream_write_tree (ob
, ref_node
->ref
, true);
2368 streamer_write_uhwi (ob
, ref_node
->every_access
);
2369 streamer_write_uhwi (ob
, vec_safe_length (ref_node
->accesses
));
2372 modref_access_node
*access_node
;
2373 FOR_EACH_VEC_SAFE_ELT (ref_node
->accesses
, k
, access_node
)
2375 streamer_write_hwi (ob
, access_node
->parm_index
);
2376 if (access_node
->parm_index
!= -1)
2378 streamer_write_uhwi (ob
, access_node
->parm_offset_known
);
2379 if (access_node
->parm_offset_known
)
2381 streamer_write_poly_int64 (ob
, access_node
->parm_offset
);
2382 streamer_write_poly_int64 (ob
, access_node
->offset
);
2383 streamer_write_poly_int64 (ob
, access_node
->size
);
2384 streamer_write_poly_int64 (ob
, access_node
->max_size
);
2392 /* Read a modref_tree from the input block IB using the data from DATA_IN.
2393 This assumes that the tree was encoded using write_modref_tree.
2394 Either nolto_ret or lto_ret is initialized by the tree depending whether
2395 LTO streaming is expected or not. */
2398 read_modref_records (lto_input_block
*ib
, struct data_in
*data_in
,
2399 modref_records
**nolto_ret
,
2400 modref_records_lto
**lto_ret
)
2402 size_t max_bases
= streamer_read_uhwi (ib
);
2403 size_t max_refs
= streamer_read_uhwi (ib
);
2404 size_t max_accesses
= streamer_read_uhwi (ib
);
2407 *lto_ret
= modref_records_lto::create_ggc (max_bases
, max_refs
,
2410 *nolto_ret
= modref_records::create_ggc (max_bases
, max_refs
,
2412 gcc_checking_assert (lto_ret
|| nolto_ret
);
2414 size_t every_base
= streamer_read_uhwi (ib
);
2415 size_t nbase
= streamer_read_uhwi (ib
);
2417 gcc_assert (!every_base
|| nbase
== 0);
2421 (*nolto_ret
)->collapse ();
2423 (*lto_ret
)->collapse ();
2425 for (size_t i
= 0; i
< nbase
; i
++)
2427 tree base_tree
= stream_read_tree (ib
, data_in
);
2428 modref_base_node
<alias_set_type
> *nolto_base_node
= NULL
;
2429 modref_base_node
<tree
> *lto_base_node
= NULL
;
2431 /* At stream in time we have LTO alias info. Check if we streamed in
2432 something obviously unnecessary. Do not glob types by alias sets;
2433 it is not 100% clear that ltrans types will get merged same way.
2434 Types may get refined based on ODR type conflicts. */
2435 if (base_tree
&& !get_alias_set (base_tree
))
2439 fprintf (dump_file
, "Streamed in alias set 0 type ");
2440 print_generic_expr (dump_file
, base_tree
);
2441 fprintf (dump_file
, "\n");
2447 nolto_base_node
= (*nolto_ret
)->insert_base (base_tree
2448 ? get_alias_set (base_tree
)
2451 lto_base_node
= (*lto_ret
)->insert_base (base_tree
, 0);
2452 size_t every_ref
= streamer_read_uhwi (ib
);
2453 size_t nref
= streamer_read_uhwi (ib
);
2455 gcc_assert (!every_ref
|| nref
== 0);
2458 if (nolto_base_node
)
2459 nolto_base_node
->collapse ();
2461 lto_base_node
->collapse ();
2463 for (size_t j
= 0; j
< nref
; j
++)
2465 tree ref_tree
= stream_read_tree (ib
, data_in
);
2467 if (ref_tree
&& !get_alias_set (ref_tree
))
2471 fprintf (dump_file
, "Streamed in alias set 0 type ");
2472 print_generic_expr (dump_file
, ref_tree
);
2473 fprintf (dump_file
, "\n");
2478 modref_ref_node
<alias_set_type
> *nolto_ref_node
= NULL
;
2479 modref_ref_node
<tree
> *lto_ref_node
= NULL
;
2481 if (nolto_base_node
)
2483 = nolto_base_node
->insert_ref (ref_tree
2484 ? get_alias_set (ref_tree
) : 0,
2487 lto_ref_node
= lto_base_node
->insert_ref (ref_tree
, max_refs
);
2489 size_t every_access
= streamer_read_uhwi (ib
);
2490 size_t naccesses
= streamer_read_uhwi (ib
);
2493 nolto_ref_node
->every_access
= every_access
;
2495 lto_ref_node
->every_access
= every_access
;
2497 for (size_t k
= 0; k
< naccesses
; k
++)
2499 int parm_index
= streamer_read_hwi (ib
);
2500 bool parm_offset_known
= false;
2501 poly_int64 parm_offset
= 0;
2502 poly_int64 offset
= 0;
2503 poly_int64 size
= -1;
2504 poly_int64 max_size
= -1;
2506 if (parm_index
!= -1)
2508 parm_offset_known
= streamer_read_uhwi (ib
);
2509 if (parm_offset_known
)
2511 parm_offset
= streamer_read_poly_int64 (ib
);
2512 offset
= streamer_read_poly_int64 (ib
);
2513 size
= streamer_read_poly_int64 (ib
);
2514 max_size
= streamer_read_poly_int64 (ib
);
2517 modref_access_node a
= {offset
, size
, max_size
, parm_offset
,
2518 parm_index
, parm_offset_known
, false};
2520 nolto_ref_node
->insert_access (a
, max_accesses
, false);
2522 lto_ref_node
->insert_access (a
, max_accesses
, false);
2527 (*lto_ret
)->cleanup ();
2529 (*nolto_ret
)->cleanup ();
2532 /* Write ESUM to BP. */
2535 modref_write_escape_summary (struct bitpack_d
*bp
, escape_summary
*esum
)
2539 bp_pack_var_len_unsigned (bp
, 0);
2542 bp_pack_var_len_unsigned (bp
, esum
->esc
.length ());
2545 FOR_EACH_VEC_ELT (esum
->esc
, i
, ee
)
2547 bp_pack_var_len_unsigned (bp
, ee
->parm_index
);
2548 bp_pack_var_len_unsigned (bp
, ee
->arg
);
2549 bp_pack_var_len_unsigned (bp
, ee
->min_flags
);
2550 bp_pack_value (bp
, ee
->direct
, 1);
2554 /* Read escape summary for E from BP. */
2557 modref_read_escape_summary (struct bitpack_d
*bp
, cgraph_edge
*e
)
2559 unsigned int n
= bp_unpack_var_len_unsigned (bp
);
2562 escape_summary
*esum
= escape_summaries
->get_create (e
);
2563 esum
->esc
.reserve_exact (n
);
2564 for (unsigned int i
= 0; i
< n
; i
++)
2567 ee
.parm_index
= bp_unpack_var_len_unsigned (bp
);
2568 ee
.arg
= bp_unpack_var_len_unsigned (bp
);
2569 ee
.min_flags
= bp_unpack_var_len_unsigned (bp
);
2570 ee
.direct
= bp_unpack_value (bp
, 1);
2571 esum
->esc
.quick_push (ee
);
2575 /* Callback for write_summary. */
2580 struct output_block
*ob
= create_output_block (LTO_section_ipa_modref
);
2581 lto_symtab_encoder_t encoder
= ob
->decl_state
->symtab_node_encoder
;
2582 unsigned int count
= 0;
2587 streamer_write_uhwi (ob
, 0);
2588 streamer_write_char_stream (ob
->main_stream
, 0);
2589 produce_asm (ob
, NULL
);
2590 destroy_output_block (ob
);
2594 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
2596 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
2597 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
2598 modref_summary_lto
*r
;
2600 if (cnode
&& cnode
->definition
&& !cnode
->alias
2601 && (r
= summaries_lto
->get (cnode
))
2602 && r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
2605 streamer_write_uhwi (ob
, count
);
2607 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
2609 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
2610 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
2612 if (cnode
&& cnode
->definition
&& !cnode
->alias
)
2614 modref_summary_lto
*r
= summaries_lto
->get (cnode
);
2616 if (!r
|| !r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
2619 streamer_write_uhwi (ob
, lto_symtab_encoder_encode (encoder
, cnode
));
2621 streamer_write_uhwi (ob
, r
->arg_flags
.length ());
2622 for (unsigned int i
= 0; i
< r
->arg_flags
.length (); i
++)
2623 streamer_write_uhwi (ob
, r
->arg_flags
[i
]);
2625 write_modref_records (r
->loads
, ob
);
2626 write_modref_records (r
->stores
, ob
);
2628 struct bitpack_d bp
= bitpack_create (ob
->main_stream
);
2629 bp_pack_value (&bp
, r
->writes_errno
, 1);
2632 for (cgraph_edge
*e
= cnode
->indirect_calls
;
2633 e
; e
= e
->next_callee
)
2635 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
2636 bp_pack_value (&bp
, sum
!= NULL
, 1);
2638 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
2639 class escape_summary
*esum
= escape_summaries
->get (e
);
2640 modref_write_escape_summary (&bp
,esum
);
2642 for (cgraph_edge
*e
= cnode
->callees
; e
; e
= e
->next_callee
)
2644 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
2645 bp_pack_value (&bp
, sum
!= NULL
, 1);
2647 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
2648 class escape_summary
*esum
= escape_summaries
->get (e
);
2649 modref_write_escape_summary (&bp
,esum
);
2652 streamer_write_bitpack (&bp
);
2655 streamer_write_char_stream (ob
->main_stream
, 0);
2656 produce_asm (ob
, NULL
);
2657 destroy_output_block (ob
);
2661 read_section (struct lto_file_decl_data
*file_data
, const char *data
,
2664 const struct lto_function_header
*header
2665 = (const struct lto_function_header
*) data
;
2666 const int cfg_offset
= sizeof (struct lto_function_header
);
2667 const int main_offset
= cfg_offset
+ header
->cfg_size
;
2668 const int string_offset
= main_offset
+ header
->main_size
;
2669 struct data_in
*data_in
;
2671 unsigned int f_count
;
2673 lto_input_block
ib ((const char *) data
+ main_offset
, header
->main_size
,
2674 file_data
->mode_table
);
2677 = lto_data_in_create (file_data
, (const char *) data
+ string_offset
,
2678 header
->string_size
, vNULL
);
2679 f_count
= streamer_read_uhwi (&ib
);
2680 for (i
= 0; i
< f_count
; i
++)
2682 struct cgraph_node
*node
;
2683 lto_symtab_encoder_t encoder
;
2685 unsigned int index
= streamer_read_uhwi (&ib
);
2686 encoder
= file_data
->symtab_node_encoder
;
2687 node
= dyn_cast
<cgraph_node
*> (lto_symtab_encoder_deref (encoder
,
2690 modref_summary
*modref_sum
= summaries
2691 ? summaries
->get_create (node
) : NULL
;
2692 modref_summary_lto
*modref_sum_lto
= summaries_lto
2693 ? summaries_lto
->get_create (node
)
2695 if (optimization_summaries
)
2696 modref_sum
= optimization_summaries
->get_create (node
);
2699 modref_sum
->writes_errno
= false;
2701 modref_sum_lto
->writes_errno
= false;
2703 gcc_assert (!modref_sum
|| (!modref_sum
->loads
2704 && !modref_sum
->stores
));
2705 gcc_assert (!modref_sum_lto
|| (!modref_sum_lto
->loads
2706 && !modref_sum_lto
->stores
));
2707 unsigned int args
= streamer_read_uhwi (&ib
);
2708 if (args
&& modref_sum
)
2709 modref_sum
->arg_flags
.reserve_exact (args
);
2710 if (args
&& modref_sum_lto
)
2711 modref_sum_lto
->arg_flags
.reserve_exact (args
);
2712 for (unsigned int i
= 0; i
< args
; i
++)
2714 eaf_flags_t flags
= streamer_read_uhwi (&ib
);
2716 modref_sum
->arg_flags
.quick_push (flags
);
2718 modref_sum_lto
->arg_flags
.quick_push (flags
);
2720 read_modref_records (&ib
, data_in
,
2721 modref_sum
? &modref_sum
->loads
: NULL
,
2722 modref_sum_lto
? &modref_sum_lto
->loads
: NULL
);
2723 read_modref_records (&ib
, data_in
,
2724 modref_sum
? &modref_sum
->stores
: NULL
,
2725 modref_sum_lto
? &modref_sum_lto
->stores
: NULL
);
2726 struct bitpack_d bp
= streamer_read_bitpack (&ib
);
2727 if (bp_unpack_value (&bp
, 1))
2730 modref_sum
->writes_errno
= true;
2732 modref_sum_lto
->writes_errno
= true;
2736 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
2738 if (bp_unpack_value (&bp
, 1))
2740 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
2741 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
2743 modref_read_escape_summary (&bp
, e
);
2745 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
2747 if (bp_unpack_value (&bp
, 1))
2749 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
2750 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
2752 modref_read_escape_summary (&bp
, e
);
2757 fprintf (dump_file
, "Read modref for %s\n",
2758 node
->dump_name ());
2760 modref_sum
->dump (dump_file
);
2762 modref_sum_lto
->dump (dump_file
);
2763 dump_modref_edge_summaries (dump_file
, node
, 4);
2767 lto_free_section_data (file_data
, LTO_section_ipa_modref
, NULL
, data
,
2769 lto_data_in_delete (data_in
);
2772 /* Callback for read_summary. */
2777 struct lto_file_decl_data
**file_data_vec
= lto_get_file_decl_data ();
2778 struct lto_file_decl_data
*file_data
;
2781 gcc_checking_assert (!optimization_summaries
&& !summaries
&& !summaries_lto
);
2783 optimization_summaries
= modref_summaries::create_ggc (symtab
);
2786 if (flag_wpa
|| flag_incremental_link
== INCREMENTAL_LINK_LTO
)
2787 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
2789 || (flag_incremental_link
== INCREMENTAL_LINK_LTO
2790 && flag_fat_lto_objects
))
2791 summaries
= modref_summaries::create_ggc (symtab
);
2792 if (!fnspec_summaries
)
2793 fnspec_summaries
= new fnspec_summaries_t (symtab
);
2794 if (!escape_summaries
)
2795 escape_summaries
= new escape_summaries_t (symtab
);
2798 while ((file_data
= file_data_vec
[j
++]))
2801 const char *data
= lto_get_summary_section_data (file_data
,
2802 LTO_section_ipa_modref
,
2805 read_section (file_data
, data
, len
);
2807 /* Fatal error here. We do not want to support compiling ltrans units
2808 with different version of compiler or different flags than the WPA
2809 unit, so this should never happen. */
2810 fatal_error (input_location
,
2811 "IPA modref summary is missing in input file");
2815 /* Recompute arg_flags for param adjustments in INFO. */
2818 remap_arg_flags (auto_vec
<eaf_flags_t
> &arg_flags
, clone_info
*info
)
2820 auto_vec
<eaf_flags_t
> old
= arg_flags
.copy ();
2823 ipa_adjusted_param
*p
;
2825 arg_flags
.release ();
2827 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2829 int o
= info
->param_adjustments
->get_original_index (i
);
2830 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
2834 arg_flags
.safe_grow_cleared (max
+ 1, true);
2835 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2837 int o
= info
->param_adjustments
->get_original_index (i
);
2838 if (o
>= 0 && (int)old
.length () > o
&& old
[o
])
2839 arg_flags
[i
] = old
[o
];
2843 /* If signature changed, update the summary. */
2846 update_signature (struct cgraph_node
*node
)
2848 clone_info
*info
= clone_info::get (node
);
2849 if (!info
|| !info
->param_adjustments
)
2852 modref_summary
*r
= optimization_summaries
2853 ? optimization_summaries
->get (node
) : NULL
;
2854 modref_summary_lto
*r_lto
= summaries_lto
2855 ? summaries_lto
->get (node
) : NULL
;
2860 fprintf (dump_file
, "Updating summary for %s from:\n",
2861 node
->dump_name ());
2863 r
->dump (dump_file
);
2865 r_lto
->dump (dump_file
);
2869 ipa_adjusted_param
*p
;
2871 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2873 int idx
= info
->param_adjustments
->get_original_index (i
);
2878 auto_vec
<int, 32> map
;
2880 map
.reserve (max
+ 1);
2881 for (i
= 0; i
<= max
; i
++)
2882 map
.quick_push (-1);
2883 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2885 int idx
= info
->param_adjustments
->get_original_index (i
);
2891 r
->loads
->remap_params (&map
);
2892 r
->stores
->remap_params (&map
);
2893 if (r
->arg_flags
.length ())
2894 remap_arg_flags (r
->arg_flags
, info
);
2898 r_lto
->loads
->remap_params (&map
);
2899 r_lto
->stores
->remap_params (&map
);
2900 if (r_lto
->arg_flags
.length ())
2901 remap_arg_flags (r_lto
->arg_flags
, info
);
2905 fprintf (dump_file
, "to:\n");
2907 r
->dump (dump_file
);
2909 r_lto
->dump (dump_file
);
2914 /* Definition of the modref IPA pass. */
2915 const pass_data pass_data_ipa_modref
=
2917 IPA_PASS
, /* type */
2918 "modref", /* name */
2919 OPTGROUP_IPA
, /* optinfo_flags */
2920 TV_IPA_MODREF
, /* tv_id */
2921 0, /* properties_required */
2922 0, /* properties_provided */
2923 0, /* properties_destroyed */
2924 0, /* todo_flags_start */
2925 ( TODO_dump_symtab
), /* todo_flags_finish */
2928 class pass_ipa_modref
: public ipa_opt_pass_d
2931 pass_ipa_modref (gcc::context
*ctxt
)
2932 : ipa_opt_pass_d (pass_data_ipa_modref
, ctxt
,
2933 modref_generate
, /* generate_summary */
2934 modref_write
, /* write_summary */
2935 modref_read
, /* read_summary */
2936 modref_write
, /* write_optimization_summary */
2937 modref_read
, /* read_optimization_summary */
2938 NULL
, /* stmt_fixup */
2939 0, /* function_transform_todo_flags_start */
2940 NULL
, /* function_transform */
2941 NULL
) /* variable_transform */
2944 /* opt_pass methods: */
2945 opt_pass
*clone () { return new pass_ipa_modref (m_ctxt
); }
2946 virtual bool gate (function
*)
2950 virtual unsigned int execute (function
*);
2956 unsigned int pass_modref::execute (function
*f
)
2958 analyze_function (f
, false);
2963 make_pass_modref (gcc::context
*ctxt
)
2965 return new pass_modref (ctxt
);
2969 make_pass_ipa_modref (gcc::context
*ctxt
)
2971 return new pass_ipa_modref (ctxt
);
2974 /* Skip edges from and to nodes without ipa_pure_const enabled.
2975 Ignore not available symbols. */
2978 ignore_edge (struct cgraph_edge
*e
)
2980 /* We merge summaries of inline clones into summaries of functions they
2981 are inlined to. For that reason the complete function bodies must
2983 if (!e
->inline_failed
)
2985 enum availability avail
;
2986 cgraph_node
*callee
= e
->callee
->function_or_virtual_thunk_symbol
2987 (&avail
, e
->caller
);
2989 return (avail
<= AVAIL_INTERPOSABLE
2990 || ((!optimization_summaries
|| !optimization_summaries
->get (callee
))
2991 && (!summaries_lto
|| !summaries_lto
->get (callee
)))
2992 || flags_from_decl_or_type (e
->callee
->decl
)
2993 & (ECF_CONST
| ECF_NOVOPS
));
2996 /* Compute parm_map for CALLEE_EDGE. */
2999 compute_parm_map (cgraph_edge
*callee_edge
, vec
<modref_parm_map
> *parm_map
)
3001 class ipa_edge_args
*args
;
3002 if (ipa_node_params_sum
3003 && !callee_edge
->call_stmt_cannot_inline_p
3004 && (args
= ipa_edge_args_sum
->get (callee_edge
)) != NULL
)
3006 int i
, count
= ipa_get_cs_argument_count (args
);
3007 class ipa_node_params
*caller_parms_info
, *callee_pi
;
3008 class ipa_call_summary
*es
3009 = ipa_call_summaries
->get (callee_edge
);
3011 = callee_edge
->callee
->function_or_virtual_thunk_symbol
3012 (NULL
, callee_edge
->caller
);
3015 = ipa_node_params_sum
->get (callee_edge
->caller
->inlined_to
3016 ? callee_edge
->caller
->inlined_to
3017 : callee_edge
->caller
);
3018 callee_pi
= ipa_node_params_sum
->get (callee
);
3020 (*parm_map
).safe_grow_cleared (count
, true);
3022 for (i
= 0; i
< count
; i
++)
3024 if (es
&& es
->param
[i
].points_to_local_or_readonly_memory
)
3026 (*parm_map
)[i
].parm_index
= -2;
3030 struct ipa_jump_func
*jf
3031 = ipa_get_ith_jump_func (args
, i
);
3032 if (jf
&& callee_pi
)
3034 tree cst
= ipa_value_from_jfunc (caller_parms_info
,
3038 if (cst
&& points_to_local_or_readonly_memory_p (cst
))
3040 (*parm_map
)[i
].parm_index
= -2;
3044 if (jf
&& jf
->type
== IPA_JF_PASS_THROUGH
)
3046 (*parm_map
)[i
].parm_index
3047 = ipa_get_jf_pass_through_formal_id (jf
);
3048 if (ipa_get_jf_pass_through_operation (jf
) == NOP_EXPR
)
3050 (*parm_map
)[i
].parm_offset_known
= true;
3051 (*parm_map
)[i
].parm_offset
= 0;
3053 else if (ipa_get_jf_pass_through_operation (jf
)
3054 == POINTER_PLUS_EXPR
3055 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf
),
3056 &(*parm_map
)[i
].parm_offset
))
3057 (*parm_map
)[i
].parm_offset_known
= true;
3059 (*parm_map
)[i
].parm_offset_known
= false;
3062 if (jf
&& jf
->type
== IPA_JF_ANCESTOR
)
3064 (*parm_map
)[i
].parm_index
= ipa_get_jf_ancestor_formal_id (jf
);
3065 (*parm_map
)[i
].parm_offset_known
= true;
3067 (!(ipa_get_jf_ancestor_offset (jf
) & (BITS_PER_UNIT
- 1)));
3068 (*parm_map
)[i
].parm_offset
3069 = ipa_get_jf_ancestor_offset (jf
) >> LOG2_BITS_PER_UNIT
;
3072 (*parm_map
)[i
].parm_index
= -1;
3076 fprintf (dump_file
, " Parm map: ");
3077 for (i
= 0; i
< count
; i
++)
3078 fprintf (dump_file
, " %i", (*parm_map
)[i
].parm_index
);
3079 fprintf (dump_file
, "\n");
3086 /* Map used to translate escape infos. */
3094 /* Update escape map fo E. */
3097 update_escape_summary_1 (cgraph_edge
*e
,
3098 vec
<vec
<escape_map
>> &map
,
3101 escape_summary
*sum
= escape_summaries
->get (e
);
3104 auto_vec
<escape_entry
> old
= sum
->esc
.copy ();
3105 sum
->esc
.release ();
3109 FOR_EACH_VEC_ELT (old
, i
, ee
)
3112 struct escape_map
*em
;
3113 if (ee
->parm_index
>= map
.length ())
3115 FOR_EACH_VEC_ELT (map
[ee
->parm_index
], j
, em
)
3117 int min_flags
= ee
->min_flags
;
3118 if (ee
->direct
&& !em
->direct
)
3119 min_flags
= deref_flags (min_flags
, ignore_stores
);
3120 struct escape_entry entry
= {em
->parm_index
, ee
->arg
,
3122 ee
->direct
& em
->direct
};
3123 sum
->esc
.safe_push (entry
);
3126 if (!sum
->esc
.length ())
3127 escape_summaries
->remove (e
);
3130 /* Update escape map fo NODE. */
3133 update_escape_summary (cgraph_node
*node
,
3134 vec
<vec
<escape_map
>> &map
,
3137 if (!escape_summaries
)
3139 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
3140 update_escape_summary_1 (e
, map
, ignore_stores
);
3141 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
3143 if (!e
->inline_failed
)
3144 update_escape_summary (e
->callee
, map
, ignore_stores
);
3146 update_escape_summary_1 (e
, map
, ignore_stores
);
3150 /* Call EDGE was inlined; merge summary from callee to the caller. */
3153 ipa_merge_modref_summary_after_inlining (cgraph_edge
*edge
)
3155 if (!summaries
&& !summaries_lto
)
3158 struct cgraph_node
*to
= (edge
->caller
->inlined_to
3159 ? edge
->caller
->inlined_to
: edge
->caller
);
3160 class modref_summary
*to_info
= summaries
? summaries
->get (to
) : NULL
;
3161 class modref_summary_lto
*to_info_lto
= summaries_lto
3162 ? summaries_lto
->get (to
) : NULL
;
3164 if (!to_info
&& !to_info_lto
)
3167 summaries
->remove (edge
->callee
);
3169 summaries_lto
->remove (edge
->callee
);
3170 remove_modref_edge_summaries (edge
->callee
);
3174 class modref_summary
*callee_info
= summaries
? summaries
->get (edge
->callee
)
3176 class modref_summary_lto
*callee_info_lto
3177 = summaries_lto
? summaries_lto
->get (edge
->callee
) : NULL
;
3178 int flags
= flags_from_decl_or_type (edge
->callee
->decl
);
3179 bool ignore_stores
= ignore_stores_p (edge
->caller
->decl
, flags
);
3181 if (!callee_info
&& to_info
)
3183 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3184 to_info
->loads
->collapse ();
3186 to_info
->stores
->collapse ();
3188 if (!callee_info_lto
&& to_info_lto
)
3190 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3191 to_info_lto
->loads
->collapse ();
3193 to_info_lto
->stores
->collapse ();
3195 if (callee_info
|| callee_info_lto
)
3197 auto_vec
<modref_parm_map
, 32> parm_map
;
3199 compute_parm_map (edge
, &parm_map
);
3203 if (to_info
&& callee_info
)
3204 to_info
->stores
->merge (callee_info
->stores
, &parm_map
, false);
3205 if (to_info_lto
&& callee_info_lto
)
3206 to_info_lto
->stores
->merge (callee_info_lto
->stores
, &parm_map
,
3209 if (!(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3211 if (to_info
&& callee_info
)
3212 to_info
->loads
->merge (callee_info
->loads
, &parm_map
, false);
3213 if (to_info_lto
&& callee_info_lto
)
3214 to_info_lto
->loads
->merge (callee_info_lto
->loads
, &parm_map
,
3219 /* Now merge escape summaries.
3220 For every escape to the callee we need to merge calle flags
3221 and remap calees escapes. */
3222 class escape_summary
*sum
= escape_summaries
->get (edge
);
3223 int max_escape
= -1;
3227 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3228 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3229 if ((int)ee
->arg
> max_escape
)
3230 max_escape
= ee
->arg
;
3232 auto_vec
<vec
<struct escape_map
>, 32> emap (max_escape
+ 1);
3233 emap
.safe_grow (max_escape
+ 1, true);
3234 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
3237 if (sum
&& !(flags
& (ECF_CONST
| ECF_NOVOPS
)))
3238 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3240 bool needed
= false;
3241 if (to_info
&& to_info
->arg_flags
.length () > ee
->parm_index
)
3243 int flags
= callee_info
3244 && callee_info
->arg_flags
.length () > ee
->arg
3245 ? callee_info
->arg_flags
[ee
->arg
] : 0;
3247 flags
= deref_flags (flags
, ignore_stores
);
3248 else if (ignore_stores
)
3249 flags
|= ignore_stores_eaf_flags
;
3250 flags
|= ee
->min_flags
;
3251 to_info
->arg_flags
[ee
->parm_index
] &= flags
;
3252 if (to_info
->arg_flags
[ee
->parm_index
])
3255 if (to_info_lto
&& to_info_lto
->arg_flags
.length () > ee
->parm_index
)
3257 int flags
= callee_info_lto
3258 && callee_info_lto
->arg_flags
.length () > ee
->arg
3259 ? callee_info_lto
->arg_flags
[ee
->arg
] : 0;
3261 flags
= deref_flags (flags
, ignore_stores
);
3262 else if (ignore_stores
)
3263 flags
|= ignore_stores_eaf_flags
;
3264 flags
|= ee
->min_flags
;
3265 to_info_lto
->arg_flags
[ee
->parm_index
] &= flags
;
3266 if (to_info_lto
->arg_flags
[ee
->parm_index
])
3269 struct escape_map entry
= {ee
->parm_index
, ee
->direct
};
3271 emap
[ee
->arg
].safe_push (entry
);
3273 update_escape_summary (edge
->callee
, emap
, ignore_stores
);
3274 for (i
= 0; (int)i
< max_escape
+ 1; i
++)
3277 escape_summaries
->remove (edge
);
3281 if (to_info
&& !to_info
->useful_p (flags
))
3284 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
3286 summaries
->remove (to
);
3289 else if (to_info
&& dump_file
)
3292 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
3294 to_info
->dump (dump_file
);
3297 summaries
->remove (edge
->callee
);
3301 if (to_info_lto
&& !to_info_lto
->useful_p (flags
))
3304 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
3306 summaries_lto
->remove (to
);
3308 else if (to_info_lto
&& dump_file
)
3311 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
3313 to_info_lto
->dump (dump_file
);
3316 if (callee_info_lto
)
3317 summaries_lto
->remove (edge
->callee
);
3319 if (!to_info
&& !to_info_lto
)
3320 remove_modref_edge_summaries (to
);
3324 /* Get parameter type from DECL. This is only safe for special cases
3325 like builtins we create fnspec for because the type match is checked
3326 at fnspec creation time. */
3329 get_parm_type (tree decl
, unsigned int i
)
3331 tree t
= TYPE_ARG_TYPES (TREE_TYPE (decl
));
3333 for (unsigned int p
= 0; p
< i
; p
++)
3335 return TREE_VALUE (t
);
3338 /* Return access mode for argument I of call E with FNSPEC. */
3340 static modref_access_node
3341 get_access_for_fnspec (cgraph_edge
*e
, attr_fnspec
&fnspec
,
3342 unsigned int i
, modref_parm_map
&map
)
3344 tree size
= NULL_TREE
;
3345 unsigned int size_arg
;
3347 if (!fnspec
.arg_specified_p (i
))
3349 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
3351 cgraph_node
*node
= e
->caller
->inlined_to
3352 ? e
->caller
->inlined_to
: e
->caller
;
3353 ipa_node_params
*caller_parms_info
= ipa_node_params_sum
->get (node
);
3354 ipa_edge_args
*args
= ipa_edge_args_sum
->get (e
);
3355 struct ipa_jump_func
*jf
= ipa_get_ith_jump_func (args
, size_arg
);
3358 size
= ipa_value_from_jfunc (caller_parms_info
, jf
,
3359 get_parm_type (e
->callee
->decl
, size_arg
));
3361 else if (fnspec
.arg_access_size_given_by_type_p (i
))
3362 size
= TYPE_SIZE_UNIT (get_parm_type (e
->callee
->decl
, i
));
3363 modref_access_node a
= {0, -1, -1,
3364 map
.parm_offset
, map
.parm_index
,
3365 map
.parm_offset_known
, 0};
3366 poly_int64 size_hwi
;
3368 && poly_int_tree_p (size
, &size_hwi
)
3369 && coeffs_in_range_p (size_hwi
, 0,
3370 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
3373 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
3378 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
3379 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
3382 propagate_unknown_call (cgraph_node
*node
,
3383 cgraph_edge
*e
, int ecf_flags
,
3384 modref_summary
*cur_summary
,
3385 modref_summary_lto
*cur_summary_lto
)
3387 bool changed
= false;
3388 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
3389 auto_vec
<modref_parm_map
, 32> parm_map
;
3391 && compute_parm_map (e
, &parm_map
))
3393 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
3395 gcc_checking_assert (fnspec
.known_p ());
3396 if (fnspec
.global_memory_read_p ())
3397 collapse_loads (cur_summary
, cur_summary_lto
);
3400 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
3401 for (unsigned i
= 0; i
< parm_map
.length () && t
;
3402 i
++, t
= TREE_CHAIN (t
))
3403 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
3405 else if (!fnspec
.arg_specified_p (i
)
3406 || fnspec
.arg_maybe_read_p (i
))
3408 modref_parm_map map
= parm_map
[i
];
3409 if (map
.parm_index
== -2)
3411 if (map
.parm_index
== -1)
3413 collapse_loads (cur_summary
, cur_summary_lto
);
3417 changed
|= cur_summary
->loads
->insert
3418 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
), false);
3419 if (cur_summary_lto
)
3420 changed
|= cur_summary_lto
->loads
->insert
3421 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
), false);
3424 if (ignore_stores_p (node
->decl
, ecf_flags
))
3426 else if (fnspec
.global_memory_written_p ())
3427 collapse_stores (cur_summary
, cur_summary_lto
);
3430 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
3431 for (unsigned i
= 0; i
< parm_map
.length () && t
;
3432 i
++, t
= TREE_CHAIN (t
))
3433 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
3435 else if (!fnspec
.arg_specified_p (i
)
3436 || fnspec
.arg_maybe_written_p (i
))
3438 modref_parm_map map
= parm_map
[i
];
3439 if (map
.parm_index
== -2)
3441 if (map
.parm_index
== -1)
3443 collapse_stores (cur_summary
, cur_summary_lto
);
3447 changed
|= cur_summary
->stores
->insert
3448 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
), false);
3449 if (cur_summary_lto
)
3450 changed
|= cur_summary_lto
->stores
->insert
3451 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
), false);
3454 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
3456 if (cur_summary
&& !cur_summary
->writes_errno
)
3458 cur_summary
->writes_errno
= true;
3461 if (cur_summary_lto
&& !cur_summary_lto
->writes_errno
)
3463 cur_summary_lto
->writes_errno
= true;
3470 fprintf (dump_file
, " collapsing loads\n");
3471 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
3472 if (!ignore_stores_p (node
->decl
, ecf_flags
))
3475 fprintf (dump_file
, " collapsing stores\n");
3476 changed
|= collapse_stores (cur_summary
, cur_summary_lto
);
3481 /* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
3482 and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
3485 remove_useless_summaries (cgraph_node
*node
,
3486 modref_summary
**cur_summary_ptr
,
3487 modref_summary_lto
**cur_summary_lto_ptr
,
3490 if (*cur_summary_ptr
&& !(*cur_summary_ptr
)->useful_p (ecf_flags
, false))
3492 optimization_summaries
->remove (node
);
3493 *cur_summary_ptr
= NULL
;
3495 if (*cur_summary_lto_ptr
3496 && !(*cur_summary_lto_ptr
)->useful_p (ecf_flags
, false))
3498 summaries_lto
->remove (node
);
3499 *cur_summary_lto_ptr
= NULL
;
3503 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3504 and propagate loads/stores. */
3507 modref_propagate_in_scc (cgraph_node
*component_node
)
3509 bool changed
= true;
3516 for (struct cgraph_node
*cur
= component_node
; cur
;
3517 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3519 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
3520 modref_summary
*cur_summary
= optimization_summaries
3521 ? optimization_summaries
->get (node
)
3523 modref_summary_lto
*cur_summary_lto
= summaries_lto
3524 ? summaries_lto
->get (node
)
3527 if (!cur_summary
&& !cur_summary_lto
)
3530 int cur_ecf_flags
= flags_from_decl_or_type (node
->decl
);
3533 fprintf (dump_file
, " Processing %s%s%s\n",
3535 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3536 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3538 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
3540 if (e
->indirect_info
->ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
3543 fprintf (dump_file
, " Indirect call"
3544 "collapsing loads\n");
3545 if (propagate_unknown_call
3546 (node
, e
, e
->indirect_info
->ecf_flags
,
3547 cur_summary
, cur_summary_lto
))
3550 remove_useless_summaries (node
, &cur_summary
,
3553 if (!cur_summary
&& !cur_summary_lto
)
3558 if (!cur_summary
&& !cur_summary_lto
)
3561 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
3562 callee_edge
= callee_edge
->next_callee
)
3564 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
3565 modref_summary
*callee_summary
= NULL
;
3566 modref_summary_lto
*callee_summary_lto
= NULL
;
3567 struct cgraph_node
*callee
;
3569 if (flags
& (ECF_CONST
| ECF_NOVOPS
)
3570 || !callee_edge
->inline_failed
)
3573 /* Get the callee and its summary. */
3574 enum availability avail
;
3575 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
3578 /* It is not necessary to re-process calls outside of the
3582 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
3583 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
3587 fprintf (dump_file
, " Call to %s\n",
3588 callee_edge
->callee
->dump_name ());
3590 bool ignore_stores
= ignore_stores_p (cur
->decl
, flags
);
3592 if (avail
<= AVAIL_INTERPOSABLE
)
3595 fprintf (dump_file
, " Call target interposable"
3596 " or not available\n");
3597 changed
|= propagate_unknown_call
3598 (node
, callee_edge
, flags
,
3599 cur_summary
, cur_summary_lto
);
3600 if (!cur_summary
&& !cur_summary_lto
)
3605 /* We don't know anything about CALLEE, hence we cannot tell
3606 anything about the entire component. */
3609 && !(callee_summary
= optimization_summaries
->get (callee
)))
3612 fprintf (dump_file
, " No call target summary\n");
3613 changed
|= propagate_unknown_call
3614 (node
, callee_edge
, flags
,
3618 && !(callee_summary_lto
= summaries_lto
->get (callee
)))
3621 fprintf (dump_file
, " No call target summary\n");
3622 changed
|= propagate_unknown_call
3623 (node
, callee_edge
, flags
,
3624 NULL
, cur_summary_lto
);
3627 /* We can not safely optimize based on summary of callee if it
3628 does not always bind to current def: it is possible that
3629 memory load was optimized out earlier which may not happen in
3630 the interposed variant. */
3631 if (!callee_edge
->binds_to_current_def_p ())
3633 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
3635 fprintf (dump_file
, " May not bind local;"
3636 " collapsing loads\n");
3640 auto_vec
<modref_parm_map
, 32> parm_map
;
3642 compute_parm_map (callee_edge
, &parm_map
);
3644 /* Merge in callee's information. */
3647 changed
|= cur_summary
->loads
->merge
3648 (callee_summary
->loads
, &parm_map
, !first
);
3651 changed
|= cur_summary
->stores
->merge
3652 (callee_summary
->stores
, &parm_map
,
3654 if (!cur_summary
->writes_errno
3655 && callee_summary
->writes_errno
)
3657 cur_summary
->writes_errno
= true;
3662 if (callee_summary_lto
)
3664 changed
|= cur_summary_lto
->loads
->merge
3665 (callee_summary_lto
->loads
, &parm_map
,
3669 changed
|= cur_summary_lto
->stores
->merge
3670 (callee_summary_lto
->stores
, &parm_map
,
3672 if (!cur_summary_lto
->writes_errno
3673 && callee_summary_lto
->writes_errno
)
3675 cur_summary_lto
->writes_errno
= true;
3681 remove_useless_summaries (node
, &cur_summary
,
3684 if (!cur_summary
&& !cur_summary_lto
)
3686 if (dump_file
&& changed
)
3689 cur_summary
->dump (dump_file
);
3690 if (cur_summary_lto
)
3691 cur_summary_lto
->dump (dump_file
);
3692 dump_modref_edge_summaries (dump_file
, node
, 4);
3701 "Propagation finished in %i iterations\n", iteration
);
3704 /* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
3707 modref_propagate_dump_scc (cgraph_node
*component_node
)
3709 for (struct cgraph_node
*cur
= component_node
; cur
;
3710 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3711 if (!cur
->inlined_to
)
3713 modref_summary
*cur_summary
= optimization_summaries
3714 ? optimization_summaries
->get (cur
)
3716 modref_summary_lto
*cur_summary_lto
= summaries_lto
3717 ? summaries_lto
->get (cur
)
3720 fprintf (dump_file
, "Propagated modref for %s%s%s\n",
3722 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3723 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3724 if (optimization_summaries
)
3727 cur_summary
->dump (dump_file
);
3729 fprintf (dump_file
, " Not tracked\n");
3733 if (cur_summary_lto
)
3734 cur_summary_lto
->dump (dump_file
);
3736 fprintf (dump_file
, " Not tracked (lto)\n");
3741 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
3742 and SUMMARY_LTO to CUR_SUMMARY_LTO.
3743 Return true if something changed. */
3746 modref_merge_call_site_flags (escape_summary
*sum
,
3747 modref_summary
*cur_summary
,
3748 modref_summary_lto
*cur_summary_lto
,
3749 modref_summary
*summary
,
3750 modref_summary_lto
*summary_lto
,
3756 bool changed
= false;
3757 bool ignore_stores
= ignore_stores_p (caller
, ecf_flags
);
3759 /* If we have no useful info to propagate. */
3760 if ((!cur_summary
|| !cur_summary
->arg_flags
.length ())
3761 && (!cur_summary_lto
|| !cur_summary_lto
->arg_flags
.length ()))
3764 FOR_EACH_VEC_ELT (sum
->esc
, i
, ee
)
3769 if (summary
&& ee
->arg
< summary
->arg_flags
.length ())
3770 flags
= summary
->arg_flags
[ee
->arg
];
3772 && ee
->arg
< summary_lto
->arg_flags
.length ())
3773 flags_lto
= summary_lto
->arg_flags
[ee
->arg
];
3776 flags
= deref_flags (flags
, ignore_stores
);
3777 flags_lto
= deref_flags (flags_lto
, ignore_stores
);
3779 else if (ignore_stores
)
3781 flags
|= ignore_stores_eaf_flags
;
3782 flags_lto
|= ignore_stores_eaf_flags
;
3784 /* Returning the value is already accounted to at local propagation. */
3785 flags
|= ee
->min_flags
| EAF_NOT_RETURNED
;
3786 flags_lto
|= ee
->min_flags
| EAF_NOT_RETURNED
;
3787 /* Noescape implies that value also does not escape directly.
3788 Fnspec machinery does set both so compensate for this. */
3789 if (flags
& EAF_NOESCAPE
)
3790 flags
|= EAF_NODIRECTESCAPE
;
3791 if (flags_lto
& EAF_NOESCAPE
)
3792 flags_lto
|= EAF_NODIRECTESCAPE
;
3793 if (!(flags
& EAF_UNUSED
)
3794 && cur_summary
&& ee
->parm_index
< cur_summary
->arg_flags
.length ())
3796 int f
= cur_summary
->arg_flags
[ee
->parm_index
];
3797 if ((f
& flags
) != f
)
3799 f
= remove_useless_eaf_flags
3800 (f
& flags
, ecf_flags
,
3801 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
3802 cur_summary
->arg_flags
[ee
->parm_index
] = f
;
3806 if (!(flags_lto
& EAF_UNUSED
)
3808 && ee
->parm_index
< cur_summary_lto
->arg_flags
.length ())
3810 int f
= cur_summary_lto
->arg_flags
[ee
->parm_index
];
3811 if ((f
& flags_lto
) != f
)
3813 f
= remove_useless_eaf_flags
3814 (f
& flags_lto
, ecf_flags
,
3815 VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller
))));
3816 cur_summary_lto
->arg_flags
[ee
->parm_index
] = f
;
3824 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
3825 and propagate arg flags. */
3828 modref_propagate_flags_in_scc (cgraph_node
*component_node
)
3830 bool changed
= true;
3836 for (struct cgraph_node
*cur
= component_node
; cur
;
3837 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
3839 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
3840 modref_summary
*cur_summary
= optimization_summaries
3841 ? optimization_summaries
->get (node
)
3843 modref_summary_lto
*cur_summary_lto
= summaries_lto
3844 ? summaries_lto
->get (node
)
3847 if (!cur_summary
&& !cur_summary_lto
)
3851 fprintf (dump_file
, " Processing %s%s%s\n",
3853 TREE_READONLY (cur
->decl
) ? " (const)" : "",
3854 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
3856 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
3858 escape_summary
*sum
= escape_summaries
->get (e
);
3860 if (!sum
|| (e
->indirect_info
->ecf_flags
3861 & (ECF_CONST
| ECF_NOVOPS
)))
3864 changed
|= modref_merge_call_site_flags
3865 (sum
, cur_summary
, cur_summary_lto
,
3867 node
->decl
, e
->indirect_info
->ecf_flags
);
3870 if (!cur_summary
&& !cur_summary_lto
)
3873 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
3874 callee_edge
= callee_edge
->next_callee
)
3876 int ecf_flags
= flags_from_decl_or_type
3877 (callee_edge
->callee
->decl
);
3878 modref_summary
*callee_summary
= NULL
;
3879 modref_summary_lto
*callee_summary_lto
= NULL
;
3880 struct cgraph_node
*callee
;
3882 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
)
3883 || !callee_edge
->inline_failed
)
3885 /* Get the callee and its summary. */
3886 enum availability avail
;
3887 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
3890 /* It is not necessary to re-process calls outside of the
3894 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
3895 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
3898 escape_summary
*sum
= escape_summaries
->get (callee_edge
);
3903 fprintf (dump_file
, " Call to %s\n",
3904 callee_edge
->callee
->dump_name ());
3906 if (avail
<= AVAIL_INTERPOSABLE
3907 || callee_edge
->call_stmt_cannot_inline_p
)
3912 callee_summary
= optimization_summaries
->get (callee
);
3913 if (cur_summary_lto
)
3914 callee_summary_lto
= summaries_lto
->get (callee
);
3916 changed
|= modref_merge_call_site_flags
3917 (sum
, cur_summary
, cur_summary_lto
,
3918 callee_summary
, callee_summary_lto
,
3919 node
->decl
, ecf_flags
);
3920 if (dump_file
&& changed
)
3923 cur_summary
->dump (dump_file
);
3924 if (cur_summary_lto
)
3925 cur_summary_lto
->dump (dump_file
);
3933 "Propagation of flags finished in %i iterations\n", iteration
);
3936 /* Run the IPA pass. This will take a function's summaries and calls and
3937 construct new summaries which represent a transitive closure. So that
3938 summary of an analyzed function contains information about the loads and
3939 stores that the function or any function that it calls does. */
3942 pass_ipa_modref::execute (function
*)
3944 if (!summaries
&& !summaries_lto
)
3947 if (optimization_summaries
)
3948 ggc_delete (optimization_summaries
);
3949 optimization_summaries
= summaries
;
3952 struct cgraph_node
**order
= XCNEWVEC (struct cgraph_node
*,
3953 symtab
->cgraph_count
);
3955 order_pos
= ipa_reduced_postorder (order
, true, ignore_edge
);
3958 /* Iterate over all strongly connected components in post-order. */
3959 for (i
= 0; i
< order_pos
; i
++)
3961 /* Get the component's representative. That's just any node in the
3962 component from which we can traverse the entire component. */
3963 struct cgraph_node
*component_node
= order
[i
];
3966 fprintf (dump_file
, "\n\nStart of SCC component\n");
3968 modref_propagate_in_scc (component_node
);
3969 modref_propagate_flags_in_scc (component_node
);
3971 modref_propagate_dump_scc (component_node
);
3974 FOR_EACH_FUNCTION (node
)
3975 update_signature (node
);
3977 ((modref_summaries_lto
*)summaries_lto
)->propagated
= true;
3978 ipa_free_postorder_info ();
3980 delete fnspec_summaries
;
3981 fnspec_summaries
= NULL
;
3982 delete escape_summaries
;
3983 escape_summaries
= NULL
;
3987 /* Summaries must stay alive until end of compilation. */
3990 ipa_modref_c_finalize ()
3992 if (optimization_summaries
)
3993 ggc_delete (optimization_summaries
);
3994 optimization_summaries
= NULL
;
3995 gcc_checking_assert (!summaries
3996 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
3998 ggc_delete (summaries_lto
);
3999 summaries_lto
= NULL
;
4000 if (fnspec_summaries
)
4001 delete fnspec_summaries
;
4002 fnspec_summaries
= NULL
;
4003 if (escape_summaries
)
4004 delete escape_summaries
;
4005 escape_summaries
= NULL
;
4008 #include "gt-ipa-modref.h"