xref: /dflybsd-src/contrib/gcc-8.0/gcc/ipa-reference.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
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&LTRANS_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&LTRANS_STATICS == BITS&LTRANS_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