OSDN Git Service

* lto-symtab.c (lto_symtab_entry_def) Add vnode.
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 29 Apr 2010 07:10:38 +0000 (07:10 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 29 Apr 2010 07:10:38 +0000 (07:10 +0000)
(lto_varpool_replace_node): New.
(lto_symtab_resolve_symbols): Resolve varpool nodes.
(lto_symtab_merge_decls_1): Prefer decls with varpool node.
(lto_symtab_merge_cgraph_nodes_1): Merge varpools.
* cgraph.h (varpool_node_ptr): New type.
(varpool_node_ptr): New vector.
(varpool_node_set_def): New structure.
(varpool_node_set): New type.
(varpool_node_set): New vector.
(varpool_node_set_element_def): New structure.
(varpool_node_set_element, const_varpool_node_set_element): New types.
(varpool_node_set_iterator): New type.
(varpool_node): Add prev pointers, add used_from_other_partition,
in_other_partition.
(varpool_node_set_new, varpool_node_set_find, varpool_node_set_add,
varpool_node_set_remove, dump_varpool_node_set, debug_varpool_node_set,
varpool_get_node, varpool_remove_node): Declare.
(vsi_end_p, vsi_next, vsi_node, vsi_start, varpool_node_in_set_p,
varpool_node_set_size): New inlines.
* cgraph.c (dump_cgraph_node): Dump asm names of aliases.
* tree-pass.h (varpool_node_set_def): Forward declare.
(ipa_opt_pass_d): Summary writting takes vnode sets too.
(ipa_write_optimization_summaries): Update prototype.
* ipa-cp.c (ipcp_write_summary): Update.
* ipa-reference.c (ipa_reference_write_summary): Update.
* lto-cgraph.c (lto_output_varpool_node): New static function.
(output_varpool): New function.
(input_varpool_node): New static function.
(input_varpool_1): New function.
(input_cgraph): Input varpool.
* ipa-pure-const.c (pure_const_write_summary): Update.
* lto-streamer-out.c (lto_output): Update, output varpool too.
(write_global_stream): Kill WPA hack.
(produce_asm_for_decls): Update.
(output_alias_pair_p): Handle variables.
(output_unreferenced_globals): Output only needed partition of varpool.
* ipa-inline.c (inline_write_summary): Update.
* lto-streamer-in.c (lto_input_tree_ref, lto_input_tree): Do not build cgraph.
* lto-section-in.c (lto_section_name): Add varpool and jump funcs.
* ipa.c (hash_varpool_node_set_element, eq_varpool_node_set_element,
varpool_node_set_new, varpool_node_set_add,
varpool_node_set_remove, varpool_node_set_find, dump_varpool_node_set,
debug_varpool_node_set): New functions.
* passes.c (rest_of_decl_compilation): when in LTO do not finalize.
(execute_one_pass): Process new decls too.
(ipa_write_summaries_2): Pass around vsets.
(ipa_write_summaries_1): Likewise.
(ipa_write_summaries): Build vset; be more selective about cgraph nodes
to add.
(ipa_write_optimization_summaries_1): Pass around vsets.
(ipa_write_optimization_summaries): Likewise.
* varpool.c (varpool_get_node): New.
(varpool_node): Update doubly linked lists.
(varpool_remove_node): New.
(dump_varpool_node): More dumping.
(varpool_enqueue_needed_node): Update doubly linked lists.
(decide_is_variable_needed): Kill ltrans hack.
(varpool_finalize_decl): Kill lto hack.
(varpool_assemble_decl): Skip decls in other partitions.
(varpool_assemble_pending_decls): Update doubly linkes lists.
(varpool_empty_needed_queue): Likewise.
(varpool_extra_name_alias): Likewise.
* lto-streamer.c (lto_get_section_name): Add vars section.
* lto-streamer.h (lto_section_type): Update.
(output_varpool, input_varpool): Declare.

* lto.c (lto_varpool_node_sets): New.
(lto_1_to_1_map): Partition varpool too.
(globalize_context_t, globalize_cross_file_statics,
lto_scan_statics_in_ref_table, lto_scan_statics_in_cgraph_node,
lto_scan_statics_in_remaining_global_vars): Remove.
(lto_promote_cross_file_statics): Rewrite.
(get_filename_for_set): Take vset argument.
(lto_wpa_write_files): Pass around vsets.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@158854 138bc75d-0d04-0410-961f-82ee72b054a4

21 files changed:
gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphunit.c
gcc/ipa-cp.c
gcc/ipa-inline.c
gcc/ipa-pure-const.c
gcc/ipa-reference.c
gcc/ipa.c
gcc/lto-cgraph.c
gcc/lto-section-in.c
gcc/lto-streamer-in.c
gcc/lto-streamer-out.c
gcc/lto-streamer.c
gcc/lto-streamer.h
gcc/lto-symtab.c
gcc/lto/ChangeLog
gcc/lto/lto.c
gcc/passes.c
gcc/tree-pass.h
gcc/varpool.c

index bca2414..6da5d35 100644 (file)
@@ -1,3 +1,72 @@
+2010-04-28  Jan Hubicka  <jh@suse.cz>
+
+       * lto-symtab.c (lto_symtab_entry_def) Add vnode.
+       (lto_varpool_replace_node): New.
+       (lto_symtab_resolve_symbols): Resolve varpool nodes.
+       (lto_symtab_merge_decls_1): Prefer decls with varpool node.
+       (lto_symtab_merge_cgraph_nodes_1): Merge varpools.
+       * cgraph.h (varpool_node_ptr): New type.
+       (varpool_node_ptr): New vector.
+       (varpool_node_set_def): New structure.
+       (varpool_node_set): New type.
+       (varpool_node_set): New vector.
+       (varpool_node_set_element_def): New structure.
+       (varpool_node_set_element, const_varpool_node_set_element): New types.
+       (varpool_node_set_iterator): New type.
+       (varpool_node): Add prev pointers, add used_from_other_partition,
+       in_other_partition.
+       (varpool_node_set_new, varpool_node_set_find, varpool_node_set_add,
+       varpool_node_set_remove, dump_varpool_node_set, debug_varpool_node_set,
+       varpool_get_node, varpool_remove_node): Declare.
+       (vsi_end_p, vsi_next, vsi_node, vsi_start, varpool_node_in_set_p,
+       varpool_node_set_size): New inlines.
+       * cgraph.c (dump_cgraph_node): Dump asm names of aliases.
+       * tree-pass.h (varpool_node_set_def): Forward declare.
+       (ipa_opt_pass_d): Summary writting takes vnode sets too.
+       (ipa_write_optimization_summaries): Update prototype.
+       * ipa-cp.c (ipcp_write_summary): Update.
+       * ipa-reference.c (ipa_reference_write_summary): Update.
+       * lto-cgraph.c (lto_output_varpool_node): New static function.
+       (output_varpool): New function.
+       (input_varpool_node): New static function.
+       (input_varpool_1): New function.
+       (input_cgraph): Input varpool.
+       * ipa-pure-const.c (pure_const_write_summary): Update.
+       * lto-streamer-out.c (lto_output): Update, output varpool too.
+       (write_global_stream): Kill WPA hack.
+       (produce_asm_for_decls): Update.
+       (output_alias_pair_p): Handle variables.
+       (output_unreferenced_globals): Output only needed partition of varpool.
+       * ipa-inline.c (inline_write_summary): Update.
+       * lto-streamer-in.c (lto_input_tree_ref, lto_input_tree): Do not build cgraph.
+       * lto-section-in.c (lto_section_name): Add varpool and jump funcs.
+       * ipa.c (hash_varpool_node_set_element, eq_varpool_node_set_element,
+       varpool_node_set_new, varpool_node_set_add,
+       varpool_node_set_remove, varpool_node_set_find, dump_varpool_node_set,
+       debug_varpool_node_set): New functions.
+       * passes.c (rest_of_decl_compilation): when in LTO do not finalize.
+       (execute_one_pass): Process new decls too.
+       (ipa_write_summaries_2): Pass around vsets.
+       (ipa_write_summaries_1): Likewise.
+       (ipa_write_summaries): Build vset; be more selective about cgraph nodes
+       to add.
+       (ipa_write_optimization_summaries_1): Pass around vsets.
+       (ipa_write_optimization_summaries): Likewise.
+       * varpool.c (varpool_get_node): New.
+       (varpool_node): Update doubly linked lists.
+       (varpool_remove_node): New.
+       (dump_varpool_node): More dumping.
+       (varpool_enqueue_needed_node): Update doubly linked lists.
+       (decide_is_variable_needed): Kill ltrans hack.
+       (varpool_finalize_decl): Kill lto hack.
+       (varpool_assemble_decl): Skip decls in other partitions.
+       (varpool_assemble_pending_decls): Update doubly linkes lists.
+       (varpool_empty_needed_queue): Likewise.
+       (varpool_extra_name_alias): Likewise.
+       * lto-streamer.c (lto_get_section_name): Add vars section.
+       * lto-streamer.h (lto_section_type): Update.
+       (output_varpool, input_varpool): Declare.
+
 2010-04-28  Mike Stump  <mikestump@comcast.net>
 
        * config/i386/darwin.h (CC1_SPEC): Ignore -mdynamic-no-pic for now.
index c7b619a..424c3f2 100644 (file)
@@ -1877,6 +1877,8 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
                       (int)n->thunk.virtual_offset_p);
              fprintf (f, ")");
            }
+         if (DECL_ASSEMBLER_NAME_SET_P (n->decl))
+           fprintf (f, " (asm: %s)", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl)));
        }
       fprintf (f, "\n");
     }
index 1bd4b2c..f063cb4 100644 (file)
@@ -274,7 +274,7 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
   /* Set once the function has been instantiated and its callee
      lists created.  */
   unsigned analyzed : 1;
-  /* Set when function is available in the other LTO partition.  */
+  /* Set when function is available in the other LTRANS partition.  */
   unsigned in_other_partition : 1;
   /* Set when function is scheduled to be processed by local passes.  */
   unsigned process : 1;
@@ -305,12 +305,33 @@ struct GTY(()) cgraph_node_set_def
   PTR GTY ((skip)) aux;
 };
 
+typedef struct varpool_node *varpool_node_ptr;
+
+DEF_VEC_P(varpool_node_ptr);
+DEF_VEC_ALLOC_P(varpool_node_ptr,heap);
+DEF_VEC_ALLOC_P(varpool_node_ptr,gc);
+
+/* A varpool node set is a collection of varpool nodes.  A varpool node
+   can appear in multiple sets.  */
+struct GTY(()) varpool_node_set_def
+{
+  htab_t GTY((param_is (struct varpool_node_set_element_def))) hashtab;
+  VEC(varpool_node_ptr, gc) *nodes;
+  PTR GTY ((skip)) aux;
+};
+
 typedef struct cgraph_node_set_def *cgraph_node_set;
 
 DEF_VEC_P(cgraph_node_set);
 DEF_VEC_ALLOC_P(cgraph_node_set,gc);
 DEF_VEC_ALLOC_P(cgraph_node_set,heap);
 
+typedef struct varpool_node_set_def *varpool_node_set;
+
+DEF_VEC_P(varpool_node_set);
+DEF_VEC_ALLOC_P(varpool_node_set,gc);
+DEF_VEC_ALLOC_P(varpool_node_set,heap);
+
 /* A cgraph node set element contains an index in the vector of nodes in
    the set.  */
 struct GTY(()) cgraph_node_set_element_def
@@ -329,6 +350,24 @@ typedef struct
   unsigned index;
 } cgraph_node_set_iterator;
 
+/* A varpool node set element contains an index in the vector of nodes in
+   the set.  */
+struct GTY(()) varpool_node_set_element_def
+{
+  struct varpool_node *node;
+  HOST_WIDE_INT index;
+};
+
+typedef struct varpool_node_set_element_def *varpool_node_set_element;
+typedef const struct varpool_node_set_element_def *const_varpool_node_set_element;
+
+/* Iterator structure for varpool node sets.  */
+typedef struct
+{
+  varpool_node_set set;
+  unsigned index;
+} varpool_node_set_iterator;
+
 #define DEFCIFCODE(code, string)       CIF_ ## code,
 /* Reasons for inlining failures.  */
 typedef enum {
@@ -398,9 +437,9 @@ DEF_VEC_ALLOC_P(cgraph_edge_p,heap);
 struct GTY((chain_next ("%h.next"))) varpool_node {
   tree decl;
   /* Pointer to the next function in varpool_nodes.  */
-  struct varpool_node *next;
+  struct varpool_node *next, *prev;
   /* Pointer to the next function in varpool_nodes_queue.  */
-  struct varpool_node *next_needed;
+  struct varpool_node *next_needed, *prev_needed;
   /* For normal nodes a pointer to the first extra name alias.  For alias
      nodes a pointer to the normal node.  */
   struct varpool_node *extra_name;
@@ -425,6 +464,10 @@ struct GTY((chain_next ("%h.next"))) varpool_node {
   /* Set for aliases once they got through assemble_alias.  Also set for
      extra name aliases in varpool_extra_name_alias.  */
   unsigned alias : 1;
+  /* Set when variable is used from other LTRANS partition.  */
+  unsigned used_from_other_partition : 1;
+  /* Set when variable is available in the other LTRANS partition.  */
+  unsigned in_other_partition : 1;
 };
 
 /* Every top level asm statement is put into a cgraph_asm_node.  */
@@ -594,6 +637,13 @@ void cgraph_node_set_remove (cgraph_node_set, struct cgraph_node *);
 void dump_cgraph_node_set (FILE *, cgraph_node_set);
 void debug_cgraph_node_set (cgraph_node_set);
 
+varpool_node_set varpool_node_set_new (void);
+varpool_node_set_iterator varpool_node_set_find (varpool_node_set,
+                                              struct varpool_node *);
+void varpool_node_set_add (varpool_node_set, struct varpool_node *);
+void varpool_node_set_remove (varpool_node_set, struct varpool_node *);
+void dump_varpool_node_set (FILE *, varpool_node_set);
+void debug_varpool_node_set (varpool_node_set);
 
 /* In predict.c  */
 bool cgraph_maybe_hot_edge_p (struct cgraph_edge *e);
@@ -616,6 +666,9 @@ void cgraph_make_decl_local (tree);
 void cgraph_make_node_local (struct cgraph_node *);
 bool cgraph_node_can_be_local_p (struct cgraph_node *);
 
+
+struct varpool_node * varpool_get_node (tree decl);
+void varpool_remove_node (struct varpool_node *node);
 bool varpool_assemble_pending_decls (void);
 bool varpool_assemble_decl (struct varpool_node *node);
 bool varpool_analyze_pending_decls (void);
@@ -734,6 +787,54 @@ cgraph_node_set_size (cgraph_node_set set)
   return htab_elements (set->hashtab);
 }
 
+/* Return true if iterator VSI points to nothing.  */
+static inline bool
+vsi_end_p (varpool_node_set_iterator vsi)
+{
+  return vsi.index >= VEC_length (varpool_node_ptr, vsi.set->nodes);
+}
+
+/* Advance iterator VSI.  */
+static inline void
+vsi_next (varpool_node_set_iterator *vsi)
+{
+  vsi->index++;
+}
+
+/* Return the node pointed to by VSI.  */
+static inline struct varpool_node *
+vsi_node (varpool_node_set_iterator vsi)
+{
+  return VEC_index (varpool_node_ptr, vsi.set->nodes, vsi.index);
+}
+
+/* Return an iterator to the first node in SET.  */
+static inline varpool_node_set_iterator
+vsi_start (varpool_node_set set)
+{
+  varpool_node_set_iterator vsi;
+
+  vsi.set = set;
+  vsi.index = 0;
+  return vsi;
+}
+
+/* Return true if SET contains NODE.  */
+static inline bool
+varpool_node_in_set_p (struct varpool_node *node, varpool_node_set set)
+{
+  varpool_node_set_iterator vsi;
+  vsi = varpool_node_set_find (set, node);
+  return !vsi_end_p (vsi);
+}
+
+/* Return number of nodes in SET.  */
+static inline size_t
+varpool_node_set_size (varpool_node_set set)
+{
+  return htab_elements (set->hashtab);
+}
+
 /* Uniquize all constants that appear in memory.
    Each constant in memory thus far output is recorded
    in `const_desc_table'.  */
index 5ace85b..cd67f2a 100644 (file)
@@ -382,6 +382,7 @@ cgraph_process_new_functions (void)
   tree fndecl;
   struct cgraph_node *node;
 
+  varpool_analyze_pending_decls ();
   /*  Note that this queue may grow as its being processed, as the new
       functions may generate new ones.  */
   while (cgraph_new_nodes)
@@ -437,6 +438,7 @@ cgraph_process_new_functions (void)
          break;
        }
       cgraph_call_function_insertion_hooks (node);
+      varpool_analyze_pending_decls ();
     }
   return output;
 }
index 74d365e..6e83b89 100644 (file)
@@ -1304,7 +1304,8 @@ ipcp_generate_summary (void)
 
 /* Write ipcp summary for nodes in SET.  */
 static void
-ipcp_write_summary (cgraph_node_set set)
+ipcp_write_summary (cgraph_node_set set,
+                   varpool_node_set vset ATTRIBUTE_UNUSED)
 {
   ipa_prop_write_jump_functions (set);
 }
index 75adb01..5146c3c 100644 (file)
@@ -2097,7 +2097,8 @@ inline_read_summary (void)
    active, we don't need to write them twice.  */
 
 static void
-inline_write_summary (cgraph_node_set set)
+inline_write_summary (cgraph_node_set set,
+                     varpool_node_set vset ATTRIBUTE_UNUSED)
 {
   if (flag_indirect_inlining && !flag_ipa_cp)
     ipa_prop_write_jump_functions (set);
index 46d03e6..b7a8de3 100644 (file)
@@ -771,7 +771,8 @@ generate_summary (void)
 /* Serialize the ipa info for lto.  */
 
 static void
-pure_const_write_summary (cgraph_node_set set)
+pure_const_write_summary (cgraph_node_set set,
+                         varpool_node_set vset ATTRIBUTE_UNUSED)
 {
   struct cgraph_node *node;
   struct lto_simple_output_block *ob
index 7183e65..2617072 100644 (file)
@@ -1040,7 +1040,8 @@ write_node_summary_p (struct cgraph_node *node)
 /* Serialize the ipa info for lto.  */
 
 static void
-ipa_reference_write_summary (cgraph_node_set set)
+ipa_reference_write_summary (cgraph_node_set set,
+                            varpool_node_set vset ATTRIBUTE_UNUSED)
 {
   struct cgraph_node *node;
   struct lto_simple_output_block *ob
index 00488b2..36fe714 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -762,6 +762,164 @@ debug_cgraph_node_set (cgraph_node_set set)
   dump_cgraph_node_set (stderr, set);
 }
 
+/* Hash a varpool node set element.  */
+
+static hashval_t
+hash_varpool_node_set_element (const void *p)
+{
+  const_varpool_node_set_element element = (const_varpool_node_set_element) p;
+  return htab_hash_pointer (element->node);
+}
+
+/* Compare two varpool node set elements.  */
+
+static int
+eq_varpool_node_set_element (const void *p1, const void *p2)
+{
+  const_varpool_node_set_element e1 = (const_varpool_node_set_element) p1;
+  const_varpool_node_set_element e2 = (const_varpool_node_set_element) p2;
+
+  return e1->node == e2->node;
+}
+
+/* Create a new varpool node set.  */
+
+varpool_node_set
+varpool_node_set_new (void)
+{
+  varpool_node_set new_node_set;
+
+  new_node_set = GGC_NEW (struct varpool_node_set_def);
+  new_node_set->hashtab = htab_create_ggc (10,
+                                          hash_varpool_node_set_element,
+                                          eq_varpool_node_set_element,
+                                          NULL);
+  new_node_set->nodes = NULL;
+  return new_node_set;
+}
+
+/* Add varpool_node NODE to varpool_node_set SET.  */
+
+void
+varpool_node_set_add (varpool_node_set set, struct varpool_node *node)
+{
+  void **slot;
+  varpool_node_set_element element;
+  struct varpool_node_set_element_def dummy;
+
+  dummy.node = node;
+  slot = htab_find_slot (set->hashtab, &dummy, INSERT);
+
+  if (*slot != HTAB_EMPTY_ENTRY)
+    {
+      element = (varpool_node_set_element) *slot;
+      gcc_assert (node == element->node
+                 && (VEC_index (varpool_node_ptr, set->nodes, element->index)
+                     == node));
+      return;
+    }
+
+  /* Insert node into hash table.  */
+  element =
+    (varpool_node_set_element) GGC_NEW (struct varpool_node_set_element_def);
+  element->node = node;
+  element->index = VEC_length (varpool_node_ptr, set->nodes);
+  *slot = element;
+
+  /* Insert into node vector.  */
+  VEC_safe_push (varpool_node_ptr, gc, set->nodes, node);
+}
+
+/* Remove varpool_node NODE from varpool_node_set SET.  */
+
+void
+varpool_node_set_remove (varpool_node_set set, struct varpool_node *node)
+{
+  void **slot, **last_slot;
+  varpool_node_set_element element, last_element;
+  struct varpool_node *last_node;
+  struct varpool_node_set_element_def dummy;
+
+  dummy.node = node;
+  slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
+  if (slot == NULL)
+    return;
+
+  element = (varpool_node_set_element) *slot;
+  gcc_assert (VEC_index (varpool_node_ptr, set->nodes, element->index)
+             == node);
+
+  /* Remove from vector. We do this by swapping node with the last element
+     of the vector.  */
+  last_node = VEC_pop (varpool_node_ptr, set->nodes);
+  if (last_node != node)
+    {
+      dummy.node = last_node;
+      last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
+      last_element = (varpool_node_set_element) *last_slot;
+      gcc_assert (last_element);
+
+      /* Move the last element to the original spot of NODE.  */
+      last_element->index = element->index;
+      VEC_replace (varpool_node_ptr, set->nodes, last_element->index,
+                  last_node);
+    }
+
+  /* Remove element from hash table.  */
+  htab_clear_slot (set->hashtab, slot);
+  ggc_free (element);
+}
+
+/* Find NODE in SET and return an iterator to it if found.  A null iterator
+   is returned if NODE is not in SET.  */
+
+varpool_node_set_iterator
+varpool_node_set_find (varpool_node_set set, struct varpool_node *node)
+{
+  void **slot;
+  struct varpool_node_set_element_def dummy;
+  varpool_node_set_element element;
+  varpool_node_set_iterator vsi;
+
+  dummy.node = node;
+  slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
+  if (slot == NULL)
+    vsi.index = (unsigned) ~0;
+  else
+    {
+      element = (varpool_node_set_element) *slot;
+      gcc_assert (VEC_index (varpool_node_ptr, set->nodes, element->index)
+                 == node);
+      vsi.index = element->index;
+    }
+  vsi.set = set;
+
+  return vsi;
+}
+
+/* Dump content of SET to file F.  */
+
+void
+dump_varpool_node_set (FILE *f, varpool_node_set set)
+{
+  varpool_node_set_iterator iter;
+
+  for (iter = vsi_start (set); !vsi_end_p (iter); vsi_next (&iter))
+    {
+      struct varpool_node *node = vsi_node (iter);
+      dump_varpool_node (f, node);
+    }
+}
+
+/* Dump content of SET to stderr.  */
+
+void
+debug_varpool_node_set (varpool_node_set set)
+{
+  dump_varpool_node_set (stderr, set);
+}
+
+
 /* Simple ipa profile pass propagating frequencies across the callgraph.  */
 
 static unsigned int
index b805768..6405432 100644 (file)
@@ -378,6 +378,45 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
     lto_output_uleb128_stream (ob->main_stream, 0);
 }
 
+/* Output the varpool NODE to OB. 
+   If NODE is not in SET, then NODE is a boundary.  */
+
+static void
+lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node *node,
+                        varpool_node_set set)
+{
+  bool boundary_p = !varpool_node_in_set_p (node, set) && node->analyzed;
+  struct bitpack_d *bp;
+  struct varpool_node *alias;
+  int count = 0;
+
+  lto_output_var_decl_index (ob->decl_state, ob->main_stream, node->decl);
+  bp = bitpack_create ();
+  bp_pack_value (bp, node->externally_visible, 1);
+  bp_pack_value (bp, node->force_output, 1);
+  bp_pack_value (bp, node->finalized, 1);
+  gcc_assert (node->finalized || !node->analyzed);
+  gcc_assert (node->needed);
+  gcc_assert (!node->alias);
+  /* FIXME: We have no idea how we move references around.  For moment assume that
+     everything is used externally.  */
+  bp_pack_value (bp, flag_wpa, 1);  /* used_from_other_parition.  */
+  bp_pack_value (bp, boundary_p, 1);  /* in_other_partition.  */
+  /* Also emit any extra name aliases.  */
+  for (alias = node->extra_name; alias; alias = alias->next)
+    count++;
+  bp_pack_value (bp, count != 0, 1);
+  lto_output_bitpack (ob->main_stream, bp);
+  bitpack_delete (bp);
+
+  if (count)
+    {
+      lto_output_uleb128_stream (ob->main_stream, count);
+      for (alias = node->extra_name; alias; alias = alias->next)
+       lto_output_var_decl_index (ob->decl_state, ob->main_stream, alias->decl);
+    }
+}
+
 /* Stream out profile_summary to OB.  */
 
 static void
@@ -564,6 +603,32 @@ input_overwrite_node (struct lto_file_decl_data *file_data,
   node->frequency = (enum node_frequency)bp_unpack_value (bp, 2);
 }
 
+/* Output the part of the cgraph in SET.  */
+
+void
+output_varpool (varpool_node_set set)
+{
+  struct varpool_node *node;
+  struct lto_simple_output_block *ob;
+  int len = 0;
+
+  ob = lto_create_simple_output_block (LTO_section_varpool);
+
+  for (node = varpool_nodes; node; node = node->next)
+    if (node->needed && node->analyzed)
+      len++;
+
+  lto_output_uleb128_stream (ob->main_stream, len);
+
+  /* Write out the nodes.  We must first output a node and then its clones,
+     otherwise at a time reading back the node there would be nothing to clone
+     from.  */
+  for (node = varpool_nodes; node; node = node->next)
+    if (node->needed && node->analyzed)
+      lto_output_varpool_node (ob, node, set);
+
+  lto_destroy_simple_output_block (ob);
+}
 
 /* Read a node from input_block IB.  TAG is the node's tag just read.
    Return the node read or overwriten.  */
@@ -683,6 +748,48 @@ input_node (struct lto_file_decl_data *file_data,
   return node;
 }
 
+/* Read a node from input_block IB.  TAG is the node's tag just read.
+   Return the node read or overwriten.  */
+
+static struct varpool_node *
+input_varpool_node (struct lto_file_decl_data *file_data,
+                   struct lto_input_block *ib)
+{
+  int decl_index;
+  tree var_decl;
+  struct varpool_node *node;
+  struct bitpack_d *bp;
+  bool aliases_p;
+  int count;
+
+  decl_index = lto_input_uleb128 (ib);
+  var_decl = lto_file_decl_data_get_var_decl (file_data, decl_index);
+  node = varpool_node (var_decl);
+
+  bp = lto_input_bitpack (ib);
+  node->externally_visible = bp_unpack_value (bp, 1);
+  node->force_output = bp_unpack_value (bp, 1);
+  node->finalized = bp_unpack_value (bp, 1);
+  node->analyzed = 1; 
+  node->used_from_other_partition = bp_unpack_value (bp, 1);
+  node->in_other_partition = bp_unpack_value (bp, 1);
+  aliases_p = bp_unpack_value (bp, 1);
+  if (node->finalized)
+    varpool_mark_needed_node (node);
+  bitpack_delete (bp);
+  if (aliases_p)
+    {
+      count = lto_input_uleb128 (ib);
+      for (; count > 0; count --)
+       {
+         tree decl = lto_file_decl_data_get_var_decl (file_data,
+                                                      lto_input_uleb128 (ib));
+         varpool_extra_name_alias (decl, var_decl);
+       }
+    }
+  return node;
+}
+
 
 /* Read an edge from IB.  NODES points to a vector of previously read nodes for
    decoding caller and callee of the edge to be read.  If INDIRECT is true, the
@@ -812,6 +919,22 @@ input_cgraph_1 (struct lto_file_decl_data *file_data,
   VEC_free (cgraph_node_ptr, heap, nodes);
 }
 
+/* Read a varpool from IB using the info in FILE_DATA.  */
+
+static void
+input_varpool_1 (struct lto_file_decl_data *file_data,
+               struct lto_input_block *ib)
+{
+  unsigned HOST_WIDE_INT len;
+
+  len = lto_input_uleb128 (ib);
+  while (len)
+    {
+      input_varpool_node (file_data, ib);
+      len--;
+    }
+}
+
 static struct gcov_ctr_summary lto_gcov_summary;
 
 /* Input profile_info from IB.  */
@@ -867,6 +990,12 @@ input_cgraph (void)
       lto_destroy_simple_input_block (file_data, LTO_section_cgraph,
                                      ib, data, len);
 
+      ib = lto_create_simple_input_block (file_data, LTO_section_varpool,
+                                         &data, &len);
+      input_varpool_1 (file_data, ib);
+      lto_destroy_simple_input_block (file_data, LTO_section_varpool,
+                                     ib, data, len);
+
       /* Assume that every file read needs to be processed by LTRANS.  */
       if (flag_wpa)
        lto_mark_file_for_ltrans (file_data);
index 4f2ae4f..16fd086 100644 (file)
@@ -52,6 +52,8 @@ const char *lto_section_name[LTO_N_SECTION_TYPES] =
   "function_body",
   "static_initializer",
   "cgraph",
+  "varpool",
+  "jump_funcs"
   "ipa_pure_const",
   "ipa_reference",
   "symtab",
index bbcd2ab..c45bfd0 100644 (file)
@@ -358,8 +358,6 @@ lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
     case LTO_label_decl_ref:
       ix_u = lto_input_uleb128 (ib);
       result = lto_file_decl_data_get_var_decl (data_in->file_data, ix_u);
-      if (TREE_CODE (result) == VAR_DECL)
-       varpool_mark_needed_node (varpool_node (result));
       break;
 
     default:
@@ -2727,17 +2725,6 @@ lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
         the code and class.  */
       result = lto_get_builtin_tree (ib, data_in);
     }
-  else if (tag == LTO_var_decl_alias)
-    {
-      /* An extra_name alias for a variable.  */
-      unsigned HOST_WIDE_INT ix;
-      tree target;
-      ix = lto_input_uleb128 (ib);
-      result = lto_file_decl_data_get_var_decl (data_in->file_data, ix);
-      ix = lto_input_uleb128 (ib);
-      target = lto_file_decl_data_get_var_decl (data_in->file_data, ix);
-      varpool_extra_name_alias (result, target);
-    }
   else if (tag == lto_tree_code_to_tag (INTEGER_CST))
     {
       /* For integer constants we only need the type and its hi/low
index 99a7da1..0c8544c 100644 (file)
@@ -1930,22 +1930,14 @@ output_function (struct cgraph_node *node)
    the file processed by LTRANS.  */
 
 static bool
-output_alias_pair_p (alias_pair *p, cgraph_node_set set)
+output_alias_pair_p (alias_pair *p, cgraph_node_set set, varpool_node_set vset)
 {
-  cgraph_node_set_iterator csi;
-  struct cgraph_node *target_node;
-
-  /* Always emit VAR_DECLs.  FIXME lto, we should probably only emit
-     those VAR_DECLs that are instantiated in this file partition, but
-     we have no easy way of knowing this based on SET.  */
   if (TREE_CODE (p->decl) == VAR_DECL)
-    return true;
+    return varpool_node_in_set_p (varpool_node_for_asm (p->target), vset);
 
   /* Check if the assembler name for P->TARGET has its cgraph node in SET.  */
   gcc_assert (TREE_CODE (p->decl) == FUNCTION_DECL);
-  target_node = cgraph_node_for_asm (p->target);
-  csi = cgraph_node_set_find (set, target_node);
-  return (!csi_end_p (csi));
+  return cgraph_node_in_set_p (cgraph_node_for_asm (p->target), set);
 }
 
 
@@ -1953,7 +1945,7 @@ output_alias_pair_p (alias_pair *p, cgraph_node_set set)
    and labels.  */
 
 static void
-output_unreferenced_globals (cgraph_node_set set)
+output_unreferenced_globals (cgraph_node_set set, varpool_node_set vset)
 {
   struct output_block *ob;
   alias_pair *p;
@@ -1974,40 +1966,28 @@ output_unreferenced_globals (cgraph_node_set set)
      symbols at link time if a file defines a global symbol but
      never references it.  */
   FOR_EACH_STATIC_VARIABLE (vnode)
-    {
-      tree var = vnode->decl;
-
-      if (TREE_CODE (var) == VAR_DECL)
-        {
-         struct varpool_node *alias;
-
-          /* Output the object in order to output references used in the
-             initialization. */
-          lto_output_tree (ob, var, true);
-
-          /* If it is public we also need a reference to the object itself. */
-          if (TREE_PUBLIC (var))
-            lto_output_tree_ref (ob, var);
-
-         /* Also output any extra_name aliases for this variable.  */
-         for (alias = vnode->extra_name; alias; alias = alias->next)
-           {
-             lto_output_tree (ob, alias->decl, true);
-             output_record_start (ob, LTO_var_decl_alias);
-             lto_output_var_decl_index (ob->decl_state, ob->main_stream,
-                                        alias->decl);
-             lto_output_var_decl_index (ob->decl_state, ob->main_stream,
-                                        var);
-           }
-        }
-    }
+   if (vnode->needed && varpool_node_in_set_p (vnode, vset))
+      {
+       tree var = vnode->decl;
+
+       if (TREE_CODE (var) == VAR_DECL)
+         {
+           /* Output the object in order to output references used in the
+              initialization. */
+           lto_output_tree (ob, var, true);
+
+           /* If it is public we also need a reference to the object itself. */
+           if (TREE_PUBLIC (var))
+             lto_output_tree_ref (ob, var);
+         }
+      }
 
   output_zero (ob);
 
   /* Emit the alias pairs for the nodes in SET.  */
   for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
     {
-      if (output_alias_pair_p (p, set))
+      if (output_alias_pair_p (p, set, vset))
        {
          lto_output_tree_ref (ob, p->decl);
          lto_output_tree_ref (ob, p->target);
@@ -2091,7 +2071,7 @@ lto_writer_init (void)
 /* Main entry point from the pass manager.  */
 
 static void
-lto_output (cgraph_node_set set)
+lto_output (cgraph_node_set set, varpool_node_set vset)
 {
   struct cgraph_node *node;
   struct lto_out_decl_state *decl_state;
@@ -2124,6 +2104,7 @@ lto_output (cgraph_node_set set)
      have been renumbered so that edges can be associated with call
      statements using the statement UIDs.  */
   output_cgraph (set);
+  output_varpool (vset);
 
   lto_bitmap_free (output);
 }
@@ -2178,20 +2159,6 @@ write_global_stream (struct output_block *ob,
       t = lto_tree_ref_encoder_get_tree (encoder, index);
       if (!lto_streamer_cache_lookup (ob->writer_cache, t, NULL))
        lto_output_tree (ob, t, false);
-
-      if (flag_wpa)
-       {
-         /* In WPA we should not emit multiple definitions of the
-            same symbol to all the files in the link set.  If
-            T had already been emitted as the pervailing definition
-            in one file, do not emit it in the others.  */
-         /* FIXME lto.  We should check if T belongs to the
-            file we are writing to.  */
-         if (TREE_CODE (t) == VAR_DECL
-             && TREE_PUBLIC (t)
-             && !DECL_EXTERNAL (t))
-           TREE_ASM_WRITTEN (t) = 1;
-       }
     }
 }
 
@@ -2444,7 +2411,7 @@ produce_symtab (struct lto_streamer_cache_d *cache)
    recover these on other side.  */
 
 static void
-produce_asm_for_decls (cgraph_node_set set)
+produce_asm_for_decls (cgraph_node_set set, varpool_node_set vset)
 {
   struct lto_out_decl_state *out_state;
   struct lto_out_decl_state *fn_out_state;
@@ -2462,7 +2429,7 @@ produce_asm_for_decls (cgraph_node_set set)
   /* Write out unreferenced globals, alias pairs and labels.  We defer
      doing this until now so that we can write out only what is
      needed.  */
-  output_unreferenced_globals (set);
+  output_unreferenced_globals (set, vset);
 
   memset (&header, 0, sizeof (struct lto_decl_header));
 
index 84baeac..ec2a308 100644 (file)
@@ -160,6 +160,9 @@ lto_get_section_name (int section_type, const char *name)
     case LTO_section_cgraph:
       return concat (LTO_SECTION_NAME_PREFIX, ".cgraph", NULL);
 
+    case LTO_section_varpool:
+      return concat (LTO_SECTION_NAME_PREFIX, ".vars", NULL);
+
     case LTO_section_jump_functions:
       return concat (LTO_SECTION_NAME_PREFIX, ".jmpfuncs", NULL);
 
index a9544b5..c33feb6 100644 (file)
@@ -217,9 +217,6 @@ enum LTO_tags
   /* Special for global streamer. Reference to previously-streamed node.  */
   LTO_tree_pickle_reference,
 
-  /* A decl which exists only to provide an extra symbol for another var.  */
-  LTO_var_decl_alias,
-
   /* References to indexable tree nodes.  These objects are stored in
      tables that are written separately from the function bodies that
      reference them.  This way they can be instantiated even when the
@@ -259,11 +256,11 @@ enum lto_section_type
   LTO_section_function_body,
   LTO_section_static_initializer,
   LTO_section_cgraph,
+  LTO_section_varpool,
   LTO_section_jump_functions,
   LTO_section_ipa_pure_const,
   LTO_section_ipa_reference,
   LTO_section_symtab,
-  LTO_section_wpa_fixup,
   LTO_section_opts,
   LTO_N_SECTION_TYPES          /* Must be last.  */
 };
@@ -834,6 +831,8 @@ int lto_cgraph_encoder_encode (lto_cgraph_encoder_t, struct cgraph_node *);
 void lto_cgraph_encoder_delete (lto_cgraph_encoder_t encoder);
 void output_cgraph (cgraph_node_set);
 void input_cgraph (void);
+void output_varpool (varpool_node_set);
+void input_varpool (void);
 
 
 /* In lto-symtab.c.  */
index 79eb3e4..a35d82f 100644 (file)
@@ -44,6 +44,9 @@ struct GTY(()) lto_symtab_entry_def
   /* The cgraph node if decl is a function decl.  Filled in during the
      merging process.  */
   struct cgraph_node *node;
+  /* The varpool node if decl is a variable decl.  Filled in during the
+     merging process.  */
+  struct varpool_node *vnode;
   /* LTO file-data and symbol resolution for this decl.  */
   struct lto_file_decl_data * GTY((skip (""))) file_data;
   enum ld_plugin_symbol_resolution resolution;
@@ -244,6 +247,26 @@ lto_cgraph_replace_node (struct cgraph_node *node,
   cgraph_remove_node (node);
 }
 
+/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
+   all edges and removing the old node.  */
+
+static void
+lto_varpool_replace_node (struct varpool_node *vnode,
+                         struct varpool_node *prevailing_node)
+{
+  /* Merge node flags.  */
+  if (vnode->needed)
+    {
+      gcc_assert (prevailing_node->analyzed);
+      varpool_mark_needed_node (prevailing_node);
+    }
+  gcc_assert (!vnode->finalized || prevailing_node->finalized);
+  gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
+
+  /* Finally remove the replaced node.  */
+  varpool_remove_node (vnode);
+}
+
 /* Merge two variable or function symbol table entries PREVAILING and ENTRY.
    Return false if the symbols are not fully compatible and a diagnostic
    should be emitted.  */
@@ -406,6 +429,8 @@ lto_symtab_resolve_symbols (void **slot)
     {
       if (TREE_CODE (e->decl) == FUNCTION_DECL)
        e->node = cgraph_get_node (e->decl);
+      else if (TREE_CODE (e->decl) == VAR_DECL)
+       e->vnode = varpool_get_node (e->decl);
     }
 
   e = (lto_symtab_entry_t) *slot;
@@ -559,6 +584,10 @@ lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED)
        while (!prevailing->node
               && prevailing->next)
          prevailing = prevailing->next;
+      if (TREE_CODE (prevailing->decl) == VAR_DECL)
+       while (!prevailing->vnode
+              && prevailing->next)
+         prevailing = prevailing->next;
       /* We do not stream varpool nodes, so the first decl has to
         be good enough for now.
         ???  For QOI choose a variable with readonly initializer
@@ -625,7 +654,8 @@ lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED)
   lto_symtab_merge_decls_2 (slot);
 
   /* Drop all but the prevailing decl from the symtab.  */
-  if (TREE_CODE (prevailing->decl) != FUNCTION_DECL)
+  if (TREE_CODE (prevailing->decl) != FUNCTION_DECL
+      && TREE_CODE (prevailing->decl) != VAR_DECL)
     prevailing->next = NULL;
 
   return 1;
@@ -650,8 +680,6 @@ lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED)
   if (!prevailing->next)
     return 1;
 
-  gcc_assert (TREE_CODE (prevailing->decl) == FUNCTION_DECL);
-
   /* Replace the cgraph node of each entry with the prevailing one.  */
   for (e = prevailing->next; e; e = e->next)
     {
@@ -672,6 +700,8 @@ lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED)
            }
          lto_cgraph_replace_node (e->node, prevailing->node);
        }
+      if (e->vnode != NULL)
+       lto_varpool_replace_node (e->vnode, prevailing->vnode);
     }
 
   /* Drop all but the prevailing decl from the symtab.  */
index b757655..5bf7a29 100644 (file)
@@ -1,3 +1,14 @@
+2010-04-28  Jan Hubicka  <jh@suse.cz>
+
+       * lto.c (lto_varpool_node_sets): New.
+       (lto_1_to_1_map): Partition varpool too.
+       (globalize_context_t, globalize_cross_file_statics,
+       lto_scan_statics_in_ref_table, lto_scan_statics_in_cgraph_node,
+       lto_scan_statics_in_remaining_global_vars): Remove.
+       (lto_promote_cross_file_statics): Rewrite.
+       (get_filename_for_set): Take vset argument.
+       (lto_wpa_write_files): Pass around vsets.
+
 2010-04-27  Dave Korn  <dave.korn.cygwin@gmail.com>
 
        PR lto/42776
index 9002686..7aa1f3e 100644 (file)
@@ -523,6 +523,7 @@ free_section_data (struct lto_file_decl_data *file_data ATTRIBUTE_UNUSED,
 
 /* Vector of all cgraph node sets. */
 static GTY (()) VEC(cgraph_node_set, gc) *lto_cgraph_node_sets;
+static GTY (()) VEC(varpool_node_set, gc) *lto_varpool_node_sets;
 
 
 /* Group cgrah nodes by input files.  This is used mainly for testing
@@ -532,25 +533,21 @@ static void
 lto_1_to_1_map (void)
 {
   struct cgraph_node *node;
+  struct varpool_node *vnode;
   struct lto_file_decl_data *file_data;
   struct pointer_map_t *pmap;
+  struct pointer_map_t *vpmap;
   cgraph_node_set set;
+  varpool_node_set vset;
   void **slot;
 
   timevar_push (TV_WHOPR_WPA);
 
   lto_cgraph_node_sets = VEC_alloc (cgraph_node_set, gc, 1);
-
-  /* If the cgraph is empty, create one cgraph node set so that there is still
-     an output file for any variables that need to be exported in a DSO.  */
-  if (!cgraph_nodes)
-    {
-      set = cgraph_node_set_new ();
-      VEC_safe_push (cgraph_node_set, gc, lto_cgraph_node_sets, set);
-      goto finish;
-    }
+  lto_varpool_node_sets = VEC_alloc (varpool_node_set, gc, 1);
 
   pmap = pointer_map_create ();
+  vpmap = pointer_map_create ();
 
   for (node = cgraph_nodes; node; node = node->next)
     {
@@ -558,6 +555,9 @@ lto_1_to_1_map (void)
         cloned from.  */
       if (node->global.inlined_to || node->clone_of)
        continue;
+      /* Nodes without a body do not need partitioning.  */
+      if (!node->analyzed || node->same_body_alias)
+       continue;
       /* We only need to partition the nodes that we read from the
         gimple bytecode files.  */
       file_data = node->local.lto_file_data;
@@ -573,14 +573,50 @@ lto_1_to_1_map (void)
          slot = pointer_map_insert (pmap, file_data);
          *slot = set;
          VEC_safe_push (cgraph_node_set, gc, lto_cgraph_node_sets, set);
+         vset = varpool_node_set_new ();
+         slot = pointer_map_insert (vpmap, file_data);
+         *slot = vset;
+         VEC_safe_push (varpool_node_set, gc, lto_varpool_node_sets, vset);
        }
 
       cgraph_node_set_add (set, node);
     }
 
+  for (vnode = varpool_nodes; vnode; vnode = vnode->next)
+    {
+      if (vnode->alias)
+       continue;
+      slot = pointer_map_contains (vpmap, file_data);
+      if (slot)
+       vset = (varpool_node_set) *slot;
+      else
+       {
+         set = cgraph_node_set_new ();
+         slot = pointer_map_insert (pmap, file_data);
+         *slot = set;
+         VEC_safe_push (cgraph_node_set, gc, lto_cgraph_node_sets, set);
+         vset = varpool_node_set_new ();
+         slot = pointer_map_insert (vpmap, file_data);
+         *slot = vset;
+         VEC_safe_push (varpool_node_set, gc, lto_varpool_node_sets, vset);
+       }
+
+      varpool_node_set_add (vset, vnode);
+    }
+
+  /* If the cgraph is empty, create one cgraph node set so that there is still
+     an output file for any variables that need to be exported in a DSO.  */
+  if (!lto_cgraph_node_sets)
+    {
+      set = cgraph_node_set_new ();
+      VEC_safe_push (cgraph_node_set, gc, lto_cgraph_node_sets, set);
+      vset = varpool_node_set_new ();
+      VEC_safe_push (varpool_node_set, gc, lto_varpool_node_sets, vset);
+    }
+
   pointer_map_destroy (pmap);
+  pointer_map_destroy (vpmap);
 
-finish:
   timevar_pop (TV_WHOPR_WPA);
 
   lto_stats.num_cgraph_partitions += VEC_length (cgraph_node_set, 
@@ -672,174 +708,6 @@ lto_add_all_inlinees (cgraph_node_set set)
   lto_bitmap_free (original_decls);
 }
 
-/* Owing to inlining, we may need to promote a file-scope variable
-   to a global variable.  Consider this case:
-
-   a.c:
-   static int var;
-
-   void
-   foo (void)
-   {
-     var++;
-   }
-
-   b.c:
-
-   extern void foo (void);
-
-   void
-   bar (void)
-   {
-     foo ();
-   }
-
-   If WPA inlines FOO inside BAR, then the static variable VAR needs to
-   be promoted to global because BAR and VAR may be in different LTRANS
-   files. */
-
-/* This struct keeps track of states used in globalization.  */
-
-typedef struct
-{
-  /* Current cgraph node set.  */  
-  cgraph_node_set set;
-
-  /* Function DECLs of cgraph nodes seen.  */
-  bitmap seen_node_decls;
-
-  /* Use in walk_tree to avoid multiple visits of a node.  */
-  struct pointer_set_t *visited;
-
-  /* static vars in this set.  */
-  bitmap static_vars_in_set;
-
-  /* static vars in all previous set.  */
-  bitmap all_static_vars;
-
-  /* all vars in all previous set.  */
-  bitmap all_vars;
-} globalize_context_t;
-
-/* Callback for walk_tree.  Examine the tree pointer to by TP and see if
-   if its a file-scope static variable of function that need to be turned
-   into a global.  */
-
-static tree
-globalize_cross_file_statics (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
-                             void *data)
-{
-  globalize_context_t *context = (globalize_context_t *) data;
-  tree t = *tp;
-
-  if (t == NULL_TREE)
-    return NULL;
-
-  /* The logic for globalization of VAR_DECLs and FUNCTION_DECLs are
-     different.  For functions, we can simply look at the cgraph node sets
-     to tell if there are references to static functions outside the set.
-     The cgraph node sets do not keep track of vars, we need to traverse
-     the trees to determine what vars need to be globalized.  */
-  if (TREE_CODE (t) == VAR_DECL)
-    {
-      if (!TREE_PUBLIC (t))
-       {
-         /* This file-scope static variable is reachable from more
-            that one set.  Make it global but with hidden visibility
-            so that we do not export it in dynamic linking.  */
-         if (bitmap_bit_p (context->all_static_vars, DECL_UID (t)))
-           {
-             TREE_PUBLIC (t) = 1;
-             DECL_VISIBILITY (t) = VISIBILITY_HIDDEN;
-           }
-         bitmap_set_bit (context->static_vars_in_set, DECL_UID (t));
-       }
-      bitmap_set_bit (context->all_vars, DECL_UID (t));
-      walk_tree (&DECL_INITIAL (t), globalize_cross_file_statics, context,
-                context->visited);
-    }
-  else if (TREE_CODE (t) == FUNCTION_DECL && !TREE_PUBLIC (t))
-    {
-      if (!cgraph_node_in_set_p (cgraph_node (t), context->set)
-         || cgraph_node (t)->address_taken)
-       {
-         /* This file-scope static function is reachable from a set
-            which does not contain the function DECL.  Make it global
-            but with hidden visibility.  */
-         TREE_PUBLIC (t) = 1;
-         DECL_VISIBILITY (t) = VISIBILITY_HIDDEN;
-       }
-    }
-
-  return NULL; 
-}
-
-/* Helper of lto_scan_statics_in_cgraph_node below.  Scan TABLE for
-   static decls that may be used in more than one LTRANS file.
-   CONTEXT is a globalize_context_t for storing scanning states.  */
-
-static void
-lto_scan_statics_in_ref_table (struct lto_tree_ref_table *table,
-                              globalize_context_t *context)
-{
-  unsigned i;
-
-  for (i = 0; i < table->size; i++)
-    walk_tree (&table->trees[i], globalize_cross_file_statics, context,
-              context->visited);
-}
-
-/* Promote file-scope decl reachable from NODE if necessary to global.
-   CONTEXT is a globalize_context_t storing scanning states.  */
-
-static void
-lto_scan_statics_in_cgraph_node (struct cgraph_node *node,
-                                globalize_context_t *context)
-{
-  struct lto_in_decl_state *state;
-  
-  /* Do nothing if NODE has no function body.  */
-  if (!node->analyzed)
-    return;
-  
-  /* Return if the DECL of nodes has been visited before.  */
-  if (bitmap_bit_p (context->seen_node_decls, DECL_UID (node->decl)))
-    return;
-
-  bitmap_set_bit (context->seen_node_decls, DECL_UID (node->decl));
-
-  state = lto_get_function_in_decl_state (node->local.lto_file_data,
-                                         node->decl);
-  gcc_assert (state);
-
-  lto_scan_statics_in_ref_table (&state->streams[LTO_DECL_STREAM_VAR_DECL],
-                                context);
-  lto_scan_statics_in_ref_table (&state->streams[LTO_DECL_STREAM_FN_DECL],
-                                context);
-}
-
-/* Scan all global variables that we have not yet seen so far.  CONTEXT
-   is a globalize_context_t storing scanning states.  */
-
-static void
-lto_scan_statics_in_remaining_global_vars (globalize_context_t *context)
-{
-  tree var, var_context;
-  struct varpool_node *vnode;
-
-  FOR_EACH_STATIC_VARIABLE (vnode)
-    {
-      var = vnode->decl;
-      var_context = DECL_CONTEXT (var);
-      if (TREE_STATIC (var)
-         && TREE_PUBLIC (var)
-          && (!var_context || TREE_CODE (var_context) != FUNCTION_DECL)
-          && !bitmap_bit_p (context->all_vars, DECL_UID (var)))
-       walk_tree (&var, globalize_cross_file_statics, context,
-                  context->visited);
-    }
-}
-
 /* Find out all static decls that need to be promoted to global because
    of cross file sharing.  This function must be run in the WPA mode after
    all inlinees are added.  */
@@ -847,39 +715,61 @@ lto_scan_statics_in_remaining_global_vars (globalize_context_t *context)
 static void
 lto_promote_cross_file_statics (void)
 {
+  struct varpool_node *vnode;
   unsigned i, n_sets;
   cgraph_node_set set;
   cgraph_node_set_iterator csi;
-  globalize_context_t context;
 
-  memset (&context, 0, sizeof (context));
-  context.all_vars = lto_bitmap_alloc ();
-  context.all_static_vars = lto_bitmap_alloc ();
+  gcc_assert (flag_wpa);
 
+  /* At moment we make no attempt to figure out who is refering the variables,
+     so all must become global.  */
+  for (vnode = varpool_nodes; vnode; vnode = vnode->next)
+    if (!vnode->externally_visible && vnode->analyzed)
+       {
+         TREE_PUBLIC (vnode->decl) = 1;
+         DECL_VISIBILITY (vnode->decl) = VISIBILITY_HIDDEN;
+       }
   n_sets = VEC_length (cgraph_node_set, lto_cgraph_node_sets);
   for (i = 0; i < n_sets; i++)
     {
       set = VEC_index (cgraph_node_set, lto_cgraph_node_sets, i);
-      context.set = set;
-      context.visited = pointer_set_create ();
-      context.static_vars_in_set = lto_bitmap_alloc ();
-      context.seen_node_decls = lto_bitmap_alloc ();
 
+      /* If node has either address taken (and we have no clue from where)
+        or it is called from other partition, it needs to be globalized.  */
       for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
-       lto_scan_statics_in_cgraph_node (csi_node (csi), &context);
-
-      if (i == n_sets - 1)
-        lto_scan_statics_in_remaining_global_vars (&context);
-
-      bitmap_ior_into (context.all_static_vars, context.static_vars_in_set);
+       {
+         struct cgraph_node *node = csi_node (csi);
+         bool globalize = node->address_taken || node->local.vtable_method;
+         struct cgraph_edge *e;
+         if (node->local.externally_visible)
+           continue;
+         for (e = node->callers; e && !globalize; e = e->next_caller)
+           {
+             struct cgraph_node *caller = e->caller;
+             if (caller->global.inlined_to)
+               caller = caller->global.inlined_to;
+             if (!cgraph_node_in_set_p (caller, set))
+               globalize = true;
+           }
+         if (globalize)
+            {
+               TREE_PUBLIC (node->decl) = 1;
+               DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN;
+               if (node->same_body)
+                 {
+                   struct cgraph_node *alias;
+                   for (alias = node->same_body;
+                        alias; alias = alias->next)
+                     {
+                       TREE_PUBLIC (alias->decl) = 1;
+                       DECL_VISIBILITY (alias->decl) = VISIBILITY_HIDDEN;
+                     }
+                 }
+            }
+       }
 
-      pointer_set_destroy (context.visited);
-      lto_bitmap_free (context.static_vars_in_set);
-      lto_bitmap_free (context.seen_node_decls);
     }
-
-  lto_bitmap_free (context.all_vars);
-  lto_bitmap_free (context.all_static_vars);
 }
 
 
@@ -999,6 +889,7 @@ lto_wpa_write_files (void)
   unsigned i, n_sets, last_out_file_ix, num_out_files;
   lto_file *file;
   cgraph_node_set set;
+  varpool_node_set vset;
 
   timevar_push (TV_WHOPR_WPA);
 
@@ -1034,6 +925,7 @@ lto_wpa_write_files (void)
       char *temp_filename;
 
       set = VEC_index (cgraph_node_set, lto_cgraph_node_sets, i);
+      vset = VEC_index (varpool_node_set, lto_varpool_node_sets, i);
       temp_filename = get_filename_for_set (set);
       output_files[i] = temp_filename;
 
@@ -1046,7 +938,7 @@ lto_wpa_write_files (void)
 
          lto_set_current_out_file (file);
 
-         ipa_write_optimization_summaries (set);
+         ipa_write_optimization_summaries (set, vset);
 
          lto_set_current_out_file (NULL);
          lto_obj_file_close (file);
index ee6de54..7a5d16f 100644 (file)
@@ -191,7 +191,11 @@ rest_of_decl_compilation (tree decl,
           || DECL_INITIAL (decl))
          && !DECL_EXTERNAL (decl))
        {
-         if (TREE_CODE (decl) != FUNCTION_DECL)
+         /* When reading LTO unit, we also read varpool, so do not
+            rebuild it.  */
+         if (in_lto_p && !at_end)
+           ;
+         else if (TREE_CODE (decl) != FUNCTION_DECL)
            varpool_finalize_decl (decl);
          else
            assemble_variable (decl, top_level, at_end, 0);
@@ -218,7 +222,9 @@ rest_of_decl_compilation (tree decl,
     }
 
   /* Let cgraph know about the existence of variables.  */
-  if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
+  if (in_lto_p && !at_end)
+    ;
+  else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
     varpool_node (decl);
 }
 
@@ -1649,6 +1655,7 @@ execute_pass_list (struct opt_pass *pass)
 
 static void
 ipa_write_summaries_2 (struct opt_pass *pass, cgraph_node_set set,
+                      varpool_node_set vset,
                       struct lto_out_decl_state *state)
 {
   while (pass)
@@ -1665,7 +1672,7 @@ ipa_write_summaries_2 (struct opt_pass *pass, cgraph_node_set set,
          if (pass->tv_id)
            timevar_push (pass->tv_id);
 
-         ipa_pass->write_summary (set);
+         ipa_pass->write_summary (set,vset);
 
          /* If a timevar is present, start it.  */
          if (pass->tv_id)
@@ -1673,7 +1680,7 @@ ipa_write_summaries_2 (struct opt_pass *pass, cgraph_node_set set,
        }
 
       if (pass->sub && pass->sub->type != GIMPLE_PASS)
-       ipa_write_summaries_2 (pass->sub, set, state);
+       ipa_write_summaries_2 (pass->sub, set, vset, state);
 
       pass = pass->next;
     }
@@ -1684,14 +1691,14 @@ ipa_write_summaries_2 (struct opt_pass *pass, cgraph_node_set set,
    summaries.  SET is the set of nodes to be written.  */
 
 static void
-ipa_write_summaries_1 (cgraph_node_set set)
+ipa_write_summaries_1 (cgraph_node_set set, varpool_node_set vset)
 {
   struct lto_out_decl_state *state = lto_new_out_decl_state ();
   lto_push_out_decl_state (state);
 
   gcc_assert (!flag_wpa);
-  ipa_write_summaries_2 (all_regular_ipa_passes, set, state);
-  ipa_write_summaries_2 (all_lto_gen_passes, set, state);
+  ipa_write_summaries_2 (all_regular_ipa_passes, set, vset, state);
+  ipa_write_summaries_2 (all_lto_gen_passes, set, vset, state);
 
   gcc_assert (lto_get_out_decl_state () == state);
   lto_pop_out_decl_state ();
@@ -1704,7 +1711,9 @@ void
 ipa_write_summaries (void)
 {
   cgraph_node_set set;
+  varpool_node_set vset;
   struct cgraph_node **order;
+  struct varpool_node *vnode;
   int i, order_pos;
 
   if (!flag_generate_lto || errorcount || sorrycount)
@@ -1736,13 +1745,20 @@ ipa_write_summaries (void)
          renumber_gimple_stmt_uids ();
          pop_cfun ();
        }
-      cgraph_node_set_add (set, node);
+      if (node->needed || node->reachable || node->address_taken)
+       cgraph_node_set_add (set, node);
     }
+  vset = varpool_node_set_new ();
 
-  ipa_write_summaries_1 (set);
+  for (vnode = varpool_nodes; vnode; vnode = vnode->next)
+    if (vnode->needed && !vnode->alias)
+      varpool_node_set_add (vset, vnode);
+
+  ipa_write_summaries_1 (set, vset);
 
   free (order);
   ggc_free (set);
+  ggc_free (vset);
 }
 
 /* Same as execute_pass_list but assume that subpasses of IPA passes
@@ -1751,6 +1767,7 @@ ipa_write_summaries (void)
 
 static void
 ipa_write_optimization_summaries_1 (struct opt_pass *pass, cgraph_node_set set,
+                      varpool_node_set vset,
                       struct lto_out_decl_state *state)
 {
   while (pass)
@@ -1767,7 +1784,7 @@ ipa_write_optimization_summaries_1 (struct opt_pass *pass, cgraph_node_set set,
          if (pass->tv_id)
            timevar_push (pass->tv_id);
 
-         ipa_pass->write_optimization_summary (set);
+         ipa_pass->write_optimization_summary (set, vset);
 
          /* If a timevar is present, start it.  */
          if (pass->tv_id)
@@ -1775,7 +1792,7 @@ ipa_write_optimization_summaries_1 (struct opt_pass *pass, cgraph_node_set set,
        }
 
       if (pass->sub && pass->sub->type != GIMPLE_PASS)
-       ipa_write_optimization_summaries_1 (pass->sub, set, state);
+       ipa_write_optimization_summaries_1 (pass->sub, set, vset, state);
 
       pass = pass->next;
     }
@@ -1785,14 +1802,14 @@ ipa_write_optimization_summaries_1 (struct opt_pass *pass, cgraph_node_set set,
    NULL, write out all summaries of all nodes. */
 
 void
-ipa_write_optimization_summaries (cgraph_node_set set)
+ipa_write_optimization_summaries (cgraph_node_set set, varpool_node_set vset)
 {
   struct lto_out_decl_state *state = lto_new_out_decl_state ();
   lto_push_out_decl_state (state);
 
   gcc_assert (flag_wpa);
-  ipa_write_optimization_summaries_1 (all_regular_ipa_passes, set, state);
-  ipa_write_optimization_summaries_1 (all_lto_gen_passes, set, state);
+  ipa_write_optimization_summaries_1 (all_regular_ipa_passes, set, vset, state);
+  ipa_write_optimization_summaries_1 (all_lto_gen_passes, set, vset, state);
 
   gcc_assert (lto_get_out_decl_state () == state);
   lto_pop_out_decl_state ();
index a82dc83..8542aab 100644 (file)
@@ -168,6 +168,7 @@ struct rtl_opt_pass
 struct varpool_node;
 struct cgraph_node;
 struct cgraph_node_set_def;
+struct varpool_node_set_def;
 
 /* Description of IPA pass with generate summary, write, execute, read and
    transform stages.  */
@@ -180,13 +181,15 @@ struct ipa_opt_pass_d
   void (*generate_summary) (void);
 
   /* This hook is used to serialize IPA summaries on disk.  */
-  void (*write_summary) (struct cgraph_node_set_def *);
+  void (*write_summary) (struct cgraph_node_set_def *,
+                        struct varpool_node_set_def *);
 
   /* This hook is used to deserialize IPA summaries from disk.  */
   void (*read_summary) (void);
 
   /* This hook is used to serialize IPA optimization summaries on disk.  */
-  void (*write_optimization_summary) (struct cgraph_node_set_def *);
+  void (*write_optimization_summary) (struct cgraph_node_set_def *,
+                                     struct varpool_node_set_def *);
 
   /* This hook is used to deserialize IPA summaries from disk.  */
   void (*read_optimization_summary) (void);
@@ -607,7 +610,8 @@ extern const char *get_current_pass_name (void);
 extern void print_current_pass (FILE *);
 extern void debug_pass (void);
 extern void ipa_write_summaries (void);
-extern void ipa_write_optimization_summaries (struct cgraph_node_set_def *);
+extern void ipa_write_optimization_summaries (struct cgraph_node_set_def *,
+                                             struct varpool_node_set_def *);
 extern void ipa_read_summaries (void);
 extern void ipa_read_optimization_summaries (void);
 extern void register_one_dump_file (struct opt_pass *);
index 40decfc..77f52c3 100644 (file)
@@ -105,6 +105,22 @@ eq_varpool_node (const void *p1, const void *p2)
   return DECL_UID (n1->decl) == DECL_UID (n2->decl);
 }
 
+/* Return varpool node assigned to DECL without creating new one.  */
+struct varpool_node *
+varpool_get_node (tree decl)
+{
+  struct varpool_node key, **slot;
+
+  gcc_assert (DECL_P (decl) && TREE_CODE (decl) != FUNCTION_DECL);
+
+  if (!varpool_hash)
+    return NULL;
+  key.decl = decl;
+  slot = (struct varpool_node **)
+    htab_find_slot (varpool_hash, &key, INSERT);
+  return *slot;
+}
+
 /* Return varpool node assigned to DECL.  Create new one when needed.  */
 struct varpool_node *
 varpool_node (tree decl)
@@ -125,11 +141,50 @@ varpool_node (tree decl)
   node->decl = decl;
   node->order = cgraph_order++;
   node->next = varpool_nodes;
+  if (varpool_nodes)
+    varpool_nodes->prev = node;
   varpool_nodes = node;
   *slot = node;
   return node;
 }
 
+/* Remove node from the varpool.  */
+void
+varpool_remove_node (struct varpool_node *node)
+{
+  void **slot;
+  slot = htab_find_slot (varpool_hash, node, NO_INSERT);
+  gcc_assert (*slot == node);
+  htab_clear_slot (varpool_hash, slot);
+  gcc_assert (!varpool_assembled_nodes_queue);
+  if (node->next)
+    node->next->prev = node->prev;
+  if (node->prev)
+    node->prev->next = node->next;
+  else if (node->next)
+    {
+      gcc_assert (varpool_nodes == node);
+      varpool_nodes = node->next;
+    }
+  if (varpool_first_unanalyzed_node == node)
+    varpool_first_unanalyzed_node = node->next_needed;
+  if (node->next_needed)
+    node->next_needed->prev_needed = node->prev_needed;
+  else if (node->prev_needed)
+    {
+      gcc_assert (varpool_last_needed_node);
+      varpool_last_needed_node = node->prev_needed;
+    }
+  if (node->prev_needed)
+    node->prev_needed->next_needed = node->next_needed;
+  else if (node->next_needed)
+    {
+      gcc_assert (varpool_nodes_queue == node);
+      varpool_nodes_queue = node->next_needed;
+    }
+  node->decl = NULL;
+}
+
 /* Dump given cgraph node.  */
 void
 dump_varpool_node (FILE *f, struct varpool_node *node)
@@ -139,8 +194,12 @@ dump_varpool_node (FILE *f, struct varpool_node *node)
           cgraph_function_flags_ready
           ? cgraph_availability_names[cgraph_variable_initializer_availability (node)]
           : "not-ready");
+  if (DECL_ASSEMBLER_NAME_SET_P (node->decl))
+    fprintf (f, " (asm: %s)", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl)));
   if (DECL_INITIAL (node->decl))
     fprintf (f, " initialized");
+  if (TREE_ASM_WRITTEN (node->decl))
+    fprintf (f, " (asm written)");
   if (node->needed)
     fprintf (f, " needed");
   if (node->analyzed)
@@ -151,6 +210,10 @@ dump_varpool_node (FILE *f, struct varpool_node *node)
     fprintf (f, " output");
   if (node->externally_visible)
     fprintf (f, " externally_visible");
+  if (node->in_other_partition)
+    fprintf (f, " in_other_partition");
+  else if (node->used_from_other_partition)
+    fprintf (f, " used_from_other_partition");
   fprintf (f, "\n");
 }
 
@@ -192,7 +255,10 @@ static void
 varpool_enqueue_needed_node (struct varpool_node *node)
 {
   if (varpool_last_needed_node)
-    varpool_last_needed_node->next_needed = node;
+    {
+      varpool_last_needed_node->next_needed = node;
+      node->prev_needed = varpool_last_needed_node;
+    }
   varpool_last_needed_node = node;
   node->next_needed = NULL;
   if (!varpool_nodes_queue)
@@ -230,11 +296,7 @@ varpool_reset_queue (void)
 bool
 decide_is_variable_needed (struct varpool_node *node, tree decl)
 {
-  /* We do not track variable references at all and thus have no idea if the
-     variable was referenced in some other partition or not.  
-     FIXME: We really need address taken edges in callgraph and varpool to
-     drive WPA and decide whether other partition might reference it or not.  */
-  if (flag_ltrans)
+  if (node->used_from_other_partition)
     return true;
   /* If the user told us it is used, then it must be so.  */
   if ((node->externally_visible && !DECL_COMDAT (decl))
@@ -288,17 +350,6 @@ varpool_finalize_decl (tree decl)
 {
   struct varpool_node *node = varpool_node (decl);
 
-  /* FIXME: We don't really stream varpool datastructure and instead rebuild it
-     by varpool_finalize_decl.  This is not quite correct since this way we can't
-     attach any info to varpool.  Eventually we will want to stream varpool nodes
-     and the flags.
-
-     For the moment just prevent analysis of varpool nodes to happen again, so
-     we will re-try to compute "address_taken" flag of varpool that breaks
-     in presence of clones.  */
-  if (in_lto_p)
-    node->analyzed = true;
-
   /* The first declaration of a variable that comes through this function
      decides whether it is global (in C, has external linkage)
      or local (in C, has internal linkage).  So do nothing more
@@ -364,7 +415,7 @@ varpool_analyze_pending_decls (void)
         We however don't want to re-analyze already analyzed nodes.  */
       if (!analyzed)
        {
-         gcc_assert (!in_lto_p);
+         gcc_assert (!in_lto_p || cgraph_function_flags_ready);
           /* Compute the alignment early so function body expanders are
             already informed about increased alignment.  */
           align_variable (decl, 0);
@@ -385,6 +436,7 @@ varpool_assemble_decl (struct varpool_node *node)
 
   if (!TREE_ASM_WRITTEN (decl)
       && !node->alias
+      && !node->in_other_partition
       && !DECL_EXTERNAL (decl)
       && (TREE_CODE (decl) != VAR_DECL || !DECL_HAS_VALUE_EXPR_P (decl)))
     {
@@ -394,6 +446,9 @@ varpool_assemble_decl (struct varpool_node *node)
          struct varpool_node *alias;
 
          node->next_needed = varpool_assembled_nodes_queue;
+         node->prev_needed = NULL;
+         if (varpool_assembled_nodes_queue)
+           varpool_assembled_nodes_queue->prev_needed = node;
          varpool_assembled_nodes_queue = node;
          node->finalized = 1;
 
@@ -476,7 +531,10 @@ varpool_assemble_pending_decls (void)
       if (varpool_assemble_decl (node))
        changed = true;
       else
-        node->next_needed = NULL;
+       {
+         node->prev_needed = NULL;
+          node->next_needed = NULL;
+       }
     }
   /* varpool_nodes_queue is now empty, clear the pointer to the last element
      in the queue.  */
@@ -498,6 +556,7 @@ varpool_empty_needed_queue (void)
       struct varpool_node *node = varpool_nodes_queue;
       varpool_nodes_queue = varpool_nodes_queue->next_needed;
       node->next_needed = NULL;
+      node->prev_needed = NULL;
     }
   /* varpool_nodes_queue is now empty, clear the pointer to the last element
      in the queue.  */
@@ -559,6 +618,8 @@ varpool_extra_name_alias (tree alias, tree decl)
   alias_node->alias = 1;
   alias_node->extra_name = decl_node;
   alias_node->next = decl_node->extra_name;
+  if (decl_node->extra_name)
+    decl_node->extra_name->prev = alias_node;
   decl_node->extra_name = alias_node;
   *slot = alias_node;
   return true;