> Hi,
>
> PR 57539 revealed two problems with remapping reference descriptors
> during cloning of trees of inlined call graph nodes. First, when
> indirect inlining is involved, we happily remove the reference
> descriptor itself by calling ipa_free_edge_args_substructures in
> ipa_propagate_indirect_call_infos. Second, the current remapping code
> does not work because the global.inlined_to field of the destination
> caller is not yet set.
>
> The patch below fixes the first problem by not calling the freeing
> function and the second one by making cgraph_clone_node set the
> required field prior to calling any duplication hooks (which is the
> only place where we have the pair of corresponding source and
> destination edge at our disposal so the duplication/remapping has to
> happen there). I have also shortened the lists of corresponding
> references and cleared up the search loop a little.
>
> I'll post a testcase in a separate patch. This one bootstrapped and
> passed testsuite on x86_64-linux without any issues. OK for trunk?
>
> Thanks,
>
> Martin
>
>
> 2013-06-10 Martin Jambor <[email protected]>
>
> PR tree-optimization/57539
> * cgraphclones.c (cgraph_clone_node): Add parameter new_inlined_to, set
> global.inlined_to of the new node to it. All callers changed.
> * ipa-inline-transform.c (clone_inlined_nodes): New variable
> inlining_into, pass it to cgraph_clone_node.
> * ipa-prop.c (ipa_propagate_indirect_call_infos): Do not call
> ipa_free_edge_args_substructures.
> (ipa_edge_duplication_hook): Only add edges from inlined nodes to
> rdesc linked list. Do not assert rdesc edges have inlined caller.
> Assert we have found an rdesc in the rdesc list.
OK,
thanks
Honza
>
> Index: src/gcc/cgraph.h
> ===================================================================
> --- src.orig/gcc/cgraph.h
> +++ src/gcc/cgraph.h
> @@ -707,7 +707,7 @@ struct cgraph_edge * cgraph_clone_edge (
> unsigned, gcov_type, int, bool);
> struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree,
> gcov_type,
> int, bool, vec<cgraph_edge_p>,
> - bool);
> + bool, struct cgraph_node *);
> tree clone_function_name (tree decl, const char *);
> struct cgraph_node * cgraph_create_virtual_clone (struct cgraph_node
> *old_node,
> vec<cgraph_edge_p>,
> Index: src/gcc/cgraphclones.c
> ===================================================================
> --- src.orig/gcc/cgraphclones.c
> +++ src/gcc/cgraphclones.c
> @@ -167,13 +167,19 @@ cgraph_clone_edge (struct cgraph_edge *e
> function's profile to reflect the fact that part of execution is handled
> by node.
> When CALL_DUPLICATOIN_HOOK is true, the ipa passes are acknowledged about
> - the new clone. Otherwise the caller is responsible for doing so later. */
> + the new clone. Otherwise the caller is responsible for doing so later.
> +
> + If the new node is being inlined into another one, NEW_INLINED_TO should
> be
> + the outline function the new one is (even indirectly) inlined to. All
> hooks
> + will see this in node's global.inlined_to, when invoked. Can be NULL if
> the
> + node is not inlined. */
>
> struct cgraph_node *
> cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int
> freq,
> bool update_original,
> vec<cgraph_edge_p> redirect_callers,
> - bool call_duplication_hook)
> + bool call_duplication_hook,
> + struct cgraph_node *new_inlined_to)
> {
> struct cgraph_node *new_node = cgraph_create_empty_node ();
> struct cgraph_edge *e;
> @@ -195,6 +201,7 @@ cgraph_clone_node (struct cgraph_node *n
> new_node->symbol.externally_visible = false;
> new_node->local.local = true;
> new_node->global = n->global;
> + new_node->global.inlined_to = new_inlined_to;
> new_node->rtl = n->rtl;
> new_node->count = count;
> new_node->frequency = n->frequency;
> @@ -307,7 +314,7 @@ cgraph_create_virtual_clone (struct cgra
>
> new_node = cgraph_clone_node (old_node, new_decl, old_node->count,
> CGRAPH_FREQ_BASE, false,
> - redirect_callers, false);
> + redirect_callers, false, NULL);
> /* Update the properties.
> Make clone visible only within this translation unit. Make sure
> that is not weak also.
> Index: src/gcc/ipa-inline-transform.c
> ===================================================================
> --- src.orig/gcc/ipa-inline-transform.c
> +++ src/gcc/ipa-inline-transform.c
> @@ -132,6 +132,13 @@ void
> clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
> bool update_original, int *overall_size)
> {
> + struct cgraph_node *inlining_into;
> +
> + if (e->caller->global.inlined_to)
> + inlining_into = e->caller->global.inlined_to;
> + else
> + inlining_into = e->caller;
> +
> if (duplicate)
> {
> /* We may eliminate the need for out-of-line copy to be output.
> @@ -167,18 +174,15 @@ clone_inlined_nodes (struct cgraph_edge
> {
> struct cgraph_node *n;
> n = cgraph_clone_node (e->callee, e->callee->symbol.decl,
> - e->count, e->frequency,
> - update_original, vNULL, true);
> + e->count, e->frequency, update_original,
> + vNULL, true, inlining_into);
> cgraph_redirect_edge_callee (e, n);
> }
> }
> else
> symtab_dissolve_same_comdat_group_list ((symtab_node) e->callee);
>
> - if (e->caller->global.inlined_to)
> - e->callee->global.inlined_to = e->caller->global.inlined_to;
> - else
> - e->callee->global.inlined_to = e->caller;
> + e->callee->global.inlined_to = inlining_into;
>
> /* Recursively clone all bodies. */
> for (e = e->callee->callees; e; e = e->next_callee)
> Index: src/gcc/ipa-inline.c
> ===================================================================
> --- src.orig/gcc/ipa-inline.c
> +++ src/gcc/ipa-inline.c
> @@ -1315,7 +1315,7 @@ recursive_inlining (struct cgraph_edge *
> /* We need original clone to copy around. */
> master_clone = cgraph_clone_node (node, node->symbol.decl,
> node->count, CGRAPH_FREQ_BASE,
> - false, vNULL, true);
> + false, vNULL, true, NULL);
> for (e = master_clone->callees; e; e = e->next_callee)
> if (!e->inline_failed)
> clone_inlined_nodes (e, true, false, NULL);
> Index: src/gcc/ipa-prop.c
> ===================================================================
> --- src.orig/gcc/ipa-prop.c
> +++ src/gcc/ipa-prop.c
> @@ -2683,9 +2683,6 @@ ipa_propagate_indirect_call_infos (struc
> propagate_controlled_uses (cs);
> changed = propagate_info_to_inlined_callees (cs, cs->callee, new_edges);
>
> - /* We do not keep jump functions of inlined edges up to date. Better to
> free
> - them so we do not access them accidentally. */
> - ipa_free_edge_args_substructures (IPA_EDGE_REF (cs));
> return changed;
> }
>
> @@ -2815,9 +2812,12 @@ ipa_edge_duplication_hook (struct cgraph
> dst_rdesc
> = (struct ipa_cst_ref_desc *) pool_alloc (ipa_refdesc_pool);
> dst_rdesc->cs = dst;
> - dst_rdesc->next_duplicate = src_rdesc->next_duplicate;
> - src_rdesc->next_duplicate = dst_rdesc;
> dst_rdesc->refcount = src_rdesc->refcount;
> + if (dst->caller->global.inlined_to)
> + {
> + dst_rdesc->next_duplicate = src_rdesc->next_duplicate;
> + src_rdesc->next_duplicate = dst_rdesc;
> + }
> dst_jf->value.constant.rdesc = dst_rdesc;
> }
> else
> @@ -2832,13 +2832,10 @@ ipa_edge_duplication_hook (struct cgraph
> for (dst_rdesc = src_rdesc->next_duplicate;
> dst_rdesc;
> dst_rdesc = dst_rdesc->next_duplicate)
> - {
> - gcc_assert (dst_rdesc->cs->caller->global.inlined_to);
> - if (dst_rdesc->cs->caller->global.inlined_to
> - == dst->caller->global.inlined_to)
> - break;
> - }
> -
> + if (dst_rdesc->cs->caller->global.inlined_to
> + == dst->caller->global.inlined_to)
> + break;
> + gcc_assert (dst_rdesc);
> dst_jf->value.constant.rdesc = dst_rdesc;
> }
> }
> Index: src/gcc/lto-cgraph.c
> ===================================================================
> --- src.orig/gcc/lto-cgraph.c
> +++ src/gcc/lto-cgraph.c
> @@ -951,7 +951,7 @@ input_node (struct lto_file_decl_data *f
> {
> node = cgraph_clone_node (cgraph (nodes[clone_ref]), fn_decl,
> 0, CGRAPH_FREQ_BASE, false,
> - vNULL, false);
> + vNULL, false, NULL);
> }
> else
> node = cgraph_get_create_node (fn_decl);