gcc_unreachable ();
break;
}
+ cgraph_call_function_insertion_hooks (node);
}
return output;
}
}
if (node->analyzed
- && gimple_body (node->decl)
&& !TREE_ASM_WRITTEN (node->decl)
&& (!DECL_EXTERNAL (node->decl) || node->global.inlined_to))
{
{
fprintf (cgraph_dump_file, "Initial entry points:");
for (node = cgraph_nodes; node != first_analyzed; node = node->next)
- if (node->needed && gimple_body (node->decl))
+ if (node->needed)
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
fprintf (cgraph_dump_file, "\n");
}
if (!edge->callee->reachable)
cgraph_mark_reachable_node (edge->callee);
+ /* If decl is a clone of an abstract function, mark that abstract
+ function so that we don't release its body. The DECL_INITIAL() of that
+ abstract function declaration will be later needed to output debug info. */
+ if (DECL_ABSTRACT_ORIGIN (decl))
+ {
+ struct cgraph_node *origin_node = cgraph_node (DECL_ABSTRACT_ORIGIN (decl));
+ origin_node->abstract_and_needed = true;
+ }
+
/* We finalize local static variables during constructing callgraph
edges. Process their attributes too. */
process_function_and_variable_attributes (first_processed,
{
fprintf (cgraph_dump_file, "Unit entry points:");
for (node = cgraph_nodes; node != first_analyzed; node = node->next)
- if (node->needed && gimple_body (node->decl))
+ if (node->needed)
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
fprintf (cgraph_dump_file, "\n\nInitial ");
dump_cgraph (cgraph_dump_file);
tree decl = node->decl;
next = node->next;
- if (node->local.finalized && !gimple_body (decl))
+ if (node->local.finalized && !gimple_has_body_p (decl))
cgraph_reset_node (node);
- if (!node->reachable && gimple_body (decl))
+ if (!node->reachable && gimple_has_body_p (decl))
{
if (cgraph_dump_file)
fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
}
else
node->next_needed = NULL;
- gcc_assert (!node->local.finalized || gimple_body (decl));
+ gcc_assert (!node->local.finalized || gimple_has_body_p (decl));
gcc_assert (node->analyzed == node->local.finalized);
}
if (cgraph_dump_file)
/* We need to output all local functions that are used and not
always inlined, as well as those that are reachable from
outside the current compilation unit. */
- if (gimple_body (decl)
+ if (node->analyzed
&& !node->global.inlined_to
&& (node->needed
|| (e && node->reachable))
/* We should've reclaimed all functions that are not needed. */
#ifdef ENABLE_CHECKING
if (!node->global.inlined_to
- && gimple_body (decl)
+ && gimple_has_body_p (decl)
&& !DECL_EXTERNAL (decl))
{
dump_cgraph_node (stderr, node);
}
#endif
gcc_assert (node->global.inlined_to
- || !gimple_body (decl)
+ || !gimple_has_body_p (decl)
|| DECL_EXTERNAL (decl));
}
tree_rest_of_compilation (decl);
/* Make sure that BE didn't give up on compiling. */
- /* ??? Can happen with nested function of extern inline. */
gcc_assert (TREE_ASM_WRITTEN (decl));
current_function_decl = NULL;
- if (!cgraph_preserve_function_body_p (decl))
- {
- cgraph_release_function_body (node);
- /* Eliminate all call edges. This is important so the call_expr no longer
- points to the dead function body. */
- cgraph_node_remove_callees (node);
- }
+ gcc_assert (!cgraph_preserve_function_body_p (decl));
+ cgraph_release_function_body (node);
+ /* Eliminate all call edges. This is important so the GIMPLE_CALL no longer
+ points to the dead function body. */
+ cgraph_node_remove_callees (node);
cgraph_function_flags_ready = true;
}
for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed
&& (node->global.inlined_to
- || gimple_body (node->decl)))
+ || gimple_has_body_p (node->decl)))
{
error_found = true;
dump_cgraph_node (stderr, node);
/* Update the call expr on the edges to call the new version. */
for (e = new_version->callers; e; e = e->next_caller)
- gimple_call_set_fndecl (e->call_stmt, new_version->decl);
+ {
+ struct function *inner_function = DECL_STRUCT_FUNCTION (e->caller->decl);
+ gimple_call_set_fndecl (e->call_stmt, new_version->decl);
+ /* Update EH information too, just in case. */
+ if (!stmt_could_throw_p (e->call_stmt)
+ && lookup_stmt_eh_region_fn (inner_function, e->call_stmt))
+ remove_stmt_from_eh_region_fn (inner_function, e->call_stmt);
+ }
}
TREE_MAP is a mapping of tree nodes we want to replace with
new ones (according to results of prior analysis).
OLD_VERSION_NODE is the node that is versioned.
- It returns the new version's cgraph node. */
+ It returns the new version's cgraph node.
+ ARGS_TO_SKIP lists arguments to be omitted from functions
+ */
struct cgraph_node *
cgraph_function_versioning (struct cgraph_node *old_version_node,
VEC(cgraph_edge_p,heap) *redirect_callers,
- varray_type tree_map)
+ varray_type tree_map,
+ bitmap args_to_skip)
{
tree old_decl = old_version_node->decl;
struct cgraph_node *new_version_node = NULL;
/* Make a new FUNCTION_DECL tree node for the
new version. */
- new_decl = copy_node (old_decl);
+ if (!args_to_skip)
+ new_decl = copy_node (old_decl);
+ else
+ new_decl = build_function_decl_skip_args (old_decl, args_to_skip);
/* Create the new version's call-graph node.
and update the edges of the new node. */
redirect_callers);
/* Copy the OLD_VERSION_NODE function tree to the new version. */
- tree_function_versioning (old_decl, new_decl, tree_map, false);
- /* Update the call_expr on the edges to call the new version node. */
- update_call_expr (new_version_node);
+ tree_function_versioning (old_decl, new_decl, tree_map, false, args_to_skip);
/* Update the new version's properties.
- Make The new version visible only within this translation unit.
+ Make The new version visible only within this translation unit. Make sure
+ 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_ONE_ONLY (new_version_node->decl) = 0;
TREE_PUBLIC (new_version_node->decl) = 0;
DECL_COMDAT (new_version_node->decl) = 0;
+ DECL_WEAK (new_version_node->decl) = 0;
new_version_node->local.externally_visible = 0;
new_version_node->local.local = 1;
new_version_node->lowered = true;
+
+ /* Update the call_expr on the edges to call the new version node. */
+ update_call_expr (new_version_node);
+
+ cgraph_call_function_insertion_hooks (new_version_node);
return new_version_node;
}
gcc_assert (first_clone == cgraph_node (first_clone->decl));
/* Copy the OLD_VERSION_NODE function tree to the new version. */
- tree_function_versioning (node->decl, first_clone->decl, NULL, true);
+ tree_function_versioning (node->decl, first_clone->decl, NULL, true, NULL);
DECL_EXTERNAL (first_clone->decl) = 0;
DECL_ONE_ONLY (first_clone->decl) = 0;