+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
+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
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 *);
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 },
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. */
/* 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;
/* 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);
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;
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;
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)
/* 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));
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
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))
DECL_ATTRIBUTES (decl) = remove_attribute ("weakref",
DECL_ATTRIBUTES (decl));
}
- process_common_attributes (decl);
+ process_common_attributes (vnode, 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
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;
{
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;
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;
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 ();
}
@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
__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
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)
{
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);
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);
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);
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);
+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.
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)
{
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.
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;
INT_MAX, best_internal = 0;
int npartitions;
int current_order = -1;
+ int noreorder_pos = 0;
FOR_EACH_VARIABLE (vnode)
gcc_assert (!vnode->aux);
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;
}
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))
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]))
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)
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,
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);
}
}
+ 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);
}
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]);
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;
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
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 ());
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;
}