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 and
30 In future more information will be tracked.
32 This file contains a tree pass and an IPA pass. Both performs the same
33 analys however tree pass is executed during early and late optimization
34 passes to propagate info downwards in the compilation order. IPA pass
35 propagates across the callgraph and is able to handle recursion and works on
36 whole program during link-time analysis.
38 LTO mode differs from the local mode by not recording alias sets but types
39 that are translated to alias sets later. This is necessary in order stream
40 the information because the alias sets are rebuild at stream-in time and may
41 not correspond to ones seen during analysis. For this reason part of analysis
46 #include "coretypes.h"
50 #include "alloc-pool.h"
51 #include "tree-pass.h"
52 #include "gimple-iterator.h"
55 #include "ipa-utils.h"
56 #include "symbol-summary.h"
57 #include "gimple-pretty-print.h"
58 #include "gimple-walk.h"
59 #include "print-tree.h"
60 #include "tree-streamer.h"
63 #include "ipa-modref-tree.h"
64 #include "ipa-modref.h"
65 #include "value-range.h"
67 #include "ipa-fnsummary.h"
69 /* Class (from which there is one global instance) that holds modref summaries
70 for all analyzed functions. */
71 class GTY((user
)) modref_summaries
72 : public fast_function_summary
<modref_summary
*, va_gc
>
75 modref_summaries (symbol_table
*symtab
)
76 : fast_function_summary
<modref_summary
*, va_gc
> (symtab
) {}
77 virtual void insert (cgraph_node
*, modref_summary
*state
);
78 virtual void duplicate (cgraph_node
*src_node
,
79 cgraph_node
*dst_node
,
80 modref_summary
*src_data
,
81 modref_summary
*dst_data
);
82 /* This flag controls whether newly inserted functions should be analyzed
83 in IPA or normal mode. Functions inserted between IPA analysis and
84 ipa-modref pass execution needs to be analyzed in IPA mode while all
85 other insertions leads to normal analysis. */
89 /* Global variable holding all modref summaries. */
90 static GTY(()) fast_function_summary
<modref_summary
*, va_gc
> *summaries
;
92 /* Summary for a single function which this pass produces. */
94 modref_summary::modref_summary ()
95 : loads (NULL
), stores (NULL
), loads_lto (NULL
),
96 stores_lto (NULL
), finished (0)
100 modref_summary::~modref_summary ()
107 ggc_delete (loads_lto
);
109 ggc_delete (stores_lto
);
112 /* Return true if lto summary is potentially useful for optimization. */
115 modref_summary::lto_useful_p (int ecf_flags
)
117 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
119 if (loads_lto
&& !loads_lto
->every_base
)
121 if (ecf_flags
& ECF_PURE
)
123 return stores_lto
&& !stores_lto
->every_base
;
126 /* Return true if summary is potentially useful for optimization. */
129 modref_summary::useful_p (int ecf_flags
)
131 if (ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
133 if (lto_useful_p (ecf_flags
))
135 if (loads
&& !loads
->every_base
)
137 if (ecf_flags
& ECF_PURE
)
139 return stores
&& !loads
->every_base
;
142 /* Dump records TT to OUT. */
145 dump_records (modref_records
*tt
, FILE *out
)
147 fprintf (out
, " Limits: %i bases, %i refs\n",
148 (int)tt
->max_bases
, (int)tt
->max_refs
);
151 fprintf (out
, " Every base\n");
155 modref_base_node
<alias_set_type
> *n
;
156 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
158 fprintf (out
, " Base %i: alias set %i\n", (int)i
, n
->base
);
161 fprintf (out
, " Every ref\n");
165 modref_ref_node
<alias_set_type
> *r
;
166 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
168 fprintf (out
, " Ref %i: alias set %i\n", (int)j
, r
->ref
);
173 /* Dump records TT to OUT. */
176 dump_lto_records (modref_records_lto
*tt
, FILE *out
)
178 fprintf (out
, " Limits: %i bases, %i refs\n",
179 (int)tt
->max_bases
, (int)tt
->max_refs
);
182 fprintf (out
, " Every base\n");
186 modref_base_node
<tree
> *n
;
187 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, n
)
189 fprintf (out
, " Base %i:", (int)i
);
190 print_generic_expr (dump_file
, n
->base
);
191 fprintf (out
, " (alias set %i)\n",
192 n
->base
? get_alias_set (n
->base
) : 0);
195 fprintf (out
, " Every ref\n");
199 modref_ref_node
<tree
> *r
;
200 FOR_EACH_VEC_SAFE_ELT (n
->refs
, j
, r
)
202 fprintf (out
, " Ref %i:", (int)j
);
203 print_generic_expr (dump_file
, r
->ref
);
204 fprintf (out
, " (alias set %i)\n",
205 r
->ref
? get_alias_set (r
->ref
) : 0);
213 modref_summary::dump (FILE *out
)
217 fprintf (out
, " loads:\n");
218 dump_records (loads
, out
);
222 fprintf (out
, " stores:\n");
223 dump_records (stores
, out
);
227 fprintf (out
, " LTO loads:\n");
228 dump_lto_records (loads_lto
, out
);
232 fprintf (out
, " LTO stores:\n");
233 dump_lto_records (stores_lto
, out
);
238 /* Get function summary for FUNC if it exists, return NULL otherwise. */
241 get_modref_function_summary (cgraph_node
*func
)
243 /* Avoid creation of the summary too early (e.g. when front-end calls us). */
247 /* A single function body may be represented by multiple symbols with
248 different visibility. For example, if FUNC is an interposable alias,
249 we don't want to return anything, even if we have summary for the target
251 enum availability avail
;
252 func
= func
->function_or_virtual_thunk_symbol
253 (&avail
, cgraph_node::get (current_function_decl
));
254 if (avail
<= AVAIL_INTERPOSABLE
)
257 /* Attempt to get summary for FUNC. If analysis of FUNC hasn't finished yet,
258 don't return anything. */
259 modref_summary
*r
= summaries
->get (func
);
260 if (r
&& r
->finished
)
266 /* Record access into the modref_records data structure. */
269 record_access (modref_records
*tt
, ao_ref
*ref
)
271 alias_set_type base_set
= !flag_strict_aliasing
? 0
272 : ao_ref_base_alias_set (ref
);
273 alias_set_type ref_set
= !flag_strict_aliasing
? 0
274 : (ao_ref_alias_set (ref
));
277 fprintf (dump_file
, " - Recording base_set=%i ref_set=%i\n",
280 tt
->insert (base_set
, ref_set
);
283 /* IPA version of record_access_tree. */
286 record_access_lto (modref_records_lto
*tt
, ao_ref
*ref
)
288 /* get_alias_set sometimes use different type to compute the alias set
289 than TREE_TYPE (base). Do same adjustments. */
290 tree base_type
= NULL_TREE
, ref_type
= NULL_TREE
;
291 if (flag_strict_aliasing
)
296 while (handled_component_p (base
))
297 base
= TREE_OPERAND (base
, 0);
299 base_type
= reference_alias_ptr_type_1 (&base
);
302 base_type
= TREE_TYPE (base
);
304 base_type
= TYPE_REF_CAN_ALIAS_ALL (base_type
)
305 ? NULL_TREE
: TREE_TYPE (base_type
);
307 tree ref_expr
= ref
->ref
;
308 ref_type
= reference_alias_ptr_type_1 (&ref_expr
);
311 ref_type
= TREE_TYPE (ref_expr
);
313 ref_type
= TYPE_REF_CAN_ALIAS_ALL (ref_type
)
314 ? NULL_TREE
: TREE_TYPE (ref_type
);
316 /* Sanity check that we are in sync with what get_alias_set does. */
317 gcc_checking_assert ((!base_type
&& !ao_ref_base_alias_set (ref
))
318 || get_alias_set (base_type
)
319 == ao_ref_base_alias_set (ref
));
320 gcc_checking_assert ((!ref_type
&& !ao_ref_alias_set (ref
))
321 || get_alias_set (ref_type
)
322 == ao_ref_alias_set (ref
));
324 /* Do not bother to record types that have no meaningful alias set.
325 Also skip variably modified types since these go to local streams. */
326 if (base_type
&& (!get_alias_set (base_type
)
327 || variably_modified_type_p (base_type
, NULL_TREE
)))
328 base_type
= NULL_TREE
;
329 if (ref_type
&& (!get_alias_set (ref_type
)
330 || variably_modified_type_p (ref_type
, NULL_TREE
)))
331 ref_type
= NULL_TREE
;
335 fprintf (dump_file
, " - Recording base type:");
336 print_generic_expr (dump_file
, base_type
);
337 fprintf (dump_file
, " (alias set %i) ref type:",
338 base_type
? get_alias_set (base_type
) : 0);
339 print_generic_expr (dump_file
, ref_type
);
340 fprintf (dump_file
, " (alias set %i)\n",
341 ref_type
? get_alias_set (ref_type
) : 0);
344 tt
->insert (base_type
, ref_type
);
347 /* Returns true if and only if we should store the access to EXPR.
348 Some accesses, e.g. loads from automatic variables, are not interesting. */
351 record_access_p (tree expr
)
353 if (refs_local_or_readonly_memory_p (expr
))
356 fprintf (dump_file
, " - Read-only or local, ignoring.\n");
362 /* Return true if ECF flags says that stores can be ignored. */
365 ignore_stores_p (tree caller
, int flags
)
367 if (flags
& ECF_PURE
)
369 if ((flags
& (ECF_NORETURN
| ECF_NOTHROW
)) == (ECF_NORETURN
| ECF_NOTHROW
)
370 || (!opt_for_fn (caller
, flag_exceptions
) && (flags
& ECF_NORETURN
)))
375 /* Analyze function call STMT in function F. */
378 analyze_call (modref_summary
*cur_summary
,
381 /* Check flags on the function call. In certain cases, analysis can be
383 int flags
= gimple_call_flags (stmt
);
384 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
388 " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
389 "except for args.\n");
393 /* Pure functions do not affect global memory. Stores by functions which are
394 noreturn and do not throw can safely be ignored. */
395 bool ignore_stores
= ignore_stores_p (current_function_decl
, flags
);
397 /* Next, we try to get the callee's function declaration. The goal is to
398 merge their summary with ours. */
399 tree callee
= gimple_call_fndecl (stmt
);
401 /* Check if this is an indirect call. */
404 /* If the indirect call does not write memory, our store summary is
405 unaffected, but we have to discard our loads summary (we don't know
406 anything about the loads that the called function performs). */
410 fprintf (dump_file
, " - Indirect call which does not write memory, "
411 "discarding loads.\n");
412 if (cur_summary
->loads
)
413 cur_summary
->loads
->collapse ();
414 if (cur_summary
->loads_lto
)
415 cur_summary
->loads_lto
->collapse ();
419 fprintf (dump_file
, " - Indirect call.\n");
423 struct cgraph_node
*callee_node
= cgraph_node::get_create (callee
);
425 /* We can not safely optimize based on summary of callee if it does
426 not always bind to current def: it is possible that memory load
427 was optimized out earlier which may not happen in the interposed
429 if (!callee_node
->binds_to_current_def_p ())
432 fprintf (dump_file
, " - May be interposed: collapsing loads.\n");
433 if (cur_summary
->loads
)
434 cur_summary
->loads
->collapse ();
435 if (cur_summary
->loads_lto
)
436 cur_summary
->loads_lto
->collapse ();
439 /* If this is a recursive call, the target summary is the same as ours, so
440 there's nothing to do. */
441 if (recursive_call_p (current_function_decl
, callee
))
444 fprintf (dump_file
, " - Skipping recursive call.\n");
448 gcc_assert (callee_node
!= NULL
);
450 /* Get the function symbol and its availability. */
451 enum availability avail
;
452 callee_node
= callee_node
->function_symbol (&avail
);
453 if (avail
<= AVAIL_INTERPOSABLE
)
455 /* Keep stores summary, but discard all loads for interposable function
459 if (cur_summary
->loads
)
460 cur_summary
->loads
->collapse ();
461 if (cur_summary
->loads_lto
)
462 cur_summary
->loads_lto
->collapse ();
466 fprintf (dump_file
, " - Function availability <= AVAIL_INTERPOSABLE.\n");
470 /* Get callee's modref summary. As above, if there's no summary, we either
471 have to give up or, if stores are ignored, we can just purge loads. */
472 modref_summary
*callee_summary
= summaries
->get (callee_node
);
477 if (cur_summary
->loads
)
478 cur_summary
->loads
->collapse ();
479 if (cur_summary
->loads_lto
)
480 cur_summary
->loads_lto
->collapse ();
484 fprintf (dump_file
, " - No modref summary available for callee.\n");
488 /* Merge with callee's summary. */
489 if (cur_summary
->loads
)
490 cur_summary
->loads
->merge (callee_summary
->loads
);
491 if (cur_summary
->loads_lto
)
492 cur_summary
->loads_lto
->merge (callee_summary
->loads_lto
);
495 if (cur_summary
->stores
)
496 cur_summary
->stores
->merge (callee_summary
->stores
);
497 if (cur_summary
->stores_lto
)
498 cur_summary
->stores_lto
->merge (callee_summary
->stores_lto
);
504 /* Helper for analyze_stmt. */
507 analyze_load (gimple
*, tree
, tree op
, void *data
)
509 modref_summary
*summary
= (modref_summary
*)data
;
513 fprintf (dump_file
, " - Analyzing load: ");
514 print_generic_expr (dump_file
, op
);
515 fprintf (dump_file
, "\n");
518 if (!record_access_p (op
))
522 ao_ref_init (&r
, op
);
525 record_access (summary
->loads
, &r
);
526 if (summary
->loads_lto
)
527 record_access_lto (summary
->loads_lto
, &r
);
531 /* Helper for analyze_stmt. */
534 analyze_store (gimple
*, tree
, tree op
, void *data
)
536 modref_summary
*summary
= (modref_summary
*)data
;
540 fprintf (dump_file
, " - Analyzing store: ");
541 print_generic_expr (dump_file
, op
);
542 fprintf (dump_file
, "\n");
545 if (!record_access_p (op
))
549 ao_ref_init (&r
, op
);
552 record_access (((modref_summary
*)data
)->stores
, &r
);
553 if (summary
->stores_lto
)
554 record_access_lto (((modref_summary
*)data
)->stores_lto
, &r
);
558 /* Analyze statement STMT of function F.
559 If IPA is true do not merge in side effects of calls. */
562 analyze_stmt (modref_summary
*summary
, gimple
*stmt
, bool ipa
)
564 /* There is no need to record clobbers. */
565 if (gimple_clobber_p (stmt
))
567 /* Analyze all loads and stores in STMT. */
568 walk_stmt_load_store_ops (stmt
, summary
,
569 analyze_load
, analyze_store
);
570 /* or call analyze_load_ipa, analyze_store_ipa */
572 switch (gimple_code (stmt
))
575 /* If the ASM statement does not read nor write memory, there's nothing
576 to do. Otherwise just give up. */
577 if (!gimple_asm_clobbers_memory_p (as_a
<gasm
*> (stmt
)))
580 fprintf (dump_file
, " - Function contains GIMPLE_ASM statement "
581 "which clobbers memory.\n");
585 return analyze_call (summary
, stmt
);
588 /* Nothing to do for other types of statements. */
593 /* Analyze function F. IPA indicates whether we're running in tree mode (false)
594 or the IPA mode (true). */
597 analyze_function (function
*f
, bool ipa
)
600 fprintf (dump_file
, "modref analyzing '%s' (ipa=%i)%s%s\n",
601 function_name (f
), ipa
,
602 TREE_READONLY (current_function_decl
) ? " (const)" : "",
603 DECL_PURE_P (current_function_decl
) ? " (pure)" : "");
605 /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
606 if (!flag_ipa_modref
)
609 /* Initialize the summary. */
611 summaries
= new (ggc_alloc
<modref_summaries
> ())
612 modref_summaries (symtab
);
613 else /* Remove existing summary if we are re-running the pass. */
614 summaries
->remove (cgraph_node::get (f
->decl
));
616 ((modref_summaries
*)summaries
)->ipa
= ipa
;
618 modref_summary
*summary
= summaries
->get_create (cgraph_node::get (f
->decl
));
620 /* Compute no-LTO summaries when local optimization is going to happen. */
621 bool nolto
= (!ipa
|| ((!flag_lto
|| flag_fat_lto_objects
) && !in_lto_p
)
622 || (in_lto_p
&& !flag_wpa
623 && flag_incremental_link
!= INCREMENTAL_LINK_LTO
));
625 /* Compute LTO when LTO streaming is going to happen. */
626 bool lto
= ipa
&& ((flag_lto
&& !in_lto_p
)
628 || flag_incremental_link
== INCREMENTAL_LINK_LTO
);
630 /* Create and initialize summary for F.
631 Note that summaries may be already allocated from previous
635 gcc_assert (!summary
->loads
);
637 = new (ggc_alloc
<modref_tree
<alias_set_type
> > ())
638 modref_records (param_modref_max_bases
,
639 param_modref_max_refs
);
640 gcc_assert (!summary
->stores
);
642 = new (ggc_alloc
<modref_tree
<alias_set_type
> > ())
643 modref_records (param_modref_max_bases
,
644 param_modref_max_refs
);
648 gcc_assert (!summary
->loads_lto
);
650 = new (ggc_alloc
<modref_tree
<tree
> > ())
651 modref_records_lto (param_modref_max_bases
,
652 param_modref_max_refs
);
653 gcc_assert (!summary
->stores_lto
);
655 = new (ggc_alloc
<modref_tree
<tree
> > ())
656 modref_records_lto (param_modref_max_bases
,
657 param_modref_max_refs
);
659 summary
->finished
= false;
660 int ecf_flags
= flags_from_decl_or_type (current_function_decl
);
662 /* Analyze each statement in each basic block of the function. If the
663 statement cannot be analyzed (for any reason), the entire function cannot
664 be analyzed by modref. */
666 FOR_EACH_BB_FN (bb
, f
)
668 gimple_stmt_iterator si
;
669 for (si
= gsi_after_labels (bb
); !gsi_end_p (si
); gsi_next (&si
))
671 if (!analyze_stmt (summary
, gsi_stmt (si
), ipa
)
672 || !summary
->useful_p (ecf_flags
))
674 cgraph_node
*fnode
= cgraph_node::get (current_function_decl
);
675 summaries
->remove (fnode
);
678 " - modref done with result: not tracked.\n");
685 summary
->finished
= true;
689 fprintf (dump_file
, " - modref done with result: tracked.\n");
690 summary
->dump (dump_file
);
694 /* Callback for generate_summary. */
697 modref_generate (void)
699 struct cgraph_node
*node
;
700 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node
)
702 function
*f
= DECL_STRUCT_FUNCTION (node
->decl
);
706 analyze_function (f
, true);
711 /* Called when a new function is inserted to callgraph late. */
714 modref_summaries::insert (struct cgraph_node
*node
, modref_summary
*)
716 if (!DECL_STRUCT_FUNCTION (node
->decl
))
718 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
719 analyze_function (DECL_STRUCT_FUNCTION (node
->decl
), ipa
);
723 /* Called when new clone is inserted to callgraph late. */
726 modref_summaries::duplicate (cgraph_node
*, cgraph_node
*,
727 modref_summary
*src_data
,
728 modref_summary
*dst_data
)
730 dst_data
->finished
= src_data
->finished
;
731 if (src_data
->stores
)
733 dst_data
->stores
= new (ggc_alloc
<modref_tree
<alias_set_type
> > ())
735 (src_data
->stores
->max_bases
,
736 src_data
->stores
->max_refs
);
737 dst_data
->stores
->merge (src_data
->stores
);
741 dst_data
->loads
= new (ggc_alloc
<modref_tree
<alias_set_type
> > ())
743 (src_data
->loads
->max_bases
,
744 src_data
->loads
->max_refs
);
745 dst_data
->loads
->merge (src_data
->loads
);
747 if (src_data
->stores_lto
)
749 dst_data
->stores_lto
= new (ggc_alloc
<modref_tree
<tree
> > ())
751 (src_data
->stores_lto
->max_bases
,
752 src_data
->stores_lto
->max_refs
);
753 dst_data
->stores_lto
->merge (src_data
->stores_lto
);
755 if (src_data
->loads_lto
)
757 dst_data
->loads_lto
= new (ggc_alloc
<modref_tree
<tree
> > ())
759 (src_data
->stores_lto
->max_bases
,
760 src_data
->stores_lto
->max_refs
);
761 dst_data
->loads_lto
->merge (src_data
->loads_lto
);
767 /* Definition of the modref pass on GIMPLE. */
768 const pass_data pass_data_modref
= {
773 (PROP_cfg
| PROP_ssa
),
780 class pass_modref
: public gimple_opt_pass
783 pass_modref (gcc::context
*ctxt
)
784 : gimple_opt_pass (pass_data_modref
, ctxt
) {}
786 /* opt_pass methods: */
789 return new pass_modref (m_ctxt
);
791 virtual bool gate (function
*)
793 return flag_ipa_modref
;
795 virtual unsigned int execute (function
*);
798 /* Encode TT to the output block OB using the summary streaming API. */
801 write_modref_records (modref_records_lto
*tt
, struct output_block
*ob
)
803 streamer_write_uhwi (ob
, tt
->max_bases
);
804 streamer_write_uhwi (ob
, tt
->max_refs
);
806 streamer_write_uhwi (ob
, tt
->every_base
);
807 streamer_write_uhwi (ob
, vec_safe_length (tt
->bases
));
809 modref_base_node
<tree
> *base_node
;
810 FOR_EACH_VEC_SAFE_ELT (tt
->bases
, i
, base_node
)
812 stream_write_tree (ob
, base_node
->base
, true);
814 streamer_write_uhwi (ob
, base_node
->every_ref
);
815 streamer_write_uhwi (ob
, vec_safe_length (base_node
->refs
));
817 modref_ref_node
<tree
> *ref_node
;
818 FOR_EACH_VEC_SAFE_ELT (base_node
->refs
, j
, ref_node
)
820 stream_write_tree (ob
, ref_node
->ref
, true);
825 /* Read a modref_tree from the input block IB using the data from DATA_IN.
826 This assumes that the tree was encoded using write_modref_tree.
827 Either nolto_ret or lto_ret is initialized by the tree depending whether
828 LTO streaming is expected or not. */
831 read_modref_records (lto_input_block
*ib
, struct data_in
*data_in
,
832 modref_records
**nolto_ret
,
833 modref_records_lto
**lto_ret
)
835 size_t max_bases
= streamer_read_uhwi (ib
);
836 size_t max_refs
= streamer_read_uhwi (ib
);
838 /* Decide whether we want to turn LTO data types to non-LTO (i.e. when
839 LTO re-streaming is not going to happen). */
840 if (flag_wpa
|| flag_incremental_link
== INCREMENTAL_LINK_LTO
)
841 *lto_ret
= new (ggc_alloc
<modref_records_lto
> ()) modref_records_lto
842 (max_bases
, max_refs
);
844 *nolto_ret
= new (ggc_alloc
<modref_records
> ()) modref_records
845 (max_bases
, max_refs
);
847 size_t every_base
= streamer_read_uhwi (ib
);
848 size_t nbase
= streamer_read_uhwi (ib
);
850 gcc_assert (!every_base
|| nbase
== 0);
854 (*nolto_ret
)->collapse ();
856 (*lto_ret
)->collapse ();
858 for (size_t i
= 0; i
< nbase
; i
++)
860 tree base_tree
= stream_read_tree (ib
, data_in
);
861 modref_base_node
<alias_set_type
> *nolto_base_node
= NULL
;
862 modref_base_node
<tree
> *lto_base_node
= NULL
;
864 /* At stream in time we have LTO alias info. Check if we streamed in
865 something obviously unnecessary. Do not glob types by alias sets;
866 it is not 100% clear that ltrans types will get merged same way.
867 Types may get refined based on ODR type conflicts. */
868 if (base_tree
&& !get_alias_set (base_tree
))
872 fprintf (dump_file
, "Streamed in alias set 0 type ");
873 print_generic_expr (dump_file
, base_tree
);
874 fprintf (dump_file
, "\n");
880 nolto_base_node
= (*nolto_ret
)->insert_base (base_tree
881 ? get_alias_set (base_tree
)
884 lto_base_node
= (*lto_ret
)->insert_base (base_tree
);
885 size_t every_ref
= streamer_read_uhwi (ib
);
886 size_t nref
= streamer_read_uhwi (ib
);
888 gcc_assert (!every_ref
|| nref
== 0);
892 nolto_base_node
->collapse ();
894 lto_base_node
->collapse ();
896 for (size_t j
= 0; j
< nref
; j
++)
898 tree ref_tree
= stream_read_tree (ib
, data_in
);
900 if (ref_tree
&& !get_alias_set (ref_tree
))
904 fprintf (dump_file
, "Streamed in alias set 0 type ");
905 print_generic_expr (dump_file
, ref_tree
);
906 fprintf (dump_file
, "\n");
912 nolto_base_node
->insert_ref (ref_tree
? get_alias_set (ref_tree
)
915 lto_base_node
->insert_ref (ref_tree
, max_refs
);
920 /* Callback for write_summary. */
925 struct output_block
*ob
= create_output_block (LTO_section_ipa_modref
);
926 lto_symtab_encoder_t encoder
= ob
->decl_state
->symtab_node_encoder
;
927 unsigned int count
= 0;
932 streamer_write_uhwi (ob
, 0);
933 streamer_write_char_stream (ob
->main_stream
, 0);
934 produce_asm (ob
, NULL
);
935 destroy_output_block (ob
);
939 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
941 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
942 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
945 if (cnode
&& cnode
->definition
&& !cnode
->alias
946 && (r
= summaries
->get (cnode
))
947 && r
->lto_useful_p (flags_from_decl_or_type (cnode
->decl
)))
950 streamer_write_uhwi (ob
, count
);
952 for (i
= 0; i
< lto_symtab_encoder_size (encoder
); i
++)
954 symtab_node
*snode
= lto_symtab_encoder_deref (encoder
, i
);
955 cgraph_node
*cnode
= dyn_cast
<cgraph_node
*> (snode
);
957 if (cnode
&& cnode
->definition
&& !cnode
->alias
)
960 modref_summary
*r
= summaries
->get (cnode
);
962 if (!r
|| !r
->lto_useful_p (flags_from_decl_or_type (cnode
->decl
)))
965 streamer_write_uhwi (ob
, lto_symtab_encoder_encode (encoder
, cnode
));
967 streamer_write_uhwi (ob
, r
->loads_lto
? 1 : 0);
968 streamer_write_uhwi (ob
, r
->stores_lto
? 1 : 0);
970 write_modref_records (r
->loads_lto
, ob
);
972 write_modref_records (r
->stores_lto
, ob
);
975 streamer_write_char_stream (ob
->main_stream
, 0);
976 produce_asm (ob
, NULL
);
977 destroy_output_block (ob
);
981 read_section (struct lto_file_decl_data
*file_data
, const char *data
,
984 const struct lto_function_header
*header
985 = (const struct lto_function_header
*) data
;
986 const int cfg_offset
= sizeof (struct lto_function_header
);
987 const int main_offset
= cfg_offset
+ header
->cfg_size
;
988 const int string_offset
= main_offset
+ header
->main_size
;
989 struct data_in
*data_in
;
991 unsigned int f_count
;
993 lto_input_block
ib ((const char *) data
+ main_offset
, header
->main_size
,
994 file_data
->mode_table
);
997 = lto_data_in_create (file_data
, (const char *) data
+ string_offset
,
998 header
->string_size
, vNULL
);
999 f_count
= streamer_read_uhwi (&ib
);
1000 for (i
= 0; i
< f_count
; i
++)
1002 struct cgraph_node
*node
;
1003 lto_symtab_encoder_t encoder
;
1005 unsigned int index
= streamer_read_uhwi (&ib
);
1006 encoder
= file_data
->symtab_node_encoder
;
1007 node
= dyn_cast
<cgraph_node
*> (lto_symtab_encoder_deref (encoder
,
1010 modref_summary
*modref_sum
= summaries
->get_create (node
);
1011 modref_sum
->finished
= false;
1012 int have_loads
= streamer_read_uhwi (&ib
);
1013 int have_stores
= streamer_read_uhwi (&ib
);
1014 gcc_assert (!modref_sum
->loads_lto
1015 && !modref_sum
->stores_lto
1016 && !modref_sum
->loads
1017 && !modref_sum
->stores
);
1019 read_modref_records (&ib
, data_in
,
1021 &modref_sum
->loads_lto
);
1023 read_modref_records (&ib
, data_in
,
1024 &modref_sum
->stores
,
1025 &modref_sum
->stores_lto
);
1028 fprintf (dump_file
, "Read modref for %s\n",
1029 node
->dump_name ());
1030 modref_sum
->dump (dump_file
);
1033 modref_sum
->finished
= true;
1036 lto_free_section_data (file_data
, LTO_section_ipa_modref
, NULL
, data
,
1038 lto_data_in_delete (data_in
);
1041 /* Callback for read_summary. */
1046 struct lto_file_decl_data
**file_data_vec
= lto_get_file_decl_data ();
1047 struct lto_file_decl_data
*file_data
;
1051 summaries
= new (ggc_alloc
<modref_summaries
> ())
1052 modref_summaries (symtab
);
1053 ((modref_summaries
*)summaries
)->ipa
= true;
1055 while ((file_data
= file_data_vec
[j
++]))
1058 const char *data
= lto_get_summary_section_data (file_data
,
1059 LTO_section_ipa_modref
,
1062 read_section (file_data
, data
, len
);
1064 /* Fatal error here. We do not want to support compiling ltrans units
1065 with different version of compiler or different flags than the WPA
1066 unit, so this should never happen. */
1067 fatal_error (input_location
,
1068 "IPA modref summary is missing in input file");
1072 /* Definition of the modref IPA pass. */
1073 const pass_data pass_data_ipa_modref
=
1075 IPA_PASS
, /* type */
1076 "modref", /* name */
1077 OPTGROUP_IPA
, /* optinfo_flags */
1078 TV_IPA_MODREF
, /* tv_id */
1079 0, /* properties_required */
1080 0, /* properties_provided */
1081 0, /* properties_destroyed */
1082 0, /* todo_flags_start */
1083 ( TODO_dump_symtab
), /* todo_flags_finish */
1086 class pass_ipa_modref
: public ipa_opt_pass_d
1089 pass_ipa_modref (gcc::context
*ctxt
)
1090 : ipa_opt_pass_d (pass_data_ipa_modref
, ctxt
,
1091 modref_generate
, /* generate_summary */
1092 modref_write
, /* write_summary */
1093 modref_read
, /* read_summary */
1094 modref_write
, /* write_optimization_summary */
1095 modref_read
, /* read_optimization_summary */
1096 NULL
, /* stmt_fixup */
1097 0, /* function_transform_todo_flags_start */
1098 NULL
, /* function_transform */
1099 NULL
) /* variable_transform */
1102 /* opt_pass methods: */
1103 opt_pass
*clone () { return new pass_ipa_modref (m_ctxt
); }
1104 virtual bool gate (function
*)
1108 virtual unsigned int execute (function
*);
1114 unsigned int pass_modref::execute (function
*f
)
1116 /* If new function is being added during IPA, we can skip analysis. */
1117 if (summaries
&& ((modref_summaries
*)summaries
)->ipa
)
1119 analyze_function (f
, false);
1124 make_pass_modref (gcc::context
*ctxt
)
1126 return new pass_modref (ctxt
);
1130 make_pass_ipa_modref (gcc::context
*ctxt
)
1132 return new pass_ipa_modref (ctxt
);
1135 /* Skip edges from and to nodes without ipa_pure_const enabled.
1136 Ignore not available symbols. */
1139 ignore_edge (struct cgraph_edge
*e
)
1141 enum availability avail
;
1142 cgraph_node
*callee
= e
->callee
->function_or_virtual_thunk_symbol
1143 (&avail
, e
->caller
);
1145 return (avail
<= AVAIL_INTERPOSABLE
1146 || !summaries
->get (callee
)
1147 || flags_from_decl_or_type (e
->callee
->decl
)
1148 & (ECF_CONST
| ECF_NOVOPS
));
1151 /* Run the IPA pass. This will take a function's summaries and calls and
1152 construct new summaries which represent a transitive closure. So that
1153 summary of an analyzed function contains information about the loads and
1154 stores that the function or any function that it calls does. */
1156 unsigned int pass_ipa_modref::execute (function
*)
1161 struct cgraph_node
**order
= XCNEWVEC (struct cgraph_node
*,
1162 symtab
->cgraph_count
);
1164 order_pos
= ipa_reduced_postorder (order
, true, ignore_edge
);
1167 /* Iterate over all strongly connected components in post-order. */
1168 for (i
= 0; i
< order_pos
; i
++)
1170 bool its_hopeless
= false;
1171 modref_records
*loads
= NULL
;
1172 modref_records
*stores
= NULL
;
1173 modref_records_lto
*loads_lto
= NULL
;
1174 modref_records_lto
*stores_lto
= NULL
;
1176 /* Get the component's representative. That's just any node in the
1177 component from which we can traverse the entire component. */
1178 struct cgraph_node
*component_node
= order
[i
];
1179 cgraph_node
*first
= NULL
;
1182 fprintf (dump_file
, "Start of SCC component\n");
1184 /* Walk the component. CUR is the current node of the component that's
1186 for (struct cgraph_node
*cur
= component_node
; cur
&& !its_hopeless
;
1187 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
1189 /* Merge in summaries from CUR. */
1190 modref_summary
*cur_summary
= summaries
->get (cur
);
1193 fprintf (dump_file
, " Processing %s\n",
1196 /* We don't know anything about CUR, hence we cannot tell anything
1197 about the entire component. */
1201 fprintf (dump_file
, " No summary\n");
1202 its_hopeless
= true;
1206 /* Summaries are all going to be same, pick first ones and merge
1211 loads
= cur_summary
->loads
;
1212 stores
= cur_summary
->stores
;
1213 loads_lto
= cur_summary
->loads_lto
;
1214 stores_lto
= cur_summary
->stores_lto
;
1216 for (cgraph_edge
*e
= cur
->indirect_calls
; e
; e
= e
->next_callee
)
1218 if (e
->indirect_info
->ecf_flags
& (ECF_CONST
| ECF_NOVOPS
))
1220 if (ignore_stores_p (cur
->decl
, e
->indirect_info
->ecf_flags
))
1223 fprintf (dump_file
, " Indirect call: "
1224 "collapsing loads\n");
1228 loads_lto
->collapse ();
1233 fprintf (dump_file
, " Indirect call: giving up\n");
1234 its_hopeless
= true;
1238 /* Walk every function that CUR calls and merge its summary. */
1239 for (cgraph_edge
*callee_edge
= cur
->callees
; callee_edge
;
1240 callee_edge
= callee_edge
->next_callee
)
1242 int flags
= flags_from_decl_or_type (callee_edge
->callee
->decl
);
1243 modref_summary
*callee_summary
;
1244 struct cgraph_node
*callee
;
1246 if (flags
& (ECF_CONST
| ECF_NOVOPS
))
1250 fprintf (dump_file
, " Call to %s\n",
1251 callee_edge
->callee
->dump_name ());
1253 /* We can not safely optimize based on summary of callee if it
1254 does not always bind to current def: it is possible that
1255 memory load was optimized out earlier which may not happen in
1256 the interposed variant. */
1257 if (!callee_edge
->binds_to_current_def_p ())
1262 loads_lto
->collapse ();
1264 fprintf (dump_file
, " May not bind local;"
1265 " collapsing loads\n");
1268 /* Get the callee and its summary. */
1269 enum availability avail
;
1270 callee
= callee_edge
->callee
->function_or_virtual_thunk_symbol
1273 /* See if we can derive something from ECF flags. Be careful on
1274 not skipping calls within the SCC component: we must merge
1275 all their summaries.
1276 If we switch to iterative dataflow that may be necessary
1277 for future improvements this may go away. */
1279 && ((struct ipa_dfs_info
*)cur
->aux
)->scc_no
1280 == ((struct ipa_dfs_info
*)callee
->aux
)->scc_no
)
1283 bool ignore_stores
= ignore_stores_p (cur
->decl
, flags
);
1285 /* We don't know anything about CALLEE, hence we cannot tell
1286 anything about the entire component. */
1288 if (avail
<= AVAIL_INTERPOSABLE
1289 || !(callee_summary
= summaries
->get (callee
)))
1293 its_hopeless
= true;
1294 if (dump_file
&& avail
<= AVAIL_INTERPOSABLE
)
1295 fprintf (dump_file
, " Call target interposable"
1296 " or not available\n");
1298 fprintf (dump_file
, " No call target summary\n");
1306 loads_lto
->collapse ();
1307 if (dump_file
&& avail
<= AVAIL_INTERPOSABLE
)
1308 fprintf (dump_file
, " Call target interposable"
1309 "or not available; collapsing loads\n");
1311 fprintf (dump_file
, " No call target summary;"
1312 " collapsing loads\n");
1317 /* Merge in callee's information. */
1318 if (callee_summary
->loads
1319 && callee_summary
->loads
!= loads
)
1320 loads
->merge (callee_summary
->loads
);
1321 if (callee_summary
->stores
1322 && callee_summary
->stores
!= stores
)
1323 stores
->merge (callee_summary
->stores
);
1324 if (callee_summary
->loads_lto
1325 && callee_summary
->loads_lto
!= loads_lto
)
1326 loads_lto
->merge (callee_summary
->loads_lto
);
1327 if (callee_summary
->stores_lto
1328 && callee_summary
->stores_lto
!= stores_lto
)
1329 stores_lto
->merge (callee_summary
->stores_lto
);
1333 /* At this time, ipa_loads and ipa_stores contain information
1334 about all loads and stores done by any of the component's nodes and
1335 all functions that any of the nodes calls. We will now propagate
1336 this information to all nodes in the component. Therefore, we will
1337 walk the component one more time to do it. */
1338 for (struct cgraph_node
*cur
= component_node
; cur
;
1339 cur
= ((struct ipa_dfs_info
*) cur
->aux
)->next_cycle
)
1341 modref_summary
*cur_summary
= summaries
->get (cur
);
1344 /* The function doesn't have a summary. We must have noticed
1345 that during the first pass and the hopeless flag must
1346 therefore be set. Skip the function. */
1347 gcc_assert (its_hopeless
);
1349 else if (its_hopeless
)
1352 fprintf (dump_file
, "Cleared modref info for %s\n",
1354 summaries
->remove (cur
);
1363 cur_summary
->loads
->merge (loads
);
1365 cur_summary
->stores
->merge (stores
);
1367 cur_summary
->loads_lto
->merge (loads_lto
);
1369 cur_summary
->stores_lto
->merge (stores_lto
);
1371 cur_summary
->finished
= true;
1374 fprintf (dump_file
, "Propagated modref for %s%s%s\n",
1376 TREE_READONLY (cur
->decl
) ? " (const)" : "",
1377 DECL_PURE_P (cur
->decl
) ? " (pure)" : "");
1378 cur_summary
->dump (dump_file
);
1383 ((modref_summaries
*)summaries
)->ipa
= false;
1384 ipa_free_postorder_info ();
1388 /* Summaries must stay alive until end of compilation. */
1391 ipa_modref_c_finalize ()
1394 ggc_delete (summaries
);
1398 #include "gt-ipa-modref.h"