OSDN Git Service

PR target/38695
[pf3gnuchains/gcc-fork.git] / gcc / ipa-reference.c
index c28c732..a9afd45 100644 (file)
@@ -1,5 +1,5 @@
 /* Callgraph based analysis of static variables.
-   Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
 
 This file is part of GCC.
@@ -69,6 +69,52 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic.h"
 #include "langhooks.h"
 
+/* The static variables defined within the compilation unit that are
+   loaded or stored directly by function that owns this structure.  */ 
+
+struct ipa_reference_local_vars_info_d 
+{
+  bitmap statics_read;
+  bitmap statics_written;
+
+  /* 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;
+};
+
+/* 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.  */ 
+
+struct ipa_reference_global_vars_info_d
+{
+  bitmap statics_read;
+  bitmap statics_written;
+  bitmap statics_not_read;
+  bitmap statics_not_written;
+};
+
+typedef struct ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t;
+typedef struct ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t;
+struct ipa_reference_vars_info_d 
+{
+  ipa_reference_local_vars_info_t local;
+  ipa_reference_global_vars_info_t global;
+};
+
+typedef struct ipa_reference_vars_info_d *ipa_reference_vars_info_t;
+
 /* 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
@@ -93,7 +139,16 @@ static bitmap all_module_statics;
 
 static struct pointer_set_t *visited_nodes;
 
-static bitmap_obstack ipa_obstack;
+/* Obstack holding bitmaps of local analysis (live from analysis to
+   propagation)  */
+static bitmap_obstack local_info_obstack;
+/* Obstack holding global analysis live forever.  */
+static bitmap_obstack global_info_obstack;
+
+/* Holders of ipa cgraph hooks: */
+static struct cgraph_node_hook_list *function_insertion_hook_holder;
+static struct cgraph_2node_hook_list *node_duplication_hook_holder;
+static struct cgraph_node_hook_list *node_removal_hook_holder;
 
 enum initialization_status_t
 {
@@ -104,19 +159,37 @@ enum initialization_status_t
 
 tree memory_identifier_string;
 
+/* Vector where the reference var infos are actually stored. */
+DEF_VEC_P (ipa_reference_vars_info_t);
+DEF_VEC_ALLOC_P (ipa_reference_vars_info_t, heap);
+static VEC (ipa_reference_vars_info_t, heap) *ipa_reference_vars_vector;
+
 /* Return the ipa_reference_vars structure starting from the cgraph NODE.  */
 static inline ipa_reference_vars_info_t
-get_reference_vars_info_from_cgraph (struct cgraph_node * node)
+get_reference_vars_info (struct cgraph_node *node)
+{
+  if (!ipa_reference_vars_vector
+      || VEC_length (ipa_reference_vars_info_t, ipa_reference_vars_vector) <= (unsigned int)node->uid)
+    return NULL;
+  return VEC_index (ipa_reference_vars_info_t, ipa_reference_vars_vector, node->uid);
+}
+
+/* Return the ipa_reference_vars structure starting from the cgraph NODE.  */
+static inline void
+set_reference_vars_info (struct cgraph_node *node, ipa_reference_vars_info_t info)
 {
-  return get_function_ann (node->decl)->reference_vars_info;
+  if (!ipa_reference_vars_vector
+      || VEC_length (ipa_reference_vars_info_t, ipa_reference_vars_vector) <= (unsigned int)node->uid)
+     VEC_safe_grow_cleared (ipa_reference_vars_info_t, heap, ipa_reference_vars_vector, node->uid + 1);
+  VEC_replace (ipa_reference_vars_info_t, ipa_reference_vars_vector, node->uid, info);
 }
 
 /* Get a bitmap that contains all of the locally referenced static
    variables for function FN.  */
 static ipa_reference_local_vars_info_t
-get_local_reference_vars_info (tree fn) 
+get_local_reference_vars_info (struct cgraph_node *fn) 
 {
-  ipa_reference_vars_info_t info = get_function_ann (fn)->reference_vars_info;
+  ipa_reference_vars_info_t info = get_reference_vars_info (fn);
 
   if (info)
     return info->local;
@@ -129,9 +202,9 @@ get_local_reference_vars_info (tree fn)
    variables for function FN.  */
  
 static ipa_reference_global_vars_info_t
-get_global_reference_vars_info (tree fn) 
+get_global_reference_vars_info (struct cgraph_node *fn) 
 {
-  ipa_reference_vars_info_t info = get_function_ann (fn)->reference_vars_info;
+  ipa_reference_vars_info_t info = get_reference_vars_info (fn);
 
   if (info)
     return info->global;
@@ -141,39 +214,11 @@ get_global_reference_vars_info (tree fn)
 }
 
 /* Return a bitmap indexed by 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.  */
-
-bitmap 
-ipa_reference_get_read_local (tree fn)
-{
-  ipa_reference_local_vars_info_t l = get_local_reference_vars_info (fn);
-  if (l) 
-    return l->statics_read;
-  else
-    return NULL;
-}
-
-/* Return a bitmap indexed by 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.  */
-
-bitmap 
-ipa_reference_get_written_local (tree fn)
-{
-  ipa_reference_local_vars_info_t l = get_local_reference_vars_info (fn);
-  if (l) 
-    return l->statics_written;
-  else
-    return NULL;
-}
-
-/* Return a bitmap indexed by VAR_DECL uid for the static variables
    that are read during the execution of the function FN.  Returns
    NULL if no data is available.  */
 
 bitmap 
-ipa_reference_get_read_global (tree fn) 
+ipa_reference_get_read_global (struct cgraph_node *fn) 
 {
   ipa_reference_global_vars_info_t g = get_global_reference_vars_info (fn);
   if (g) 
@@ -188,7 +233,7 @@ ipa_reference_get_read_global (tree fn)
    call.  Returns NULL if no data is available.  */
 
 bitmap 
-ipa_reference_get_written_global (tree fn) 
+ipa_reference_get_written_global (struct cgraph_node *fn) 
 {
   ipa_reference_global_vars_info_t g = get_global_reference_vars_info (fn);
   if (g) 
@@ -202,7 +247,7 @@ ipa_reference_get_written_global (tree fn)
    NULL if no data is available.  */
 
 bitmap 
-ipa_reference_get_not_read_global (tree fn) 
+ipa_reference_get_not_read_global (struct cgraph_node *fn) 
 {
   ipa_reference_global_vars_info_t g = get_global_reference_vars_info (fn);
   if (g) 
@@ -217,7 +262,7 @@ ipa_reference_get_not_read_global (tree fn)
    call.  Returns NULL if no data is available.  */
 
 bitmap 
-ipa_reference_get_not_written_global (tree fn) 
+ipa_reference_get_not_written_global (struct cgraph_node *fn) 
 {
   ipa_reference_global_vars_info_t g = get_global_reference_vars_info (fn);
   if (g) 
@@ -235,6 +280,7 @@ static inline void
 add_static_var (tree var) 
 {
   int uid = DECL_UID (var);
+  gcc_assert (TREE_CODE (var) == VAR_DECL);
   if (!bitmap_bit_p (all_module_statics, uid))
     {
       splay_tree_insert (reference_vars_to_consider,
@@ -278,146 +324,52 @@ has_proper_scope_for_analysis (tree t)
   return true;
 }
 
-/* If T is a VAR_DECL for a static that we are interested in, add the
-   uid to the bitmap.  */
+/* Mark tree T as having address taken.  */
 
 static void
-check_operand (ipa_reference_local_vars_info_t local, 
-              tree t, bool checking_write)
+mark_address_taken (tree x)
 {
-  if (!t) return;
-
-  if ((TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL)
-      && (has_proper_scope_for_analysis (t))) 
-    {
-      if (checking_write)
-       {
-         if (local)
-           bitmap_set_bit (local->statics_written, DECL_UID (t));
-         /* Mark the write so we can tell which statics are
-            readonly.  */
-         bitmap_set_bit (module_statics_written, DECL_UID (t));
-       }
-      else if (local)
-       bitmap_set_bit (local->statics_read, DECL_UID (t));
-    }
+  if (TREE_CODE (x) == VAR_DECL
+      && module_statics_escape && has_proper_scope_for_analysis (x))
+    bitmap_set_bit (module_statics_escape, DECL_UID (x));
 }
 
-/* Examine tree T for references to static variables. All internal
-   references like array references or indirect references are added
-   to the READ_BM. Direct references are added to either READ_BM or
-   WRITE_BM depending on the value of CHECKING_WRITE.   */
+/* Mark load of T.  */
 
 static void
-check_tree (ipa_reference_local_vars_info_t local, tree t, bool checking_write)
+mark_load (ipa_reference_local_vars_info_t local, 
+          tree t)
 {
-  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 (local, TREE_OPERAND (t, 1), false);
-      t = TREE_OPERAND (t, 0);
-    }
-
-  /* The bottom of an indirect reference can only be read, not
-     written.  So just recurse and whatever we find, check it against
-     the read bitmaps.  */
-
-  /*  if (INDIRECT_REF_P (t) || TREE_CODE (t) == MEM_REF) */
-  /* FIXME when we have array_ref's of pointers.  */
-  if (INDIRECT_REF_P (t))
-    check_tree (local, TREE_OPERAND (t, 0), false);
-
-  if (SSA_VAR_P (t))
-    check_operand (local, t, checking_write);
+  if (TREE_CODE (t) == VAR_DECL
+      && has_proper_scope_for_analysis (t))
+    bitmap_set_bit (local->statics_read, DECL_UID (t));
 }
 
-/* Scan tree T to see if there are any addresses taken in within T.  */
+/* Mark store of T.  */
 
-static void 
-look_for_address_of (tree t)
+static void
+mark_store (ipa_reference_local_vars_info_t local, 
+          tree t)
 {
-  if (TREE_CODE (t) == ADDR_EXPR)
+  if (TREE_CODE (t) == VAR_DECL
+      && has_proper_scope_for_analysis (t))
     {
-      tree x = get_base_var (t);
-      if (TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == FUNCTION_DECL) 
-       if (has_proper_scope_for_analysis (x))
-         bitmap_set_bit (module_statics_escape, DECL_UID (x));
+      if (local)
+       bitmap_set_bit (local->statics_written, DECL_UID (t));
+      /* Mark the write so we can tell which statics are
+        readonly.  */
+      if (module_statics_written)
+       bitmap_set_bit (module_statics_written, DECL_UID (t));
     }
 }
 
-/* Check to see if T is a read or address of operation on a static var
-   we are interested in analyzing.  LOCAL is passed in to get access
-   to its bit vectors.  Local is NULL if this is called from a static
-   initializer.  */
-
-static void
-check_rhs_var (ipa_reference_local_vars_info_t local, tree t)
-{
-  look_for_address_of (t);
-
-  if (local == NULL) 
-    return;
-
-  check_tree(local, t, false);
-}
-
-/* Check to see if T is an assignment to a static var we are
-   interested in analyzing.  LOCAL is passed in to get access to its bit
-   vectors.  */
-
-static void
-check_lhs_var (ipa_reference_local_vars_info_t local, tree t)
-{
-  if (local == NULL) 
-    return;
-   
-  check_tree(local, t, true);
-}
-
-/* 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.  */
+/* Look for memory clobber and set read_all/write_all if present.  */
 
 static void
-get_asm_stmt_operands (ipa_reference_local_vars_info_t local, gimple stmt)
+check_asm_memory_clobber (ipa_reference_local_vars_info_t local, gimple stmt)
 {
-  size_t noutputs = gimple_asm_noutputs (stmt);
-  const char **oconstraints
-    = (const char **) alloca ((noutputs) * sizeof (const char *));
   size_t i;
   tree op;
-  const char *constraint;
-  bool allows_mem, allows_reg, is_inout;
-  
-  for (i = 0; i < noutputs; i++)
-    {
-      op = gimple_asm_output_op (stmt, i);
-      oconstraints[i] = constraint
-       = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op)));
-      parse_output_constraint (&constraint, i, 0, 0,
-                              &allows_mem, &allows_reg, &is_inout);
-      
-      check_lhs_var (local, TREE_VALUE (op));
-    }
-
-  for (i = 0; i < gimple_asm_ninputs (stmt); i++)
-    {
-      op = gimple_asm_input_op (stmt, i);
-      constraint
-       = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op)));
-      parse_input_constraint (&constraint, 0, 0, noutputs, 0,
-                             oconstraints, &allows_mem, &allows_reg);
-      
-      check_rhs_var (local, TREE_VALUE (op));
-    }
   
   for (i = 0; i < gimple_asm_nclobbers (stmt); i++)
     {
@@ -431,27 +383,14 @@ get_asm_stmt_operands (ipa_reference_local_vars_info_t local, gimple stmt)
     }
 }
 
-/* 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.  */
+/* Look for external calls and set read_all/write_all correspondingly.  */
 
 static void
 check_call (ipa_reference_local_vars_info_t local, gimple stmt)
 {
   int flags = gimple_call_flags (stmt);
-  tree operand;
   tree callee_t = gimple_call_fndecl (stmt);
   enum availability avail = AVAIL_NOT_AVAILABLE;
-  size_t i;
-
-  if ((operand = gimple_call_lhs (stmt)) != NULL)
-    check_lhs_var (local, operand);
-
-  for (i = 0; i < gimple_call_num_args (stmt); i++)
-    check_rhs_var (local, gimple_call_arg (stmt, i));
 
   if (callee_t)
     {
@@ -459,10 +398,12 @@ check_call (ipa_reference_local_vars_info_t local, gimple stmt)
       avail = cgraph_function_body_availability (callee);
     }
 
-  if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
+  if (avail <= AVAIL_OVERWRITABLE)
     if (local) 
       {
-       if (flags & ECF_PURE) 
+       if (flags & ECF_CONST) 
+         ;
+       else if (flags & ECF_PURE)
          local->calls_read_all = true;
        else 
          {
@@ -470,130 +411,78 @@ check_call (ipa_reference_local_vars_info_t local, gimple stmt)
            local->calls_write_all = true;
          }
       }
+   /* TODO: To be able to produce sane results, we should also handle
+      common builtins, in particular throw.
+      Indirect calls hsould be only counted and as inliner is replacing them
+      by direct calls, we can conclude if any indirect calls are left in body */
 }
 
 /* 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.  */
 
-/* FIXME: When this is converted to run over SSA form, this code
-   should be converted to use the operand scanner.  */
-
 static tree
-scan_stmt_for_static_refs (gimple_stmt_iterator *gsip, bool *handled_ops_p,
-                          struct walk_stmt_info *data)
+scan_stmt_for_static_refs (gimple_stmt_iterator *gsip,
+                          struct cgraph_node *fn)
 {
-  struct cgraph_node *fn = (struct cgraph_node *) data->info;
   gimple stmt = gsi_stmt (*gsip);
   ipa_reference_local_vars_info_t local = NULL;
+  unsigned int i;
+  bitmap_iterator bi;
+
   if (fn)
-    local = get_reference_vars_info_from_cgraph (fn)->local;
+    local = get_reference_vars_info (fn)->local;
+
+  if (gimple_loaded_syms (stmt))
+    EXECUTE_IF_SET_IN_BITMAP (gimple_loaded_syms (stmt), 0, i, bi)
+      mark_load (local, referenced_var_lookup (i));
+  if (gimple_stored_syms (stmt))
+    EXECUTE_IF_SET_IN_BITMAP (gimple_stored_syms (stmt), 0, i, bi)
+      mark_store (local, referenced_var_lookup (i));
+  if (gimple_addresses_taken (stmt))
+    EXECUTE_IF_SET_IN_BITMAP (gimple_addresses_taken (stmt), 0, i, bi)
+      mark_address_taken (referenced_var_lookup (i));
 
   switch (gimple_code (stmt))
     {
-    case GIMPLE_ASSIGN:
-      {
-       /* First look on the lhs and see what variable is stored to */
-       tree lhs = gimple_assign_lhs (stmt);
-       tree rhs1 = gimple_assign_rhs1 (stmt);
-       tree rhs2 = gimple_assign_rhs2 (stmt);
-       enum tree_code code = gimple_assign_rhs_code (stmt);
-
-       check_lhs_var (local, lhs);
-
-       /* For the purposes of figuring out what the cast affects */
-
-       /* Next check the operands on the rhs to see if they are ok. */
-       switch (TREE_CODE_CLASS (code))
-         {
-         case tcc_binary:          
-         case tcc_comparison:      
-           check_rhs_var (local, rhs1);
-           check_rhs_var (local, rhs2);
-           break;
-
-         case tcc_unary:
-         case tcc_reference:
-         case tcc_declaration:
-           check_rhs_var (local, rhs1);
-           break;
-
-         case tcc_expression:
-           switch (code)
-             {
-             case ADDR_EXPR:
-               check_rhs_var (local, rhs1);
-               break;
-             default:
-               break;
-             }
-           break;
-         default:
-           break;
-         }
-       *handled_ops_p = true;
-      }
-      break;
-
-    case GIMPLE_LABEL:
-      if (DECL_NONLOCAL (gimple_label_label (stmt)))
-       {
-         /* Target of long jump. */
-         local->calls_read_all = true;
-         local->calls_write_all = true;
-       }
-      break;
-
     case GIMPLE_CALL:
       check_call (local, stmt);
-      *handled_ops_p = true;
       break;
       
     case GIMPLE_ASM:
-      get_asm_stmt_operands (local, stmt);
-      *handled_ops_p = true;
+      check_asm_memory_clobber (local, stmt);
       break;
-      
+
+    /* We used to check nonlocal labels here and set them as potentially modifying
+       everything.  This is not needed, since we can get to nonlocal label only
+       from callee and thus we will get info propagated.  */
+
     default:
       break;
     }
+  
   return NULL;
 }
 
-/* Call-back to scan GIMPLE operands for static references.  This is supposed
-   to work with scan_stmt_for_static_refs so the real call-back data is stored
-   inside a walk_stmt_info struct.  Callers using the walk_tree interface must
-   also wrap the call-back data in a walk_stmt_info struct.  */
+/* Call-back to scan variable initializers for static references.  
+   Called using walk_tree.  */
 
 static tree
-scan_op_for_static_refs (tree *tp, int *walk_subtrees, void *data)
+scan_initializer_for_static_refs (tree *tp, int *walk_subtrees,
+                                 void *data ATTRIBUTE_UNUSED)
 {
-  struct walk_stmt_info *wi = (struct walk_stmt_info*) data;
-  struct cgraph_node *fn = (struct cgraph_node *) wi->info;
   tree t = *tp;
-  ipa_reference_local_vars_info_t local = NULL;
-  if (fn)
-    local = get_reference_vars_info_from_cgraph (fn)->local;
 
-  switch (TREE_CODE (t))  
+  if (TREE_CODE (t) == ADDR_EXPR)
     {
-    case VAR_DECL:
-      if (DECL_INITIAL (t))
-       walk_tree (&DECL_INITIAL (t), scan_op_for_static_refs, data,
-                  wi->pset);
-      *walk_subtrees = 0;
-      break;
-
-    case ADDR_EXPR:
-      /* This case is here to find addresses on rhs of constructors in
-        decl_initial of static variables. */
-      check_rhs_var (local, t);
+      mark_address_taken (get_base_var (t));
       *walk_subtrees = 0;
-      break;
-
-    default:
-      break;
     }
+  /* Save some cycles by not walking types and declaration as we
+     won't find anything useful there anyway.  */
+  else if (IS_TYPE_OR_DECL_P (*tp))
+    *walk_subtrees = 0;
   return NULL;
 }
 
@@ -621,29 +510,30 @@ get_static_name (int index)
   return NULL;
 }
 
-/* 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
+/* Or in all of the bits from every callee of X into X_GLOBAL, the caller's cycle,
+   bit vector.  There are several cases to check to avoid the sparse
    bitmap oring.  */
 
 static void
-propagate_bits (struct cgraph_node *x)
+propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x)
 {
-  ipa_reference_vars_info_t x_info = get_reference_vars_info_from_cgraph (x);
-  ipa_reference_global_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 (cgraph_function_body_availability (e->callee) > AVAIL_OVERWRITABLE)
        {
-         if (get_reference_vars_info_from_cgraph (y))
+         if (get_reference_vars_info (y))
            {
-             ipa_reference_vars_info_t y_info = get_reference_vars_info_from_cgraph (y);
+             ipa_reference_vars_info_t y_info 
+               = get_reference_vars_info (y);
              ipa_reference_global_vars_info_t y_global = y_info->global;
+
+             /* Calls in current cycle do not have global computed yet.  */
+             if (!y_info->global)
+               continue;
              
              if (x_global->statics_read
                  != all_module_statics)
@@ -682,75 +572,9 @@ propagate_bits (struct cgraph_node *x)
                }
            }
          else 
-           {
-             gcc_unreachable ();
-           }
-       }
-    }
-}
-
-/* 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.  
-
-   This function goes away when Jan changes the inliner and IPA
-   analysis so that this is not run between the time when inlining
-   decisions are made and when the inlining actually occurs.  */
-
-static void 
-merge_callee_local_info (struct cgraph_node *target, 
-                        struct cgraph_node *x)
-{
-  struct cgraph_edge *e;
-  ipa_reference_local_vars_info_t x_l = 
-    get_reference_vars_info_from_cgraph (target)->local;
-
-  /* Make the world safe for tail recursion.  */
-  struct ipa_dfs_info *node_info = (struct ipa_dfs_info *) x->aux;
-  
-  if (node_info->aux) 
-    return;
-
-  node_info->aux = x;
-
-  for (e = x->callees; e; e = e->next_callee) 
-    {
-      struct cgraph_node *y = e->callee;
-      if (y->global.inlined_to) 
-       {
-         ipa_reference_vars_info_t y_info;
-         ipa_reference_local_vars_info_t y_l;
-         struct cgraph_node* orig_y = y;
-        
-         y = cgraph_master_clone (y);
-         if (y)
-           {
-             y_info = get_reference_vars_info_from_cgraph (y);
-             y_l = y_info->local;
-             if (x_l != y_l)
-               {
-                 bitmap_ior_into (x_l->statics_read,
-                                  y_l->statics_read);
-                 bitmap_ior_into (x_l->statics_written,
-                                  y_l->statics_written);
-               }
-             x_l->calls_read_all |= y_l->calls_read_all;
-             x_l->calls_write_all |= y_l->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);
-           }
+           gcc_unreachable ();
        }
     }
-
-  node_info->aux = NULL;
 }
 
 /* The init routine for analyzing global static variable usage.  See
@@ -758,20 +582,16 @@ merge_callee_local_info (struct cgraph_node *target,
 static void 
 ipa_init (void) 
 {
-  struct cgraph_node *node;
   memory_identifier_string = build_string(7, "memory");
 
   reference_vars_to_consider =
     splay_tree_new_ggc (splay_tree_compare_ints);
 
-  bitmap_obstack_initialize (&ipa_obstack);
-  module_statics_escape = BITMAP_ALLOC (&ipa_obstack);
-  module_statics_written = BITMAP_ALLOC (&ipa_obstack);
-  all_module_statics = BITMAP_ALLOC (&ipa_obstack);
-
-  /* This will add NODE->DECL to the splay trees.  */
-  for (node = cgraph_nodes; node; node = node->next)
-    has_proper_scope_for_analysis (node->decl);
+  bitmap_obstack_initialize (&local_info_obstack);
+  bitmap_obstack_initialize (&global_info_obstack);
+  module_statics_escape = BITMAP_ALLOC (&local_info_obstack);
+  module_statics_written = BITMAP_ALLOC (&local_info_obstack);
+  all_module_statics = BITMAP_ALLOC (&global_info_obstack);
 
   /* There are some shared nodes, in particular the initializers on
      static declarations.  We do not need to scan them more than once
@@ -794,103 +614,99 @@ analyze_variable (struct varpool_node *vnode)
 
   memset (&wi, 0, sizeof (wi));
   wi.pset = visited_nodes;
-  walk_tree (&DECL_INITIAL (global), scan_op_for_static_refs,
+  walk_tree (&DECL_INITIAL (global), scan_initializer_for_static_refs,
              &wi, wi.pset);
 }
 
-/* This is the main routine for finding the reference patterns for
-   global variables within a function FN.  */
+/* Set up the persistent info for FN.  */
 
-static void
-analyze_function (struct cgraph_node *fn)
+static ipa_reference_local_vars_info_t
+init_function_info (struct cgraph_node *fn)
 {
   ipa_reference_vars_info_t info 
     = XCNEW (struct ipa_reference_vars_info_d);
   ipa_reference_local_vars_info_t l
     = XCNEW (struct ipa_reference_local_vars_info_d);
-  tree decl = fn->decl;
-  struct walk_stmt_info wi;
 
   /* Add the info to the tree's annotation.  */
-  get_function_ann (fn->decl)->reference_vars_info = info;
+  set_reference_vars_info (fn, info);
 
   info->local = l;
-  l->statics_read = BITMAP_ALLOC (&ipa_obstack);
-  l->statics_written = BITMAP_ALLOC (&ipa_obstack);
+  l->statics_read = BITMAP_ALLOC (&local_info_obstack);
+  l->statics_written = BITMAP_ALLOC (&local_info_obstack);
 
-  if (dump_file)
-    fprintf (dump_file, "\n local analysis of %s\n", cgraph_node_name (fn));
-  
-  {
-    struct function *this_cfun = DECL_STRUCT_FUNCTION (decl);
-    basic_block this_block;
+  return l;
+}
 
-    FOR_EACH_BB_FN (this_block, this_cfun)
-      {
-       gimple_stmt_iterator gsi;
-       gimple phi;
-       tree op;
-       use_operand_p use;
-       ssa_op_iter iter;
-
-       /* Find the addresses taken in phi node arguments.  */
-       for (gsi = gsi_start_phis (this_block);
-            !gsi_end_p (gsi);
-            gsi_next (&gsi))
-         {
-           phi = gsi_stmt (gsi);
-           FOR_EACH_PHI_ARG (use, phi, iter, SSA_OP_USE)
-             {
-               op = USE_FROM_PTR (use);
-               if (TREE_CODE (op) == ADDR_EXPR)
-                 check_rhs_var (l, op);
-             }
-         }
+/* 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;
+  struct function *this_cfun = DECL_STRUCT_FUNCTION (decl);
+  basic_block this_block;
+#ifdef ENABLE_CHECKING
+  tree step;
+#endif
 
-       memset (&wi, 0, sizeof (wi));
-       wi.info = fn;
-       wi.pset = visited_nodes;
-       for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi))
-         walk_gimple_stmt (&gsi, scan_stmt_for_static_refs,
-                           scan_op_for_static_refs, &wi);
-      }
-  }
+  if (dump_file)
+    fprintf (dump_file, "\n local analysis of %s\n", cgraph_node_name (fn));
 
-  /* There may be const decls with interesting right hand sides.  */
-  if (DECL_STRUCT_FUNCTION (decl))
+  push_cfun (DECL_STRUCT_FUNCTION (decl));
+  current_function_decl = decl;
+  
+  init_function_info (fn);
+  FOR_EACH_BB_FN (this_block, this_cfun)
     {
-      tree step;
-      for (step = DECL_STRUCT_FUNCTION (decl)->local_decls;
-          step;
-          step = TREE_CHAIN (step))
+      gimple_stmt_iterator gsi;
+      gimple phi;
+      tree op;
+      use_operand_p use;
+      ssa_op_iter iter;
+
+      /* Find the addresses taken in phi node arguments.  */
+      for (gsi = gsi_start_phis (this_block);
+          !gsi_end_p (gsi);
+          gsi_next (&gsi))
        {
-         tree var = TREE_VALUE (step);
-         if (TREE_CODE (var) == VAR_DECL 
-             && DECL_INITIAL (var)
-             && !TREE_STATIC (var))
+         phi = gsi_stmt (gsi);
+         FOR_EACH_PHI_ARG (use, phi, iter, SSA_OP_USE)
            {
-             memset (&wi, 0, sizeof (wi));
-             wi.info = fn;
-             wi.pset = visited_nodes;
-             walk_tree (&DECL_INITIAL (var), scan_op_for_static_refs,
-                        &wi, wi.pset);
+             op = USE_FROM_PTR (use);
+             if (TREE_CODE (op) == ADDR_EXPR)
+               mark_address_taken (get_base_var (op));
            }
        }
+
+      for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi))
+       scan_stmt_for_static_refs (&gsi, fn);
     }
-}
 
-/* If FN is avail == AVAIL_OVERWRITABLE, replace the effects bit
-   vectors with worst case bit vectors.  We had to analyze it above to
-   find out if it took the address of any statics. However, now that
-   we know that, we can get rid of all of the other side effects.  */
+#ifdef ENABLE_CHECKING
+  /* Verify that all local initializers was expanded by gimplifier.  */
+  for (step = DECL_STRUCT_FUNCTION (decl)->local_decls;
+       step;
+       step = TREE_CHAIN (step))
+    {
+      tree var = TREE_VALUE (step);
+      if (TREE_CODE (var) == VAR_DECL 
+         && DECL_INITIAL (var)
+         && !TREE_STATIC (var))
+       gcc_unreachable ();
+    }
+#endif
+  pop_cfun ();
+  current_function_decl = NULL;
+}
 
+/* Remove local data associated with function FN.  */
 static void
-clean_function (struct cgraph_node *fn)
+clean_function_local_data (struct cgraph_node *fn)
 {
-  ipa_reference_vars_info_t info = get_reference_vars_info_from_cgraph (fn);
+  ipa_reference_vars_info_t info = get_reference_vars_info (fn);
   ipa_reference_local_vars_info_t l = info->local;
-  ipa_reference_global_vars_info_t g = info->global;
-  
   if (l)
     {
       if (l->statics_read
@@ -900,8 +716,19 @@ clean_function (struct cgraph_node *fn)
          &&l->statics_written != all_module_statics)
        BITMAP_FREE (l->statics_written);
       free (l);
+      info->local = NULL;
     }
+}
+
+/* Remove all data associated with function FN.  */
+
+static void
+clean_function (struct cgraph_node *fn)
+{
+  ipa_reference_vars_info_t info = get_reference_vars_info (fn);
+  ipa_reference_global_vars_info_t g = info->global;
   
+  clean_function_local_data (fn);
   if (g)
     {
       if (g->statics_read
@@ -920,30 +747,117 @@ clean_function (struct cgraph_node *fn)
          && g->statics_not_written != all_module_statics)
        BITMAP_FREE (g->statics_not_written);
       free (g);
+      info->global = NULL;
     }
-
   
-  free (get_function_ann (fn->decl)->reference_vars_info);
-  get_function_ann (fn->decl)->reference_vars_info = NULL;
+  free (get_reference_vars_info (fn));
+  set_reference_vars_info (fn, NULL);
 }
 
-\f
-/* Produce the global information by preforming a transitive closure
-   on the local information that was produced by ipa_analyze_function
-   and ipa_analyze_variable.  */
+/* Called when new function is inserted to callgraph late.  */
+static void
+add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+{
+  /* 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 interested in are the addressof
+     operations.  */
+  analyze_function (node);
+  visited_nodes = NULL;
+}
 
-static unsigned int
-static_execute (void)
+static bitmap
+copy_local_bitmap (bitmap src)
+{
+  bitmap dst;
+  if (!src)
+    return NULL;
+  if (src == all_module_statics)
+    return all_module_statics;
+  dst = BITMAP_ALLOC (&local_info_obstack);
+  bitmap_copy (dst, src);
+  return dst;
+}
+
+static bitmap
+copy_global_bitmap (bitmap src)
+{
+  bitmap dst;
+  if (!src)
+    return NULL;
+  if (src == all_module_statics)
+    return all_module_statics;
+  dst = BITMAP_ALLOC (&global_info_obstack);
+  bitmap_copy (dst, src);
+  return dst;
+}
+
+/* Called when new clone is inserted to callgraph late.  */
+
+static void
+duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
+                    void *data ATTRIBUTE_UNUSED)
+{
+  ipa_reference_global_vars_info_t ginfo;
+  ipa_reference_local_vars_info_t linfo;
+  ipa_reference_global_vars_info_t dst_ginfo;
+  ipa_reference_local_vars_info_t dst_linfo;
+
+  ginfo = get_global_reference_vars_info (src);
+  linfo = get_local_reference_vars_info (src);
+  if (!linfo && !ginfo)
+    return;
+  init_function_info (dst);
+  if (linfo)
+    {
+      dst_linfo = get_local_reference_vars_info (dst);
+      dst_linfo->statics_read = copy_local_bitmap (linfo->statics_read);
+      dst_linfo->statics_written = copy_local_bitmap (linfo->statics_written);
+      dst_linfo->calls_read_all = linfo->calls_read_all;
+      dst_linfo->calls_write_all = linfo->calls_write_all;
+    }
+  if (ginfo)
+    {
+      get_reference_vars_info (dst)->global = XCNEW (struct ipa_reference_global_vars_info_d);
+      dst_ginfo = get_global_reference_vars_info (dst);
+      dst_ginfo->statics_read = copy_global_bitmap (ginfo->statics_read);
+      dst_ginfo->statics_written = copy_global_bitmap (ginfo->statics_written);
+      dst_ginfo->statics_not_read = copy_global_bitmap (ginfo->statics_not_read);
+      dst_ginfo->statics_not_written = copy_global_bitmap (ginfo->statics_not_written);
+    }
+}
+
+/* Called when node is removed.  */
+
+static void
+remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+{
+  if (get_reference_vars_info (node))
+    clean_function (node);
+}
+
+/* Analyze each function in the cgraph to see which global or statics
+   are read or written.  */
+
+static void 
+generate_summary (void)
 {
   struct cgraph_node *node;
   struct varpool_node *vnode;
-  struct cgraph_node *w;
-  struct cgraph_node **order =
-    XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
-  int order_pos = ipa_utils_reduced_inorder (order, false, true);
-  int i;
-
+  unsigned int index;
+  bitmap_iterator bi;
+  bitmap module_statics_readonly;
+  bitmap bm_temp;
+  
+  function_insertion_hook_holder =
+      cgraph_add_function_insertion_hook (&add_new_function, NULL);
+  node_removal_hook_holder =
+      cgraph_add_node_removal_hook (&remove_node_data, NULL);
+  node_duplication_hook_holder =
+      cgraph_add_node_duplication_hook (&duplicate_node_data, NULL);
   ipa_init ();
+  module_statics_readonly = BITMAP_ALLOC (&local_info_obstack);
+  bm_temp = BITMAP_ALLOC (&local_info_obstack);
 
   /* Process all of the variables first.  */
   FOR_EACH_STATIC_INITIALIZER (vnode)
@@ -961,114 +875,98 @@ static_execute (void)
      replaced with worst case info.  
   */
   for (node = cgraph_nodes; node; node = node->next)
-    if (node->analyzed 
-       && (cgraph_is_master_clone (node)
-           || (cgraph_function_body_availability (node) 
-               == AVAIL_OVERWRITABLE)))
+    if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
       analyze_function (node);
 
   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 their address taken).  */
-  {
-    unsigned int index;
-    bitmap_iterator bi;
-    bitmap module_statics_readonly = BITMAP_ALLOC (&ipa_obstack);
-    bitmap bm_temp = BITMAP_ALLOC (&ipa_obstack);
-
-    EXECUTE_IF_SET_IN_BITMAP (module_statics_escape, 0, index, bi)
-      {
-       splay_tree_remove (reference_vars_to_consider, index);
-      }
-
-    bitmap_and_compl_into (all_module_statics, 
-                          module_statics_escape);
-
-    bitmap_and_compl (module_statics_readonly, all_module_statics,
-                     module_statics_written);
-
-    /* If the address is not taken, we can unset the addressable bit
-       on this variable.  */
+  EXECUTE_IF_SET_IN_BITMAP (module_statics_escape, 0, index, bi)
+    {
+      splay_tree_remove (reference_vars_to_consider, index);
+    }
+  
+  bitmap_and_compl_into (all_module_statics, 
+                        module_statics_escape);
+  
+  bitmap_and_compl (module_statics_readonly, all_module_statics,
+                   module_statics_written);
+  
+  /* If the address is not taken, we can unset the addressable bit
+     on this variable.  */
+  EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi)
+    {
+      tree var = get_static_decl (index);
+      TREE_ADDRESSABLE (var) = 0;
+      if (dump_file) 
+       fprintf (dump_file, "Not TREE_ADDRESSABLE var %s\n",
+                get_static_name (index));
+    }
+  
+  /* If the variable is never written, we can set the TREE_READONLY
+     flag.  Additionally if it has a DECL_INITIAL that is made up of
+     constants we can treat the entire global as a constant.  */
+  
+  bitmap_and_compl (module_statics_readonly, all_module_statics,
+                   module_statics_written);
+  EXECUTE_IF_SET_IN_BITMAP (module_statics_readonly, 0, index, bi)
+    {
+      tree var = get_static_decl (index);
+      
+      /* Ignore variables in named sections - changing TREE_READONLY
+        changes the section flags, potentially causing conflicts with
+        other variables in the same named section.  */
+      if (DECL_SECTION_NAME (var) == NULL_TREE)
+       {
+         TREE_READONLY (var) = 1;
+         if (dump_file)
+           fprintf (dump_file, "read-only var %s\n", 
+                    get_static_name (index));
+       }
+    }
+  
+  BITMAP_FREE(module_statics_escape);
+  BITMAP_FREE(module_statics_written);
+  module_statics_escape = NULL;
+  module_statics_written = NULL;
+  
+  if (dump_file)
     EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi)
       {
-       tree var = get_static_decl (index);
-       TREE_ADDRESSABLE (var) = 0;
-       if (dump_file) 
-         fprintf (dump_file, "Not TREE_ADDRESSABLE var %s\n",
-                  get_static_name (index));
-      }
-
-    /* If the variable is never written, we can set the TREE_READONLY
-       flag.  Additionally if it has a DECL_INITIAL that is made up of
-       constants we can treat the entire global as a constant.  */
-
-    bitmap_and_compl (module_statics_readonly, all_module_statics,
-                     module_statics_written);
-    EXECUTE_IF_SET_IN_BITMAP (module_statics_readonly, 0, index, bi)
-      {
-       tree var = get_static_decl (index);
-
-       /* Readonly on a function decl is very different from the
-          variable.  */
-       if (TREE_CODE (var) == FUNCTION_DECL)
-         continue;
-
-       /* Ignore variables in named sections - changing TREE_READONLY
-          changes the section flags, potentially causing conflicts with
-          other variables in the same named section.  */
-       if (DECL_SECTION_NAME (var) == NULL_TREE)
-         {
-           TREE_READONLY (var) = 1;
-           if (dump_file)
-             fprintf (dump_file, "read-only var %s\n", 
-                      get_static_name (index));
-         }
+       fprintf (dump_file, "\nPromotable global:%s",
+                get_static_name (index));
       }
-
-    BITMAP_FREE(module_statics_escape);
-    BITMAP_FREE(module_statics_written);
-
-    if (dump_file)
-      EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi)
-       {
-         fprintf (dump_file, "\nPromotable global:%s",
-                  get_static_name (index));
-       }
-
-    for (i = 0; i < order_pos; i++ )
+  
+  for (node = cgraph_nodes; node; node = node->next)
+    if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
       {
        ipa_reference_local_vars_info_t l;
-       node = order[i];
-       l = get_reference_vars_info_from_cgraph (node)->local;
-
+       l = get_reference_vars_info (node)->local;
+       
        /* Any variables that are not in all_module_statics are
           removed from the local maps.  This will include all of the
           variables that were found to escape in the function
           scanning.  */
        bitmap_and_into (l->statics_read, 
-                        all_module_statics);
+                        all_module_statics);
        bitmap_and_into (l->statics_written, 
-                        all_module_statics);
+                        all_module_statics);
       }
-
-    BITMAP_FREE(module_statics_readonly);
-    BITMAP_FREE(bm_temp);
-  }
-
+  
+  BITMAP_FREE(module_statics_readonly);
+  BITMAP_FREE(bm_temp);
+  
   if (dump_file)
-    {
-      for (i = 0; i < order_pos; i++ )
+    for (node = cgraph_nodes; node; node = node->next)
+      if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
        {
-         unsigned int index;
          ipa_reference_local_vars_info_t l;
+         unsigned int index;
          bitmap_iterator bi;
-
-         node = order[i];
-         l = get_reference_vars_info_from_cgraph (node)->local;
+         
+         l = get_reference_vars_info (node)->local;
          fprintf (dump_file, 
                   "\nFunction name:%s/%i:", 
                   cgraph_node_name (node), node->uid);
@@ -1086,8 +984,30 @@ static_execute (void)
              fprintf(dump_file, "%s ",
                      get_static_name (index));
            }
+         if (l->calls_read_all)
+            fprintf (dump_file, "\n  calls read all: ");
+         if (l->calls_write_all)
+            fprintf (dump_file, "\n  calls read all: ");
        }
-    }
+}
+\f
+/* 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 unsigned int
+propagate (void)
+{
+  struct cgraph_node *node;
+  struct cgraph_node *w;
+  struct cgraph_node **order =
+    XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
+  int order_pos = ipa_utils_reduced_inorder (order, false, true);
+  int i;
+
+  cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
+  if (dump_file) 
+    dump_cgraph (dump_file);
 
   /* Propagate the local information thru the call graph to produce
      the global information.  All the nodes within a cycle will have
@@ -1109,7 +1029,7 @@ static_execute (void)
       struct ipa_dfs_info * w_info;
 
       node = order[i];
-      node_info = get_reference_vars_info_from_cgraph (node);
+      node_info = get_reference_vars_info (node);
       if (!node_info) 
        {
          dump_cgraph_node (stderr, node);
@@ -1117,7 +1037,7 @@ static_execute (void)
          gcc_unreachable ();
        }
 
-      node_info->global = node_g;
+      gcc_assert (!node_info->global);
       node_l = node_info->local;
 
       read_all = node_l->calls_read_all;
@@ -1130,7 +1050,7 @@ static_execute (void)
       while (w)
        {
          ipa_reference_local_vars_info_t w_l = 
-           get_reference_vars_info_from_cgraph (w)->local;
+           get_reference_vars_info (w)->local;
          read_all |= w_l->calls_read_all;
          write_all |= w_l->calls_write_all;
 
@@ -1143,7 +1063,7 @@ static_execute (void)
        node_g->statics_read = all_module_statics;
       else 
        {
-         node_g->statics_read = BITMAP_ALLOC (&ipa_obstack);
+         node_g->statics_read = BITMAP_ALLOC (&global_info_obstack);
          bitmap_copy (node_g->statics_read, 
                       node_l->statics_read);
        }
@@ -1152,21 +1072,19 @@ static_execute (void)
        node_g->statics_written = all_module_statics;
       else
        {
-         node_g->statics_written = BITMAP_ALLOC (&ipa_obstack);
+         node_g->statics_written = BITMAP_ALLOC (&global_info_obstack);
          bitmap_copy (node_g->statics_written, 
                       node_l->statics_written);
        }
 
+      propagate_bits (node_g, node);
       w_info = (struct ipa_dfs_info *) node->aux;
       w = w_info->next_cycle;
       while (w)
        {
          ipa_reference_vars_info_t w_ri = 
-           get_reference_vars_info_from_cgraph (w);
+           get_reference_vars_info (w);
          ipa_reference_local_vars_info_t w_l = w_ri->local;
-
-         /* All nodes within a cycle share the same global info bitmaps.  */
-         w_ri->global = node_g;
          
          /* These global bitmaps are initialized from the local info
             of all of the nodes in the region.  However there is no
@@ -1178,36 +1096,25 @@ static_execute (void)
          if (!write_all)
            bitmap_ior_into (node_g->statics_written,
                             w_l->statics_written);
+         propagate_bits (node_g, w);
          w_info = (struct ipa_dfs_info *) w->aux;
          w = w_info->next_cycle;
        }
 
-      w = node;
-      while (w)
-       {
-         propagate_bits (w);
-         w_info = (struct ipa_dfs_info *) w->aux;
-         w = w_info->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.  Note that the
-     local sets are not shared between all of the nodes in a cycle so
-     those nodes in the cycle must be processed explicitly.  */
-  for (i = 0; i < order_pos; i++ )
-    {
-      struct ipa_dfs_info * w_info;
-      node = order[i];
-      merge_callee_local_info (node, node);
-      
+      /* All nodes within a cycle have the same global info bitmaps.  */
+      node_info->global = node_g;
       w_info = (struct ipa_dfs_info *) node->aux;
       w = w_info->next_cycle;
       while (w)
        {
-         merge_callee_local_info (w, w);
+         ipa_reference_vars_info_t w_ri = 
+           get_reference_vars_info (w);
+
+         gcc_assert (!w_ri->global);
+          w_ri->global = XCNEW (struct ipa_reference_global_vars_info_d);
+         w_ri->global->statics_read = copy_global_bitmap (node_g->statics_read);
+         w_ri->global->statics_written = copy_global_bitmap (node_g->statics_written);
+
          w_info = (struct ipa_dfs_info *) w->aux;
          w = w_info->next_cycle;
        }
@@ -1225,7 +1132,7 @@ static_execute (void)
          struct ipa_dfs_info * w_info;
 
          node = order[i];
-         node_info = get_reference_vars_info_from_cgraph (node);
+         node_info = get_reference_vars_info (node);
          node_g = node_info->global;
          node_l = node_info->local;
          fprintf (dump_file, 
@@ -1251,7 +1158,7 @@ static_execute (void)
          while (w) 
            {
              ipa_reference_vars_info_t w_ri = 
-               get_reference_vars_info_from_cgraph (w);
+               get_reference_vars_info (w);
              ipa_reference_local_vars_info_t w_l = w_ri->local;
              fprintf (dump_file, "\n  next cycle: %s/%i ",
                       cgraph_node_name (w), w->uid);
@@ -1298,20 +1205,18 @@ static_execute (void)
       ipa_reference_vars_info_t node_info;
       ipa_reference_global_vars_info_t node_g;
       node = order[i];
-      node_info = get_reference_vars_info_from_cgraph (node);
+      node_info = get_reference_vars_info (node);
       node_g = node_info->global;
       
       /* Create the complimentary sets.  These are more useful for
         certain apis.  */
-      node_g->statics_not_read = BITMAP_ALLOC (&ipa_obstack);
-      node_g->statics_not_written = BITMAP_ALLOC (&ipa_obstack);
+      node_g->statics_not_read = BITMAP_ALLOC (&global_info_obstack);
+      node_g->statics_not_written = BITMAP_ALLOC (&global_info_obstack);
 
       if (node_g->statics_read != all_module_statics) 
-       {
-         bitmap_and_compl (node_g->statics_not_read, 
-                           all_module_statics,
-                           node_g->statics_read);
-       }
+       bitmap_and_compl (node_g->statics_not_read, 
+                         all_module_statics,
+                         node_g->statics_read);
 
       if (node_g->statics_written 
          != all_module_statics) 
@@ -1324,6 +1229,8 @@ static_execute (void)
 
   for (node = cgraph_nodes; node; node = node->next)
     {
+      ipa_reference_vars_info_t node_info;
+      node_info = get_reference_vars_info (node);
       /* Get rid of the aux information.  */
       
       if (node->aux)
@@ -1332,10 +1239,12 @@ static_execute (void)
          node->aux = NULL;
        }
       
-      if (node->analyzed 
-         && (cgraph_function_body_availability (node) == AVAIL_OVERWRITABLE))
+      if (cgraph_function_body_availability (node) == AVAIL_OVERWRITABLE)
        clean_function (node);
+      else if (node_info)
+       clean_function_local_data (node);
     }
+  bitmap_obstack_release (&local_info_obstack);
   return 0;
 }
 
@@ -1348,13 +1257,13 @@ gate_reference (void)
          && !(errorcount || sorrycount));
 }
 
-struct simple_ipa_opt_pass pass_ipa_reference =
+struct ipa_opt_pass pass_ipa_reference =
 {
  {
-  SIMPLE_IPA_PASS,
+  IPA_PASS,
   "static-var",                                /* name */
   gate_reference,                      /* gate */
-  static_execute,                      /* execute */
+  propagate,                           /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
@@ -1364,7 +1273,14 @@ struct simple_ipa_opt_pass pass_ipa_reference =
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   0                                     /* todo_flags_finish */
- }
+ },
+ generate_summary,                     /* generate_summary */
+ NULL,                                 /* write_summary */
+ NULL,                                 /* read_summary */
+ NULL,                                 /* function_read_summary */
+ 0,                                    /* TODOs */
+ NULL,                                 /* function_transform */
+ NULL                                  /* variable_transform */
 };
 
 #include "gt-ipa-reference.h"