Message ID | 20240414195740.237329-1-hjl.tools@gmail.com |
---|---|
State | New |
Headers | show |
Series | [Backport,1/2] tree-profile: Disable indirect call profiling for IFUNC resolvers | expand |
On Sun, 14 Apr 2024, H.J. Lu wrote: > We can't profile indirect calls to IFUNC resolvers nor their callees as > it requires TLS which hasn't been set up yet when the dynamic linker is > resolving IFUNC symbols. > > Add an IFUNC resolver caller marker to cgraph_node and set it if the > function is called by an IFUNC resolver. Disable indirect call profiling > for IFUNC resolvers and their callees. > > Tested with profiledbootstrap on Fedora 39/x86-64. > > gcc/ChangeLog: > > PR tree-optimization/114115 > * cgraph.h (symtab_node): Add check_ifunc_callee_symtab_nodes. > (cgraph_node): Add called_by_ifunc_resolver. > * cgraphunit.cc (symbol_table::compile): Call > symtab_node::check_ifunc_callee_symtab_nodes. > * symtab.cc (check_ifunc_resolver): New. > (ifunc_ref_map): Likewise. > (is_caller_ifunc_resolver): Likewise. > (symtab_node::check_ifunc_callee_symtab_nodes): Likewise. > * tree-profile.cc (gimple_gen_ic_func_profiler): Disable indirect > call profiling for IFUNC resolvers and their callees. > > gcc/testsuite/ChangeLog: > > PR tree-optimization/114115 > * gcc.dg/pr114115.c: New test. > > (cherry picked from commit cab32bacaea268ec062b1fb4fc662d90c9d1cfce) > --- > gcc/cgraph.h | 6 +++ > gcc/cgraphunit.cc | 2 + > gcc/symtab.cc | 89 +++++++++++++++++++++++++++++++++ > gcc/testsuite/gcc.dg/pr114115.c | 24 +++++++++ > gcc/tree-profile.cc | 8 ++- > 5 files changed, 128 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/gcc.dg/pr114115.c > > diff --git a/gcc/cgraph.h b/gcc/cgraph.h > index c1a3691b6f5..430c87d8bb7 100644 > --- a/gcc/cgraph.h > +++ b/gcc/cgraph.h > @@ -479,6 +479,9 @@ public: > Return NULL if there's no such node. */ > static symtab_node *get_for_asmname (const_tree asmname); > > + /* Check symbol table for callees of IFUNC resolvers. */ > + static void check_ifunc_callee_symtab_nodes (void); > + > /* Verify symbol table for internal consistency. */ > static DEBUG_FUNCTION void verify_symtab_nodes (void); > > @@ -896,6 +899,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node > redefined_extern_inline (false), tm_may_enter_irr (false), > ipcp_clone (false), declare_variant_alt (false), > calls_declare_variant_alt (false), gc_candidate (false), > + called_by_ifunc_resolver (false), > m_uid (uid), m_summary_id (-1) > {} > > @@ -1491,6 +1495,8 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node > is set for local SIMD clones when they are created and cleared if the > vectorizer uses them. */ > unsigned gc_candidate : 1; > + /* Set if the function is called by an IFUNC resolver. */ > + unsigned called_by_ifunc_resolver : 1; > > private: > /* Unique id of the node. */ > diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc > index bccd2f2abb5..40dcceccca5 100644 > --- a/gcc/cgraphunit.cc > +++ b/gcc/cgraphunit.cc > @@ -2313,6 +2313,8 @@ symbol_table::compile (void) > > symtab_node::checking_verify_symtab_nodes (); > > + symtab_node::check_ifunc_callee_symtab_nodes (); > + > timevar_push (TV_CGRAPHOPT); > if (pre_ipa_mem_report) > dump_memory_report ("Memory consumption before IPA"); > diff --git a/gcc/symtab.cc b/gcc/symtab.cc > index 0470509a98d..df09def81e9 100644 > --- a/gcc/symtab.cc > +++ b/gcc/symtab.cc > @@ -1369,6 +1369,95 @@ symtab_node::verify (void) > timevar_pop (TV_CGRAPH_VERIFY); > } > > +/* Return true and set *DATA to true if NODE is an ifunc resolver. */ > + > +static bool > +check_ifunc_resolver (cgraph_node *node, void *data) > +{ > + if (node->ifunc_resolver) > + { > + bool *is_ifunc_resolver = (bool *) data; > + *is_ifunc_resolver = true; > + return true; > + } > + return false; > +} > + > +static auto_bitmap ifunc_ref_map; Please don't use static auto_bitmap, that isn't constructed properly. Instead allocate it in the proper place and make sure to initialize the global bitmap obstack. > + > +/* Return true if any caller of NODE is an ifunc resolver. */ > + > +static bool > +is_caller_ifunc_resolver (cgraph_node *node) > +{ > + bool is_ifunc_resolver = false; > + > + for (cgraph_edge *e = node->callers; e; e = e->next_caller) > + { > + /* Return true if caller is known to be an IFUNC resolver. */ > + if (e->caller->called_by_ifunc_resolver) > + return true; > + > + /* Check for recursive call. */ > + if (e->caller == node) > + continue; > + > + /* Skip if it has been visited. */ > + unsigned int uid = e->caller->get_uid (); > + if (bitmap_bit_p (ifunc_ref_map, uid)) > + continue; > + bitmap_set_bit (ifunc_ref_map, uid); > + > + if (is_caller_ifunc_resolver (e->caller)) > + { > + /* Return true if caller is an IFUNC resolver. */ > + e->caller->called_by_ifunc_resolver = true; > + return true; > + } > + > + /* Check if caller's alias is an IFUNC resolver. */ > + e->caller->call_for_symbol_and_aliases (check_ifunc_resolver, > + &is_ifunc_resolver, > + true); > + if (is_ifunc_resolver) > + { > + /* Return true if caller's alias is an IFUNC resolver. */ > + e->caller->called_by_ifunc_resolver = true; > + return true; > + } > + } > + > + return false; > +} > + > +/* Check symbol table for callees of IFUNC resolvers. */ > + > +void > +symtab_node::check_ifunc_callee_symtab_nodes (void) > +{ > + symtab_node *node; > + > + FOR_EACH_SYMBOL (node) > + { > + cgraph_node *cnode = dyn_cast <cgraph_node *> (node); > + if (!cnode) > + continue; > + > + unsigned int uid = cnode->get_uid (); > + if (bitmap_bit_p (ifunc_ref_map, uid)) > + continue; > + bitmap_set_bit (ifunc_ref_map, uid); > + > + bool is_ifunc_resolver = false; > + cnode->call_for_symbol_and_aliases (check_ifunc_resolver, > + &is_ifunc_resolver, true); > + if (is_ifunc_resolver || is_caller_ifunc_resolver (cnode)) > + cnode->called_by_ifunc_resolver = true; > + } > + > + bitmap_clear (ifunc_ref_map); > +} > + > /* Verify symbol table for internal consistency. */ > > DEBUG_FUNCTION void > diff --git a/gcc/testsuite/gcc.dg/pr114115.c b/gcc/testsuite/gcc.dg/pr114115.c > new file mode 100644 > index 00000000000..2629f591877 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pr114115.c > @@ -0,0 +1,24 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O0 -fprofile-generate -fdump-tree-optimized" } */ > +/* { dg-require-profiling "-fprofile-generate" } */ > +/* { dg-require-ifunc "" } */ > + > +void *foo_ifunc2() __attribute__((ifunc("foo_resolver"))); > + > +void bar(void) > +{ > +} > + > +static int f3() > +{ > + bar (); > + return 5; > +} > + > +void (*foo_resolver(void))(void) > +{ > + f3(); > + return bar; > +} > + > +/* { dg-final { scan-tree-dump-not "__gcov_indirect_call_profiler_v" "optimized" } } */ > diff --git a/gcc/tree-profile.cc b/gcc/tree-profile.cc > index da300d5f9e8..b5de0fb914f 100644 > --- a/gcc/tree-profile.cc > +++ b/gcc/tree-profile.cc > @@ -418,7 +418,13 @@ gimple_gen_ic_func_profiler (void) > gcall *stmt1; > tree tree_uid, cur_func, void0; > > - if (c_node->only_called_directly_p ()) > + /* Disable indirect call profiling for an IFUNC resolver and its > + callees since it requires TLS which hasn't been set up yet when > + the dynamic linker is resolving IFUNC symbols. See > + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114115 > + */ > + if (c_node->only_called_directly_p () > + || c_node->called_by_ifunc_resolver) > return; > > gimple_init_gcov_profiler (); >
On Mon, 15 Apr 2024, Richard Biener wrote: > On Sun, 14 Apr 2024, H.J. Lu wrote: > > > We can't profile indirect calls to IFUNC resolvers nor their callees as > > it requires TLS which hasn't been set up yet when the dynamic linker is > > resolving IFUNC symbols. > > > > Add an IFUNC resolver caller marker to cgraph_node and set it if the > > function is called by an IFUNC resolver. Disable indirect call profiling > > for IFUNC resolvers and their callees. > > > > Tested with profiledbootstrap on Fedora 39/x86-64. > > > > gcc/ChangeLog: > > > > PR tree-optimization/114115 > > * cgraph.h (symtab_node): Add check_ifunc_callee_symtab_nodes. > > (cgraph_node): Add called_by_ifunc_resolver. > > * cgraphunit.cc (symbol_table::compile): Call > > symtab_node::check_ifunc_callee_symtab_nodes. > > * symtab.cc (check_ifunc_resolver): New. > > (ifunc_ref_map): Likewise. > > (is_caller_ifunc_resolver): Likewise. > > (symtab_node::check_ifunc_callee_symtab_nodes): Likewise. > > * tree-profile.cc (gimple_gen_ic_func_profiler): Disable indirect > > call profiling for IFUNC resolvers and their callees. > > > > gcc/testsuite/ChangeLog: > > > > PR tree-optimization/114115 > > * gcc.dg/pr114115.c: New test. > > > > (cherry picked from commit cab32bacaea268ec062b1fb4fc662d90c9d1cfce) > > --- > > gcc/cgraph.h | 6 +++ > > gcc/cgraphunit.cc | 2 + > > gcc/symtab.cc | 89 +++++++++++++++++++++++++++++++++ > > gcc/testsuite/gcc.dg/pr114115.c | 24 +++++++++ > > gcc/tree-profile.cc | 8 ++- > > 5 files changed, 128 insertions(+), 1 deletion(-) > > create mode 100644 gcc/testsuite/gcc.dg/pr114115.c > > > > diff --git a/gcc/cgraph.h b/gcc/cgraph.h > > index c1a3691b6f5..430c87d8bb7 100644 > > --- a/gcc/cgraph.h > > +++ b/gcc/cgraph.h > > @@ -479,6 +479,9 @@ public: > > Return NULL if there's no such node. */ > > static symtab_node *get_for_asmname (const_tree asmname); > > > > + /* Check symbol table for callees of IFUNC resolvers. */ > > + static void check_ifunc_callee_symtab_nodes (void); > > + > > /* Verify symbol table for internal consistency. */ > > static DEBUG_FUNCTION void verify_symtab_nodes (void); > > > > @@ -896,6 +899,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node > > redefined_extern_inline (false), tm_may_enter_irr (false), > > ipcp_clone (false), declare_variant_alt (false), > > calls_declare_variant_alt (false), gc_candidate (false), > > + called_by_ifunc_resolver (false), > > m_uid (uid), m_summary_id (-1) > > {} > > > > @@ -1491,6 +1495,8 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node > > is set for local SIMD clones when they are created and cleared if the > > vectorizer uses them. */ > > unsigned gc_candidate : 1; > > + /* Set if the function is called by an IFUNC resolver. */ > > + unsigned called_by_ifunc_resolver : 1; > > > > private: > > /* Unique id of the node. */ > > diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc > > index bccd2f2abb5..40dcceccca5 100644 > > --- a/gcc/cgraphunit.cc > > +++ b/gcc/cgraphunit.cc > > @@ -2313,6 +2313,8 @@ symbol_table::compile (void) > > > > symtab_node::checking_verify_symtab_nodes (); > > > > + symtab_node::check_ifunc_callee_symtab_nodes (); > > + > > timevar_push (TV_CGRAPHOPT); > > if (pre_ipa_mem_report) > > dump_memory_report ("Memory consumption before IPA"); > > diff --git a/gcc/symtab.cc b/gcc/symtab.cc > > index 0470509a98d..df09def81e9 100644 > > --- a/gcc/symtab.cc > > +++ b/gcc/symtab.cc > > @@ -1369,6 +1369,95 @@ symtab_node::verify (void) > > timevar_pop (TV_CGRAPH_VERIFY); > > } > > > > +/* Return true and set *DATA to true if NODE is an ifunc resolver. */ > > + > > +static bool > > +check_ifunc_resolver (cgraph_node *node, void *data) > > +{ > > + if (node->ifunc_resolver) > > + { > > + bool *is_ifunc_resolver = (bool *) data; > > + *is_ifunc_resolver = true; > > + return true; > > + } > > + return false; > > +} > > + > > +static auto_bitmap ifunc_ref_map; > > Please don't use static auto_bitmap, that isn't constructed > properly. > > Instead allocate it in the proper place and make sure to > initialize the global bitmap obstack. Sorry - ignore that. I've not seen 2/2. Richard. > > + > > +/* Return true if any caller of NODE is an ifunc resolver. */ > > + > > +static bool > > +is_caller_ifunc_resolver (cgraph_node *node) > > +{ > > + bool is_ifunc_resolver = false; > > + > > + for (cgraph_edge *e = node->callers; e; e = e->next_caller) > > + { > > + /* Return true if caller is known to be an IFUNC resolver. */ > > + if (e->caller->called_by_ifunc_resolver) > > + return true; > > + > > + /* Check for recursive call. */ > > + if (e->caller == node) > > + continue; > > + > > + /* Skip if it has been visited. */ > > + unsigned int uid = e->caller->get_uid (); > > + if (bitmap_bit_p (ifunc_ref_map, uid)) > > + continue; > > + bitmap_set_bit (ifunc_ref_map, uid); > > + > > + if (is_caller_ifunc_resolver (e->caller)) > > + { > > + /* Return true if caller is an IFUNC resolver. */ > > + e->caller->called_by_ifunc_resolver = true; > > + return true; > > + } > > + > > + /* Check if caller's alias is an IFUNC resolver. */ > > + e->caller->call_for_symbol_and_aliases (check_ifunc_resolver, > > + &is_ifunc_resolver, > > + true); > > + if (is_ifunc_resolver) > > + { > > + /* Return true if caller's alias is an IFUNC resolver. */ > > + e->caller->called_by_ifunc_resolver = true; > > + return true; > > + } > > + } > > + > > + return false; > > +} > > + > > +/* Check symbol table for callees of IFUNC resolvers. */ > > + > > +void > > +symtab_node::check_ifunc_callee_symtab_nodes (void) > > +{ > > + symtab_node *node; > > + > > + FOR_EACH_SYMBOL (node) > > + { > > + cgraph_node *cnode = dyn_cast <cgraph_node *> (node); > > + if (!cnode) > > + continue; > > + > > + unsigned int uid = cnode->get_uid (); > > + if (bitmap_bit_p (ifunc_ref_map, uid)) > > + continue; > > + bitmap_set_bit (ifunc_ref_map, uid); > > + > > + bool is_ifunc_resolver = false; > > + cnode->call_for_symbol_and_aliases (check_ifunc_resolver, > > + &is_ifunc_resolver, true); > > + if (is_ifunc_resolver || is_caller_ifunc_resolver (cnode)) > > + cnode->called_by_ifunc_resolver = true; > > + } > > + > > + bitmap_clear (ifunc_ref_map); > > +} > > + > > /* Verify symbol table for internal consistency. */ > > > > DEBUG_FUNCTION void > > diff --git a/gcc/testsuite/gcc.dg/pr114115.c b/gcc/testsuite/gcc.dg/pr114115.c > > new file mode 100644 > > index 00000000000..2629f591877 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/pr114115.c > > @@ -0,0 +1,24 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O0 -fprofile-generate -fdump-tree-optimized" } */ > > +/* { dg-require-profiling "-fprofile-generate" } */ > > +/* { dg-require-ifunc "" } */ > > + > > +void *foo_ifunc2() __attribute__((ifunc("foo_resolver"))); > > + > > +void bar(void) > > +{ > > +} > > + > > +static int f3() > > +{ > > + bar (); > > + return 5; > > +} > > + > > +void (*foo_resolver(void))(void) > > +{ > > + f3(); > > + return bar; > > +} > > + > > +/* { dg-final { scan-tree-dump-not "__gcov_indirect_call_profiler_v" "optimized" } } */ > > diff --git a/gcc/tree-profile.cc b/gcc/tree-profile.cc > > index da300d5f9e8..b5de0fb914f 100644 > > --- a/gcc/tree-profile.cc > > +++ b/gcc/tree-profile.cc > > @@ -418,7 +418,13 @@ gimple_gen_ic_func_profiler (void) > > gcall *stmt1; > > tree tree_uid, cur_func, void0; > > > > - if (c_node->only_called_directly_p ()) > > + /* Disable indirect call profiling for an IFUNC resolver and its > > + callees since it requires TLS which hasn't been set up yet when > > + the dynamic linker is resolving IFUNC symbols. See > > + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114115 > > + */ > > + if (c_node->only_called_directly_p () > > + || c_node->called_by_ifunc_resolver) > > return; > > > > gimple_init_gcov_profiler (); > > > >
diff --git a/gcc/cgraph.h b/gcc/cgraph.h index c1a3691b6f5..430c87d8bb7 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -479,6 +479,9 @@ public: Return NULL if there's no such node. */ static symtab_node *get_for_asmname (const_tree asmname); + /* Check symbol table for callees of IFUNC resolvers. */ + static void check_ifunc_callee_symtab_nodes (void); + /* Verify symbol table for internal consistency. */ static DEBUG_FUNCTION void verify_symtab_nodes (void); @@ -896,6 +899,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node redefined_extern_inline (false), tm_may_enter_irr (false), ipcp_clone (false), declare_variant_alt (false), calls_declare_variant_alt (false), gc_candidate (false), + called_by_ifunc_resolver (false), m_uid (uid), m_summary_id (-1) {} @@ -1491,6 +1495,8 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node is set for local SIMD clones when they are created and cleared if the vectorizer uses them. */ unsigned gc_candidate : 1; + /* Set if the function is called by an IFUNC resolver. */ + unsigned called_by_ifunc_resolver : 1; private: /* Unique id of the node. */ diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc index bccd2f2abb5..40dcceccca5 100644 --- a/gcc/cgraphunit.cc +++ b/gcc/cgraphunit.cc @@ -2313,6 +2313,8 @@ symbol_table::compile (void) symtab_node::checking_verify_symtab_nodes (); + symtab_node::check_ifunc_callee_symtab_nodes (); + timevar_push (TV_CGRAPHOPT); if (pre_ipa_mem_report) dump_memory_report ("Memory consumption before IPA"); diff --git a/gcc/symtab.cc b/gcc/symtab.cc index 0470509a98d..df09def81e9 100644 --- a/gcc/symtab.cc +++ b/gcc/symtab.cc @@ -1369,6 +1369,95 @@ symtab_node::verify (void) timevar_pop (TV_CGRAPH_VERIFY); } +/* Return true and set *DATA to true if NODE is an ifunc resolver. */ + +static bool +check_ifunc_resolver (cgraph_node *node, void *data) +{ + if (node->ifunc_resolver) + { + bool *is_ifunc_resolver = (bool *) data; + *is_ifunc_resolver = true; + return true; + } + return false; +} + +static auto_bitmap ifunc_ref_map; + +/* Return true if any caller of NODE is an ifunc resolver. */ + +static bool +is_caller_ifunc_resolver (cgraph_node *node) +{ + bool is_ifunc_resolver = false; + + for (cgraph_edge *e = node->callers; e; e = e->next_caller) + { + /* Return true if caller is known to be an IFUNC resolver. */ + if (e->caller->called_by_ifunc_resolver) + return true; + + /* Check for recursive call. */ + if (e->caller == node) + continue; + + /* Skip if it has been visited. */ + unsigned int uid = e->caller->get_uid (); + if (bitmap_bit_p (ifunc_ref_map, uid)) + continue; + bitmap_set_bit (ifunc_ref_map, uid); + + if (is_caller_ifunc_resolver (e->caller)) + { + /* Return true if caller is an IFUNC resolver. */ + e->caller->called_by_ifunc_resolver = true; + return true; + } + + /* Check if caller's alias is an IFUNC resolver. */ + e->caller->call_for_symbol_and_aliases (check_ifunc_resolver, + &is_ifunc_resolver, + true); + if (is_ifunc_resolver) + { + /* Return true if caller's alias is an IFUNC resolver. */ + e->caller->called_by_ifunc_resolver = true; + return true; + } + } + + return false; +} + +/* Check symbol table for callees of IFUNC resolvers. */ + +void +symtab_node::check_ifunc_callee_symtab_nodes (void) +{ + symtab_node *node; + + FOR_EACH_SYMBOL (node) + { + cgraph_node *cnode = dyn_cast <cgraph_node *> (node); + if (!cnode) + continue; + + unsigned int uid = cnode->get_uid (); + if (bitmap_bit_p (ifunc_ref_map, uid)) + continue; + bitmap_set_bit (ifunc_ref_map, uid); + + bool is_ifunc_resolver = false; + cnode->call_for_symbol_and_aliases (check_ifunc_resolver, + &is_ifunc_resolver, true); + if (is_ifunc_resolver || is_caller_ifunc_resolver (cnode)) + cnode->called_by_ifunc_resolver = true; + } + + bitmap_clear (ifunc_ref_map); +} + /* Verify symbol table for internal consistency. */ DEBUG_FUNCTION void diff --git a/gcc/testsuite/gcc.dg/pr114115.c b/gcc/testsuite/gcc.dg/pr114115.c new file mode 100644 index 00000000000..2629f591877 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr114115.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -fprofile-generate -fdump-tree-optimized" } */ +/* { dg-require-profiling "-fprofile-generate" } */ +/* { dg-require-ifunc "" } */ + +void *foo_ifunc2() __attribute__((ifunc("foo_resolver"))); + +void bar(void) +{ +} + +static int f3() +{ + bar (); + return 5; +} + +void (*foo_resolver(void))(void) +{ + f3(); + return bar; +} + +/* { dg-final { scan-tree-dump-not "__gcov_indirect_call_profiler_v" "optimized" } } */ diff --git a/gcc/tree-profile.cc b/gcc/tree-profile.cc index da300d5f9e8..b5de0fb914f 100644 --- a/gcc/tree-profile.cc +++ b/gcc/tree-profile.cc @@ -418,7 +418,13 @@ gimple_gen_ic_func_profiler (void) gcall *stmt1; tree tree_uid, cur_func, void0; - if (c_node->only_called_directly_p ()) + /* Disable indirect call profiling for an IFUNC resolver and its + callees since it requires TLS which hasn't been set up yet when + the dynamic linker is resolving IFUNC symbols. See + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114115 + */ + if (c_node->only_called_directly_p () + || c_node->called_by_ifunc_resolver) return; gimple_init_gcov_profiler ();