Hi,
this patch removes the duplication of boundary logic in between
lto_promote_cross_file_statics and compute_ltrans_boundary. With common
representation it is easy to compute boundaries first and the promote the
symbols that appear in some boundary.

This duplication was source of quite few bugs and issues, so hopefully
the new code will run a lot smoother ;)

Bootstrapped/regtested x86_64-linux.

        * passes.c (ipa_write_summaries_1): Set state;
        do not call compute_ltrans_boundary.
        (ipa_write_optimization_summaries): Likewise.
        (ipa_write_summaries): compute_ltrans_boundary here.
        * lto-streamer.h (lto_symtab_encoder_d): NODES are allocated in heap.
        (compute_ltrans_boundary): Update prototype.

        * lto.c (lto_wpa_write_files): Do not delete partition encoder;
        it is deleted after streaming.
        * lto-partition.c (partition_symbol_p): New function.
        (promote_var, promote_fn): Remove.
        (promote_symbol): New function.
        (lto_promote_cross_file_statics): First compute boundaries; rewrite
        to lookup the actual boundaries instead of computing them ad-hoc.
Index: lto-streamer.h
===================================================================
*** lto-streamer.h      (revision 191107)
--- lto-streamer.h      (working copy)
*************** DEF_VEC_ALLOC_O(lto_encoder_entry, heap)
*** 441,447 ****
  /* Encoder data structure used to stream callgraph nodes.  */
  struct lto_symtab_encoder_d
  {
!   VEC(lto_encoder_entry,gc) *nodes;
    pointer_map_t *map;
  };
  
--- 441,447 ----
  /* Encoder data structure used to stream callgraph nodes.  */
  struct lto_symtab_encoder_d
  {
!   VEC(lto_encoder_entry,heap) *nodes;
    pointer_map_t *map;
  };
  
*************** bool referenced_from_this_partition_p (s
*** 856,863 ****
                                        lto_symtab_encoder_t);
  bool reachable_from_this_partition_p (struct cgraph_node *,
                                      lto_symtab_encoder_t);
! void compute_ltrans_boundary (struct lto_out_decl_state *state,
!                             lto_symtab_encoder_t encoder);
  
  
  /* In lto-symtab.c.  */
--- 856,862 ----
                                        lto_symtab_encoder_t);
  bool reachable_from_this_partition_p (struct cgraph_node *,
                                      lto_symtab_encoder_t);
! lto_symtab_encoder_t compute_ltrans_boundary (lto_symtab_encoder_t encoder);
  
  
  /* In lto-symtab.c.  */
Index: lto-cgraph.c
===================================================================
*** lto-cgraph.c        (revision 191107)
--- lto-cgraph.c        (working copy)
*************** output_profile_summary (struct lto_simpl
*** 588,625 ****
      streamer_write_uhwi_stream (ob->main_stream, 0);
  }
  
- /* Add NODE into encoder as well as nodes it is cloned from.
-    Do it in a way so clones appear first.  */
- 
- static void
- add_node_to (lto_symtab_encoder_t encoder, struct cgraph_node *node,
-            bool include_body)
- {
-   if (node->clone_of)
-     add_node_to (encoder, node->clone_of, include_body);
-   else if (include_body)
-     lto_set_symtab_encoder_encode_body (encoder, node);
-   lto_symtab_encoder_encode (encoder, (symtab_node)node);
- }
- 
- /* Add all references in LIST to encoders.  */
- 
- static void
- add_references (lto_symtab_encoder_t encoder,
-               struct ipa_ref_list *list)
- {
-   int i;
-   struct ipa_ref *ref;
-   for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
-     if (symtab_function_p (ref->referred))
-       add_node_to (encoder, ipa_ref_node (ref), false);
-     else
-       {
-       struct varpool_node *vnode = ipa_ref_varpool_node (ref);
-         lto_symtab_encoder_encode (encoder, (symtab_node)vnode);
-       }
- }
- 
  /* Output all callees or indirect outgoing edges.  EDGE must be the first such
     edge.  */
  
--- 588,593 ----
*************** output_refs (lto_symtab_encoder_t encode
*** 674,684 ****
    lto_destroy_simple_output_block (ob);
  }
  
! /* Find out all cgraph and varpool nodes we want to encode in current unit
!    and insert them to encoders.  */
! void
! compute_ltrans_boundary (struct lto_out_decl_state *state,
!                        lto_symtab_encoder_t in_encoder)
  {
    struct cgraph_node *node;
    struct cgraph_edge *edge;
--- 642,689 ----
    lto_destroy_simple_output_block (ob);
  }
  
! /* Add NODE into encoder as well as nodes it is cloned from.
!    Do it in a way so clones appear first.  */
! 
! static void
! add_node_to (lto_symtab_encoder_t encoder, struct cgraph_node *node,
!            bool include_body)
! {
!   if (node->clone_of)
!     add_node_to (encoder, node->clone_of, include_body);
!   else if (include_body)
!     lto_set_symtab_encoder_encode_body (encoder, node);
!   lto_symtab_encoder_encode (encoder, (symtab_node)node);
! }
! 
! /* Add all references in LIST to encoders.  */
! 
! static void
! add_references (lto_symtab_encoder_t encoder,
!               struct ipa_ref_list *list)
! {
!   int i;
!   struct ipa_ref *ref;
!   for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
!     if (symtab_function_p (ref->referred))
!       add_node_to (encoder, ipa_ref_node (ref), false);
!     else
!       {
!       struct varpool_node *vnode = ipa_ref_varpool_node (ref);
!         lto_symtab_encoder_encode (encoder, (symtab_node)vnode);
!       }
! }
! 
! /* Find all symbols we want to stream into given partition and insert them
!    to encoders.
! 
!    The function actually replaces IN_ENCODER by new one.  The reason is that
!    streaming code needs clone's origin to be streamed before clone.  This
!    means that we need to insert the nodes in specific order.  This order is
!    ignored by the partitioning logic earlier.  */
! 
! lto_symtab_encoder_t 
! compute_ltrans_boundary (lto_symtab_encoder_t in_encoder)
  {
    struct cgraph_node *node;
    struct cgraph_edge *edge;
*************** compute_ltrans_boundary (struct lto_out_
*** 686,692 ****
    lto_symtab_encoder_t encoder;
    lto_symtab_encoder_iterator lsei;
  
!   encoder = state->symtab_node_encoder = lto_symtab_encoder_new ();
  
    /* Go over all entries in the IN_ENCODER and duplicate them to
       ENCODER. At the same time insert masters of clones so
--- 691,697 ----
    lto_symtab_encoder_t encoder;
    lto_symtab_encoder_iterator lsei;
  
!   encoder = lto_symtab_encoder_new ();
  
    /* Go over all entries in the IN_ENCODER and duplicate them to
       ENCODER. At the same time insert masters of clones so
*************** compute_ltrans_boundary (struct lto_out_
*** 747,752 ****
--- 752,759 ----
            }
        }
      }
+  lto_symtab_encoder_delete (in_encoder);
+  return encoder;
  }
  
  /* Output the part of the symtab in SET and VSET.  */
Index: passes.c
===================================================================
*** passes.c    (revision 191107)
--- passes.c    (working copy)
*************** static void
*** 2264,2270 ****
  ipa_write_summaries_1 (lto_symtab_encoder_t encoder)
  {
    struct lto_out_decl_state *state = lto_new_out_decl_state ();
!   compute_ltrans_boundary (state, encoder);
  
    lto_push_out_decl_state (state);
  
--- 2264,2270 ----
  ipa_write_summaries_1 (lto_symtab_encoder_t encoder)
  {
    struct lto_out_decl_state *state = lto_new_out_decl_state ();
!   state->symtab_node_encoder = encoder;
  
    lto_push_out_decl_state (state);
  
*************** ipa_write_summaries (void)
*** 2324,2330 ****
      if ((!vnode->alias || vnode->alias_of))
        lto_set_symtab_encoder_in_partition (encoder, (symtab_node)vnode);
  
!   ipa_write_summaries_1 (encoder);
  
    free (order);
  }
--- 2324,2330 ----
      if ((!vnode->alias || vnode->alias_of))
        lto_set_symtab_encoder_in_partition (encoder, (symtab_node)vnode);
  
!   ipa_write_summaries_1 (compute_ltrans_boundary (encoder));
  
    free (order);
  }
*************** ipa_write_optimization_summaries (lto_sy
*** 2376,2382 ****
  {
    struct lto_out_decl_state *state = lto_new_out_decl_state ();
    lto_symtab_encoder_iterator lsei;
!   compute_ltrans_boundary (state, encoder);
  
    lto_push_out_decl_state (state);
    for (lsei = lsei_start_function_in_partition (encoder);
--- 2376,2382 ----
  {
    struct lto_out_decl_state *state = lto_new_out_decl_state ();
    lto_symtab_encoder_iterator lsei;
!   state->symtab_node_encoder = encoder;
  
    lto_push_out_decl_state (state);
    for (lsei = lsei_start_function_in_partition (encoder);
Index: lto/lto-partition.c
===================================================================
*** lto/lto-partition.c (revision 191107)
--- lto/lto-partition.c (working copy)
*************** partition_varpool_node_p (struct varpool
*** 280,285 ****
--- 280,297 ----
    return true;
  }
  
+ /* Return true if NODE should be partitioned. 
+    This means that partitioning algorithm should put NODE into one of 
partitions. */
+ 
+ static bool
+ partition_symbol_p (symtab_node node)
+ {
+   if (symtab_function_p (node))
+     return partition_cgraph_node_p (cgraph (node));
+   else
+     return partition_varpool_node_p (varpool (node));
+ }
+ 
  /* Group cgrah nodes by input files.  This is used mainly for testing
     right now.  */
  
*************** lto_balanced_map (void)
*** 739,777 ****
  
  /* Promote variable VNODE to be static.  */
  
! static bool
! promote_var (struct varpool_node *vnode)
  {
!   if (TREE_PUBLIC (vnode->symbol.decl) || DECL_EXTERNAL (vnode->symbol.decl))
!     return false;
!   gcc_assert (flag_wpa);
!   TREE_PUBLIC (vnode->symbol.decl) = 1;
!   DECL_VISIBILITY (vnode->symbol.decl) = VISIBILITY_HIDDEN;
!   DECL_VISIBILITY_SPECIFIED (vnode->symbol.decl) = true;
!   if (cgraph_dump_file)
!     fprintf (cgraph_dump_file,
!           "Promoting var as hidden: %s\n", varpool_node_name (vnode));
!   return true;
! }
  
! /* Promote function NODE to be static.  */
! 
! static bool
! promote_fn (struct cgraph_node *node)
! {
!   gcc_assert (flag_wpa);
!   if (TREE_PUBLIC (node->symbol.decl) || DECL_EXTERNAL (node->symbol.decl))
!     return false;
    TREE_PUBLIC (node->symbol.decl) = 1;
    DECL_VISIBILITY (node->symbol.decl) = VISIBILITY_HIDDEN;
    DECL_VISIBILITY_SPECIFIED (node->symbol.decl) = true;
    if (cgraph_dump_file)
      fprintf (cgraph_dump_file,
!            "Promoting function as hidden: %s/%i\n",
!            cgraph_node_name (node), node->uid);
!   return true;
  }
  
  /* 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.  */
--- 751,776 ----
  
  /* Promote variable VNODE to be static.  */
  
! static void
! promote_symbol (symtab_node node)
  {
!   /* We already promoted ... */
!   if (DECL_VISIBILITY (node->symbol.decl) == VISIBILITY_HIDDEN
!       && DECL_VISIBILITY_SPECIFIED (node->symbol.decl)
!       && TREE_PUBLIC (node->symbol.decl))
!     return;
  
!   gcc_checking_assert (!TREE_PUBLIC (node->symbol.decl)
!                      && !DECL_EXTERNAL (node->symbol.decl));
    TREE_PUBLIC (node->symbol.decl) = 1;
    DECL_VISIBILITY (node->symbol.decl) = VISIBILITY_HIDDEN;
    DECL_VISIBILITY_SPECIFIED (node->symbol.decl) = true;
    if (cgraph_dump_file)
      fprintf (cgraph_dump_file,
!           "Promoting as hidden: %s\n", symtab_node_name (node));
  }
  
+ 
  /* 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.  */
*************** promote_fn (struct cgraph_node *node)
*** 779,896 ****
  void
  lto_promote_cross_file_statics (void)
  {
-   struct varpool_node *vnode;
    unsigned i, n_sets;
-   VEC(varpool_node_ptr, heap) *promoted_initializers = NULL;
-   struct pointer_set_t *inserted = pointer_set_create ();
-   lto_symtab_encoder_iterator lsei;
-   lto_symtab_encoder_t encoder;
  
    gcc_assert (flag_wpa);
  
    n_sets = VEC_length (ltrans_partition, ltrans_partitions);
    for (i = 0; i < n_sets; i++)
      {
        ltrans_partition part
        = VEC_index (ltrans_partition, ltrans_partitions, i);
!       encoder = part->encoder;
! 
!       /* If node called or referred to from other partition, it needs to be
!        globalized.  */
!       for (lsei = lsei_start_in_partition (encoder); !lsei_end_p (lsei);
!          lsei_next_in_partition (&lsei))
!       {
!         symtab_node node = lsei_node (lsei);
!         if (node->symbol.externally_visible)
!           continue;
!         if (symtab_function_p (node))
!           {
!             struct cgraph_node *cnode = cgraph (node);
!             if (partition_cgraph_node_p (cnode)
!                 && (referenced_from_other_partition_p 
(&cnode->symbol.ref_list, encoder)
!                     || reachable_from_other_partition_p (cnode, encoder)))
!               promote_fn (cnode);
!           }
!         else if (symtab_variable_p (node))
!           {
!             vnode = varpool (node);
!             /* Constant pool references use internal labels and thus can not
!                be made global.  It is sensible to keep those ltrans local to
!                allow better optimization.  */
!             if (partition_varpool_node_p (vnode)
!                 && referenced_from_other_partition_p (&vnode->symbol.ref_list,
!                                                       encoder))
!               promote_var (vnode);
!           }
!         else
!           gcc_unreachable ();
!       }
  
!       /* We export the initializer of a read-only var into each partition
!        referencing the var.  Folding might take declarations from the
!        initializer and use them, so everything referenced from the
!        initializer can be accessed from this partition after folding.
! 
!        This means that we need to promote all variables and functions
!        referenced from all initializers of read-only vars referenced
!        from this partition that are not in this partition.  This needs
!        to be done recursively.  */
!       FOR_EACH_VARIABLE (vnode)
!       if (const_value_known_p (vnode->symbol.decl)
!           && DECL_INITIAL (vnode->symbol.decl)
!           && !lto_symtab_encoder_in_partition_p (encoder, (symtab_node)vnode)
!           && referenced_from_this_partition_p (&vnode->symbol.ref_list, 
encoder)
!           && !pointer_set_insert (inserted, vnode))
!       VEC_safe_push (varpool_node_ptr, heap, promoted_initializers, vnode);
  
!       while (!VEC_empty (varpool_node_ptr, promoted_initializers))
!       {
!         int i;
!         struct ipa_ref *ref;
  
!         vnode = VEC_pop (varpool_node_ptr, promoted_initializers);
!         for (i = 0;
!              ipa_ref_list_reference_iterate (&vnode->symbol.ref_list, i, ref);
!              i++)
!           {
!             if (symtab_function_p (ref->referred))
!               {
!                 struct cgraph_node *n = ipa_ref_node (ref);
!                 gcc_assert (!n->global.inlined_to);
!                 if (!n->symbol.externally_visible
!                     && !lto_symtab_encoder_in_partition_p (encoder, 
(symtab_node)n))
!                   promote_fn (n);
!               }
!             else
!               {
!                 struct varpool_node *v = ipa_ref_varpool_node (ref);
!                 if (lto_symtab_encoder_in_partition_p (encoder, 
(symtab_node)v))
!                   continue;
! 
!                 /* Constant pool references use internal labels and thus
!                    cannot be made global.  It is sensible to keep those
!                    ltrans local to allow better optimization.
!                    Similarly we ship external vars initializers into
!                    every ltrans unit possibly referring to it.  */
!                 if (DECL_IN_CONSTANT_POOL (v->symbol.decl)
!                     || DECL_EXTERNAL (v->symbol.decl))
!                   {
!                     if (!pointer_set_insert (inserted, vnode))
!                       VEC_safe_push (varpool_node_ptr, heap,
!                                      promoted_initializers, v);
!                   }
!                 else if (!v->symbol.externally_visible && v->analyzed)
!                   {
!                     if (promote_var (v)
!                         && DECL_INITIAL (v->symbol.decl)
!                         && const_value_known_p (v->symbol.decl)
!                         && !pointer_set_insert (inserted, vnode))
!                       VEC_safe_push (varpool_node_ptr, heap,
!                                      promoted_initializers, v);
!                   }
!               }
!           }
!       }
      }
-   pointer_set_destroy (inserted);
  }
--- 778,820 ----
  void
  lto_promote_cross_file_statics (void)
  {
    unsigned i, n_sets;
  
    gcc_assert (flag_wpa);
  
+   /* First compute boundaries.  */
    n_sets = VEC_length (ltrans_partition, ltrans_partitions);
    for (i = 0; i < n_sets; i++)
      {
        ltrans_partition part
        = VEC_index (ltrans_partition, ltrans_partitions, i);
!       part->encoder = compute_ltrans_boundary (part->encoder);
!     }
  
!   /* Look at boundaries and promote symbols as needed.  */
!   for (i = 0; i < n_sets; i++)
!     {
!       lto_symtab_encoder_iterator lsei;
!       lto_symtab_encoder_t encoder;
!       ltrans_partition part
!       = VEC_index (ltrans_partition, ltrans_partitions, i);
  
!       encoder = part->encoder;
!       for (lsei = lsei_start (encoder); !lsei_end_p (lsei);
!          lsei_next (&lsei))
!         {
!           symtab_node node = lsei_node (lsei);
! 
!         /* No need to promote if symbol already is externally visible ... */
!         if (node->symbol.externally_visible
!             /* ... or if it is part of current partition ... */
!             || lto_symtab_encoder_in_partition_p (encoder, node)
!             /* ... or if we do not partition it. This mean that it will
!                appear in every partition refernecing it.  */
!             || !partition_symbol_p (node))
!           continue;
  
!           promote_symbol (node);
!         }
      }
  }
Index: lto/lto.c
===================================================================
*** lto/lto.c   (revision 191107)
--- lto/lto.c   (working copy)
*************** lto_wpa_write_files (void)
*** 1514,1520 ****
  
        lto_set_current_out_file (NULL);
        lto_obj_file_close (file);
-       lto_symtab_encoder_delete (part->encoder);
        part->encoder = NULL;
  
        len = strlen (temp_filename);
--- 1514,1519 ----

Reply via email to