Don't mark IFUNC resolver as only called directly

Message ID 20180412112925.GA222547@intel.com
State New
Headers show
Series
  • Don't mark IFUNC resolver as only called directly
Related show

Commit Message

H.J. Lu April 12, 2018, 11:29 a.m.
Since IFUNC resolver is called indirectly, don't mark IFUNC resolver as
only called directly.

OK for trunk?


H.J.
---
gcc/

	PR target/85345
	* cgraph.h: Include stringpool.h" and "attribs.h".
	(cgraph_node::only_called_directly_or_aliased_p): Return false
	for IFUNC resolver.

gcc/testsuite/

	PR target/85345
	* gcc.target/i386/pr85345.c: New test.
---
 gcc/cgraph.h                            |  5 +++-
 gcc/testsuite/gcc.target/i386/pr85345.c | 44 +++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr85345.c

-- 
2.14.3

Comments

Richard Biener April 12, 2018, 12:13 p.m. | #1
On Thu, Apr 12, 2018 at 1:29 PM, H.J. Lu <hongjiu.lu@intel.com> wrote:
> Since IFUNC resolver is called indirectly, don't mark IFUNC resolver as

> only called directly.

>

> OK for trunk?

>

>

> H.J.

> ---

> gcc/

>

>         PR target/85345

>         * cgraph.h: Include stringpool.h" and "attribs.h".

>         (cgraph_node::only_called_directly_or_aliased_p): Return false

>         for IFUNC resolver.

>

> gcc/testsuite/

>

>         PR target/85345

>         * gcc.target/i386/pr85345.c: New test.

> ---

>  gcc/cgraph.h                            |  5 +++-

>  gcc/testsuite/gcc.target/i386/pr85345.c | 44 +++++++++++++++++++++++++++++++++

>  2 files changed, 48 insertions(+), 1 deletion(-)

>  create mode 100644 gcc/testsuite/gcc.target/i386/pr85345.c

>

> diff --git a/gcc/cgraph.h b/gcc/cgraph.h

> index d1ef8408497..9e195824fcc 100644

> --- a/gcc/cgraph.h

> +++ b/gcc/cgraph.h

> @@ -24,6 +24,8 @@ along with GCC; see the file COPYING3.  If not see

>  #include "profile-count.h"

>  #include "ipa-ref.h"

>  #include "plugin-api.h"

> +#include "stringpool.h"

> +#include "attribs.h"

>

>  class ipa_opt_pass_d;

>  typedef ipa_opt_pass_d *ipa_opt_pass;

> @@ -2894,7 +2896,8 @@ cgraph_node::only_called_directly_or_aliased_p (void)

>           && !DECL_STATIC_CONSTRUCTOR (decl)

>           && !DECL_STATIC_DESTRUCTOR (decl)

>           && !used_from_object_file_p ()

> -         && !externally_visible);

> +         && !externally_visible

> +         && !lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)));


How's it handled for our own generated resolver functions?  That is,
isn't there sth cheaper than doing a lookup_attribute here?  I see
that make_dispatcher_decl nor ix86_get_function_versions_dispatcher
adds the 'ifunc' attribute (though they are TREE_PUBLIC there).

Richard.

>  }

>

>  /* Return true when function can be removed from callgraph

> diff --git a/gcc/testsuite/gcc.target/i386/pr85345.c b/gcc/testsuite/gcc.target/i386/pr85345.c

> new file mode 100644

> index 00000000000..63f771294ad

> --- /dev/null

> +++ b/gcc/testsuite/gcc.target/i386/pr85345.c

> @@ -0,0 +1,44 @@

> +/* { dg-do compile } */

> +/* { dg-options "-O2 -fcf-protection -mcet" } */

> +/* { dg-final { scan-assembler-times {\mendbr} 4 } } */

> +

> +int resolver_fn = 0;

> +int resolved_fn = 0;

> +

> +static inline void

> +do_it_right_at_runtime_A (void)

> +{

> +  resolved_fn++;

> +}

> +

> +static inline void

> +do_it_right_at_runtime_B (void)

> +{

> +  resolved_fn++;

> +}

> +

> +static inline void do_it_right_at_runtime (void);

> +

> +void do_it_right_at_runtime (void)

> +  __attribute__ ((ifunc ("resolve_do_it_right_at_runtime")));

> +

> +extern int r;

> +static void (*resolve_do_it_right_at_runtime (void)) (void)

> +{

> +  resolver_fn++;

> +

> +  typeof(do_it_right_at_runtime) *func;

> +  if (r & 1)

> +    func = do_it_right_at_runtime_A;

> +  else

> +    func = do_it_right_at_runtime_B;

> +

> +  return (void *) func;

> +}

> +

> +int

> +main ()

> +{

> +  do_it_right_at_runtime ();

> +  return 0;

> +}

> --

> 2.14.3

>
Jan Hubicka April 12, 2018, 12:17 p.m. | #2
> On Thu, Apr 12, 2018 at 1:29 PM, H.J. Lu <hongjiu.lu@intel.com> wrote:

> > Since IFUNC resolver is called indirectly, don't mark IFUNC resolver as

> > only called directly.

> >

> > OK for trunk?

> >

> >

> > H.J.

> > ---

> > gcc/

> >

> >         PR target/85345

> >         * cgraph.h: Include stringpool.h" and "attribs.h".

> >         (cgraph_node::only_called_directly_or_aliased_p): Return false

> >         for IFUNC resolver.

> >

> > gcc/testsuite/

> >

> >         PR target/85345

> >         * gcc.target/i386/pr85345.c: New test.

> > ---

> >  gcc/cgraph.h                            |  5 +++-

> >  gcc/testsuite/gcc.target/i386/pr85345.c | 44 +++++++++++++++++++++++++++++++++

> >  2 files changed, 48 insertions(+), 1 deletion(-)

> >  create mode 100644 gcc/testsuite/gcc.target/i386/pr85345.c

> >

> > diff --git a/gcc/cgraph.h b/gcc/cgraph.h

> > index d1ef8408497..9e195824fcc 100644

> > --- a/gcc/cgraph.h

> > +++ b/gcc/cgraph.h

> > @@ -24,6 +24,8 @@ along with GCC; see the file COPYING3.  If not see

> >  #include "profile-count.h"

> >  #include "ipa-ref.h"

> >  #include "plugin-api.h"

> > +#include "stringpool.h"

> > +#include "attribs.h"

> >

> >  class ipa_opt_pass_d;

> >  typedef ipa_opt_pass_d *ipa_opt_pass;

> > @@ -2894,7 +2896,8 @@ cgraph_node::only_called_directly_or_aliased_p (void)

> >           && !DECL_STATIC_CONSTRUCTOR (decl)

> >           && !DECL_STATIC_DESTRUCTOR (decl)

> >           && !used_from_object_file_p ()

> > -         && !externally_visible);

> > +         && !externally_visible

> > +         && !lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)));

> 

> How's it handled for our own generated resolver functions?  That is,

> isn't there sth cheaper than doing a lookup_attribute here?  I see

> that make_dispatcher_decl nor ix86_get_function_versions_dispatcher

> adds the 'ifunc' attribute (though they are TREE_PUBLIC there).


Is there any drawback of setting force_output flag?
Honza
> 

> Richard.

> 

> >  }

> >

> >  /* Return true when function can be removed from callgraph

> > diff --git a/gcc/testsuite/gcc.target/i386/pr85345.c b/gcc/testsuite/gcc.target/i386/pr85345.c

> > new file mode 100644

> > index 00000000000..63f771294ad

> > --- /dev/null

> > +++ b/gcc/testsuite/gcc.target/i386/pr85345.c

> > @@ -0,0 +1,44 @@

> > +/* { dg-do compile } */

> > +/* { dg-options "-O2 -fcf-protection -mcet" } */

> > +/* { dg-final { scan-assembler-times {\mendbr} 4 } } */

> > +

> > +int resolver_fn = 0;

> > +int resolved_fn = 0;

> > +

> > +static inline void

> > +do_it_right_at_runtime_A (void)

> > +{

> > +  resolved_fn++;

> > +}

> > +

> > +static inline void

> > +do_it_right_at_runtime_B (void)

> > +{

> > +  resolved_fn++;

> > +}

> > +

> > +static inline void do_it_right_at_runtime (void);

> > +

> > +void do_it_right_at_runtime (void)

> > +  __attribute__ ((ifunc ("resolve_do_it_right_at_runtime")));

> > +

> > +extern int r;

> > +static void (*resolve_do_it_right_at_runtime (void)) (void)

> > +{

> > +  resolver_fn++;

> > +

> > +  typeof(do_it_right_at_runtime) *func;

> > +  if (r & 1)

> > +    func = do_it_right_at_runtime_A;

> > +  else

> > +    func = do_it_right_at_runtime_B;

> > +

> > +  return (void *) func;

> > +}

> > +

> > +int

> > +main ()

> > +{

> > +  do_it_right_at_runtime ();

> > +  return 0;

> > +}

> > --

> > 2.14.3

> >
H.J. Lu April 12, 2018, 1:37 p.m. | #3
On Thu, Apr 12, 2018 at 5:13 AM, Richard Biener
<richard.guenther@gmail.com> wrote:
> On Thu, Apr 12, 2018 at 1:29 PM, H.J. Lu <hongjiu.lu@intel.com> wrote:

>> Since IFUNC resolver is called indirectly, don't mark IFUNC resolver as

>> only called directly.

>>

>> OK for trunk?

>>

>>

>> H.J.

>> ---

>> gcc/

>>

>>         PR target/85345

>>         * cgraph.h: Include stringpool.h" and "attribs.h".

>>         (cgraph_node::only_called_directly_or_aliased_p): Return false

>>         for IFUNC resolver.

>>

>> gcc/testsuite/

>>

>>         PR target/85345

>>         * gcc.target/i386/pr85345.c: New test.

>> ---

>>  gcc/cgraph.h                            |  5 +++-

>>  gcc/testsuite/gcc.target/i386/pr85345.c | 44 +++++++++++++++++++++++++++++++++

>>  2 files changed, 48 insertions(+), 1 deletion(-)

>>  create mode 100644 gcc/testsuite/gcc.target/i386/pr85345.c

>>

>> diff --git a/gcc/cgraph.h b/gcc/cgraph.h

>> index d1ef8408497..9e195824fcc 100644

>> --- a/gcc/cgraph.h

>> +++ b/gcc/cgraph.h

>> @@ -24,6 +24,8 @@ along with GCC; see the file COPYING3.  If not see

>>  #include "profile-count.h"

>>  #include "ipa-ref.h"

>>  #include "plugin-api.h"

>> +#include "stringpool.h"

>> +#include "attribs.h"

>>

>>  class ipa_opt_pass_d;

>>  typedef ipa_opt_pass_d *ipa_opt_pass;

>> @@ -2894,7 +2896,8 @@ cgraph_node::only_called_directly_or_aliased_p (void)

>>           && !DECL_STATIC_CONSTRUCTOR (decl)

>>           && !DECL_STATIC_DESTRUCTOR (decl)

>>           && !used_from_object_file_p ()

>> -         && !externally_visible);

>> +         && !externally_visible

>> +         && !lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)));

>

> How's it handled for our own generated resolver functions?  That is,

> isn't there sth cheaper than doing a lookup_attribute here?  I see

> that make_dispatcher_decl nor ix86_get_function_versions_dispatcher

> adds the 'ifunc' attribute (though they are TREE_PUBLIC there).

>


ext/mv*.C tests failed to compile:

error: '-fcf-protection=full' requires Intel CET support. Use -mcet or
both of -mibt and -mshstk options to enable CET

with -fcf-protection -mcet.   So it is unsupported.

-- 
H.J.
H.J. Lu April 12, 2018, 1:39 p.m. | #4
On Thu, Apr 12, 2018 at 5:17 AM, Jan Hubicka <hubicka@ucw.cz> wrote:
>> On Thu, Apr 12, 2018 at 1:29 PM, H.J. Lu <hongjiu.lu@intel.com> wrote:

>> > Since IFUNC resolver is called indirectly, don't mark IFUNC resolver as

>> > only called directly.

>> >

>> > OK for trunk?

>> >

>> >

>> > H.J.

>> > ---

>> > gcc/

>> >

>> >         PR target/85345

>> >         * cgraph.h: Include stringpool.h" and "attribs.h".

>> >         (cgraph_node::only_called_directly_or_aliased_p): Return false

>> >         for IFUNC resolver.

>> >

>> > gcc/testsuite/

>> >

>> >         PR target/85345

>> >         * gcc.target/i386/pr85345.c: New test.

>> > ---

>> >  gcc/cgraph.h                            |  5 +++-

>> >  gcc/testsuite/gcc.target/i386/pr85345.c | 44 +++++++++++++++++++++++++++++++++

>> >  2 files changed, 48 insertions(+), 1 deletion(-)

>> >  create mode 100644 gcc/testsuite/gcc.target/i386/pr85345.c

>> >

>> > diff --git a/gcc/cgraph.h b/gcc/cgraph.h

>> > index d1ef8408497..9e195824fcc 100644

>> > --- a/gcc/cgraph.h

>> > +++ b/gcc/cgraph.h

>> > @@ -24,6 +24,8 @@ along with GCC; see the file COPYING3.  If not see

>> >  #include "profile-count.h"

>> >  #include "ipa-ref.h"

>> >  #include "plugin-api.h"

>> > +#include "stringpool.h"

>> > +#include "attribs.h"

>> >

>> >  class ipa_opt_pass_d;

>> >  typedef ipa_opt_pass_d *ipa_opt_pass;

>> > @@ -2894,7 +2896,8 @@ cgraph_node::only_called_directly_or_aliased_p (void)

>> >           && !DECL_STATIC_CONSTRUCTOR (decl)

>> >           && !DECL_STATIC_DESTRUCTOR (decl)

>> >           && !used_from_object_file_p ()

>> > -         && !externally_visible);

>> > +         && !externally_visible

>> > +         && !lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)));

>>

>> How's it handled for our own generated resolver functions?  That is,

>> isn't there sth cheaper than doing a lookup_attribute here?  I see

>> that make_dispatcher_decl nor ix86_get_function_versions_dispatcher

>> adds the 'ifunc' attribute (though they are TREE_PUBLIC there).

>

> Is there any drawback of setting force_output flag?

> Honza


Setting force_output may prevent some optimizations.  Can we add a bit
for IFUNC resolver?

-- 
H.J.
H.J. Lu April 12, 2018, 10:50 p.m. | #5
On Thu, Apr 12, 2018 at 6:39 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Thu, Apr 12, 2018 at 5:17 AM, Jan Hubicka <hubicka@ucw.cz> wrote:

>>> On Thu, Apr 12, 2018 at 1:29 PM, H.J. Lu <hongjiu.lu@intel.com> wrote:

>>> > Since IFUNC resolver is called indirectly, don't mark IFUNC resolver as

>>> > only called directly.

>>> >

>>> > OK for trunk?

>>> >

>>> >

>>> > H.J.

>>> > ---

>>> > gcc/

>>> >

>>> >         PR target/85345

>>> >         * cgraph.h: Include stringpool.h" and "attribs.h".

>>> >         (cgraph_node::only_called_directly_or_aliased_p): Return false

>>> >         for IFUNC resolver.

>>> >

>>> > gcc/testsuite/

>>> >

>>> >         PR target/85345

>>> >         * gcc.target/i386/pr85345.c: New test.

>>> > ---

>>> >  gcc/cgraph.h                            |  5 +++-

>>> >  gcc/testsuite/gcc.target/i386/pr85345.c | 44 +++++++++++++++++++++++++++++++++

>>> >  2 files changed, 48 insertions(+), 1 deletion(-)

>>> >  create mode 100644 gcc/testsuite/gcc.target/i386/pr85345.c

>>> >

>>> > diff --git a/gcc/cgraph.h b/gcc/cgraph.h

>>> > index d1ef8408497..9e195824fcc 100644

>>> > --- a/gcc/cgraph.h

>>> > +++ b/gcc/cgraph.h

>>> > @@ -24,6 +24,8 @@ along with GCC; see the file COPYING3.  If not see

>>> >  #include "profile-count.h"

>>> >  #include "ipa-ref.h"

>>> >  #include "plugin-api.h"

>>> > +#include "stringpool.h"

>>> > +#include "attribs.h"

>>> >

>>> >  class ipa_opt_pass_d;

>>> >  typedef ipa_opt_pass_d *ipa_opt_pass;

>>> > @@ -2894,7 +2896,8 @@ cgraph_node::only_called_directly_or_aliased_p (void)

>>> >           && !DECL_STATIC_CONSTRUCTOR (decl)

>>> >           && !DECL_STATIC_DESTRUCTOR (decl)

>>> >           && !used_from_object_file_p ()

>>> > -         && !externally_visible);

>>> > +         && !externally_visible

>>> > +         && !lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)));

>>>

>>> How's it handled for our own generated resolver functions?  That is,

>>> isn't there sth cheaper than doing a lookup_attribute here?  I see

>>> that make_dispatcher_decl nor ix86_get_function_versions_dispatcher

>>> adds the 'ifunc' attribute (though they are TREE_PUBLIC there).

>>

>> Is there any drawback of setting force_output flag?

>> Honza

>

> Setting force_output may prevent some optimizations.  Can we add a bit

> for IFUNC resolver?

>


Here is the patch to add ifunc_resolver to cgraph_node. Tested on x86-64
and i686.  Any comments?

Thanks.

-- 
H.J.
From 283a3282d018a40ab550a137a5a2770ce63f4a40 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Wed, 11 Apr 2018 12:31:21 -0700
Subject: [PATCH] Don't mark IFUNC resolver as only called directly

Since IFUNC resolver is called indirectly, don't mark IFUNC resolver as
only called directly.  This patch adds ifunc_resolver to cgraph_node,
sets ifunc_resolver for ifunc attribute and checks ifunc_resolver
instead of looking up ifunc attribute.

gcc/

	PR target/85345
	* cgraph.h (cgraph_node::create): Set ifunc_resolver for ifunc
	attribute.
	(cgraph_node::create_alias): Likewise.
	(cgraph_node::get_availability): Check ifunc_resolver instead
	of looking up ifunc attribute.
	* cgraphunit.c (maybe_diag_incompatible_alias): Likewise.
	* symtab.c (symtab_node::binds_to_current_def_p): Likewise.
	* varasm.c (do_assemble_alias): Likewise.
	(assemble_alias): Likewise.
	(default_binds_local_p_3): Likewise.
	* cgraph.h (cgraph_node): Add ifunc_resolver.
	(cgraph_node::only_called_directly_or_aliased_p): Return false
	for IFUNC resolver.
	* lto-cgraph.c (input_node): Set ifunc_resolver for ifunc
	attribute.

gcc/testsuite/

	PR target/85345
	* gcc.target/i386/pr85345.c: New test.
---
 gcc/cgraph.c                            |  7 +++++-
 gcc/cgraph.h                            |  4 +++
 gcc/cgraphunit.c                        |  2 +-
 gcc/lto-cgraph.c                        |  2 ++
 gcc/symtab.c                            |  4 +--
 gcc/testsuite/gcc.target/i386/pr85345.c | 44 +++++++++++++++++++++++++++++++++
 gcc/varasm.c                            |  8 +++---
 7 files changed, 64 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr85345.c

diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 9a7d54d7cee..9f3a2929f6b 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -517,6 +517,9 @@ cgraph_node::create (tree decl)
 	g->have_offload = true;
     }
 
+  if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)))
+    node->ifunc_resolver = true;
+
   node->register_symbol ();
 
   if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
@@ -575,6 +578,8 @@ cgraph_node::create_alias (tree alias, tree target)
   alias_node->alias = true;
   if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL)
     alias_node->transparent_alias = alias_node->weakref = true;
+  if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (alias)))
+    alias_node->ifunc_resolver = true;
   return alias_node;
 }
 
@@ -2299,7 +2304,7 @@ cgraph_node::get_availability (symtab_node *ref)
     avail = AVAIL_AVAILABLE;
   else if (transparent_alias)
     ultimate_alias_target (&avail, ref);
-  else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl))
+  else if (ifunc_resolver
 	   || lookup_attribute ("noipa", DECL_ATTRIBUTES (decl)))
     avail = AVAIL_INTERPOSABLE;
   else if (!externally_visible)
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index d1ef8408497..4bf4e2d0b11 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -530,6 +530,9 @@ public:
   /* Set when symbol can be streamed into bytecode for offloading.  */
   unsigned offloadable : 1;
 
+  /* Set when symbol is an IFUNC resolver.  */
+  unsigned ifunc_resolver : 1;
+
 
   /* Ordering of all symtab entries.  */
   int order;
@@ -2889,6 +2892,7 @@ cgraph_node::only_called_directly_or_aliased_p (void)
 {
   gcc_assert (!global.inlined_to);
   return (!force_output && !address_taken
+	  && !ifunc_resolver
 	  && !used_from_other_partition
 	  && !DECL_VIRTUAL_P (decl)
 	  && !DECL_STATIC_CONSTRUCTOR (decl)
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index e418ec04149..212ee7b8340 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -1307,7 +1307,7 @@ maybe_diag_incompatible_alias (tree alias, tree target)
   tree altype = TREE_TYPE (alias);
   tree targtype = TREE_TYPE (target);
 
-  bool ifunc = lookup_attribute ("ifunc", DECL_ATTRIBUTES (alias));
+  bool ifunc = cgraph_node::get (alias)->ifunc_resolver;
   tree funcptr = altype;
 
   if (ifunc)
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index dcd5391012c..40baf858ca5 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -1257,6 +1257,8 @@ input_node (struct lto_file_decl_data *file_data,
 	 of ipa passes is done.  Alays forcingly create a fresh node.  */
       node = symtab->create_empty ();
       node->decl = fn_decl;
+      if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (fn_decl)))
+	node->ifunc_resolver = 1;
       node->register_symbol ();
     }
 
diff --git a/gcc/symtab.c b/gcc/symtab.c
index b54183fbd49..8b63937d18f 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -2247,13 +2247,13 @@ symtab_node::binds_to_current_def_p (symtab_node *ref)
   if (transparent_alias)
     return definition
 	   && get_alias_target()->binds_to_current_def_p (ref);
-  if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)))
+  cgraph_node *cnode = dyn_cast <cgraph_node *> (this);
+  if (cnode && cnode->ifunc_resolver)
     return false;
   if (decl_binds_to_current_def_p (decl))
     return true;
 
   /* Inline clones always binds locally.  */
-  cgraph_node *cnode = dyn_cast <cgraph_node *> (this);
   if (cnode && cnode->global.inlined_to)
     return true;
 
diff --git a/gcc/testsuite/gcc.target/i386/pr85345.c b/gcc/testsuite/gcc.target/i386/pr85345.c
new file mode 100644
index 00000000000..63f771294ad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr85345.c
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times {\mendbr} 4 } } */
+
+int resolver_fn = 0;
+int resolved_fn = 0;
+
+static inline void
+do_it_right_at_runtime_A (void)
+{
+  resolved_fn++;
+}
+
+static inline void
+do_it_right_at_runtime_B (void)
+{
+  resolved_fn++;
+}
+
+static inline void do_it_right_at_runtime (void);
+
+void do_it_right_at_runtime (void)
+  __attribute__ ((ifunc ("resolve_do_it_right_at_runtime")));
+
+extern int r;
+static void (*resolve_do_it_right_at_runtime (void)) (void)
+{
+  resolver_fn++;
+
+  typeof(do_it_right_at_runtime) *func;
+  if (r & 1)
+    func = do_it_right_at_runtime_A;
+  else
+    func = do_it_right_at_runtime_B;
+
+  return (void *) func;
+}
+
+int
+main ()
+{
+  do_it_right_at_runtime ();
+  return 0;
+}
diff --git a/gcc/varasm.c b/gcc/varasm.c
index d24bac4ad8f..85b0b16b8d0 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -5821,7 +5821,8 @@ do_assemble_alias (tree decl, tree target)
       globalize_decl (decl);
       maybe_assemble_visibility (decl);
     }
-  if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)))
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && cgraph_node::get (decl)->ifunc_resolver)
     {
 #if defined (ASM_OUTPUT_TYPE_DIRECTIVE)
       if (targetm.has_ifunc_p ())
@@ -5904,7 +5905,7 @@ assemble_alias (tree decl, tree target)
 # else
       if (!DECL_WEAK (decl))
 	{
-	  if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)))
+	  if (cgraph_node::get (decl)->ifunc_resolver)
 	    error_at (DECL_SOURCE_LOCATION (decl),
 		      "ifunc is not supported in this configuration");
 	  else
@@ -7024,7 +7025,8 @@ default_binds_local_p_3 (const_tree exp, bool shlib, bool weak_dominate,
      weakref alias.  */
   if (lookup_attribute ("weakref", DECL_ATTRIBUTES (exp))
       || (TREE_CODE (exp) == FUNCTION_DECL
-	  && lookup_attribute ("ifunc", DECL_ATTRIBUTES (exp))))
+	  && cgraph_node::get (exp)
+	  && cgraph_node::get (exp)->ifunc_resolver))
     return false;
 
   /* Static variables are always local.  */

Patch

diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index d1ef8408497..9e195824fcc 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -24,6 +24,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "profile-count.h"
 #include "ipa-ref.h"
 #include "plugin-api.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 class ipa_opt_pass_d;
 typedef ipa_opt_pass_d *ipa_opt_pass;
@@ -2894,7 +2896,8 @@  cgraph_node::only_called_directly_or_aliased_p (void)
 	  && !DECL_STATIC_CONSTRUCTOR (decl)
 	  && !DECL_STATIC_DESTRUCTOR (decl)
 	  && !used_from_object_file_p ()
-	  && !externally_visible);
+	  && !externally_visible
+	  && !lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)));
 }
 
 /* Return true when function can be removed from callgraph
diff --git a/gcc/testsuite/gcc.target/i386/pr85345.c b/gcc/testsuite/gcc.target/i386/pr85345.c
new file mode 100644
index 00000000000..63f771294ad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr85345.c
@@ -0,0 +1,44 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times {\mendbr} 4 } } */
+
+int resolver_fn = 0;
+int resolved_fn = 0;
+
+static inline void
+do_it_right_at_runtime_A (void)
+{
+  resolved_fn++;
+}
+
+static inline void
+do_it_right_at_runtime_B (void)
+{
+  resolved_fn++;
+}
+
+static inline void do_it_right_at_runtime (void);
+
+void do_it_right_at_runtime (void)
+  __attribute__ ((ifunc ("resolve_do_it_right_at_runtime")));
+
+extern int r;
+static void (*resolve_do_it_right_at_runtime (void)) (void)
+{
+  resolver_fn++;
+
+  typeof(do_it_right_at_runtime) *func;
+  if (r & 1)
+    func = do_it_right_at_runtime_A;
+  else
+    func = do_it_right_at_runtime_B;
+
+  return (void *) func;
+}
+
+int
+main ()
+{
+  do_it_right_at_runtime ();
+  return 0;
+}