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)
committerMasaki Muranaka <monaka@monami-software.com>
Sun, 23 May 2010 04:54:39 +0000 (13:54 +0900)
(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

19 files changed:
gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphunit.c
gcc/ipa-cp.c
gcc/ipa-inline.c
gcc/ipa-reference.c
gcc/ipa.c
gcc/lto-cgraph.c
gcc/lto-section-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 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 4d59832..0c8544c 100644 (file)
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "params.h"
 #include "input.h"
+#include "varray.h"
 #include "hashtab.h"
 #include "basic-block.h"
 #include "tree-flow.h"
@@ -844,23 +845,7 @@ lto_output_ts_decl_common_tree_pointers (struct output_block *ob, tree expr,
   lto_output_tree_or_ref (ob, DECL_SIZE_UNIT (expr), ref_p);
 
   if (TREE_CODE (expr) != FUNCTION_DECL)
-    {
-      tree initial = DECL_INITIAL (expr);
-      if (TREE_CODE (expr) == VAR_DECL
-         && (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
-         && initial)
-       {
-         lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder;
-         struct varpool_node *vnode = varpool_get_node (expr);
-         if (!vnode)
-           initial = error_mark_node;
-         else if (!lto_varpool_encoder_encode_initializer_p (varpool_encoder,
-                                                             vnode))
-           initial = NULL;
-       }
-    
-      lto_output_tree_or_ref (ob, initial, ref_p);
-    }
+    lto_output_tree_or_ref (ob, DECL_INITIAL (expr), ref_p);
 
   lto_output_tree_or_ref (ob, DECL_ATTRIBUTES (expr), ref_p);
   lto_output_tree_or_ref (ob, DECL_ABSTRACT_ORIGIN (expr), ref_p);
@@ -1702,7 +1687,6 @@ output_gimple_stmt (struct output_block *ob, gimple stmt)
       lto_output_uleb128_stream (ob->main_stream, gimple_asm_ninputs (stmt));
       lto_output_uleb128_stream (ob->main_stream, gimple_asm_noutputs (stmt));
       lto_output_uleb128_stream (ob->main_stream, gimple_asm_nclobbers (stmt));
-      lto_output_uleb128_stream (ob->main_stream, gimple_asm_nlabels (stmt));
       output_string (ob, ob->main_stream, gimple_asm_string (stmt));
       /* Fallthru  */
 
@@ -2091,25 +2075,18 @@ lto_output (cgraph_node_set set, varpool_node_set vset)
 {
   struct cgraph_node *node;
   struct lto_out_decl_state *decl_state;
-#ifdef ENABLE_CHECKING
+  cgraph_node_set_iterator csi;
   bitmap output = lto_bitmap_alloc ();
-#endif
-  int i, n_nodes;
-  lto_cgraph_encoder_t encoder = lto_get_out_decl_state ()->cgraph_node_encoder;
 
   lto_writer_init ();
 
-  n_nodes = lto_cgraph_encoder_size (encoder);
   /* Process only the functions with bodies.  */
-  for (i = 0; i < n_nodes; i++)
+  for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
     {
-      node = lto_cgraph_encoder_deref (encoder, i);
-      if (lto_cgraph_encoder_encode_body_p (encoder, node))
+      node = csi_node (csi);
+      if (node->analyzed && !bitmap_bit_p (output, DECL_UID (node->decl)))
        {
-#ifdef ENABLE_CHECKING
-         gcc_assert (!bitmap_bit_p (output, DECL_UID (node->decl)));
          bitmap_set_bit (output, DECL_UID (node->decl));
-#endif
          decl_state = lto_new_out_decl_state ();
          lto_push_out_decl_state (decl_state);
          if (!flag_wpa)
@@ -2126,11 +2103,10 @@ lto_output (cgraph_node_set set, varpool_node_set vset)
      be done now to make sure that all the statements in every function
      have been renumbered so that edges can be associated with call
      statements using the statement UIDs.  */
-  output_cgraph (set, vset);
+  output_cgraph (set);
+  output_varpool (vset);
 
-#ifdef ENABLE_CHECKING
   lto_bitmap_free (output);
-#endif
 }
 
 struct ipa_opt_pass_d pass_ipa_lto_gimple_out =
@@ -2531,14 +2507,7 @@ produce_asm_for_decls (cgraph_node_set set, varpool_node_set vset)
   lto_write_options ();
 
   /* Deallocate memory and clean up.  */
-  for (idx = 0; idx < num_fns; idx++)
-    {
-      fn_out_state =
-       VEC_index (lto_out_decl_state_ptr, lto_function_decl_states, idx);
-      lto_delete_out_decl_state (fn_out_state);
-    }
   lto_cgraph_encoder_delete (ob->decl_state->cgraph_node_encoder);
-  lto_varpool_encoder_delete (ob->decl_state->varpool_node_encoder);
   VEC_free (lto_out_decl_state_ptr, heap, lto_function_decl_states);
   lto_function_decl_states = NULL;
   destroy_output_block (ob);
index 20ce075..ec2a308 100644 (file)
@@ -163,9 +163,6 @@ lto_get_section_name (int section_type, const char *name)
     case LTO_section_varpool:
       return concat (LTO_SECTION_NAME_PREFIX, ".vars", NULL);
 
-    case LTO_section_refs:
-      return concat (LTO_SECTION_NAME_PREFIX, ".refs", NULL);
-
     case LTO_section_jump_functions:
       return concat (LTO_SECTION_NAME_PREFIX, ".jmpfuncs", NULL);
 
@@ -178,9 +175,6 @@ lto_get_section_name (int section_type, const char *name)
     case LTO_section_opts:
       return concat (LTO_SECTION_NAME_PREFIX, ".opts", NULL);
 
-    case LTO_section_cgraph_opt_sum:
-      return concat (LTO_SECTION_NAME_PREFIX, ".cgraphopt", NULL);
-
     default:
       internal_error ("bytecode stream: unexpected LTO section %s", name);
     }
@@ -461,7 +455,7 @@ lto_streamer_cache_add_to_node_array (struct lto_streamer_cache_d *cache,
   if (ix >= (int) VEC_length (tree, cache->nodes))
     {
       size_t sz = ix + (20 + ix) / 4;
-      VEC_safe_grow_cleared (tree, heap, cache->nodes, sz);
+      VEC_safe_grow_cleared (tree, gc, cache->nodes, sz);
       VEC_safe_grow_cleared (unsigned, heap, cache->offsets, sz);
     }
 
@@ -503,7 +497,7 @@ lto_streamer_cache_insert_1 (struct lto_streamer_cache_d *cache,
       else
        ix = *ix_p;
 
-      entry = (struct tree_int_map *)pool_alloc (cache->node_map_entries);
+      entry = XCNEW (struct tree_int_map);
       entry->base.from = t;
       entry->to = (unsigned) ix;
       *slot = entry;
@@ -765,10 +759,6 @@ lto_streamer_cache_create (void)
 
   cache->node_map = htab_create (101, tree_int_map_hash, tree_int_map_eq, NULL);
 
-  cache->node_map_entries = create_alloc_pool ("node map",
-                                              sizeof (struct tree_int_map),
-                                              100);
-
   /* Load all the well-known tree nodes that are always created by
      the compiler on startup.  This prevents writing them out
      unnecessarily.  */
@@ -792,8 +782,7 @@ lto_streamer_cache_delete (struct lto_streamer_cache_d *c)
     return;
 
   htab_delete (c->node_map);
-  free_alloc_pool (c->node_map_entries);
-  VEC_free (tree, heap, c->nodes);
+  VEC_free (tree, gc, c->nodes);
   VEC_free (unsigned, heap, c->offsets);
   free (c);
 }
index b7c0c36..c33feb6 100644 (file)
@@ -30,7 +30,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "vec.h"
 #include "vecprim.h"
-#include "alloc-pool.h"
 
 /* Define when debugging the LTO streamer.  This causes the writer
    to output the numeric value for the memory address of the tree node
@@ -258,13 +257,11 @@ enum lto_section_type
   LTO_section_static_initializer,
   LTO_section_cgraph,
   LTO_section_varpool,
-  LTO_section_refs,
   LTO_section_jump_functions,
   LTO_section_ipa_pure_const,
   LTO_section_ipa_reference,
   LTO_section_symtab,
   LTO_section_opts,
-  LTO_section_cgraph_opt_sum,
   LTO_N_SECTION_TYPES          /* Must be last.  */
 };
 
@@ -348,14 +345,11 @@ struct lto_streamer_cache_d
   /* The mapping between tree nodes and slots into the nodes array.  */
   htab_t node_map;
 
-  /* Node map to store entries into.  */
-  alloc_pool node_map_entries;
-
   /* Next available slot in the nodes and offsets arrays.  */
   unsigned next_slot;
 
   /* The nodes pickled so far.  */
-  VEC(tree,heap) *nodes;
+  VEC(tree,gc) *nodes;
 
   /* Offset into the stream where the nodes have been written.  */
   VEC(unsigned,heap) *offsets;
@@ -468,41 +462,15 @@ struct lto_cgraph_encoder_d
 
   /* Map reference number to node. */
   VEC(cgraph_node_ptr,heap) *nodes;
-
-  /* Map of nodes where we want to output body.  */
-  struct pointer_set_t *body;
 };
 
 typedef struct lto_cgraph_encoder_d *lto_cgraph_encoder_t;
 
-/* Return number of encoded nodes in ENCODER.  */
-
-static inline int
-lto_cgraph_encoder_size (lto_cgraph_encoder_t encoder)
-{
-  return VEC_length (cgraph_node_ptr, encoder->nodes);
-}
-
-
-/* Encoder data structure used to stream callgraph nodes.  */
-struct lto_varpool_encoder_d
-{
-  /* Map nodes to reference number. */
-  struct pointer_map_t *map;
-
-  /* Map reference number to node. */
-  VEC(varpool_node_ptr,heap) *nodes;
-
-  /* Map of nodes where we want to output initializer.  */
-  struct pointer_set_t *initializer;
-};
-typedef struct lto_varpool_encoder_d *lto_varpool_encoder_t;
-
 /* Mapping from indices to trees.  */
-struct GTY(()) lto_tree_ref_table
+struct lto_tree_ref_table
 {
   /* Array of referenced trees . */
-  tree * GTY((length ("%h.size"))) trees;
+  tree *trees;
 
   /* Size of array. */
   unsigned int size;
@@ -528,7 +496,7 @@ struct lto_tree_ref_encoder
 
 
 /* Structure to hold states of input scope.  */
-struct GTY(()) lto_in_decl_state
+struct lto_in_decl_state
 {
   /* Array of lto_in_decl_buffers to store type and decls streams. */
   struct lto_tree_ref_table streams[LTO_N_DECL_STREAMS];
@@ -552,9 +520,6 @@ struct lto_out_decl_state
   /* Encoder for cgraph nodes.  */
   lto_cgraph_encoder_t cgraph_node_encoder;
 
-  /* Encoder for varpool nodes.  */
-  lto_varpool_encoder_t varpool_node_encoder;
-
   /* If this out-decl state belongs to a function, fn_decl points to that
      function.  Otherwise, it is NULL. */
   tree fn_decl;
@@ -569,7 +534,7 @@ DEF_VEC_ALLOC_P(lto_out_decl_state_ptr, heap);
    by lto.  This structure contains the tables that are needed by the
    serialized functions and ipa passes to connect themselves to the
    global types and decls as they are reconstituted.  */
-struct GTY(()) lto_file_decl_data
+struct lto_file_decl_data
 {
   /* Decl state currently used. */
   struct lto_in_decl_state *current_decl_state;
@@ -579,22 +544,22 @@ struct GTY(()) lto_file_decl_data
   struct lto_in_decl_state *global_decl_state;
 
   /* Table of cgraph nodes present in this file.  */
-  lto_cgraph_encoder_t GTY((skip)) cgraph_node_encoder;
-
-  /* Table of varpool nodes present in this file.  */
-  lto_varpool_encoder_t GTY((skip)) varpool_node_encoder;
+  lto_cgraph_encoder_t cgraph_node_encoder;
 
   /* Hash table maps lto-related section names to location in file.  */
-  htab_t GTY((param_is (struct lto_in_decl_state))) function_decl_states;
+  htab_t function_decl_states;
 
   /* The .o file that these offsets relate to.  */
-  const char *GTY((skip)) file_name;
+  const char *file_name;
+
+  /* Nonzero if this file should be recompiled with LTRANS.  */
+  unsigned needs_ltrans_p : 1;
 
   /* Hash table maps lto-related section names to location in file.  */
-  htab_t GTY((skip)) section_hash_table;
+  htab_t section_hash_table;
 
   /* Hash new name of renamed global declaration to its original name.  */
-  htab_t GTY((skip)) renaming_hash_table;
+  htab_t renaming_hash_table;
 };
 
 struct lto_char_ptr_base
@@ -863,33 +828,11 @@ struct cgraph_node *lto_cgraph_encoder_deref (lto_cgraph_encoder_t, int);
 int lto_cgraph_encoder_lookup (lto_cgraph_encoder_t, struct cgraph_node *);
 lto_cgraph_encoder_t lto_cgraph_encoder_new (void);
 int lto_cgraph_encoder_encode (lto_cgraph_encoder_t, struct cgraph_node *);
-void lto_cgraph_encoder_delete (lto_cgraph_encoder_t);
-bool lto_cgraph_encoder_encode_body_p (lto_cgraph_encoder_t,
-                                      struct cgraph_node *);
-
-bool lto_varpool_encoder_encode_body_p (lto_varpool_encoder_t,
-                                       struct varpool_node *);
-struct varpool_node *lto_varpool_encoder_deref (lto_varpool_encoder_t, int);
-int lto_varpool_encoder_lookup (lto_varpool_encoder_t, struct varpool_node *);
-lto_varpool_encoder_t lto_varpool_encoder_new (void);
-int lto_varpool_encoder_encode (lto_varpool_encoder_t, struct varpool_node *);
-void lto_varpool_encoder_delete (lto_varpool_encoder_t);
-bool lto_varpool_encoder_encode_initializer_p (lto_varpool_encoder_t,
-                                              struct varpool_node *);
-void output_cgraph (cgraph_node_set, varpool_node_set);
+void lto_cgraph_encoder_delete (lto_cgraph_encoder_t encoder);
+void output_cgraph (cgraph_node_set);
 void input_cgraph (void);
-bool referenced_from_other_partition_p (struct ipa_ref_list *,
-                                       cgraph_node_set,
-                                       varpool_node_set vset);
-bool reachable_from_other_partition_p (struct cgraph_node *,
-                                      cgraph_node_set);
-bool referenced_from_this_partition_p (struct ipa_ref_list *,
-                                       cgraph_node_set,
-                                       varpool_node_set vset);
-bool reachable_from_this_partition_p (struct cgraph_node *,
-                                      cgraph_node_set);
-void compute_ltrans_boundary (struct lto_out_decl_state *state,
-                             cgraph_node_set, varpool_node_set);
+void output_varpool (varpool_node_set);
+void input_varpool (void);
 
 
 /* In lto-symtab.c.  */
@@ -899,7 +842,6 @@ extern void lto_symtab_merge_decls (void);
 extern void lto_symtab_merge_cgraph_nodes (void);
 extern tree lto_symtab_prevailing_decl (tree decl);
 extern enum ld_plugin_symbol_resolution lto_symtab_get_resolution (tree decl);
-extern void lto_symtab_free (void);
 
 
 /* In lto-opts.c.  */
@@ -980,6 +922,38 @@ lto_tag_to_tree_code (enum LTO_tags tag)
   return (enum tree_code) ((unsigned) tag - 1);
 }
 
+
+/* Return true if FILE needs to be compiled with LTRANS.  */
+static inline bool
+lto_file_needs_ltrans_p (struct lto_file_decl_data *file)
+{
+  return file->needs_ltrans_p != 0;
+}
+
+
+/* Mark FILE to be compiled with LTRANS.  */
+static inline void
+lto_mark_file_for_ltrans (struct lto_file_decl_data *file)
+{
+  file->needs_ltrans_p = 1;
+}
+
+
+/* Return true if any files in node set SET need to be compiled
+   with LTRANS.  */
+static inline bool
+cgraph_node_set_needs_ltrans_p (cgraph_node_set set)
+{
+  cgraph_node_set_iterator csi;
+
+  for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
+    if (lto_file_needs_ltrans_p (csi_node (csi)->local.lto_file_data))
+      return true;
+
+  return false;
+}
+
+
 /* Initialize an lto_out_decl_buffer ENCODER.  */
 static inline void
 lto_init_tree_ref_encoder (struct lto_tree_ref_encoder *encoder,
index f02824d..a35d82f 100644 (file)
@@ -65,15 +65,6 @@ static GTY ((if_marked ("lto_symtab_entry_marked_p"),
             param_is (struct lto_symtab_entry_def)))
   htab_t lto_symtab_identifiers;
 
-/* Free symtab hashtable.  */
-
-void
-lto_symtab_free (void)
-{
-  htab_delete (lto_symtab_identifiers);
-  lto_symtab_identifiers = NULL;
-}
-
 /* Return the hash value of an lto_symtab_entry_t object pointed to by P.  */
 
 static hashval_t
@@ -81,7 +72,7 @@ lto_symtab_entry_hash (const void *p)
 {
   const struct lto_symtab_entry_def *base =
     (const struct lto_symtab_entry_def *) p;
-  return IDENTIFIER_HASH_VALUE (base->id);
+  return htab_hash_string (IDENTIFIER_POINTER (base->id));
 }
 
 /* Return non-zero if P1 and P2 points to lto_symtab_entry_def structs
@@ -106,10 +97,9 @@ lto_symtab_entry_marked_p (const void *p)
   const struct lto_symtab_entry_def *base =
      (const struct lto_symtab_entry_def *) p;
 
-  /* Keep this only if the common IDENTIFIER_NODE of the symtab chain
-     is marked which it will be if at least one of the DECLs in the
-     chain is marked.  */
-  return ggc_marked_p (base->id);
+  /* Keep this only if the decl or the chain is marked.  */
+  return (ggc_marked_p (base->decl)
+         || (base->next && ggc_marked_p (base->next)));
 }
 
 /* Lazily initialize resolution hash tables.  */
@@ -224,8 +214,15 @@ lto_cgraph_replace_node (struct cgraph_node *node,
       next = e->next_caller;
       cgraph_redirect_edge_callee (e, prevailing_node);
     }
-  /* Redirect incomming references.  */
-  ipa_clone_refering (prevailing_node, NULL, &node->ref_list);
+
+  /* There are not supposed to be any outgoing edges from a node we
+     replace.  Still this can happen for multiple instances of weak
+     functions.  */
+  for (e = node->callees; e; e = next)
+    {
+      next = e->next_callee;
+      cgraph_remove_edge (e);
+    }
 
   if (node->same_body)
     {
@@ -260,40 +257,12 @@ lto_varpool_replace_node (struct varpool_node *vnode,
   /* Merge node flags.  */
   if (vnode->needed)
     {
-      gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
+      gcc_assert (prevailing_node->analyzed);
       varpool_mark_needed_node (prevailing_node);
     }
-  /* Relink aliases.  */
-  if (vnode->extra_name && !vnode->alias)
-    {
-      struct varpool_node *alias, *last;
-      for (alias = vnode->extra_name;
-          alias; alias = alias->next)
-       {
-         last = alias;
-         alias->extra_name = prevailing_node;
-       }
-
-      if (prevailing_node->extra_name)
-       {
-         last->next = prevailing_node->extra_name;
-         prevailing_node->extra_name->prev = last;
-       }
-      prevailing_node->extra_name = vnode->extra_name;
-      vnode->extra_name = NULL;
-    }
   gcc_assert (!vnode->finalized || prevailing_node->finalized);
   gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
 
-  /* When replacing by an alias, the references goes to the original
-     variable.  */
-  if (prevailing_node->alias && prevailing_node->extra_name)
-    prevailing_node = prevailing_node->extra_name;
-  ipa_clone_refering (NULL, prevailing_node, &vnode->ref_list);
-
-  /* Be sure we can garbage collect the initializer.  */
-  if (DECL_INITIAL (vnode->decl))
-    DECL_INITIAL (vnode->decl) = error_mark_node;
   /* Finally remove the replaced node.  */
   varpool_remove_node (vnode);
 }
@@ -437,13 +406,11 @@ lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
 
   /* A variable should have a size.  */
   else if (TREE_CODE (e->decl) == VAR_DECL)
-    {
-      if (!e->vnode)
-       return false;
-      if (e->vnode->finalized)
-       return true;
-      return e->vnode->alias && e->vnode->extra_name->finalized;
-    }
+    return (DECL_SIZE (e->decl) != NULL_TREE
+           /* The C++ frontend retains TREE_STATIC on the declaration
+              of foo_ in struct Foo { static Foo *foo_; }; but it is
+              not a definition.  g++.dg/lto/20090315_0.C.  */
+           && !DECL_EXTERNAL (e->decl));
 
   gcc_unreachable ();
 }
@@ -463,13 +430,7 @@ 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);
-         /* The LTO plugin for gold doesn't handle common symbols
-            properly.  Let us choose manually.  */
-         if (DECL_COMMON (e->decl))
-           e->resolution = LDPR_UNKNOWN;
-       }
+       e->vnode = varpool_get_node (e->decl);
     }
 
   e = (lto_symtab_entry_t) *slot;
@@ -623,22 +584,21 @@ lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED)
        while (!prevailing->node
               && prevailing->next)
          prevailing = prevailing->next;
-      /* For variables chose with a priority variant with vnode
-        attached (i.e. from unit where external declaration of
-        variable is actually used).
-        When there are multiple variants, chose one with size.
-        This is needed for C++ typeinfos, for example in
-        lto/20081204-1 there are typeifos in both units, just
-        one of them do have size.  */
       if (TREE_CODE (prevailing->decl) == VAR_DECL)
-       {
-         for (e = prevailing->next; e; e = e->next)
-           if ((!prevailing->vnode && e->vnode)
-               || ((prevailing->vnode != NULL) == (e->vnode != NULL)
-                   && !COMPLETE_TYPE_P (TREE_TYPE (prevailing->decl))
-                   && COMPLETE_TYPE_P (TREE_TYPE (e->decl))))
-             prevailing = e;
-       }
+       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
+        if there is one.  This matches C++
+        struct Foo { static const int i = 1; }; without a real
+        definition.  */
+      if (TREE_CODE (prevailing->decl) == VAR_DECL)
+       while (!(TREE_READONLY (prevailing->decl)
+                && DECL_INITIAL (prevailing->decl))
+              && prevailing->next)
+         prevailing = prevailing->next;
     }
 
   /* Move it first in the list.  */
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;