Hi, when reviewing various IPA bits and pieces I have discovered two embarrassing problems with jump function duplication.
First, aggregate jump function vector copying contained a pasto where the source is the (empty) destination vector and so no aggregate jump functions ever got copied to jump functions of clones. Second, the code did not copy value range information stored in the jump functions, again not making them available for the inliner when examining calls going out of IPA clones. This patch fixes both issues and on top of that moves copying of individual jump functions out of the duplication hook to a special function because we expect it to be useful in creating jump functions for planned call-graph edges that model transfer of control to OpenMP outlined regions through calls to gomp functions. Bootstrapped and tested on x86_64-linux, the whole patch series has additionally passed LTO and profiled-LTO bootstrap on the same platform and a bootstrap and testsuite on ppc64-linux. Aarch64-linux bootstrap and testing is in progress. Because we have agreed with Honza this is necessary last week, I consider the patch pre-approved and will commit it later today. Thanks, Martin gcc/ChangeLog: 2024-11-01 Martin Jambor <mjam...@suse.cz> * ipa-prop.cc (ipa_duplicate_jump_function): New function. (ipa_edge_args_sum_t::duplicate): Move individual jump function copying to ipa_duplicate_jump_function. --- gcc/ipa-prop.cc | 187 ++++++++++++++++++++++++++---------------------- 1 file changed, 100 insertions(+), 87 deletions(-) diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc index add3a12b584..db8eda8c361 100644 --- a/gcc/ipa-prop.cc +++ b/gcc/ipa-prop.cc @@ -4497,6 +4497,105 @@ ipa_edge_args_sum_t::remove (cgraph_edge *cs, ipa_edge_args *args) } } +/* Copy information from SRC_JF to DST_JF which correstpond to call graph edges + SRC and DST. */ + +static void +ipa_duplicate_jump_function (cgraph_edge *src, cgraph_edge *dst, + ipa_jump_func *src_jf, ipa_jump_func *dst_jf) +{ + dst_jf->agg.items = vec_safe_copy (src_jf->agg.items); + + if (src_jf->type == IPA_JF_CONST) + { + struct ipa_cst_ref_desc *src_rdesc = jfunc_rdesc_usable (src_jf); + + if (!src_rdesc) + dst_jf->value.constant.rdesc = NULL; + else if (src->caller == dst->caller) + { + /* Creation of a speculative edge. If the source edge is the one + grabbing a reference, we must create a new (duplicate) + reference description. Otherwise they refer to the same + description corresponding to a reference taken in a function + src->caller is inlined to. In that case we just must + increment the refcount. */ + if (src_rdesc->cs == src) + { + symtab_node *n = symtab_node_for_jfunc (src_jf); + gcc_checking_assert (n); + ipa_ref *ref + = src->caller->find_reference (n, src->call_stmt, + src->lto_stmt_uid, + IPA_REF_ADDR); + gcc_checking_assert (ref); + dst->caller->clone_reference (ref, ref->stmt); + + ipa_cst_ref_desc *dst_rdesc = ipa_refdesc_pool.allocate (); + dst_rdesc->cs = dst; + dst_rdesc->refcount = src_rdesc->refcount; + dst_rdesc->next_duplicate = NULL; + dst_jf->value.constant.rdesc = dst_rdesc; + } + else + { + src_rdesc->refcount++; + dst_jf->value.constant.rdesc = src_rdesc; + } + } + else if (src_rdesc->cs == src) + { + struct ipa_cst_ref_desc *dst_rdesc = ipa_refdesc_pool.allocate (); + dst_rdesc->cs = dst; + dst_rdesc->refcount = src_rdesc->refcount; + dst_rdesc->next_duplicate = src_rdesc->next_duplicate; + src_rdesc->next_duplicate = dst_rdesc; + dst_jf->value.constant.rdesc = dst_rdesc; + } + else + { + struct ipa_cst_ref_desc *dst_rdesc; + /* This can happen during inlining, when a JFUNC can refer to a + reference taken in a function up in the tree of inline clones. + We need to find the duplicate that refers to our tree of + inline clones. */ + + gcc_assert (dst->caller->inlined_to); + for (dst_rdesc = src_rdesc->next_duplicate; + dst_rdesc; + dst_rdesc = dst_rdesc->next_duplicate) + { + struct cgraph_node *top; + top = dst_rdesc->cs->caller->inlined_to + ? dst_rdesc->cs->caller->inlined_to + : dst_rdesc->cs->caller; + if (dst->caller->inlined_to == top) + break; + } + gcc_assert (dst_rdesc); + dst_jf->value.constant.rdesc = dst_rdesc; + } + } + else if (dst_jf->type == IPA_JF_PASS_THROUGH + && src->caller == dst->caller) + { + struct cgraph_node *inline_root = dst->caller->inlined_to + ? dst->caller->inlined_to : dst->caller; + ipa_node_params *root_info = ipa_node_params_sum->get (inline_root); + int idx = ipa_get_jf_pass_through_formal_id (dst_jf); + + int c = ipa_get_controlled_uses (root_info, idx); + if (c != IPA_UNDESCRIBED_USE) + { + c++; + ipa_set_controlled_uses (root_info, idx, c); + } + } + + if (src_jf->m_vr && src_jf->m_vr->known_p ()) + ipa_set_jfunc_vr (dst_jf, *src_jf->m_vr); +} + /* Method invoked when an edge is duplicated. Copy ipa_edge_args and adjust reference count data strucutres accordingly. */ @@ -4516,93 +4615,7 @@ ipa_edge_args_sum_t::duplicate (cgraph_edge *src, cgraph_edge *dst, struct ipa_jump_func *src_jf = ipa_get_ith_jump_func (old_args, i); struct ipa_jump_func *dst_jf = ipa_get_ith_jump_func (new_args, i); - dst_jf->agg.items = vec_safe_copy (dst_jf->agg.items); - - if (src_jf->type == IPA_JF_CONST) - { - struct ipa_cst_ref_desc *src_rdesc = jfunc_rdesc_usable (src_jf); - - if (!src_rdesc) - dst_jf->value.constant.rdesc = NULL; - else if (src->caller == dst->caller) - { - /* Creation of a speculative edge. If the source edge is the one - grabbing a reference, we must create a new (duplicate) - reference description. Otherwise they refer to the same - description corresponding to a reference taken in a function - src->caller is inlined to. In that case we just must - increment the refcount. */ - if (src_rdesc->cs == src) - { - symtab_node *n = symtab_node_for_jfunc (src_jf); - gcc_checking_assert (n); - ipa_ref *ref - = src->caller->find_reference (n, src->call_stmt, - src->lto_stmt_uid, - IPA_REF_ADDR); - gcc_checking_assert (ref); - dst->caller->clone_reference (ref, ref->stmt); - - ipa_cst_ref_desc *dst_rdesc = ipa_refdesc_pool.allocate (); - dst_rdesc->cs = dst; - dst_rdesc->refcount = src_rdesc->refcount; - dst_rdesc->next_duplicate = NULL; - dst_jf->value.constant.rdesc = dst_rdesc; - } - else - { - src_rdesc->refcount++; - dst_jf->value.constant.rdesc = src_rdesc; - } - } - else if (src_rdesc->cs == src) - { - struct ipa_cst_ref_desc *dst_rdesc = ipa_refdesc_pool.allocate (); - dst_rdesc->cs = dst; - dst_rdesc->refcount = src_rdesc->refcount; - dst_rdesc->next_duplicate = src_rdesc->next_duplicate; - src_rdesc->next_duplicate = dst_rdesc; - dst_jf->value.constant.rdesc = dst_rdesc; - } - else - { - struct ipa_cst_ref_desc *dst_rdesc; - /* This can happen during inlining, when a JFUNC can refer to a - reference taken in a function up in the tree of inline clones. - We need to find the duplicate that refers to our tree of - inline clones. */ - - gcc_assert (dst->caller->inlined_to); - for (dst_rdesc = src_rdesc->next_duplicate; - dst_rdesc; - dst_rdesc = dst_rdesc->next_duplicate) - { - struct cgraph_node *top; - top = dst_rdesc->cs->caller->inlined_to - ? dst_rdesc->cs->caller->inlined_to - : dst_rdesc->cs->caller; - if (dst->caller->inlined_to == top) - break; - } - gcc_assert (dst_rdesc); - dst_jf->value.constant.rdesc = dst_rdesc; - } - } - else if (dst_jf->type == IPA_JF_PASS_THROUGH - && src->caller == dst->caller) - { - struct cgraph_node *inline_root = dst->caller->inlined_to - ? dst->caller->inlined_to : dst->caller; - ipa_node_params *root_info = ipa_node_params_sum->get (inline_root); - int idx = ipa_get_jf_pass_through_formal_id (dst_jf); - - int c = ipa_get_controlled_uses (root_info, idx); - if (c != IPA_UNDESCRIBED_USE) - { - c++; - ipa_set_controlled_uses (root_info, idx, c); - } - } + ipa_duplicate_jump_function (src, dst, src_jf, dst_jf); } } -- 2.47.0