Add an no_reorder attribute for LTO
authorAndi Kleen <ak@linux.intel.com>
Wed, 24 Sep 2014 03:29:24 +0000 (03:29 +0000)
committerAndi Kleen <ak@gcc.gnu.org>
Wed, 24 Sep 2014 03:29:24 +0000 (03:29 +0000)
Some projects need to prevent reordering of specific top level
declarations with LTO, in particular declarations defining init calls.

The only way to do that with LTO was to use -fno-toplevel-reorder,
which stops reordering for all declarations and makes LTO partitioning
less efficient.

This patch adds a new no_reorder attribute that stops reordering only
for the marked declaration. The program can then only mark e.g. the
initcalls and leave all the other declarations alone.

The patch does:

- Adds the new no_reorder attribute for the C family.
- Initializes a new no_reorder flag in the symtab_nodes in the
function visibility flag.
- Maintains the no_reorder flag when creating new nodes.
- Changes the partition code to always keep a separate
sorted queue of ordered nodes and flush them in order with the other
nodes. This is used by all nodes with -fno-toplevel-reorder,
and only the marked ones without it.
Parts of the old -fno-toplevel-reorder code paths are reused.
- Adds various checks throughout the tree to make no_reorder
marked functions behave the same as with -fno-toplevel-reorder
- Changes the LTO streamer to serialize the no_reorder attribute.

gcc/c-family/:

2014-09-23  Andi Kleen  <ak@linux.intel.com>

* c-common.c (handle_no_reorder_attribute): New function.
(c_common_attribute_table): Add no_reorder attribute.

gcc/:

2014-09-23  Andi Kleen  <ak@linux.intel.com>

* cgraph.h (symtab_node): Add no_reorder attribute.
(symbol_table::output_asm_statements): Remove.
* cgraphclones.c (cgraph_node::create_clone): Copy no_reorder.
(cgraph_node::create_version_clone): Dito.
(symbol_table::output_asm_statements): Remove.
* trans-mem.c (ipa_tm_create_version_alias): Dito.
* cgraphunit.c (varpool_node::finalize_decl): Check no_reorder.
(output_in_order): Add no_reorder flag. Only handle no_reorder
nodes when set.
(symbol_table::compile): Add separate pass for no_reorder nodes.
(process_common_attributes): Set no_reorder flag in symtab node.
Add node argument.
(process_function_and_variable_attributes): Pass symtab nodes to
process_common_attributes.
* doc/extend.texi (no_reorder): Document no_reorder attribute.
* lto-cgraph.c (lto_output_node): Serialize no_reorder.
(lto_output_varpool_node): Dito.
(input_overwrite_node): Dito.
(input_varpool_node): Dito.
* varpool.c (varpool_node::add): Set no_reorder attribute.
(symbol_table::remove_unreferenced_decls): Handle no_reorder.
(symbol_table::output_variables): Dito.
* symtab.c (symtab_node::dump_base): Print no_reorder.

gcc/lto/:

2014-09-23  Andi Kleen  <ak@linux.intel.com>

* lto-partition.c (node_cmp): Update comment.
(varpool_node_cmp): Use symtab_node for comparison.
(add_sorted_nodes): New function.
(lto_balanced_map): Change to keep ordered queue
of ordered node. Handle no_reorder attribute.

From-SVN: r215537

14 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/cgraph.h
gcc/cgraphclones.c
gcc/cgraphunit.c
gcc/doc/extend.texi
gcc/ipa-visibility.c
gcc/lto-cgraph.c
gcc/lto/ChangeLog
gcc/lto/lto-partition.c
gcc/symtab.c
gcc/trans-mem.c
gcc/varpool.c

index 4d1c9149c25ab826d82abf9ed760b9e1af23e2ca..a0de60bbc534fd0ee44e722070a59320361970a6 100644 (file)
@@ -1,3 +1,29 @@
+2014-09-23  Andi Kleen  <ak@linux.intel.com>
+
+       * cgraph.h (symtab_node): Add no_reorder attribute.
+       (symbol_table::output_asm_statements): Remove.
+       * cgraphclones.c (cgraph_node::create_clone): Copy no_reorder.
+       (cgraph_node::create_version_clone): Dito.
+       (symbol_table::output_asm_statements): Remove.
+       * trans-mem.c (ipa_tm_create_version_alias): Dito.
+       * cgraphunit.c (varpool_node::finalize_decl): Check no_reorder.
+       (output_in_order): Add no_reorder flag. Only handle no_reorder
+       nodes when set.
+       (symbol_table::compile): Add separate pass for no_reorder nodes.
+       (process_common_attributes): Set no_reorder flag in symtab node.
+       Add node argument.
+       (process_function_and_variable_attributes): Pass symtab nodes to
+       process_common_attributes.
+       * doc/extend.texi (no_reorder): Document no_reorder attribute.
+       * lto-cgraph.c (lto_output_node): Serialize no_reorder.
+       (lto_output_varpool_node): Dito.
+       (input_overwrite_node): Dito.
+       (input_varpool_node): Dito.
+       * varpool.c (varpool_node::add): Set no_reorder attribute.
+       (symbol_table::remove_unreferenced_decls): Handle no_reorder.
+       (symbol_table::output_variables): Dito.
+       * symtab.c (symtab_node::dump_base): Print no_reorder.
+
 2014-09-23  Jiong Wang  <jiong.wang@arm.com>
 
        * shrink-wrap.c (try_shrink_wrapping): Check PIC_OFFSET_TABLE_REGNUM not
index 468c78bfa2642bcbb9285981719d2f58eb18ffa3..f8b4a14e4eac1265c6482ec911c888eb459fb9f7 100644 (file)
@@ -1,3 +1,8 @@
+2014-09-23  Andi Kleen  <ak@linux.intel.com>
+
+       * c-common.c (handle_no_reorder_attribute): New function.
+       (c_common_attribute_table): Add no_reorder attribute.
+
 2014-09-22  Joseph Myers  <joseph@codesourcery.com>
 
        * c-cppbuiltin.c (c_cpp_builtins): Define
index 818c32d68a0e0af558640954bd2bbd09a02598f3..a9e019199cdccbfd10687682fb14dc1ecde9f034 100644 (file)
@@ -328,6 +328,8 @@ static tree handle_used_attribute (tree *, tree, tree, int, bool *);
 static tree handle_unused_attribute (tree *, tree, tree, int, bool *);
 static tree handle_externally_visible_attribute (tree *, tree, tree, int,
                                                 bool *);
+static tree handle_no_reorder_attribute (tree *, tree, tree, int,
+                                                bool *);
 static tree handle_const_attribute (tree *, tree, tree, int, bool *);
 static tree handle_transparent_union_attribute (tree *, tree, tree,
                                                int, bool *);
@@ -652,6 +654,8 @@ const struct attribute_spec c_common_attribute_table[] =
                              handle_unused_attribute, false },
   { "externally_visible",     0, 0, true,  false, false,
                              handle_externally_visible_attribute, false },
+  { "no_reorder",            0, 0, true, false, false,
+                              handle_no_reorder_attribute, false },
   /* The same comments as for noreturn attributes apply to const ones.  */
   { "const",                  0, 0, true,  false, false,
                              handle_const_attribute, false },
@@ -6953,6 +6957,30 @@ handle_externally_visible_attribute (tree *pnode, tree name,
   return NULL_TREE;
 }
 
+/* Handle the "no_reorder" attribute. Arguments as in
+   struct attribute_spec.handler. */
+
+static tree
+handle_no_reorder_attribute (tree *pnode,
+                            tree name,
+                            tree,
+                            int,
+                            bool *no_add_attrs)
+{
+  tree node = *pnode;
+
+  if ((TREE_CODE (node) != FUNCTION_DECL && TREE_CODE (node) != VAR_DECL)
+       && !(TREE_STATIC (node) || DECL_EXTERNAL (node)))
+    {
+      warning (OPT_Wattributes,
+               "%qE attribute only affects top level objects",
+               name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "const" attribute; arguments as in
    struct attribute_spec.handler.  */
 
index a316e406ce7af4e972846eefaffe278f09367f89..6c046c739940a2399c6b2206f5527e12a3cffbcf 100644 (file)
@@ -406,6 +406,8 @@ public:
 
   /* Set when function is visible by other units.  */
   unsigned externally_visible : 1;
+  /* Don't reorder to other symbols having this set.  */
+  unsigned no_reorder : 1;
   /* The symbol will be assumed to be used in an invisible way (like
      by an toplevel asm statement).  */
   unsigned force_output : 1;
@@ -1707,9 +1709,6 @@ public:
   /* Output all variables enqueued to be assembled.  */
   bool output_variables (void);
 
-  /* Output all asm statements we have stored up to be output.  */
-  void output_asm_statements (void);
-
   /* Weakrefs may be associated to external decls and thus not output
      at expansion time.  Emit all necessary aliases.  */
   void output_weakrefs (void);
index 224bb55eebb5f76ea1bae64e7bb780c8c3379987..38d92f53e836d8993b03acbbb40f1d831673c6d6 100644 (file)
@@ -437,6 +437,7 @@ cgraph_node::create_clone (tree decl, gcov_type gcov_count, int freq,
   new_node->definition = definition;
   new_node->local = local;
   new_node->externally_visible = false;
+  new_node->no_reorder = no_reorder;
   new_node->local.local = true;
   new_node->global = global;
   new_node->global.inlined_to = new_inlined_to;
@@ -876,6 +877,7 @@ cgraph_node::create_version_clone (tree new_decl,
    new_version->definition = definition;
    new_version->local = local;
    new_version->externally_visible = false;
+   new_version->no_reorder = no_reorder;
    new_version->local.local = new_version->definition;
    new_version->global = global;
    new_version->rtl = rtl;
index 3e3b8d227005ddd52b9d25c854b617510feba571..b854e4b2a37d6c644f12004dd89ba3a6a61b0d0d 100644 (file)
@@ -545,22 +545,6 @@ cgraph_node::add_new_function (tree fndecl, bool lowered)
     DECL_FUNCTION_PERSONALITY (fndecl) = lang_hooks.eh_personality ();
 }
 
-/* Output all asm statements we have stored up to be output.  */
-
-void
-symbol_table::output_asm_statements (void)
-{
-  asm_node *can;
-
-  if (seen_error ())
-    return;
-
-  for (can = first_asm_symbol (); can; can = can->next)
-    assemble_asm (can->asm_str);
-
-  clear_asm_symbols ();
-}
-
 /* Analyze the function scheduled to be output.  */
 void
 cgraph_node::analyze (void)
@@ -657,7 +641,7 @@ symbol_table::process_same_body_aliases (void)
 /* Process attributes common for vars and functions.  */
 
 static void
-process_common_attributes (tree decl)
+process_common_attributes (symtab_node *node, tree decl)
 {
   tree weakref = lookup_attribute ("weakref", DECL_ATTRIBUTES (decl));
 
@@ -670,6 +654,9 @@ process_common_attributes (tree decl)
       DECL_ATTRIBUTES (decl) = remove_attribute ("weakref",
                                                 DECL_ATTRIBUTES (decl));
     }
+
+  if (lookup_attribute ("no_reorder", DECL_ATTRIBUTES (decl)))
+    node->no_reorder = 1;
 }
 
 /* Look for externally_visible and used attributes and mark cgraph nodes
@@ -734,7 +721,7 @@ process_function_and_variable_attributes (cgraph_node *first,
        warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes,
                    "always_inline function might not be inlinable");
      
-      process_common_attributes (decl);
+      process_common_attributes (node, decl);
     }
   for (vnode = symtab->first_variable (); vnode != first_var;
        vnode = symtab->next_variable (vnode))
@@ -763,7 +750,7 @@ process_function_and_variable_attributes (cgraph_node *first,
          DECL_ATTRIBUTES (decl) = remove_attribute ("weakref",
                                                      DECL_ATTRIBUTES (decl));
        }
-      process_common_attributes (decl);
+      process_common_attributes (vnode, decl);
     }
 }
 
@@ -785,8 +772,10 @@ varpool_node::finalize_decl (tree decl)
   if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl)
       /* Traditionally we do not eliminate static variables when not
         optimizing and when not doing toplevel reoder.  */
-      || (!flag_toplevel_reorder && !DECL_COMDAT (node->decl)
-         && !DECL_ARTIFICIAL (node->decl)))
+      || node->no_reorder
+      || ((!flag_toplevel_reorder
+          && !DECL_COMDAT (node->decl)
+          && !DECL_ARTIFICIAL (node->decl))))
     node->force_output = true;
 
   if (symtab->state == CONSTRUCTION
@@ -1922,10 +1911,11 @@ struct cgraph_order_sort
    according to their order fields, which is the order in which they
    appeared in the file.  This implements -fno-toplevel-reorder.  In
    this mode we may output functions and variables which don't really
-   need to be output.  */
+   need to be output.
+   When NO_REORDER is true only do this for symbols marked no reorder. */
 
 static void
-output_in_order (void)
+output_in_order (bool no_reorder)
 {
   int max;
   cgraph_order_sort *nodes;
@@ -1940,6 +1930,8 @@ output_in_order (void)
     {
       if (pf->process && !pf->thunk.thunk_p && !pf->alias)
        {
+         if (no_reorder && !pf->no_reorder)
+           continue;
          i = pf->order;
          gcc_assert (nodes[i].kind == ORDER_UNDEFINED);
          nodes[i].kind = ORDER_FUNCTION;
@@ -1950,6 +1942,8 @@ output_in_order (void)
   FOR_EACH_DEFINED_VARIABLE (pv)
     if (!DECL_EXTERNAL (pv->decl))
       {
+       if (no_reorder && !pv->no_reorder)
+           continue;
        i = pv->order;
        gcc_assert (nodes[i].kind == ORDER_UNDEFINED);
        nodes[i].kind = ORDER_VAR;
@@ -2203,11 +2197,12 @@ symbol_table::compile (void)
   state = EXPANSION;
 
   if (!flag_toplevel_reorder)
-    output_in_order ();
+    output_in_order (false);
   else
     {
-      output_asm_statements ();
-
+      /* Output first asm statements and anything ordered. The process
+         flag is cleared for these nodes, so we skip them later.  */
+      output_in_order (true);
       expand_all_functions ();
       output_variables ();
     }
index 4eef90018206d9fbfeabb860e9326beb001c255c..c78ffb2dabc184e7fa320f8b66bc3dce68832007 100644 (file)
@@ -2180,7 +2180,7 @@ attributes are currently defined for functions on all targets:
 @code{returns_nonnull}, @code{gnu_inline},
 @code{externally_visible}, @code{hot}, @code{cold}, @code{artificial},
 @code{no_sanitize_address}, @code{no_address_safety_analysis},
-@code{no_sanitize_undefined},
+@code{no_sanitize_undefined}, @code{no_reorder},
 @code{error} and @code{warning}.
 Several other attributes are defined for functions on particular
 target systems.  Other attributes, including @code{section} are
@@ -3472,6 +3472,16 @@ my_memcpy (void *dest, const void *src, size_t len)
         __attribute__((nonnull));
 @end smallexample
 
+@item no_reorder
+@cindex @code{no_reorder} function or variable attribute
+Do not reorder functions or variables marked @code{no_reorder}
+against each other or top level assembler statements the executable.
+The actual order in the program will depend on the linker command
+line. Static variables marked like this are also not removed.
+This has a similar effect
+as the @option{-fno-toplevel-reorder} option, but only applies to the
+marked symbols.
+
 @item returns_nonnull
 @cindex @code{returns_nonnull} function attribute
 The @code{returns_nonnull} attribute specifies that the function
index ea6052f8861f10781b2dbdd8140d6403468c2e05..42d528c6634c9ddf7a3270ed50fc429ce584c167 100644 (file)
@@ -640,6 +640,9 @@ function_and_variable_visibility (bool whole_program)
           vnode->externally_visible = false;
          vnode->forced_by_abi = false;
        }
+      if (lookup_attribute ("no_reorder",
+                           DECL_ATTRIBUTES (vnode->decl)))
+       vnode->no_reorder = 1;
       if (!vnode->externally_visible
          && !vnode->weakref)
        {
index 68f6a521682a4ce03e79f45bc241985c503ae2bc..0584946d5b0edf4f70c1639b8a61c0422b46557a 100644 (file)
@@ -508,6 +508,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
   bp = bitpack_create (ob->main_stream);
   bp_pack_value (&bp, node->local.local, 1);
   bp_pack_value (&bp, node->externally_visible, 1);
+  bp_pack_value (&bp, node->no_reorder, 1);
   bp_pack_value (&bp, node->definition, 1);
   bp_pack_value (&bp, node->local.versionable, 1);
   bp_pack_value (&bp, node->local.can_change_signature, 1);
@@ -581,6 +582,7 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, varpool_node *node,
   lto_output_var_decl_index (ob->decl_state, ob->main_stream, node->decl);
   bp = bitpack_create (ob->main_stream);
   bp_pack_value (&bp, node->externally_visible, 1);
+  bp_pack_value (&bp, node->no_reorder, 1);
   bp_pack_value (&bp, node->force_output, 1);
   bp_pack_value (&bp, node->forced_by_abi, 1);
   bp_pack_value (&bp, node->unique_name, 1);
@@ -1041,6 +1043,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data,
 
   node->local.local = bp_unpack_value (bp, 1);
   node->externally_visible = bp_unpack_value (bp, 1);
+  node->no_reorder = bp_unpack_value (bp, 1);
   node->definition = bp_unpack_value (bp, 1);
   node->local.versionable = bp_unpack_value (bp, 1);
   node->local.can_change_signature = bp_unpack_value (bp, 1);
@@ -1246,6 +1249,7 @@ input_varpool_node (struct lto_file_decl_data *file_data,
 
   bp = streamer_read_bitpack (ib);
   node->externally_visible = bp_unpack_value (&bp, 1);
+  node->no_reorder = bp_unpack_value (&bp, 1);
   node->force_output = bp_unpack_value (&bp, 1);
   node->forced_by_abi = bp_unpack_value (&bp, 1);
   node->unique_name = bp_unpack_value (&bp, 1);
index a8dd53f8a8e49a66d6c23a20f818d4324be3cb6d..762296cc6b7cdccd174caaf2f8cc08611ab58974 100644 (file)
@@ -1,3 +1,11 @@
+2014-09-23  Andi Kleen  <ak@linux.intel.com>
+
+       * lto-partition.c (node_cmp): Update comment.
+       (varpool_node_cmp): Use symtab_node for comparison.
+       (add_sorted_nodes): New function.
+       (lto_balanced_map): Change to keep ordered queue
+       of ordered node. Handle no_reorder attribute.
+
 2014-09-11  Jan Hubicka  <hubicka@ucw.cz>
 
        * lto.c (lto_read_decls): Register ODR types.
index 5bd089b128660b1f36d396b110f3ddb09d241f2e..0451a66be3457b7515b019d077c516304f417d03 100644 (file)
@@ -333,7 +333,8 @@ lto_max_map (void)
     new_partition ("empty");
 }
 
-/* Helper function for qsort; sort nodes by order.  */
+/* Helper function for qsort; sort nodes by order. noreorder functions must have
+   been removed earlier.  */
 static int
 node_cmp (const void *pa, const void *pb)
 {
@@ -365,11 +366,26 @@ node_cmp (const void *pa, const void *pb)
 static int
 varpool_node_cmp (const void *pa, const void *pb)
 {
-  const varpool_node *a = *(const varpool_node * const *) pa;
-  const varpool_node *b = *(const varpool_node * const *) pb;
+  const symtab_node *a = *static_cast<const symtab_node * const *> (pa);
+  const symtab_node *b = *static_cast<const symtab_node * const *> (pb);
   return b->order - a->order;
 }
 
+/* Add all symtab nodes from NEXT_NODE to PARTITION in order.  */
+
+static void
+add_sorted_nodes (vec<symtab_node *> &next_nodes, ltrans_partition partition)
+{
+  unsigned i;
+  symtab_node *node;
+
+  next_nodes.qsort (varpool_node_cmp);
+  FOR_EACH_VEC_ELT (next_nodes, i, node)
+    if (!symbol_partitioned_p (node))
+      add_symbol_to_partition (partition, node);
+}
+
+
 /* Group cgraph nodes into equally-sized partitions.
 
    The partitioning algorithm is simple: nodes are taken in predefined order.
@@ -414,7 +430,8 @@ lto_balanced_map (int n_lto_partitions)
   int n_nodes = 0;
   int n_varpool_nodes = 0, varpool_pos = 0, best_varpool_pos = 0;
   struct cgraph_node **order = XNEWVEC (cgraph_node *, symtab->cgraph_max_uid);
-  varpool_node **varpool_order = NULL;
+  auto_vec<cgraph_node *> noreorder;
+  auto_vec<varpool_node *> varpool_order;
   int i;
   struct cgraph_node *node;
   int total_size = 0, best_total_size = 0;
@@ -427,6 +444,7 @@ lto_balanced_map (int n_lto_partitions)
     INT_MAX, best_internal = 0;
   int npartitions;
   int current_order = -1;
+  int noreorder_pos = 0;
 
   FOR_EACH_VARIABLE (vnode)
     gcc_assert (!vnode->aux);
@@ -434,7 +452,10 @@ lto_balanced_map (int n_lto_partitions)
   FOR_EACH_DEFINED_FUNCTION (node)
     if (node->get_partitioning_class () == SYMBOL_PARTITION)
       {
-       order[n_nodes++] = node;
+       if (node->no_reorder)
+         noreorder.safe_push (node);
+       else
+         order[n_nodes++] = node;
        if (!node->alias)
          total_size += inline_summary (node)->size;
       }
@@ -445,27 +466,26 @@ lto_balanced_map (int n_lto_partitions)
      get better about minimizing the function bounday, but until that
      things works smoother if we order in source order.  */
   qsort (order, n_nodes, sizeof (struct cgraph_node *), node_cmp);
+  noreorder.qsort (node_cmp);
 
   if (symtab->dump_file)
-    for(i = 0; i < n_nodes; i++)
-      fprintf (symtab->dump_file, "Balanced map symbol order:%s:%u\n",
-              order[i]->name (), order[i]->tp_first_run);
-
-  if (!flag_toplevel_reorder)
     {
-      FOR_EACH_VARIABLE (vnode)
-       if (vnode->get_partitioning_class () == SYMBOL_PARTITION)
-         n_varpool_nodes++;
-      varpool_order = XNEWVEC (varpool_node *, n_varpool_nodes);
-
-      n_varpool_nodes = 0;
-      FOR_EACH_VARIABLE (vnode)
-       if (vnode->get_partitioning_class () == SYMBOL_PARTITION)
-         varpool_order[n_varpool_nodes++] = vnode;
-      qsort (varpool_order, n_varpool_nodes, sizeof (varpool_node *),
-            varpool_node_cmp);
+      for(i = 0; i < n_nodes; i++)
+       fprintf (symtab->dump_file, "Balanced map symbol order:%s:%u\n",
+                order[i]->name (), order[i]->tp_first_run);
+      for(i = 0; i < (int)noreorder.length(); i++)
+       fprintf (symtab->dump_file, "Balanced map symbol no_reorder:%s:%u\n",
+                noreorder[i]->name (), noreorder[i]->tp_first_run);
     }
 
+  /* Collect all variables that should not be reordered.  */
+  FOR_EACH_VARIABLE (vnode)
+    if (vnode->get_partitioning_class () == SYMBOL_PARTITION
+       && (!flag_toplevel_reorder || vnode->no_reorder))
+      varpool_order.safe_push (vnode);
+  n_varpool_nodes = varpool_order.length ();
+  varpool_order.qsort (varpool_node_cmp);
+
   /* Compute partition size and create the first partition.  */
   partition_size = total_size / n_lto_partitions;
   if (partition_size < PARAM_VALUE (MIN_PARTITION_SIZE))
@@ -476,6 +496,8 @@ lto_balanced_map (int n_lto_partitions)
     fprintf (symtab->dump_file, "Total unit size: %i, partition size: %i\n",
             total_size, partition_size);
 
+  auto_vec<symtab_node *> next_nodes;
+
   for (i = 0; i < n_nodes; i++)
     {
       if (symbol_partitioned_p (order[i]))
@@ -483,14 +505,19 @@ lto_balanced_map (int n_lto_partitions)
 
       current_order = order[i]->order;
 
-      if (!flag_toplevel_reorder)
-       while (varpool_pos < n_varpool_nodes
-              && varpool_order[varpool_pos]->order < current_order)
-         {
-           if (!symbol_partitioned_p (varpool_order[varpool_pos]))
-             add_symbol_to_partition (partition, varpool_order[varpool_pos]);
-           varpool_pos++;
-         }
+      /* Output noreorder and varpool in program order first.  */
+      next_nodes.truncate (0);
+      while (varpool_pos < n_varpool_nodes
+            && varpool_order[varpool_pos]->order < current_order)
+       next_nodes.safe_push (varpool_order[varpool_pos++]);
+      while (noreorder_pos < (int)noreorder.length ()
+            && noreorder[noreorder_pos]->order < current_order)
+       {
+         if (!noreorder[noreorder_pos]->alias)
+           total_size -= inline_summary (noreorder[noreorder_pos])->size;
+         next_nodes.safe_push (noreorder[noreorder_pos++]);
+       }
+      add_sorted_nodes (next_nodes, partition);
 
       add_symbol_to_partition (partition, order[i]);
       if (!order[i]->alias)
@@ -580,6 +607,7 @@ lto_balanced_map (int n_lto_partitions)
                if (!vnode->definition)
                  continue;
                if (!symbol_partitioned_p (vnode) && flag_toplevel_reorder
+                   && !vnode->no_reorder
                    && vnode->get_partitioning_class () == SYMBOL_PARTITION)
                  add_symbol_to_partition (partition, vnode);
                index = lto_symtab_encoder_lookup (partition->encoder,
@@ -616,6 +644,7 @@ lto_balanced_map (int n_lto_partitions)
                   to be removed.  Coupling with objects they refer to only helps to reduce
                   number of symbols promoted to hidden.  */
                if (!symbol_partitioned_p (vnode) && flag_toplevel_reorder
+                   && !vnode->no_reorder
                    && !vnode->can_remove_if_no_refs_p ()
                    && vnode->get_partitioning_class () == SYMBOL_PARTITION)
                  add_symbol_to_partition (partition, vnode);
@@ -705,24 +734,25 @@ lto_balanced_map (int n_lto_partitions)
        }
     }
 
+  next_nodes.truncate (0);
+
   /* Varables that are not reachable from the code go into last partition.  */
   if (flag_toplevel_reorder)
     {
       FOR_EACH_VARIABLE (vnode)
        if (vnode->get_partitioning_class () == SYMBOL_PARTITION
-           && !symbol_partitioned_p (vnode))
-         add_symbol_to_partition (partition, vnode);
-    }
-  else
-    {
-      while (varpool_pos < n_varpool_nodes)
-       {
-         if (!symbol_partitioned_p (varpool_order[varpool_pos]))
-           add_symbol_to_partition (partition, varpool_order[varpool_pos]);
-         varpool_pos++;
-       }
-      free (varpool_order);
+           && !symbol_partitioned_p (vnode)
+           && !vnode->no_reorder)
+         next_nodes.safe_push (vnode);
     }
+
+  /* Output remaining ordered symbols.  */
+  while (varpool_pos < n_varpool_nodes)
+    next_nodes.safe_push (varpool_order[varpool_pos++]);
+  while (noreorder_pos < (int)noreorder.length ())
+    next_nodes.safe_push (noreorder[noreorder_pos++]);
+  add_sorted_nodes (next_nodes, partition);
+
   free (order);
 }
 
index 9590fc83dd2c320501e634361a9ddd4b658c386c..76223b2f20ee58f39111d7c93f469f6a8eb60b48 100644 (file)
@@ -831,6 +831,8 @@ symtab_node::dump_base (FILE *f)
     fprintf (f, " forced_by_abi");
   if (externally_visible)
     fprintf (f, " externally_visible");
+  if (no_reorder)
+    fprintf (f, " no_reorder");
   if (resolution != LDPR_UNKNOWN)
     fprintf (f, " %s",
             ld_plugin_symbol_resolution_names[(int)resolution]);
index 82857963f544a55bf77316c54f23e57cddf1777b..94d896d6f9db57f11badd94ae629bd8a0eeea61c 100644 (file)
@@ -4849,6 +4849,7 @@ ipa_tm_create_version_alias (struct cgraph_node *node, void *data)
   new_node = cgraph_node::create_same_body_alias (new_decl, info->new_decl);
   new_node->tm_clone = true;
   new_node->externally_visible = info->old_node->externally_visible;
+  new_node->no_reorder = info->old_node->no_reorder;
   /* ?? Do not traverse aliases here.  */
   get_cg_data (&node, false)->clone = new_node;
 
index 14ef0896eac21594d55c2beb4d866aff92d9e02b..8001c93b012f4b1ee9c0f183b893ec021757b9af 100644 (file)
@@ -449,6 +449,8 @@ varpool_node::add (tree decl)
   symtab->call_varpool_insertion_hooks (node);
   if (node->externally_visible_p ())
     node->externally_visible = true;
+  if (lookup_attribute ("no_reorder", decl))
+    node->no_reorder = 1;
 }
 
 /* Return variable availability.  See cgraph.h for description of individual
@@ -640,7 +642,7 @@ symbol_table::remove_unreferenced_decls (void)
   for (node = first_defined_variable (); node; node = next)
     {
       next = next_defined_variable (node);
-      if (!node->aux)
+      if (!node->aux && !node->no_reorder)
        {
          if (dump_file)
            fprintf (dump_file, " %s", node->asm_name ());
@@ -687,11 +689,22 @@ symbol_table::output_variables (void)
   timevar_push (TV_VAROUT);
 
   FOR_EACH_DEFINED_VARIABLE (node)
-    node->finalize_named_section_flags ();
+    {
+      /* Handled in output_in_order.  */
+      if (node->no_reorder)
+       continue;
+
+      node->finalize_named_section_flags ();
+    }
 
   FOR_EACH_DEFINED_VARIABLE (node)
-    if (node->assemble_decl ())
-      changed = true;
+    {
+      /* Handled in output_in_order.  */
+      if (node->no_reorder)
+       continue;
+      if (node->assemble_decl ())
+        changed = true;
+    }
   timevar_pop (TV_VAROUT);
   return changed;
 }