On Wed, Feb 9, 2022 at 8:16 AM Eugene Rozenfeld via Gcc-patches <gcc-patches@gcc.gnu.org> wrote: > > AutoFDO tries to promote and inline all indirect calls that were promoted > and inlined in the original binary and that are still hot. In the included > test case, the promotion results in a direct call that is a recursive call. > inline_call and optimize_inline_calls can't handle recursive calls at this > stage. > Currently, inline_call fails with a segmentation fault. > > This change leaves the indirect call alone if promotion will result in a > recursive call. > > Tested on x86_64-pc-linux-gnu.
OK. Thanks, Richard. > gcc/ChangeLog: > * auto-profile.cc (afdo_indirect_call): Don't attempt to promote > indirect calls > that will result in direct recursive calls. > > gcc/testsuite/g++.dg/tree-prof/ChangeLog: > * indir-call-recursive-inlining.C : New test. > --- > gcc/auto-profile.cc | 40 ++++++++------ > .../tree-prof/indir-call-recursive-inlining.C | 54 +++++++++++++++++++ > 2 files changed, 78 insertions(+), 16 deletions(-) > create mode 100644 > gcc/testsuite/g++.dg/tree-prof/indir-call-recursive-inlining.C > > diff --git a/gcc/auto-profile.cc b/gcc/auto-profile.cc > index c7cee639c85..2b34b80b82d 100644 > --- a/gcc/auto-profile.cc > +++ b/gcc/auto-profile.cc > @@ -975,7 +975,7 @@ read_profile (void) > * after annotation, we just need to mark, and let follow-up logic to > decide if it needs to promote and inline. */ > > -static void > +static bool > afdo_indirect_call (gimple_stmt_iterator *gsi, const icall_target_map &map, > bool transform) > { > @@ -983,12 +983,12 @@ afdo_indirect_call (gimple_stmt_iterator *gsi, const > icall_target_map &map, > tree callee; > > if (map.size () == 0) > - return; > + return false; > gcall *stmt = dyn_cast <gcall *> (gs); > if (!stmt > || gimple_call_internal_p (stmt) > || gimple_call_fndecl (stmt) != NULL_TREE) > - return; > + return false; > > gcov_type total = 0; > icall_target_map::const_iterator max_iter = map.end (); > @@ -1003,7 +1003,7 @@ afdo_indirect_call (gimple_stmt_iterator *gsi, const > icall_target_map &map, > struct cgraph_node *direct_call = cgraph_node::get_for_asmname ( > get_identifier (afdo_string_table->get_name (max_iter->first))); > if (direct_call == NULL || !direct_call->profile_id) > - return; > + return false; > > callee = gimple_call_fn (stmt); > > @@ -1013,20 +1013,27 @@ afdo_indirect_call (gimple_stmt_iterator *gsi, const > icall_target_map &map, > hist->hvalue.counters = XNEWVEC (gcov_type, hist->n_counters); > gimple_add_histogram_value (cfun, stmt, hist); > > - // Total counter > + /* Total counter */ > hist->hvalue.counters[0] = total; > - // Number of value/counter pairs > + /* Number of value/counter pairs */ > hist->hvalue.counters[1] = 1; > - // Value > + /* Value */ > hist->hvalue.counters[2] = direct_call->profile_id; > - // Counter > + /* Counter */ > hist->hvalue.counters[3] = max_iter->second; > > if (!transform) > - return; > + return false; > + > + cgraph_node* current_function_node = cgraph_node::get > (current_function_decl); > + > + /* If the direct call is a recursive call, don't promote it since > + we are not set up to inline recursive calls at this stage. */ > + if (direct_call == current_function_node) > + return false; > > struct cgraph_edge *indirect_edge > - = cgraph_node::get (current_function_decl)->get_edge (stmt); > + = current_function_node->get_edge (stmt); > > if (dump_file) > { > @@ -1040,13 +1047,13 @@ afdo_indirect_call (gimple_stmt_iterator *gsi, const > icall_target_map &map, > { > if (dump_file) > fprintf (dump_file, " not transforming\n"); > - return; > + return false; > } > if (DECL_STRUCT_FUNCTION (direct_call->decl) == NULL) > { > if (dump_file) > fprintf (dump_file, " no declaration\n"); > - return; > + return false; > } > > if (dump_file) > @@ -1063,16 +1070,17 @@ afdo_indirect_call (gimple_stmt_iterator *gsi, const > icall_target_map &map, > cgraph_edge::redirect_call_stmt_to_callee (new_edge); > gimple_remove_histogram_value (cfun, stmt, hist); > inline_call (new_edge, true, NULL, NULL, false); > + return true; > } > > /* From AutoFDO profiles, find values inside STMT for that we want to measure > histograms and adds them to list VALUES. */ > > -static void > +static bool > afdo_vpt (gimple_stmt_iterator *gsi, const icall_target_map &map, > bool transform) > { > - afdo_indirect_call (gsi, map, transform); > + return afdo_indirect_call (gsi, map, transform); > } > > typedef std::set<basic_block> bb_set; > @@ -1498,8 +1506,8 @@ afdo_vpt_for_early_inline (stmt_set *promoted_stmts) > { > /* Promote the indirect call and update the promoted_stmts. */ > promoted_stmts->insert (stmt); > - afdo_vpt (&gsi, info.targets, true); > - has_vpt = true; > + if (afdo_vpt (&gsi, info.targets, true)) > + has_vpt = true; > } > } > } > diff --git a/gcc/testsuite/g++.dg/tree-prof/indir-call-recursive-inlining.C > b/gcc/testsuite/g++.dg/tree-prof/indir-call-recursive-inlining.C > new file mode 100644 > index 00000000000..11f690063ef > --- /dev/null > +++ b/gcc/testsuite/g++.dg/tree-prof/indir-call-recursive-inlining.C > @@ -0,0 +1,54 @@ > +/* { dg-options "-O2 " } */ > + > +class Parent > +{ > +public: > + Parent *object; > + > + Parent() > + { > + object = this; > + } > + > + virtual void recurse (int t) = 0; > +}; > + > +class Child : public Parent > +{ > + > + Parent * > + get_object () > + { > + return this; > + } > + > +public: > + virtual void > + recurse (int t) > + { > + if (t != 10) > + for (int i = 0; i < 5; ++i) > + get_object()->recurse(t + 1); > + }; > +}; > + > +Parent * > +create_object () > +{ > + Child *mod = new Child; > + return mod; > +} > + > +int > +main (int argc, char **argv) > +{ > + Parent *parent = create_object (); > + > + for (int i = 0; i < 5; ++i) > + { > + parent->recurse (0); > + } > + > + return 0; > +} > + > -- > 2.25.1