Hi, Even though we have had code to handle creation of indirect call graph edges (so that these calls can than be made direct as part of IPA-CP and inlining and eventually also inlined) for C++ member pointers for many years, this code expects the member pointers to be structures passed by value. In PR 108802 it turned out that for lambdas these are passed by reference. This patch adjusts the code for that so that small lambdas are also inlineable without depending on early inlining.
Bootstrapped and LTO bootstrapped on x86_64-linux. This is technically a regression against GCC 10. OK for master even now? Thanks, Martin gcc/ChangeLog: 2024-02-20 Martin Jambor <mjam...@suse.cz> PR ipa/108802 * ipa-prop.cc (ipa_get_stmt_member_ptr_load_param): Also recognize loads from a pointer parameter. (ipa_analyze_indirect_call_uses): Likewise. gcc/testsuite/ChangeLog: 2024-02-20 Martin Jambor <mjam...@suse.cz> PR ipa/108802 * g++.dg/ipa/pr108802.C: New test. --- gcc/ipa-prop.cc | 56 +++++++++++++++++++++-------- gcc/testsuite/g++.dg/ipa/pr108802.C | 14 ++++++++ 2 files changed, 55 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ipa/pr108802.C diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc index bec0ebd210c..25d252fd57c 100644 --- a/gcc/ipa-prop.cc +++ b/gcc/ipa-prop.cc @@ -2514,14 +2514,26 @@ ipa_get_stmt_member_ptr_load_param (gimple *stmt, bool use_delta, if (TREE_CODE (rhs) != MEM_REF) return NULL_TREE; rec = TREE_OPERAND (rhs, 0); - if (TREE_CODE (rec) != ADDR_EXPR) - return NULL_TREE; - rec = TREE_OPERAND (rec, 0); - if (TREE_CODE (rec) != PARM_DECL - || !type_like_member_ptr_p (TREE_TYPE (rec), &ptr_field, &delta_field)) + if (TREE_CODE (rec) == ADDR_EXPR) + { + rec = TREE_OPERAND (rec, 0); + if (TREE_CODE (rec) != PARM_DECL + || !type_like_member_ptr_p (TREE_TYPE (rec), &ptr_field, + &delta_field)) + return NULL_TREE; + } + else if (TREE_CODE (rec) == SSA_NAME + && SSA_NAME_IS_DEFAULT_DEF (rec)) + { + if (TREE_CODE (SSA_NAME_VAR (rec)) != PARM_DECL + || !type_like_member_ptr_p (TREE_TYPE (TREE_TYPE (rec)), &ptr_field, + &delta_field)) + return NULL_TREE; + } + else return NULL_TREE; - ref_offset = TREE_OPERAND (rhs, 1); + ref_offset = TREE_OPERAND (rhs, 1); if (use_delta) fld = delta_field; else @@ -2757,17 +2769,31 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call, if (rec != rec2) return; - index = ipa_get_param_decl_index (info, rec); - if (index >= 0 - && parm_preserved_before_stmt_p (fbi, index, call, rec)) + if (TREE_CODE (rec) == SSA_NAME) { - struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, - call, false); - cs->indirect_info->offset = offset; - cs->indirect_info->agg_contents = 1; - cs->indirect_info->member_ptr = 1; - cs->indirect_info->guaranteed_unmodified = 1; + index = ipa_get_param_decl_index (info, SSA_NAME_VAR (rec)); + if (index < 0 + || !parm_ref_data_preserved_p (fbi, index, call, + gimple_assign_rhs1 (def))) + return; + by_ref = true; } + else + { + index = ipa_get_param_decl_index (info, rec); + if (index < 0 + || !parm_preserved_before_stmt_p (fbi, index, call, rec)) + return; + by_ref = false; + } + + struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, + call, false); + cs->indirect_info->offset = offset; + cs->indirect_info->agg_contents = 1; + cs->indirect_info->member_ptr = 1; + cs->indirect_info->by_ref = by_ref; + cs->indirect_info->guaranteed_unmodified = 1; return; } diff --git a/gcc/testsuite/g++.dg/ipa/pr108802.C b/gcc/testsuite/g++.dg/ipa/pr108802.C new file mode 100644 index 00000000000..2e2b6c66b64 --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/pr108802.C @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -std=c++14 -fdump-ipa-inline -fno-early-inlining" } */ +/* { dg-add-options bind_pic_locally } */ + +struct A { + int interesting(int x) { return 2 * x; } +}; + +int f1() { + A a; + return [&](auto&& f) { return (a.*f)(42); } (&A::interesting); +} + +/* { dg-final { scan-ipa-dump "A::interesting\[^\\n\]*inline copy in int f1" "inline" } } */ -- 2.43.0