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)
break;
}
cgraph_call_function_insertion_hooks (node);
+ varpool_analyze_pending_decls ();
}
return output;
}
error ("Inline clone is needed");
error_found = true;
}
+ for (e = node->indirect_calls; e; e = e->next_callee)
+ {
+ if (e->aux)
+ {
+ error ("aux field set for indirect edge from %s",
+ identifier_to_locale (cgraph_node_name (e->caller)));
+ error_found = true;
+ }
+ if (!e->indirect_unknown_callee
+ || !e->indirect_info)
+ {
+ error ("An indirect edge from %s is not marked as indirect or has "
+ "associated indirect_info, the corresponding statement is: ",
+ identifier_to_locale (cgraph_node_name (e->caller)));
+ debug_gimple_stmt (e->call_stmt);
+ error_found = true;
+ }
+ }
for (e = node->callers; e; e = e->next_caller)
{
if (e->count < 0)
error ("double linked list of clones corrupted");
error_found = true;
}
+ if (node->same_comdat_group)
+ {
+ struct cgraph_node *n = node->same_comdat_group;
+
+ if (!DECL_ONE_ONLY (node->decl))
+ {
+ error ("non-DECL_ONE_ONLY node in a same_comdat_group list");
+ error_found = true;
+ }
+ if (n == node)
+ {
+ error ("node is alone in a comdat group");
+ error_found = true;
+ }
+ do
+ {
+ if (!n->same_comdat_group)
+ {
+ error ("same_comdat_group is not a circular list");
+ error_found = true;
+ break;
+ }
+ n = n->same_comdat_group;
+ }
+ while (n != node);
+ }
if (node->analyzed && gimple_has_body_p (node->decl)
&& !TREE_ASM_WRITTEN (node->decl)
gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
- tree decl;
- if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
+ if (is_gimple_call (stmt))
{
struct cgraph_edge *e = cgraph_edge (node, stmt);
+ tree decl = gimple_call_fndecl (stmt);
if (e)
{
if (e->aux)
debug_gimple_stmt (stmt);
error_found = true;
}
- if (e->callee->same_body_alias)
+ if (!e->indirect_unknown_callee)
{
- error ("edge points to same body alias:");
- debug_tree (e->callee->decl);
- error_found = true;
+ if (e->callee->same_body_alias)
+ {
+ error ("edge points to same body alias:");
+ debug_tree (e->callee->decl);
+ error_found = true;
+ }
+ else if (!node->global.inlined_to
+ && !e->callee->global.inlined_to
+ && decl
+ && !clone_of_p (cgraph_node (decl),
+ e->callee))
+ {
+ error ("edge points to wrong declaration:");
+ debug_tree (e->callee->decl);
+ fprintf (stderr," Instead of:");
+ debug_tree (decl);
+ error_found = true;
+ }
}
- else if (!clone_of_p (cgraph_node (decl), e->callee)
- && !e->callee->global.inlined_to)
+ else if (decl)
{
- error ("edge points to wrong declaration:");
- debug_tree (e->callee->decl);
- fprintf (stderr," Instead of:");
- debug_tree (decl);
+ error ("an indirect edge with unknown callee "
+ "corresponding to a call_stmt with "
+ "a known declaration:");
error_found = true;
+ debug_gimple_stmt (e->call_stmt);
}
e->aux = (void *)1;
}
- else
+ else if (decl)
{
error ("missing callgraph edge for call stmt:");
debug_gimple_stmt (stmt);
for (e = node->callees; e; e = e->next_callee)
{
- if (!e->aux && !e->indirect_call)
+ if (!e->aux)
{
error ("edge %s->%s has no corresponding call_stmt",
identifier_to_locale (cgraph_node_name (e->caller)),
}
e->aux = 0;
}
+ for (e = node->indirect_calls; e; e = e->next_callee)
+ {
+ if (!e->aux)
+ {
+ error ("an indirect edge from %s has no corresponding call_stmt",
+ identifier_to_locale (cgraph_node_name (e->caller)));
+ debug_gimple_stmt (e->call_stmt);
+ error_found = true;
+ }
+ e->aux = 0;
+ }
}
if (error_found)
{
current_function_decl = decl;
push_cfun (DECL_STRUCT_FUNCTION (decl));
+ assign_assembler_name_if_neeeded (node->decl);
+
/* Make sure to gimplify bodies only once. During analyzing a
function we lower it, which will require gimplified nested
functions, so we can end up here with an already gimplified
for (node = cgraph_nodes; node != first; node = node->next)
{
tree decl = node->decl;
- if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
+ if (DECL_PRESERVE_P (decl))
{
mark_decl_referenced (decl);
if (node->local.finalized)
for (vnode = varpool_nodes; vnode != first_var; vnode = vnode->next)
{
tree decl = vnode->decl;
- if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
+ if (DECL_PRESERVE_P (decl))
{
mark_decl_referenced (decl);
vnode->force_output = true;
outside the current compilation unit. */
if (node->analyzed
&& !node->global.inlined_to
- && (node->needed
+ && (node->needed || node->reachable_from_other_partition
|| (e && node->reachable))
&& !TREE_ASM_WRITTEN (decl)
&& !DECL_EXTERNAL (decl))
#ifdef ENABLE_CHECKING
if (!node->global.inlined_to
&& gimple_has_body_p (decl)
+ /* FIXME: in ltrans unit when offline copy is outside partition but inline copies
+ are inside partition, we can end up not removing the body since we no longer
+ have analyzed node pointing to it. */
+ && !node->in_other_partition
&& !DECL_EXTERNAL (decl))
{
dump_cgraph_node (stderr, node);
#endif
gcc_assert (node->global.inlined_to
|| !gimple_has_body_p (decl)
+ || node->in_other_partition
|| DECL_EXTERNAL (decl));
}
tree decl = node->decl;
if (!node->global.inlined_to
&& gimple_has_body_p (decl)
+ /* FIXME: in ltrans unit when offline copy is outside partition but inline copies
+ are inside partition, we can end up not removing the body since we no longer
+ have analyzed node pointing to it. */
+ && !node->in_other_partition
&& !DECL_EXTERNAL (decl))
{
dump_cgraph_node (stderr, node);
cgraph_output_in_order (void)
{
int max;
- size_t size;
struct cgraph_order_sort *nodes;
int i;
struct cgraph_node *pf;
struct cgraph_asm_node *pa;
max = cgraph_order;
- size = max * sizeof (struct cgraph_order_sort);
- nodes = (struct cgraph_order_sort *) alloca (size);
- memset (nodes, 0, size);
+ nodes = XCNEWVEC (struct cgraph_order_sort, max);
varpool_analyze_pending_decls ();
}
cgraph_asm_nodes = NULL;
+ free (nodes);
}
/* Return true when function body of DECL still needs to be kept around
DECL_ARTIFICIAL (decl) = 1;
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
DECL_SAVED_TREE (decl) = body;
- TREE_PUBLIC (decl) = ! targetm.have_ctors_dtors;
+ if (!targetm.have_ctors_dtors)
+ {
+ TREE_PUBLIC (decl) = 1;
+ DECL_PRESERVE_P (decl) = 1;
+ }
DECL_UNINLINABLE (decl) = 1;
DECL_INITIAL (decl) = make_node (BLOCK);
VEC(cgraph_edge_p,heap) *redirect_callers)
{
struct cgraph_node *new_version;
- struct cgraph_edge *e, *new_e;
+ struct cgraph_edge *e;
struct cgraph_edge *next_callee;
unsigned i;
also cloned. */
for (e = old_version->callees;e; e=e->next_callee)
{
- new_e = cgraph_clone_edge (e, new_version, e->call_stmt,
- e->lto_stmt_uid, 0, e->frequency,
- e->loop_nest, true);
- new_e->count = e->count;
+ cgraph_clone_edge (e, new_version, e->call_stmt,
+ e->lto_stmt_uid, REG_BR_PROB_BASE,
+ CGRAPH_FREQ_BASE,
+ e->loop_nest, true);
}
/* Fix recursive calls.
If OLD_VERSION has a recursive call after the
that is not weak also.
??? We cannot use COMDAT linkage because there is no
ABI support for this. */
- DECL_EXTERNAL (new_version_node->decl) = 0;
- DECL_COMDAT_GROUP (new_version_node->decl) = NULL_TREE;
- TREE_PUBLIC (new_version_node->decl) = 0;
- DECL_COMDAT (new_version_node->decl) = 0;
- DECL_WEAK (new_version_node->decl) = 0;
+ cgraph_make_decl_local (new_version_node->decl);
DECL_VIRTUAL_P (new_version_node->decl) = 0;
new_version_node->local.externally_visible = 0;
new_version_node->local.local = 1;
bitmap_obstack_release (NULL);
}
+/* If necessary, change the function declaration in the call statement
+ associated with E so that it corresponds to the edge callee. */
+
+gimple
+cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e)
+{
+ tree decl = gimple_call_fndecl (e->call_stmt);
+ gimple new_stmt;
+ gimple_stmt_iterator gsi;
+
+ if (!decl || decl == e->callee->decl
+ /* Don't update call from same body alias to the real function. */
+ || cgraph_get_node (decl) == cgraph_get_node (e->callee->decl))
+ return e->call_stmt;
+
+ if (cgraph_dump_file)
+ {
+ fprintf (cgraph_dump_file, "updating call of %s/%i -> %s/%i: ",
+ cgraph_node_name (e->caller), e->caller->uid,
+ cgraph_node_name (e->callee), e->callee->uid);
+ print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags);
+ }
+
+ if (e->callee->clone.combined_args_to_skip)
+ new_stmt = gimple_call_copy_skip_args (e->call_stmt,
+ e->callee->clone.combined_args_to_skip);
+ else
+ new_stmt = e->call_stmt;
+ if (gimple_vdef (new_stmt)
+ && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME)
+ SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
+ gimple_call_set_fndecl (new_stmt, e->callee->decl);
+
+ gsi = gsi_for_stmt (e->call_stmt);
+ gsi_replace (&gsi, new_stmt, true);
+ update_stmt (new_stmt);
+
+ /* Update EH information too, just in case. */
+ maybe_clean_or_replace_eh_stmt (e->call_stmt, new_stmt);
+
+ cgraph_set_call_stmt_including_clones (e->caller, e->call_stmt, new_stmt);
+
+ if (cgraph_dump_file)
+ {
+ fprintf (cgraph_dump_file, " updated to:");
+ print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags);
+ }
+ return new_stmt;
+}
+
/* Once all functions from compilation unit are in memory, produce all clones
- and update all calls.
- We might also do this on demand if we don't want to bring all functions to
- memory prior compilation, but current WHOPR implementation does that and it is
- is bit easier to keep everything right in this order. */
+ and update all calls. We might also do this on demand if we don't want to
+ bring all functions to memory prior compilation, but current WHOPR
+ implementation does that and it is is bit easier to keep everything right in
+ this order. */
void
cgraph_materialize_all_clones (void)
{
if (cgraph_dump_file)
fprintf (cgraph_dump_file, "Updating call sites\n");
for (node = cgraph_nodes; node; node = node->next)
- if (node->analyzed && gimple_has_body_p (node->decl)
- && (!node->clone_of || node->clone_of->decl != node->decl))
+ if (node->analyzed && !node->clone_of
+ && gimple_has_body_p (node->decl))
{
struct cgraph_edge *e;
current_function_decl = node->decl;
push_cfun (DECL_STRUCT_FUNCTION (node->decl));
for (e = node->callees; e; e = e->next_callee)
- {
- tree decl = gimple_call_fndecl (e->call_stmt);
- /* When function gets inlined, indirect inlining might've invented
- new edge for orginally indirect stmt. Since we are not
- preserving clones in the original form, we must not update here
- since other inline clones don't need to contain call to the same
- call. Inliner will do the substitution for us later. */
- if (decl && decl != e->callee->decl)
- {
- gimple new_stmt;
- gimple_stmt_iterator gsi;
-
- if (cgraph_get_node (decl) == cgraph_get_node (e->callee->decl))
- /* Don't update call from same body alias to the real function. */
- continue;
-
- if (cgraph_dump_file)
- {
- fprintf (cgraph_dump_file, "updating call of %s in %s:",
- cgraph_node_name (node),
- cgraph_node_name (e->callee));
- print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags);
- }
-
- if (e->callee->clone.combined_args_to_skip)
- new_stmt = gimple_call_copy_skip_args (e->call_stmt,
- e->callee->clone.combined_args_to_skip);
- else
- new_stmt = e->call_stmt;
- if (gimple_vdef (new_stmt)
- && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME)
- SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
- gimple_call_set_fndecl (new_stmt, e->callee->decl);
-
- gsi = gsi_for_stmt (e->call_stmt);
- gsi_replace (&gsi, new_stmt, true);
-
- /* Update EH information too, just in case. */
- maybe_clean_or_replace_eh_stmt (e->call_stmt, new_stmt);
-
- cgraph_set_call_stmt_including_clones (node, e->call_stmt, new_stmt);
-
- if (cgraph_dump_file)
- {
- fprintf (cgraph_dump_file, " updated to:");
- print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags);
- }
- }
- }
+ cgraph_redirect_edge_call_stmt_to_callee (e);
+ gcc_assert (!need_ssa_update_p (cfun));
pop_cfun ();
current_function_decl = NULL;
#ifdef ENABLE_CHECKING
verify_cgraph_node (node);
#endif
}
+ if (cgraph_dump_file)
+ fprintf (cgraph_dump_file, "Materialization Call site updates done.\n");
+ /* All changes to parameters have been performed. In order not to
+ incorrectly repeat them, we simply dispose of the bitmaps that drive the
+ changes. */
+ for (node = cgraph_nodes; node; node = node->next)
+ node->clone.combined_args_to_skip = NULL;
#ifdef ENABLE_CHECKING
verify_cgraph ();
#endif