diff options
author | Julia Koval <julia.koval@intel.com> | 2015-09-11 08:31:51 +0300 |
---|---|---|
committer | Julia Koval <julia.koval@intel.com> | 2015-09-11 17:43:24 +0300 |
commit | aaca35d5af5f5bab7b3d892739ab6d342e41389c (patch) | |
tree | 254af3ce8b56a07d06edf9047c17c87dc9d5ab8b | |
parent | 2100aaaa8173889930363cdc32275cb8a895d2a7 (diff) | |
download | gcc-aaca35d5af5f5bab7b3d892739ab6d342e41389c.tar.gz |
Interrupt
-rw-r--r-- | gcc/config/i386/i386-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 167 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 9 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/interrupt-args-err.c | 9 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/interrupt-iamcu.c | 33 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/interrupt-redzone.c | 10 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/interrupt-retval-err.c | 11 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/interrupt-sibcall.c | 12 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/interrupt-switch-abi.c | 13 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/interrupt.c | 32 |
10 files changed, 283 insertions, 15 deletions
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 6a17ef40a2e..cac267d9a9b 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -26,6 +26,8 @@ extern bool ix86_handle_option (struct gcc_options *opts, /* Functions in i386.c */ extern bool ix86_target_stack_probe (void); extern bool ix86_can_use_return_insn_p (void); +extern bool ix86_is_interrupt_p (void); +extern bool ix86_is_exception_p (void); extern void ix86_setup_frame_addresses (void); extern HOST_WIDE_INT ix86_initial_elimination_offset (int, int); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 7a97f3725d2..5c486f8b403 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -4503,16 +4503,6 @@ ix86_conditional_register_usage (void) { int i, c_mask; - /* For 32-bit targets, squash the REX registers. */ - if (! TARGET_64BIT) - { - for (i = FIRST_REX_INT_REG; i <= LAST_REX_INT_REG; i++) - fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = ""; - for (i = FIRST_REX_SSE_REG; i <= LAST_REX_SSE_REG; i++) - fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = ""; - for (i = FIRST_EXT_REX_SSE_REG; i <= LAST_EXT_REX_SSE_REG; i++) - fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = ""; - } /* See the definition of CALL_USED_REGISTERS in i386.h. */ c_mask = (TARGET_64BIT_MS_ABI ? (1 << 3) @@ -4535,6 +4525,39 @@ ix86_conditional_register_usage (void) SET_HARD_REG_BIT (reg_class_contents[(int)CLOBBERED_REGS], i); } + if (current_function_decl && ix86_is_interrupt_p ()) + { + for (i = AX_REG; i <= DI_REG; i++) + { + call_used_regs[i] = 0; + fixed_regs[i] = 0; + } + for (i = XMM0_REG; i <= XMM7_REG; i++) + { + call_used_regs[i] = 0; + fixed_regs[i] = 0; + } + for (i = R8_REG; i <FIRST_PSEUDO_REGISTER; i++) + { + call_used_regs[i] = 0; + fixed_regs[i] = 0; + } + } + + + /* For 32-bit targets, squash the REX registers. */ + if (! TARGET_64BIT) + { + for (i = FIRST_REX_INT_REG; i <= LAST_REX_INT_REG; i++) + fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = ""; + for (i = FIRST_REX_SSE_REG; i <= LAST_REX_SSE_REG; i++) + fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = ""; + for (i = FIRST_EXT_REX_SSE_REG; i <= LAST_EXT_REX_SSE_REG; i++) + fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = ""; + } + + + /* If MMX is disabled, squash the registers. */ if (! TARGET_MMX) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) @@ -5562,6 +5585,10 @@ ix86_function_ok_for_sibcall (tree decl, tree exp) tree type, decl_or_type; rtx a, b; + if (ix86_is_interrupt_p ()) + return false; + + /* If we are generating position-independent code, we cannot sibcall optimize direct calls to global functions, as the PLT requires %ebx be live. (Darwin does not have a PLT.) */ @@ -6440,8 +6467,10 @@ ix86_call_abi_override (const_tree fndecl) static void ix86_maybe_switch_abi (void) { - if (TARGET_64BIT && - call_used_regs[SI_REG] == (cfun->machine->call_abi == MS_ABI)) + if (call_used_regs[AX_REG] == ix86_is_interrupt_p ()) + reinit_regs (); + else if ((TARGET_64BIT && + call_used_regs[SI_REG] == (cfun->machine->call_abi == MS_ABI))) reinit_regs (); } @@ -10135,7 +10164,7 @@ ix86_nsaved_sseregs (void) int nregs = 0; int regno; - if (!TARGET_64BIT_MS_ABI) + if (!TARGET_64BIT_MS_ABI && !ix86_is_interrupt_p ()) return 0; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (SSE_REGNO_P (regno) && ix86_save_reg (regno, true)) @@ -11466,6 +11495,14 @@ ix86_expand_prologue (void) /* DRAP should not coexist with stack_realign_fp */ gcc_assert (!(crtl->drap_reg && stack_realign_fp)); + if (ix86_is_interrupt_p () && ix86_using_red_zone ()) + { + emit_insn (gen_adddi3 ( + gen_rtx_REG (DImode, SP_REG), + gen_rtx_REG (DImode, SP_REG), + GEN_INT (-128))); + } + memset (&m->fs, 0, sizeof (m->fs)); /* Initialize CFA state for before the prologue. */ @@ -12437,7 +12474,29 @@ ix86_expand_epilogue (int style) return; } - if (crtl->args.pops_args && crtl->args.size) + if (ix86_is_interrupt_p ()) + { + if (ix86_using_red_zone ()) + emit_insn (gen_adddi3 ( + gen_rtx_REG (DImode, SP_REG), + gen_rtx_REG (DImode, SP_REG), + GEN_INT (128))); + if (ix86_is_exception_p ()) + { + if (!TARGET_64BIT) + emit_insn (gen_addsi3 ( + gen_rtx_REG (SImode, SP_REG), + gen_rtx_REG (SImode, SP_REG), + GEN_INT (POINTER_SIZE_UNITS))); + else + emit_insn (gen_adddi3 ( + gen_rtx_REG (DImode, SP_REG), + gen_rtx_REG (DImode, SP_REG), + GEN_INT (POINTER_SIZE_UNITS))); + } + emit_jump_insn (gen_simple_return_interrupt ()); + } + else if (crtl->args.pops_args && crtl->args.size) { rtx popc = GEN_INT (crtl->args.pops_args); @@ -25752,12 +25811,23 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, } } + if (ix86_is_interrupt_p ()) + { + unsigned regno; + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + { + if (!call_used_regs[regno] && !fixed_regs[regno] && !STACK_REGNO_P (regno) && !MMX_REGNO_P (regno)) + { + clobber_reg(&use, gen_rtx_REG (GET_MODE(regno_reg_rtx[regno]), regno)); + } + } + } + if (vec_len > 1) call = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (vec_len, vec)); call = emit_call_insn (call); if (use) CALL_INSN_FUNCTION_USAGE (call) = use; - return call; } @@ -42204,6 +42274,23 @@ ix86_hard_regno_mode_ok (int regno, machine_mode mode) return false; } +bool +ix86_is_interrupt_p () +{ + return lookup_attribute ("interrupt", + DECL_ATTRIBUTES (current_function_decl)) || + lookup_attribute ("exception", + DECL_ATTRIBUTES (current_function_decl)); +} + +bool +ix86_is_exception_p () +{ + return lookup_attribute ("exception", + DECL_ATTRIBUTES (current_function_decl)); +} + + /* A subroutine of ix86_modes_tieable_p. Return true if MODE is a tieable integer mode. */ @@ -43126,6 +43213,51 @@ ix86_handle_fndecl_attribute (tree *node, tree name, tree, int, return NULL_TREE; } + +static tree +ix86_handle_interrupt_attribute (tree *node, tree name, tree, int, + bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); + *no_add_attrs = true; + } + + /* DECL_RESULT and DECL_ARGUMENTS do not exist there yet, + but the function type contains args and return type data. */ + tree func_type = TREE_TYPE (*node); + tree first_arg_type = TYPE_ARG_TYPES (func_type); + tree return_type = TREE_TYPE (func_type); + if (first_arg_type && ! VOID_TYPE_P ( TREE_VALUE (first_arg_type))) + error ("Interrupt service routine can't have arguments"); + if (! VOID_TYPE_P (return_type)) + error ("Interrupt service routine can't have non-void return value"); + + return NULL_TREE; +} + +static tree +ix86_handle_exception_attribute (tree *node, tree name, tree, int, + bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); + *no_add_attrs = true; + } + + tree func_type = TREE_TYPE (*node); + tree return_type = TREE_TYPE (func_type); + if (! VOID_TYPE_P (return_type)) + error ("Interrupt service routine can't have non-void return value"); + + return NULL_TREE; +} + + static bool ix86_ms_bitfield_layout_p (const_tree record_type) { @@ -47127,6 +47259,11 @@ static const struct attribute_spec ix86_attribute_table[] = false }, { "callee_pop_aggregate_return", 1, 1, false, true, true, ix86_handle_callee_pop_aggregate_return, true }, +{ "interrupt", 0, 0, true, false, false, ix86_handle_interrupt_attribute, + false }, + { "exception", 0, 0, true, false, false, ix86_handle_exception_attribute, + false }, + /* End element. */ { NULL, 0, 0, false, false, false, NULL, false } }; diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 7017913afe2..b7568ba0c22 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -193,6 +193,9 @@ UNSPEC_BNDCU UNSPEC_BNDCN UNSPEC_MPX_FENCE + + ;; IRET support + UNSPEC_INTERRUPT_RETURN ]) (define_c_enum "unspecv" [ @@ -12094,6 +12097,12 @@ (set_attr "modrm" "0") (set_attr "maybe_prefix_bnd" "1")]) +(define_insn "simple_return_interrupt" + [(simple_return) + (unspec [(const_int 0)] UNSPEC_INTERRUPT_RETURN)] + "" + "iret") + ;; Used by x86_machine_dependent_reorg to avoid penalty on single byte RET ;; instruction Athlon and K8 have. diff --git a/gcc/testsuite/gcc.target/i386/interrupt-args-err.c b/gcc/testsuite/gcc.target/i386/interrupt-args-err.c new file mode 100644 index 00000000000..1ea093e25a7 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-args-err.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +extern void foo (int,int) __attribute__ ((interrupt)); /* { dg-error "Interrupt service routine can't have arguments" } */ +extern void bar (int, int); + +void foo (int x, int y) +{ + bar (x, y); +} 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..9c9d266cec2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-iamcu.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=iamcu" } */ + +extern void foo (void) __attribute__ ((interrupt)); +extern int bar (int); + +void foo () +{ + 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 "push.\t%.ax" } }*/ +/* { dg-final { scan-assembler "pop.\t%.ax" } }*/ +/* { dg-final { scan-assembler "push.\t%.dx" } }*/ +/* { dg-final { scan-assembler "pop.\t%.dx" } }*/ +/* { dg-final { scan-assembler "push.\t%.cx" } }*/ +/* { dg-final { scan-assembler "pop.\t%.cx" } }*/ +/* { dg-final { scan-assembler "push.\t%.bx" } }*/ +/* { dg-final { scan-assembler "pop.\t%.bx" } }*/ +/* { dg-final { scan-assembler "push.\t%.si" } }*/ +/* { dg-final { scan-assembler "pop.\t%.si" } }*/ +/* { dg-final { scan-assembler "push.\t%.di" } }*/ +/* { dg-final { scan-assembler "pop.\t%.di" } }*/ +/* { dg-final { scan-assembler "iret" } }*/ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-redzone.c b/gcc/testsuite/gcc.target/i386/interrupt-redzone.c new file mode 100644 index 00000000000..d59eb663966 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-redzone.c @@ -0,0 +1,10 @@ +/* { dg-do compile { target { ! { ia32 } } } } */ +/* { dg-options "-mabi=sysv" } */ +extern int a; +void __attribute__((interrupt)) bar () + { + a = 4; + } + +/* { dg-final { scan-assembler "addq\t\\\$-?128, %rsp" } } */ +/* { dg-final { scan-assembler "subq\t\\\$-?128, %rsp" } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt-retval-err.c b/gcc/testsuite/gcc.target/i386/interrupt-retval-err.c new file mode 100644 index 00000000000..7e8990c8c4d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-retval-err.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ + +extern int foo (void) __attribute__ ((interrupt)); /* { dg-error "Interrupt service routine can't have non-void return value" } */ +extern int bar (int, int); + +int foo (void) +{ + int x, y; + x = y = 1; + return bar (x, y); +} 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..6d418bef59a --- /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 () +{ + 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..33de0bc4186 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt-switch-abi.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +extern void bar(int); + +void f1(){ bar(1); } +__attribute__((interrupt)) +void f2(){ bar(2); } +void f3(){ bar(3); } +__attribute__((exception)) +void f4(){ bar(4); } +void f5(){ bar(5); } + +/* { dg-final { scan-assembler-times "iret" 2 } } */ diff --git a/gcc/testsuite/gcc.target/i386/interrupt.c b/gcc/testsuite/gcc.target/i386/interrupt.c new file mode 100644 index 00000000000..9153a521640 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/interrupt.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ + +extern void foo (void) __attribute__ ((interrupt)); +extern int bar (int); + +void foo () +{ + 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 "push.\t%.ax" } }*/ +/* { dg-final { scan-assembler "pop.\t%.ax" } }*/ +/* { dg-final { scan-assembler "push.\t%.dx" } }*/ +/* { dg-final { scan-assembler "pop.\t%.dx" } }*/ +/* { dg-final { scan-assembler "push.\t%.cx" } }*/ +/* { dg-final { scan-assembler "pop.\t%.cx" } }*/ +/* { dg-final { scan-assembler "push.\t%.bx" } }*/ +/* { dg-final { scan-assembler "pop.\t%.bx" } }*/ +/* { dg-final { scan-assembler "push.\t%.si" } }*/ +/* { dg-final { scan-assembler "pop.\t%.si" } }*/ +/* { dg-final { scan-assembler "push.\t%.di" } }*/ +/* { dg-final { scan-assembler "pop.\t%.di" } }*/ +/* { dg-final { scan-assembler "iret" } }*/ |