diff mbox

Do not allow to inline ifunc resolvers (PR ipa/81128).

Message ID 4ad58eaa-1d72-88a8-e0c0-e1719255a3b1@suse.cz
State New
Headers show

Commit Message

Martin Liška June 27, 2017, 12:49 p.m. UTC
Hello.

Currently ifunc is interpreted as normal alias by IPA optimizations. That's problematic
as should not consider ifunc alias as candidate for inlining, or redirection.

Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
And survives MVC tests on x86_64-linux-gnu.

Ready to be installed?
Martin

gcc/ChangeLog:

2017-06-22  Martin Liska  <mliska@suse.cz>

	* ipa-inline.c (can_inline_edge_p): Return false for ifunc fns.
	* ipa-visibility.c (can_replace_by_local_alias): Likewise.

gcc/c-family/ChangeLog:

2017-06-22  Martin Liska  <mliska@suse.cz>

	* c-attribs.c (handle_alias_ifunc_attribute): Append ifunc alias
	to a function declaration.

gcc/testsuite/ChangeLog:

2017-06-22  Martin Liska  <mliska@suse.cz>

	* gcc.target/i386/pr81128.c: New test.
---
 gcc/c-family/c-attribs.c                | 11 ++++--
 gcc/ipa-inline.c                        |  2 +
 gcc/ipa-visibility.c                    |  3 +-
 gcc/testsuite/gcc.target/i386/pr81128.c | 65 +++++++++++++++++++++++++++++++++
 4 files changed, 77 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr81128.c

Comments

Jan Hubicka June 27, 2017, 2:57 p.m. UTC | #1
> Hello.
> 
> Currently ifunc is interpreted as normal alias by IPA optimizations. That's problematic
> as should not consider ifunc alias as candidate for inlining, or redirection.
> 
> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
> And survives MVC tests on x86_64-linux-gnu.
> 
> Ready to be installed?

Wasn't this supposed to go with arranging availability to be AVAIL_INTERPOSABLE
(as the target will be interposed by linker to the corect target)

Honza
> Martin
> 
> gcc/ChangeLog:
> 
> 2017-06-22  Martin Liska  <mliska@suse.cz>
> 
> 	* ipa-inline.c (can_inline_edge_p): Return false for ifunc fns.
> 	* ipa-visibility.c (can_replace_by_local_alias): Likewise.
> 
> gcc/c-family/ChangeLog:
> 
> 2017-06-22  Martin Liska  <mliska@suse.cz>
> 
> 	* c-attribs.c (handle_alias_ifunc_attribute): Append ifunc alias
> 	to a function declaration.
> 
> gcc/testsuite/ChangeLog:
> 
> 2017-06-22  Martin Liska  <mliska@suse.cz>
> 
> 	* gcc.target/i386/pr81128.c: New test.
> ---
>  gcc/c-family/c-attribs.c                | 11 ++++--
>  gcc/ipa-inline.c                        |  2 +
>  gcc/ipa-visibility.c                    |  3 +-
>  gcc/testsuite/gcc.target/i386/pr81128.c | 65 +++++++++++++++++++++++++++++++++
>  4 files changed, 77 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr81128.c
> 
> 

> diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
> index 2b6845f2cbd..626ffa1cde7 100644
> --- a/gcc/c-family/c-attribs.c
> +++ b/gcc/c-family/c-attribs.c
> @@ -1846,9 +1846,14 @@ handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args,
>  	TREE_STATIC (decl) = 1;
>  
>        if (!is_alias)
> -	/* ifuncs are also aliases, so set that attribute too.  */
> -	DECL_ATTRIBUTES (decl)
> -	  = tree_cons (get_identifier ("alias"), args, DECL_ATTRIBUTES (decl));
> +	{
> +	  /* ifuncs are also aliases, so set that attribute too.  */
> +	  DECL_ATTRIBUTES (decl)
> +	    = tree_cons (get_identifier ("alias"), args,
> +			 DECL_ATTRIBUTES (decl));
> +	  DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("ifunc"),
> +					      NULL, DECL_ATTRIBUTES (decl));
> +	}
>      }
>    else
>      {
> diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
> index fb20d3723cc..588fa9c41e4 100644
> --- a/gcc/ipa-inline.c
> +++ b/gcc/ipa-inline.c
> @@ -370,6 +370,8 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
>        e->inline_failed = CIF_ATTRIBUTE_MISMATCH;
>        inlinable = false;
>      }
> +  else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (e->callee->decl)))
> +      inlinable = false;
>    /* Check if caller growth allows the inlining.  */
>    else if (!DECL_DISREGARD_INLINE_LIMITS (callee->decl)
>  	   && !disregard_limits
> diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c
> index d5a3ae56c46..79d05b41085 100644
> --- a/gcc/ipa-visibility.c
> +++ b/gcc/ipa-visibility.c
> @@ -345,7 +345,8 @@ can_replace_by_local_alias (symtab_node *node)
>    
>    return (node->get_availability () > AVAIL_INTERPOSABLE
>  	  && !decl_binds_to_current_def_p (node->decl)
> -	  && !node->can_be_discarded_p ());
> +	  && !node->can_be_discarded_p ()
> +	  && !lookup_attribute ("ifunc", DECL_ATTRIBUTES (node->decl)));
>  }
>  
>  /* Return true if we can replace reference to NODE by local alias
> diff --git a/gcc/testsuite/gcc.target/i386/pr81128.c b/gcc/testsuite/gcc.target/i386/pr81128.c
> new file mode 100644
> index 00000000000..90a567ad690
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr81128.c
> @@ -0,0 +1,65 @@
> +/* PR ipa/81128 */
> +/* { dg-do run } */
> +/* { dg-options "-O3" } */
> +/* { dg-require-ifunc "" } */
> +
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <time.h>
> +
> +int resolver_fn = 0;
> +int resolved_fn = 0;
> +
> +static inline void
> +do_it_right_at_runtime_A ()
> +{
> +  resolved_fn++;
> +}
> +
> +static inline void
> +do_it_right_at_runtime_B ()
> +{
> +  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")));
> +
> +static void (*resolve_do_it_right_at_runtime (void)) (void)
> +{
> +  srand (time (NULL));
> +  int r = rand ();
> +  resolver_fn++;
> +
> +  /* Use intermediate variable to get a warning for non-matching
> +   * prototype. */
> +  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 (void)
> +{
> +  const unsigned int ITERS = 10;
> +
> +  for (int i = ITERS; i > 0; i--)
> +    {
> +      do_it_right_at_runtime ();
> +    }
> +
> +  if (resolver_fn != 1)
> +    __builtin_abort ();
> +
> +  if (resolved_fn != 10)
> +    __builtin_abort ();
> +
> +  return 0;
> +}
>
diff mbox

Patch

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 2b6845f2cbd..626ffa1cde7 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -1846,9 +1846,14 @@  handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args,
 	TREE_STATIC (decl) = 1;
 
       if (!is_alias)
-	/* ifuncs are also aliases, so set that attribute too.  */
-	DECL_ATTRIBUTES (decl)
-	  = tree_cons (get_identifier ("alias"), args, DECL_ATTRIBUTES (decl));
+	{
+	  /* ifuncs are also aliases, so set that attribute too.  */
+	  DECL_ATTRIBUTES (decl)
+	    = tree_cons (get_identifier ("alias"), args,
+			 DECL_ATTRIBUTES (decl));
+	  DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("ifunc"),
+					      NULL, DECL_ATTRIBUTES (decl));
+	}
     }
   else
     {
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index fb20d3723cc..588fa9c41e4 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -370,6 +370,8 @@  can_inline_edge_p (struct cgraph_edge *e, bool report,
       e->inline_failed = CIF_ATTRIBUTE_MISMATCH;
       inlinable = false;
     }
+  else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (e->callee->decl)))
+      inlinable = false;
   /* Check if caller growth allows the inlining.  */
   else if (!DECL_DISREGARD_INLINE_LIMITS (callee->decl)
 	   && !disregard_limits
diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c
index d5a3ae56c46..79d05b41085 100644
--- a/gcc/ipa-visibility.c
+++ b/gcc/ipa-visibility.c
@@ -345,7 +345,8 @@  can_replace_by_local_alias (symtab_node *node)
   
   return (node->get_availability () > AVAIL_INTERPOSABLE
 	  && !decl_binds_to_current_def_p (node->decl)
-	  && !node->can_be_discarded_p ());
+	  && !node->can_be_discarded_p ()
+	  && !lookup_attribute ("ifunc", DECL_ATTRIBUTES (node->decl)));
 }
 
 /* Return true if we can replace reference to NODE by local alias
diff --git a/gcc/testsuite/gcc.target/i386/pr81128.c b/gcc/testsuite/gcc.target/i386/pr81128.c
new file mode 100644
index 00000000000..90a567ad690
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr81128.c
@@ -0,0 +1,65 @@ 
+/* PR ipa/81128 */
+/* { dg-do run } */
+/* { dg-options "-O3" } */
+/* { dg-require-ifunc "" } */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+int resolver_fn = 0;
+int resolved_fn = 0;
+
+static inline void
+do_it_right_at_runtime_A ()
+{
+  resolved_fn++;
+}
+
+static inline void
+do_it_right_at_runtime_B ()
+{
+  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")));
+
+static void (*resolve_do_it_right_at_runtime (void)) (void)
+{
+  srand (time (NULL));
+  int r = rand ();
+  resolver_fn++;
+
+  /* Use intermediate variable to get a warning for non-matching
+   * prototype. */
+  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 (void)
+{
+  const unsigned int ITERS = 10;
+
+  for (int i = ITERS; i > 0; i--)
+    {
+      do_it_right_at_runtime ();
+    }
+
+  if (resolver_fn != 1)
+    __builtin_abort ();
+
+  if (resolved_fn != 10)
+    __builtin_abort ();
+
+  return 0;
+}