summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2015-09-04 08:53:23 -0700
committerH.J. Lu <hjl.tools@gmail.com>2015-09-04 09:02:16 -0700
commitf3d3789106cdd80c8f7a905f9cc42a32581c79df (patch)
treeb737a44d54bb2d2e61118f441e1b03a48ddc5d7c
parent9964a98388674fd4884943ff1ac12152af99fa7f (diff)
downloadgcc-f3d3789106cdd80c8f7a905f9cc42a32581c79df.tar.gz
Add __builtin_ia32_interrupt_data
The interrupt and exception handlers are called by x86 processors. X86 hardware pushes information onto stack and calls the handler. We need a builtin function to access interrupt or exception data from the interrupt and exception handlers which are void function without arguments. This patch adds __builtin_ia32_interrupt_data so that interrupt or exception data can be retrieved from the interrupt and exception handlers. gcc/ PR target/66960 * config/i386/i386.c (ix86_expand_prologue): Sorry if DRAP is used and the address of interrupt/exception data has been taken. (ix86_builtins): Add IX86_BUILTIN_INTERRUPT_DATA. (ix86_expand_builtin): Handle IX86_BUILTIN_INTERRUPT_DATA. * config/i386/i386.h (machine_function): Add interrupt_data_taken. * doc/extend.texi: Document __builtin_ia32_interrupt_data. gcc/testsuite/ PR target/66960 * gcc.target/i386/pr66960-1.c: New test. * gcc.target/i386/pr66960-2.c: Likewise. * gcc.target/i386/pr66960-3.c: Likewise.
-rw-r--r--gcc/config/i386/i386.c29
-rw-r--r--gcc/config/i386/i386.h4
-rw-r--r--gcc/doc/extend.texi9
-rw-r--r--gcc/testsuite/gcc.target/i386/pr66960-1.c21
-rw-r--r--gcc/testsuite/gcc.target/i386/pr66960-2.c21
-rw-r--r--gcc/testsuite/gcc.target/i386/pr66960-3.c17
6 files changed, 101 insertions, 0 deletions
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index d78f4e7f175..7a97f3725d2 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -11577,6 +11577,13 @@ ix86_expand_prologue (void)
{
int align_bytes = crtl->stack_alignment_needed / BITS_PER_UNIT;
+ /* Can't use DRAP if the address of interrupt/exception data has
+ been taken. */
+ if (cfun->machine->interrupt_data_taken)
+ sorry ("%<__builtin_ia32_interrupt_data%> not supported with"
+ " stack realignment. This may be worked around by"
+ " adding -maccumulate-outgoing-arg.");
+
/* Only need to push parameter pointer reg if it is caller saved. */
if (!call_used_regs[REGNO (crtl->drap_reg)])
{
@@ -30747,6 +30754,9 @@ enum ix86_builtins
IX86_BUILTIN_READ_FLAGS,
IX86_BUILTIN_WRITE_FLAGS,
+ /* Get the address of interrupt or exception data. */
+ IX86_BUILTIN_INTERRUPT_DATA,
+
IX86_BUILTIN_MAX
};
@@ -34374,6 +34384,10 @@ ix86_init_mmx_sse_builtins (void)
def_builtin (OPTION_MASK_ISA_MWAITX, "__builtin_ia32_mwaitx",
VOID_FTYPE_UNSIGNED_UNSIGNED_UNSIGNED, IX86_BUILTIN_MWAITX);
+ /* Get the stack address when the function is called. */
+ def_builtin (0, "__builtin_ia32_interrupt_data",
+ PVOID_FTYPE_VOID, IX86_BUILTIN_INTERRUPT_DATA);
+
/* Add FMA4 multi-arg argument instructions */
for (i = 0, d = bdesc_multi_arg; i < ARRAY_SIZE (bdesc_multi_arg); i++, d++)
{
@@ -40298,6 +40312,21 @@ rdseed_step:
emit_insn (gen_xabort (op0));
return 0;
+ case IX86_BUILTIN_INTERRUPT_DATA:
+ cfun->machine->interrupt_data_taken = true;
+
+ if (!target
+ || GET_MODE (target) != Pmode
+ || !register_operand (target, Pmode))
+ target = gen_reg_rtx (Pmode);
+
+ /* After the prologue, he address of interrupt or exception data
+ is at -WORD(AP) in the current frame. */
+ emit_insn (gen_rtx_SET (target,
+ plus_constant (Pmode, arg_pointer_rtx,
+ -UNITS_PER_WORD)));
+ return target;
+
default:
break;
}
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 7bd23ecadef..d838acb536a 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -2492,6 +2492,10 @@ struct GTY(()) machine_function {
/* If true, it is safe to not save/restore DRAP register. */
BOOL_BITFIELD no_drap_save_restore : 1;
+ /* If true, the address of interrupt or exception data has been
+ taken. */
+ BOOL_BITFIELD interrupt_data_taken : 1;
+
/* If true, there is register available for argument passing. This
is used only in ix86_function_ok_for_sibcall by 32-bit to determine
if there is scratch register available for indirect sibcall. In
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 23e6a76b8a8..7ddf8bfd455 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -16815,6 +16815,15 @@ The following built-in function is always available.
@item void __builtin_ia32_pause (void)
Generates the @code{pause} machine instruction with a compiler memory
barrier.
+
+@item void *__builtin_ia32_interrupt_data (void)
+Returns a pointer to interrupt or exception data pushed onto the stack
+by processor.
+
+The @code{__builtin_frame_address} builtin isn't suitable for interrupt
+and exception handlers since it returns the stack frame address on the
+callee side and compiler may generate a new stack frame for stack
+alignment.
@end table
The following floating-point built-in functions are made available in the
diff --git a/gcc/testsuite/gcc.target/i386/pr66960-1.c b/gcc/testsuite/gcc.target/i386/pr66960-1.c
new file mode 100644
index 00000000000..eeb67d2aadf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66960-1.c
@@ -0,0 +1,21 @@
+/* { dg-do link } */
+/* { dg-options "-O" } */
+
+extern void link_error (void);
+
+__attribute__ ((noinline, noclone))
+void
+foo (void)
+{
+ void **p = __builtin_ia32_interrupt_data ();
+ void *ra = __builtin_return_address (0);
+ if (*p != ra)
+ link_error ();
+}
+
+int
+main (void)
+{
+ foo ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr66960-2.c b/gcc/testsuite/gcc.target/i386/pr66960-2.c
new file mode 100644
index 00000000000..2ed6e2a2447
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66960-2.c
@@ -0,0 +1,21 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -maccumulate-outgoing-args" { target { lp64 } } } */
+/* { dg-options "-O2 -maccumulate-outgoing-args -maddress-mode=short" { target { x32 } } } */
+/* { dg-options "-O2 -maccumulate-outgoing-args -miamcu" { target { ia32 } } } */
+
+extern void abort (void);
+extern int check_int (int *i, int align);
+typedef int aligned __attribute__((aligned(64)));
+
+void *
+foo (void)
+{
+ aligned j;
+ if (check_int (&j, __alignof__(j)) != j)
+ abort ();
+ return __builtin_ia32_interrupt_data ();
+}
+
+/* { dg-final { scan-assembler "leaq\[ \t\]8\\(%rbp\\), %rax" { target lp64 } } } */
+/* { dg-final { scan-assembler "leal\[ \t\]8\\(%rbp\\), %eax" { target x32 } } } */
+/* { dg-final { scan-assembler "leal\[ \t\]4\\(%ebp\\), %eax" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr66960-3.c b/gcc/testsuite/gcc.target/i386/pr66960-3.c
new file mode 100644
index 00000000000..b08400de07b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr66960-3.c
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -mno-accumulate-outgoing-args" { target { lp64 } } } */
+/* { dg-options "-O2 -mno-accumulate-outgoing-args -maddress-mode=short" { target { x32 } } } */
+/* { dg-options "-O2 -mno-accumulate-outgoing-args -miamcu" { target { ia32 } } } */
+
+extern void abort (void);
+extern int check_int (int *i, int align);
+typedef int aligned __attribute__((aligned(64)));
+
+void *
+foo (void)
+{
+ aligned j;
+ if (check_int (&j, __alignof__(j)) != j)
+ abort ();
+ return __builtin_ia32_interrupt_data ();
+} /* { dg-message "sorry, unimplemented: .__builtin_ia32_interrupt_data. not supported" } */