[2/3] i386: Change indirect_return to function type attribute

Message ID 20180718153329.GA13951@intel.com
State New
Headers show
Series
  • Untitled series #5678
Related show

Commit Message

H.J. Lu July 18, 2018, 3:33 p.m.
In

struct ucontext;
typedef struct ucontext ucontext_t;

extern int (*bar) (ucontext_t *__restrict __oucp,
                   const ucontext_t *__restrict __ucp)
  __attribute__((__indirect_return__));

extern int res;

void
foo (ucontext_t *oucp, ucontext_t *ucp)
{
  res = bar (oucp, ucp);
}

bar() may return via indirect branch.  This patch changes indirect_return
to type attribute to allow indirect_return attribute on variable or type
of function pointer so that ENDBR can be inserted after call to bar().

Tested on i386 and x86-64.  OK for trunk?

Thanks.


H.J.
---
gcc/

	PR target/86560
	* config/i386/i386.c (rest_of_insert_endbranch): Lookup
	indirect_return as function type attribute.
	(ix86_attribute_table): Change indirect_return to function
	type attribute.
	* doc/extend.texi: Update indirect_return attribute.

gcc/testsuite/

	PR target/86560
	* gcc.target/i386/pr86560-1.c: New test.
	* gcc.target/i386/pr86560-2.c: Likewise.
	* gcc.target/i386/pr86560-3.c: Likewise.
---
 gcc/config/i386/i386.c                    | 23 +++++++++++++++--------
 gcc/doc/extend.texi                       |  5 +++--
 gcc/testsuite/gcc.target/i386/pr86560-1.c | 16 ++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr86560-2.c | 16 ++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr86560-3.c | 17 +++++++++++++++++
 5 files changed, 67 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr86560-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr86560-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr86560-3.c

-- 
2.17.1

Comments

Richard Biener July 19, 2018, 8:35 a.m. | #1
On Wed, Jul 18, 2018 at 5:33 PM H.J. Lu <hongjiu.lu@intel.com> wrote:
>

> In

>

> struct ucontext;

> typedef struct ucontext ucontext_t;

>

> extern int (*bar) (ucontext_t *__restrict __oucp,

>                    const ucontext_t *__restrict __ucp)

>   __attribute__((__indirect_return__));

>

> extern int res;

>

> void

> foo (ucontext_t *oucp, ucontext_t *ucp)

> {

>   res = bar (oucp, ucp);

> }

>

> bar() may return via indirect branch.  This patch changes indirect_return

> to type attribute to allow indirect_return attribute on variable or type

> of function pointer so that ENDBR can be inserted after call to bar().

>

> Tested on i386 and x86-64.  OK for trunk?


OK.

Richard.

> Thanks.

>

>

> H.J.

> ---

> gcc/

>

>         PR target/86560

>         * config/i386/i386.c (rest_of_insert_endbranch): Lookup

>         indirect_return as function type attribute.

>         (ix86_attribute_table): Change indirect_return to function

>         type attribute.

>         * doc/extend.texi: Update indirect_return attribute.

>

> gcc/testsuite/

>

>         PR target/86560

>         * gcc.target/i386/pr86560-1.c: New test.

>         * gcc.target/i386/pr86560-2.c: Likewise.

>         * gcc.target/i386/pr86560-3.c: Likewise.

> ---

>  gcc/config/i386/i386.c                    | 23 +++++++++++++++--------

>  gcc/doc/extend.texi                       |  5 +++--

>  gcc/testsuite/gcc.target/i386/pr86560-1.c | 16 ++++++++++++++++

>  gcc/testsuite/gcc.target/i386/pr86560-2.c | 16 ++++++++++++++++

>  gcc/testsuite/gcc.target/i386/pr86560-3.c | 17 +++++++++++++++++

>  5 files changed, 67 insertions(+), 10 deletions(-)

>  create mode 100644 gcc/testsuite/gcc.target/i386/pr86560-1.c

>  create mode 100644 gcc/testsuite/gcc.target/i386/pr86560-2.c

>  create mode 100644 gcc/testsuite/gcc.target/i386/pr86560-3.c

>

> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c

> index aec739c3974..ac27248370b 100644

> --- a/gcc/config/i386/i386.c

> +++ b/gcc/config/i386/i386.c

> @@ -2627,16 +2627,23 @@ rest_of_insert_endbranch (void)

>                 {

>                   rtx call = get_call_rtx_from (insn);

>                   rtx fnaddr = XEXP (call, 0);

> +                 tree fndecl = NULL_TREE;

>

>                   /* Also generate ENDBRANCH for non-tail call which

>                      may return via indirect branch.  */

> -                 if (MEM_P (fnaddr)

> -                     && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF)

> +                 if (GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF)

> +                   fndecl = SYMBOL_REF_DECL (XEXP (fnaddr, 0));

> +                 if (fndecl == NULL_TREE)

> +                   fndecl = MEM_EXPR (fnaddr);

> +                 if (fndecl

> +                     && TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE

> +                     && TREE_CODE (TREE_TYPE (fndecl)) != METHOD_TYPE)

> +                   fndecl = NULL_TREE;

> +                 if (fndecl && TYPE_ARG_TYPES (TREE_TYPE (fndecl)))

>                     {

> -                     tree fndecl = SYMBOL_REF_DECL (XEXP (fnaddr, 0));

> -                     if (fndecl

> -                         && lookup_attribute ("indirect_return",

> -                                              DECL_ATTRIBUTES (fndecl)))

> +                     tree fntype = TREE_TYPE (fndecl);

> +                     if (lookup_attribute ("indirect_return",

> +                                           TYPE_ATTRIBUTES (fntype)))

>                         need_endbr = true;

>                     }

>                 }

> @@ -46101,8 +46108,8 @@ static const struct attribute_spec ix86_attribute_table[] =

>      ix86_handle_fndecl_attribute, NULL },

>    { "function_return", 1, 1, true, false, false, false,

>      ix86_handle_fndecl_attribute, NULL },

> -  { "indirect_return", 0, 0, true, false, false, false,

> -    ix86_handle_fndecl_attribute, NULL },

> +  { "indirect_return", 0, 0, false, true, true, false,

> +    NULL, NULL },

>

>    /* End element.  */

>    { NULL, 0, 0, false, false, false, false, NULL, NULL }

> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi

> index 8b4d3fd9de3..edeaec6d872 100644

> --- a/gcc/doc/extend.texi

> +++ b/gcc/doc/extend.texi

> @@ -5861,8 +5861,9 @@ foo (void)

>  @item indirect_return

>  @cindex @code{indirect_return} function attribute, x86

>

> -The @code{indirect_return} attribute on a function is used to inform

> -the compiler that the function may return via indirect branch.

> +The @code{indirect_return} attribute can be applied to a function,

> +as well as variable or type of function pointer to inform the

> +compiler that the function may return via indirect branch.

>

>  @end table

>

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

> new file mode 100644

> index 00000000000..a2b702695c5

> --- /dev/null

> +++ b/gcc/testsuite/gcc.target/i386/pr86560-1.c

> @@ -0,0 +1,16 @@

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

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

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

> +

> +struct ucontext;

> +

> +extern int (*bar) (struct ucontext *)

> +  __attribute__((__indirect_return__));

> +

> +extern int res;

> +

> +void

> +foo (struct ucontext *oucp)

> +{

> +  res = bar (oucp);

> +}

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

> new file mode 100644

> index 00000000000..6f01b385afd

> --- /dev/null

> +++ b/gcc/testsuite/gcc.target/i386/pr86560-2.c

> @@ -0,0 +1,16 @@

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

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

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

> +

> +struct ucontext;

> +

> +typedef int (*bar_p) (struct ucontext *)

> +  __attribute__((__indirect_return__));

> +

> +extern int res;

> +

> +void

> +foo (bar_p bar, struct ucontext *oucp)

> +{

> +  res = bar (oucp);

> +}

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

> new file mode 100644

> index 00000000000..05328e24509

> --- /dev/null

> +++ b/gcc/testsuite/gcc.target/i386/pr86560-3.c

> @@ -0,0 +1,17 @@

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

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

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

> +

> +struct ucontext;

> +

> +extern int (*bar) (struct ucontext *);

> +

> +extern int res;

> +

> +void

> +foo (struct ucontext *oucp)

> +{

> +  int (*f) (struct ucontext *) __attribute__((__indirect_return__))

> +    = bar;

> +  res = f (oucp);

> +}

> --

> 2.17.1

>

Patch

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index aec739c3974..ac27248370b 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2627,16 +2627,23 @@  rest_of_insert_endbranch (void)
 		{
 		  rtx call = get_call_rtx_from (insn);
 		  rtx fnaddr = XEXP (call, 0);
+		  tree fndecl = NULL_TREE;
 
 		  /* Also generate ENDBRANCH for non-tail call which
 		     may return via indirect branch.  */
-		  if (MEM_P (fnaddr)
-		      && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF)
+		  if (GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF)
+		    fndecl = SYMBOL_REF_DECL (XEXP (fnaddr, 0));
+		  if (fndecl == NULL_TREE)
+		    fndecl = MEM_EXPR (fnaddr);
+		  if (fndecl
+		      && TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE
+		      && TREE_CODE (TREE_TYPE (fndecl)) != METHOD_TYPE)
+		    fndecl = NULL_TREE;
+		  if (fndecl && TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
 		    {
-		      tree fndecl = SYMBOL_REF_DECL (XEXP (fnaddr, 0));
-		      if (fndecl
-			  && lookup_attribute ("indirect_return",
-					       DECL_ATTRIBUTES (fndecl)))
+		      tree fntype = TREE_TYPE (fndecl);
+		      if (lookup_attribute ("indirect_return",
+					    TYPE_ATTRIBUTES (fntype)))
 			need_endbr = true;
 		    }
 		}
@@ -46101,8 +46108,8 @@  static const struct attribute_spec ix86_attribute_table[] =
     ix86_handle_fndecl_attribute, NULL },
   { "function_return", 1, 1, true, false, false, false,
     ix86_handle_fndecl_attribute, NULL },
-  { "indirect_return", 0, 0, true, false, false, false,
-    ix86_handle_fndecl_attribute, NULL },
+  { "indirect_return", 0, 0, false, true, true, false,
+    NULL, NULL },
 
   /* End element.  */
   { NULL, 0, 0, false, false, false, false, NULL, NULL }
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 8b4d3fd9de3..edeaec6d872 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -5861,8 +5861,9 @@  foo (void)
 @item indirect_return
 @cindex @code{indirect_return} function attribute, x86
 
-The @code{indirect_return} attribute on a function is used to inform
-the compiler that the function may return via indirect branch.
+The @code{indirect_return} attribute can be applied to a function,
+as well as variable or type of function pointer to inform the
+compiler that the function may return via indirect branch.
 
 @end table
 
diff --git a/gcc/testsuite/gcc.target/i386/pr86560-1.c b/gcc/testsuite/gcc.target/i386/pr86560-1.c
new file mode 100644
index 00000000000..a2b702695c5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr86560-1.c
@@ -0,0 +1,16 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* { dg-final { scan-assembler-times {\mendbr} 2 } } */
+
+struct ucontext;
+
+extern int (*bar) (struct ucontext *)
+  __attribute__((__indirect_return__));
+
+extern int res;
+
+void
+foo (struct ucontext *oucp)
+{
+  res = bar (oucp);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr86560-2.c b/gcc/testsuite/gcc.target/i386/pr86560-2.c
new file mode 100644
index 00000000000..6f01b385afd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr86560-2.c
@@ -0,0 +1,16 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* { dg-final { scan-assembler-times {\mendbr} 2 } } */
+
+struct ucontext;
+
+typedef int (*bar_p) (struct ucontext *)
+  __attribute__((__indirect_return__));
+
+extern int res;
+
+void
+foo (bar_p bar, struct ucontext *oucp)
+{
+  res = bar (oucp);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr86560-3.c b/gcc/testsuite/gcc.target/i386/pr86560-3.c
new file mode 100644
index 00000000000..05328e24509
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr86560-3.c
@@ -0,0 +1,17 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* { dg-final { scan-assembler-times {\mendbr} 2 } } */
+
+struct ucontext;
+
+extern int (*bar) (struct ucontext *);
+
+extern int res;
+
+void
+foo (struct ucontext *oucp)
+{
+  int (*f) (struct ucontext *) __attribute__((__indirect_return__))
+    = bar;
+  res = f (oucp);
+}