/* Callgraph based interprocedural optimizations.
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- 2011 Free Software Foundation, Inc.
+ 2011, 2012 Free Software Foundation, Inc.
Contributed by Jan Hubicka
This file is part of GCC.
to change the behavior here. */
if (((TREE_PUBLIC (decl)
|| (!optimize
+ && !node->same_body_alias
&& !DECL_DISREGARD_INLINE_LIMITS (decl)
&& !DECL_DECLARED_INLINE_P (decl)
&& !(DECL_CONTEXT (decl)
return false;
node = cgraph_function_or_thunk_node (node, NULL);
- if ((e->callee->former_clone_of != node->decl)
+ if ((e->callee->former_clone_of != node->decl
+ && (!node->same_body_alias
+ || e->callee->former_clone_of != node->thunk.alias))
/* IPA-CP sometimes redirect edge to clone and then back to the former
- function. This ping-pong has to go, eventaully. */
+ function. This ping-pong has to go, eventually. */
&& (node != cgraph_function_or_thunk_node (e->callee, NULL))
- && !clone_of_p (node, e->callee))
+ && !clone_of_p (node, e->callee)
+ /* If decl is a same body alias of some other decl, allow e->callee to be
+ a clone of a clone of that other decl too. */
+ && (!node->same_body_alias
+ || !clone_of_p (cgraph_get_node (node->thunk.alias), e->callee)))
return true;
else
return false;
for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++)
if (ref->use != IPA_REF_ALIAS)
{
- error ("Alias has non-alias refernece");
+ error ("Alias has non-alias reference");
error_found = true;
}
else if (ref_found)
if (node->alias && node->thunk.alias)
{
struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias);
+ struct cgraph_node *n;
+
+ for (n = tgt; n && n->alias;
+ n = n->analyzed ? cgraph_alias_aliased_node (n) : NULL)
+ if (n == node)
+ {
+ error ("function %q+D part of alias cycle", node->decl);
+ node->alias = false;
+ return;
+ }
if (!VEC_length (ipa_ref_t, node->ref_list.references))
ipa_record_reference (node, NULL, tgt, NULL, IPA_REF_ALIAS, NULL);
if (node->same_body_alias)
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. */
+ /* FIXME: in an ltrans unit when the offline copy is outside a
+ partition but inline copies are inside a partition, we can
+ end up not removing the body since we no longer have an
+ analyzed node pointing to it. */
&& !node->in_other_partition
&& !DECL_EXTERNAL (decl))
{
dump_cgraph_node (stderr, node);
- internal_error ("failed to reclaim unneeded functionin same comdat group");
+ internal_error ("failed to reclaim unneeded function in same "
+ "comdat group");
}
}
#endif
VEC_quick_push (tree, vargs, arg);
call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias), vargs);
VEC_free (tree, heap, vargs);
- gimple_call_set_cannot_inline (call, true);
gimple_call_set_from_thunk (call, true);
if (restmp)
gimple_call_set_lhs (call, restmp);
#endif
bitmap_obstack_release (NULL);
cgraph_mark_functions_to_output ();
+ output_weakrefs ();
cgraph_state = CGRAPH_STATE_EXPANSION;
if (!flag_toplevel_reorder)
varpool_assemble_pending_decls ();
}
- output_weakrefs ();
cgraph_process_new_functions ();
cgraph_state = CGRAPH_STATE_FINISHED;
cgraph_redirect_edge_callee (e, new_version);
}
+ cgraph_call_node_duplication_hooks (old_version, new_version);
+
return new_version;
}
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.
+
If non-NULL ARGS_TO_SKIP determine function parameters to remove
from new version.
+ If SKIP_RETURN is true, the new version will return void.
If non-NULL BLOCK_TO_COPY determine what basic blocks to copy.
- If non_NULL NEW_ENTRY determine new entry BB of the clone. */
+ If non_NULL NEW_ENTRY determine new entry BB of the clone.
+
+ Return the new version's cgraph node. */
struct cgraph_node *
cgraph_function_versioning (struct cgraph_node *old_version_node,
VEC(cgraph_edge_p,heap) *redirect_callers,
VEC (ipa_replace_map_p,gc)* tree_map,
bitmap args_to_skip,
+ bool skip_return,
bitmap bbs_to_copy,
basic_block new_entry_block,
const char *clone_name)
gcc_assert (old_version_node->local.can_change_signature || !args_to_skip);
- /* Make a new FUNCTION_DECL tree node for the
- new version. */
- if (!args_to_skip)
+ /* Make a new FUNCTION_DECL tree node for the new version. */
+ if (!args_to_skip && !skip_return)
new_decl = copy_node (old_decl);
else
- new_decl = build_function_decl_skip_args (old_decl, args_to_skip);
+ new_decl
+ = build_function_decl_skip_args (old_decl, args_to_skip, skip_return);
/* Generate a new name for the new version. */
DECL_NAME (new_decl) = clone_function_name (old_decl, clone_name);
/* Copy the OLD_VERSION_NODE function tree to the new version. */
tree_function_versioning (old_decl, new_decl, tree_map, false, args_to_skip,
- bbs_to_copy, new_entry_block);
+ skip_return, bbs_to_copy, new_entry_block);
/* Update the new version's properties.
Make The new version visible only within this translation unit. Make sure
/* Copy the OLD_VERSION_NODE function tree to the new version. */
tree_function_versioning (node->clone_of->decl, node->decl,
node->clone.tree_map, true,
- node->clone.args_to_skip, NULL, NULL);
+ node->clone.args_to_skip, false,
+ NULL, NULL);
if (cgraph_dump_file)
{
dump_function_to_file (node->clone_of->decl, cgraph_dump_file, dump_flags);
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);
+ xstrdup (cgraph_node_name (e->caller)), e->caller->uid,
+ xstrdup (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)
{
if (cgraph_dump_file)
{
fprintf (cgraph_dump_file, "cloning %s to %s\n",
- cgraph_node_name (node->clone_of),
- cgraph_node_name (node));
+ xstrdup (cgraph_node_name (node->clone_of)),
+ xstrdup (cgraph_node_name (node)));
if (node->clone.tree_map)
{
unsigned int i;
replace_info = VEC_index (ipa_replace_map_p,
node->clone.tree_map,
i);
- print_generic_expr (cgraph_dump_file, replace_info->old_tree, 0);
+ print_generic_expr (cgraph_dump_file,
+ replace_info->old_tree, 0);
fprintf (cgraph_dump_file, " -> ");
- print_generic_expr (cgraph_dump_file, replace_info->new_tree, 0);
+ print_generic_expr (cgraph_dump_file,
+ replace_info->new_tree, 0);
fprintf (cgraph_dump_file, "%s%s;",
replace_info->replace_p ? "(replace)":"",
replace_info->ref_p ? "(ref)":"");
if (node->clone.args_to_skip)
{
fprintf (cgraph_dump_file, " args_to_skip: ");
- dump_bitmap (cgraph_dump_file, node->clone.args_to_skip);
+ dump_bitmap (cgraph_dump_file,
+ node->clone.args_to_skip);
}
if (node->clone.args_to_skip)
{
- fprintf (cgraph_dump_file, " combined_args_to_skip:");
- dump_bitmap (cgraph_dump_file, node->clone.combined_args_to_skip);
+ fprintf (cgraph_dump_file,
+ " combined_args_to_skip:");
+ dump_bitmap (cgraph_dump_file,
+ node->clone.combined_args_to_skip);
}
}
cgraph_materialize_clone (node);