138fd1498Szrj /* Callgraph based analysis of static variables.
238fd1498Szrj Copyright (C) 2004-2018 Free Software Foundation, Inc.
338fd1498Szrj Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
438fd1498Szrj
538fd1498Szrj This file is part of GCC.
638fd1498Szrj
738fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
838fd1498Szrj the terms of the GNU General Public License as published by the Free
938fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1038fd1498Szrj version.
1138fd1498Szrj
1238fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1338fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1438fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1538fd1498Szrj for more details.
1638fd1498Szrj
1738fd1498Szrj You should have received a copy of the GNU General Public License
1838fd1498Szrj along with GCC; see the file COPYING3. If not see
1938fd1498Szrj <http://www.gnu.org/licenses/>. */
2038fd1498Szrj
2138fd1498Szrj /* This file gathers information about how variables whose scope is
2238fd1498Szrj confined to the compilation unit are used.
2338fd1498Szrj
2438fd1498Szrj The transitive call site specific clobber effects are computed
2538fd1498Szrj for the variables whose scope is contained within this compilation
2638fd1498Szrj unit.
2738fd1498Szrj
2838fd1498Szrj First each function and static variable initialization is analyzed
2938fd1498Szrj to determine which local static variables are either read, written,
3038fd1498Szrj or have their address taken. Any local static that has its address
3138fd1498Szrj taken is removed from consideration. Once the local read and
3238fd1498Szrj writes are determined, a transitive closure of this information is
3338fd1498Szrj performed over the call graph to determine the worst case set of
3438fd1498Szrj side effects of each call. In later parts of the compiler, these
3538fd1498Szrj local and global sets are examined to make the call clobbering less
3638fd1498Szrj traumatic, promote some statics to registers, and improve aliasing
3738fd1498Szrj information. */
3838fd1498Szrj
3938fd1498Szrj #include "config.h"
4038fd1498Szrj #include "system.h"
4138fd1498Szrj #include "coretypes.h"
4238fd1498Szrj #include "backend.h"
4338fd1498Szrj #include "tree.h"
4438fd1498Szrj #include "gimple.h"
4538fd1498Szrj #include "tree-pass.h"
4638fd1498Szrj #include "cgraph.h"
4738fd1498Szrj #include "data-streamer.h"
4838fd1498Szrj #include "calls.h"
4938fd1498Szrj #include "splay-tree.h"
5038fd1498Szrj #include "ipa-utils.h"
5138fd1498Szrj #include "ipa-reference.h"
5238fd1498Szrj
5338fd1498Szrj static void remove_node_data (struct cgraph_node *node,
5438fd1498Szrj void *data ATTRIBUTE_UNUSED);
5538fd1498Szrj static void duplicate_node_data (struct cgraph_node *src,
5638fd1498Szrj struct cgraph_node *dst,
5738fd1498Szrj void *data ATTRIBUTE_UNUSED);
5838fd1498Szrj
5938fd1498Szrj /* The static variables defined within the compilation unit that are
6038fd1498Szrj loaded or stored directly by function that owns this structure. */
6138fd1498Szrj
6238fd1498Szrj struct ipa_reference_local_vars_info_d
6338fd1498Szrj {
6438fd1498Szrj bitmap statics_read;
6538fd1498Szrj bitmap statics_written;
6638fd1498Szrj };
6738fd1498Szrj
6838fd1498Szrj /* Statics that are read and written by some set of functions. The
6938fd1498Szrj local ones are based on the loads and stores local to the function.
7038fd1498Szrj The global ones are based on the local info as well as the
7138fd1498Szrj transitive closure of the functions that are called. */
7238fd1498Szrj
7338fd1498Szrj struct ipa_reference_global_vars_info_d
7438fd1498Szrj {
7538fd1498Szrj bitmap statics_read;
7638fd1498Szrj bitmap statics_written;
7738fd1498Szrj };
7838fd1498Szrj
7938fd1498Szrj /* Information we save about every function after ipa-reference is completed. */
8038fd1498Szrj
8138fd1498Szrj struct ipa_reference_optimization_summary_d
8238fd1498Szrj {
8338fd1498Szrj bitmap statics_not_read;
8438fd1498Szrj bitmap statics_not_written;
8538fd1498Szrj };
8638fd1498Szrj
8738fd1498Szrj typedef struct ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t;
8838fd1498Szrj typedef struct ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t;
8938fd1498Szrj typedef struct ipa_reference_optimization_summary_d *ipa_reference_optimization_summary_t;
9038fd1498Szrj
9138fd1498Szrj struct ipa_reference_vars_info_d
9238fd1498Szrj {
9338fd1498Szrj struct ipa_reference_local_vars_info_d local;
9438fd1498Szrj struct ipa_reference_global_vars_info_d global;
9538fd1498Szrj };
9638fd1498Szrj
9738fd1498Szrj typedef struct ipa_reference_vars_info_d *ipa_reference_vars_info_t;
9838fd1498Szrj
9938fd1498Szrj /* This splay tree contains all of the static variables that are
10038fd1498Szrj being considered by the compilation level alias analysis. */
10138fd1498Szrj static splay_tree reference_vars_to_consider;
10238fd1498Szrj
10338fd1498Szrj /* Set of all interesting module statics. A bit is set for every module
10438fd1498Szrj static we are considering. This is added to the local info when asm
10538fd1498Szrj code is found that clobbers all memory. */
10638fd1498Szrj static bitmap all_module_statics;
10738fd1498Szrj /* Set of all statics that should be ignored because they are touched by
10838fd1498Szrj -fno-ipa-reference code. */
10938fd1498Szrj static bitmap ignore_module_statics;
11038fd1498Szrj
11138fd1498Szrj /* Obstack holding bitmaps of local analysis (live from analysis to
11238fd1498Szrj propagation) */
11338fd1498Szrj static bitmap_obstack local_info_obstack;
11438fd1498Szrj /* Obstack holding global analysis live forever. */
11538fd1498Szrj static bitmap_obstack optimization_summary_obstack;
11638fd1498Szrj
11738fd1498Szrj /* Holders of ipa cgraph hooks: */
11838fd1498Szrj static struct cgraph_2node_hook_list *node_duplication_hook_holder;
11938fd1498Szrj static struct cgraph_node_hook_list *node_removal_hook_holder;
12038fd1498Szrj
12138fd1498Szrj /* Vector where the reference var infos are actually stored.
12238fd1498Szrj Indexed by UID of call graph nodes. */
12338fd1498Szrj static vec<ipa_reference_vars_info_t> ipa_reference_vars_vector;
12438fd1498Szrj
12538fd1498Szrj /* TODO: find a place where we should release the vector. */
12638fd1498Szrj static vec<ipa_reference_optimization_summary_t> ipa_reference_opt_sum_vector;
12738fd1498Szrj
12838fd1498Szrj /* Return the ipa_reference_vars structure starting from the cgraph NODE. */
12938fd1498Szrj static inline ipa_reference_vars_info_t
get_reference_vars_info(struct cgraph_node * node)13038fd1498Szrj get_reference_vars_info (struct cgraph_node *node)
13138fd1498Szrj {
13238fd1498Szrj if (!ipa_reference_vars_vector.exists ()
13338fd1498Szrj || ipa_reference_vars_vector.length () <= (unsigned int) node->uid)
13438fd1498Szrj return NULL;
13538fd1498Szrj return ipa_reference_vars_vector[node->uid];
13638fd1498Szrj }
13738fd1498Szrj
13838fd1498Szrj /* Return the ipa_reference_vars structure starting from the cgraph NODE. */
13938fd1498Szrj static inline ipa_reference_optimization_summary_t
get_reference_optimization_summary(struct cgraph_node * node)14038fd1498Szrj get_reference_optimization_summary (struct cgraph_node *node)
14138fd1498Szrj {
14238fd1498Szrj if (!ipa_reference_opt_sum_vector.exists ()
14338fd1498Szrj || (ipa_reference_opt_sum_vector.length () <= (unsigned int) node->uid))
14438fd1498Szrj return NULL;
14538fd1498Szrj return ipa_reference_opt_sum_vector[node->uid];
14638fd1498Szrj }
14738fd1498Szrj
14838fd1498Szrj /* Return the ipa_reference_vars structure starting from the cgraph NODE. */
14938fd1498Szrj static inline void
set_reference_vars_info(struct cgraph_node * node,ipa_reference_vars_info_t info)15038fd1498Szrj set_reference_vars_info (struct cgraph_node *node,
15138fd1498Szrj ipa_reference_vars_info_t info)
15238fd1498Szrj {
15338fd1498Szrj if (!ipa_reference_vars_vector.exists ()
15438fd1498Szrj || ipa_reference_vars_vector.length () <= (unsigned int) node->uid)
15538fd1498Szrj ipa_reference_vars_vector.safe_grow_cleared (node->uid + 1);
15638fd1498Szrj ipa_reference_vars_vector[node->uid] = info;
15738fd1498Szrj }
15838fd1498Szrj
15938fd1498Szrj /* Return the ipa_reference_vars structure starting from the cgraph NODE. */
16038fd1498Szrj static inline void
set_reference_optimization_summary(struct cgraph_node * node,ipa_reference_optimization_summary_t info)16138fd1498Szrj set_reference_optimization_summary (struct cgraph_node *node,
16238fd1498Szrj ipa_reference_optimization_summary_t info)
16338fd1498Szrj {
16438fd1498Szrj if (!ipa_reference_opt_sum_vector.exists ()
16538fd1498Szrj || (ipa_reference_opt_sum_vector.length () <= (unsigned int) node->uid))
16638fd1498Szrj ipa_reference_opt_sum_vector.safe_grow_cleared (node->uid + 1);
16738fd1498Szrj ipa_reference_opt_sum_vector[node->uid] = info;
16838fd1498Szrj }
16938fd1498Szrj
17038fd1498Szrj /* Return a bitmap indexed by ipa_reference_var_uid for the static variables
17138fd1498Szrj that are *not* read during the execution of the function FN. Returns
17238fd1498Szrj NULL if no data is available. */
17338fd1498Szrj
17438fd1498Szrj bitmap
ipa_reference_get_not_read_global(struct cgraph_node * fn)17538fd1498Szrj ipa_reference_get_not_read_global (struct cgraph_node *fn)
17638fd1498Szrj {
17738fd1498Szrj if (!opt_for_fn (current_function_decl, flag_ipa_reference))
17838fd1498Szrj return NULL;
17938fd1498Szrj
18038fd1498Szrj enum availability avail;
18138fd1498Szrj struct cgraph_node *fn2 = fn->function_symbol (&avail);
18238fd1498Szrj ipa_reference_optimization_summary_t info =
18338fd1498Szrj get_reference_optimization_summary (fn2);
18438fd1498Szrj
18538fd1498Szrj if (info
18638fd1498Szrj && (avail >= AVAIL_AVAILABLE
18738fd1498Szrj || (avail == AVAIL_INTERPOSABLE
18838fd1498Szrj && flags_from_decl_or_type (fn->decl) & ECF_LEAF))
18938fd1498Szrj && opt_for_fn (fn2->decl, flag_ipa_reference))
19038fd1498Szrj return info->statics_not_read;
19138fd1498Szrj else if (avail == AVAIL_NOT_AVAILABLE
19238fd1498Szrj && flags_from_decl_or_type (fn->decl) & ECF_LEAF)
19338fd1498Szrj return all_module_statics;
19438fd1498Szrj else
19538fd1498Szrj return NULL;
19638fd1498Szrj }
19738fd1498Szrj
19838fd1498Szrj /* Return a bitmap indexed by ipa_reference_var_uid for the static variables
19938fd1498Szrj that are *not* written during the execution of the function FN. Note
20038fd1498Szrj that variables written may or may not be read during the function
20138fd1498Szrj call. Returns NULL if no data is available. */
20238fd1498Szrj
20338fd1498Szrj bitmap
ipa_reference_get_not_written_global(struct cgraph_node * fn)20438fd1498Szrj ipa_reference_get_not_written_global (struct cgraph_node *fn)
20538fd1498Szrj {
20638fd1498Szrj if (!opt_for_fn (current_function_decl, flag_ipa_reference))
20738fd1498Szrj return NULL;
20838fd1498Szrj
20938fd1498Szrj enum availability avail;
21038fd1498Szrj struct cgraph_node *fn2 = fn->function_symbol (&avail);
21138fd1498Szrj ipa_reference_optimization_summary_t info =
21238fd1498Szrj get_reference_optimization_summary (fn2);
21338fd1498Szrj
21438fd1498Szrj if (info
21538fd1498Szrj && (avail >= AVAIL_AVAILABLE
21638fd1498Szrj || (avail == AVAIL_INTERPOSABLE
21738fd1498Szrj && flags_from_decl_or_type (fn->decl) & ECF_LEAF))
21838fd1498Szrj && opt_for_fn (fn2->decl, flag_ipa_reference))
21938fd1498Szrj return info->statics_not_written;
22038fd1498Szrj else if (avail == AVAIL_NOT_AVAILABLE
22138fd1498Szrj && flags_from_decl_or_type (fn->decl) & ECF_LEAF)
22238fd1498Szrj return all_module_statics;
22338fd1498Szrj else
22438fd1498Szrj return NULL;
22538fd1498Szrj }
22638fd1498Szrj
22738fd1498Szrj
22838fd1498Szrj /* Hepler for is_proper_for_analysis. */
22938fd1498Szrj static bool
is_improper(symtab_node * n,void * v ATTRIBUTE_UNUSED)23038fd1498Szrj is_improper (symtab_node *n, void *v ATTRIBUTE_UNUSED)
23138fd1498Szrj {
23238fd1498Szrj tree t = n->decl;
23338fd1498Szrj /* If the variable has the "used" attribute, treat it as if it had a
23438fd1498Szrj been touched by the devil. */
23538fd1498Szrj if (DECL_PRESERVE_P (t))
23638fd1498Szrj return true;
23738fd1498Szrj
23838fd1498Szrj /* Do not want to do anything with volatile except mark any
23938fd1498Szrj function that uses one to be not const or pure. */
24038fd1498Szrj if (TREE_THIS_VOLATILE (t))
24138fd1498Szrj return true;
24238fd1498Szrj
24338fd1498Szrj /* We do not need to analyze readonly vars, we already know they do not
24438fd1498Szrj alias. */
24538fd1498Szrj if (TREE_READONLY (t))
24638fd1498Szrj return true;
24738fd1498Szrj
24838fd1498Szrj /* We can not track variables with address taken. */
24938fd1498Szrj if (TREE_ADDRESSABLE (t))
25038fd1498Szrj return true;
25138fd1498Szrj
25238fd1498Szrj /* TODO: We could track public variables that are not addressable, but
25338fd1498Szrj currently frontends don't give us those. */
25438fd1498Szrj if (TREE_PUBLIC (t))
25538fd1498Szrj return true;
25638fd1498Szrj
25738fd1498Szrj return false;
25838fd1498Szrj }
25938fd1498Szrj
26038fd1498Szrj /* Return true if the variable T is the right kind of static variable to
26138fd1498Szrj perform compilation unit scope escape analysis. */
26238fd1498Szrj
26338fd1498Szrj static inline bool
is_proper_for_analysis(tree t)26438fd1498Szrj is_proper_for_analysis (tree t)
26538fd1498Szrj {
26638fd1498Szrj if (bitmap_bit_p (ignore_module_statics, ipa_reference_var_uid (t)))
26738fd1498Szrj return false;
26838fd1498Szrj
26938fd1498Szrj if (symtab_node::get (t)
27038fd1498Szrj ->call_for_symbol_and_aliases (is_improper, NULL, true))
27138fd1498Szrj return false;
27238fd1498Szrj
27338fd1498Szrj return true;
27438fd1498Szrj }
27538fd1498Szrj
27638fd1498Szrj /* Lookup the tree node for the static variable that has UID and
27738fd1498Szrj convert the name to a string for debugging. */
27838fd1498Szrj
27938fd1498Szrj static const char *
get_static_name(int index)28038fd1498Szrj get_static_name (int index)
28138fd1498Szrj {
28238fd1498Szrj splay_tree_node stn =
28338fd1498Szrj splay_tree_lookup (reference_vars_to_consider, index);
28438fd1498Szrj return fndecl_name ((tree)(stn->value));
28538fd1498Szrj }
28638fd1498Szrj
28738fd1498Szrj /* Dump a set of static vars to FILE. */
28838fd1498Szrj static void
dump_static_vars_set_to_file(FILE * f,bitmap set)28938fd1498Szrj dump_static_vars_set_to_file (FILE *f, bitmap set)
29038fd1498Szrj {
29138fd1498Szrj unsigned int index;
29238fd1498Szrj bitmap_iterator bi;
29338fd1498Szrj if (set == NULL)
29438fd1498Szrj return;
29538fd1498Szrj else if (set == all_module_statics)
29638fd1498Szrj fprintf (f, "ALL");
29738fd1498Szrj else
29838fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (set, 0, index, bi)
29938fd1498Szrj {
30038fd1498Szrj fprintf (f, "%s ", get_static_name (index));
30138fd1498Szrj }
30238fd1498Szrj }
30338fd1498Szrj
30438fd1498Szrj /* Compute X |= Y, taking into account the possibility that
30538fd1498Szrj either X or Y is already the maximum set.
30638fd1498Szrj Return true if X is the maximum set after taking the union with Y. */
30738fd1498Szrj
30838fd1498Szrj static bool
union_static_var_sets(bitmap & x,bitmap y)30938fd1498Szrj union_static_var_sets (bitmap &x, bitmap y)
31038fd1498Szrj {
31138fd1498Szrj if (x != all_module_statics)
31238fd1498Szrj {
31338fd1498Szrj if (y == all_module_statics)
31438fd1498Szrj {
31538fd1498Szrj BITMAP_FREE (x);
31638fd1498Szrj x = all_module_statics;
31738fd1498Szrj }
31838fd1498Szrj else if (bitmap_ior_into (x, y))
31938fd1498Szrj {
32038fd1498Szrj /* The union may have reduced X to the maximum set.
32138fd1498Szrj In that case, we want to make that visible explicitly.
32238fd1498Szrj Even though bitmap_equal_p can be very expensive, it
32338fd1498Szrj turns out to be an overall win to check this here for
32438fd1498Szrj an LTO bootstrap of GCC itself. Liberally extrapoliate
32538fd1498Szrj that result to be applicable to all cases. */
32638fd1498Szrj if (bitmap_equal_p (x, all_module_statics))
32738fd1498Szrj {
32838fd1498Szrj BITMAP_FREE (x);
32938fd1498Szrj x = all_module_statics;
33038fd1498Szrj }
33138fd1498Szrj }
33238fd1498Szrj }
33338fd1498Szrj return x == all_module_statics;
33438fd1498Szrj }
33538fd1498Szrj
33638fd1498Szrj /* Return a copy of SET on the bitmap obstack containing SET.
33738fd1498Szrj But if SET is NULL or the maximum set, return that instead. */
33838fd1498Szrj
33938fd1498Szrj static bitmap
copy_static_var_set(bitmap set)34038fd1498Szrj copy_static_var_set (bitmap set)
34138fd1498Szrj {
34238fd1498Szrj if (set == NULL || set == all_module_statics)
34338fd1498Szrj return set;
34438fd1498Szrj bitmap_obstack *o = set->obstack;
34538fd1498Szrj gcc_checking_assert (o);
34638fd1498Szrj bitmap copy = BITMAP_ALLOC (o);
34738fd1498Szrj bitmap_copy (copy, set);
34838fd1498Szrj return copy;
34938fd1498Szrj }
35038fd1498Szrj
35138fd1498Szrj /* Compute the union all of the statics read and written by every callee of X
35238fd1498Szrj into X_GLOBAL->statics_read and X_GLOBAL->statics_written. X_GLOBAL is
35338fd1498Szrj actually the set representing the cycle containing X. If the read and
35438fd1498Szrj written sets of X_GLOBAL has been reduced to the maximum set, we don't
35538fd1498Szrj have to look at the remaining callees. */
35638fd1498Szrj
35738fd1498Szrj static void
propagate_bits(ipa_reference_global_vars_info_t x_global,struct cgraph_node * x)35838fd1498Szrj propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x)
35938fd1498Szrj {
36038fd1498Szrj struct cgraph_edge *e;
36138fd1498Szrj bool read_all = x_global->statics_read == all_module_statics;
36238fd1498Szrj bool write_all = x_global->statics_written == all_module_statics;
36338fd1498Szrj for (e = x->callees;
36438fd1498Szrj e && !(read_all && write_all);
36538fd1498Szrj e = e->next_callee)
36638fd1498Szrj {
36738fd1498Szrj enum availability avail;
36838fd1498Szrj struct cgraph_node *y = e->callee->function_symbol (&avail);
36938fd1498Szrj if (!y)
37038fd1498Szrj continue;
37138fd1498Szrj
37238fd1498Szrj /* Only look into nodes we can propagate something. */
37338fd1498Szrj int flags = flags_from_decl_or_type (y->decl);
37438fd1498Szrj if (opt_for_fn (y->decl, flag_ipa_reference)
37538fd1498Szrj && (avail > AVAIL_INTERPOSABLE
37638fd1498Szrj || (avail == AVAIL_INTERPOSABLE && (flags & ECF_LEAF))))
37738fd1498Szrj {
37838fd1498Szrj if (get_reference_vars_info (y))
37938fd1498Szrj {
38038fd1498Szrj ipa_reference_vars_info_t y_info = get_reference_vars_info (y);
38138fd1498Szrj ipa_reference_global_vars_info_t y_global = &y_info->global;
38238fd1498Szrj
38338fd1498Szrj /* Calls in the current cycle do not have their global set
38438fd1498Szrj computed yet (but everything else does because we're
38538fd1498Szrj visiting nodes in topological order). */
38638fd1498Szrj if (!y_global->statics_read)
38738fd1498Szrj continue;
38838fd1498Szrj
38938fd1498Szrj /* If the function is const, it reads no memory even if it
39038fd1498Szrj seems so to local analysis. */
39138fd1498Szrj if (flags & ECF_CONST)
39238fd1498Szrj continue;
39338fd1498Szrj
39438fd1498Szrj union_static_var_sets (x_global->statics_read,
39538fd1498Szrj y_global->statics_read);
39638fd1498Szrj
39738fd1498Szrj /* If the function is pure, it has no stores even if it
39838fd1498Szrj seems so to local analysis. If we cannot return from
39938fd1498Szrj the function, we can safely ignore the call. */
40038fd1498Szrj if ((flags & ECF_PURE)
40138fd1498Szrj || e->cannot_lead_to_return_p ())
40238fd1498Szrj continue;
40338fd1498Szrj
40438fd1498Szrj union_static_var_sets (x_global->statics_written,
40538fd1498Szrj y_global->statics_written);
40638fd1498Szrj }
40738fd1498Szrj else
40838fd1498Szrj gcc_unreachable ();
40938fd1498Szrj }
41038fd1498Szrj }
41138fd1498Szrj }
41238fd1498Szrj
41338fd1498Szrj static bool ipa_init_p = false;
41438fd1498Szrj
41538fd1498Szrj /* The init routine for analyzing global static variable usage. See
41638fd1498Szrj comments at top for description. */
41738fd1498Szrj static void
ipa_init(void)41838fd1498Szrj ipa_init (void)
41938fd1498Szrj {
42038fd1498Szrj if (ipa_init_p)
42138fd1498Szrj return;
42238fd1498Szrj
42338fd1498Szrj ipa_init_p = true;
42438fd1498Szrj
42538fd1498Szrj if (dump_file)
42638fd1498Szrj reference_vars_to_consider = splay_tree_new (splay_tree_compare_ints, 0, 0);
42738fd1498Szrj
42838fd1498Szrj bitmap_obstack_initialize (&local_info_obstack);
42938fd1498Szrj bitmap_obstack_initialize (&optimization_summary_obstack);
43038fd1498Szrj all_module_statics = BITMAP_ALLOC (&optimization_summary_obstack);
43138fd1498Szrj ignore_module_statics = BITMAP_ALLOC (&optimization_summary_obstack);
43238fd1498Szrj
43338fd1498Szrj node_removal_hook_holder =
43438fd1498Szrj symtab->add_cgraph_removal_hook (&remove_node_data, NULL);
43538fd1498Szrj node_duplication_hook_holder =
43638fd1498Szrj symtab->add_cgraph_duplication_hook (&duplicate_node_data, NULL);
43738fd1498Szrj }
43838fd1498Szrj
43938fd1498Szrj
44038fd1498Szrj /* Set up the persistent info for FN. */
44138fd1498Szrj
44238fd1498Szrj static ipa_reference_local_vars_info_t
init_function_info(struct cgraph_node * fn)44338fd1498Szrj init_function_info (struct cgraph_node *fn)
44438fd1498Szrj {
44538fd1498Szrj ipa_reference_vars_info_t info
44638fd1498Szrj = XCNEW (struct ipa_reference_vars_info_d);
44738fd1498Szrj
44838fd1498Szrj /* Add the info to the tree's annotation. */
44938fd1498Szrj set_reference_vars_info (fn, info);
45038fd1498Szrj
45138fd1498Szrj info->local.statics_read = BITMAP_ALLOC (&local_info_obstack);
45238fd1498Szrj info->local.statics_written = BITMAP_ALLOC (&local_info_obstack);
45338fd1498Szrj
45438fd1498Szrj return &info->local;
45538fd1498Szrj }
45638fd1498Szrj
45738fd1498Szrj
45838fd1498Szrj /* This is the main routine for finding the reference patterns for
45938fd1498Szrj global variables within a function FN. */
46038fd1498Szrj
46138fd1498Szrj static void
analyze_function(struct cgraph_node * fn)46238fd1498Szrj analyze_function (struct cgraph_node *fn)
46338fd1498Szrj {
46438fd1498Szrj ipa_reference_local_vars_info_t local;
46538fd1498Szrj struct ipa_ref *ref = NULL;
46638fd1498Szrj int i;
46738fd1498Szrj tree var;
46838fd1498Szrj
46938fd1498Szrj if (!opt_for_fn (fn->decl, flag_ipa_reference))
47038fd1498Szrj return;
47138fd1498Szrj local = init_function_info (fn);
47238fd1498Szrj for (i = 0; fn->iterate_reference (i, ref); i++)
47338fd1498Szrj {
47438fd1498Szrj if (!is_a <varpool_node *> (ref->referred))
47538fd1498Szrj continue;
47638fd1498Szrj var = ref->referred->decl;
47738fd1498Szrj if (!is_proper_for_analysis (var))
47838fd1498Szrj continue;
47938fd1498Szrj /* This is a variable we care about. Check if we have seen it
48038fd1498Szrj before, and if not add it the set of variables we care about. */
48138fd1498Szrj if (all_module_statics
48238fd1498Szrj && bitmap_set_bit (all_module_statics, ipa_reference_var_uid (var)))
48338fd1498Szrj {
48438fd1498Szrj if (dump_file)
48538fd1498Szrj splay_tree_insert (reference_vars_to_consider,
48638fd1498Szrj ipa_reference_var_uid (var),
48738fd1498Szrj (splay_tree_value)var);
48838fd1498Szrj }
48938fd1498Szrj switch (ref->use)
49038fd1498Szrj {
49138fd1498Szrj case IPA_REF_LOAD:
49238fd1498Szrj bitmap_set_bit (local->statics_read, ipa_reference_var_uid (var));
49338fd1498Szrj break;
49438fd1498Szrj case IPA_REF_STORE:
49538fd1498Szrj if (ref->cannot_lead_to_return ())
49638fd1498Szrj break;
49738fd1498Szrj bitmap_set_bit (local->statics_written, ipa_reference_var_uid (var));
49838fd1498Szrj break;
49938fd1498Szrj case IPA_REF_ADDR:
50038fd1498Szrj break;
50138fd1498Szrj default:
50238fd1498Szrj gcc_unreachable ();
50338fd1498Szrj }
50438fd1498Szrj }
50538fd1498Szrj
50638fd1498Szrj if (fn->cannot_return_p ())
50738fd1498Szrj bitmap_clear (local->statics_written);
50838fd1498Szrj }
50938fd1498Szrj
51038fd1498Szrj
51138fd1498Szrj /* Called when new clone is inserted to callgraph late. */
51238fd1498Szrj
51338fd1498Szrj static void
duplicate_node_data(struct cgraph_node * src,struct cgraph_node * dst,void * data ATTRIBUTE_UNUSED)51438fd1498Szrj duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
51538fd1498Szrj void *data ATTRIBUTE_UNUSED)
51638fd1498Szrj {
51738fd1498Szrj ipa_reference_optimization_summary_t ginfo;
51838fd1498Szrj ipa_reference_optimization_summary_t dst_ginfo;
51938fd1498Szrj
52038fd1498Szrj ginfo = get_reference_optimization_summary (src);
52138fd1498Szrj if (!ginfo)
52238fd1498Szrj return;
52338fd1498Szrj dst_ginfo = XCNEW (struct ipa_reference_optimization_summary_d);
52438fd1498Szrj set_reference_optimization_summary (dst, dst_ginfo);
52538fd1498Szrj dst_ginfo->statics_not_read =
52638fd1498Szrj copy_static_var_set (ginfo->statics_not_read);
52738fd1498Szrj dst_ginfo->statics_not_written =
52838fd1498Szrj copy_static_var_set (ginfo->statics_not_written);
52938fd1498Szrj }
53038fd1498Szrj
53138fd1498Szrj /* Called when node is removed. */
53238fd1498Szrj
53338fd1498Szrj static void
remove_node_data(struct cgraph_node * node,void * data ATTRIBUTE_UNUSED)53438fd1498Szrj remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
53538fd1498Szrj {
53638fd1498Szrj ipa_reference_optimization_summary_t ginfo;
53738fd1498Szrj ginfo = get_reference_optimization_summary (node);
53838fd1498Szrj if (ginfo)
53938fd1498Szrj {
54038fd1498Szrj if (ginfo->statics_not_read
54138fd1498Szrj && ginfo->statics_not_read != all_module_statics)
54238fd1498Szrj BITMAP_FREE (ginfo->statics_not_read);
54338fd1498Szrj
54438fd1498Szrj if (ginfo->statics_not_written
54538fd1498Szrj && ginfo->statics_not_written != all_module_statics)
54638fd1498Szrj BITMAP_FREE (ginfo->statics_not_written);
54738fd1498Szrj free (ginfo);
54838fd1498Szrj set_reference_optimization_summary (node, NULL);
54938fd1498Szrj }
55038fd1498Szrj }
55138fd1498Szrj
55238fd1498Szrj /* Analyze each function in the cgraph to see which global or statics
55338fd1498Szrj are read or written. */
55438fd1498Szrj
55538fd1498Szrj static void
generate_summary(void)55638fd1498Szrj generate_summary (void)
55738fd1498Szrj {
55838fd1498Szrj struct cgraph_node *node;
55938fd1498Szrj unsigned int index;
56038fd1498Szrj bitmap_iterator bi;
56138fd1498Szrj
56238fd1498Szrj ipa_init ();
56338fd1498Szrj
56438fd1498Szrj /* Process all of the functions next. */
56538fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
56638fd1498Szrj if (!node->alias && !opt_for_fn (node->decl, flag_ipa_reference))
56738fd1498Szrj {
56838fd1498Szrj struct ipa_ref *ref = NULL;
56938fd1498Szrj int i;
57038fd1498Szrj tree var;
57138fd1498Szrj for (i = 0; node->iterate_reference (i, ref); i++)
57238fd1498Szrj {
57338fd1498Szrj if (!is_a <varpool_node *> (ref->referred))
57438fd1498Szrj continue;
57538fd1498Szrj var = ref->referred->decl;
57638fd1498Szrj if (!is_proper_for_analysis (var))
57738fd1498Szrj continue;
57838fd1498Szrj bitmap_set_bit (ignore_module_statics, ipa_reference_var_uid (var));
57938fd1498Szrj }
58038fd1498Szrj }
58138fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
58238fd1498Szrj analyze_function (node);
58338fd1498Szrj
58438fd1498Szrj if (dump_file)
58538fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi)
58638fd1498Szrj {
58738fd1498Szrj fprintf (dump_file, "\nPromotable global:%s (uid=%u)\n",
58838fd1498Szrj get_static_name (index), index);
58938fd1498Szrj }
59038fd1498Szrj
59138fd1498Szrj if (dump_file)
59238fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
59338fd1498Szrj if (node->get_availability () >= AVAIL_INTERPOSABLE
59438fd1498Szrj && opt_for_fn (node->decl, flag_ipa_reference))
59538fd1498Szrj {
59638fd1498Szrj ipa_reference_local_vars_info_t l;
59738fd1498Szrj unsigned int index;
59838fd1498Szrj bitmap_iterator bi;
59938fd1498Szrj
60038fd1498Szrj l = &get_reference_vars_info (node)->local;
60138fd1498Szrj fprintf (dump_file,
60238fd1498Szrj "\nFunction name:%s:", node->dump_name ());
60338fd1498Szrj fprintf (dump_file, "\n locals read: ");
60438fd1498Szrj if (l->statics_read)
60538fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (l->statics_read,
60638fd1498Szrj 0, index, bi)
60738fd1498Szrj {
60838fd1498Szrj fprintf (dump_file, "%s ",
60938fd1498Szrj get_static_name (index));
61038fd1498Szrj }
61138fd1498Szrj fprintf (dump_file, "\n locals written: ");
61238fd1498Szrj if (l->statics_written)
61338fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (l->statics_written,
61438fd1498Szrj 0, index, bi)
61538fd1498Szrj {
61638fd1498Szrj fprintf (dump_file, "%s ", get_static_name (index));
61738fd1498Szrj }
61838fd1498Szrj }
61938fd1498Szrj }
62038fd1498Szrj
62138fd1498Szrj /* Set READ_ALL/WRITE_ALL based on decl flags of NODE. */
62238fd1498Szrj
62338fd1498Szrj static void
read_write_all_from_decl(struct cgraph_node * node,bool & read_all,bool & write_all)62438fd1498Szrj read_write_all_from_decl (struct cgraph_node *node,
62538fd1498Szrj bool &read_all, bool &write_all)
62638fd1498Szrj {
62738fd1498Szrj tree decl = node->decl;
62838fd1498Szrj int flags = flags_from_decl_or_type (decl);
62938fd1498Szrj if ((flags & ECF_LEAF)
63038fd1498Szrj && node->get_availability () < AVAIL_INTERPOSABLE)
63138fd1498Szrj ;
63238fd1498Szrj else if (flags & ECF_CONST)
63338fd1498Szrj ;
63438fd1498Szrj else if ((flags & ECF_PURE) || node->cannot_return_p ())
63538fd1498Szrj {
63638fd1498Szrj read_all = true;
63738fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
63838fd1498Szrj fprintf (dump_file, " %s -> read all\n", node->dump_name ());
63938fd1498Szrj }
64038fd1498Szrj else
64138fd1498Szrj {
64238fd1498Szrj /* TODO: To be able to produce sane results, we should also handle
64338fd1498Szrj common builtins, in particular throw. */
64438fd1498Szrj read_all = true;
64538fd1498Szrj write_all = true;
64638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
64738fd1498Szrj fprintf (dump_file, " %s -> read all, write all\n",
64838fd1498Szrj node->dump_name ());
64938fd1498Szrj }
65038fd1498Szrj }
65138fd1498Szrj
65238fd1498Szrj /* Set READ_ALL/WRITE_ALL based on decl flags of NODE or any member
65338fd1498Szrj in the cycle of NODE. */
65438fd1498Szrj
65538fd1498Szrj static void
get_read_write_all_from_node(struct cgraph_node * node,bool & read_all,bool & write_all)65638fd1498Szrj get_read_write_all_from_node (struct cgraph_node *node,
65738fd1498Szrj bool &read_all, bool &write_all)
65838fd1498Szrj {
65938fd1498Szrj struct cgraph_edge *e, *ie;
66038fd1498Szrj
66138fd1498Szrj /* When function is overwritable, we can not assume anything. */
66238fd1498Szrj if (node->get_availability () <= AVAIL_INTERPOSABLE
66338fd1498Szrj || (node->analyzed && !opt_for_fn (node->decl, flag_ipa_reference)))
66438fd1498Szrj read_write_all_from_decl (node, read_all, write_all);
66538fd1498Szrj
66638fd1498Szrj for (e = node->callees;
66738fd1498Szrj e && !(read_all && write_all);
66838fd1498Szrj e = e->next_callee)
66938fd1498Szrj {
67038fd1498Szrj enum availability avail;
67138fd1498Szrj struct cgraph_node *callee = e->callee->function_symbol (&avail);
67238fd1498Szrj gcc_checking_assert (callee);
67338fd1498Szrj if (avail <= AVAIL_INTERPOSABLE
67438fd1498Szrj || (callee->analyzed && !opt_for_fn (callee->decl, flag_ipa_reference)))
67538fd1498Szrj read_write_all_from_decl (callee, read_all, write_all);
67638fd1498Szrj }
67738fd1498Szrj
67838fd1498Szrj for (ie = node->indirect_calls;
67938fd1498Szrj ie && !(read_all && write_all);
68038fd1498Szrj ie = ie->next_callee)
68138fd1498Szrj if (!(ie->indirect_info->ecf_flags & ECF_CONST))
68238fd1498Szrj {
68338fd1498Szrj read_all = true;
68438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
68538fd1498Szrj fprintf (dump_file, " indirect call -> read all\n");
68638fd1498Szrj if (!ie->cannot_lead_to_return_p ()
68738fd1498Szrj && !(ie->indirect_info->ecf_flags & ECF_PURE))
68838fd1498Szrj {
68938fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
69038fd1498Szrj fprintf (dump_file, " indirect call -> write all\n");
69138fd1498Szrj write_all = true;
69238fd1498Szrj }
69338fd1498Szrj }
69438fd1498Szrj }
69538fd1498Szrj
69638fd1498Szrj /* Skip edges from and to nodes without ipa_reference enables. This leave
69738fd1498Szrj them out of strongy connected coponents and makes them easyto skip in the
69838fd1498Szrj propagation loop bellow. */
69938fd1498Szrj
70038fd1498Szrj static bool
ignore_edge_p(cgraph_edge * e)70138fd1498Szrj ignore_edge_p (cgraph_edge *e)
70238fd1498Szrj {
70338fd1498Szrj return (!opt_for_fn (e->caller->decl, flag_ipa_reference)
70438fd1498Szrj || !opt_for_fn (e->callee->function_symbol ()->decl,
70538fd1498Szrj flag_ipa_reference));
70638fd1498Szrj }
70738fd1498Szrj
70838fd1498Szrj /* Produce the global information by preforming a transitive closure
70938fd1498Szrj on the local information that was produced by ipa_analyze_function. */
71038fd1498Szrj
71138fd1498Szrj static unsigned int
propagate(void)71238fd1498Szrj propagate (void)
71338fd1498Szrj {
71438fd1498Szrj struct cgraph_node *node;
71538fd1498Szrj struct cgraph_node **order =
71638fd1498Szrj XCNEWVEC (struct cgraph_node *, symtab->cgraph_count);
71738fd1498Szrj int order_pos;
71838fd1498Szrj int i;
71938fd1498Szrj bool remove_p;
72038fd1498Szrj
72138fd1498Szrj if (dump_file)
72238fd1498Szrj cgraph_node::dump_cgraph (dump_file);
72338fd1498Szrj
72438fd1498Szrj remove_p = ipa_discover_readonly_nonaddressable_vars ();
72538fd1498Szrj generate_summary ();
72638fd1498Szrj
72738fd1498Szrj /* Propagate the local information through the call graph to produce
72838fd1498Szrj the global information. All the nodes within a cycle will have
72938fd1498Szrj the same info so we collapse cycles first. Then we can do the
73038fd1498Szrj propagation in one pass from the leaves to the roots. */
731*58e805e6Szrj order_pos = ipa_reduced_postorder (order, true, ignore_edge_p);
73238fd1498Szrj if (dump_file)
73338fd1498Szrj ipa_print_order (dump_file, "reduced", order, order_pos);
73438fd1498Szrj
73538fd1498Szrj for (i = 0; i < order_pos; i++ )
73638fd1498Szrj {
73738fd1498Szrj unsigned x;
73838fd1498Szrj struct cgraph_node *w;
73938fd1498Szrj ipa_reference_vars_info_t node_info;
74038fd1498Szrj ipa_reference_global_vars_info_t node_g;
74138fd1498Szrj ipa_reference_local_vars_info_t node_l;
74238fd1498Szrj bool read_all = false;
74338fd1498Szrj bool write_all = false;
74438fd1498Szrj
74538fd1498Szrj node = order[i];
74638fd1498Szrj if (node->alias || !opt_for_fn (node->decl, flag_ipa_reference))
74738fd1498Szrj continue;
74838fd1498Szrj
74938fd1498Szrj node_info = get_reference_vars_info (node);
75038fd1498Szrj gcc_assert (node_info);
75138fd1498Szrj node_l = &node_info->local;
75238fd1498Szrj node_g = &node_info->global;
75338fd1498Szrj
75438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
75538fd1498Szrj fprintf (dump_file, "Starting cycle with %s\n", node->dump_name ());
75638fd1498Szrj
75738fd1498Szrj vec<cgraph_node *> cycle_nodes = ipa_get_nodes_in_cycle (node);
75838fd1498Szrj
75938fd1498Szrj /* If any node in a cycle is read_all or write_all, they all are. */
76038fd1498Szrj FOR_EACH_VEC_ELT (cycle_nodes, x, w)
76138fd1498Szrj {
76238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
76338fd1498Szrj fprintf (dump_file, " Visiting %s\n", w->dump_asm_name ());
76438fd1498Szrj get_read_write_all_from_node (w, read_all, write_all);
76538fd1498Szrj if (read_all && write_all)
76638fd1498Szrj break;
76738fd1498Szrj }
76838fd1498Szrj
76938fd1498Szrj /* Initialized the bitmaps global sets for the reduced node. */
77038fd1498Szrj if (read_all)
77138fd1498Szrj node_g->statics_read = all_module_statics;
77238fd1498Szrj else
77338fd1498Szrj node_g->statics_read = copy_static_var_set (node_l->statics_read);
77438fd1498Szrj if (write_all)
77538fd1498Szrj node_g->statics_written = all_module_statics;
77638fd1498Szrj else
77738fd1498Szrj node_g->statics_written = copy_static_var_set (node_l->statics_written);
77838fd1498Szrj
77938fd1498Szrj /* Merge the sets of this cycle with all sets of callees reached
78038fd1498Szrj from this cycle. */
78138fd1498Szrj FOR_EACH_VEC_ELT (cycle_nodes, x, w)
78238fd1498Szrj {
78338fd1498Szrj if (read_all && write_all)
78438fd1498Szrj break;
78538fd1498Szrj
78638fd1498Szrj if (w != node)
78738fd1498Szrj {
78838fd1498Szrj ipa_reference_vars_info_t w_ri = get_reference_vars_info (w);
78938fd1498Szrj ipa_reference_local_vars_info_t w_l = &w_ri->local;
79038fd1498Szrj int flags = flags_from_decl_or_type (w->decl);
79138fd1498Szrj
79238fd1498Szrj if (!(flags & ECF_CONST))
79338fd1498Szrj read_all = union_static_var_sets (node_g->statics_read,
79438fd1498Szrj w_l->statics_read);
79538fd1498Szrj if (!(flags & ECF_PURE)
79638fd1498Szrj && !w->cannot_return_p ())
79738fd1498Szrj write_all = union_static_var_sets (node_g->statics_written,
79838fd1498Szrj w_l->statics_written);
79938fd1498Szrj }
80038fd1498Szrj
80138fd1498Szrj propagate_bits (node_g, w);
80238fd1498Szrj }
80338fd1498Szrj
80438fd1498Szrj /* All nodes within a cycle have the same global info bitmaps. */
80538fd1498Szrj FOR_EACH_VEC_ELT (cycle_nodes, x, w)
80638fd1498Szrj {
80738fd1498Szrj ipa_reference_vars_info_t w_ri = get_reference_vars_info (w);
80838fd1498Szrj w_ri->global = *node_g;
80938fd1498Szrj }
81038fd1498Szrj
81138fd1498Szrj cycle_nodes.release ();
81238fd1498Szrj }
81338fd1498Szrj
81438fd1498Szrj if (dump_file)
81538fd1498Szrj {
81638fd1498Szrj for (i = 0; i < order_pos; i++)
81738fd1498Szrj {
81838fd1498Szrj unsigned x;
81938fd1498Szrj struct cgraph_node *w;
82038fd1498Szrj
82138fd1498Szrj node = order[i];
82238fd1498Szrj if (node->alias || !opt_for_fn (node->decl, flag_ipa_reference))
82338fd1498Szrj continue;
82438fd1498Szrj
82538fd1498Szrj fprintf (dump_file, "\nFunction name:%s:", node->dump_asm_name ());
82638fd1498Szrj
82738fd1498Szrj ipa_reference_vars_info_t node_info = get_reference_vars_info (node);
82838fd1498Szrj ipa_reference_global_vars_info_t node_g = &node_info->global;
82938fd1498Szrj
83038fd1498Szrj vec<cgraph_node *> cycle_nodes = ipa_get_nodes_in_cycle (node);
83138fd1498Szrj FOR_EACH_VEC_ELT (cycle_nodes, x, w)
83238fd1498Szrj {
83338fd1498Szrj ipa_reference_vars_info_t w_ri = get_reference_vars_info (w);
83438fd1498Szrj ipa_reference_local_vars_info_t w_l = &w_ri->local;
83538fd1498Szrj if (w != node)
83638fd1498Szrj fprintf (dump_file, "\n next cycle: %s ", w->dump_asm_name ());
83738fd1498Szrj fprintf (dump_file, "\n locals read: ");
83838fd1498Szrj dump_static_vars_set_to_file (dump_file, w_l->statics_read);
83938fd1498Szrj fprintf (dump_file, "\n locals written: ");
84038fd1498Szrj dump_static_vars_set_to_file (dump_file, w_l->statics_written);
84138fd1498Szrj }
84238fd1498Szrj cycle_nodes.release ();
84338fd1498Szrj
84438fd1498Szrj fprintf (dump_file, "\n globals read: ");
84538fd1498Szrj dump_static_vars_set_to_file (dump_file, node_g->statics_read);
84638fd1498Szrj fprintf (dump_file, "\n globals written: ");
84738fd1498Szrj dump_static_vars_set_to_file (dump_file, node_g->statics_written);
84838fd1498Szrj fprintf (dump_file, "\n");
84938fd1498Szrj }
85038fd1498Szrj }
85138fd1498Szrj
85238fd1498Szrj /* Cleanup. */
85338fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
85438fd1498Szrj {
85538fd1498Szrj ipa_reference_vars_info_t node_info;
85638fd1498Szrj ipa_reference_global_vars_info_t node_g;
85738fd1498Szrj ipa_reference_optimization_summary_t opt;
85838fd1498Szrj
85938fd1498Szrj node_info = get_reference_vars_info (node);
86038fd1498Szrj if (!node->alias && opt_for_fn (node->decl, flag_ipa_reference)
86138fd1498Szrj && (node->get_availability () > AVAIL_INTERPOSABLE
86238fd1498Szrj || (flags_from_decl_or_type (node->decl) & ECF_LEAF)))
86338fd1498Szrj {
86438fd1498Szrj node_g = &node_info->global;
86538fd1498Szrj
86638fd1498Szrj opt = XCNEW (struct ipa_reference_optimization_summary_d);
86738fd1498Szrj set_reference_optimization_summary (node, opt);
86838fd1498Szrj
86938fd1498Szrj /* Create the complimentary sets. */
87038fd1498Szrj
87138fd1498Szrj if (bitmap_empty_p (node_g->statics_read))
87238fd1498Szrj opt->statics_not_read = all_module_statics;
87338fd1498Szrj else
87438fd1498Szrj {
87538fd1498Szrj opt->statics_not_read
87638fd1498Szrj = BITMAP_ALLOC (&optimization_summary_obstack);
87738fd1498Szrj if (node_g->statics_read != all_module_statics)
87838fd1498Szrj bitmap_and_compl (opt->statics_not_read,
87938fd1498Szrj all_module_statics,
88038fd1498Szrj node_g->statics_read);
88138fd1498Szrj }
88238fd1498Szrj
88338fd1498Szrj if (bitmap_empty_p (node_g->statics_written))
88438fd1498Szrj opt->statics_not_written = all_module_statics;
88538fd1498Szrj else
88638fd1498Szrj {
88738fd1498Szrj opt->statics_not_written
88838fd1498Szrj = BITMAP_ALLOC (&optimization_summary_obstack);
88938fd1498Szrj if (node_g->statics_written != all_module_statics)
89038fd1498Szrj bitmap_and_compl (opt->statics_not_written,
89138fd1498Szrj all_module_statics,
89238fd1498Szrj node_g->statics_written);
89338fd1498Szrj }
89438fd1498Szrj }
89538fd1498Szrj free (node_info);
89638fd1498Szrj }
89738fd1498Szrj
89838fd1498Szrj ipa_free_postorder_info ();
89938fd1498Szrj free (order);
90038fd1498Szrj
90138fd1498Szrj bitmap_obstack_release (&local_info_obstack);
90238fd1498Szrj ipa_reference_vars_vector.release ();
90338fd1498Szrj if (dump_file)
90438fd1498Szrj splay_tree_delete (reference_vars_to_consider);
90538fd1498Szrj reference_vars_to_consider = NULL;
90638fd1498Szrj return remove_p ? TODO_remove_functions : 0;
90738fd1498Szrj }
90838fd1498Szrj
90938fd1498Szrj /* Return true if we need to write summary of NODE. */
91038fd1498Szrj
91138fd1498Szrj static bool
write_node_summary_p(struct cgraph_node * node,lto_symtab_encoder_t encoder,bitmap ltrans_statics)91238fd1498Szrj write_node_summary_p (struct cgraph_node *node,
91338fd1498Szrj lto_symtab_encoder_t encoder,
91438fd1498Szrj bitmap ltrans_statics)
91538fd1498Szrj {
91638fd1498Szrj ipa_reference_optimization_summary_t info;
91738fd1498Szrj
91838fd1498Szrj /* See if we have (non-empty) info. */
91938fd1498Szrj if (!node->definition || node->global.inlined_to)
92038fd1498Szrj return false;
92138fd1498Szrj info = get_reference_optimization_summary (node);
92238fd1498Szrj if (!info || (bitmap_empty_p (info->statics_not_read)
92338fd1498Szrj && bitmap_empty_p (info->statics_not_written)))
92438fd1498Szrj return false;
92538fd1498Szrj
92638fd1498Szrj /* See if we want to encode it.
92738fd1498Szrj Encode also referenced functions since constant folding might turn it into
92838fd1498Szrj a direct call.
92938fd1498Szrj
93038fd1498Szrj In future we might also want to include summaries of functions references
93138fd1498Szrj by initializers of constant variables references in current unit. */
93238fd1498Szrj if (!reachable_from_this_partition_p (node, encoder)
93338fd1498Szrj && !referenced_from_this_partition_p (node, encoder))
93438fd1498Szrj return false;
93538fd1498Szrj
93638fd1498Szrj /* See if the info has non-empty intersections with vars we want to encode. */
93738fd1498Szrj if (!bitmap_intersect_p (info->statics_not_read, ltrans_statics)
93838fd1498Szrj && !bitmap_intersect_p (info->statics_not_written, ltrans_statics))
93938fd1498Szrj return false;
94038fd1498Szrj return true;
94138fd1498Szrj }
94238fd1498Szrj
94338fd1498Szrj /* Stream out BITS<RANS_STATICS as list of decls to OB.
94438fd1498Szrj LTRANS_STATICS_BITCOUNT specify number of bits in LTRANS_STATICS
94538fd1498Szrj or -1. When it is positive, just output -1 when
94638fd1498Szrj BITS<RANS_STATICS == BITS<RANS_STATICS. */
94738fd1498Szrj
94838fd1498Szrj static void
stream_out_bitmap(struct lto_simple_output_block * ob,bitmap bits,bitmap ltrans_statics,int ltrans_statics_bitcount)94938fd1498Szrj stream_out_bitmap (struct lto_simple_output_block *ob,
95038fd1498Szrj bitmap bits, bitmap ltrans_statics,
95138fd1498Szrj int ltrans_statics_bitcount)
95238fd1498Szrj {
95338fd1498Szrj int count = 0;
95438fd1498Szrj unsigned int index;
95538fd1498Szrj bitmap_iterator bi;
95638fd1498Szrj if (bits == all_module_statics)
95738fd1498Szrj {
95838fd1498Szrj streamer_write_hwi_stream (ob->main_stream, -1);
95938fd1498Szrj return;
96038fd1498Szrj }
96138fd1498Szrj EXECUTE_IF_AND_IN_BITMAP (bits, ltrans_statics, 0, index, bi)
96238fd1498Szrj count ++;
96338fd1498Szrj if (count == ltrans_statics_bitcount)
96438fd1498Szrj {
96538fd1498Szrj streamer_write_hwi_stream (ob->main_stream, -1);
96638fd1498Szrj return;
96738fd1498Szrj }
96838fd1498Szrj streamer_write_hwi_stream (ob->main_stream, count);
96938fd1498Szrj if (!count)
97038fd1498Szrj return;
97138fd1498Szrj EXECUTE_IF_AND_IN_BITMAP (bits, ltrans_statics, 0, index, bi)
97238fd1498Szrj {
97338fd1498Szrj tree decl = (tree)splay_tree_lookup (reference_vars_to_consider, index)->value;
97438fd1498Szrj lto_output_var_decl_index (ob->decl_state, ob->main_stream, decl);
97538fd1498Szrj }
97638fd1498Szrj }
97738fd1498Szrj
97838fd1498Szrj /* Serialize the ipa info for lto. */
97938fd1498Szrj
98038fd1498Szrj static void
ipa_reference_write_optimization_summary(void)98138fd1498Szrj ipa_reference_write_optimization_summary (void)
98238fd1498Szrj {
98338fd1498Szrj struct lto_simple_output_block *ob
98438fd1498Szrj = lto_create_simple_output_block (LTO_section_ipa_reference);
98538fd1498Szrj unsigned int count = 0;
98638fd1498Szrj int ltrans_statics_bitcount = 0;
98738fd1498Szrj lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
98838fd1498Szrj auto_bitmap ltrans_statics;
98938fd1498Szrj int i;
99038fd1498Szrj
99138fd1498Szrj reference_vars_to_consider = splay_tree_new (splay_tree_compare_ints, 0, 0);
99238fd1498Szrj
99338fd1498Szrj /* See what variables we are interested in. */
99438fd1498Szrj for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
99538fd1498Szrj {
99638fd1498Szrj symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
99738fd1498Szrj varpool_node *vnode = dyn_cast <varpool_node *> (snode);
99838fd1498Szrj if (vnode
99938fd1498Szrj && bitmap_bit_p (all_module_statics,
100038fd1498Szrj ipa_reference_var_uid (vnode->decl))
100138fd1498Szrj && referenced_from_this_partition_p (vnode, encoder))
100238fd1498Szrj {
100338fd1498Szrj tree decl = vnode->decl;
100438fd1498Szrj bitmap_set_bit (ltrans_statics, ipa_reference_var_uid (decl));
100538fd1498Szrj splay_tree_insert (reference_vars_to_consider,
100638fd1498Szrj ipa_reference_var_uid (decl),
100738fd1498Szrj (splay_tree_value)decl);
100838fd1498Szrj ltrans_statics_bitcount ++;
100938fd1498Szrj }
101038fd1498Szrj }
101138fd1498Szrj
101238fd1498Szrj
101338fd1498Szrj if (ltrans_statics_bitcount)
101438fd1498Szrj for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
101538fd1498Szrj {
101638fd1498Szrj symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
101738fd1498Szrj cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
101838fd1498Szrj if (cnode && write_node_summary_p (cnode, encoder, ltrans_statics))
101938fd1498Szrj count++;
102038fd1498Szrj }
102138fd1498Szrj
102238fd1498Szrj streamer_write_uhwi_stream (ob->main_stream, count);
102338fd1498Szrj if (count)
102438fd1498Szrj stream_out_bitmap (ob, ltrans_statics, ltrans_statics,
102538fd1498Szrj -1);
102638fd1498Szrj
102738fd1498Szrj /* Process all of the functions. */
102838fd1498Szrj if (ltrans_statics_bitcount)
102938fd1498Szrj for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
103038fd1498Szrj {
103138fd1498Szrj symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
103238fd1498Szrj cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
103338fd1498Szrj if (cnode && write_node_summary_p (cnode, encoder, ltrans_statics))
103438fd1498Szrj {
103538fd1498Szrj ipa_reference_optimization_summary_t info;
103638fd1498Szrj int node_ref;
103738fd1498Szrj
103838fd1498Szrj info = get_reference_optimization_summary (cnode);
103938fd1498Szrj node_ref = lto_symtab_encoder_encode (encoder, snode);
104038fd1498Szrj streamer_write_uhwi_stream (ob->main_stream, node_ref);
104138fd1498Szrj
104238fd1498Szrj stream_out_bitmap (ob, info->statics_not_read, ltrans_statics,
104338fd1498Szrj ltrans_statics_bitcount);
104438fd1498Szrj stream_out_bitmap (ob, info->statics_not_written, ltrans_statics,
104538fd1498Szrj ltrans_statics_bitcount);
104638fd1498Szrj }
104738fd1498Szrj }
104838fd1498Szrj lto_destroy_simple_output_block (ob);
104938fd1498Szrj splay_tree_delete (reference_vars_to_consider);
105038fd1498Szrj }
105138fd1498Szrj
105238fd1498Szrj /* Deserialize the ipa info for lto. */
105338fd1498Szrj
105438fd1498Szrj static void
ipa_reference_read_optimization_summary(void)105538fd1498Szrj ipa_reference_read_optimization_summary (void)
105638fd1498Szrj {
105738fd1498Szrj struct lto_file_decl_data ** file_data_vec
105838fd1498Szrj = lto_get_file_decl_data ();
105938fd1498Szrj struct lto_file_decl_data * file_data;
106038fd1498Szrj unsigned int j = 0;
106138fd1498Szrj bitmap_obstack_initialize (&optimization_summary_obstack);
106238fd1498Szrj
106338fd1498Szrj node_removal_hook_holder =
106438fd1498Szrj symtab->add_cgraph_removal_hook (&remove_node_data, NULL);
106538fd1498Szrj node_duplication_hook_holder =
106638fd1498Szrj symtab->add_cgraph_duplication_hook (&duplicate_node_data, NULL);
106738fd1498Szrj all_module_statics = BITMAP_ALLOC (&optimization_summary_obstack);
106838fd1498Szrj
106938fd1498Szrj while ((file_data = file_data_vec[j++]))
107038fd1498Szrj {
107138fd1498Szrj const char *data;
107238fd1498Szrj size_t len;
107338fd1498Szrj struct lto_input_block *ib
107438fd1498Szrj = lto_create_simple_input_block (file_data,
107538fd1498Szrj LTO_section_ipa_reference,
107638fd1498Szrj &data, &len);
107738fd1498Szrj if (ib)
107838fd1498Szrj {
107938fd1498Szrj unsigned int i;
108038fd1498Szrj unsigned int f_count = streamer_read_uhwi (ib);
108138fd1498Szrj int b_count;
108238fd1498Szrj if (!f_count)
108338fd1498Szrj continue;
108438fd1498Szrj b_count = streamer_read_hwi (ib);
108538fd1498Szrj if (dump_file)
108638fd1498Szrj fprintf (dump_file, "all module statics:");
108738fd1498Szrj for (i = 0; i < (unsigned int)b_count; i++)
108838fd1498Szrj {
108938fd1498Szrj unsigned int var_index = streamer_read_uhwi (ib);
109038fd1498Szrj tree v_decl = lto_file_decl_data_get_var_decl (file_data,
109138fd1498Szrj var_index);
109238fd1498Szrj bitmap_set_bit (all_module_statics,
109338fd1498Szrj ipa_reference_var_uid (v_decl));
109438fd1498Szrj if (dump_file)
109538fd1498Szrj fprintf (dump_file, " %s", fndecl_name (v_decl));
109638fd1498Szrj }
109738fd1498Szrj
109838fd1498Szrj for (i = 0; i < f_count; i++)
109938fd1498Szrj {
110038fd1498Szrj unsigned int j, index;
110138fd1498Szrj struct cgraph_node *node;
110238fd1498Szrj ipa_reference_optimization_summary_t info;
110338fd1498Szrj int v_count;
110438fd1498Szrj lto_symtab_encoder_t encoder;
110538fd1498Szrj
110638fd1498Szrj index = streamer_read_uhwi (ib);
110738fd1498Szrj encoder = file_data->symtab_node_encoder;
110838fd1498Szrj node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref
110938fd1498Szrj (encoder, index));
111038fd1498Szrj info = XCNEW (struct ipa_reference_optimization_summary_d);
111138fd1498Szrj set_reference_optimization_summary (node, info);
111238fd1498Szrj info->statics_not_read = BITMAP_ALLOC (&optimization_summary_obstack);
111338fd1498Szrj info->statics_not_written = BITMAP_ALLOC (&optimization_summary_obstack);
111438fd1498Szrj if (dump_file)
111538fd1498Szrj fprintf (dump_file,
111638fd1498Szrj "\nFunction name:%s:\n static not read:",
111738fd1498Szrj node->dump_asm_name ());
111838fd1498Szrj
111938fd1498Szrj /* Set the statics not read. */
112038fd1498Szrj v_count = streamer_read_hwi (ib);
112138fd1498Szrj if (v_count == -1)
112238fd1498Szrj {
112338fd1498Szrj info->statics_not_read = all_module_statics;
112438fd1498Szrj if (dump_file)
112538fd1498Szrj fprintf (dump_file, " all module statics");
112638fd1498Szrj }
112738fd1498Szrj else
112838fd1498Szrj for (j = 0; j < (unsigned int)v_count; j++)
112938fd1498Szrj {
113038fd1498Szrj unsigned int var_index = streamer_read_uhwi (ib);
113138fd1498Szrj tree v_decl = lto_file_decl_data_get_var_decl (file_data,
113238fd1498Szrj var_index);
113338fd1498Szrj bitmap_set_bit (info->statics_not_read,
113438fd1498Szrj ipa_reference_var_uid (v_decl));
113538fd1498Szrj if (dump_file)
113638fd1498Szrj fprintf (dump_file, " %s", fndecl_name (v_decl));
113738fd1498Szrj }
113838fd1498Szrj
113938fd1498Szrj if (dump_file)
114038fd1498Szrj fprintf (dump_file,
114138fd1498Szrj "\n static not written:");
114238fd1498Szrj /* Set the statics not written. */
114338fd1498Szrj v_count = streamer_read_hwi (ib);
114438fd1498Szrj if (v_count == -1)
114538fd1498Szrj {
114638fd1498Szrj info->statics_not_written = all_module_statics;
114738fd1498Szrj if (dump_file)
114838fd1498Szrj fprintf (dump_file, " all module statics");
114938fd1498Szrj }
115038fd1498Szrj else
115138fd1498Szrj for (j = 0; j < (unsigned int)v_count; j++)
115238fd1498Szrj {
115338fd1498Szrj unsigned int var_index = streamer_read_uhwi (ib);
115438fd1498Szrj tree v_decl = lto_file_decl_data_get_var_decl (file_data,
115538fd1498Szrj var_index);
115638fd1498Szrj bitmap_set_bit (info->statics_not_written,
115738fd1498Szrj ipa_reference_var_uid (v_decl));
115838fd1498Szrj if (dump_file)
115938fd1498Szrj fprintf (dump_file, " %s", fndecl_name (v_decl));
116038fd1498Szrj }
116138fd1498Szrj if (dump_file)
116238fd1498Szrj fprintf (dump_file, "\n");
116338fd1498Szrj }
116438fd1498Szrj
116538fd1498Szrj lto_destroy_simple_input_block (file_data,
116638fd1498Szrj LTO_section_ipa_reference,
116738fd1498Szrj ib, data, len);
116838fd1498Szrj }
116938fd1498Szrj else
117038fd1498Szrj /* Fatal error here. We do not want to support compiling ltrans units with
117138fd1498Szrj different version of compiler or different flags than the WPA unit, so
117238fd1498Szrj this should never happen. */
117338fd1498Szrj fatal_error (input_location,
117438fd1498Szrj "ipa reference summary is missing in ltrans unit");
117538fd1498Szrj }
117638fd1498Szrj }
117738fd1498Szrj
117838fd1498Szrj namespace {
117938fd1498Szrj
118038fd1498Szrj const pass_data pass_data_ipa_reference =
118138fd1498Szrj {
118238fd1498Szrj IPA_PASS, /* type */
118338fd1498Szrj "static-var", /* name */
118438fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
118538fd1498Szrj TV_IPA_REFERENCE, /* tv_id */
118638fd1498Szrj 0, /* properties_required */
118738fd1498Szrj 0, /* properties_provided */
118838fd1498Szrj 0, /* properties_destroyed */
118938fd1498Szrj 0, /* todo_flags_start */
119038fd1498Szrj 0, /* todo_flags_finish */
119138fd1498Szrj };
119238fd1498Szrj
119338fd1498Szrj class pass_ipa_reference : public ipa_opt_pass_d
119438fd1498Szrj {
119538fd1498Szrj public:
pass_ipa_reference(gcc::context * ctxt)119638fd1498Szrj pass_ipa_reference (gcc::context *ctxt)
119738fd1498Szrj : ipa_opt_pass_d (pass_data_ipa_reference, ctxt,
119838fd1498Szrj NULL, /* generate_summary */
119938fd1498Szrj NULL, /* write_summary */
120038fd1498Szrj NULL, /* read_summary */
120138fd1498Szrj ipa_reference_write_optimization_summary, /*
120238fd1498Szrj write_optimization_summary */
120338fd1498Szrj ipa_reference_read_optimization_summary, /*
120438fd1498Szrj read_optimization_summary */
120538fd1498Szrj NULL, /* stmt_fixup */
120638fd1498Szrj 0, /* function_transform_todo_flags_start */
120738fd1498Szrj NULL, /* function_transform */
120838fd1498Szrj NULL) /* variable_transform */
120938fd1498Szrj {}
121038fd1498Szrj
121138fd1498Szrj /* opt_pass methods: */
gate(function *)121238fd1498Szrj virtual bool gate (function *)
121338fd1498Szrj {
121438fd1498Szrj return ((in_lto_p || flag_ipa_reference)
121538fd1498Szrj /* Don't bother doing anything if the program has errors. */
121638fd1498Szrj && !seen_error ());
121738fd1498Szrj }
121838fd1498Szrj
execute(function *)121938fd1498Szrj virtual unsigned int execute (function *) { return propagate (); }
122038fd1498Szrj
122138fd1498Szrj }; // class pass_ipa_reference
122238fd1498Szrj
122338fd1498Szrj } // anon namespace
122438fd1498Szrj
122538fd1498Szrj ipa_opt_pass_d *
make_pass_ipa_reference(gcc::context * ctxt)122638fd1498Szrj make_pass_ipa_reference (gcc::context *ctxt)
122738fd1498Szrj {
122838fd1498Szrj return new pass_ipa_reference (ctxt);
122938fd1498Szrj }
123038fd1498Szrj
123138fd1498Szrj /* Reset all state within ipa-reference.c so that we can rerun the compiler
123238fd1498Szrj within the same process. For use by toplev::finalize. */
123338fd1498Szrj
123438fd1498Szrj void
ipa_reference_c_finalize(void)123538fd1498Szrj ipa_reference_c_finalize (void)
123638fd1498Szrj {
123738fd1498Szrj if (ipa_init_p)
123838fd1498Szrj {
123938fd1498Szrj bitmap_obstack_release (&optimization_summary_obstack);
124038fd1498Szrj ipa_init_p = false;
124138fd1498Szrj }
124238fd1498Szrj
124338fd1498Szrj if (node_removal_hook_holder)
124438fd1498Szrj {
124538fd1498Szrj symtab->remove_cgraph_removal_hook (node_removal_hook_holder);
124638fd1498Szrj node_removal_hook_holder = NULL;
124738fd1498Szrj }
124838fd1498Szrj if (node_duplication_hook_holder)
124938fd1498Szrj {
125038fd1498Szrj symtab->remove_cgraph_duplication_hook (node_duplication_hook_holder);
125138fd1498Szrj node_duplication_hook_holder = NULL;
125238fd1498Szrj }
125338fd1498Szrj }
1254