diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2015-09-04 08:53:23 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2015-09-04 09:02:16 -0700 |
commit | f3d3789106cdd80c8f7a905f9cc42a32581c79df (patch) | |
tree | b737a44d54bb2d2e61118f441e1b03a48ddc5d7c | |
parent | 9964a98388674fd4884943ff1ac12152af99fa7f (diff) | |
download | gcc-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.c | 29 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 4 | ||||
-rw-r--r-- | gcc/doc/extend.texi | 9 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr66960-1.c | 21 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr66960-2.c | 21 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr66960-3.c | 17 |
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" } */ |