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);
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)
{}
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. */
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
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 ();