This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

static vars analysis added to tree-profiling branch.


This code has been tested on i686-linux and power-pc-darwin.

This patch was approved by Jan and has been checked in by me.

2004-11-08 Kenneth Zadeck <Kenneth.Zadeck@NaturalBridge.com>

* Makefile.in (cgraph.h, ipa-static.h, ipa-static-vars-anal.c):
Add dependencies.
* (ipa-static.h, ipa-static-vars-anal.c) : New files to implement
the analysis if compilation wide static variables.
* cgraph.c (cgraph_create_node, cgraph_remove_node
dump_cgraph_node): Now handles master_clone_nodes and ipa_static info.
(cgraph_is_master_clone, cgraph_master_clone,
cgraph_immortal_master_clone): Added.
(cgraph_function_body_availability): Handles inlinable and
overwrittable functions.
* cgraph.h (availablilty):Handles inlinable and
overwrittable functions.
(cgraph_node) Has static vars analyis info.
* cgraph_unit (cgraph_function_and_variable_visibility): Fixed
comments and removed external bit.
* regclass.c (regset_release_memory): removed call to
bitmap_release_memory which does not work with ipa reorganization.
* tree-dfa.c: (find_referenced_vars) Add initialization code for
static vars analysis.
* tree-flow.h: (static_vars_info): Added.
* tree-gimple.c (get_base_var) Added.
* tree.h (get_base_var) Added.
* tree-pass.h (pass_ipa_static) Added.
* tree-sra.c (sra_insert_before, sra_insert_after) Made public.
(sra_type_can_be_decomposed_p) renamed from
type_can_be_decomposed_p and made public.
(sra_init_cache): new.
(tree_sra) Added call to sra_init_cache.
* tree-ssa-operands.c: (get_call_expr_operands,
add_call_clobber_ops, add_call_read_ops) changed to clobber fewer
static variables.
2004-11-08 Kenneth Zadeck <Kenneth.Zadeck@NaturalBridge.com>
* gcc.c-torture/execute/20041007-1.c: New




? gcc/Makefile.in.promote
? gcc/save-tree-promote-statics.c
Index: gcc/Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.903.2.179.2.22
diff -c -3 -p -r1.903.2.179.2.22 Makefile.in
*** gcc/Makefile.in	26 Oct 2004 14:06:40 -0000	1.903.2.179.2.22
--- gcc/Makefile.in	8 Nov 2004 17:34:43 -0000
*************** RA_H = ra.h bitmap.h sbitmap.h hard-reg-
*** 701,709 ****
  RESOURCE_H = resource.h hard-reg-set.h
  SCHED_INT_H = sched-int.h $(INSN_ATTR_H) $(BASIC_BLOCK_H) $(RTL_H)
  INTEGRATE_H = integrate.h varray.h
  CFGLAYOUT_H = cfglayout.h $(BASIC_BLOCK_H)
  CFGLOOP_H = cfgloop.h $(BASIC_BLOCK_H) $(RTL_H)
! CGRAPH_H = cgraph.h tree.h 
  DF_H = df.h bitmap.h sbitmap.h $(BASIC_BLOCK_H)
  DDG_H = ddg.h sbitmap.h $(DF_H)
  GCC_H = gcc.h version.h
--- 701,710 ----
  RESOURCE_H = resource.h hard-reg-set.h
  SCHED_INT_H = sched-int.h $(INSN_ATTR_H) $(BASIC_BLOCK_H) $(RTL_H)
  INTEGRATE_H = integrate.h varray.h
+ IPA_STATIC_H = ipa-static.h bitmap.h $(TREE_H)  
  CFGLAYOUT_H = cfglayout.h $(BASIC_BLOCK_H)
  CFGLOOP_H = cfgloop.h $(BASIC_BLOCK_H) $(RTL_H)
! CGRAPH_H = cgraph.h $(IPA_STATIC_H) 
  DF_H = df.h bitmap.h sbitmap.h $(BASIC_BLOCK_H)
  DDG_H = ddg.h sbitmap.h $(DF_H)
  GCC_H = gcc.h version.h
*************** TREE_DUMP_H = tree-dump.h $(SPLAY_TREE_H
*** 724,730 ****
  TREE_GIMPLE_H = tree-gimple.h tree-iterator.h
  TREE_FLOW_H = tree-flow.h tree-flow-inline.h tree-ssa-operands.h \
  		bitmap.h $(BASIC_BLOCK_H) hard-reg-set.h $(TREE_GIMPLE_H) \
! 		$(HASHTAB_H) $(CGRAPH_H)
  TREE_SSA_LIVE_H = tree-ssa-live.h $(PARTITION_H)
  PRETTY_PRINT_H = pretty-print.h input.h $(OBSTACK_H)
  DIAGNOSTIC_H = diagnostic.h diagnostic.def $(PRETTY_PRINT_H)
--- 725,731 ----
  TREE_GIMPLE_H = tree-gimple.h tree-iterator.h
  TREE_FLOW_H = tree-flow.h tree-flow-inline.h tree-ssa-operands.h \
  		bitmap.h $(BASIC_BLOCK_H) hard-reg-set.h $(TREE_GIMPLE_H) \
! 		$(HASHTAB_H) $(IPA_STATIC_H)
  TREE_SSA_LIVE_H = tree-ssa-live.h $(PARTITION_H)
  PRETTY_PRINT_H = pretty-print.h input.h $(OBSTACK_H)
  DIAGNOSTIC_H = diagnostic.h diagnostic.def $(PRETTY_PRINT_H)
*************** OBJS-common = \
*** 925,935 ****
   varasm.o varray.o vec.o version.o vmsdbgout.o xcoffout.o alloc-pool.o	   \
   et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o	   \
   rtl-profile.o tree-profile.o rtlhooks.o cfgexpand.o lambda-mat.o          \
!  lambda-trans.o	lambda-code.o tree-loop-linear.o
  
  OBJS-md = $(out_object_file)
  OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) tree-inline.o		   \
!   cgraph.o ipa_prop.o cgraphunit.o tree-nomudflap.o
  
  OBJS = $(OBJS-common) $(out_object_file) $(OBJS-archive)
  
--- 926,936 ----
   varasm.o varray.o vec.o version.o vmsdbgout.o xcoffout.o alloc-pool.o	   \
   et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o	   \
   rtl-profile.o tree-profile.o rtlhooks.o cfgexpand.o lambda-mat.o          \
!  lambda-trans.o	lambda-code.o tree-loop-linear.o 
  
  OBJS-md = $(out_object_file)
  OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) tree-inline.o		   \
!   cgraph.o ipa_prop.o ipa-static-vars-anal.o cgraphunit.o tree-nomudflap.o
  
  OBJS = $(OBJS-common) $(out_object_file) $(OBJS-archive)
  
*************** tree-dfa.o : tree-dfa.c $(TREE_FLOW_H) $
*** 1688,1696 ****
     $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h diagnostic.h \
     errors.h tree-inline.h $(HASHTAB_H) pointer-set.h $(FLAGS_H) function.h $(TIMEVAR_H) \
     convert.h $(TM_H) coretypes.h langhooks.h \
!    $(TREE_DUMP_H) tree-pass.h params.h $(CGRAPH_H)
  tree-ssa-operands.o : tree-ssa-operands.c $(TREE_FLOW_H) $(CONFIG_H) \
!    $(SYSTEM_H) $(TREE_H) $(TM_P_H) $(GGC_H) $(CGRAPH_H) diagnostic.h errors.h \
     tree-inline.h $(FLAGS_H) function.h $(TM_H) $(TIMEVAR_H) tree-pass.h
  tree-eh.o : tree-eh.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
     $(RTL_H) $(TREE_H) $(TM_H) $(FLAGS_H) function.h except.h langhooks.h \
--- 1689,1697 ----
     $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h diagnostic.h \
     errors.h tree-inline.h $(HASHTAB_H) pointer-set.h $(FLAGS_H) function.h $(TIMEVAR_H) \
     convert.h $(TM_H) coretypes.h langhooks.h \
!    $(TREE_DUMP_H) tree-pass.h params.h $(IPA_STATIC_H)
  tree-ssa-operands.o : tree-ssa-operands.c $(TREE_FLOW_H) $(CONFIG_H) \
!    $(SYSTEM_H) $(TREE_H) $(TM_P_H) $(GGC_H) $(IPA_STATIC_H) diagnostic.h errors.h \
     tree-inline.h $(FLAGS_H) function.h $(TM_H) $(TIMEVAR_H) tree-pass.h
  tree-eh.o : tree-eh.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
     $(RTL_H) $(TREE_H) $(TM_H) $(FLAGS_H) function.h except.h langhooks.h \
*************** simplify-rtx.o : simplify-rtx.c $(CONFIG
*** 1920,1929 ****
     output.h function.h $(GGC_H) $(OBSTACK_H) $(TM_P_H) $(TREE_H) $(TARGET_H)
  cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
     langhooks.h toplev.h $(FLAGS_H) $(GGC_H)  $(TARGET_H) $(CGRAPH_H) gt-cgraph.h \
!    output.h intl.h
  ipa_prop.o : ipa_prop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
     langhooks.h toplev.h $(FLAGS_H) $(GGC_H)  $(TARGET_H) cgraph.h gt-cgraph.h \
     output.h intl.h ipa_prop.h tree.h tree-iterator.h tree-gimple.h tree-inline.h
  cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
     langhooks.h tree-inline.h toplev.h $(FLAGS_H) $(GGC_H)  $(TARGET_H) $(CGRAPH_H) intl.h \
     pointer-set.h function.h $(TREE_GIMPLE_H) $(TREE_FLOW_H) ipa_prop.h
--- 1921,1934 ----
     output.h function.h $(GGC_H) $(OBSTACK_H) $(TM_P_H) $(TREE_H) $(TARGET_H)
  cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
     langhooks.h toplev.h $(FLAGS_H) $(GGC_H)  $(TARGET_H) $(CGRAPH_H) gt-cgraph.h \
!    output.h intl.h tree-inline.h
  ipa_prop.o : ipa_prop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
     langhooks.h toplev.h $(FLAGS_H) $(GGC_H)  $(TARGET_H) cgraph.h gt-cgraph.h \
     output.h intl.h ipa_prop.h tree.h tree-iterator.h tree-gimple.h tree-inline.h
+ ipa_static-vars-anal.o : ipa-static-vars-anal.c $(CONFIG_H) $(SYSTEM_H) \
+    coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) tree-inline.h langhooks.h \
+    pointer-set.h $(GGC_H) $(IPA_STATIC_H) $(C_COMMON_H) $(TREE_GIMPLE_H) \
+    $(CGRAPH_H) output.h $(FLAGS_H) tree-pass.h  
  cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
     langhooks.h tree-inline.h toplev.h $(FLAGS_H) $(GGC_H)  $(TARGET_H) $(CGRAPH_H) intl.h \
     pointer-set.h function.h $(TREE_GIMPLE_H) $(TREE_FLOW_H) ipa_prop.h
*************** insn-preds.o : insn-preds.c $(CONFIG_H) 
*** 2404,2409 ****
--- 2409,2415 ----
  GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \
    $(CPP_ID_DATA_H) $(host_xm_file_list) \
    $(tm_file_list) $(HASHTAB_H) $(SPLAY_TREE_H) $(srcdir)/bitmap.h \
+   $(srcdir)/ipa-static.h \
    $(srcdir)/coverage.c $(srcdir)/function.h $(srcdir)/rtl.h \
    $(srcdir)/optabs.h $(srcdir)/tree.h $(srcdir)/libfuncs.h $(SYMTAB_H) \
    $(srcdir)/real.h $(srcdir)/varray.h $(srcdir)/insn-addr.h $(srcdir)/hwint.h \
*************** GTFILES = $(srcdir)/input.h $(srcdir)/co
*** 2429,2434 ****
--- 2435,2441 ----
    $(srcdir)/tree-chrec.h \
    $(srcdir)/tree-ssa-operands.h $(srcdir)/tree-ssa-operands.c \
    $(srcdir)/tree-profile.c $(srcdir)/rtl-profile.c $(srcdir)/tree-nested.c \
+   $(srcdir)/ipa-static-vars-anal.c \
    $(out_file) \
    @all_gtfiles@
  
Index: gcc/cgraph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v
retrieving revision 1.4.4.18.2.13
diff -c -3 -p -r1.4.4.18.2.13 cgraph.c
*** gcc/cgraph.c	2 Nov 2004 16:43:19 -0000	1.4.4.18.2.13
--- gcc/cgraph.c	8 Nov 2004 17:34:43 -0000
*************** The varpool data structure:
*** 84,89 ****
--- 84,90 ----
  #include "coretypes.h"
  #include "tm.h"
  #include "tree.h"
+ #include "tree-inline.h"
  #include "langhooks.h"
  #include "hashtab.h"
  #include "toplev.h"
*************** cgraph_create_node (void)
*** 163,168 ****
--- 164,170 ----
    if (cgraph_nodes)
      cgraph_nodes->previous = node;
    node->previous = NULL;
+   node->static_vars_info = NULL;
    cgraph_nodes = node;
    cgraph_n_nodes++;
    return node;
*************** cgraph_node (tree decl)
*** 184,190 ****
    slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT);
  
    if (*slot)
!     return *slot;
  
    node = cgraph_create_node ();
    node->decl = decl;
--- 186,197 ----
    slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT);
  
    if (*slot)
!     {
!       node = *slot;
!       if (!node->master_clone)
! 	node->master_clone = node;
!       return node;
!     }
  
    node = cgraph_create_node ();
    node->decl = decl;
*************** cgraph_node (tree decl)
*** 194,199 ****
--- 201,207 ----
        node->origin = cgraph_node (DECL_CONTEXT (decl));
        node->next_nested = node->origin->nested;
        node->origin->nested = node;
+       node->master_clone = node;
      }
    return node;
  }
*************** cgraph_remove_node (struct cgraph_node *
*** 316,328 ****
      node->previous->next = node->next;
    else
      cgraph_nodes = node->next;
    if (node->next)
      node->next->previous = node->previous;
    slot = htab_find_slot (cgraph_hash, node, NO_INSERT);
    if (*slot == node)
      {
        if (node->next_clone)
! 	*slot = node->next_clone;
        else
  	{
            htab_clear_slot (cgraph_hash, slot);
--- 324,347 ----
      node->previous->next = node->next;
    else
      cgraph_nodes = node->next;
+ 
    if (node->next)
      node->next->previous = node->previous;
    slot = htab_find_slot (cgraph_hash, node, NO_INSERT);
    if (*slot == node)
      {
        if (node->next_clone)
! 	{
! 	  struct cgraph_node *new_node = node->next_clone;
! 	  struct cgraph_node *n;
! 	  *slot = new_node;
! 	  
! 	  /* Make the next clone be the master clone */
! 	  for (n = new_node; n; n = n->next_clone) 
! 	    n->master_clone = new_node;
! 	
! 	  new_node->master_clone = new_node;
! 	}
        else
  	{
            htab_clear_slot (cgraph_hash, slot);
*************** cgraph_varpool_node_name (struct cgraph_
*** 461,478 ****
  static const char * const availability_names[] = 
    {"not_available", "overwrittable", "available", "local"};
  
  /* Dump given cgraph node.  */
  void
  dump_cgraph_node (FILE *f, struct cgraph_node *node)
  {
    struct cgraph_edge *edge;
  
    fprintf (f, "%s/%i:", cgraph_node_name (node), node->uid);
    if (node->global.inlined_to)
      fprintf (f, " (inline copy in %s/%i)",
  	     cgraph_node_name (node->global.inlined_to),
  	     node->global.inlined_to->uid);
!   fprintf (f, " availability:%s", availability_names [cgraph_function_body_availability (node)]);
    if (node->local.self_insns)
      fprintf (f, " %i insns", node->local.self_insns);
    if (node->local.self_insns)
--- 480,512 ----
  static const char * const availability_names[] = 
    {"not_available", "overwrittable", "available", "local"};
  
+ /* Return name of the node used in debug output.  */
+ static const char *
+ cgraph_varpool_node_name (struct cgraph_varpool_node *node)
+ {
+   return lang_hooks.decl_printable_name (node->decl, 2);
+ }
+ 
+ /* Names used to print out the availability enum.  */
+ static const char * const availability_names[] = 
+   {"not_available", "overwrittable", "available", "local"};
+ 
  /* Dump given cgraph node.  */
  void
  dump_cgraph_node (FILE *f, struct cgraph_node *node)
  {
+   struct cgraph_node *n;
    struct cgraph_edge *edge;
  
    fprintf (f, "%s/%i:", cgraph_node_name (node), node->uid);
+   if (node->master_clone && node->master_clone->uid != node->uid)
+     fprintf (f, "(%i)", node->master_clone->uid);
    if (node->global.inlined_to)
      fprintf (f, " (inline copy in %s/%i)",
  	     cgraph_node_name (node->global.inlined_to),
  	     node->global.inlined_to->uid);
!   fprintf (f, " availability:%s", 
! 	   availability_names [cgraph_function_body_availability (node)]);
    if (node->local.self_insns)
      fprintf (f, " %i insns", node->local.self_insns);
    if (node->local.self_insns)
*************** dump_cgraph_node (FILE *f, struct cgraph
*** 491,500 ****
--- 525,544 ----
      fprintf (f, " output");
    if (node->local.local)
      fprintf (f, " local");
+   if (node->local.externally_visible)
+     fprintf (f, " externally_visible");
+   if (node->local.finalized)
+     fprintf (f, " finalized");
+   if (node->local.calls_read_all)
+     fprintf (f, " calls_read_all");
+   if (node->local.calls_write_all)
+     fprintf (f, " calls_write_all");
    if (node->local.disregard_inline_limits)
      fprintf (f, " always_inline");
    else if (node->local.inlinable)
      fprintf (f, " inlinable");
+   if (node->local.redefined_extern_inline)
+     fprintf (f, " redefined_extern_inline");
    if (TREE_ASM_WRITTEN (node->decl))
      fprintf (f, " asm_written");
  
*************** dump_cgraph_node (FILE *f, struct cgraph
*** 515,520 ****
--- 559,568 ----
        if (!edge->inline_failed)
  	fprintf(f, "(inlined) ");
      }
+   fprintf (f, "\n  cycle: ");
+   n = node->next_cycle;
+   while (n)
+     fprintf (f, "%s/%i ", cgraph_node_name (n), n->uid);
    fprintf (f, "\n");
  }
  /* Dump the callgraph.  */
*************** cgraph_clone_node (struct cgraph_node *n
*** 758,766 ****
--- 806,816 ----
        new->origin->nested = new;
      }
    new->analyzed = n->analyzed;
+   new->static_vars_info = n->static_vars_info;
    new->local = n->local;
    new->global = n->global;
    new->rtl = n->rtl;
+   new->master_clone = n->master_clone;
  
    for (e = n->callees;e; e=e->next_callee)
      cgraph_clone_edge (e, new, e->call_expr);
*************** cgraph_clone_node (struct cgraph_node *n
*** 771,776 ****
--- 821,887 ----
    return new;
  }
  
+ /* Return true if N is an master_clone, (see cgraph_master_clone).  */
+ 
+ bool
+ cgraph_is_master_clone (struct cgraph_node *n)
+ {
+   return (n == cgraph_master_clone (n));
+ }
+ 
+ /* Return true if N is an immortal_master_clone, (see
+    cgraph_immortal_master_clone).  */
+ 
+ bool
+ cgraph_is_immortal_master_clone (struct cgraph_node *n)
+ {
+   return (n == cgraph_immortal_master_clone (n));
+ }
+ 
+ /* Return pointer to the callgraph node presenting master clone of N.
+    For functions defined outside the compilation unit, NULL is
+    returned.  For inline functions that have no out of line clone to
+    be output this the choice of which is the master is random and this
+    node will not exist after inlining has happened.  For inline
+    functions that do have an out of line clone to be output, the
+    master clone is a cgraph node that will not be released before any
+    of the clones.  */
+ 
+ struct cgraph_node *
+ cgraph_master_clone (struct cgraph_node *n)
+ {
+   enum availability avail = cgraph_function_body_availability (n);
+    
+   if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITTABLE)
+     return NULL;
+ 
+   if (!n->master_clone) 
+     n->master_clone = cgraph_node (n->decl);
+   
+   return n->master_clone;
+ }
+ 
+ /* Return pointer to the callgraph node presenting immortal master
+    clone of N, if one exists, NULL otherwise.  The immortal master
+    clone is a cgraph node that will not be released before any of the
+    clones and thus it is usefull for holding information about
+    function body that is the same for all clones.  Inline functions
+    that have no out of line clone to be output have a master node that
+    is not immortal.  For functions defined outside the compilation
+    unit, NULL is returned.  */
+ 
+ struct cgraph_node *
+ cgraph_immortal_master_clone (struct cgraph_node *n)
+ {
+   struct cgraph_node *master = cgraph_master_clone (n);
+   if (!master) 
+     return NULL;
+ 
+   if (master->global.inlined_to)
+     return NULL;
+   return master;
+ }
+ 
  /* NODE is no longer nested function; update cgraph accordingly.  */
  void
  cgraph_unnest_node (struct cgraph_node *node)
*************** cgraph_unnest_node (struct cgraph_node *
*** 789,817 ****
  enum availability
  cgraph_function_body_availability (struct cgraph_node *node)
  {
!   if (!node->local.finalized)
!     return AVAIL_NOT_AVAILABLE;
!   if (node->local.local)
!     return AVAIL_LOCAL;
!   if (!node->local.externally_visible)
!     return AVAIL_AVAILABLE;
!   /* If the function can be overwritted, return OVERWRITTABLE.  Take care
!      at least of two notable extensions - the COMDAT functions used to share
!      template instantiations in C++ (this is symmetric to code
!      cp_cannot_inline_tree_fn and probably shall be shared and the inlinability
!      hooks completelly elliminated).
!      ??? Does C++ one definition rule allow us to always return AVAIL_AVAILABLE
!      here?  That would be good reason to preserve this hook
!      Similarly deal with extern inline functions - this is aggain neccesary to
!      get C++ shared functions having keyed templates right and in the C
!      extension documentation we probably should document the requirement of
!      both versions of function (extern inline and offline) having same side
!      effect characteristics as good optimization is what this optimization
!      is about.  */
!   if (!(*targetm.binds_local_p) (node->decl)
!       && !DECL_COMDAT (node->decl) && !DECL_EXTERNAL (node->decl))
!     return AVAIL_OVERWRITTABLE;
!   return AVAIL_AVAILABLE;
  }
  
  /* Return variable availability.  See cgraph.h for description of individual
--- 900,940 ----
  enum availability
  cgraph_function_body_availability (struct cgraph_node *node)
  {
!   enum availability avail = node->local.avail;
! 
!   if (avail != AVAIL_UNSET)
!     return avail;
!   else if (!node->local.finalized)
!     avail = AVAIL_NOT_AVAILABLE;
!   else if (node->local.local)
!     avail = AVAIL_LOCAL;
!   else if (!node->local.externally_visible)
!     avail = AVAIL_AVAILABLE;
! 
!   /* If the function can be overwritten, return OVERWRITTABLE.  Take
!      care at least of two notable extensions - the COMDAT functions
!      used to share template instantiations in C++ (this is symmetric
!      to code cp_cannot_inline_tree_fn and probably shall be shared and
!      the inlinability hooks completelly elliminated).
! 
!      ??? Does the C++ one definition rule allow us to always return
!      AVAIL_AVAILABLE here?  That would be good reason to preserve this
!      hook Similarly deal with extern inline functions - this is again
!      neccesary to get C++ shared functions having keyed templates
!      right and in the C extension documentation we probably should
!      document the requirement of both versions of function (extern
!      inline and offline) having same side effect characteristics as
!      good optimization is what this optimization is about.  */
!   
!   else if (!(*targetm.binds_local_p) (node->decl)
! 	   && !DECL_COMDAT (node->decl) && !DECL_EXTERNAL (node->decl))
!     if (tree_inlinable_function_p (node->decl))
!       avail = AVAIL_OVERWRITTABLE_BUT_INLINABLE;
!     else 
!       avail = AVAIL_OVERWRITTABLE;
!   else avail = AVAIL_AVAILABLE;
!   node->local.avail = avail;
!   return avail;
  }
  
  /* Return variable availability.  See cgraph.h for description of individual
*************** cgraph_variable_initializer_availability
*** 823,831 ****
      return AVAIL_NOT_AVAILABLE;
    if (!TREE_PUBLIC (node->decl))
      return AVAIL_AVAILABLE;
!   /* If the variable can be overwritted, return OVERWRITTABLE.  Take care
!      at least of two notable extensions - the COMDAT variables used to share
!      template instantiations in C++.  */
    if (!(*targetm.binds_local_p) (node->decl) && !DECL_COMDAT (node->decl))
      return AVAIL_OVERWRITTABLE;
    return AVAIL_AVAILABLE;
--- 946,954 ----
      return AVAIL_NOT_AVAILABLE;
    if (!TREE_PUBLIC (node->decl))
      return AVAIL_AVAILABLE;
!   /* If the variable can be overwritted, return OVERWRITTABLE.  Takes
!      care of at least two notable extensions - the COMDAT variables
!      used to share template instantiations in C++.  */
    if (!(*targetm.binds_local_p) (node->decl) && !DECL_COMDAT (node->decl))
      return AVAIL_OVERWRITTABLE;
    return AVAIL_AVAILABLE;
Index: gcc/cgraph.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.h,v
retrieving revision 1.1.4.16.2.11
diff -c -3 -p -r1.1.4.16.2.11 cgraph.h
*** gcc/cgraph.h	2 Nov 2004 16:43:19 -0000	1.1.4.16.2.11
--- gcc/cgraph.h	8 Nov 2004 17:34:44 -0000
*************** Software Foundation, 59 Temple Place - S
*** 21,33 ****
  
  #ifndef GCC_CGRAPH_H
  #define GCC_CGRAPH_H
! #include "tree.h"
  
  /* Information about the function collected locally.
     Available after function is analyzed.  */
  
  struct cgraph_local_info GTY(())
  {
    /* Size of the function before inlining.  */
    int self_insns;
  
--- 21,59 ----
  
  #ifndef GCC_CGRAPH_H
  #define GCC_CGRAPH_H
! #include "ipa-static.h"
! 
! enum availability
! {
!   /* Not yet set by cgraph_function_body_availability.  */
!   AVAIL_UNSET,
!   /* Function body/variable initializer is unknown.  */
!   AVAIL_NOT_AVAILABLE,
!   /* Function body/variable initializer is known but might be replaced
!      by a different one from other compilation unit and thus can be
!      dealt with only as a hint.  */
!   AVAIL_OVERWRITTABLE,
!   /* Same as AVAIL_OVERWRITTABLE except the front end has said that
!      this instance is stable enough to analyze or even inline.  */
!   AVAIL_OVERWRITTABLE_BUT_INLINABLE,
!   /* Function body/variable initializer is known and will be used in final
!      program.  */
!   AVAIL_AVAILABLE,
!   /* Function body/variable initializer is known and all it's uses are explicitly
!      visible within current unit (ie it's address is never taken and it is not
!      exported to other units).
!      Currently used only for functions.  */
!   AVAIL_LOCAL
! };
  
  /* Information about the function collected locally.
     Available after function is analyzed.  */
  
  struct cgraph_local_info GTY(())
  {
+   /* Cached version of cgraph_function_body_availability.  */
+   enum availability avail;
+ 
    /* Size of the function before inlining.  */
    int self_insns;
  
*************** struct cgraph_local_info GTY(())
*** 38,43 ****
--- 64,77 ----
    /* Set when function is visible by other units.  */
    bool externally_visible;
  
+   /* Set when this function calls another function external to the
+      compilation unit or if the function has a asm clobber of memory.
+      In general, such calls are modeled as reading and writing all
+      variables (both bits on) but sometime there are attributes on the
+      called function so we can do better.  */
+   bool calls_read_all;
+   bool calls_write_all;
+ 
    /* Set once it has been finalized so we consider it to be output.  */
    bool finalized;
  
*************** struct cgraph_local_info GTY(())
*** 50,59 ****
    /* True when the function has been originally extern inline, but it is
       redefined now.  */
    bool redefined_extern_inline;
- 
-   /* True if statics_read_for_function and
-      statics_written_for_function contain valid data.  */
-   bool for_functions_valid;
  };
  
  /* Information about the function that needs to be computed globally
--- 84,89 ----
*************** struct cgraph_node GTY((chain_next ("%h.
*** 101,112 ****
--- 131,152 ----
    struct cgraph_node *next_needed;
    /* Pointer to the next clone.  */
    struct cgraph_node *next_clone;
+   /* Pointer to next node in a recursive call graph cycle; */
+   struct cgraph_node *next_cycle;
+   /* Pointer to a single unique cgraph node for this function.  If the
+      function is to be output, this is the copy that will survive.  */
+   struct cgraph_node *master_clone;
+ 
    PTR GTY ((skip)) aux;
  
    struct cgraph_local_info local;
    struct cgraph_global_info global;
    struct cgraph_rtl_info rtl;
    
+   /* Pointer to the structure that contains the sets of global
+      variables modified by function calls.  */
+   ipa_static_vars_info_t GTY ((skip)) static_vars_info;
+ 
    /* Unique id of the node.  */
    int uid;
    /* Set when function must be output - it is externally visible
*************** bool cgraph_function_possibly_inlined_p 
*** 216,221 ****
--- 256,265 ----
  void cgraph_unnest_node (struct cgraph_node *);
  enum availability cgraph_function_body_availability (struct cgraph_node *);
  enum availability cgraph_variable_initializer_availability (struct cgraph_varpool_node *);
+ bool cgraph_is_master_clone (struct cgraph_node *);
+ bool cgraph_is_immortal_master_clone (struct cgraph_node *);
+ struct cgraph_node *cgraph_master_clone (struct cgraph_node *);
+ struct cgraph_node *cgraph_immortal_master_clone (struct cgraph_node *);
  
  /* In cgraphunit.c  */
  bool cgraph_assemble_pending_functions (void);
Index: gcc/cgraphunit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraphunit.c,v
retrieving revision 1.1.4.35.2.24
diff -c -3 -p -r1.1.4.35.2.24 cgraphunit.c
*** gcc/cgraphunit.c	2 Nov 2004 16:43:19 -0000	1.1.4.35.2.24
--- gcc/cgraphunit.c	8 Nov 2004 17:34:44 -0000
*************** cgraph_expand_all_functions (void)
*** 1860,1875 ****
    free (order);
  }
  
! /* Mark all local and external functions.
     
     A local function is one whose calls can occur only in the current
     compilation unit and all its calls are explicit, so we can change
     its calling convention.  We simply mark all static functions whose
     address is not taken as local.
  
-    An external function is one whose body is outside the current
-    compilation unit.  
-    
     We also change the TREE_PUBLIC flag of all declarations that are public
     in language point of view but we want to overwrite this default
     via -fwhole-program for the backend point of view.  */
--- 1860,1872 ----
    free (order);
  }
  
! /* Mark visibility of all functions.
     
     A local function is one whose calls can occur only in the current
     compilation unit and all its calls are explicit, so we can change
     its calling convention.  We simply mark all static functions whose
     address is not taken as local.
  
     We also change the TREE_PUBLIC flag of all declarations that are public
     in language point of view but we want to overwrite this default
     via -fwhole-program for the backend point of view.  */
*************** cgraph_function_and_variable_visibility 
*** 1910,1921 ****
  	}
      }
  
!   /* Because we have to be conservative on the boundaries of source level units,
!      it is possible that we marked some functions in reachable just because they
!      might be used later via external linkage, but after making them local they
!      are really unreachable now.  */
    if (flag_whole_program)
      cgraph_remove_unreachable_nodes (true);
    if (cgraph_dump_file)
      {
        fprintf (cgraph_dump_file, "\nMarking local functions:");
--- 1907,1920 ----
  	}
      }
  
!   /* Because we have to be conservative on the boundaries of source
!      level units, it is possible that we marked some functions in
!      reachable just because they might be used later via external
!      linkage, but after making them local they are really unreachable
!      now.  */
    if (flag_whole_program)
      cgraph_remove_unreachable_nodes (true);
+ 
    if (cgraph_dump_file)
      {
        fprintf (cgraph_dump_file, "\nMarking local functions:");
*************** cgraph_function_and_variable_visibility 
*** 1923,1928 ****
--- 1922,1932 ----
  	if (node->local.local)
  	  fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
        fprintf (cgraph_dump_file, "\n\n");
+       fprintf (cgraph_dump_file, "\nMarking externally visible functions:");
+       for (node = cgraph_nodes; node; node = node->next)
+ 	if (node->local.externally_visible)
+ 	  fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
+       fprintf (cgraph_dump_file, "\n\n");
      }
  }
  
Index: gcc/regclass.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/regclass.c,v
retrieving revision 1.152.2.19.2.7
diff -c -3 -p -r1.152.2.19.2.7 regclass.c
*** gcc/regclass.c	17 Oct 2004 18:30:50 -0000	1.152.2.19.2.7
--- gcc/regclass.c	8 Nov 2004 17:34:45 -0000
*************** reg_classes_intersect_p (enum reg_class 
*** 2588,2594 ****
  void
  regset_release_memory (void)
  {
!   bitmap_release_memory ();
  }
  
  #ifdef CANNOT_CHANGE_MODE_CLASS
--- 2588,2594 ----
  void
  regset_release_memory (void)
  {
!   /*  bitmap_release_memory (); */
  }
  
  #ifdef CANNOT_CHANGE_MODE_CLASS
Index: gcc/tree-dfa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-dfa.c,v
retrieving revision 1.1.4.217.2.14
diff -c -3 -p -r1.1.4.217.2.14 tree-dfa.c
*** gcc/tree-dfa.c	26 Oct 2004 14:06:51 -0000	1.1.4.217.2.14
--- gcc/tree-dfa.c	8 Nov 2004 17:34:46 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 46,52 ****
  #include "tree-pass.h"
  #include "convert.h"
  #include "params.h"
! #include "cgraph.h"
  
  /* Build and maintain data flow information for trees.  */
  
--- 46,52 ----
  #include "tree-pass.h"
  #include "convert.h"
  #include "params.h"
! #include "ipa-static.h"
  
  /* Build and maintain data flow information for trees.  */
  
*************** find_referenced_vars (void)
*** 109,114 ****
--- 109,116 ----
    block_stmt_iterator si;
    struct walk_state walk_state;
  
+   ipa_static_reset_maps ();
+ 
    vars_found = htab_create (50, htab_hash_pointer, htab_eq_pointer, NULL);
    memset (&walk_state, 0, sizeof (walk_state));
    walk_state.vars_found = vars_found;
Index: gcc/tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-flow.h,v
retrieving revision 1.1.4.187.2.19
diff -c -3 -p -r1.1.4.187.2.19 tree-flow.h
*** gcc/tree-flow.h	26 Oct 2004 14:06:52 -0000	1.1.4.187.2.19
--- gcc/tree-flow.h	8 Nov 2004 17:34:46 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 29,35 ****
  #include "hashtab.h"
  #include "tree-gimple.h"
  #include "tree-ssa-operands.h"
! #include "cgraph.h"
  
  /* Forward declare structures for the garbage collector GTY markers.  */
  #ifndef GCC_BASIC_BLOCK_H
--- 29,35 ----
  #include "hashtab.h"
  #include "tree-gimple.h"
  #include "tree-ssa-operands.h"
! #include "ipa-static.h"
  
  /* Forward declare structures for the garbage collector GTY markers.  */
  #ifndef GCC_BASIC_BLOCK_H
*************** struct var_ann_d GTY(())
*** 201,206 ****
--- 201,211 ----
       live at the same time and this can happen for each call to the
       dominator optimizer.  */
    tree current_def;
+ 
+   /* Pointer to the structure that contains the sets of global
+      variables modified by function calls.  This field is only used
+      for FUNCTION_DECLs.  */
+   ipa_static_vars_info_t GTY ((skip)) static_vars_info;
  };
  
  
*************** extern void bsi_insert_after (block_stmt
*** 448,453 ****
--- 453,464 ----
  
  extern void bsi_replace (const block_stmt_iterator *, tree, bool);
  
+ /* In tree-sra.c  */
+ void sra_insert_before (block_stmt_iterator *, tree);
+ void sra_insert_after (block_stmt_iterator *, tree);
+ void sra_init_cache (void);
+ bool sra_type_can_be_decomposed_p (tree);
+ 
  /*---------------------------------------------------------------------------
  			      Function prototypes
  ---------------------------------------------------------------------------*/
Index: gcc/tree-gimple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-gimple.c,v
retrieving revision 2.1.2.8
diff -c -3 -p -r2.1.2.8 tree-gimple.c
*** gcc/tree-gimple.c	17 Oct 2004 18:31:00 -0000	2.1.2.8
--- gcc/tree-gimple.c	8 Nov 2004 17:34:46 -0000
*************** get_call_expr_in (tree t)
*** 429,434 ****
--- 429,454 ----
    return NULL_TREE;
  }
  
+ /* Given a memory reference T, will return the variable at the bottom
+    of the access.  Unlike get_base_address below, this will recurse
+    thru INDIRECT_REFS.  */
+ 
+ tree
+ get_base_var (tree t)
+ {
+   if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR))
+     return t;
+ 
+   while (!SSA_VAR_P (t) 
+ 	 && (!CONSTANT_CLASS_P (t))
+ 	 && TREE_CODE (t) != LABEL_DECL
+ 	 && TREE_CODE (t) != FUNCTION_DECL)
+     {
+       t = TREE_OPERAND (t, 0);
+     }
+   return t;
+ } 
+ 
  /* Given a memory reference expression, return the base address.  Note that,
     in contrast with get_base_var, this will not recurse inside INDIRECT_REF
     expressions.  Therefore, given the reference PTR->FIELD, this function
Index: gcc/tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 1.1.4.122.2.23
diff -c -3 -p -r1.1.4.122.2.23 tree-optimize.c
*** gcc/tree-optimize.c	25 Oct 2004 09:15:36 -0000	1.1.4.122.2.23
--- gcc/tree-optimize.c	8 Nov 2004 17:34:46 -0000
*************** init_tree_optimization_passes (void)
*** 447,454 ****
--- 447,457 ----
    NEXT_PASS (pass_complete_unroll);
    NEXT_PASS (pass_iv_optimize);
    NEXT_PASS (pass_loop_done);
+   *p = NULL;
+ 
    p = &all_ipa_passes;
    NEXT_PASS (pass_ipa_inline);
+   NEXT_PASS (pass_ipa_static);
    *p = NULL;
  
  #undef NEXT_PASS
Index: gcc/tree-pass.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pass.h,v
retrieving revision 1.1.2.12.2.9
diff -c -3 -p -r1.1.2.12.2.9 tree-pass.h
*** gcc/tree-pass.h	25 Oct 2004 09:15:36 -0000	1.1.2.12.2.9
--- gcc/tree-pass.h	8 Nov 2004 17:34:46 -0000
*************** extern struct tree_opt_pass pass_lower_c
*** 145,152 ****
  extern struct tree_opt_pass pass_lower_eh;
  extern struct tree_opt_pass pass_build_cfg;
  extern struct tree_opt_pass pass_tree_profile;
- extern struct tree_opt_pass pass_referenced_vars;
  extern struct tree_opt_pass pass_sra;
  extern struct tree_opt_pass pass_tail_recursion;
  extern struct tree_opt_pass pass_tail_calls;
  extern struct tree_opt_pass pass_loop;
--- 145,152 ----
  extern struct tree_opt_pass pass_lower_eh;
  extern struct tree_opt_pass pass_build_cfg;
  extern struct tree_opt_pass pass_tree_profile;
  extern struct tree_opt_pass pass_sra;
+ extern struct tree_opt_pass pass_referenced_vars;
  extern struct tree_opt_pass pass_tail_recursion;
  extern struct tree_opt_pass pass_tail_calls;
  extern struct tree_opt_pass pass_loop;
*************** extern struct tree_opt_pass pass_fre;
*** 190,194 ****
--- 190,195 ----
  extern struct tree_opt_pass pass_linear_transform;
  
  extern struct tree_opt_pass pass_ipa_inline;
+ extern struct tree_opt_pass pass_ipa_static;
  
  #endif /* GCC_TREE_PASS_H */
Index: gcc/tree-sra.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-sra.c,v
retrieving revision 1.1.2.20.2.12
diff -c -3 -p -r1.1.2.20.2.12 tree-sra.c
*** gcc/tree-sra.c	25 Oct 2004 09:15:37 -0000	1.1.2.20.2.12
--- gcc/tree-sra.c	8 Nov 2004 17:34:47 -0000
*************** is_sra_scalar_type (tree type)
*** 171,178 ****
     instantiated, just that if we decide to break up the type into
     separate pieces that it can be done.  */
  
! static bool
! type_can_be_decomposed_p (tree type)
  {
    unsigned int cache = TYPE_UID (TYPE_MAIN_VARIANT (type)) * 2;
    tree t;
--- 171,178 ----
     instantiated, just that if we decide to break up the type into
     separate pieces that it can be done.  */
  
! bool
! sra_type_can_be_decomposed_p (tree type)
  {
    unsigned int cache = TYPE_UID (TYPE_MAIN_VARIANT (type)) * 2;
    tree t;
*************** decl_can_be_decomposed_p (tree var)
*** 273,279 ****
      }
  
    /* We must be able to decompose the variable's type.  */
!   if (!type_can_be_decomposed_p (TREE_TYPE (var)))
      {
        if (dump_file && (dump_flags & TDF_DETAILS))
  	{
--- 273,279 ----
      }
  
    /* We must be able to decompose the variable's type.  */
!   if (!sra_type_can_be_decomposed_p (TREE_TYPE (var)))
      {
        if (dump_file && (dump_flags & TDF_DETAILS))
  	{
*************** type_can_instantiate_all_elements (tree 
*** 294,300 ****
  {
    if (is_sra_scalar_type (type))
      return true;
!   if (!type_can_be_decomposed_p (type))
      return false;
  
    switch (TREE_CODE (type))
--- 294,300 ----
  {
    if (is_sra_scalar_type (type))
      return true;
!   if (!sra_type_can_be_decomposed_p (type))
      return false;
  
    switch (TREE_CODE (type))
*************** insert_edge_copies (tree stmt, basic_blo
*** 1665,1671 ****
  
  /* Helper function to insert LIST before BSI, and set up line number info.  */
  
! static void
  sra_insert_before (block_stmt_iterator *bsi, tree list)
  {
    tree stmt = bsi_stmt (*bsi);
--- 1665,1671 ----
  
  /* Helper function to insert LIST before BSI, and set up line number info.  */
  
! void
  sra_insert_before (block_stmt_iterator *bsi, tree list)
  {
    tree stmt = bsi_stmt (*bsi);
*************** sra_insert_before (block_stmt_iterator *
*** 1677,1683 ****
  
  /* Similarly, but insert after BSI.  Handles insertion onto edges as well.  */
  
! static void
  sra_insert_after (block_stmt_iterator *bsi, tree list)
  {
    tree stmt = bsi_stmt (*bsi);
--- 1677,1683 ----
  
  /* Similarly, but insert after BSI.  Handles insertion onto edges as well.  */
  
! void
  sra_insert_after (block_stmt_iterator *bsi, tree list)
  {
    tree stmt = bsi_stmt (*bsi);
*************** debug_sra_elt_name (struct sra_elt *elt)
*** 2025,2030 ****
--- 2025,2040 ----
    fputc ('\n', stderr);
  }
  
+ void 
+ sra_init_cache (void)
+ {
+   if (sra_type_decomp_cache) 
+     return;
+ 
+   sra_type_decomp_cache = BITMAP_XMALLOC ();
+   sra_type_inst_cache = BITMAP_XMALLOC ();
+ }
+ 
  /* Main entry point.  */
  
  static void
*************** tree_sra (void)
*** 2034,2041 ****
    gcc_obstack_init (&sra_obstack);
    sra_candidates = BITMAP_XMALLOC ();
    needs_copy_in = BITMAP_XMALLOC ();
!   sra_type_decomp_cache = BITMAP_XMALLOC ();
!   sra_type_inst_cache = BITMAP_XMALLOC ();
    sra_map = htab_create (101, sra_elt_hash, sra_elt_eq, NULL);
  
    /* Scan.  If we find anything, instantiate and scalarize.  */
--- 2044,2050 ----
    gcc_obstack_init (&sra_obstack);
    sra_candidates = BITMAP_XMALLOC ();
    needs_copy_in = BITMAP_XMALLOC ();
!   sra_init_cache ();
    sra_map = htab_create (101, sra_elt_hash, sra_elt_eq, NULL);
  
    /* Scan.  If we find anything, instantiate and scalarize.  */
Index: gcc/tree-ssa-operands.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-operands.c,v
retrieving revision 1.1.2.9.2.15
diff -c -3 -p -r1.1.2.9.2.15 tree-ssa-operands.c
*** gcc/tree-ssa-operands.c	26 Oct 2004 14:06:52 -0000	1.1.2.9.2.15
--- gcc/tree-ssa-operands.c	8 Nov 2004 17:34:47 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 32,37 ****
--- 32,38 ----
  #include "tree-pass.h"
  #include "ggc.h"
  #include "timevar.h"
+ #include "ipa-static.h"
  
  #include "langhooks.h"
  
*************** static inline void append_def (tree *);
*** 134,141 ****
  static inline void append_use (tree *);
  static void append_v_may_def (tree);
  static void append_v_must_def (tree);
! static void add_call_clobber_ops (tree);
! static void add_call_read_ops (tree);
  static void add_stmt_operand (tree *, tree, int);
  
  /* Return a vector of contiguous memory for NUM def operands.  */
--- 135,142 ----
  static inline void append_use (tree *);
  static void append_v_may_def (tree);
  static void append_v_must_def (tree);
! static void add_call_clobber_ops (tree, tree);
! static void add_call_read_ops (tree, tree);
  static void add_stmt_operand (tree *, tree, int);
  
  /* Return a vector of contiguous memory for NUM def operands.  */
*************** get_call_expr_operands (tree stmt, tree 
*** 1398,1403 ****
--- 1399,1405 ----
  {
    tree op;
    int call_flags = call_expr_flags (expr);
+   tree callee = get_callee_fndecl (expr);
  
    /* Find uses in the called function.  */
    get_expr_operands (stmt, &TREE_OPERAND (expr, 0), opf_none);
*************** get_call_expr_operands (tree stmt, tree 
*** 1414,1422 ****
  	 there is no point in recording that.  */ 
        if (TREE_SIDE_EFFECTS (expr)
  	  && !(call_flags & (ECF_PURE | ECF_CONST | ECF_NORETURN)))
! 	add_call_clobber_ops (stmt);
        else if (!(call_flags & ECF_CONST))
! 	add_call_read_ops (stmt);
      }
  }
  
--- 1416,1424 ----
  	 there is no point in recording that.  */ 
        if (TREE_SIDE_EFFECTS (expr)
  	  && !(call_flags & (ECF_PURE | ECF_CONST | ECF_NORETURN)))
! 	add_call_clobber_ops (stmt, callee);
        else if (!(call_flags & ECF_CONST))
! 	add_call_read_ops (stmt, callee);
      }
  }
  
*************** note_addressable (tree var, stmt_ann_t s
*** 1580,1586 ****
     clobbered variables in the function.  */
  
  static void
! add_call_clobber_ops (tree stmt)
  {
    /* Functions that are not const, pure or never return may clobber
       call-clobbered variables.  */
--- 1582,1588 ----
     clobbered variables in the function.  */
  
  static void
! add_call_clobber_ops (tree stmt, tree callee)
  {
    /* Functions that are not const, pure or never return may clobber
       call-clobbered variables.  */
*************** add_call_clobber_ops (tree stmt)
*** 1598,1611 ****
        size_t i;
        bitmap_iterator bi;
  
        EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
  	{
  	  tree var = referenced_var (i);
! 	  if (TREE_READONLY (var)
! 	      && (TREE_STATIC (var) || DECL_EXTERNAL (var)))
! 	    add_stmt_operand (&var, stmt, opf_none);
  	  else
! 	    add_stmt_operand (&var, stmt, opf_is_def);
  	}
      }
  }
--- 1600,1653 ----
        size_t i;
        bitmap_iterator bi;
  
+       /* Get info for local and module level statics.  There is a bit
+ 	 set for each static if the call being processed does not read
+ 	 or write that variable.  */
+ 
+       bitmap not_read_b = callee 
+ 	? ipa_get_statics_not_read_global (callee) : NULL; 
+       bitmap not_written_b = callee 
+ 	? ipa_get_statics_not_written_global (callee) : NULL; 
+ 
        EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
  	{
  	  tree var = referenced_var (i);
! 
! 	  bool not_read
! 	    = not_read_b ? bitmap_bit_p (not_read_b, i) : false;
! 	  bool not_written
! 	    = not_written_b ? bitmap_bit_p (not_written_b, i) : false;
! 
! 	  if (not_read)
! 	    {
! 	      /* The var is not read during the call.  */
! 	      if (!not_written)
! 		add_stmt_operand (&var, stmt, opf_is_def);
! 	    }
  	  else
! 	    {
! 	      /* The var is read during the call.  */
! 	      if (not_written) 
! 		add_stmt_operand (&var, stmt, opf_none);
! 
! 	      /* The not_read and not_written bits are only set for module
! 		 static variables.  Neither is set here, so we may be dealing
! 		 with a module static or we may not.  So we still must look
! 		 anywhere else we can (such as the TREE_READONLY) to get
! 		 better info.  */
! 
! 	      /* If VAR is read-only, don't add a V_MAY_DEF, just a
! 		 VUSE operand.  FIXME, this is quirky.  TREE_READONLY
! 		 by itself is not enough here.  We can only decide
! 		 that the call will not affect VAR if all these
! 		 conditions are met.  One would think that
! 		 TREE_READONLY should be sufficient.  */
! 	      else if (TREE_READONLY (var)
! 		       && (TREE_STATIC (var) || DECL_EXTERNAL (var)))
! 		add_stmt_operand (&var, stmt, opf_none);
! 	      else
! 		add_stmt_operand (&var, stmt, opf_is_def);
! 	    }
  	}
      }
  }
*************** add_call_clobber_ops (tree stmt)
*** 1615,1621 ****
     function.  */
  
  static void
! add_call_read_ops (tree stmt)
  {
    bitmap_iterator bi;
  
--- 1657,1663 ----
     function.  */
  
  static void
! add_call_read_ops (tree stmt, tree callee)
  {
    bitmap_iterator bi;
  
*************** add_call_read_ops (tree stmt)
*** 1628,1638 ****
    else
      {
        size_t i;
        
        EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
  	{
  	  tree var = referenced_var (i);
! 	  add_stmt_operand (&var, stmt, opf_none);
  	}
      }
  }
--- 1670,1685 ----
    else
      {
        size_t i;
+       bitmap not_read_b = callee 
+ 	? ipa_get_statics_not_read_global (callee) : NULL; 
        
        EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
  	{
  	  tree var = referenced_var (i);
! 	  bool not_read = not_read_b 
! 	    ? bitmap_bit_p(not_read_b, i) : false;
! 	  if (!not_read)
! 	    add_stmt_operand (&var, stmt, opf_none);
  	}
      }
  }
Index: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.169.2.16
diff -c -3 -p -r1.342.2.169.2.16 tree.h
*** gcc/tree.h	17 Oct 2004 18:31:08 -0000	1.342.2.169.2.16
--- gcc/tree.h	8 Nov 2004 17:34:48 -0000
*************** tree upper_bound_in_type (tree, tree);
*** 3938,3943 ****
--- 3938,3944 ----
  extern bool thread_through_all_blocks (void);
  
  /* In tree-gimple.c.  */
+ extern tree get_base_var (tree t);
  extern tree get_base_address (tree t);
  
  #endif  /* GCC_TREE_H  */
/* Callgraph based analysis of static variables.
   Copyright (C) 2004 Free Software Foundation, Inc.
   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.  */

/* This file gathers information about how statics that are local to
   the compilation unit are used.  It is to be run after the call
   graph is built and after inlining decisions have been made.

   First each function is analyzed to determine which local static
   variables are either read or written or have their address taken.
   Any local static that has its address taken is removed from
   consideration.  Once the local read and writes are determined, a
   transitive closure of this information is performed over the call
   graph to determine the worst case set of side effects of each call.
   In later parts of the compiler, these local and global sets are
   examined to make the call clobbering less traumatic, promote some
   statics to registers, and improve aliasing information.

   This must be run after inlining decisions have been made since
   otherwise, the local sets will not contain information that is
   consistent with post inlined state.  The global sets are less prone
   to problems since they are by definition transitive.  */

/* The code in this module is called by the ipa pass manager. It
   should be one of the later passes since it's information is used by
   the rest of the compilation. */

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "tree-flow.h"
#include "tree-inline.h"
#include "tree-pass.h"
#include "langhooks.h"
#include "pointer-set.h"
#include "ggc.h"
#include "ipa-static.h"
#include "c-common.h"
#include "tree-gimple.h"
#include "cgraph.h"
#include "output.h"
#include "flags.h"

/* FIXME -- PROFILE-RESTRUCTURE: change comment from DECL_UID to var-ann. */    
/* This splay tree contains all of the static variables that are
   being considered by the compilation level alias analysis.  For
   module_at_a_time compilation, this is the set of static but not
   public variables.  Any variables that either have their address
   taken or participate in otherwise unsavory operations are deleted
   from this list.  */
static GTY((param1_is(int), param2_is(tree)))
     splay_tree static_vars_to_consider_by_uid;

/* This bitmap is used to knock out the module static variables whose
   addresses have been taken and passed around.  This is indexed by
   uid.  */
static bitmap module_statics_escape;

/* FIXME -- PROFILE-RESTRUCTURE: change comment from DECL_UID to var-ann. */    
/* A bit is set for every module static we are considering and is
   indexed by DECL_UID.  This is ored into the local info when asm
   code is found that clobbers all memory. */
static bitmap all_module_statics;

/* Records tree nodes seen in cgraph_create_edges.  Simply using
   walk_tree_without_duplicates doesn't guarantee each node is visited
   once because it gets a new htab upon each recursive call from
   scan_for_static_refs.  */
static struct pointer_set_t *visited_nodes;

tree memory_identifier_string;

/* Debugging function for postorder and inorder code. NOTE is a string
   that is printed before the nodes are printed.  ORDER is an array of
   cgraph_nodes that has COUNT useful nodes in it.  */

static void 
print_order (FILE* out, 
	     const char * note, 
	     struct cgraph_node** order, 
	     int count) 
{
  int i;
  fprintf (out, "\n\n ordered call graph: %s\n", note);
  
  for (i = count - 1; i >= 0; i--)
    dump_cgraph_node(dump_file, order[i]);
  fprintf (out, "\n");
  fflush(out);
}

/* FIXME -- PROFILE-RESTRUCTURE: Remove this function, it becomes a nop. */    
/* Convert IN_DECL bitmap which is indexed by DECL_UID to IN_ANN, a
   bitmap indexed by var_ann (VAR_DECL)->uid.  */

static void 
convert_UIDs_in_bitmap (bitmap in_ann, bitmap in_decl) 
{
  int index;
  bitmap_iterator bi;

  EXECUTE_IF_SET_IN_BITMAP(in_decl, 0, index, bi)
    {
      splay_tree_node n = 
	      splay_tree_lookup (static_vars_to_consider_by_uid, index);
      if (n != NULL) 
	{
	  tree t = (tree)n->value;
	  var_ann_t va = var_ann (t);
	  if (va) 
	    bitmap_set_bit(in_ann, va->uid);
	}
    }
}


/* FIXME -- PROFILE-RESTRUCTURE: Remove this function, it becomes a
   nop. */    
/* The bitmaps used to represent the static global variables are
   indexed by DECL_UID however, this is not used inside of functions
   to index the ssa variables.  The denser var_ann (VAR_DECL)->uid is
   used there.  This function is called from
   tree_dfa:find_referenced_vars after the denser representation is
   built.  This function invalidates any cached indexes.  */ 

void
ipa_static_reset_maps (void) 
{
  struct cgraph_node *node;
  
  for (node = cgraph_nodes; node; node = node->next)
    {
      ipa_static_vars_info_t info = node->static_vars_info;

      if (info) 
	{
	  ipa_local_static_vars_info_t l = info->local;
	  ipa_global_static_vars_info_t g = info->global;

	  if (l->var_anns_valid) 
	    {
	      bitmap_clear (l->statics_read_by_ann_uid);
	      bitmap_clear (l->statics_written_by_ann_uid);
	      l->var_anns_valid = false;
	    }

	  /* There may be orphans in the cgraph so must check that
	     there is global info.  */
	  if (g && g->var_anns_valid) 
	    {
	      bitmap_clear (g->statics_read_by_ann_uid);
	      bitmap_clear (g->statics_written_by_ann_uid);
	      bitmap_clear (g->statics_not_read_by_ann_uid);
	      bitmap_clear (g->statics_not_written_by_ann_uid);
	      g->var_anns_valid = false;
	    }
	}
    }
}

/* Get the cgraph_node for the local function and make sure the
   var_ann bitmaps are properly converted.  */
 
static ipa_local_static_vars_info_t
get_local_static_vars_info (tree fn) 
{
  ipa_local_static_vars_info_t l;

  /* Was not compiled -O2 or higher.  */ 
  ipa_static_vars_info_t info = get_var_ann (fn)->static_vars_info;

  if (!info)
    return NULL;

  l = info->local;
  if (!l->var_anns_valid) 
    {
      convert_UIDs_in_bitmap (l->statics_read_by_ann_uid, 
			      l->statics_read_by_decl_uid);
      convert_UIDs_in_bitmap (l->statics_written_by_ann_uid, 
			      l->statics_written_by_decl_uid);
      l->var_anns_valid = true;
    }
  return l;
}

/* Get the global static_vars_info structure for the function FN and
   make sure the ann_uid's bitmaps are properly converted.  */
 
static ipa_global_static_vars_info_t
get_global_static_vars_info (tree fn) 
{
  ipa_global_static_vars_info_t g;

  /* Was not compiled -O2 or higher.  */ 
  ipa_static_vars_info_t info = get_var_ann (fn)->static_vars_info;

  if (!info)
    return NULL;

  g = info->global;
  if (!g) 
    return NULL;

  if (!g->var_anns_valid) 
    {
      convert_UIDs_in_bitmap (g->statics_read_by_ann_uid, 
			      g->statics_read_by_decl_uid);
      convert_UIDs_in_bitmap (g->statics_written_by_ann_uid, 
			      g->statics_written_by_decl_uid);
      convert_UIDs_in_bitmap (g->statics_not_read_by_ann_uid, 
			      g->statics_not_read_by_decl_uid);
      convert_UIDs_in_bitmap (g->statics_not_written_by_ann_uid, 
			      g->statics_not_written_by_decl_uid);
      g->var_anns_valid = true;
    }
  return g;
}

/* Return a bitmap indexed by var_ann (VAR_DECL)->uid for the static
   variables that may be read locally by the execution of the function
   fn.  Returns NULL if no data is available, such as it was not
   compiled with -O2 or higher.  */

bitmap 
ipa_get_statics_read_local (tree fn)
{
  ipa_local_static_vars_info_t l = get_local_static_vars_info (fn);
  if (l) 
    return l->statics_read_by_ann_uid;
  else
    return NULL;
}

/* Return a bitmap indexed by var_ann (VAR_DECL)->uid for the static
   variables that may be written locally by the execution of the function
   fn.  Returns NULL if no data is available, such as it was not
   compiled with -O2 or higher.  */

bitmap 
ipa_get_statics_written_local (tree fn)
{
  ipa_local_static_vars_info_t l = get_local_static_vars_info (fn);
  if (l) 
    return l->statics_written_by_ann_uid;
  else
    return NULL;
}

/* Return a bitmap indexed by var_ann (VAR_DECL)->uid for the static
   variables that are read during the execution of the function
   FN.  Returns NULL if no data is available, such as it was not
   compiled with -O2 or higher.  */

bitmap 
ipa_get_statics_read_global (tree fn) 
{
  ipa_global_static_vars_info_t g = get_global_static_vars_info (fn);
  if (g) 
    return g->statics_read_by_ann_uid;
  else
    return NULL;
}

/* Return a bitmap indexed by var_ann (VAR_DECL)->uid for the static
   variables that are written during the execution of the function
   FN.  Note that variables written may or may not be read during the
   function call.  Returns NULL if no data is available, such as it
   was not compiled with -O2 or higher.  */

bitmap 
ipa_get_statics_written_global (tree fn) 
{
  ipa_global_static_vars_info_t g = get_global_static_vars_info (fn);
  if (g) 
    return g->statics_written_by_ann_uid;
  else
    return NULL;
}

/* Return a bitmap indexed by var_ann (VAR_DECL)->uid for the static
   variables that are not read during the execution of the function
   FN.  Returns NULL if no data is available, such as it was not
   compiled with -O2 or higher.  */

bitmap 
ipa_get_statics_not_read_global (tree fn) 
{
  ipa_global_static_vars_info_t g = get_global_static_vars_info (fn);
  if (g) 
    return g->statics_not_read_by_ann_uid;
  else
    return NULL;
}

/* Return a bitmap indexed by var_ann (VAR_DECL)->uid for the static
   variables that are not written during the execution of the function
   FN.  Note that variables written may or may not be read during the
   function call.  Returns NULL if no data is available, such as it
   was not compiled with -O2 or higher.  */

bitmap 
ipa_get_statics_not_written_global (tree fn) 
{
  ipa_global_static_vars_info_t g = get_global_static_vars_info (fn);
  if (g) 
    return g->statics_not_written_by_ann_uid;
  else
    return NULL;
}

struct searchc_env {
  struct cgraph_node **stack;
  int stack_size;
  struct cgraph_node **result;
  int order_pos;
  splay_tree nodes_marked_new;
  bool reduce;
  int count;
};

struct dfs_info {
  int dfn_number;
  int low_link;
  bool new;
  bool on_stack;
};

/* This is an implementation of Tarjan's strongly connected region
   finder as reprinted in Aho Hopcraft and Ullman's The Design and
   Analysis of Computer Programs (1975) pages 192-193.  This version
   has been customized for cgraph_nodes.  The env parameter is because
   it is recursive and there are no nested functions here.  This
   function should only be called from itself or
   cgraph_reduced_inorder.  ENV is a stack env and would be
   unnecessary if C had nested functions.  V is the node to start
   searching from.  */

static void
searchc (struct searchc_env* env, struct cgraph_node *v) 
{
  struct cgraph_edge *edge;
  struct dfs_info *v_info = v->aux;
  
  /* mark node as old */
  v_info->new = false;
  splay_tree_remove (env->nodes_marked_new, v->uid);
  
  v_info->dfn_number = env->count;
  v_info->low_link = env->count;
  env->count++;
  env->stack[(env->stack_size)++] = v;
  v_info->on_stack = true;
  
  for (edge = v->callees; edge; edge = edge->next_callee)
    {
      struct dfs_info * w_info;
      struct cgraph_node *w = edge->callee;
      /* Bypass the clones and only look at the master node.  Skip
	 external and other bogus nodes.  */
      w = cgraph_master_clone (w);
      if (w && w->aux) 
	{
	  w_info = w->aux;
	  if (w_info->new) 
	    {
	      searchc (env, w);
	      v_info->low_link =
		(v_info->low_link < w_info->low_link) ?
		v_info->low_link : w_info->low_link;
	    } 
	  else 
	    if ((w_info->dfn_number < v_info->dfn_number) 
		&& (w_info->on_stack)) 
	      v_info->low_link =
		(w_info->dfn_number < v_info->low_link) ?
		w_info->dfn_number : v_info->low_link;
	}
    }


  if (v_info->low_link == v_info->dfn_number) 
    {
      struct cgraph_node *last = NULL;
      struct cgraph_node *x;
      struct dfs_info *x_info;
      do {
	x = env->stack[--(env->stack_size)];
	x_info = x->aux;
	x_info->on_stack = false;
	
	if (env->reduce) 
	  {
	    x->next_cycle = last;
	    last = x;
	  } 
	else 
	  env->result[env->order_pos++] = x;
      } 
      while (v != x);
      if (env->reduce) 
	env->result[env->order_pos++] = v;
    }
}

/* Topsort the call graph by caller relation.  Put the result in ORDER.

   The REDUCE flag is true if you want the cycles reduced to single
   nodes.  Only consider nodes that have the output bit set. */

static int
reduced_inorder (struct cgraph_node **order, bool reduce)
{
  struct cgraph_node *node;
  struct searchc_env env;
  splay_tree_node result;
  env.stack = xcalloc (cgraph_n_nodes, sizeof (struct cgraph_node *));
  env.stack_size = 0;
  env.result = order;
  env.order_pos = 0;
  env.nodes_marked_new = splay_tree_new (splay_tree_compare_ints, 0, 0);
  env.count = 1;
  env.reduce = reduce;
  
  for (node = cgraph_nodes; node; node = node->next) 
    if (cgraph_is_master_clone (node)
	&& (node->local.finalized))
      {
	struct dfs_info *info = xcalloc (1, sizeof (struct dfs_info));
	info->new = true;
	info->on_stack = false;
	node->aux = info;
	node->next_cycle = NULL;
	
	splay_tree_insert (env.nodes_marked_new,
			   node->uid, (splay_tree_value)node);
      } 
    else 
      node->aux = NULL;
  result = splay_tree_min (env.nodes_marked_new);
  while (result)
    {
      node = (struct cgraph_node *)result->value;
      searchc (&env, node);
      result = splay_tree_min (env.nodes_marked_new);
    }
  splay_tree_delete (env.nodes_marked_new);
  free (env.stack);

  for (node = cgraph_nodes; node; node = node->next)
    if (node->aux)
      {
	free (node->aux);
	node->aux = NULL;
      }
  return env.order_pos;
}

/* Add VAR to all_module_statics and the two static_vars_to_consider*
   sets.  */

static inline
void add_static_var (tree var) 
{
  /* FIXME -- PROFILE-RESTRUCTURE: Change the call from
     DECL_UID to get the uid from the var_ann field. */    
  splay_tree_insert (static_vars_to_consider_by_uid,
		     DECL_UID (var), (splay_tree_value)var);
  
  if (dump_file)
    fprintf (dump_file, "\nConsidering var:%s",
	     lang_hooks.decl_printable_name (var, 2));
  /* FIXME -- PROFILE-RESTRUCTURE: Change the call from
     DECL_UID to get the uid from the var_ann field. */    
  bitmap_set_bit (all_module_statics, DECL_UID (var));
}

/* FIXME this needs to be enhanced.  If we are compiling a single
   module this returns true if the variable is a module level static,
   but if we are doing whole program compilation, this could return
   true if TREE_PUBLIC is true. */
/* Return true if the variable T is the right kind of static variable to
   perform compilation unit scope escape analysis.  */

static inline
bool has_proper_scope_for_analysis (tree t)
{
  bool result = (TREE_STATIC (t)) && !(TREE_PUBLIC (t)) && !(TREE_THIS_VOLATILE (t));
  if ((result) && !bitmap_bit_p (all_module_statics, DECL_UID (t)))
    add_static_var (t);
  return result;
}

/* If T is a VAR_DECL for a static that we are interrested in, add the
   uid to the bitmap.  */

static void
check_operand (tree t, bitmap bm)
{
  if (!t) return;

  /* FIXME -- PROFILE-RESTRUCTURE: Change the call from DECL_UID to
     get the uid from the var_ann field. */    
  if ((TREE_CODE (t) == VAR_DECL) && has_proper_scope_for_analysis (t))
    bitmap_set_bit (bm, DECL_UID (t));
}

/* Examine tree T for references to static variables. All internal
   references like array references or indirect references are added
   to the INTERNAL_BM. Direct references are added to BASE_BM.  When
   this is called from the rhs or recursively, both bitmap operands
   are for the read bitmap.  When called from the lhs, the BASE_BM is
   the write bitmap.  */

static void
check_tree (tree t, bitmap base_bm, bitmap internal_bm)
{
  if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR))
    return;

  while (TREE_CODE (t) == REALPART_EXPR 
	 || TREE_CODE (t) == IMAGPART_EXPR
	 || handled_component_p (t))
    {
      if (TREE_CODE (t) == ARRAY_REF)
	check_operand (TREE_OPERAND (t, 1), internal_bm);
      t = TREE_OPERAND (t, 0);
    }

  /* The bottom of an indirect reference can only be read, not
     written.  So just recurse and but what ever we find, check it
     against the read bitmaps.  */
  if (INDIRECT_REF_P (t))
    check_tree (TREE_OPERAND (t, 0), internal_bm, internal_bm);

  if (SSA_VAR_P (t))
    check_operand (t, base_bm);
}

/* Scan tree T to see if there are any addresses taken in within T.  */

static void 
look_for_address_of (tree t)
{
  if (TREE_CODE (t) == ADDR_EXPR)
    {
      tree x = get_base_var (t);
      if ((TREE_CODE (x) == VAR_DECL) && has_proper_scope_for_analysis (x))
	{
	  if (dump_file)
	    fprintf (dump_file, "\nadding address:%s",
		     lang_hooks.decl_printable_name (x, 2));
	  
	  /* FIXME -- PROFILE-RESTRUCTURE: Change the call from
	     DECL_UID to get the uid from the var_ann field. */    
	  bitmap_set_bit (module_statics_escape, DECL_UID (x));
	}
    }
}


/* Check to see if T is a read or address of operation on a static var
   we are interested in analyzing.  FN is passed in to get access to
   its bit vectors.  */

static void
check_rhs_var (struct cgraph_node *fn, tree t)
{
  look_for_address_of (t);

  if (fn == NULL) 
    return;

  /* FIXME -- PROFILE-RESTRUCTURE: Change the call from DECL_UID to
     get the uid from the var_ann field. */    
  check_tree(t,
	     fn->static_vars_info->local->statics_read_by_decl_uid,
	     fn->static_vars_info->local->statics_read_by_decl_uid);
}

/* Check to see if T is an assignment to a static var we are
   interrested in analyzing.  FN is passed in to get access to its bit
   vectors.
*/

static void
check_lhs_var (struct cgraph_node *fn, tree t)
{
  if (fn == NULL) 
    return;

  /* FIXME -- PROFILE-RESTRUCTURE: Change the call from DECL_UID to
     get the uid from the var_ann field. */    
  check_tree(t, 
	     fn->static_vars_info->local->statics_written_by_decl_uid,
	     fn->static_vars_info->local->statics_read_by_decl_uid);
}

/* This is a scaled down version of get_asm_expr_operands from
   tree_ssa_operands.c.  The version there runs much later and assumes
   that aliasing information is already available. Here we are just
   trying to find if the set of inputs and outputs contain references
   or address of operations to local static variables.  FN is the
   function being analyzed and STMT is the actual asm statement.  */

static void
get_asm_expr_operands (struct cgraph_node * fn, tree stmt)
{
  int noutputs = list_length (ASM_OUTPUTS (stmt));
  const char **oconstraints
    = (const char **) alloca ((noutputs) * sizeof (const char *));
  int i;
  tree link;
  const char *constraint;
  bool allows_mem, allows_reg, is_inout;
  
  for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link))
    {
      oconstraints[i] = constraint
	= TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
      parse_output_constraint (&constraint, i, 0, 0,
			       &allows_mem, &allows_reg, &is_inout);
      
      /* Memory operands are addressable.  Note that STMT needs the
	 address of this operand.  */
      if (!allows_reg && allows_mem) 
	check_lhs_var (fn, TREE_VALUE (link));
    }

  for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
    {
      constraint
	= TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
      parse_input_constraint (&constraint, 0, 0, noutputs, 0,
			      oconstraints, &allows_mem, &allows_reg);
      
      /* Memory operands are addressable.  Note that STMT needs the
	 address of this operand.  */
      if (!allows_reg && allows_mem) 
	check_rhs_var (fn, TREE_VALUE (link));
    }
  
  for (link = ASM_CLOBBERS (stmt); link; link = TREE_CHAIN (link))
    if (simple_cst_equal(TREE_VALUE (link), memory_identifier_string) == 1) 
      {
	/* Abandon all hope, ye who enter here. */
	fn->local.calls_read_all = true;
	fn->local.calls_write_all = true;
      }      
}

/* Check the parameters of a function call from CALLER to CALL_EXPR to
   see if any of them are static vars.  Also check to see if this is
   either an indirect call, a call outside the compilation unit, or
   has special attributes that effect the clobbers.  The caller
   parameter is the tree node for the caller and the second operand is
   the tree node for the entire call expression.  */

static void
process_call_for_static_vars(struct cgraph_node * caller, tree call_expr) 
{
  int flags = call_expr_flags(call_expr);
  tree operandList = TREE_OPERAND (call_expr, 1);
  tree operand;
  tree callee_t = get_callee_fndecl (call_expr);

  for (operand = operandList;
       operand != NULL_TREE;
       operand = TREE_CHAIN (operand))
    {
      tree argument = TREE_VALUE (operand);
      check_rhs_var (caller, argument);
    }
  
  /* Const and pure functions have less clobber effects than other
     functions so we process these first.  Otherwise if it is a call
     outside the compilation unit or an indirect call we punt.  This
     leaves local calls which will be processed by following the call
     graph.  */  

  if (flags & ECF_CONST) 
    return;
  else if (flags & ECF_PURE) 
    caller->local.calls_write_all = true;
  else 
    {
      enum availability avail = AVAIL_NOT_AVAILABLE;
      if (callee_t)
	{
	  struct cgraph_node* callee = cgraph_node(callee_t);
	  avail = cgraph_function_body_availability (callee);
	}

      /* Indirect call or external call. */
      if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITTABLE) 
	{
	  caller->local.calls_read_all = true;
	  caller->local.calls_write_all = true;
	}
    }
}

/* FIXME -- PROFILE-RESTRUCTURE: Change to walk by explicitly walking
   the basic blocks rather than calling walktree.  */    

/* Walk tree and record all calls.  Called via walk_tree.  FIXME When
   this is moved into the tree-profiling-branch, and is dealing with
   low GIMPLE, this routine should be changed to use tree iterators
   rather than being a walk_tree callback.  The data is the function
   that is being scanned.  */
/* TP is the part of the tree currently under the
   microscope. WALK_SUBTREES is part of the walk_tree api but is
   unused here.  DATA is cgraph_node of the function being walked.  */

static tree
scan_for_static_refs (tree *tp, 
		      int *walk_subtrees ATTRIBUTE_UNUSED, 
		      void *data)
{
  struct cgraph_node *fn = data;
  tree t = *tp;
  
  switch (TREE_CODE (t))  
    {
    case VAR_DECL:
      if (DECL_INITIAL (t))
	walk_tree (&DECL_INITIAL (t), scan_for_static_refs, fn, visited_nodes);
      break;

    case MODIFY_EXPR:
      {
	/* First look on the lhs and see what variable is stored to */
	tree rhs = TREE_OPERAND (t, 1);
	check_lhs_var (fn, TREE_OPERAND (t, 0));
	/* Next check the operands on the rhs to see if they are ok. */
	switch (TREE_CODE_CLASS (TREE_CODE (rhs))) 
	  {
	  case tcc_binary:
	    check_rhs_var (fn, TREE_OPERAND (rhs, 0));
	    check_rhs_var (fn, TREE_OPERAND (rhs, 1));
	    break;
	  case tcc_unary:
	  case tcc_reference:
	    check_rhs_var (fn, TREE_OPERAND (rhs, 0));
	    break;
	  case tcc_declaration:
	    check_rhs_var (fn, rhs);
	    break;
	  case tcc_expression:
	    switch (TREE_CODE (rhs)) 
	      {
	      case ADDR_EXPR:
		check_rhs_var (fn, rhs);
		break;
	      case CALL_EXPR: 
		process_call_for_static_vars (fn, rhs);
		break;
	      default:
		break;
	      }
	    break;
	  default:
	    break;
	  }
      }
      break;
      
      
    case CALL_EXPR: 
      process_call_for_static_vars (fn, t);
      break;
      
    case ASM_EXPR:
      get_asm_expr_operands (fn, t);
      break;
      
    default:
      break;
    }
  return NULL;
}

/* Lookup the tree node for the static variable that has UID and
   conver the name to a string for debugging.  */

static const char *
get_static_name_by_uid (int index)
{
  splay_tree_node stn = splay_tree_lookup (static_vars_to_consider_by_uid, index);
  if (stn)
    return lang_hooks.decl_printable_name ((tree)(stn->value), 2);
  return NULL;
}

/* FIXME -- PROFILE-RESTRUCTURE: Change all *_decl_uid to *_ann_uid.  */

/* Or in all of the bits from every callee into X, the caller's, bit
   vector.  There are several cases to check to avoid the sparse
   bitmap oring.  */

static void
propagate_bits (struct cgraph_node *x)
{
  ipa_static_vars_info_t x_info = x->static_vars_info;
  ipa_global_static_vars_info_t x_global = x_info->global;

  struct cgraph_edge *e;
  for (e = x->callees; e; e = e->next_callee) 
    {
      struct cgraph_node *y = e->callee;

      /* Only look at the master nodes and skip external nodes.  */
      y = cgraph_master_clone (y);
      if (y)
	{
	  if (y->static_vars_info)
	    {
	      ipa_static_vars_info_t y_info; 
	      ipa_global_static_vars_info_t y_global;
	      y_info = y->static_vars_info;
	      y_global = y_info->global;
	      
	      if (x_global->statics_read_by_decl_uid != all_module_statics)
		{
		  if (y_global->statics_read_by_decl_uid 
		      == all_module_statics)
		    {
		      BITMAP_XFREE(x_global->statics_read_by_decl_uid);
		      x_global->statics_read_by_decl_uid 
			= all_module_statics;
		    }
		  /* Skip bitmaps that are pointer equal to node's bitmap
		     (no reason to spin within the cycle).  */
		  else if (x_global->statics_read_by_decl_uid 
			   != y_global->statics_read_by_decl_uid)
		    bitmap_a_or_b (x_global->statics_read_by_decl_uid,
				   x_global->statics_read_by_decl_uid,
				   y_global->statics_read_by_decl_uid);
		}
	      
	      if (x_global->statics_written_by_decl_uid != all_module_statics)
		{
		  if (y_global->statics_written_by_decl_uid 
		      == all_module_statics)
		    {
		      BITMAP_XFREE(x_global->statics_written_by_decl_uid);
		      x_global->statics_written_by_decl_uid 
			= all_module_statics;
		    }
		  /* Skip bitmaps that are pointer equal to node's bitmap
		     (no reason to spin within the cycle).  */
		  else if (x_global->statics_written_by_decl_uid 
			   != y_global->statics_written_by_decl_uid)
		    bitmap_a_or_b (x_global->statics_written_by_decl_uid,
				   x_global->statics_written_by_decl_uid,
				   y_global->statics_written_by_decl_uid);
		}
	    }
	  else 
	    {

	    }
	}
    }
}

/* FIXME -- PROFILE-RESTRUCTURE: Change all *_decl_uid to *_ann_uid.  */

/* Look at all of the callees of X to see which ones represent inlined
   calls.  For each of these callees, merge their local info into TARGET
   and check their children recursively.  */

static void 
merge_callee_local_info (struct cgraph_node *target, 
			 struct cgraph_node *x)
{
  struct cgraph_edge *e;
  ipa_local_static_vars_info_t x_l = target->static_vars_info->local;

  /* Make the world safe for tail recursion.  */
  if (x->aux) 
    return;

  x->aux = x;

  for (e = x->callees; e; e = e->next_callee) 
    {
      struct cgraph_node *y = e->callee;
      if (y->global.inlined_to) 
	{
	  ipa_static_vars_info_t y_info;
	  ipa_local_static_vars_info_t y_l;
	  struct cgraph_node* orig_y = y;
	 
	  y = cgraph_master_clone (y);
	  if (y)
	    {
	      y_info = y->static_vars_info;
	      y_l = y_info->local;
	      bitmap_a_or_b (x_l->statics_read_by_decl_uid,
			     x_l->statics_read_by_decl_uid,
			     y_l->statics_read_by_decl_uid);
	      bitmap_a_or_b (x_l->statics_written_by_decl_uid,
			     x_l->statics_written_by_decl_uid,
			     y_l->statics_written_by_decl_uid);
	      target->local.calls_read_all |= y->local.calls_read_all;
	      target->local.calls_write_all |= y->local.calls_write_all;
	      merge_callee_local_info (target, y);
	    }
	  else 
	    {
	      fprintf(stderr, "suspect inlining of ");
	      dump_cgraph_node (stderr, orig_y);
	      fprintf(stderr, "\ninto ");
	      dump_cgraph_node (stderr, target);
	      dump_cgraph (stderr);
	      gcc_assert(false);
	    }
	}
    }

  x->aux = NULL;
}

/* The init routine for analyzing global static variable usage. See
   comments at top for description.  */

static void 
ipa_init (void) 
{
  memory_identifier_string = build_string(7, "memory");

  static_vars_to_consider_by_uid =
    splay_tree_new_ggc (splay_tree_compare_ints);

  module_statics_escape = BITMAP_XMALLOC ();
  all_module_statics = BITMAP_XMALLOC ();

  /* There are some shared nodes, in particular the initializers on
     static declarations.  We do not need to scan them more than once
     since all we would be interrested in are the addressof
     operations.  */
  visited_nodes = pointer_set_create ();
}

/* Check out the rhs of a static or global initialization VNODE to see
   if any of them contain addressof operations.  Note that some of
   these variables may not even be referenced in the code in this
   compilation unit but their right hand sides may contain references
   to variables defined within this unit.  */

static void 
analyze_variable (struct cgraph_varpool_node *vnode)
{
  tree global = vnode->decl;
  if (!memory_identifier_string) ipa_init();

  if (TREE_CODE (global) == VAR_DECL)
    if (DECL_INITIAL (global)) 
      walk_tree (&DECL_INITIAL (global), scan_for_static_refs, 
		 NULL, visited_nodes);
}

/* This is the main routine for finding the reference patterns for
   global variables within a function FN.  */

static void
analyze_function (struct cgraph_node *fn)
{
  tree decl = fn->decl;
  ipa_static_vars_info_t info 
    = xcalloc (1, sizeof (struct ipa_static_vars_info_d));
  ipa_local_static_vars_info_t l
    = xcalloc (1, sizeof (struct ipa_local_static_vars_info_d));
  var_ann_t var_ann = get_var_ann (fn->decl);

  if (!memory_identifier_string) ipa_init();

  /* Add the info to the tree's annotation.  */
  fn->static_vars_info = info;
  var_ann->static_vars_info = info;

  info->local = l;
  l->statics_read_by_decl_uid = BITMAP_XMALLOC ();
  l->statics_written_by_decl_uid = BITMAP_XMALLOC ();
  l->statics_read_by_ann_uid = BITMAP_XMALLOC ();
  l->statics_written_by_ann_uid = BITMAP_XMALLOC ();

  if (dump_file)
    fprintf (dump_file, "\n local analysis of %s", cgraph_node_name (fn));
  
  walk_tree (&DECL_SAVED_TREE (decl), scan_for_static_refs, fn, visited_nodes);
}

/* Produce the global information by preforming a transitive closure
   on the local information that was produced by ipa_analyze_function
   and ipa_analyze_variable.  */


static void
static_execute (void)
{
  struct cgraph_node *node;
  struct cgraph_node *w;
  struct cgraph_node **order =
    xcalloc (cgraph_n_nodes, sizeof (struct cgraph_node *));
  int order_pos = order_pos = reduced_inorder (order, false);
  int i;

  if (!memory_identifier_string) ipa_init();
  pointer_set_destroy (visited_nodes);
  visited_nodes = NULL;
  if (dump_file) 
    dump_cgraph (dump_file);

  /* Prune out the variables that were found to behave badly
     (i.e. have there address taken).  */
  {
    int index;
    bitmap_iterator bi;

    EXECUTE_IF_SET_IN_BITMAP (module_statics_escape, 0, index, bi)
      {
	splay_tree_remove (static_vars_to_consider_by_uid, index);
      }
    bitmap_operation (all_module_statics, all_module_statics,
		      module_statics_escape, BITMAP_AND_COMPL);

    BITMAP_XFREE(module_statics_escape);

    if (0) {
      FILE *ok_statics_file = fopen("/home/zadeck/ok_statics", "r");
      char line[100];
      int value;
      fgets(line, sizeof(line), ok_statics_file);
      sscanf(line, "%d", &value);
      for (i = 0; i < value; i++ )
   	{
   	  int j = bitmap_first_set_bit(all_module_statics);
 	  if (j == -1) break;
   	  fprintf(stderr, "  not considering %s\n",
   		  get_static_name_by_uid (j));
   	  splay_tree_remove (static_vars_to_consider_by_uid, j);
   	  bitmap_clear_bit(all_module_statics, j);
   	}
    }

    if (dump_file)
      EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi)
	{
	  fprintf (dump_file, "\nPromotable global:%s",
		   get_static_name_by_uid (index));
	}

    /* Remove any variables from the local maps that are not in
       all_module_statics.  This will include all of the variables
       that were found to escape in the function scanning.  */
    for (i = 0; i < order_pos; i++ )
      {
	ipa_local_static_vars_info_t l;
	node = order[i];
	l = node->static_vars_info->local;

	bitmap_a_and_b (l->statics_read_by_decl_uid, 
			l->statics_read_by_decl_uid,
			all_module_statics);
	bitmap_a_and_b (l->statics_written_by_decl_uid, 
			l->statics_written_by_decl_uid,
			all_module_statics);
      }
  }

  if (dump_file)
    {
      for (i = 0; i < order_pos; i++ )
	{
	  int index;
	  ipa_local_static_vars_info_t l;
	  bitmap_iterator bi;

	  node = order[i];
	  l = node->static_vars_info->local;
	  fprintf (dump_file, 
		   "\nFunction name:%s/%i:", 
		   cgraph_node_name (node), node->uid);
	  fprintf (dump_file, "\n  locals read: ");
	  EXECUTE_IF_SET_IN_BITMAP (l->statics_read_by_decl_uid,
				    0, index, bi)
	    {
	      fprintf (dump_file, "%s ",
		       get_static_name_by_uid (index));
	    }
	  fprintf (dump_file, "\n  locals written: ");
	  EXECUTE_IF_SET_IN_BITMAP (l->statics_written_by_decl_uid,
				    0, index, bi)
	    {
	      fprintf(dump_file, "%s ",
		      get_static_name_by_uid (index));
	    }
	}
    }

  /* Propagate the local information thru the call graph to produce
     the global information.  All the nodes within a cycle will have
     the same info so we collapse cycles first.  Then we can do the
     propagation in one pass from the leaves to the roots.  */
  order_pos = reduced_inorder (order, true);
  if (dump_file)
    print_order(dump_file, "reduced", order, order_pos);

  for (i = 0; i < order_pos; i++ )
    {
      ipa_static_vars_info_t node_info;
      ipa_global_static_vars_info_t node_g = 
	xcalloc (1, sizeof (struct ipa_global_static_vars_info_d));
      ipa_local_static_vars_info_t node_l;
      
      bool read_all;
      bool write_all;

      node = order[i];
      node_info = node->static_vars_info;
      if (!node_info) 
	{
	  dump_cgraph_node (stderr, node);
	  dump_cgraph (stderr);
	  abort ();
	}

      node_info->global = node_g;
      node_l = node_info->local;

      read_all = node->local.calls_read_all;
      write_all = node->local.calls_write_all;

      /* If any node in a cycle is calls_read_all or calls_write_all
	 they all are. */
      w = node->next_cycle;
      while (w)
	{
	  read_all |= w->local.calls_read_all;
	  write_all |= w->local.calls_write_all;
	  w = w->next_cycle;
	}

      /* Initialized the bitmaps for the reduced nodes */
      if (read_all) 
	node_g->statics_read_by_decl_uid = all_module_statics;
      else 
	{
	  node_g->statics_read_by_decl_uid = BITMAP_XMALLOC ();
	  bitmap_copy (node_g->statics_read_by_decl_uid, 
		       node_l->statics_read_by_decl_uid);
	}

      if (write_all) 
	node_g->statics_written_by_decl_uid = all_module_statics;
      else
	{
	  node_g->statics_written_by_decl_uid = BITMAP_XMALLOC ();
	  bitmap_copy (node_g->statics_written_by_decl_uid, 
		       node_l->statics_written_by_decl_uid);
	}

      w = node->next_cycle;
      while (w)
	{
	  ipa_static_vars_info_t w_info = w->static_vars_info;
	  ipa_local_static_vars_info_t w_l = w_info->local;

	  /* All nodes within a cycle share the same global info bitmaps.  */
	  w_info->global = node_g;
	  
	  /* These global bitmaps are initialized from the local info
	     of all of the nodes in the region.  However there is no
	     need to do any work if the bitmaps were set to
	     all_module_statics.  */
	  if (!read_all)
	    bitmap_a_or_b (node_g->statics_read_by_decl_uid,
			   node_g->statics_read_by_decl_uid,
			   w_l->statics_read_by_decl_uid);
	  if (!write_all)
	    bitmap_a_or_b (node_g->statics_written_by_decl_uid,
			   node_g->statics_written_by_decl_uid,
			   w_l->statics_written_by_decl_uid);
	  w = w->next_cycle;
	}

      propagate_bits (node);

      w = node->next_cycle;
      while (w)
	{
	  propagate_bits (w);
	  w = w->next_cycle;
	}
    }

  /* Need to fix up the local information sets.  The information that
     has been gathered so far is preinlining.  However, the
     compilation will progress post inlining so the local sets for the
     inlined calls need to be merged into the callers.  */
  for (i = 0; i < order_pos; i++ )
    {
      node = order[i];
      if (cgraph_is_immortal_master_clone (node))
	merge_callee_local_info (node, node);
    }

  if (dump_file)
    {
      for (i = 0; i < order_pos; i++ )
	{
	  ipa_static_vars_info_t node_info;
	  ipa_global_static_vars_info_t node_g;
	  ipa_local_static_vars_info_t node_l;
	  int index;
	  bitmap_iterator bi;

	  node = order[i];
	  node_info = node->static_vars_info;
	  node_g = node_info->global;
	  node_l = node_info->local;
	  fprintf (dump_file, 
		   "\nFunction name:%s/%i:", 
		   cgraph_node_name (node), node->uid);
	  w = node->next_cycle;
	  while (w) 
	    {
	      fprintf (dump_file, "\n  next cycle: %s/%i ",
		       cgraph_node_name (w), w->uid);
	      w = w->next_cycle;
	    }
	  fprintf (dump_file, "\n  locals read: ");
	  EXECUTE_IF_SET_IN_BITMAP (node_l->statics_read_by_decl_uid,
				    0, index, bi)
	    {
	      fprintf (dump_file, "%s ",
		       get_static_name_by_uid (index));
	    }
	  fprintf (dump_file, "\n  locals written: ");
	  EXECUTE_IF_SET_IN_BITMAP (node_l->statics_written_by_decl_uid,
				    0, index, bi)
	    {
	      fprintf(dump_file, "%s ",
		      get_static_name_by_uid (index));
	    }
	  fprintf (dump_file, "\n  globals read: ");
	  EXECUTE_IF_SET_IN_BITMAP (node_g->statics_read_by_decl_uid,
				    0, index, bi)
	    {
	      fprintf (dump_file, "%s ",
		       get_static_name_by_uid (index));
	    }
	  fprintf (dump_file, "\n  globals written: ");
	  EXECUTE_IF_SET_IN_BITMAP (node_g->statics_written_by_decl_uid,
				    0, index, bi)
	    {
	      fprintf (dump_file, "%s ",
		       get_static_name_by_uid (index));
	    }
	}
    }

  /* Cleanup. */
  for (i = 0; i < order_pos; i++ )
    {
      ipa_static_vars_info_t node_info;
      ipa_global_static_vars_info_t node_g;
      node = order[i];
      node_info = node->static_vars_info;
      node_g = node_info->global;
      
      node_g->var_anns_valid = false;

      /* Create the complimentary sets.  These are more useful for
	 certain apis.  */
      node_g->statics_not_read_by_decl_uid = BITMAP_XMALLOC ();
      node_g->statics_not_written_by_decl_uid = BITMAP_XMALLOC ();

      /* FIXME -- PROFILE-RESTRUCTURE: Delete next 4 assignments.  */
      node_g->statics_read_by_ann_uid = BITMAP_XMALLOC ();
      node_g->statics_written_by_ann_uid = BITMAP_XMALLOC ();
      node_g->statics_not_read_by_ann_uid = BITMAP_XMALLOC ();
      node_g->statics_not_written_by_ann_uid = BITMAP_XMALLOC ();

      if (node_g->statics_read_by_decl_uid != all_module_statics) 
	{
	  bitmap_operation (node_g->statics_not_read_by_decl_uid, 
			    all_module_statics,
			    node_g->statics_read_by_decl_uid,
			    BITMAP_AND_COMPL);
	}

      if (node_g->statics_written_by_decl_uid != all_module_statics) 
	bitmap_operation (node_g->statics_not_written_by_decl_uid, 
			  all_module_statics,
			  node_g->statics_written_by_decl_uid,
			  BITMAP_AND_COMPL);
      w = node;

      while (w)
	{
	  struct cgraph_node * last = w;
	  ipa_static_vars_info_t w_info = w->static_vars_info;
	  ipa_local_static_vars_info_t w_l = w_info->local;
	  w_l->var_anns_valid = false;

	  w = w->next_cycle;
	  last->next_cycle = NULL;
	}
    }

  free (order);
}


static bool
gate_static_vars (void)
{
  return flag_unit_at_a_time != 0;
}

struct tree_opt_pass pass_ipa_static =
{
  "static-var",				/* name */
  gate_static_vars,			/* gate */
  analyze_function,                     /* IPA function */
  analyze_variable,		        /* IPA variable */
  static_execute,			/* execute */
  NULL, NULL,				/* IPA modification */
  NULL,					/* sub */
  NULL,					/* next */
  0,					/* static_pass_number */
  0,				        /* tv_id */
  0,	                                /* properties_required */
  0,					/* properties_provided */
  0,					/* properties_destroyed */
  0,					/* todo_flags_start */
  0,                                    /* todo_flags_finish */
  0					/* letter */
};


#include "gt-ipa-static-vars-anal.h"
/* Callgraph handling code.
   Copyright (C) 2004 Free Software Foundation, Inc.
   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.  */

#ifndef GCC_IPA_STATIC_H
#define GCC_IPA_STATIC_H
#include "bitmap.h"
#include "tree.h"

/* The static variables defined within the compilation unit that are
   loaded or stored directly by function that owns this structure.  */ 

struct ipa_local_static_vars_info_d 
{
  bitmap statics_read_by_decl_uid;
  bitmap statics_written_by_decl_uid;
  bitmap statics_read_by_ann_uid;
  bitmap statics_written_by_ann_uid;

  /* Var_anns_valid is reset at the start of compilation for each
     function because the indexing that the "_var_anns" is based
     on is invalidated between function compilations.  This allows for
     lazy creation of the "_var_ann" variables.  */
  bool var_anns_valid;
};

struct ipa_global_static_vars_info_d
{
  bitmap statics_read_by_decl_uid;
  bitmap statics_written_by_decl_uid;
  bitmap statics_read_by_ann_uid;
  bitmap statics_written_by_ann_uid;
  bitmap statics_not_read_by_decl_uid;
  bitmap statics_not_written_by_decl_uid;
  bitmap statics_not_read_by_ann_uid;
  bitmap statics_not_written_by_ann_uid;

  /* Var_anns_valid is reset at the start of compilation for each
     function because the indexing that the "_var_anns" is based
     on is invalidated between function compilations.  This allows for
     lazy creation of the "_var_ann" variables.  */
  bool var_anns_valid;
};

/* Statics that are read and written by some set of functions. The
   local ones are based on the loads and stores local to the function.
   The global ones are based on the local info as well as the
   transitive closure of the functions that are called.  The
   structures are separated to allow the global structures to be
   shared between several functions since every function within a
   strongly connected component will have the same information.  This
   sharing saves both time and space in the computation of the vectors
   as well as their translation from decl_uid form to ann_uid
   form.  */ 

typedef struct ipa_local_static_vars_info_d *ipa_local_static_vars_info_t;
typedef struct ipa_global_static_vars_info_d *ipa_global_static_vars_info_t;

struct ipa_static_vars_info_d 
{
  ipa_local_static_vars_info_t local;
  ipa_global_static_vars_info_t global;
};

typedef struct ipa_static_vars_info_d *ipa_static_vars_info_t;

/* The cgraph data structure.
   Each function decl has assigned cgraph_node listing callees and callers.  */

/* In ipa-static-vars-anal.c  */
extern tree memory_identifier_string;

void   ipa_static_reset_maps (void);
bitmap ipa_get_statics_read_local (tree fn);
bitmap ipa_get_statics_written_local (tree fn);
bitmap ipa_get_statics_read_global (tree fn);
bitmap ipa_get_statics_written_global (tree fn);
bitmap ipa_get_statics_not_read_global (tree fn);
bitmap ipa_get_statics_not_written_global (tree fn);

#endif  /* GCC_IPA_STATIC_H  */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]