diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2015-10-06 04:47:06 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2015-11-25 15:53:01 -0800 |
commit | 0428f4715d1bcbf175d1a8fa2079e51b4b9069d1 (patch) | |
tree | 767bccc6f0f2d2e43b54de23917bafafa86baee9 /gcc/testsuite | |
parent | 3b5af4184d0cd72f696dbe6d2711f68954b5cb88 (diff) | |
download | gcc-hjl/interrupt/middle.tar.gz |
Implement x86 interrupt attributehjl/interrupt/middle
The interrupt and exception handlers are called by x86 processors. X86
hardware pushes information onto stack and calls the handler. The
requirements are
1. Both interrupt and exception handlers must use the 'IRET' instruction,
instead of the 'RET' instruction, to return from the handlers.
2. All registers are callee-saved in interrupt and exception handlers.
3. The difference between interrupt and exception handlers is the
exception handler must pop 'ERROR_CODE' off the stack before the 'IRET'
instruction.
The design goals of interrupt and exception handlers for x86 processors
are:
1. Support both 32-bit and 64-bit modes.
2. Flexible for compilers to optimize.
3. Easy to use by programmers.
To implement interrupt and exception handlers for x86 processors, a
compiler should support:
'interrupt' attribute
Use this attribute to indicate that the specified function with
mandatory arguments is an interrupt or exception handler. The compiler
generates function entry and exit sequences suitable for use in an
interrupt handler when this attribute is present. The 'IRET' instruction,
instead of the 'RET' instruction, is used to return from interrupt or
exception handlers. All registers, except for the EFLAGS register which
is restored by the 'IRET' instruction, are preserved by the compiler.
Any interruptible-without-stack-switch code must be compiled with
-mno-red-zone since interrupt handlers can and will, because of the
hardware design, touch the red zone.
1. interrupt handler must be declared with a mandatory pointer argument:
struct interrupt_frame;
__attribute__ ((interrupt))
void
f (struct interrupt_frame *frame)
{
...
}
and user must properly define the structure the pointer pointing to.
2. exception handler:
The exception handler is very similar to the interrupt handler with
a different mandatory function signature:
typedef unsigned int uword_t __attribute__ ((mode (__word__)));
struct interrupt_frame;
__attribute__ ((interrupt))
void
f (struct interrupt_frame *frame, uword_t error_code)
{
...
}
and compiler pops the error code off stack before the 'IRET' instruction.
The exception handler should only be used for exceptions which push an
error code and all other exceptions must use the interrupt handler.
The system will crash if the wrong handler is used.
To be feature complete, compiler may implement the optional
'no_caller_saved_registers' attribute:
Use this attribute to indicate that the specified function has no
caller-saved registers. That is, all registers are callee-saved.
The compiler generates proper function entry and exit sequences to
save and restore any modified registers.
The user can call functions specified with 'no_caller_saved_registers'
attribute from an interrupt handler without saving and restoring all
call clobbered registers.
On x86, interrupt handlers are only called by processors which push
interrupt data onto stack at the address where the normal return address
is. Interrupt handlers must access interrupt data via pointers so that
they can update interrupt data.
gcc/
PR target/66960
PR target/67630
PR target/67634
PR target/68037
* config/i386/i386-protos.h (ix86_epilogue_uses): New prototype.
* config/i386/i386.c (ix86_frame): Add nbndregs, nmaskregs,
bnd_reg_save_offset and mask_reg_save_offset.
(ix86_conditional_register_usage): Preserve all registers,
except for function return registers if there are no caller-saved
registers.
(ix86_set_current_function): Set no_caller_saved_registers and
func_type. Sorry if non-DWARF debug format is used. Call
reinit_regs if AX register usage isn't consistent.
(ix86_function_ok_for_sibcall): Return false if there are no
caller-saved registers.
(type_natural_mode): Don't warn ABI change for MMX in interrupt
handler.
(ix86_function_arg_advance): Skip for callee in interrupt
handler.
(ix86_function_arg): Return special arguments in interrupt
handler.
(ix86_promote_function_mode): Promote pointer to word_mode only
for normal functions.
(ix86_can_use_return_insn_p): Don't use `ret' instruction in
interrupt handler.
(ix86_epilogue_uses): New function.
(ix86_reg_ever_defined_p): Likewise.
(ix86_hard_regno_scratch_ok): Likewise.
(ix86_nsaved_bndregs): Likewise.
(ix86_nsaved_maskregs): Likewise.
(ix86_emit_save_bnd_regs_using_mov): Likewise.
(ix86_emit_save_mask_regs_using_mov): Likewise.
(ix86_emit_restore_bnd_regs_using_mov): Likewise.
(ix86_emit_restore_mask_regs_using_mov): Likewise.
(ix86_handle_no_caller_saved_registers_attribute): Likewise.
(ix86_handle_interrupt_attribute): Likewise.
(ix86_save_reg): Preserve all registers in interrupt function
after reload. Preserve all registers, except for function
return registers, if there are no caller-saved registers after
reload.
(ix86_nsaved_sseregs): Don't return 0 if there are no
caller-saved registers.
(ix86_compute_frame_layout): Set nbndregs and nmaskregs. Set
and allocate BND and MASK register save areas. Allocate space to
save full vector registers if there are no caller-saved registers.
(ix86_emit_save_reg_using_mov): Don't use UNSPEC_STOREU to
SSE registers.
(ix86_emit_save_sse_regs_using_mov): Save full vector registers
if there are no caller-saved registers.
(find_drap_reg): Always use callee-saved register if there are
no caller-saved registers.
(ix86_minimum_incoming_stack_boundary): Return MIN_STACK_BOUNDARY
for interrupt handler.
(ix86_expand_prologue): Save BND and MASK registers.
(ix86_emit_restore_sse_regs_using_mov): Restore full vector
registers if there are no caller-saved registers.
(ix86_expand_epilogue): Restore BND and MASK registers. Generate
interrupt return for interrupt handler and pop the 'ERROR_CODE'
off the stack before interrupt return in exception handler.
(ix86_expand_move): Disallow 80387 instructions in exception
handler. Force PLUS source operand in store operation into a
register.
(ix86_expand_vector_move): Disallow MMX/3Dnow instructions in
exception handler.
(ix86_expand_call): Disallow calling interrupt handler directly.
If there are no caller-saved registers, mark all registers that
are clobbered by the call as clobbered.
(ix86_attribute_table): Add interrupt and no_caller_saved_registers
attributes.
(TARGET_HARD_REGNO_SCRATCH_OK): Likewise.
* config/i386/i386.h (ACCUMULATE_OUTGOING_ARGS): Use argument
accumulation in interrupt function if stack may be realigned to
avoid DRAP.
(EPILOGUE_USES): New.
(function_type): New enum.
(machine_function): Add func_type and no_caller_saved_registers.
* config/i386/i386.md (UNSPEC_INTERRUPT_RETURN): New.
(interrupt_return): New pattern.
* doc/extend.texi: Document x86 interrupt and
no_caller_saved_registers attributes.
gcc/testsuite/
PR target/66960
PR target/67630
PR target/67634
PR target/68037
* gcc.dg/guality/pr68037-1.c: New test.
* gcc.dg/guality/pr68037-2.c: Likewise.
* gcc.dg/guality/pr68037-3.c: Likewise.
* gcc.dg/torture/pr68037-1.c: Likewise.
* gcc.dg/torture/pr68037-2.c: Likewise.
* gcc.dg/torture/pr68037-3.c: Likewise.
* gcc.target/i386/interrupt-1.c: Likewise.
* gcc.target/i386/interrupt-2.c: Likewise.
* gcc.target/i386/interrupt-3.c: Likewise.
* gcc.target/i386/interrupt-4.c: Likewise.
* gcc.target/i386/interrupt-5.c: Likewise.
* gcc.target/i386/interrupt-6.c: Likewise.
* gcc.target/i386/interrupt-7.c: Likewise.
* gcc.target/i386/interrupt-8.c: Likewise.
* gcc.target/i386/interrupt-9.c: Likewise.
* gcc.target/i386/interrupt-10.c: Likewise.
* gcc.target/i386/interrupt-11.c: Likewise.
* gcc.target/i386/interrupt-12.c: Likewise.
* gcc.target/i386/interrupt-13.c: Likewise.
* gcc.target/i386/interrupt-14.c: Likewise.
* gcc.target/i386/interrupt-15.c: Likewise.
* gcc.target/i386/interrupt-16.c: Likewise.
* gcc.target/i386/interrupt-17.c: Likewise.
* gcc.target/i386/interrupt-18.c: Likewise.
* gcc.target/i386/interrupt-19.c: Likewise.
* gcc.target/i386/interrupt-20.c: Likewise.
* gcc.target/i386/interrupt-21.c: Likewise.
* gcc.target/i386/interrupt-22.c: Likewise.
* gcc.target/i386/interrupt-23.c: Likewise.
* gcc.target/i386/interrupt-24.c: Likewise.
* gcc.target/i386/interrupt-25.c: Likewise.
* gcc.target/i386/interrupt-26.c: Likewise.
* gcc.target/i386/interrupt-387-err.c: Likewise.
* gcc.target/i386/interrupt-bnd.c: Likewise.
* gcc.target/i386/interrupt-iamcu.c: Likewise.
* gcc.target/i386/interrupt-mmx-err.c: Likewise.
* gcc.target/i386/interrupt-redzone-1.c: Likewise.
* gcc.target/i386/interrupt-redzone-2.c: Likewise.
* gcc.target/i386/interrupt-sibcall.c: Likewise.
* gcc.target/i386/interrupt-switch-abi.c: Likewise.
* gcc.target/i386/interrupt-xmm.c: Likewise.
* gcc.target/i386/interrupt-ymm.c: Likewise.
* gcc.target/i386/interrupt-zmm.c: Likewise.
Diffstat (limited to 'gcc/testsuite')
45 files changed, 1326 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.dg/guality/pr68037-1.c b/gcc/testsuite/gcc.dg/guality/pr68037-1.c new file mode 100644 index 00000000000..ac3431ce22c --- /dev/null +++ b/gcc/testsuite/gcc.dg/guality/pr68037-1.c @@ -0,0 +1,65 @@ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-g" } */ + +extern void exit (int); + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); + +#define ERROR 0x12345670 +#define IP 0x12345671 +#define CS 0x12345672 +#define FLAGS 0x12345673 +#define SP 0x12345674 +#define SS 0x12345675 + +#define STRING(x) XSTRING(x) +#define XSTRING(x) #x + +struct interrupt_frame +{ + uword_t ip; + uword_t cs; + uword_t flags; + uword_t sp; + uword_t ss; +}; + +__attribute__((interrupt, used)) +void +fn (struct interrupt_frame *frame, uword_t error) +{ + if (ERROR != error) /* BREAK */ + __builtin_abort (); + if (IP != frame->ip) + __builtin_abort (); + if (CS != frame->cs) + __builtin_abort (); + if (FLAGS != frame->flags) + __builtin_abort (); + if (SP != frame->sp) + __builtin_abort (); + if (SS != frame->ss) + __builtin_abort (); + + exit (0); +} + +int +main () +{ + asm ("push $" STRING (SS) "; \ + push $" STRING (SP) "; \ + push $" STRING (FLAGS) "; \ + push $" STRING (CS) "; \ + push $" STRING (IP) "; \ + push $" STRING (ERROR) "; \ + jmp fn"); + return 0; +} + +/* { dg-final { gdb-test 31 "error" "0x12345670" } } */ +/* { dg-final { gdb-test 31 "frame->ip" "0x12345671" } } */ +/* { dg-final { gdb-test 31 "frame->cs" "0x12345672" } } */ +/* { dg-final { gdb-test 31 "frame->flags" "0x12345673" } } */ +/* { dg-final { gdb-test 31 "frame->sp" "0x12345674" } } */ +/* { dg-final { gdb-test 31 "frame->ss" "0x12345675" } } */ diff --git a/gcc/testsuite/gcc.dg/guality/pr68037-2.c b/gcc/testsuite/gcc.dg/guality/pr68037-2.c new file mode 100644 index 00000000000..2010384935d --- /dev/null +++ b/gcc/testsuite/gcc.dg/guality/pr68037-2.c @@ -0,0 +1,60 @@ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-g" } */ + +extern void exit (int); + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); + +#define IP 0x12345671 +#define CS 0x12345672 +#define FLAGS 0x12345673 +#define SP 0x12345674 +#define SS 0x12345675 + +#define STRING(x) XSTRING(x) +#define XSTRING(x) #x + +struct interrupt_frame +{ + uword_t ip; + uword_t cs; + uword_t flags; + uword_t sp; + uword_t ss; +}; + +__attribute__((interrupt, used)) +void +fn (struct interrupt_frame *frame) +{ + if (IP != frame->ip) /* BREAK */ + __builtin_abort (); + if (CS != frame->cs) + __builtin_abort (); + if (FLAGS != frame->flags) + __builtin_abort (); + if (SP != frame->sp) + __builtin_abort (); + if (SS != frame->ss) + __builtin_abort (); + + exit (0); +} + +int +main () +{ + asm ("push $" STRING (SS) "; \ + push $" STRING (SP) "; \ + push $" STRING (FLAGS) "; \ + push $" STRING (CS) "; \ + push $" STRING (IP) "; \ + jmp fn"); + return 0; +} + +/* { dg-final { gdb-test 30 "frame->ip" "0x12345671" } } */ +/* { dg-final { gdb-test 30 "frame->cs" "0x12345672" } } */ +/* { dg-final { gdb-test 30 "frame->flags" "0x12345673" } } */ +/* { dg-final { gdb-test 30 "frame->sp" "0x12345674" } } */ +/* { dg-final { gdb-test 30 "frame->ss" "0x12345675" } } */ diff --git a/gcc/testsuite/gcc.dg/guality/pr68037-3.c b/gcc/testsuite/gcc.dg/guality/pr68037-3.c new file mode 100644 index 00000000000..10854f5f42c --- /dev/null +++ b/gcc/testsuite/gcc.dg/guality/pr68037-3.c @@ -0,0 +1,76 @@ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-g" } */ + +#include <stddef.h> + +extern void exit (int); + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); +typedef int aligned __attribute__((aligned(64))); + +#define IP 0x12345671 +#define CS 0x12345672 +#define FLAGS 0x12345673 +#define SP 0x12345674 +#define SS 0x12345675 + +#define STRING(x) XSTRING(x) +#define XSTRING(x) #x + +struct interrupt_frame +{ + uword_t ip; + uword_t cs; + uword_t flags; + uword_t sp; + uword_t ss; +}; + +int +check_int (int *i, int align) +{ + *i = 20; + if ((((ptrdiff_t) i) & (align - 1)) != 0) + __builtin_abort (); + return *i; +} + +__attribute__((interrupt, used)) +void +fn (struct interrupt_frame *frame) +{ + aligned i; + if (check_int (&i, __alignof__(i)) != i) + __builtin_abort (); + + if (IP != frame->ip) /* BREAK */ + __builtin_abort (); + if (CS != frame->cs) + __builtin_abort (); + if (FLAGS != frame->flags) + __builtin_abort (); + if (SP != frame->sp) + __builtin_abort (); + if (SS != frame->ss) + __builtin_abort (); + + exit (0); +} + +int +main () +{ + asm ("push $" STRING (SS) "; \ + push $" STRING (SP) "; \ + push $" STRING (FLAGS) "; \ + push $" STRING (CS) "; \ + push $" STRING (IP) "; \ + jmp fn"); + return 0; +} + +/* { dg-final { gdb-test 46 "frame->ip" "0x12345671" } } */ +/* { dg-final { gdb-test 46 "frame->cs" "0x12345672" } } */ +/* { dg-final { gdb-test 46 "frame->flags" "0x12345673" } } */ +/* { dg-final { gdb-test 46 "frame->sp" "0x12345674" } } */ +/* { dg-final { gdb-test 46 "frame->ss" "0x12345675" } } */ diff --git a/gcc/testsuite/gcc.dg/torture/pr68037-1.c b/gcc/testsuite/gcc.dg/torture/pr68037-1.c new file mode 100644 index 00000000000..0730c410f92 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr68037-1.c @@ -0,0 +1,57 @@ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ + +extern void exit (int); + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); + +#define ERROR 0x12345670 +#define IP 0x12345671 +#define CS 0x12345672 +#define FLAGS 0x12345673 +#define SP 0x12345674 +#define SS 0x12345675 + +#define STRING(x) XSTRING(x) +#define XSTRING(x) #x + +struct interrupt_frame +{ + uword_t ip; + uword_t cs; + uword_t flags; + uword_t sp; + uword_t ss; +}; + +__attribute__((interrupt, used)) +void +fn (struct interrupt_frame *frame, uword_t error) +{ + if (ERROR != error) + __builtin_abort (); + if (IP != frame->ip) + __builtin_abort (); + if (CS != frame->cs) + __builtin_abort (); + if (FLAGS != frame->flags) + __builtin_abort (); + if (SP != frame->sp) + __builtin_abort (); + if (SS != frame->ss) + __builtin_abort (); + + exit (0); +} + +int +main () +{ + asm ("push $" STRING (SS) "; \ + push $" STRING (SP) "; \ + push $" STRING (FLAGS) "; \ + push $" STRING (CS) "; \ + push $" STRING (IP) "; \ + push $" STRING (ERROR) "; \ + jmp fn"); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr68037-2.c b/gcc/testsuite/gcc.dg/torture/pr68037-2.c new file mode 100644 index 00000000000..197e8a4893f --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr68037-2.c @@ -0,0 +1,53 @@ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ + +extern void exit (int); + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); + +#define IP 0x12345671 +#define CS 0x12345672 +#define FLAGS 0x12345673 +#define SP 0x12345674 +#define SS 0x12345675 + +#define STRING(x) XSTRING(x) +#define XSTRING(x) #x + +struct interrupt_frame +{ + uword_t ip; + uword_t cs; + uword_t flags; + uword_t sp; + uword_t ss; +}; + +__attribute__((interrupt, used)) +void +fn (struct interrupt_frame *frame) +{ + if (IP != frame->ip) + __builtin_abort (); + if (CS != frame->cs) + __builtin_abort (); + if (FLAGS != frame->flags) + __builtin_abort (); + if (SP != frame->sp) + __builtin_abort (); + if (SS != frame->ss) + __builtin_abort (); + + exit (0); +} + +int +main () +{ + asm ("push $" STRING (SS) "; \ + push $" STRING (SP) "; \ + push $" STRING (FLAGS) "; \ + push $" STRING (CS) "; \ + push $" STRING (IP) "; \ + jmp fn"); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr68037-3.c b/gcc/testsuite/gcc.dg/torture/pr68037-3.c new file mode 100644 index 00000000000..6bcc317abe8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr68037-3.c @@ -0,0 +1,69 @@ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ + +#include <stddef.h> + +extern void exit (int); + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); +typedef int aligned __attribute__((aligned(64))); + +#define IP 0x12345671 +#define CS 0x12345672 +#define FLAGS 0x12345673 +#define SP 0x12345674 +#define SS 0x12345675 + +#define STRING(x) XSTRING(x) +#define XSTRING(x) #x + +struct interrupt_frame +{ + uword_t ip; + uword_t cs; + uword_t flags; + uword_t sp; + uword_t ss; +}; + +int +check_int (int *i, int align) +{ + *i = 20; + if ((((ptrdiff_t) i) & (align - 1)) != 0) + __builtin_abort (); + return *i; +} + +__attribute__((interrupt, used)) +void +fn (struct interrupt_frame *frame) +{ + aligned i; + if (check_int (&i, __alignof__(i)) != i) + __builtin_abort (); + + if (IP != frame->ip) + __builtin_abort (); + if (CS != frame->cs) + __builtin_abort (); + if (FLAGS != frame->flags) + __builtin_abort (); + if (SP != frame->sp) + __builtin_abort (); + if (SS != frame->ss) + __builtin_abort (); + + exit (0); +} + +int +main () +{ + asm ("push $" STRING (SS) "; \ + push $" STRING (SP) "; \ + push $" STRING (FLAGS) "; \ + push $" STRING (CS) "; \ + push $" STRING (IP) "; \ + jmp fn"); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/interrupt-1.c b/gcc/testsuite/gcc.target/i386/interrupt-1.c new file mode 100644 index 00000000000..70b8f3f147b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-1.c @@ -0,0 +1,53 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-push-args -maccumulate-outgoing-args" } */ + +extern void foo (void *) __attribute__ ((interrupt)); +extern int bar (int); + +void foo (void *frame) +{ + int a,b,c,d,e,f,i; + a = bar (5); + b = bar (a); + c = bar (b); + d = bar (c); + e = bar (d); + f = bar (e); + for (i = 1; i < 10; i++) + { + a += bar (a + i) + bar (b + i) + + bar (c + i) + bar (d + i) + + bar (e + i) + bar (f + i); + } +} +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)ax" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)bx" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)cx" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)dx" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)si" 1 } } */ +/* { dg-final { scan-assembler-times "pushl\[\\t \]*%edi" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r8" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r9" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r10" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r11" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r12" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r13" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r14" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r15" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)ax" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bx" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)cx" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)dx" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)si" 1 } } */ +/* { dg-final { scan-assembler-times "popl\[\\t \]*%edi" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r8" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r9" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r10" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r11" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r12" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r13" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r14" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r15" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "iret" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-10.c b/gcc/testsuite/gcc.target/i386/interrupt-10.c new file mode 100644 index 00000000000..64e621cd3f6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-10.c @@ -0,0 +1,24 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mavx512bw -mno-iamcu -maccumulate-outgoing-args" } */ + +extern void bar (void); + +struct interrupt_frame; + +void + __attribute__ ((interrupt)) +foo (struct interrupt_frame *frame) +{ + bar (); +} + +/* { dg-final { scan-assembler-times "movups\[\\t \]*%zmm\[0-9\]+,\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\)" 32 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\),\[\\t \]*%zmm\[0-9\]+" 32 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*%zmm\[0-9\]+,\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\)" 8 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\),\[\\t \]*%zmm\[0-9\]+" 8 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "kmovq\[\\t \]*%k\[0-7\]+,\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\)" 8 } } */ +/* { dg-final { scan-assembler-times "kmovq\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\),\[\\t \]*%k\[0-7\]+" 8 } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%rbx" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r1\[2-5\]+" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushl\[\\t \]*%ebx" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "pushl\[\\t \]*%e(s|d)i" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-11.c b/gcc/testsuite/gcc.target/i386/interrupt-11.c new file mode 100644 index 00000000000..ba4701995e9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-11.c @@ -0,0 +1,37 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-sse -mno-iamcu -maccumulate-outgoing-args" } */ + +extern void bar (void); + +void + __attribute__ ((interrupt)) +foo (void *frame) +{ + bar (); +} + +/* { dg-final { scan-assembler-not "movups\[\\t .\]*%(x|y|z)mm\[0-9\]+" } } */ +/* { dg-final { scan-assembler-not "kmov.\[\\t \]*%k\[0-7\]+,\[\\t \]*\[\\-]?\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "kmov.\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%k\[0-7\]+" } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%rbx" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r1\[2-5\]+" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushl\[\\t \]*%ebx" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "pushl\[\\t \]*%e(s|d)i" { target ia32 } } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)ax" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)cx" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)dx" 1 } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%rsi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r8" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r9" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r10" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r11" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)ax" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)cx" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)dx" 1 } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%rsi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r8" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r9" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r10" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r11" 1 { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-12.c b/gcc/testsuite/gcc.target/i386/interrupt-12.c new file mode 100644 index 00000000000..5c9eb74e93f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-12.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +extern int check_int (int *i, void *, int align); +typedef int aligned __attribute__((aligned(64))); +typedef unsigned int uword_t __attribute__ ((mode (__word__))); + +__attribute__((interrupt)) +void +foo (void *frame, uword_t error_code) +{ + aligned j; + if (check_int (frame, &j, __alignof__(j))) + __builtin_abort (); +} + +/* { dg-final { scan-assembler-times "and\[lq\]?\[^\\n\]*-64,\[^\\n\]*sp" 1 } } */ +/* { dg-final { scan-assembler-times "add(?:l|q)\[\\t \]*\\\$8,\[\\t \]*%\[re\]?sp" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "addl\[\\t \]*\\\$4,\[\\t \]*%esp" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler "iret" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-13.c b/gcc/testsuite/gcc.target/i386/interrupt-13.c new file mode 100644 index 00000000000..8cf0b25f5a2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-13.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +extern int check_int (int *i, void *, int align); +typedef int aligned __attribute__((aligned(64))); + +__attribute__((interrupt)) +void +foo (void *frame) +{ + aligned j; + if (check_int (frame, &j, __alignof__(j))) + __builtin_abort (); +} + +/* { dg-final { scan-assembler-times "and\[lq\]?\[^\\n\]*-64,\[^\\n\]*sp" 1 } } */ +/* { dg-final { scan-assembler "iret" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-14.c b/gcc/testsuite/gcc.target/i386/interrupt-14.c new file mode 100644 index 00000000000..751c3283c89 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-14.c @@ -0,0 +1,39 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-sse -mno-iamcu -mno-sse4 -mno-popcnt -maccumulate-outgoing-args" } */ + +extern int i, cnt; + +void + __attribute__ ((interrupt)) +foo (void *frame) +{ + cnt = __builtin_popcount (i); +} + +/* { dg-final { scan-assembler-not "movups\[\\t .\]*%(x|y|z)mm\[0-9\]+" } } */ +/* { dg-final { scan-assembler-not "kmov.\[\\t \]*%k\[0-7\]+,\[\\t \]*\[\\-]?\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "kmov.\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%k\[0-7\]+" } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%rbx" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r1\[2-5\]+" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushl\[\\t \]*%ebx" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "pushl\[\\t \]*%edi" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "pushl\[\\t \]*%esi" { target ia32 } } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)ax" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)cx" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)dx" 1 } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%rsi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r8" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r9" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r10" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r11" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)ax" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)cx" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)dx" 1 } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%rsi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r8" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r9" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r10" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r11" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "iret" 1 } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-15.c b/gcc/testsuite/gcc.target/i386/interrupt-15.c new file mode 100644 index 00000000000..16d82c2cebb --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-15.c @@ -0,0 +1,28 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-avx512f -mno-iamcu -mavx -mpush-args -maccumulate-outgoing-args" } */ + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); +extern void bar (int) __attribute__ ((no_caller_saved_registers)); + +void + __attribute__ ((interrupt)) +fn1 (void *frame, uword_t error) +{ + bar (error); +} + +/* { dg-final { scan-assembler-not "movups\[\\t .\]*%(x|y|z)mm\[0-9\]+" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(b|c|d)x" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)si" } } */ +/* { dg-final { scan-assembler-not "(push|pop)l\[\\t \]*%edi" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%rax" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%r\[0-9\]+" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:r|e)bp" 1 } } */ +/* { dg-final { scan-assembler-times "leave" 1 } } */ +/* { dg-final { scan-assembler-times "pushl\[\\t \]*%eax" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "movl\[\\t \]*-4\\(%ebp\\),\[\\t \]*%eax" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "movq\[\\t \]*-8\\(%(?:r|e)bp\\),\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "addl\[\\t \]*\\\$4,\[\\t \]*%esp" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "add(?:l|q)\[\\t \]*\\\$8,\[\\t \]*%\[re\]?sp" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "iret" 1 } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-16.c b/gcc/testsuite/gcc.target/i386/interrupt-16.c new file mode 100644 index 00000000000..f20f117a569 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-16.c @@ -0,0 +1,28 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-avx512f -mno-iamcu -mavx -mno-push-args -maccumulate-outgoing-args" } */ + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); +extern void bar (int) __attribute__ ((no_caller_saved_registers)); + +void + __attribute__ ((interrupt)) +fn1 (void *frame, uword_t error) +{ + bar (error); +} + +/* { dg-final { scan-assembler-not "movups\[\\t .\]*%(x|y|z)mm\[0-9\]+" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(b|c|d)x" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)si" } } */ +/* { dg-final { scan-assembler-not "(push|pop)l\[\\t \]*%edi" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%rax" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%r\[0-9\]+" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:r|e)bp" 1 } } */ +/* { dg-final { scan-assembler-times "leave" 1 } } */ +/* { dg-final { scan-assembler-times "pushl\[\\t \]*%eax" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "movl\[\\t \]*-4\\(%ebp\\),\[\\t \]*%eax" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "movq\[\\t \]*-8\\(%(?:r|e)bp\\),\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "addl\[\\t \]*\\\$4,\[\\t \]*%esp" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "add(?:l|q)\[\\t \]*\\\$8,\[\\t \]*%\[re\]?sp" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "iret" 1 } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-17.c b/gcc/testsuite/gcc.target/i386/interrupt-17.c new file mode 100644 index 00000000000..4bad7dcc05b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-17.c @@ -0,0 +1,30 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-avx512f -mno-iamcu -mavx -mpush-args -mno-accumulate-outgoing-args" } */ + +extern void bar (int) __attribute__ ((no_caller_saved_registers)); + +void + __attribute__ ((interrupt)) +fn1 (void *frame) +{ + bar (3); +} + +void + __attribute__ ((interrupt)) +fn2 (void *frame) +{ + bar (3); +} + +/* { dg-final { scan-assembler-not "movups\[\\t .\]*%(x|y|z)mm\[0-9\]+" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(a|b|c|d)x" } } */ +/* { dg-final { scan-assembler-not "(push|pop)l\[\\t \]*%edi" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)si" } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%r\[8-9\]+" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%r1\[0-5\]+" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:r|e)bp" 2 } } */ +/* { dg-final { scan-assembler-times "leave" 2 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%rdi" 2 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "movq\[\\t \]*-8\\(%(?:r|e)bp\\),\[\\t \]*%rdi" 2 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "iret" 2 } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-18.c b/gcc/testsuite/gcc.target/i386/interrupt-18.c new file mode 100644 index 00000000000..af3285164f2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-18.c @@ -0,0 +1,35 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-avx512f -mno-iamcu -mavx -mpush-args -maccumulate-outgoing-args" } */ + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); +extern void bar (int) __attribute__ ((no_caller_saved_registers)); + +void + __attribute__ ((interrupt)) +fn1 (void *frame, uword_t error) +{ + bar (error); +} + +void + __attribute__ ((interrupt)) +fn2 (void *frame, uword_t error) +{ + bar (error); +} + +/* { dg-final { scan-assembler-not "movups\[\\t .\]*%(x|y|z)mm\[0-9\]+" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(b|c|d)x" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)si" } } */ +/* { dg-final { scan-assembler-not "(push|pop)l\[\\t \]*%edi" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%rax" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%r\[0-9\]+" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:r|e)bp" 2 } } */ +/* { dg-final { scan-assembler-times "leave" 2 } } */ +/* { dg-final { scan-assembler-times "pushl\[\\t \]*%eax" 2 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "movl\[\\t \]*-4\\(%ebp\\),\[\\t \]*%eax" 2 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%rdi" 2 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "movq\[\\t \]*-8\\(%(?:r|e)bp\\),\[\\t \]*%rdi" 2 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "addl\[\\t \]*\\\$4,\[\\t \]*%esp" 2 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "add(?:l|q)\[\\t \]*\\\$8,\[\\t \]*%\[re\]?sp" 2 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "iret" 2 } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-19.c b/gcc/testsuite/gcc.target/i386/interrupt-19.c new file mode 100644 index 00000000000..e1aaaec4cf9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-19.c @@ -0,0 +1,21 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-avx512f -mno-iamcu -mavx -mno-push-args -maccumulate-outgoing-args" } */ + +extern int foo (int) __attribute__ ((no_caller_saved_registers)); +extern int bar (int) __attribute__ ((no_caller_saved_registers)); + +int +foo (int i) +{ + return bar (i); +} + +/* { dg-final { scan-assembler-not "movups\[\\t \]*%(x|y|z)mm\[0-9\]+,\[\\t \]-*\[0-9\]*\\(%\[re\]?bp\\)" } } */ +/* { dg-final { scan-assembler-not "movups\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\),\[\\t \]*%(x|y|z)mm\[0-9\]+" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(a|b|c|d)x" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)si" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)bp" } } */ +/* { dg-final { scan-assembler-not "(push|pop)l\[\\t \]*%edi" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%r\[0-9\]+" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-2.c b/gcc/testsuite/gcc.target/i386/interrupt-2.c new file mode 100644 index 00000000000..27b40b09e05 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-2.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -Wall -g" } */ + +void +__attribute__((interrupt)) +fn (void *frame) +{ +} + +/* { dg-final { scan-assembler-not "add(l|q)\[\\t \]*\\$\[0-9\]*,\[\\t \]*%\[re\]?sp" } } */ +/* { dg-final { scan-assembler "iret" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-20.c b/gcc/testsuite/gcc.target/i386/interrupt-20.c new file mode 100644 index 00000000000..2a2210dc976 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-20.c @@ -0,0 +1,23 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-avx512f -mno-iamcu -mavx -mno-push-args" } */ + +extern int foo (int) __attribute__ ((no_caller_saved_registers)); +extern int bar (int) __attribute__ ((no_caller_saved_registers)); + +int +foo (int i) +{ + return bar (i + 1); +} + +/* { dg-final { scan-assembler-not "movups\[\\t \]*%(x|y|z)mm\[0-9\]+,\[\\t \]-*\[0-9\]*\\(%\[re\]?bp\\)" } } */ +/* { dg-final { scan-assembler-not "movups\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\),\[\\t \]*%(x|y|z)mm\[0-9\]+" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(a|b|c|d)x" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)si" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)bp" } } */ +/* { dg-final { scan-assembler-not "(push|pop)l\[\\t \]*%edi" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%rdx" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%r\[0-9\]+" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%rdi" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "jmp" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-21.c b/gcc/testsuite/gcc.target/i386/interrupt-21.c new file mode 100644 index 00000000000..7cc5181e21c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-21.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-avx -mno-iamcu -msse" } */ + +void +__attribute__((no_caller_saved_registers)) +fn (void) +{ + asm ("#" + : + : + : "xmm3"); +} + +/* { dg-final { scan-assembler-times "movaps\[\\t \]*%xmm3,\[\\t \]*-?\[0-9\]*\\(%\[re\]?sp\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movaps\[\\t \]*-?\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%xmm3" 1 } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*%(x|y|z)mm\[0-2\]+,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%(x|y|z)mm\[0-2\]+" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*%(x|y|z)mm\[4-9\]+,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%(x|y|z)mm\[4-9\]+" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*%(x|y|z)mm1\[0-9\]+,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%(x|y|z)mm1\[0-9\]+" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(a|b|c|d)x" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(s|d)i" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)bp" } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%r\[0-9\]+" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-22.c b/gcc/testsuite/gcc.target/i386/interrupt-22.c new file mode 100644 index 00000000000..5dd62906705 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-22.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-avx512f -mno-iamcu -mavx" } */ + +void +__attribute__((no_caller_saved_registers)) +fn (void) +{ + asm ("#" + : + : + : "xmm3"); +} + +/* { dg-final { scan-assembler-times "movups\[\\t \]*%ymm3,\[\\t \]*-?\[0-9\]*\\(%\[re\]?sp\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*-?\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%ymm3" 1 } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*%(x|y|z)mm\[0-2\]+,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%(x|y|z)mm\[0-2\]+" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*%(x|y|z)mm\[4-9\]+,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%(x|y|z)mm\[4-9\]+" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*%(x|y|z)mm1\[0-9\]+,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%(x|y|z)mm1\[0-9\]+" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(a|b|c|d)x" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(s|d)i" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)bp" } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%r\[0-9\]+" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-23.c b/gcc/testsuite/gcc.target/i386/interrupt-23.c new file mode 100644 index 00000000000..e0cf550bc83 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-23.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx512f -mno-iamcu" } */ + +void +__attribute__((no_caller_saved_registers)) +fn (void) +{ + asm ("#" + : + : + : "xmm3"); +} + +/* { dg-final { scan-assembler-times "movups\[\\t \]*%zmm3,\[\\t \]*-?\[0-9\]*\\(%\[re\]?sp\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*-?\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%zmm3" 1 } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*%(x|y|z)mm\[0-2\]+,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%(x|y|z)mm\[0-2\]+" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*%(x|y|z)mm\[4-9\]+,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%(x|y|z)mm\[4-9\]+" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*%(x|y|z)mm1\[0-9\]+,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%(x|y|z)mm1\[0-9\]+" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(a|b|c|d)x" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(s|d)i" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)bp" } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%r\[0-9\]+" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-24.c b/gcc/testsuite/gcc.target/i386/interrupt-24.c new file mode 100644 index 00000000000..9b92c005719 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-24.c @@ -0,0 +1,21 @@ +/* { dg-do compile { target { ! x32 } } } */ +/* { dg-options "-O2 -mno-iamcu -mmpx" } */ + +void +__attribute__((no_caller_saved_registers)) +fn (void) +{ + asm ("#" + : + : + : "bnd3"); +} + +/* { dg-final { scan-assembler-times "bndmov\[\\t \]*%bnd3,\[\\t \]*\[\\-\]?\[0-9\]*\\(%\[re\]?sp\\)" 1 } } */ +/* { dg-final { scan-assembler-times "bndmov\[\\t \]*\[\\-\]?\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%bnd3" 1 } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*%(x|y|z)mm\[0-9\]+,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%(x|y|z)mm\[0-9\]+" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(a|b|c|d)x" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)(s|d)i" } } */ +/* { dg-final { scan-assembler-not "(push|pop)(l|q)\[\\t \]*%(r|e)bp" } } */ +/* { dg-final { scan-assembler-not "(push|pop)q\[\\t \]*%r\[0-9\]+" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-25.c b/gcc/testsuite/gcc.target/i386/interrupt-25.c new file mode 100644 index 00000000000..849fd3aa96d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-25.c @@ -0,0 +1,24 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -mno-avx -mno-iamcu -msse -mincoming-stack-boundary=2" } */ + +void +__attribute__((no_caller_saved_registers)) +fn (void) +{ + asm ("#" + : + : + : "xmm3"); +} + +/* { dg-final { scan-assembler-times "movups\[\\t \]*%xmm3,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%xmm3" 1 } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*%(x|y|z)mm\[0-2\]+,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%(x|y|z)mm\[0-2\]+" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*%(x|y|z)mm\[4-9\]+,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%(x|y|z)mm\[4-9\]+" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*%(x|y|z)mm1\[0-9\]+,\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\)" } } */ +/* { dg-final { scan-assembler-not "mov(a|u)ps\[\\t \]*\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%(x|y|z)mm1\[0-9\]+" } } */ +/* { dg-final { scan-assembler-not "(push|pop)l\[\\t \]*%e(a|b|c|d)x" } } */ +/* { dg-final { scan-assembler-not "(push|pop)l\[\\t \]*%e(s|d)i" } } */ +/* { dg-final { scan-assembler-not "(push|pop)l\[\\t \]*%ebp" } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-26.c b/gcc/testsuite/gcc.target/i386/interrupt-26.c new file mode 100644 index 00000000000..27b40b09e05 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-26.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -Wall -g" } */ + +void +__attribute__((interrupt)) +fn (void *frame) +{ +} + +/* { dg-final { scan-assembler-not "add(l|q)\[\\t \]*\\$\[0-9\]*,\[\\t \]*%\[re\]?sp" } } */ +/* { dg-final { scan-assembler "iret" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-27.c b/gcc/testsuite/gcc.target/i386/interrupt-27.c new file mode 100644 index 00000000000..774bb4b1108 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-27.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -g -mno-avx -mno-iamcu -msse" } */ + +typedef float __v4sf __attribute__ ((__vector_size__ (16))); +__v4sf x, y; + +void +__attribute__((interrupt)) +fn (void *frame) +{ + x = y; +} + +/* { dg-final { scan-assembler-times "movups\[\\t \]*%xmm0,\[\\t \]*-?\[0-9\]*\\(%\[re\]?bp\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*-?\[0-9\]*\\(%\[re\]?bp\\),\[\\t \]*%xmm0" 1 } } */ +/* { dg-final { scan-assembler "iret" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-28.c b/gcc/testsuite/gcc.target/i386/interrupt-28.c new file mode 100644 index 00000000000..0768a46b2f0 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-28.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -mno-iamcu" } */ + +struct ret +{ + int i[8]; +}; + +extern struct ret bar (void); + +void + __attribute__ ((interrupt)) +fn (void *frame) +{ + bar (); +} /* { dg-message "sorry, unimplemented: Dynamic Realign Argument Pointer" } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-3.c b/gcc/testsuite/gcc.target/i386/interrupt-3.c new file mode 100644 index 00000000000..b09f56cd44b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-3.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -g" } */ + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); + +void +__attribute__((interrupt)) +fn (void* frame, uword_t error) +{ +} + +/* { dg-final { scan-assembler-times "add(?:l|q)\[\\t \]*\\\$8,\[\\t \]*%\[re\]?sp" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "addl\[\\t \]*\\\$4,\[\\t \]*%esp" 1 { target ia32 } } } */ +/* { dg-final { scan-assembler "iret" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-387-err.c b/gcc/testsuite/gcc.target/i386/interrupt-387-err.c new file mode 100644 index 00000000000..36094f20e16 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-387-err.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -m80387 -mlong-double-80 -mno-iamcu -mno-sse" } */ + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); + +extern long double y, x; + +void +fn0 (void) +{ + x = y; + y = 0; +} + +void +__attribute__((interrupt)) +fn1 (void *frame, uword_t error) +{ + x = 0; /* { dg-error "80387 instructions aren't allowed in exception service routine" } */ +} + +void +__attribute__((interrupt)) +fn2 (void *frame) +{ + x = y; /* { dg-error "80387 instructions aren't allowed in interrupt service routine" } */ +} diff --git a/gcc/testsuite/gcc.target/i386/interrupt-4.c b/gcc/testsuite/gcc.target/i386/interrupt-4.c new file mode 100644 index 00000000000..c34dbe0a21a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-4.c @@ -0,0 +1,32 @@ +/* { dg-do link } */ +/* { dg-options "-O -g" } */ + +#include <stdint.h> + +extern void link_error (void); + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); + +struct interrupt_frame +{ + uword_t ip; + uword_t cs; + uword_t flags; + uword_t sp; + uword_t ss; +}; + +__attribute__ ((used, interrupt)) +void +foo (struct interrupt_frame *frame) +{ + void *ra = __builtin_return_address (0); + if ((uintptr_t) ra != (uintptr_t) frame->ip) + link_error (); +} + +int +main (void) +{ + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/interrupt-5.c b/gcc/testsuite/gcc.target/i386/interrupt-5.c new file mode 100644 index 00000000000..3c4bc2da679 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-5.c @@ -0,0 +1,23 @@ +/* { dg-do link } */ +/* { dg-options "-O -g" } */ + +#include <stdint.h> + +extern void link_error (void); + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); + +__attribute__ ((used, interrupt)) +void +foo (void *frame, uword_t error) +{ + void *ra = __builtin_return_address (0); + if ((uintptr_t) ra != (uintptr_t) error) + link_error (); +} + +int +main (void) +{ + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/interrupt-6.c b/gcc/testsuite/gcc.target/i386/interrupt-6.c new file mode 100644 index 00000000000..a1a3d0e2355 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-6.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); + +extern int error; + +__attribute__((interrupt)) +void +fn1 (void *p, short error_code) +{ /* { dg-error "interrupt service routine should have unsigned \(long long |long |\)int as the second argument" } */ +} + +__attribute__((interrupt)) +void +fn2 (void) +{ /* { dg-error "interrupt service routine can only have a pointer argument and an optional integer argument" } */ +} + +__attribute__((interrupt)) +void +fn3 (uword_t error_code) +{ /* { dg-error "interrupt service routine should have a pointer as the first argument" } */ + error = error_code; +} + +__attribute__((interrupt)) +void +fn4 (uword_t error_code, void *frame) +{ /* { dg-error "interrupt service routine should have .* the .* argument" } */ + error = error_code; +} + +extern int fn5 (void *) __attribute__ ((interrupt)); /* { dg-error "interrupt service routine can't have non-void return value" } */ + +int +fn5 (void *frame) +{ + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/interrupt-7.c b/gcc/testsuite/gcc.target/i386/interrupt-7.c new file mode 100644 index 00000000000..e7441a25a58 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-7.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +extern int error; + +extern void fn (void *) __attribute__((interrupt)); + +void +foo (void) +{ + fn (&error); /* { dg-error "interrupt service routine can't be called directly" } */ +} diff --git a/gcc/testsuite/gcc.target/i386/interrupt-8.c b/gcc/testsuite/gcc.target/i386/interrupt-8.c new file mode 100644 index 00000000000..defec2e5542 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-8.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-avx512f -mno-iamcu -mavx -maccumulate-outgoing-args" } */ + +extern void bar (void); + +void + __attribute__ ((interrupt)) +foo (void *frame) +{ + bar (); +} + +/* { dg-final { scan-assembler-times "movups\[\\t \]*%ymm\[0-9\]+,\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\)" 16 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\),\[\\t \]*%ymm\[0-9\]+" 16 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*%ymm\[0-9\]+,\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\)" 8 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\),\[\\t \]*%ymm\[0-9\]+" 8 { target ia32 } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%rbx" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r1\[2-5\]+" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushl\[\\t \]*%ebx" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "pushl\[\\t \]*%e(s|d)i" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-9.c b/gcc/testsuite/gcc.target/i386/interrupt-9.c new file mode 100644 index 00000000000..56bd8dd2cba --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-9.c @@ -0,0 +1,22 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mno-avx512bw -mno-iamcu -mavx512f -maccumulate-outgoing-args" } */ + +extern void bar (void); + +void + __attribute__ ((interrupt)) +foo (void *frame) +{ + bar (); +} + +/* { dg-final { scan-assembler-times "movups\[\\t \]*%zmm\[0-9\]+,\[\\t \]-*\[0-9\]*\\(%\[re\]?bp\\)" 32 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\),\[\\t \]*%zmm\[0-9\]+" 32 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*%zmm\[0-9\]+,\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\)" 8 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\),\[\\t \]*%zmm\[0-9\]+" 8 { target ia32 } } } */ +/* { dg-final { scan-assembler-times "kmovw\[\\t \]*%k\[0-7\]+,\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\)" 8 } } */ +/* { dg-final { scan-assembler-times "kmovw\[\\t \]*-\[0-9\]*\\(%\[re\]?bp\\),\[\\t \]*%k\[0-7\]+" 8 } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%rbx" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r1\[2-5\]+" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushl\[\\t \]*%ebx" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "pushl\[\\t \]*%e(s|d)i" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-bnd.c b/gcc/testsuite/gcc.target/i386/interrupt-bnd.c new file mode 100644 index 00000000000..9f50661f05f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-bnd.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target { ! x32 } } } */ +/* { dg-options "-O2 -mno-iamcu -mmpx" } */ + +void +__attribute__((interrupt)) +fn (void *frame) +{ + asm ("#" + : + : + : "bnd3"); +} + +/* { dg-final { scan-assembler-times "bndmov\[\\t \]*%bnd3,\[\\t \]*\[\\-\]?\[0-9\]*\\(%\[re\]?sp\\)" 1 } } */ +/* { dg-final { scan-assembler-times "bndmov\[\\t \]*\[\\-\]?\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%bnd3" 1 } } */ +/* { dg-final { scan-assembler "iret" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-iamcu.c b/gcc/testsuite/gcc.target/i386/interrupt-iamcu.c new file mode 100644 index 00000000000..712b85f4105 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-iamcu.c @@ -0,0 +1,35 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -miamcu -maccumulate-outgoing-args" } */ + +extern void foo (void *) __attribute__ ((interrupt)); +extern int bar (int); + +void foo (void *frame) +{ + int a,b,c,d,e,f,i; + a = bar (5); + b = bar (a); + c = bar (b); + d = bar (c); + e = bar (d); + f = bar (e); + for (i = 1; i < 10; i++) + a += bar (a + i) + bar (b + i) + + bar (c + i) + bar (d + i) + + bar (e + i) + bar (f+i); +} + +/* { dg-final { scan-assembler-times "pushl\[\\t \]*%eax" 1 } } */ +/* { dg-final { scan-assembler-times "pushl\[\\t \]*%ebx" 1 } } */ +/* { dg-final { scan-assembler-times "pushl\[\\t \]*%ecx" 1 } } */ +/* { dg-final { scan-assembler-times "pushl\[\\t \]*%edx" 1 } } */ +/* { dg-final { scan-assembler-times "pushl\[\\t \]*%edi" 1 } } */ +/* { dg-final { scan-assembler-times "pushl\[\\t \]*%esi" 1 } } */ +/* { dg-final { scan-assembler-times "pushl\[\\t \]*%ebp" 1 } } */ +/* { dg-final { scan-assembler-times "popl\[\\t \]*%eax" 1 } } */ +/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */ +/* { dg-final { scan-assembler-times "popl\[\\t \]*%edx" 1 } } */ +/* { dg-final { scan-assembler-times "popl\[\\t \]*%edi" 1 } } */ +/* { dg-final { scan-assembler-times "popl\[\\t \]*%esi" 1 } } */ +/* { dg-final { scan-assembler-times "popl\[\\t \]*%ebp" 1 } } */ +/* { dg-final { scan-assembler "iret" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-mmx-err.c b/gcc/testsuite/gcc.target/i386/interrupt-mmx-err.c new file mode 100644 index 00000000000..fc4f3673406 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-mmx-err.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mmmx -mno-iamcu" } */ + +typedef unsigned int uword_t __attribute__ ((mode (__word__))); +typedef short __v4hi __attribute__ ((__vector_size__ (8))); +typedef int __m64 __attribute__ ((__vector_size__ (8), __may_alias__)); + +extern __m64 y, x; + +void +fn0 (void) +{ + x = __extension__ (__m64){ 0 }; + x = (__m64) __builtin_ia32_packsswb ((__v4hi) x, (__v4hi) y); + y = x; +} + +void +__attribute__((interrupt)) +fn1 (void *frame) +{ + x = (__m64) __builtin_ia32_packsswb ((__v4hi) x, (__v4hi) y); /* { dg-error "MMX/3Dnow (instructions|intrinsics) aren't allowed in interrupt service routine" } */ +} + +void +__attribute__((interrupt)) +fn2 (void *frame) +{ + x = y; /* { dg-error "MMX/3Dnow instructions aren't allowed in interrupt service routine" } */ +} + +void +__attribute__((interrupt)) +fn3 (void *frame, uword_t error) +{ + x = __extension__ (__m64){ 0 }; /* { dg-error "MMX/3Dnow instructions aren't allowed in exception service routine" } */ +} diff --git a/gcc/testsuite/gcc.target/i386/interrupt-redzone-1.c b/gcc/testsuite/gcc.target/i386/interrupt-redzone-1.c new file mode 100644 index 00000000000..78d3f27af42 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-redzone-1.c @@ -0,0 +1,31 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -mred-zone" } */ + +void +__attribute__((interrupt)) +fn (void *frame) +{ + /* No need to adjust stack if less than 128 bytes are used on stack + with a 128-byte red zone. */ + long long int i0; + long long int i1; + long long int i2; + long long int i3; + long long int i4; + long long int i5; + long long int i6; + long long int i7; + long long int i8; + long long int i9; + long long int i10; + long long int i11; + long long int i12; + long long int i13; + asm ("# %0, %1, %2, %3, %4, %5, %6, %7" + : "=m" (i0), "=m" (i1), "=m" (i2), "=m" (i3), + "=m" (i4), "=m" (i5), "=m" (i6), "=m" (i7), + "=m" (i8), "=m" (i9), "=m" (i10), "=m" (i11), + "=m" (i12), "=m" (i13)); +} + +/* { dg-final { scan-assembler-not "(sub|add)(l|q)\[\\t \]*\\$\[0-9\]*,\[\\t \]*%\[re\]?sp" } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-redzone-2.c b/gcc/testsuite/gcc.target/i386/interrupt-redzone-2.c new file mode 100644 index 00000000000..1ab7041a957 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-redzone-2.c @@ -0,0 +1,32 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -mred-zone" } */ + +void +__attribute__((interrupt)) +fn (void *frame) +{ + /* Need to adjust stack if more than 128 bytes are used on stack + with a 128-byte red zone. */ + long long int i0; + long long int i1; + long long int i2; + long long int i3; + long long int i4; + long long int i5; + long long int i6; + long long int i7; + long long int i8; + long long int i9; + long long int i10; + long long int i11; + long long int i12; + long long int i13; + char c; + asm ("# %0, %1, %2, %3, %4, %5, %6, %7" + : "=m" (i0), "=m" (i1), "=m" (i2), "=m" (i3), + "=m" (i4), "=m" (i5), "=m" (i6), "=m" (i7), + "=m" (i8), "=m" (i9), "=m" (i10), "=m" (i11), + "=m" (i12), "=m" (i13), "=m" (c)); +} + +/* { dg-final { scan-assembler-times "(?:sub|add)(?:l|q)\[\\t \]*\\\$\[0-9\]*,\[\\t \]*%\[re\]?sp" 2 } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-sibcall.c b/gcc/testsuite/gcc.target/i386/interrupt-sibcall.c new file mode 100644 index 00000000000..e222acf03dc --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-sibcall.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O3" } */ + +extern void foo (void *) __attribute__ ((interrupt)); +extern void bar (void); + +void foo (void *frame) +{ + bar (); +} +/* { dg-final { scan-assembler-not "jmp" } }*/ +/* { dg-final { scan-assembler "iret" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-switch-abi.c b/gcc/testsuite/gcc.target/i386/interrupt-switch-abi.c new file mode 100644 index 00000000000..b1b0abe57d2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-switch-abi.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +extern void bar (int); + +void f1 (void){ bar (1); } +__attribute__((interrupt)) +void f2 (void *frame){ bar (2); } +void f3 (void){ bar (3); } +__attribute__((interrupt)) +void f4 (void *frame){ bar (4); } +void f5 (void){ bar (5); } + +/* { dg-final { scan-assembler-times "push.\t%.ax" 2 } } */ +/* { dg-final { scan-assembler-times "pop.\t%.ax" 2 } } */ +/* { dg-final { scan-assembler-times "iret" 2 } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-xmm.c b/gcc/testsuite/gcc.target/i386/interrupt-xmm.c new file mode 100644 index 00000000000..6ffdd969a93 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-xmm.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-avx -mno-iamcu -msse" } */ + +void +__attribute__((interrupt)) +fn (void *frame) +{ + asm ("#" + : + : + : "xmm3"); +} + +/* { dg-final { scan-assembler-times "movups\[\\t \]*%xmm3,\[\\t \]*-?\[0-9\]*\\(%\[re\]?sp\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]*-?\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%xmm3" 1 } } */ +/* { dg-final { scan-assembler "iret" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-ymm.c b/gcc/testsuite/gcc.target/i386/interrupt-ymm.c new file mode 100644 index 00000000000..0754ae09a28 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-ymm.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-avx512f -mno-iamcu -mavx" } */ + +void +__attribute__((interrupt)) +fn (void *frame) +{ + asm ("#" + : + : + : "xmm3"); +} + +/* { dg-final { scan-assembler-times "vmovups\[\\t \]*%ymm3,\[\\t \]*-?\[0-9\]*\\(%\[re\]?sp\\)" 1 } } */ +/* { dg-final { scan-assembler-times "vmovups\[\\t \]*-?\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%ymm3" 1 } } */ +/* { dg-final { scan-assembler "iret" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-zmm.c b/gcc/testsuite/gcc.target/i386/interrupt-zmm.c new file mode 100644 index 00000000000..f4d2fa1bcce --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-zmm.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx512f -mno-iamcu" } */ + +void +__attribute__((interrupt)) +fn (void *frame) +{ + asm ("#" + : + : + : "xmm3"); +} + +/* { dg-final { scan-assembler-times "vmovups\[\\t \]*%zmm3,\[\\t \]*-?\[0-9\]*\\(%\[re\]?sp\\)" 1 } } */ +/* { dg-final { scan-assembler-times "vmovups\[\\t \]*-?\[0-9\]*\\(%\[re\]?sp\\),\[\\t \]*%zmm3" 1 } } */ +/* { dg-final { scan-assembler "iret" } }*/ |