1 /* Search for references that a functions loads or stores.
2 Copyright (C) 2020 Free Software Foundation, Inc.
3 Contributed by David Cepelik and Jan Hubicka
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 /* Mod/ref pass records summary about loads and stores performed by the
22 function. This is later used by alias analysis to disambiguate memory
23 accesses across function calls. The summary has a form of decision tree
24 described in ipa-modref-tree.h.
26 This file contains a tree pass and an IPA pass. Both performs the same
27 analysis however tree pass is executed during early and late optimization
28 passes to propagate info downwards in the compilation order. IPA pass
29 propagates across the callgraph and is able to handle recursion and works on
30 whole program during link-time analysis.
32 LTO mode differs from the local mode by not recording alias sets but types
33 that are translated to alias sets later. This is necessary in order stream
34 the information because the alias sets are rebuild at stream-in time and may
35 not correspond to ones seen during analysis. For this reason part of analysis
40 #include "coretypes.h"
44 #include "alloc-pool.h"
45 #include "tree-pass.h"
46 #include "gimple-iterator.h"
49 #include "ipa-utils.h"
50 #include "symbol-summary.h"
51 #include "gimple-pretty-print.h"
52 #include "gimple-walk.h"
53 #include "print-tree.h"
54 #include "tree-streamer.h"
57 #include "ipa-modref-tree.h"
58 #include "ipa-modref.h"
59 #include "value-range.h"
61 #include "ipa-fnsummary.h"
62 #include "attr-fnspec.h"
63 #include "symtab-clones.h"
64 #include "gimple-ssa.h"
65 #include "tree-phinodes.h"
66 #include "tree-ssa-operands.h"
67 #include "ssa-iterators.h"
68 #include "stringpool.h"
69 #include "tree-ssanames.h"
71 static int analyze_ssa_name_flags (tree name
,
72 vec
<unsigned char> &known_flags
, int depth
);
74 /* We record fnspec specifiers for call edges since they depends on actual
93 /* Summary holding fnspec string for a given call. */
95 class fnspec_summaries_t
: public call_summary
<fnspec_summary
*>
98 fnspec_summaries_t (symbol_table
*symtab
)
99 : call_summary
<fnspec_summary
*> (symtab
) {}
100 /* Hook that is called by summary when an edge is duplicated. */
101 virtual void duplicate (cgraph_edge
*,
106 dst
->fnspec
= xstrdup (src
->fnspec
);
110 static fnspec_summaries_t
*fnspec_summaries
= NULL
;
112 /* Class (from which there is one global instance) that holds modref summaries
113 for all analyzed functions. */
115 class GTY((user
)) modref_summaries
116 : public fast_function_summary
<modref_summary
*, va_gc
>
119 modref_summaries (symbol_table
*symtab
)
120 : fast_function_summary
<modref_summary
*, va_gc
> (symtab
) {}
121 virtual void insert (cgraph_node
*, modref_summary
*state
);
122 virtual void duplicate (cgraph_node
*src_node
,
123 cgraph_node
*dst_node
,
124 modref_summary
*src_data
,
125 modref_summary
*dst_data
);
126 static modref_summaries
*create_ggc (symbol_table
*symtab
)
128 return new (ggc_alloc_no_dtor
<modref_summaries
> ())
129 modref_summaries (symtab
);
133 class modref_summary_lto
;
135 /* Class (from which there is one global instance) that holds modref summaries
136 for all analyzed functions. */
138 class GTY((user
)) modref_summaries_lto
139 : public fast_function_summary
<modref_summary_lto
*, va_gc
>
142 modref_summaries_lto (symbol_table
*symtab
)
143 : fast_function_summary
<modref_summary_lto
*, va_gc
> (symtab
),
144 propagated (false) {}
145 virtual void insert (cgraph_node
*, modref_summary_lto
*state
);
146 virtual void duplicate (cgraph_node
*src_node
,
147 cgraph_node
*dst_node
,
148 modref_summary_lto
*src_data
,
149 modref_summary_lto
*dst_data
);
150 static modref_summaries_lto
*create_ggc (symbol_table
*symtab
)
152 return new (ggc_alloc_no_dtor
<modref_summaries_lto
> ())
153 modref_summaries_lto (symtab
);
158 /* Global variable holding all modref summaries
159 (from analysis to IPA propagation time). */
161 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
164 /* Global variable holding all modref optimization summaries
165 (from IPA propagation time or used by local optimization pass). */
167 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
>
168 *optimization_summaries
;
170 /* LTO summaries hold info from analysis to LTO streaming or from LTO
171 stream-in through propagation to LTO stream-out. */
173 static GTY(()) fast_function_summary
<modref_summary_lto
*, va_gc
>
176 /* Summary for a single function which this pass produces. */
178 modref_summary::modref_summary ()
179 : loads (NULL
), stores (NULL
), writes_errno (NULL
)
183 modref_summary::~modref_summary ()
191 /* Return true if summary is potentially useful for optimization. */
194 modref_summary::useful_p (int ecf_flags
)
196 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
198 if (arg_flags
.length ())
200 if (loads
&& !loads
->every_base
)
202 if (ecf_flags
& ECF_PURE
)
204 return stores
&& !stores
->every_base
;
207 /* Single function summary used for LTO. */
209 typedef modref_tree
<tree
> modref_records_lto
;
210 struct GTY(()) modref_summary_lto
212 /* Load and stores in functions using types rather then alias sets.
214 This is necessary to make the information streamable for LTO but is also
215 more verbose and thus more likely to hit the limits. */
216 modref_records_lto
*loads
;
217 modref_records_lto
*stores
;
220 modref_summary_lto ();
221 ~modref_summary_lto ();
223 bool useful_p (int ecf_flags
);
226 /* Summary for a single function which this pass produces. */
228 modref_summary_lto::modref_summary_lto ()
229 : loads (NULL
), stores (NULL
), writes_errno (NULL
)
233 modref_summary_lto::~modref_summary_lto ()
242 /* Return true if lto summary is potentially useful for optimization. */
245 modref_summary_lto::useful_p (int ecf_flags
)
247 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
249 if (loads
&& !loads
->every_base
)
251 if (ecf_flags
& ECF_PURE
)
253 return stores
&& !stores
->every_base
;
259 dump_access (modref_access_node
*a
, FILE *out
)
261 fprintf (out
, " access:");
262 if (a
->parm_index
!= -1)
264 fprintf (out
, " Parm %i", a
->parm_index
);
265 if (a
->parm_offset_known
)
267 fprintf (out
, " param offset:");
268 print_dec ((poly_int64_pod
)a
->parm_offset
, out
, SIGNED
);
271 if (a
->range_info_useful_p ())
273 fprintf (out
, " offset:");
274 print_dec ((poly_int64_pod
)a
->offset
, out
, SIGNED
);
275 fprintf (out
, " size:");
276 print_dec ((poly_int64_pod
)a
->size
, out
, SIGNED
);
277 fprintf (out
, " max_size:");
278 print_dec ((poly_int64_pod
)a
->max_size
, out
, SIGNED
);
283 /* Dump records TT to OUT. */
286 dump_records (modref_records
*tt
, FILE *out
)
288 fprintf (out
, " Limits: %i bases, %i refs\n",
289 (int)tt
->max_bases
, (int)tt
->max_refs
);
292 fprintf (out
, " Every base\n");
296 modref_base_node
<alias_set_type
> *n
;
297 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
299 fprintf (out
, " Base %i: alias set %i\n", (int)i
, n
->base
);
302 fprintf (out
, " Every ref\n");
306 modref_ref_node
<alias_set_type
> *r
;
307 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
309 fprintf (out
, " Ref %i: alias set %i\n", (int)j
, r
->ref
);
312 fprintf (out
, " Every access\n");
316 modref_access_node
*a
;
317 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
318 dump_access (a
, out
);
323 /* Dump records TT to OUT. */
326 dump_lto_records (modref_records_lto
*tt
, FILE *out
)
328 fprintf (out
, " Limits: %i bases, %i refs\n",
329 (int)tt
->max_bases
, (int)tt
->max_refs
);
332 fprintf (out
, " Every base\n");
336 modref_base_node
<tree
> *n
;
337 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
339 fprintf (out
, " Base %i:", (int)i
);
340 print_generic_expr (dump_file
, n
->base
);
341 fprintf (out
, " (alias set %i)\n",
342 n
->base
? get_alias_set (n
->base
) : 0);
345 fprintf (out
, " Every ref\n");
349 modref_ref_node
<tree
> *r
;
350 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
352 fprintf (out
, " Ref %i:", (int)j
);
353 print_generic_expr (dump_file
, r
->ref
);
354 fprintf (out
, " (alias set %i)\n",
355 r
->ref
? get_alias_set (r
->ref
) : 0);
358 fprintf (out
, " Every access\n");
362 modref_access_node
*a
;
363 FOR_EACH_VEC_SAFE_ELT (r
->accesses
, k
, a
)
364 dump_access (a
, out
);
369 /* Dump EAF flags. */
372 dump_eaf_flags (FILE *out
, int flags
)
374 if (flags
& EAF_DIRECT
)
375 fprintf (out
, " direct");
376 if (flags
& EAF_NOCLOBBER
)
377 fprintf (out
, " noclobber");
378 if (flags
& EAF_NOESCAPE
)
379 fprintf (out
, " noescape");
380 if (flags
& EAF_UNUSED
)
381 fprintf (out
, " unused");
388 modref_summary::dump (FILE *out
)
392 fprintf (out
, " loads:\n");
393 dump_records (loads
, out
);
397 fprintf (out
, " stores:\n");
398 dump_records (stores
, out
);
401 fprintf (out
, " Writes errno\n");
402 if (arg_flags
.length ())
404 for (unsigned int i
= 0; i
< arg_flags
.length (); i
++)
407 fprintf (out
, " parm %i flags:", i
);
408 dump_eaf_flags (out
, arg_flags
[i
]);
416 modref_summary_lto::dump (FILE *out
)
418 fprintf (out
, " loads:\n");
419 dump_lto_records (loads
, out
);
420 fprintf (out
, " stores:\n");
421 dump_lto_records (stores
, out
);
423 fprintf (out
, " Writes errno\n");
426 /* Get function summary for FUNC if it exists, return NULL otherwise. */
429 get_modref_function_summary (cgraph_node
*func
)
431 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
432 if (!optimization_summaries
)
435 /* A single function body may be represented by multiple symbols with
436 different visibility. For example, if FUNC is an interposable alias,
437 we don't want to return anything, even if we have summary for the target
439 enum availability avail
;
440 func
= func
->function_or_virtual_thunk_symbol
441 (&avail
, current_function_decl
?
442 cgraph_node::get (current_function_decl
) : NULL
);
443 if (avail
<= AVAIL_INTERPOSABLE
)
446 modref_summary
*r
= optimization_summaries
->get (func
);
450 /* Construct modref_access_node from REF. */
451 static modref_access_node
452 get_access (ao_ref
*ref
)
456 base
= ao_ref_base (ref
);
457 modref_access_node a
= {ref
->offset
, ref
->size
, ref
->max_size
,
459 if (TREE_CODE (base
) == MEM_REF
|| TREE_CODE (base
) == TARGET_MEM_REF
)
462 base
= TREE_OPERAND (base
, 0);
463 if (TREE_CODE (base
) == SSA_NAME
464 && SSA_NAME_IS_DEFAULT_DEF (base
)
465 && TREE_CODE (SSA_NAME_VAR (base
)) == PARM_DECL
)
468 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
469 t
!= SSA_NAME_VAR (base
); t
= DECL_CHAIN (t
))
478 if (TREE_CODE (memref
) == MEM_REF
)
481 = wi::to_poly_wide (TREE_OPERAND
482 (memref
, 1)).to_shwi (&a
.parm_offset
);
485 a
.parm_offset_known
= false;
495 /* Record access into the modref_records data structure. */
498 record_access (modref_records
*tt
, ao_ref
*ref
)
500 alias_set_type base_set
= !flag_strict_aliasing
? 0
501 : ao_ref_base_alias_set (ref
);
502 alias_set_type ref_set
= !flag_strict_aliasing
? 0
503 : (ao_ref_alias_set (ref
));
504 modref_access_node a
= get_access (ref
);
507 fprintf (dump_file
, " - Recording base_set=%i ref_set=%i parm=%i\n",
508 base_set
, ref_set
, a
.parm_index
);
510 tt
->insert (base_set
, ref_set
, a
);
513 /* IPA version of record_access_tree. */
516 record_access_lto (modref_records_lto
*tt
, ao_ref
*ref
)
518 /* get_alias_set sometimes use different type to compute the alias set
519 than TREE_TYPE (base). Do same adjustments. */
520 tree base_type
= NULL_TREE
, ref_type
= NULL_TREE
;
521 if (flag_strict_aliasing
)
526 while (handled_component_p (base
))
527 base
= TREE_OPERAND (base
, 0);
529 base_type
= reference_alias_ptr_type_1 (&base
);
532 base_type
= TREE_TYPE (base
);
534 base_type
= TYPE_REF_CAN_ALIAS_ALL (base_type
)
535 ? NULL_TREE
: TREE_TYPE (base_type
);
537 tree ref_expr
= ref
->ref
;
538 ref_type
= reference_alias_ptr_type_1 (&ref_expr
);
541 ref_type
= TREE_TYPE (ref_expr
);
543 ref_type
= TYPE_REF_CAN_ALIAS_ALL (ref_type
)
544 ? NULL_TREE
: TREE_TYPE (ref_type
);
546 /* Sanity check that we are in sync with what get_alias_set does. */
547 gcc_checking_assert ((!base_type
&& !ao_ref_base_alias_set (ref
))
548 || get_alias_set (base_type
)
549 == ao_ref_base_alias_set (ref
));
550 gcc_checking_assert ((!ref_type
&& !ao_ref_alias_set (ref
))
551 || get_alias_set (ref_type
)
552 == ao_ref_alias_set (ref
));
554 /* Do not bother to record types that have no meaningful alias set.
555 Also skip variably modified types since these go to local streams. */
556 if (base_type
&& (!get_alias_set (base_type
)
557 || variably_modified_type_p (base_type
, NULL_TREE
)))
558 base_type
= NULL_TREE
;
559 if (ref_type
&& (!get_alias_set (ref_type
)
560 || variably_modified_type_p (ref_type
, NULL_TREE
)))
561 ref_type
= NULL_TREE
;
563 modref_access_node a
= get_access (ref
);
566 fprintf (dump_file
, " - Recording base type:");
567 print_generic_expr (dump_file
, base_type
);
568 fprintf (dump_file
, " (alias set %i) ref type:",
569 base_type
? get_alias_set (base_type
) : 0);
570 print_generic_expr (dump_file
, ref_type
);
571 fprintf (dump_file
, " (alias set %i) parm:%i\n",
572 ref_type
? get_alias_set (ref_type
) : 0,
576 tt
->insert (base_type
, ref_type
, a
);
579 /* Returns true if and only if we should store the access to EXPR.
580 Some accesses, e.g. loads from automatic variables, are not interesting. */
583 record_access_p (tree expr
)
585 if (refs_local_or_readonly_memory_p (expr
))
588 fprintf (dump_file
, " - Read-only or local, ignoring.\n");
594 /* Return true if ECF flags says that stores can be ignored. */
597 ignore_stores_p (tree caller
, int flags
)
599 if (flags
& ECF_PURE
)
601 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
602 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
607 /* Determine parm_map for argument I of STMT. */
610 parm_map_for_arg (gimple
*stmt
, int i
)
612 tree op
= gimple_call_arg (stmt
, i
);
615 struct modref_parm_map parm_map
;
617 parm_map
.parm_offset_known
= false;
618 parm_map
.parm_offset
= 0;
620 offset_known
= unadjusted_ptr_and_unit_offset (op
, &op
, &offset
);
621 if (TREE_CODE (op
) == SSA_NAME
622 && SSA_NAME_IS_DEFAULT_DEF (op
)
623 && TREE_CODE (SSA_NAME_VAR (op
)) == PARM_DECL
)
626 for (tree t
= DECL_ARGUMENTS (current_function_decl
);
627 t
!= SSA_NAME_VAR (op
); t
= DECL_CHAIN (t
))
636 parm_map
.parm_index
= index
;
637 parm_map
.parm_offset_known
= offset_known
;
638 parm_map
.parm_offset
= offset
;
640 else if (points_to_local_or_readonly_memory_p (op
))
641 parm_map
.parm_index
= -2;
643 parm_map
.parm_index
= -1;
647 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
648 int CUR_SUMMARY. Return true if something changed.
649 If IGNORE_STORES is true, do not merge stores. */
652 merge_call_side_effects (modref_summary
*cur_summary
,
653 gimple
*stmt
, modref_summary
*callee_summary
,
654 bool ignore_stores
, cgraph_node
*callee_node
)
656 auto_vec
<modref_parm_map
, 32> parm_map
;
657 bool changed
= false;
660 fprintf (dump_file
, " - Merging side effects of %s with parm map:",
661 callee_node
->dump_name ());
663 /* We can not safely optimize based on summary of callee if it does
664 not always bind to current def: it is possible that memory load
665 was optimized out earlier which may not happen in the interposed
667 if (!callee_node
->binds_to_current_def_p ())
670 fprintf (dump_file
, " - May be interposed: collapsing loads.\n");
671 cur_summary
->loads
->collapse ();
674 parm_map
.safe_grow_cleared (gimple_call_num_args (stmt
), true);
675 for (unsigned i
= 0; i
< gimple_call_num_args (stmt
); i
++)
677 parm_map
[i
] = parm_map_for_arg (stmt
, i
);
680 fprintf (dump_file
, " %i", parm_map
[i
].parm_index
);
681 if (parm_map
[i
].parm_offset_known
)
683 fprintf (dump_file
, " offset:");
684 print_dec ((poly_int64_pod
)parm_map
[i
].parm_offset
,
690 fprintf (dump_file
, "\n");
692 /* Merge with callee's summary. */
693 changed
|= cur_summary
->loads
->merge (callee_summary
->loads
, &parm_map
);
696 changed
|= cur_summary
->stores
->merge (callee_summary
->stores
,
698 if (!cur_summary
->writes_errno
699 && callee_summary
->writes_errno
)
701 cur_summary
->writes_errno
= true;
708 /* Return access mode for argument I of call STMT with FNSPEC. */
710 static modref_access_node
711 get_access_for_fnspec (gcall
*call
, attr_fnspec
&fnspec
,
712 unsigned int i
, modref_parm_map
&map
)
714 tree size
= NULL_TREE
;
715 unsigned int size_arg
;
717 if (!fnspec
.arg_specified_p (i
))
719 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
720 size
= gimple_call_arg (call
, size_arg
);
721 else if (fnspec
.arg_access_size_given_by_type_p (i
))
723 tree callee
= gimple_call_fndecl (call
);
724 tree t
= TYPE_ARG_TYPES (TREE_TYPE (callee
));
726 for (unsigned int p
= 0; p
< i
; p
++)
728 size
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t
)));
730 modref_access_node a
= {0, -1, -1,
731 map
.parm_offset
, map
.parm_index
,
732 map
.parm_offset_known
};
735 && poly_int_tree_p (size
, &size_hwi
)
736 && coeffs_in_range_p (size_hwi
, 0,
737 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
740 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
745 /* Collapse loads and return true if something changed. */
748 collapse_loads (modref_summary
*cur_summary
,
749 modref_summary_lto
*cur_summary_lto
)
751 bool changed
= false;
753 if (cur_summary
&& !cur_summary
->loads
->every_base
)
755 cur_summary
->loads
->collapse ();
759 && !cur_summary_lto
->loads
->every_base
)
761 cur_summary_lto
->loads
->collapse ();
767 /* Collapse loads and return true if something changed. */
770 collapse_stores (modref_summary
*cur_summary
,
771 modref_summary_lto
*cur_summary_lto
)
773 bool changed
= false;
775 if (cur_summary
&& !cur_summary
->stores
->every_base
)
777 cur_summary
->stores
->collapse ();
781 && !cur_summary_lto
->stores
->every_base
)
783 cur_summary_lto
->stores
->collapse ();
790 /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
791 If IGNORE_STORES is true ignore them.
792 Return false if no useful summary can be produced. */
795 process_fnspec (modref_summary
*cur_summary
,
796 modref_summary_lto
*cur_summary_lto
,
797 gcall
*call
, bool ignore_stores
)
799 attr_fnspec fnspec
= gimple_call_fnspec (call
);
800 if (!fnspec
.known_p ())
802 if (dump_file
&& gimple_call_builtin_p (call
, BUILT_IN_NORMAL
))
803 fprintf (dump_file
, " Builtin with no fnspec: %s\n",
804 IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call
))));
807 collapse_loads (cur_summary
, cur_summary_lto
);
812 if (fnspec
.global_memory_read_p ())
813 collapse_loads (cur_summary
, cur_summary_lto
);
816 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
817 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
819 else if (!fnspec
.arg_specified_p (i
)
820 || fnspec
.arg_maybe_read_p (i
))
822 modref_parm_map map
= parm_map_for_arg (call
, i
);
824 if (map
.parm_index
== -2)
826 if (map
.parm_index
== -1)
828 collapse_loads (cur_summary
, cur_summary_lto
);
832 cur_summary
->loads
->insert (0, 0,
833 get_access_for_fnspec (call
,
837 cur_summary_lto
->loads
->insert (0, 0,
838 get_access_for_fnspec (call
,
845 if (fnspec
.global_memory_written_p ())
846 collapse_stores (cur_summary
, cur_summary_lto
);
849 for (unsigned int i
= 0; i
< gimple_call_num_args (call
); i
++)
850 if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call
, i
))))
852 else if (!fnspec
.arg_specified_p (i
)
853 || fnspec
.arg_maybe_written_p (i
))
855 modref_parm_map map
= parm_map_for_arg (call
, i
);
857 if (map
.parm_index
== -2)
859 if (map
.parm_index
== -1)
861 collapse_stores (cur_summary
, cur_summary_lto
);
865 cur_summary
->stores
->insert (0, 0,
866 get_access_for_fnspec (call
,
870 cur_summary_lto
->stores
->insert (0, 0,
871 get_access_for_fnspec (call
,
875 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
878 cur_summary
->writes_errno
= true;
880 cur_summary_lto
->writes_errno
= true;
886 /* Analyze function call STMT in function F.
887 Remember recursive calls in RECURSIVE_CALLS. */
890 analyze_call (modref_summary
*cur_summary
, modref_summary_lto
*cur_summary_lto
,
891 gcall
*stmt
, vec
<gimple
*> *recursive_calls
)
893 /* Check flags on the function call. In certain cases, analysis can be
895 int flags
= gimple_call_flags (stmt
);
896 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
900 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
901 "except for args.\n");
905 /* Pure functions do not affect global memory. Stores by functions which are
906 noreturn and do not throw can safely be ignored. */
907 bool ignore_stores
= ignore_stores_p (current_function_decl
, flags
);
909 /* Next, we try to get the callee's function declaration. The goal is to
910 merge their summary with ours. */
911 tree callee
= gimple_call_fndecl (stmt
);
913 /* Check if this is an indirect call. */
917 fprintf (dump_file
, gimple_call_internal_p (stmt
)
918 ? " - Internal call" : " - Indirect call.\n");
919 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
921 /* We only need to handle internal calls in IPA mode. */
922 gcc_checking_assert (!cur_summary_lto
);
924 struct cgraph_node
*callee_node
= cgraph_node::get_create (callee
);
926 /* If this is a recursive call, the target summary is the same as ours, so
927 there's nothing to do. */
928 if (recursive_call_p (current_function_decl
, callee
))
930 recursive_calls
->safe_push (stmt
);
932 fprintf (dump_file
, " - Skipping recursive call.\n");
936 gcc_assert (callee_node
!= NULL
);
938 /* Get the function symbol and its availability. */
939 enum availability avail
;
940 callee_node
= callee_node
->function_symbol (&avail
);
941 if (avail
<= AVAIL_INTERPOSABLE
)
944 fprintf (dump_file
, " - Function availability <= AVAIL_INTERPOSABLE.\n");
945 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
948 /* Get callee's modref summary. As above, if there's no summary, we either
949 have to give up or, if stores are ignored, we can just purge loads. */
950 modref_summary
*callee_summary
= optimization_summaries
->get (callee_node
);
954 fprintf (dump_file
, " - No modref summary available for callee.\n");
955 return process_fnspec (cur_summary
, cur_summary_lto
, stmt
, ignore_stores
);
958 merge_call_side_effects (cur_summary
, stmt
, callee_summary
, ignore_stores
,
964 /* Support analysis in non-lto and lto mode in parallel. */
968 struct modref_summary
*nolto
;
969 struct modref_summary_lto
*lto
;
972 /* Helper for analyze_stmt. */
975 analyze_load (gimple
*, tree
, tree op
, void *data
)
977 modref_summary
*summary
= ((summary_ptrs
*)data
)->nolto
;
978 modref_summary_lto
*summary_lto
= ((summary_ptrs
*)data
)->lto
;
982 fprintf (dump_file
, " - Analyzing load: ");
983 print_generic_expr (dump_file
, op
);
984 fprintf (dump_file
, "\n");
987 if (!record_access_p (op
))
991 ao_ref_init (&r
, op
);
994 record_access (summary
->loads
, &r
);
996 record_access_lto (summary_lto
->loads
, &r
);
1000 /* Helper for analyze_stmt. */
1003 analyze_store (gimple
*, tree
, tree op
, void *data
)
1005 modref_summary
*summary
= ((summary_ptrs
*)data
)->nolto
;
1006 modref_summary_lto
*summary_lto
= ((summary_ptrs
*)data
)->lto
;
1010 fprintf (dump_file
, " - Analyzing store: ");
1011 print_generic_expr (dump_file
, op
);
1012 fprintf (dump_file
, "\n");
1015 if (!record_access_p (op
))
1019 ao_ref_init (&r
, op
);
1022 record_access (summary
->stores
, &r
);
1024 record_access_lto (summary_lto
->stores
, &r
);
1028 /* Analyze statement STMT of function F.
1029 If IPA is true do not merge in side effects of calls. */
1032 analyze_stmt (modref_summary
*summary
, modref_summary_lto
*summary_lto
,
1033 gimple
*stmt
, bool ipa
, vec
<gimple
*> *recursive_calls
)
1035 /* In general we can not ignore clobbers because they are barriers for code
1036 motion, however after inlining it is safe to do because local optimization
1037 passes do not consider clobbers from other functions.
1038 Similar logic is in ipa-pure-const.c. */
1039 if ((ipa
|| cfun
->after_inlining
) && gimple_clobber_p (stmt
))
1042 struct summary_ptrs sums
= {summary
, summary_lto
};
1044 /* Analyze all loads and stores in STMT. */
1045 walk_stmt_load_store_ops (stmt
, &sums
,
1046 analyze_load
, analyze_store
);
1048 switch (gimple_code (stmt
))
1051 /* If the ASM statement does not read nor write memory, there's nothing
1052 to do. Otherwise just give up. */
1053 if (!gimple_asm_clobbers_memory_p (as_a
<gasm
*> (stmt
)))
1056 fprintf (dump_file
, " - Function contains GIMPLE_ASM statement "
1057 "which clobbers memory.\n");
1060 if (!ipa
|| gimple_call_internal_p (stmt
))
1061 return analyze_call (summary
, summary_lto
,
1062 as_a
<gcall
*> (stmt
), recursive_calls
);
1065 attr_fnspec fnspec
= gimple_call_fnspec (as_a
<gcall
*>(stmt
));
1067 if (fnspec
.known_p ()
1068 && (!fnspec
.global_memory_read_p ()
1069 || !fnspec
.global_memory_written_p ()))
1071 fnspec_summaries
->get_create
1072 (cgraph_node::get (current_function_decl
)->get_edge (stmt
))
1073 ->fnspec
= xstrdup (fnspec
.get_str ());
1075 fprintf (dump_file
, " Recorded fnspec %s\n", fnspec
.get_str ());
1080 /* Nothing to do for other types of statements. */
1085 /* Remove summary of current function because during the function body
1086 scan we determined it is not useful. LTO, NOLTO and IPA determines the
1090 remove_summary (bool lto
, bool nolto
, bool ipa
)
1092 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1094 optimization_summaries
->remove (fnode
);
1098 summaries
->remove (fnode
);
1100 summaries_lto
->remove (fnode
);
1104 " - modref done with result: not tracked.\n");
1107 /* Return true if OP accesses memory pointed to by SSA_NAME. */
1110 memory_access_to (tree op
, tree ssa_name
)
1112 tree base
= get_base_address (op
);
1115 if (TREE_CODE (base
) != MEM_REF
&& TREE_CODE (base
) != TARGET_MEM_REF
)
1117 return TREE_OPERAND (base
, 0) == ssa_name
;
1120 /* Consider statement val = *arg.
1121 return EAF flags of ARG that can be determined from EAF flags of VAL
1122 (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
1123 all stores to VAL, i.e. when handling noreturn function. */
1126 deref_flags (int flags
, bool ignore_stores
)
1129 if (flags
& EAF_UNUSED
)
1130 ret
|= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
;
1133 if ((flags
& EAF_NOCLOBBER
) || ignore_stores
)
1134 ret
|= EAF_NOCLOBBER
;
1135 if ((flags
& EAF_NOESCAPE
) || ignore_stores
)
1136 ret
|= EAF_NOESCAPE
;
1141 /* Call statements may return their parameters. Consider argument number
1142 ARG of USE_STMT and determine flags that can needs to be cleared
1143 in case pointer possibly indirectly references from ARG I is returned.
1144 KNOWN_FLAGS and DEPTH are same as in analyze_ssa_name_flags. */
1147 call_lhs_flags (gcall
*call
, int arg
,
1148 vec
<unsigned char> &known_flags
, int depth
)
1150 /* If there is no return value, no flags are affected. */
1151 if (!gimple_call_lhs (call
))
1152 return EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_UNUSED
;
1154 /* If we know that function returns given argument and it is not ARG
1155 we can still be happy. */
1156 int flags
= gimple_call_return_flags (call
);
1157 if ((flags
& ERF_RETURNS_ARG
)
1158 && (flags
& ERF_RETURN_ARG_MASK
) != arg
)
1159 return EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_UNUSED
;
1161 /* If return value is SSA name determine its flags. */
1162 if (TREE_CODE (gimple_call_lhs (call
)) == SSA_NAME
)
1163 return analyze_ssa_name_flags
1164 (gimple_call_lhs (call
), known_flags
,
1166 /* In the case of memory store we can do nothing. */
1171 /* Analyze EAF flags for SSA name NAME.
1172 KNOWN_FLAGS is a cache for flags we already determined.
1173 DEPTH is a recursion depth used to make debug output prettier. */
1176 analyze_ssa_name_flags (tree name
, vec
<unsigned char> &known_flags
, int depth
)
1178 imm_use_iterator ui
;
1180 int flags
= EAF_DIRECT
| EAF_NOCLOBBER
| EAF_NOESCAPE
| EAF_UNUSED
;
1182 /* See if value is already computed. */
1183 if (known_flags
[SSA_NAME_VERSION (name
)])
1185 /* Punt on cycles for now, so we do not need dataflow. */
1186 if (known_flags
[SSA_NAME_VERSION (name
)] == 1)
1190 "%*sGiving up on a cycle in SSA graph\n", depth
* 4, "");
1193 return known_flags
[SSA_NAME_VERSION (name
)] - 2;
1195 if (depth
== param_modref_max_depth
)
1199 "%*sGiving up on max depth\n", depth
* 4, "");
1202 /* Recursion guard. */
1203 known_flags
[SSA_NAME_VERSION (name
)] = 1;
1208 "%*sAnalyzing flags of ssa name: ", depth
* 4, "");
1209 print_generic_expr (dump_file
, name
);
1210 fprintf (dump_file
, "\n");
1213 FOR_EACH_IMM_USE_STMT (use_stmt
, ui
, name
)
1217 BREAK_FROM_IMM_USE_STMT (ui
);
1219 if (is_gimple_debug (use_stmt
))
1223 fprintf (dump_file
, "%*s Analyzing stmt:", depth
* 4, "");
1224 print_gimple_stmt (dump_file
, use_stmt
, 0);
1227 /* Gimple return may load the return value.
1228 Returning name counts as an use by tree-ssa-structalias.c */
1229 if (greturn
*ret
= dyn_cast
<greturn
*> (use_stmt
))
1231 if (memory_access_to (gimple_return_retval (ret
), name
)
1232 || name
== gimple_return_retval (ret
))
1233 flags
&= ~EAF_UNUSED
;
1235 /* Account for LHS store, arg loads and flags from callee function. */
1236 else if (gcall
*call
= dyn_cast
<gcall
*> (use_stmt
))
1238 tree callee
= gimple_call_fndecl (call
);
1240 /* Recursion would require bit of propagation; give up for now. */
1241 if (callee
&& recursive_call_p (current_function_decl
, callee
))
1245 int ecf_flags
= gimple_call_flags (call
);
1246 bool ignore_stores
= ignore_stores_p (current_function_decl
,
1249 /* Handle *name = func (...). */
1250 if (gimple_call_lhs (call
)
1251 && memory_access_to (gimple_call_lhs (call
), name
))
1252 flags
&= ~(EAF_UNUSED
| EAF_NOCLOBBER
);
1254 /* We do not track accesses to the static chain (we could)
1256 if (gimple_call_chain (call
)
1257 && (gimple_call_chain (call
) == name
))
1260 /* Handle all function parameters. */
1261 for (unsigned i
= 0; i
< gimple_call_num_args (call
); i
++)
1262 /* Name is directly passed to the callee. */
1263 if (gimple_call_arg (call
, i
) == name
)
1265 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
1266 flags
&= ignore_stores
1268 : call_lhs_flags (call
, i
, known_flags
, depth
);
1271 int call_flags
= gimple_call_arg_flags (call
, i
);
1273 call_flags
|= EAF_NOCLOBBER
| EAF_NOESCAPE
;
1275 call_flags
&= call_lhs_flags (call
, i
,
1276 known_flags
, depth
);
1278 flags
&= call_flags
;
1281 /* Name is dereferenced and passed to a callee. */
1282 else if (memory_access_to (gimple_call_arg (call
, i
), name
))
1284 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
1285 flags
&= ~EAF_UNUSED
;
1287 flags
&= deref_flags (gimple_call_arg_flags (call
, i
),
1290 flags
&= call_lhs_flags (call
, i
, known_flags
, depth
);
1293 /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
1294 in tree-ssa-alias.c). Give up earlier. */
1295 if ((flags
& ~(EAF_DIRECT
| EAF_NOCLOBBER
)) == 0)
1298 else if (gimple_assign_load_p (use_stmt
))
1300 gassign
*assign
= as_a
<gassign
*> (use_stmt
);
1301 /* Memory to memory copy. */
1302 if (gimple_store_p (assign
))
1304 /* Handle *name = *exp. */
1305 if (memory_access_to (gimple_assign_lhs (assign
), name
))
1306 flags
&= ~(EAF_UNUSED
| EAF_NOCLOBBER
);
1308 /* Handle *lhs = *name.
1310 We do not track memory locations, so assume that value
1311 is used arbitrarily. */
1312 if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
1315 /* Handle lhs = *name. */
1316 else if (memory_access_to (gimple_assign_rhs1 (assign
), name
))
1317 flags
&= deref_flags (analyze_ssa_name_flags
1318 (gimple_assign_lhs (assign
),
1319 known_flags
, depth
+ 1), false);
1321 else if (gimple_store_p (use_stmt
))
1323 gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
);
1325 /* Handle *lhs = name. */
1326 if (assign
&& gimple_assign_rhs1 (assign
) == name
)
1329 fprintf (dump_file
, "%*s ssa name saved to memory\n",
1333 /* Handle *name = exp. */
1335 && memory_access_to (gimple_assign_lhs (assign
), name
))
1336 flags
&= ~(EAF_UNUSED
| EAF_NOCLOBBER
);
1337 /* ASM statements etc. */
1341 fprintf (dump_file
, "%*s Unhandled store\n",
1346 else if (gassign
*assign
= dyn_cast
<gassign
*> (use_stmt
))
1348 enum tree_code code
= gimple_assign_rhs_code (assign
);
1350 /* See if operation is a merge as considered by
1351 tree-ssa-structalias.c:find_func_aliases. */
1352 if (!truth_value_p (code
)
1353 && code
!= POINTER_DIFF_EXPR
1354 && (code
!= POINTER_PLUS_EXPR
1355 || gimple_assign_rhs1 (assign
) == name
))
1356 flags
&= analyze_ssa_name_flags
1357 (gimple_assign_lhs (assign
), known_flags
,
1360 else if (gphi
*phi
= dyn_cast
<gphi
*> (use_stmt
))
1362 flags
&= analyze_ssa_name_flags
1363 (gimple_phi_result (phi
), known_flags
,
1366 /* Conditions are not considered escape points
1367 by tree-ssa-structalias. */
1368 else if (gimple_code (use_stmt
) == GIMPLE_COND
)
1373 fprintf (dump_file
, "%*s Unhandled stmt\n", depth
* 4, "");
1379 fprintf (dump_file
, "%*s current flags of ", depth
* 4, "");
1380 print_generic_expr (dump_file
, name
);
1381 dump_eaf_flags (dump_file
, flags
);
1386 fprintf (dump_file
, "%*sflags of ssa name ", depth
* 4, "");
1387 print_generic_expr (dump_file
, name
);
1388 dump_eaf_flags (dump_file
, flags
);
1390 known_flags
[SSA_NAME_VERSION (name
)] = flags
+ 2;
1394 /* Determine EAF flags for function parameters. */
1397 analyze_parms (modref_summary
*summary
)
1399 unsigned int parm_index
= 0;
1400 unsigned int count
= 0;
1402 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
;
1403 parm
= TREE_CHAIN (parm
))
1409 auto_vec
<unsigned char> known_flags
;
1410 known_flags
.safe_grow_cleared (num_ssa_names
, true);
1412 for (tree parm
= DECL_ARGUMENTS (current_function_decl
); parm
; parm_index
++,
1413 parm
= TREE_CHAIN (parm
))
1415 tree name
= ssa_default_def (cfun
, parm
);
1418 int flags
= analyze_ssa_name_flags (name
, known_flags
, 0);
1422 if (parm_index
>= summary
->arg_flags
.length ())
1423 summary
->arg_flags
.safe_grow_cleared (count
, true);
1424 summary
->arg_flags
[parm_index
] = flags
;
1429 /* Analyze function F. IPA indicates whether we're running in local mode
1430 (false) or the IPA mode (true). */
1433 analyze_function (function
*f
, bool ipa
)
1436 fprintf (dump_file
, "modref analyzing '%s' (ipa=%i)%s%s\n",
1437 function_name (f
), ipa
,
1438 TREE_READONLY (current_function_decl
) ? " (const)" : "",
1439 DECL_PURE_P (current_function_decl
) ? " (pure)" : "");
1441 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
1442 if (!flag_ipa_modref
)
1445 /* Compute no-LTO summaries when local optimization is going to happen. */
1446 bool nolto
= (!ipa
|| ((!flag_lto
|| flag_fat_lto_objects
) && !in_lto_p
)
1447 || (in_lto_p
&& !flag_wpa
1448 && flag_incremental_link
!= INCREMENTAL_LINK_LTO
));
1449 /* Compute LTO when LTO streaming is going to happen. */
1450 bool lto
= ipa
&& ((flag_lto
&& !in_lto_p
)
1452 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
1453 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
1455 modref_summary
*summary
= NULL
;
1456 modref_summary_lto
*summary_lto
= NULL
;
1458 /* Initialize the summary.
1459 If we run in local mode there is possibly pre-existing summary from
1460 IPA pass. Dump it so it is easy to compare if mod-ref info has
1464 if (!optimization_summaries
)
1465 optimization_summaries
= modref_summaries::create_ggc (symtab
);
1466 else /* Remove existing summary if we are re-running the pass. */
1470 = optimization_summaries
->get (cgraph_node::get (f
->decl
)))
1474 fprintf (dump_file
, "Past summary:\n");
1475 optimization_summaries
->get
1476 (cgraph_node::get (f
->decl
))->dump (dump_file
);
1478 optimization_summaries
->remove (cgraph_node::get (f
->decl
));
1480 summary
= optimization_summaries
->get_create (cgraph_node::get (f
->decl
));
1481 gcc_checking_assert (nolto
&& !lto
);
1483 /* In IPA mode we analyze every function precisely once. Assert that. */
1489 summaries
= modref_summaries::create_ggc (symtab
);
1491 summaries
->remove (cgraph_node::get (f
->decl
));
1492 summary
= summaries
->get_create (cgraph_node::get (f
->decl
));
1497 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
1499 summaries_lto
->remove (cgraph_node::get (f
->decl
));
1500 summary_lto
= summaries_lto
->get_create (cgraph_node::get (f
->decl
));
1502 if (!fnspec_summaries
)
1503 fnspec_summaries
= new fnspec_summaries_t (symtab
);
1507 /* Create and initialize summary for F.
1508 Note that summaries may be already allocated from previous
1512 gcc_assert (!summary
->loads
);
1513 summary
->loads
= modref_records::create_ggc (param_modref_max_bases
,
1514 param_modref_max_refs
,
1515 param_modref_max_accesses
);
1516 gcc_assert (!summary
->stores
);
1517 summary
->stores
= modref_records::create_ggc (param_modref_max_bases
,
1518 param_modref_max_refs
,
1519 param_modref_max_accesses
);
1520 summary
->writes_errno
= false;
1524 gcc_assert (!summary_lto
->loads
);
1525 summary_lto
->loads
= modref_records_lto::create_ggc
1526 (param_modref_max_bases
,
1527 param_modref_max_refs
,
1528 param_modref_max_accesses
);
1529 gcc_assert (!summary_lto
->stores
);
1530 summary_lto
->stores
= modref_records_lto::create_ggc
1531 (param_modref_max_bases
,
1532 param_modref_max_refs
,
1533 param_modref_max_accesses
);
1534 summary_lto
->writes_errno
= false;
1538 analyze_parms (summary
);
1540 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
1541 auto_vec
<gimple
*, 32> recursive_calls
;
1543 /* Analyze each statement in each basic block of the function. If the
1544 statement cannot be analyzed (for any reason), the entire function cannot
1545 be analyzed by modref. */
1547 FOR_EACH_BB_FN (bb
, f
)
1549 gimple_stmt_iterator si
;
1550 for (si
= gsi_after_labels (bb
); !gsi_end_p (si
); gsi_next (&si
))
1552 if (!analyze_stmt (summary
, summary_lto
,
1553 gsi_stmt (si
), ipa
, &recursive_calls
)
1554 || ((!summary
|| !summary
->useful_p (ecf_flags
))
1555 && (!summary_lto
|| !summary_lto
->useful_p (ecf_flags
))))
1557 collapse_loads (summary
, summary_lto
);
1558 collapse_stores (summary
, summary_lto
);
1564 /* In non-IPA mode we need to perform iterative datafow on recursive calls.
1565 This needs to be done after all other side effects are computed. */
1568 bool changed
= true;
1572 for (unsigned i
= 0; i
< recursive_calls
.length (); i
++)
1574 changed
|= merge_call_side_effects
1575 (summary
, recursive_calls
[i
], summary
,
1576 ignore_stores_p (current_function_decl
,
1578 (recursive_calls
[i
])),
1580 if (!summary
->useful_p (ecf_flags
))
1582 remove_summary (lto
, nolto
, ipa
);
1588 if (summary
&& !summary
->useful_p (ecf_flags
))
1591 optimization_summaries
->remove (fnode
);
1593 summaries
->remove (fnode
);
1596 if (summary_lto
&& !summary_lto
->useful_p (ecf_flags
))
1598 summaries_lto
->remove (fnode
);
1604 fprintf (dump_file
, " - modref done with result: tracked.\n");
1606 summary
->dump (dump_file
);
1608 summary_lto
->dump (dump_file
);
1612 /* Callback for generate_summary. */
1615 modref_generate (void)
1617 struct cgraph_node
*node
;
1618 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
1620 function
*f
= DECL_STRUCT_FUNCTION (node
->decl
);
1624 analyze_function (f
, true);
1629 /* Called when a new function is inserted to callgraph late. */
1632 modref_summaries::insert (struct cgraph_node
*node
, modref_summary
*)
1634 /* Local passes ought to be executed by the pass manager. */
1635 if (this == optimization_summaries
)
1637 optimization_summaries
->remove (node
);
1640 if (!DECL_STRUCT_FUNCTION (node
->decl
)
1641 || !opt_for_fn (node
->decl
, flag_ipa_modref
))
1643 summaries
->remove (node
);
1646 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
1647 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
1651 /* Called when a new function is inserted to callgraph late. */
1654 modref_summaries_lto::insert (struct cgraph_node
*node
, modref_summary_lto
*)
1656 /* We do not support adding new function when IPA information is already
1657 propagated. This is done only by SIMD cloning that is not very
1659 if (!DECL_STRUCT_FUNCTION (node
->decl
)
1660 || !opt_for_fn (node
->decl
, flag_ipa_modref
)
1663 summaries_lto
->remove (node
);
1666 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
1667 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), true);
1671 /* Called when new clone is inserted to callgraph late. */
1674 modref_summaries::duplicate (cgraph_node
*, cgraph_node
*dst
,
1675 modref_summary
*src_data
,
1676 modref_summary
*dst_data
)
1678 /* Do not duplicate optimization summaries; we do not handle parameter
1679 transforms on them. */
1680 if (this == optimization_summaries
)
1682 optimization_summaries
->remove (dst
);
1685 dst_data
->stores
= modref_records::create_ggc
1686 (src_data
->stores
->max_bases
,
1687 src_data
->stores
->max_refs
,
1688 src_data
->stores
->max_accesses
);
1689 dst_data
->stores
->copy_from (src_data
->stores
);
1690 dst_data
->loads
= modref_records::create_ggc
1691 (src_data
->loads
->max_bases
,
1692 src_data
->loads
->max_refs
,
1693 src_data
->loads
->max_accesses
);
1694 dst_data
->loads
->copy_from (src_data
->loads
);
1695 dst_data
->writes_errno
= src_data
->writes_errno
;
1698 /* Called when new clone is inserted to callgraph late. */
1701 modref_summaries_lto::duplicate (cgraph_node
*, cgraph_node
*,
1702 modref_summary_lto
*src_data
,
1703 modref_summary_lto
*dst_data
)
1705 /* Be sure that no further cloning happens after ipa-modref. If it does
1706 we will need to update signatures for possible param changes. */
1707 gcc_checking_assert (!((modref_summaries_lto
*)summaries_lto
)->propagated
);
1708 dst_data
->stores
= modref_records_lto::create_ggc
1709 (src_data
->stores
->max_bases
,
1710 src_data
->stores
->max_refs
,
1711 src_data
->stores
->max_accesses
);
1712 dst_data
->stores
->copy_from (src_data
->stores
);
1713 dst_data
->loads
= modref_records_lto::create_ggc
1714 (src_data
->loads
->max_bases
,
1715 src_data
->loads
->max_refs
,
1716 src_data
->loads
->max_accesses
);
1717 dst_data
->loads
->copy_from (src_data
->loads
);
1718 dst_data
->writes_errno
= src_data
->writes_errno
;
1723 /* Definition of the modref pass on GIMPLE. */
1724 const pass_data pass_data_modref
= {
1729 (PROP_cfg
| PROP_ssa
),
1736 class pass_modref
: public gimple_opt_pass
1739 pass_modref (gcc::context
*ctxt
)
1740 : gimple_opt_pass (pass_data_modref
, ctxt
) {}
1742 /* opt_pass methods: */
1745 return new pass_modref (m_ctxt
);
1747 virtual bool gate (function
*)
1749 return flag_ipa_modref
;
1751 virtual unsigned int execute (function
*);
1754 /* Encode TT to the output block OB using the summary streaming API. */
1757 write_modref_records (modref_records_lto
*tt
, struct output_block
*ob
)
1759 streamer_write_uhwi (ob
, tt
->max_bases
);
1760 streamer_write_uhwi (ob
, tt
->max_refs
);
1761 streamer_write_uhwi (ob
, tt
->max_accesses
);
1763 streamer_write_uhwi (ob
, tt
->every_base
);
1764 streamer_write_uhwi (ob
, vec_safe_length (tt
->bases
));
1766 modref_base_node
<tree
> *base_node
;
1767 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, base_node
)
1769 stream_write_tree (ob
, base_node
->base
, true);
1771 streamer_write_uhwi (ob
, base_node
->every_ref
);
1772 streamer_write_uhwi (ob
, vec_safe_length (base_node
->refs
));
1775 modref_ref_node
<tree
> *ref_node
;
1776 FOR_EACH_VEC_SAFE_ELT (base_node
->refs
, j
, ref_node
)
1778 stream_write_tree (ob
, ref_node
->ref
, true);
1779 streamer_write_uhwi (ob
, ref_node
->every_access
);
1780 streamer_write_uhwi (ob
, vec_safe_length (ref_node
->accesses
));
1783 modref_access_node
*access_node
;
1784 FOR_EACH_VEC_SAFE_ELT (ref_node
->accesses
, k
, access_node
)
1786 streamer_write_hwi (ob
, access_node
->parm_index
);
1787 if (access_node
->parm_index
!= -1)
1789 streamer_write_uhwi (ob
, access_node
->parm_offset_known
);
1790 if (access_node
->parm_offset_known
)
1792 streamer_write_poly_int64 (ob
, access_node
->parm_offset
);
1793 streamer_write_poly_int64 (ob
, access_node
->offset
);
1794 streamer_write_poly_int64 (ob
, access_node
->size
);
1795 streamer_write_poly_int64 (ob
, access_node
->max_size
);
1803 /* Read a modref_tree from the input block IB using the data from DATA_IN.
1804 This assumes that the tree was encoded using write_modref_tree.
1805 Either nolto_ret or lto_ret is initialized by the tree depending whether
1806 LTO streaming is expected or not. */
1809 read_modref_records (lto_input_block
*ib
, struct data_in
*data_in
,
1810 modref_records
**nolto_ret
,
1811 modref_records_lto
**lto_ret
)
1813 size_t max_bases
= streamer_read_uhwi (ib
);
1814 size_t max_refs
= streamer_read_uhwi (ib
);
1815 size_t max_accesses
= streamer_read_uhwi (ib
);
1818 *lto_ret
= modref_records_lto::create_ggc (max_bases
, max_refs
,
1821 *nolto_ret
= modref_records::create_ggc (max_bases
, max_refs
,
1823 gcc_checking_assert (lto_ret
|| nolto_ret
);
1825 size_t every_base
= streamer_read_uhwi (ib
);
1826 size_t nbase
= streamer_read_uhwi (ib
);
1828 gcc_assert (!every_base
|| nbase
== 0);
1832 (*nolto_ret
)->collapse ();
1834 (*lto_ret
)->collapse ();
1836 for (size_t i
= 0; i
< nbase
; i
++)
1838 tree base_tree
= stream_read_tree (ib
, data_in
);
1839 modref_base_node
<alias_set_type
> *nolto_base_node
= NULL
;
1840 modref_base_node
<tree
> *lto_base_node
= NULL
;
1842 /* At stream in time we have LTO alias info. Check if we streamed in
1843 something obviously unnecessary. Do not glob types by alias sets;
1844 it is not 100% clear that ltrans types will get merged same way.
1845 Types may get refined based on ODR type conflicts. */
1846 if (base_tree
&& !get_alias_set (base_tree
))
1850 fprintf (dump_file
, "Streamed in alias set 0 type ");
1851 print_generic_expr (dump_file
, base_tree
);
1852 fprintf (dump_file
, "\n");
1858 nolto_base_node
= (*nolto_ret
)->insert_base (base_tree
1859 ? get_alias_set (base_tree
)
1862 lto_base_node
= (*lto_ret
)->insert_base (base_tree
);
1863 size_t every_ref
= streamer_read_uhwi (ib
);
1864 size_t nref
= streamer_read_uhwi (ib
);
1866 gcc_assert (!every_ref
|| nref
== 0);
1869 if (nolto_base_node
)
1870 nolto_base_node
->collapse ();
1872 lto_base_node
->collapse ();
1874 for (size_t j
= 0; j
< nref
; j
++)
1876 tree ref_tree
= stream_read_tree (ib
, data_in
);
1878 if (ref_tree
&& !get_alias_set (ref_tree
))
1882 fprintf (dump_file
, "Streamed in alias set 0 type ");
1883 print_generic_expr (dump_file
, ref_tree
);
1884 fprintf (dump_file
, "\n");
1889 modref_ref_node
<alias_set_type
> *nolto_ref_node
= NULL
;
1890 modref_ref_node
<tree
> *lto_ref_node
= NULL
;
1892 if (nolto_base_node
)
1894 = nolto_base_node
->insert_ref (ref_tree
1895 ? get_alias_set (ref_tree
) : 0,
1898 lto_ref_node
= lto_base_node
->insert_ref (ref_tree
, max_refs
);
1900 size_t every_access
= streamer_read_uhwi (ib
);
1901 size_t naccesses
= streamer_read_uhwi (ib
);
1904 nolto_ref_node
->every_access
= every_access
;
1906 lto_ref_node
->every_access
= every_access
;
1908 for (size_t k
= 0; k
< naccesses
; k
++)
1910 int parm_index
= streamer_read_hwi (ib
);
1911 bool parm_offset_known
= false;
1912 poly_int64 parm_offset
= 0;
1913 poly_int64 offset
= 0;
1914 poly_int64 size
= -1;
1915 poly_int64 max_size
= -1;
1917 if (parm_index
!= -1)
1919 parm_offset_known
= streamer_read_uhwi (ib
);
1920 if (parm_offset_known
)
1922 parm_offset
= streamer_read_poly_int64 (ib
);
1923 offset
= streamer_read_poly_int64 (ib
);
1924 size
= streamer_read_poly_int64 (ib
);
1925 max_size
= streamer_read_poly_int64 (ib
);
1928 modref_access_node a
= {offset
, size
, max_size
, parm_offset
,
1929 parm_index
, parm_offset_known
};
1931 nolto_ref_node
->insert_access (a
, max_accesses
);
1933 lto_ref_node
->insert_access (a
, max_accesses
);
1938 (*lto_ret
)->cleanup ();
1940 (*nolto_ret
)->cleanup ();
1943 /* Callback for write_summary. */
1948 struct output_block
*ob
= create_output_block (LTO_section_ipa_modref
);
1949 lto_symtab_encoder_t encoder
= ob
->decl_state
->symtab_node_encoder
;
1950 unsigned int count
= 0;
1955 streamer_write_uhwi (ob
, 0);
1956 streamer_write_char_stream (ob
->main_stream
, 0);
1957 produce_asm (ob
, NULL
);
1958 destroy_output_block (ob
);
1962 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
1964 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
1965 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
1966 modref_summary_lto
*r
;
1968 if (cnode
&& cnode
->definition
&& !cnode
->alias
1969 && (r
= summaries_lto
->get (cnode
))
1970 && r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
1973 streamer_write_uhwi (ob
, count
);
1975 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
1977 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
1978 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
1980 if (cnode
&& cnode
->definition
&& !cnode
->alias
)
1982 modref_summary_lto
*r
= summaries_lto
->get (cnode
);
1984 if (!r
|| !r
->useful_p (flags_from_decl_or_type (cnode
->decl
)))
1987 streamer_write_uhwi (ob
, lto_symtab_encoder_encode (encoder
, cnode
));
1989 write_modref_records (r
->loads
, ob
);
1990 write_modref_records (r
->stores
, ob
);
1992 struct bitpack_d bp
= bitpack_create (ob
->main_stream
);
1993 bp_pack_value (&bp
, r
->writes_errno
, 1);
1996 for (cgraph_edge
*e
= cnode
->indirect_calls
;
1997 e
; e
= e
->next_callee
)
1999 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
2000 bp_pack_value (&bp
, sum
!= NULL
, 1);
2002 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
2004 for (cgraph_edge
*e
= cnode
->callees
; e
; e
= e
->next_callee
)
2006 class fnspec_summary
*sum
= fnspec_summaries
->get (e
);
2007 bp_pack_value (&bp
, sum
!= NULL
, 1);
2009 bp_pack_string (ob
, &bp
, sum
->fnspec
, true);
2012 streamer_write_bitpack (&bp
);
2015 streamer_write_char_stream (ob
->main_stream
, 0);
2016 produce_asm (ob
, NULL
);
2017 destroy_output_block (ob
);
2021 read_section (struct lto_file_decl_data
*file_data
, const char *data
,
2024 const struct lto_function_header
*header
2025 = (const struct lto_function_header
*) data
;
2026 const int cfg_offset
= sizeof (struct lto_function_header
);
2027 const int main_offset
= cfg_offset
+ header
->cfg_size
;
2028 const int string_offset
= main_offset
+ header
->main_size
;
2029 struct data_in
*data_in
;
2031 unsigned int f_count
;
2033 lto_input_block
ib ((const char *) data
+ main_offset
, header
->main_size
,
2034 file_data
->mode_table
);
2037 = lto_data_in_create (file_data
, (const char *) data
+ string_offset
,
2038 header
->string_size
, vNULL
);
2039 f_count
= streamer_read_uhwi (&ib
);
2040 for (i
= 0; i
< f_count
; i
++)
2042 struct cgraph_node
*node
;
2043 lto_symtab_encoder_t encoder
;
2045 unsigned int index
= streamer_read_uhwi (&ib
);
2046 encoder
= file_data
->symtab_node_encoder
;
2047 node
= dyn_cast
<cgraph_node
*> (lto_symtab_encoder_deref (encoder
,
2050 modref_summary
*modref_sum
= summaries
2051 ? summaries
->get_create (node
) : NULL
;
2052 modref_summary_lto
*modref_sum_lto
= summaries_lto
2053 ? summaries_lto
->get_create (node
)
2055 if (optimization_summaries
)
2056 modref_sum
= optimization_summaries
->get_create (node
);
2059 modref_sum
->writes_errno
= false;
2061 modref_sum_lto
->writes_errno
= false;
2063 gcc_assert (!modref_sum
|| (!modref_sum
->loads
2064 && !modref_sum
->stores
));
2065 gcc_assert (!modref_sum_lto
|| (!modref_sum_lto
->loads
2066 && !modref_sum_lto
->stores
));
2067 read_modref_records (&ib
, data_in
,
2068 modref_sum
? &modref_sum
->loads
: NULL
,
2069 modref_sum_lto
? &modref_sum_lto
->loads
: NULL
);
2070 read_modref_records (&ib
, data_in
,
2071 modref_sum
? &modref_sum
->stores
: NULL
,
2072 modref_sum_lto
? &modref_sum_lto
->stores
: NULL
);
2073 struct bitpack_d bp
= streamer_read_bitpack (&ib
);
2074 if (bp_unpack_value (&bp
, 1))
2077 modref_sum
->writes_errno
= true;
2079 modref_sum_lto
->writes_errno
= true;
2083 for (cgraph_edge
*e
= node
->indirect_calls
; e
; e
= e
->next_callee
)
2085 if (bp_unpack_value (&bp
, 1))
2087 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
2088 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
2091 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
2093 if (bp_unpack_value (&bp
, 1))
2095 class fnspec_summary
*sum
= fnspec_summaries
->get_create (e
);
2096 sum
->fnspec
= xstrdup (bp_unpack_string (data_in
, &bp
));
2102 fprintf (dump_file
, "Read modref for %s\n",
2103 node
->dump_name ());
2105 modref_sum
->dump (dump_file
);
2107 modref_sum_lto
->dump (dump_file
);
2111 lto_free_section_data (file_data
, LTO_section_ipa_modref
, NULL
, data
,
2113 lto_data_in_delete (data_in
);
2116 /* Callback for read_summary. */
2121 struct lto_file_decl_data
**file_data_vec
= lto_get_file_decl_data ();
2122 struct lto_file_decl_data
*file_data
;
2125 gcc_checking_assert (!optimization_summaries
&& !summaries
&& !summaries_lto
);
2127 optimization_summaries
= modref_summaries::create_ggc (symtab
);
2130 if (flag_wpa
|| flag_incremental_link
== INCREMENTAL_LINK_LTO
)
2131 summaries_lto
= modref_summaries_lto::create_ggc (symtab
);
2133 || (flag_incremental_link
== INCREMENTAL_LINK_LTO
2134 && flag_fat_lto_objects
))
2135 summaries
= modref_summaries::create_ggc (symtab
);
2136 if (!fnspec_summaries
)
2137 fnspec_summaries
= new fnspec_summaries_t (symtab
);
2140 while ((file_data
= file_data_vec
[j
++]))
2143 const char *data
= lto_get_summary_section_data (file_data
,
2144 LTO_section_ipa_modref
,
2147 read_section (file_data
, data
, len
);
2149 /* Fatal error here. We do not want to support compiling ltrans units
2150 with different version of compiler or different flags than the WPA
2151 unit, so this should never happen. */
2152 fatal_error (input_location
,
2153 "IPA modref summary is missing in input file");
2157 /* If signature changed, update the summary. */
2160 update_signature (struct cgraph_node
*node
)
2162 clone_info
*info
= clone_info::get (node
);
2163 if (!info
|| !info
->param_adjustments
)
2166 modref_summary
*r
= optimization_summaries
2167 ? optimization_summaries
->get (node
) : NULL
;
2168 modref_summary_lto
*r_lto
= summaries_lto
2169 ? summaries_lto
->get (node
) : NULL
;
2174 fprintf (dump_file
, "Updating summary for %s from:\n",
2175 node
->dump_name ());
2176 r
->dump (dump_file
);
2180 ipa_adjusted_param
*p
;
2182 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2184 int idx
= info
->param_adjustments
->get_original_index (i
);
2189 auto_vec
<int, 32> map
;
2191 map
.reserve (max
+ 1);
2192 for (i
= 0; i
<= max
; i
++)
2193 map
.quick_push (-1);
2194 FOR_EACH_VEC_SAFE_ELT (info
->param_adjustments
->m_adj_params
, i
, p
)
2196 int idx
= info
->param_adjustments
->get_original_index (i
);
2202 r
->loads
->remap_params (&map
);
2203 r
->stores
->remap_params (&map
);
2207 r_lto
->loads
->remap_params (&map
);
2208 r_lto
->stores
->remap_params (&map
);
2212 fprintf (dump_file
, "to:\n");
2214 r
->dump (dump_file
);
2216 r_lto
->dump (dump_file
);
2221 /* Definition of the modref IPA pass. */
2222 const pass_data pass_data_ipa_modref
=
2224 IPA_PASS
, /* type */
2225 "modref", /* name */
2226 OPTGROUP_IPA
, /* optinfo_flags */
2227 TV_IPA_MODREF
, /* tv_id */
2228 0, /* properties_required */
2229 0, /* properties_provided */
2230 0, /* properties_destroyed */
2231 0, /* todo_flags_start */
2232 ( TODO_dump_symtab
), /* todo_flags_finish */
2235 class pass_ipa_modref
: public ipa_opt_pass_d
2238 pass_ipa_modref (gcc::context
*ctxt
)
2239 : ipa_opt_pass_d (pass_data_ipa_modref
, ctxt
,
2240 modref_generate
, /* generate_summary */
2241 modref_write
, /* write_summary */
2242 modref_read
, /* read_summary */
2243 modref_write
, /* write_optimization_summary */
2244 modref_read
, /* read_optimization_summary */
2245 NULL
, /* stmt_fixup */
2246 0, /* function_transform_todo_flags_start */
2247 NULL
, /* function_transform */
2248 NULL
) /* variable_transform */
2251 /* opt_pass methods: */
2252 opt_pass
*clone () { return new pass_ipa_modref (m_ctxt
); }
2253 virtual bool gate (function
*)
2257 virtual unsigned int execute (function
*);
2263 unsigned int pass_modref::execute (function
*f
)
2265 analyze_function (f
, false);
2270 make_pass_modref (gcc::context
*ctxt
)
2272 return new pass_modref (ctxt
);
2276 make_pass_ipa_modref (gcc::context
*ctxt
)
2278 return new pass_ipa_modref (ctxt
);
2281 /* Skip edges from and to nodes without ipa_pure_const enabled.
2282 Ignore not available symbols. */
2285 ignore_edge (struct cgraph_edge
*e
)
2287 /* We merge summaries of inline clones into summaries of functions they
2288 are inlined to. For that reason the complete function bodies must
2290 if (!e
->inline_failed
)
2292 enum availability avail
;
2293 cgraph_node
*callee
= e
->callee
->function_or_virtual_thunk_symbol
2294 (&avail
, e
->caller
);
2296 return (avail
<= AVAIL_INTERPOSABLE
2297 || ((!optimization_summaries
|| !optimization_summaries
->get (callee
))
2298 && (!summaries_lto
|| !summaries_lto
->get (callee
)))
2299 || flags_from_decl_or_type (e
->callee
->decl
)
2300 & (ECF_CONST
| ECF_NOVOPS
));
2303 /* Compute parm_map for CALLEE_EDGE. */
2306 compute_parm_map (cgraph_edge
*callee_edge
, vec
<modref_parm_map
> *parm_map
)
2308 class ipa_edge_args
*args
;
2309 if (ipa_node_params_sum
2310 && !callee_edge
->call_stmt_cannot_inline_p
2311 && (args
= IPA_EDGE_REF (callee_edge
)) != NULL
)
2313 int i
, count
= ipa_get_cs_argument_count (args
);
2314 class ipa_node_params
*caller_parms_info
, *callee_pi
;
2315 class ipa_call_summary
*es
2316 = ipa_call_summaries
->get (callee_edge
);
2318 = callee_edge
->callee
->function_or_virtual_thunk_symbol
2319 (NULL
, callee_edge
->caller
);
2321 caller_parms_info
= IPA_NODE_REF (callee_edge
->caller
->inlined_to
2322 ? callee_edge
->caller
->inlined_to
2323 : callee_edge
->caller
);
2324 callee_pi
= IPA_NODE_REF (callee
);
2326 (*parm_map
).safe_grow_cleared (count
, true);
2328 for (i
= 0; i
< count
; i
++)
2330 if (es
&& es
->param
[i
].points_to_local_or_readonly_memory
)
2332 (*parm_map
)[i
].parm_index
= -2;
2336 struct ipa_jump_func
*jf
2337 = ipa_get_ith_jump_func (args
, i
);
2338 if (jf
&& callee_pi
)
2340 tree cst
= ipa_value_from_jfunc (caller_parms_info
,
2344 if (cst
&& points_to_local_or_readonly_memory_p (cst
))
2346 (*parm_map
)[i
].parm_index
= -2;
2350 if (jf
&& jf
->type
== IPA_JF_PASS_THROUGH
)
2352 (*parm_map
)[i
].parm_index
2353 = ipa_get_jf_pass_through_formal_id (jf
);
2354 if (ipa_get_jf_pass_through_operation (jf
) == NOP_EXPR
)
2356 (*parm_map
)[i
].parm_offset_known
= true;
2357 (*parm_map
)[i
].parm_offset
= 0;
2359 else if (ipa_get_jf_pass_through_operation (jf
)
2360 == POINTER_PLUS_EXPR
2361 && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf
),
2362 &(*parm_map
)[i
].parm_offset
))
2363 (*parm_map
)[i
].parm_offset_known
= true;
2365 (*parm_map
)[i
].parm_offset_known
= false;
2368 if (jf
&& jf
->type
== IPA_JF_ANCESTOR
)
2370 (*parm_map
)[i
].parm_index
= ipa_get_jf_ancestor_formal_id (jf
);
2371 (*parm_map
)[i
].parm_offset_known
= true;
2373 (!(ipa_get_jf_ancestor_offset (jf
) & (BITS_PER_UNIT
- 1)));
2374 (*parm_map
)[i
].parm_offset
2375 = ipa_get_jf_ancestor_offset (jf
) >> LOG2_BITS_PER_UNIT
;
2378 (*parm_map
)[i
].parm_index
= -1;
2382 fprintf (dump_file
, " Parm map: ");
2383 for (i
= 0; i
< count
; i
++)
2384 fprintf (dump_file
, " %i", (*parm_map
)[i
].parm_index
);
2385 fprintf (dump_file
, "\n");
2392 /* Call EDGE was inlined; merge summary from callee to the caller. */
2395 ipa_merge_modref_summary_after_inlining (cgraph_edge
*edge
)
2397 if (!summaries
&& !summaries_lto
)
2400 struct cgraph_node
*to
= (edge
->caller
->inlined_to
2401 ? edge
->caller
->inlined_to
: edge
->caller
);
2402 class modref_summary
*to_info
= summaries
? summaries
->get (to
) : NULL
;
2403 class modref_summary_lto
*to_info_lto
= summaries_lto
2404 ? summaries_lto
->get (to
) : NULL
;
2406 if (!to_info
&& !to_info_lto
)
2409 summaries
->remove (edge
->callee
);
2411 summaries_lto
->remove (edge
->callee
);
2415 class modref_summary
*callee_info
= summaries
? summaries
->get (edge
->callee
)
2417 class modref_summary_lto
*callee_info_lto
2418 = summaries_lto
? summaries_lto
->get (edge
->callee
) : NULL
;
2419 int flags
= flags_from_decl_or_type (edge
->callee
->decl
);
2421 if (!callee_info
&& to_info
)
2423 if (ignore_stores_p (edge
->caller
->decl
, flags
))
2424 to_info
->loads
->collapse ();
2427 summaries
->remove (to
);
2431 if (!callee_info_lto
&& to_info_lto
)
2433 if (ignore_stores_p (edge
->caller
->decl
, flags
))
2434 to_info_lto
->loads
->collapse ();
2437 summaries_lto
->remove (to
);
2441 if (callee_info
|| callee_info_lto
)
2443 auto_vec
<modref_parm_map
, 32> parm_map
;
2445 compute_parm_map (edge
, &parm_map
);
2447 if (!ignore_stores_p (edge
->caller
->decl
, flags
))
2449 if (to_info
&& callee_info
)
2450 to_info
->stores
->merge (callee_info
->stores
, &parm_map
);
2451 if (to_info_lto
&& callee_info_lto
)
2452 to_info_lto
->stores
->merge (callee_info_lto
->stores
, &parm_map
);
2454 if (to_info
&& callee_info
)
2455 to_info
->loads
->merge (callee_info
->loads
, &parm_map
);
2456 if (to_info_lto
&& callee_info_lto
)
2457 to_info_lto
->loads
->merge (callee_info_lto
->loads
, &parm_map
);
2461 if (to_info
&& !to_info
->useful_p (flags
))
2464 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
2466 summaries
->remove (to
);
2468 else if (to_info
&& dump_file
)
2471 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
2473 to_info
->dump (dump_file
);
2476 summaries
->remove (edge
->callee
);
2480 if (to_info_lto
&& !to_info_lto
->useful_p (flags
))
2483 fprintf (dump_file
, "Removed mod-ref summary for %s\n",
2485 summaries_lto
->remove (to
);
2487 else if (to_info_lto
&& dump_file
)
2490 fprintf (dump_file
, "Updated mod-ref summary for %s\n",
2492 to_info_lto
->dump (dump_file
);
2494 if (callee_info_lto
)
2495 summaries_lto
->remove (edge
->callee
);
2500 /* Get parameter type from DECL. This is only safe for special cases
2501 like builtins we create fnspec for because the type match is checked
2502 at fnspec creation time. */
2505 get_parm_type (tree decl
, unsigned int i
)
2507 tree t
= TYPE_ARG_TYPES (TREE_TYPE (decl
));
2509 for (unsigned int p
= 0; p
< i
; p
++)
2511 return TREE_VALUE (t
);
2514 /* Return access mode for argument I of call E with FNSPEC. */
2516 static modref_access_node
2517 get_access_for_fnspec (cgraph_edge
*e
, attr_fnspec
&fnspec
,
2518 unsigned int i
, modref_parm_map
&map
)
2520 tree size
= NULL_TREE
;
2521 unsigned int size_arg
;
2523 if (!fnspec
.arg_specified_p (i
))
2525 else if (fnspec
.arg_max_access_size_given_by_arg_p (i
, &size_arg
))
2527 cgraph_node
*node
= e
->caller
->inlined_to
2528 ? e
->caller
->inlined_to
: e
->caller
;
2529 class ipa_node_params
*caller_parms_info
= IPA_NODE_REF (node
);
2530 class ipa_edge_args
*args
= IPA_EDGE_REF (e
);
2531 struct ipa_jump_func
*jf
= ipa_get_ith_jump_func (args
, size_arg
);
2534 size
= ipa_value_from_jfunc (caller_parms_info
, jf
,
2535 get_parm_type (e
->callee
->decl
, size_arg
));
2537 else if (fnspec
.arg_access_size_given_by_type_p (i
))
2538 size
= TYPE_SIZE_UNIT (get_parm_type (e
->callee
->decl
, i
));
2539 modref_access_node a
= {0, -1, -1,
2540 map
.parm_offset
, map
.parm_index
,
2541 map
.parm_offset_known
};
2542 poly_int64 size_hwi
;
2544 && poly_int_tree_p (size
, &size_hwi
)
2545 && coeffs_in_range_p (size_hwi
, 0,
2546 HOST_WIDE_INT_MAX
/ BITS_PER_UNIT
))
2549 a
.max_size
= size_hwi
<< LOG2_BITS_PER_UNIT
;
2554 /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
2555 CUR_SUMMARY_LTO accordingly. Return true if something changed. */
2558 propagate_unknown_call (cgraph_node
*node
,
2559 cgraph_edge
*e
, int ecf_flags
,
2560 modref_summary
**cur_summary_ptr
,
2561 modref_summary_lto
**cur_summary_lto_ptr
)
2563 bool changed
= false;
2564 modref_summary
*cur_summary
= cur_summary_ptr
? *cur_summary_ptr
: NULL
;
2565 modref_summary_lto
*cur_summary_lto
= cur_summary_lto_ptr
2566 ? *cur_summary_lto_ptr
: NULL
;
2567 class fnspec_summary
*fnspec_sum
= fnspec_summaries
->get (e
);
2568 auto_vec
<modref_parm_map
, 32> parm_map
;
2570 && compute_parm_map (e
, &parm_map
))
2572 attr_fnspec
fnspec (fnspec_sum
->fnspec
);
2574 gcc_checking_assert (fnspec
.known_p ());
2575 if (fnspec
.global_memory_read_p ())
2576 collapse_loads (cur_summary
, cur_summary_lto
);
2579 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
2580 for (unsigned i
= 0; i
< parm_map
.length () && t
;
2581 i
++, t
= TREE_CHAIN (t
))
2582 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
2584 else if (!fnspec
.arg_specified_p (i
)
2585 || fnspec
.arg_maybe_read_p (i
))
2587 modref_parm_map map
= parm_map
[i
];
2588 if (map
.parm_index
== -2)
2590 if (map
.parm_index
== -1)
2592 collapse_loads (cur_summary
, cur_summary_lto
);
2596 changed
|= cur_summary
->loads
->insert
2597 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
2598 if (cur_summary_lto
)
2599 changed
|= cur_summary_lto
->loads
->insert
2600 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
2603 if (ignore_stores_p (node
->decl
, ecf_flags
))
2605 else if (fnspec
.global_memory_written_p ())
2606 collapse_stores (cur_summary
, cur_summary_lto
);
2609 tree t
= TYPE_ARG_TYPES (TREE_TYPE (e
->callee
->decl
));
2610 for (unsigned i
= 0; i
< parm_map
.length () && t
;
2611 i
++, t
= TREE_CHAIN (t
))
2612 if (!POINTER_TYPE_P (TREE_VALUE (t
)))
2614 else if (!fnspec
.arg_specified_p (i
)
2615 || fnspec
.arg_maybe_written_p (i
))
2617 modref_parm_map map
= parm_map
[i
];
2618 if (map
.parm_index
== -2)
2620 if (map
.parm_index
== -1)
2622 collapse_stores (cur_summary
, cur_summary_lto
);
2626 changed
|= cur_summary
->stores
->insert
2627 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
2628 if (cur_summary_lto
)
2629 changed
|= cur_summary_lto
->stores
->insert
2630 (0, 0, get_access_for_fnspec (e
, fnspec
, i
, map
));
2633 if (fnspec
.errno_maybe_written_p () && flag_errno_math
)
2635 if (cur_summary
&& !cur_summary
->writes_errno
)
2637 cur_summary
->writes_errno
= true;
2640 if (cur_summary_lto
&& !cur_summary_lto
->writes_errno
)
2642 cur_summary_lto
->writes_errno
= true;
2648 if (ignore_stores_p (node
->decl
, ecf_flags
))
2651 fprintf (dump_file
, " collapsing loads\n");
2652 return collapse_loads (cur_summary
, cur_summary_lto
);
2654 if (optimization_summaries
)
2655 optimization_summaries
->remove (node
);
2657 summaries_lto
->remove (node
);
2658 if (cur_summary_ptr
)
2659 *cur_summary_ptr
= NULL
;
2660 if (cur_summary_lto_ptr
)
2661 *cur_summary_lto_ptr
= NULL
;
2663 fprintf (dump_file
, " Giving up\n");
2667 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE. */
2670 modref_propagate_in_scc (cgraph_node
*component_node
)
2672 bool changed
= true;
2678 for (struct cgraph_node
*cur
= component_node
; cur
;
2679 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
2681 cgraph_node
*node
= cur
->inlined_to
? cur
->inlined_to
: cur
;
2682 modref_summary
*cur_summary
= optimization_summaries
2683 ? optimization_summaries
->get (node
)
2685 modref_summary_lto
*cur_summary_lto
= summaries_lto
2686 ? summaries_lto
->get (node
)
2689 if (!cur_summary
&& !cur_summary_lto
)
2693 fprintf (dump_file
, " Processing %s%s%s\n",
2695 TREE_READONLY (cur
->decl
) ? " (const)" : "",
2696 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
2698 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
2700 if (e
->indirect_info
->ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
2703 fprintf (dump_file
, " Indirect call"
2704 "collapsing loads\n");
2705 changed
|= propagate_unknown_call
2706 (node
, e
, e
->indirect_info
->ecf_flags
,
2707 &cur_summary
, &cur_summary_lto
);
2708 if (!cur_summary
&& !cur_summary_lto
)
2712 if (!cur_summary
&& !cur_summary_lto
)
2715 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
2716 callee_edge
= callee_edge
->next_callee
)
2718 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
2719 modref_summary
*callee_summary
= NULL
;
2720 modref_summary_lto
*callee_summary_lto
= NULL
;
2721 struct cgraph_node
*callee
;
2723 if (flags
& (ECF_CONST
| ECF_NOVOPS
)
2724 || !callee_edge
->inline_failed
)
2727 /* Get the callee and its summary. */
2728 enum availability avail
;
2729 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
2732 /* It is not necessary to re-process calls outside of the
2736 || ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
2737 != ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
))
2741 fprintf (dump_file
, " Call to %s\n",
2742 callee_edge
->callee
->dump_name ());
2744 bool ignore_stores
= ignore_stores_p (cur
->decl
, flags
);
2746 if (avail
<= AVAIL_INTERPOSABLE
)
2749 fprintf (dump_file
, " Call target interposable"
2750 " or not available\n");
2751 changed
|= propagate_unknown_call
2752 (node
, callee_edge
, flags
,
2753 &cur_summary
, &cur_summary_lto
);
2754 if (!cur_summary
&& !cur_summary_lto
)
2759 /* We don't know anything about CALLEE, hence we cannot tell
2760 anything about the entire component. */
2763 && !(callee_summary
= optimization_summaries
->get (callee
)))
2766 fprintf (dump_file
, " No call target summary\n");
2767 changed
|= propagate_unknown_call
2768 (node
, callee_edge
, flags
,
2769 &cur_summary
, NULL
);
2770 if (!cur_summary
&& !cur_summary_lto
)
2774 && !(callee_summary_lto
= summaries_lto
->get (callee
)))
2777 fprintf (dump_file
, " No call target summary\n");
2778 changed
|= propagate_unknown_call
2779 (node
, callee_edge
, flags
,
2780 NULL
, &cur_summary_lto
);
2781 if (!cur_summary
&& !cur_summary_lto
)
2785 /* We can not safely optimize based on summary of callee if it
2786 does not always bind to current def: it is possible that
2787 memory load was optimized out earlier which may not happen in
2788 the interposed variant. */
2789 if (!callee_edge
->binds_to_current_def_p ())
2791 changed
|= collapse_loads (cur_summary
, cur_summary_lto
);
2793 fprintf (dump_file
, " May not bind local;"
2794 " collapsing loads\n");
2798 auto_vec
<modref_parm_map
, 32> parm_map
;
2800 compute_parm_map (callee_edge
, &parm_map
);
2802 /* Merge in callee's information. */
2805 changed
|= cur_summary
->loads
->merge
2806 (callee_summary
->loads
, &parm_map
);
2809 changed
|= cur_summary
->stores
->merge
2810 (callee_summary
->stores
, &parm_map
);
2811 if (!cur_summary
->writes_errno
2812 && callee_summary
->writes_errno
)
2814 cur_summary
->writes_errno
= true;
2819 if (callee_summary_lto
)
2821 changed
|= cur_summary_lto
->loads
->merge
2822 (callee_summary_lto
->loads
, &parm_map
);
2825 changed
|= cur_summary_lto
->stores
->merge
2826 (callee_summary_lto
->stores
, &parm_map
);
2827 if (!cur_summary_lto
->writes_errno
2828 && callee_summary_lto
->writes_errno
)
2830 cur_summary_lto
->writes_errno
= true;
2835 if (dump_file
&& changed
)
2838 cur_summary
->dump (dump_file
);
2839 if (cur_summary_lto
)
2840 cur_summary_lto
->dump (dump_file
);
2849 "Propagation finished in %i iterations\n", iteration
);
2850 for (struct cgraph_node
*cur
= component_node
; cur
;
2851 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
2852 if (!cur
->inlined_to
)
2854 modref_summary
*cur_summary
= optimization_summaries
2855 ? optimization_summaries
->get (cur
)
2857 modref_summary_lto
*cur_summary_lto
= summaries_lto
2858 ? summaries_lto
->get (cur
)
2861 fprintf (dump_file
, "Propagated modref for %s%s%s\n",
2863 TREE_READONLY (cur
->decl
) ? " (const)" : "",
2864 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
2865 if (optimization_summaries
)
2868 cur_summary
->dump (dump_file
);
2870 fprintf (dump_file
, " Not tracked\n");
2874 if (cur_summary_lto
)
2875 cur_summary_lto
->dump (dump_file
);
2877 fprintf (dump_file
, " Not tracked (lto)\n");
2883 /* Run the IPA pass. This will take a function's summaries and calls and
2884 construct new summaries which represent a transitive closure. So that
2885 summary of an analyzed function contains information about the loads and
2886 stores that the function or any function that it calls does. */
2889 pass_ipa_modref::execute (function
*)
2891 if (!summaries
&& !summaries_lto
)
2894 if (optimization_summaries
)
2895 ggc_delete (optimization_summaries
);
2896 optimization_summaries
= summaries
;
2899 struct cgraph_node
**order
= XCNEWVEC (struct cgraph_node
*,
2900 symtab
->cgraph_count
);
2902 order_pos
= ipa_reduced_postorder (order
, true, ignore_edge
);
2905 /* Iterate over all strongly connected components in post-order. */
2906 for (i
= 0; i
< order_pos
; i
++)
2908 /* Get the component's representative. That's just any node in the
2909 component from which we can traverse the entire component. */
2910 struct cgraph_node
*component_node
= order
[i
];
2913 fprintf (dump_file
, "\n\nStart of SCC component\n");
2915 modref_propagate_in_scc (component_node
);
2918 FOR_EACH_FUNCTION (node
)
2919 update_signature (node
);
2921 ((modref_summaries_lto
*)summaries_lto
)->propagated
= true;
2922 ipa_free_postorder_info ();
2924 delete fnspec_summaries
;
2925 fnspec_summaries
= NULL
;
2929 /* Summaries must stay alive until end of compilation. */
2932 ipa_modref_c_finalize ()
2934 if (optimization_summaries
)
2935 ggc_delete (optimization_summaries
);
2936 optimization_summaries
= NULL
;
2937 gcc_checking_assert (!summaries
);
2940 ggc_delete (summaries_lto
);
2941 summaries_lto
= NULL
;
2943 if (fnspec_summaries
)
2944 delete fnspec_summaries
;
2945 fnspec_summaries
= NULL
;
2948 #include "gt-ipa-modref.h"