> Hi, > > this patch fixes PR 60640 by creating thunks to clones when that is > necessary to properly redirect edges to them. I mostly does what > cgraph_add_thunk does and what analyze_function does to thunks. It > fixes the testcases on trunk (it does not apply to 4.8, I have not > looked how easily fixable that it) and passes bootstrap and testing on > x86_64-linux. > > OK for trunk? > > Thanks, > > Martin > > > 2014-03-26 Martin Jambor <mjam...@suse.cz> > > * cgraph.h (cgraph_clone_node): New parameter added to declaration. > Adjust all callers. > * cgraphclones.c (build_function_type_skip_args): Moved upwards in the > file. > (build_function_decl_skip_args): Likewise. > (duplicate_thunk_for_node): New function. > (redirect_edge_duplicating_thunks): Likewise. > (cgraph_clone_node): New parameter args_to_skip, pass it to > redirect_edge_duplicating_thunks which is called instead of > cgraph_redirect_edge_callee. > (cgraph_create_virtual_clone): Pass args_to_skip to cgraph_clone_node. > +/* Duplicate thunk THUNK but make it to refer to NODE. ARGS_TO_SKIP, if > + non-NULL, determines which parameters should be omitted. */ > + > +static cgraph_node * > +duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node, > + bitmap args_to_skip) > +{ > + cgraph_node *new_thunk, *thunk_of; > + thunk_of = cgraph_function_or_thunk_node (thunk->callees->callee); > + > + if (thunk_of->thunk.thunk_p) > + node = duplicate_thunk_for_node (thunk_of, node, args_to_skip); > + > + tree new_decl; > + if (!args_to_skip) > + new_decl = copy_node (thunk->decl); > + else > + new_decl = build_function_decl_skip_args (thunk->decl, args_to_skip, > false); > + > + gcc_checking_assert (!DECL_STRUCT_FUNCTION (new_decl)); > + gcc_checking_assert (!DECL_INITIAL (new_decl)); > + gcc_checking_assert (!DECL_RESULT (new_decl)); > + gcc_checking_assert (!DECL_RTL_SET_P (new_decl)); > + > + DECL_NAME (new_decl) = clone_function_name (thunk->decl, > "artificial_thunk"); > + SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl)); > + DECL_EXTERNAL (new_decl) = 0; > + DECL_SECTION_NAME (new_decl) = NULL; > + DECL_COMDAT_GROUP (new_decl) = 0; > + TREE_PUBLIC (new_decl) = 0; > + DECL_COMDAT (new_decl) = 0; > + DECL_WEAK (new_decl) = 0; > + DECL_VIRTUAL_P (new_decl) = 0; > + DECL_STATIC_CONSTRUCTOR (new_decl) = 0; > + DECL_STATIC_DESTRUCTOR (new_decl) = 0;
We probably ought to factor out this to common subfunction. > + > + new_thunk = cgraph_create_node (new_decl); > + new_thunk->definition = true; > + new_thunk->thunk = thunk->thunk; > + new_thunk->unique_name = in_lto_p; > + new_thunk->externally_visible = 0; > + new_thunk->local.local = 1; > + new_thunk->lowered = true; > + new_thunk->former_clone_of = thunk->decl; > + > + struct cgraph_edge *e = cgraph_create_edge (new_thunk, node, NULL, 0, > + CGRAPH_FREQ_BASE); > + e->call_stmt_cannot_inline_p = true; > + cgraph_call_edge_duplication_hooks (thunk->callees, e); > + if (!expand_thunk (new_thunk, false)) > + new_thunk->analyzed = true; > + cgraph_call_node_duplication_hooks (thunk, new_thunk); > + return new_thunk; > +} > + > +/* If E does not lead to a thunk, simply redirect it to N. Otherwise create > + one or more equivalent thunks for N and redirect E to the first in the > + chain. */ > + > +void > +redirect_edge_duplicating_thunks (struct cgraph_edge *e, struct cgraph_node > *n, > + bitmap args_to_skip) > +{ > + cgraph_node *orig_to = cgraph_function_or_thunk_node (e->callee); > + if (orig_to->thunk.thunk_p) > + n = duplicate_thunk_for_node (orig_to, n, args_to_skip); Is there anything that would pevent us from creating a new thunk for each call? Also I think you need to avoid this logic when THIS parameter is being optimized out (i.e. it is part of skip_args) Thanks for looking into this! Honza