https://gcc.gnu.org/g:cc5779fcaf76aeee005f986eb1dc15205c696544
commit r15-5637-gcc5779fcaf76aeee005f986eb1dc15205c696544 Author: Martin Jambor <mjam...@suse.cz> Date: Sun Nov 24 23:03:43 2024 +0100 ipa: Move individual jump function copying to a separate function When reviewing various IPA bits and pieces I have falsely assumed that jump function duplication misses copying important bits because it relies on vec_safe_copy-ing all data in the vector of jump functions and then just fixes up the few fields it needs to. Perhaps more importantly, we do want a function to copy one individual jump function to form jump functions for planned call-graph edges that model transfer of control to OpenMP outlined regions through calls to gomp functions. Therefore, this patch introduces such function and makes ipa_edge_args_sum_t::duplicate just allocate the new vectors and then uses the new function to copy the data. 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. Diff: --- gcc/ipa-prop.cc | 188 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 111 insertions(+), 77 deletions(-) diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc index cbc825670fe0..9070a45f6835 100644 --- a/gcc/ipa-prop.cc +++ b/gcc/ipa-prop.cc @@ -4503,99 +4503,96 @@ ipa_edge_args_sum_t::remove (cgraph_edge *cs, ipa_edge_args *args) } } -/* Method invoked when an edge is duplicated. Copy ipa_edge_args and adjust - reference count data strucutres accordingly. */ +/* Copy information from SRC_JF to DST_JF which correstpond to call graph edges + SRC and DST. */ -void -ipa_edge_args_sum_t::duplicate (cgraph_edge *src, cgraph_edge *dst, - ipa_edge_args *old_args, ipa_edge_args *new_args) +static void +ipa_duplicate_jump_function (cgraph_edge *src, cgraph_edge *dst, + ipa_jump_func *src_jf, ipa_jump_func *dst_jf) { - unsigned int i; + dst_jf->agg.items = vec_safe_copy (src_jf->agg.items); + dst_jf->agg.by_ref = src_jf->agg.by_ref; - new_args->jump_functions = vec_safe_copy (old_args->jump_functions); - if (old_args->polymorphic_call_contexts) - new_args->polymorphic_call_contexts - = vec_safe_copy (old_args->polymorphic_call_contexts); + /* We can avoid calling ipa_set_jfunc_vr since it would only look up the + place in the hash_table where the source m_vr resides. */ + dst_jf->m_vr = src_jf->m_vr; - for (i = 0; i < vec_safe_length (old_args->jump_functions); i++) + if (src_jf->type == IPA_JF_CONST) { - 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); + ipa_set_jf_cst_copy (dst_jf, src_jf); + struct ipa_cst_ref_desc *src_rdesc = jfunc_rdesc_usable (src_jf); - if (src_jf->type == IPA_JF_CONST) + if (!src_rdesc) + dst_jf->value.constant.rdesc = NULL; + else if (src->caller == dst->caller) { - 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) + /* 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) { - struct ipa_cst_ref_desc *dst_rdesc = ipa_refdesc_pool.allocate (); + 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 = src_rdesc->next_duplicate; - src_rdesc->next_duplicate = dst_rdesc; + dst_rdesc->next_duplicate = NULL; 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; + 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) + } + else if (src_jf->type == IPA_JF_PASS_THROUGH) + { + dst_jf->type = IPA_JF_PASS_THROUGH; + dst_jf->value.pass_through = src_jf->value.pass_through; + if (src->caller == dst->caller) { struct cgraph_node *inline_root = dst->caller->inlined_to ? dst->caller->inlined_to : dst->caller; @@ -4610,6 +4607,43 @@ ipa_edge_args_sum_t::duplicate (cgraph_edge *src, cgraph_edge *dst, } } } + else if (src_jf->type == IPA_JF_ANCESTOR) + { + dst_jf->type = IPA_JF_ANCESTOR; + dst_jf->value.ancestor = src_jf->value.ancestor; + } + else + gcc_assert (src_jf->type == IPA_JF_UNKNOWN); +} + +/* Method invoked when an edge is duplicated. Copy ipa_edge_args and adjust + reference count data strucutres accordingly. */ + +void +ipa_edge_args_sum_t::duplicate (cgraph_edge *src, cgraph_edge *dst, + ipa_edge_args *old_args, ipa_edge_args *new_args) +{ + unsigned int i; + + if (old_args->polymorphic_call_contexts) + new_args->polymorphic_call_contexts + = vec_safe_copy (old_args->polymorphic_call_contexts); + + if (!vec_safe_length (old_args->jump_functions)) + { + new_args->jump_functions = NULL; + return; + } + vec_safe_grow_cleared (new_args->jump_functions, + old_args->jump_functions->length (), true); + + for (i = 0; i < vec_safe_length (old_args->jump_functions); i++) + { + 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); + + ipa_duplicate_jump_function (src, dst, src_jf, dst_jf); + } } /* Analyze newly added function into callgraph. */