From 57d5535b031f85ada1a22059d8215cb349aa0e97 Mon Sep 17 00:00:00 2001 From: amylaar Date: Mon, 30 Jan 2006 15:07:43 +0000 Subject: [PATCH] PR target/14798: gcc: * sh.c (pragma_interrupt, trap_exit, sp_switch): Remove variable. (pragma_trap, pragma_nosave_low_regs): Likewise. (current_function_anonymous_args): Likewise. (sh_deferred_function_attributes): New variable. (sh_deferred_function_attributes_tail): Likewise. (print_operand): For '@', look up trap_exit attribute. (calc_live_regs): Look up trapa_handler attribute. For trapa handlers, save/restore fpscr, but don't do any other interrupt-specific saves. Don't save r0..r7 if the nosave_low_regs attribute is in effect. Fix check for partially saved registers to check for SHmedia. (sh_expand_prologue, sh_expand_epilogue): Look up sp_switch attribute. (sh_output_function_epilogue): Don't clear any of the removed variables. (sh_insert_attributes): Don't check pragma_interrupt. Insert deferred attributes. Check that interrupt attribute is present for other attributes that require its presence. (sh_attribute_table): Add new attributes trapa_handler and nosave_low_regs. (sh_handle_sp_switch_attribute, sh_handle_trap_exit_attribute): Don't check for pragma_interrupt. Don't store argument. * sh.h (pragma_interrupt, sp_switch): Don't declare. (sh_deferred_function_attributes): Declare. (sh_deferred_function_attributes_tail): Likewise. * sh.md (sp_switch_1): Add operand. Change generator caller. (sh_pr_interrupt, sh_pr_trapa, sh_pr_nosave_low_regs): Remove. (*return_i): Don't use when trap_exit attribute is in effect. (*return_trapa): New insn pattern. * sh-c.c: New file. * config.gcc (sh[123456ble]*-* | sh-*-*): New trailer stanza, setting c_target_objs and cxx_target_objs. * t-sh: Add rule for sh-c.o. gcc/testsuite: * gcc.dg/pragma-isr.c: Added target sh[1234ble]*-*-*. * gcc.dg/pragma-isr2.c, gcc.dg/pragma-isr-trapa.c: New tests. * gcc.dg/pragma-isr-trapa2.c: Likewise. * gcc.dg/pragma-isr-nosave_low_regs.c: Likewise. * gcc.dg/pragma-isr-trap_exit.c: Likewise. * gcc.dg/attr-isr.c, gcc.dg/attr-isr-trapa.c: Likewise. * gcc.dg/attr-isr-trap_exit.c: Likewise. * gcc.dg/attr-isr-nosave_low_regs.c: Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@110398 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 36 ++++ gcc/config.gcc | 5 + gcc/config/sh/sh-c.c | 69 ++++++++ gcc/config/sh/sh.c | 198 ++++++++++++---------- gcc/config/sh/sh.h | 9 +- gcc/config/sh/sh.md | 21 ++- gcc/config/sh/t-sh | 4 + gcc/testsuite/ChangeLog | 12 ++ gcc/testsuite/gcc.dg/attr-isr-nosave_low_regs.c | 28 +++ gcc/testsuite/gcc.dg/attr-isr-trap_exit.c | 23 +++ gcc/testsuite/gcc.dg/attr-isr-trapa.c | 17 ++ gcc/testsuite/gcc.dg/attr-isr.c | 18 ++ gcc/testsuite/gcc.dg/pragma-isr-nosave_low_regs.c | 20 +++ gcc/testsuite/gcc.dg/pragma-isr-trap_exit.c | 17 ++ gcc/testsuite/gcc.dg/pragma-isr-trapa.c | 17 ++ gcc/testsuite/gcc.dg/pragma-isr-trapa2.c | 22 +++ gcc/testsuite/gcc.dg/pragma-isr.c | 2 +- gcc/testsuite/gcc.dg/pragma-isr2.c | 16 ++ 18 files changed, 427 insertions(+), 107 deletions(-) create mode 100644 gcc/config/sh/sh-c.c create mode 100644 gcc/testsuite/gcc.dg/attr-isr-nosave_low_regs.c create mode 100644 gcc/testsuite/gcc.dg/attr-isr-trap_exit.c create mode 100644 gcc/testsuite/gcc.dg/attr-isr-trapa.c create mode 100644 gcc/testsuite/gcc.dg/attr-isr.c create mode 100644 gcc/testsuite/gcc.dg/pragma-isr-nosave_low_regs.c create mode 100644 gcc/testsuite/gcc.dg/pragma-isr-trap_exit.c create mode 100644 gcc/testsuite/gcc.dg/pragma-isr-trapa.c create mode 100644 gcc/testsuite/gcc.dg/pragma-isr-trapa2.c create mode 100644 gcc/testsuite/gcc.dg/pragma-isr2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dcd3684c4f1..0a44292cb05 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,39 @@ +2006-01-30 J"orn Rennecke + + PR target/14798: + * sh.c (pragma_interrupt, trap_exit, sp_switch): Remove variable. + (pragma_trap, pragma_nosave_low_regs): Likewise. + (current_function_anonymous_args): Likewise. + (sh_deferred_function_attributes): New variable. + (sh_deferred_function_attributes_tail): Likewise. + (print_operand): For '@', look up trap_exit attribute. + (calc_live_regs): Look up trapa_handler attribute. For trapa + handlers, save/restore fpscr, but don't do any other + interrupt-specific saves. + Don't save r0..r7 if the nosave_low_regs attribute is in effect. + Fix check for partially saved registers to check for SHmedia. + (sh_expand_prologue, sh_expand_epilogue): Look up sp_switch attribute. + (sh_output_function_epilogue): Don't clear any of the removed + variables. + (sh_insert_attributes): Don't check pragma_interrupt. + Insert deferred attributes. Check that interrupt attribute is + present for other attributes that require its presence. + (sh_attribute_table): Add new attributes trapa_handler and + nosave_low_regs. + (sh_handle_sp_switch_attribute, sh_handle_trap_exit_attribute): + Don't check for pragma_interrupt. Don't store argument. + * sh.h (pragma_interrupt, sp_switch): Don't declare. + (sh_deferred_function_attributes): Declare. + (sh_deferred_function_attributes_tail): Likewise. + * sh.md (sp_switch_1): Add operand. Change generator caller. + (sh_pr_interrupt, sh_pr_trapa, sh_pr_nosave_low_regs): Remove. + (*return_i): Don't use when trap_exit attribute is in effect. + (*return_trapa): New insn pattern. + * sh-c.c: New file. + * config.gcc (sh[123456ble]*-* | sh-*-*): New trailer stanza, + setting c_target_objs and cxx_target_objs. + * t-sh: Add rule for sh-c.o. + 2006-01-30 Richard Guenther PR c++/23372 diff --git a/gcc/config.gcc b/gcc/config.gcc index 252f10c80ad..0ac27c342a5 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -2938,6 +2938,11 @@ case ${target} in fi ;; + sh[123456ble]*-*-* | sh-*-*) + c_target_objs="${c_target_objs} sh-c.o" + cxx_target_objs="${cxx_target_objs} sh-c.o" + ;; + sparc*-*-*) # Some standard aliases. case x$with_cpu in diff --git a/gcc/config/sh/sh-c.c b/gcc/config/sh/sh-c.c new file mode 100644 index 00000000000..7b9ec1c1e4d --- /dev/null +++ b/gcc/config/sh/sh-c.c @@ -0,0 +1,69 @@ +/* Pragma handling for GCC for Renesas / SuperH SH. + Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + Contributed by Joern Rennecke . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "tm_p.h" + +/* Handle machine specific pragmas to be semi-compatible with Renesas + compiler. */ + +/* Add ATTR to the attributes of the current function. If there is no + such function, save it to be added to the attributes of the next + function. */ +static void +sh_add_function_attribute (const char *attr) +{ + tree id = get_identifier (attr); + + if (current_function_decl) + decl_attributes (¤t_function_decl, + tree_cons (id, NULL_TREE, NULL_TREE), 0); + else + { + *sh_deferred_function_attributes_tail + = tree_cons (id, NULL_TREE, *sh_deferred_function_attributes_tail); + sh_deferred_function_attributes_tail + = &TREE_CHAIN (*sh_deferred_function_attributes_tail); + } +} + +void +sh_pr_interrupt (struct cpp_reader *pfile ATTRIBUTE_UNUSED) +{ + sh_add_function_attribute ("interrupt_handler"); +} + +void +sh_pr_trapa (struct cpp_reader *pfile ATTRIBUTE_UNUSED) +{ + sh_add_function_attribute ("trapa_handler"); +} + +void +sh_pr_nosave_low_regs (struct cpp_reader *pfile ATTRIBUTE_UNUSED) +{ + sh_add_function_attribute ("nosave_low_regs"); +} diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index a9cafec612f..6dfe282f4d9 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -70,35 +70,8 @@ int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch; /* Set to 1 by expand_prologue() when the function is an interrupt handler. */ int current_function_interrupt; -/* ??? The pragma interrupt support will not work for SH3. */ -/* This is set by #pragma interrupt and #pragma trapa, and causes gcc to - output code for the next function appropriate for an interrupt handler. */ -int pragma_interrupt; - -/* This is set by the trap_exit attribute for functions. It specifies - a trap number to be used in a trapa instruction at function exit - (instead of an rte instruction). */ -int trap_exit; - -/* This is used by the sp_switch attribute for functions. It specifies - a variable holding the address of the stack the interrupt function - should switch to/from at entry/exit. */ -rtx sp_switch; - -/* This is set by #pragma trapa, and is similar to the above, except that - the compiler doesn't emit code to preserve all registers. */ -static int pragma_trapa; - -/* This is set by #pragma nosave_low_regs. This is useful on the SH3, - which has a separate set of low regs for User and Supervisor modes. - This should only be used for the lowest level of interrupts. Higher levels - of interrupts must save the registers in case they themselves are - interrupted. */ -int pragma_nosave_low_regs; - -/* This is used for communication between TARGET_SETUP_INCOMING_VARARGS and - sh_expand_prologue. */ -int current_function_anonymous_args; +tree sh_deferred_function_attributes; +tree *sh_deferred_function_attributes_tail = &sh_deferred_function_attributes; /* Global variables for machine-dependent things. */ @@ -696,6 +669,8 @@ print_operand (FILE *stream, rtx x, int code) switch (code) { + tree trapa_attr; + case '.': if (final_sequence && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)) @@ -706,8 +681,11 @@ print_operand (FILE *stream, rtx x, int code) fprintf (stream, "%s", LOCAL_LABEL_PREFIX); break; case '@': - if (trap_exit) - fprintf (stream, "trapa #%d", trap_exit); + trapa_attr = lookup_attribute ("trap_exit", + DECL_ATTRIBUTES (current_function_decl)); + if (trapa_attr) + fprintf (stream, "trapa #%ld", + (long) TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (trapa_attr)))); else if (sh_cfun_interrupt_handler_p ()) fprintf (stream, "rte"); else @@ -5418,10 +5396,16 @@ calc_live_regs (HARD_REG_SET *live_regs_mask) { unsigned int reg; int count; - int interrupt_handler; + tree attrs; + bool interrupt_or_trapa_handler, trapa_handler, interrupt_handler; + bool nosave_low_regs; int pr_live, has_call; - interrupt_handler = sh_cfun_interrupt_handler_p (); + attrs = DECL_ATTRIBUTES (current_function_decl); + interrupt_or_trapa_handler = sh_cfun_interrupt_handler_p (); + trapa_handler = lookup_attribute ("trapa_handler", attrs) != NULL_TREE; + interrupt_handler = interrupt_or_trapa_handler && ! trapa_handler; + nosave_low_regs = lookup_attribute ("nosave_low_regs", attrs) != NULL_TREE; CLEAR_HARD_REG_SET (*live_regs_mask); if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && interrupt_handler @@ -5432,7 +5416,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask) for (count = 0, reg = FIRST_FP_REG; reg <= LAST_FP_REG; reg += 2) if (regs_ever_live[reg] && regs_ever_live[reg+1] && (! call_really_used_regs[reg] - || (interrupt_handler && ! pragma_trapa)) + || interrupt_handler) && ++count > 2) { target_flags &= ~MASK_FPU_SINGLE; @@ -5470,14 +5454,15 @@ calc_live_regs (HARD_REG_SET *live_regs_mask) { if (reg == (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG) ? pr_live - : (interrupt_handler && ! pragma_trapa) + : interrupt_handler ? (/* Need to save all the regs ever live. */ (regs_ever_live[reg] || (call_really_used_regs[reg] && (! fixed_regs[reg] || reg == MACH_REG || reg == MACL_REG || reg == PIC_OFFSET_TABLE_REGNUM) && has_call) - || (has_call && REGISTER_NATURAL_MODE (reg) == SImode + || (TARGET_SHMEDIA && has_call + && REGISTER_NATURAL_MODE (reg) == SImode && (GENERAL_REGISTER_P (reg) || TARGET_REGISTER_P (reg)))) && reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM && reg != RETURN_ADDRESS_POINTER_REGNUM @@ -5489,7 +5474,9 @@ calc_live_regs (HARD_REG_SET *live_regs_mask) && flag_pic && current_function_args_info.call_cookie && reg == PIC_OFFSET_TABLE_REGNUM) - || (regs_ever_live[reg] && ! call_really_used_regs[reg]) + || (regs_ever_live[reg] + && (!call_really_used_regs[reg] + || (trapa_handler && reg == FPSCR_REG && TARGET_FPU_ANY))) || (current_function_calls_eh_return && (reg == EH_RETURN_DATA_REGNO (0) || reg == EH_RETURN_DATA_REGNO (1) @@ -5521,6 +5508,8 @@ calc_live_regs (HARD_REG_SET *live_regs_mask) } } } + if (nosave_low_regs && reg == R8_REG) + break; } /* If we have a target register optimization pass after prologue / epilogue threading, we need to assume all target registers will be live even if @@ -5724,6 +5713,8 @@ sh_expand_prologue (void) int d_rounding = 0; int save_flags = target_flags; int pretend_args; + tree sp_switch_attr + = lookup_attribute ("sp_switch", DECL_ATTRIBUTES (current_function_decl)); current_function_interrupt = sh_cfun_interrupt_handler_p (); @@ -5813,8 +5804,16 @@ sh_expand_prologue (void) } /* If we're supposed to switch stacks at function entry, do so now. */ - if (sp_switch) - emit_insn (gen_sp_switch_1 ()); + if (sp_switch_attr) + { + /* The argument specifies a variable holding the address of the + stack the interrupt function should switch to/from at entry/exit. */ + const char *s + = ggc_strdup (TREE_STRING_POINTER (TREE_VALUE (sp_switch_attr))); + rtx sp_switch = gen_rtx_SYMBOL_REF (Pmode, s); + + emit_insn (gen_sp_switch_1 (sp_switch)); + } d = calc_live_regs (&live_regs_mask); /* ??? Maybe we could save some switching if we can move a mode switch @@ -6333,7 +6332,7 @@ sh_expand_epilogue (bool sibcall_p) EH_RETURN_STACKADJ_RTX)); /* Switch back to the normal stack if necessary. */ - if (sp_switch) + if (lookup_attribute ("sp_switch", DECL_ATTRIBUTES (current_function_decl))) emit_insn (gen_sp_switch_2 ()); /* Tell flow the insn that pops PR isn't dead. */ @@ -6435,9 +6434,7 @@ static void sh_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED, HOST_WIDE_INT size ATTRIBUTE_UNUSED) { - trap_exit = pragma_interrupt = pragma_trapa = pragma_nosave_low_regs = 0; sh_need_epilogue_known = 0; - sp_switch = NULL_RTX; } static rtx @@ -7446,42 +7443,69 @@ initial_elimination_offset (int from, int to) return total_auto_space; } -/* Handle machine specific pragmas to be semi-compatible with Renesas - compiler. */ - -void -sh_pr_interrupt (struct cpp_reader *pfile ATTRIBUTE_UNUSED) -{ - pragma_interrupt = 1; -} - -void -sh_pr_trapa (struct cpp_reader *pfile ATTRIBUTE_UNUSED) -{ - pragma_interrupt = pragma_trapa = 1; -} - -void -sh_pr_nosave_low_regs (struct cpp_reader *pfile ATTRIBUTE_UNUSED) -{ - pragma_nosave_low_regs = 1; -} - -/* Generate 'handle_interrupt' attribute for decls */ - +/* Insert any deferred function attributes from earlier pragmas. */ static void sh_insert_attributes (tree node, tree *attributes) { - if (! pragma_interrupt - || TREE_CODE (node) != FUNCTION_DECL) + tree attrs; + + if (TREE_CODE (node) != FUNCTION_DECL) return; /* We are only interested in fields. */ if (!DECL_P (node)) return; - /* Add a 'handle_interrupt' attribute. */ - * attributes = tree_cons (get_identifier ("interrupt_handler"), NULL, * attributes); + /* Append the attributes to the deferred attributes. */ + *sh_deferred_function_attributes_tail = *attributes; + attrs = sh_deferred_function_attributes; + if (!attrs) + return; + + /* Some attributes imply or require the interrupt attribute. */ + if (!lookup_attribute ("interrupt_handler", attrs) + && !lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (node))) + { + /* If we have a trapa_handler, but no interrupt_handler attribute, + insert an interrupt_handler attribute. */ + if (lookup_attribute ("trapa_handler", attrs) != NULL_TREE) + /* We can't use sh_pr_interrupt here because that's not in the + java frontend. */ + attrs + = tree_cons (get_identifier("interrupt_handler"), NULL_TREE, attrs); + /* However, for sp_switch, trap_exit and nosave_low_regs, if the + interrupt attribute is missing, we ignore the attribute and warn. */ + else if (lookup_attribute ("sp_switch", attrs) + || lookup_attribute ("trap_exit", attrs) + || lookup_attribute ("nosave_low_regs", attrs)) + { + tree *tail; + + for (tail = attributes; attrs; attrs = TREE_CHAIN (attrs)) + { + if (is_attribute_p ("sp_switch", TREE_PURPOSE (attrs)) + || is_attribute_p ("trap_exit", TREE_PURPOSE (attrs)) + || is_attribute_p ("nosave_low_regs", TREE_PURPOSE (attrs))) + warning (OPT_Wattributes, + "%qs attribute only applies to interrupt functions", + IDENTIFIER_POINTER (TREE_PURPOSE (attrs))); + else + { + *tail = tree_cons (TREE_PURPOSE (attrs), NULL_TREE, + NULL_TREE); + tail = &TREE_CHAIN (*tail); + } + } + attrs = *attributes; + } + } + + /* Install the processed list. */ + *attributes = attrs; + + /* Clear deferred attributes. */ + sh_deferred_function_attributes = NULL_TREE; + sh_deferred_function_attributes_tail = &sh_deferred_function_attributes; return; } @@ -7490,12 +7514,21 @@ sh_insert_attributes (tree node, tree *attributes) interrupt_handler -- specifies this function is an interrupt handler. + trapa_handler - like above, but don't save all registers. + sp_switch -- specifies an alternate stack for an interrupt handler to run on. trap_exit -- use a trapa to exit an interrupt function instead of an rte instruction. + nosave_low_regs - don't save r0..r7 in an interrupt handler. + This is useful on the SH3 and upwards, + which has a separate set of low regs for User and Supervisor modes. + This should only be used for the lowest level of interrupts. Higher levels + of interrupts must save the registers in case they themselves are + interrupted. + renesas -- use Renesas calling/layout conventions (functions and structures). @@ -7508,6 +7541,8 @@ const struct attribute_spec sh_attribute_table[] = { "sp_switch", 1, 1, true, false, false, sh_handle_sp_switch_attribute }, { "trap_exit", 1, 1, true, false, false, sh_handle_trap_exit_attribute }, { "renesas", 0, 0, false, true, false, sh_handle_renesas_attribute }, + { "trapa_handler", 0, 0, true, false, false, sh_handle_interrupt_handler_attribute }, + { "nosave_low_regs", 0, 0, true, false, false, sh_handle_interrupt_handler_attribute }, #ifdef SYMBIAN /* Symbian support adds three new attributes: dllexport - for exporting a function/variable that will live in a dll @@ -7557,13 +7592,6 @@ sh_handle_sp_switch_attribute (tree *node, tree name, tree args, IDENTIFIER_POINTER (name)); *no_add_attrs = true; } - else if (!pragma_interrupt) - { - /* The sp_switch attribute only has meaning for interrupt functions. */ - warning (OPT_Wattributes, "%qs attribute only applies to " - "interrupt functions", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) { /* The argument must be a constant string. */ @@ -7571,11 +7599,6 @@ sh_handle_sp_switch_attribute (tree *node, tree name, tree args, IDENTIFIER_POINTER (name)); *no_add_attrs = true; } - else - { - const char *s = ggc_strdup (TREE_STRING_POINTER (TREE_VALUE (args))); - sp_switch = gen_rtx_SYMBOL_REF (VOIDmode, s); - } return NULL_TREE; } @@ -7592,13 +7615,8 @@ sh_handle_trap_exit_attribute (tree *node, tree name, tree args, IDENTIFIER_POINTER (name)); *no_add_attrs = true; } - else if (!pragma_interrupt) - { - /* The trap_exit attribute only has meaning for interrupt functions. */ - warning (OPT_Wattributes, "%qs attribute only applies to " - "interrupt functions", IDENTIFIER_POINTER (name)); - *no_add_attrs = true; - } + /* The argument specifies a trap number to be used in a trapa instruction + at function exit (instead of an rte instruction). */ else if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST) { /* The argument must be a constant integer. */ @@ -7606,10 +7624,6 @@ sh_handle_trap_exit_attribute (tree *node, tree name, tree args, "integer constant", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } - else - { - trap_exit = TREE_INT_CST_LOW (TREE_VALUE (args)); - } return NULL_TREE; } diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index 87117f45b4c..72cd56391bb 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -3277,18 +3277,13 @@ extern enum mdep_reorg_phase_e mdep_reorg_phase; c_register_pragma (0, "nosave_low_regs", sh_pr_nosave_low_regs); \ } while (0) -/* Set when processing a function with pragma interrupt turned on. */ - -extern int pragma_interrupt; +extern tree sh_deferred_function_attributes; +extern tree *sh_deferred_function_attributes_tail; /* Set when processing a function with interrupt attribute. */ extern int current_function_interrupt; -/* Set to an RTX containing the address of the stack to switch to - for interrupt functions. */ -extern struct rtx_def *sp_switch; - /* Instructions with unfilled delay slots take up an extra two bytes for the nop in the delay slot. diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 38cd3bd6c6e..e2e477f2a57 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -8781,11 +8781,21 @@ mov.l\\t1f,r0\\n\\ "TARGET_SH1 && ! (TARGET_SHCOMPACT && (current_function_args_info.call_cookie & CALL_COOKIE_RET_TRAMP (1))) - && reload_completed" + && reload_completed + && lookup_attribute (\"trap_exit\", + DECL_ATTRIBUTES (current_function_decl)) == NULL_TREE" "%@ %#" [(set_attr "type" "return") (set_attr "needs_delay_slot" "yes")]) +;; trapa has no delay slot. +(define_insn "*return_trapa" + [(return)] + "TARGET_SH1 && !TARGET_SHCOMPACT + && reload_completed" + "%@" + [(set_attr "type" "return")]) + (define_expand "shcompact_return_tramp" [(return)] "TARGET_SHCOMPACT @@ -11209,15 +11219,12 @@ mov.l\\t1f,r0\\n\\ ;; Switch to a new stack with its address in sp_switch (a SYMBOL_REF). */ (define_insn "sp_switch_1" - [(const_int 1)] + [(const_int 1) (match_operand:SI 0 "symbol_ref_operand" "s")] "TARGET_SH1" "* { - rtx xoperands[1]; - - xoperands[0] = sp_switch; - output_asm_insn (\"mov.l r0,@-r15\;mov.l %0,r0\", xoperands); - output_asm_insn (\"mov.l @r0,r0\;mov.l r15,@-r0\", xoperands); + output_asm_insn (\"mov.l r0,@-r15\;mov.l %0,r0\", operands); + output_asm_insn (\"mov.l @r0,r0\;mov.l r15,@-r0\", operands); return \"mov r0,r15\"; }" [(set_attr "length" "10")]) diff --git a/gcc/config/sh/t-sh b/gcc/config/sh/t-sh index c5eb397b142..db86ad18c1d 100644 --- a/gcc/config/sh/t-sh +++ b/gcc/config/sh/t-sh @@ -1,3 +1,7 @@ +sh-c.o: $(srcdir)/config/sh/sh-c.c \ + $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TM_H) $(TM_P_H) coretypes.h + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/sh/sh-c.c + LIB1ASMSRC = sh/lib1funcs.asm LIB1ASMFUNCS = _ashiftrt _ashiftrt_n _ashiftlt _lshiftrt _movmem \ _movmem_i4 _mulsi3 _sdivsi3 _sdivsi3_i4 _udivsi3 _udivsi3_i4 _set_fpscr \ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c7b641144d2..56b8eae371c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2006-01-30 J"orn Rennecke + + PR target/14798: + * gcc.dg/pragma-isr.c: Added target sh[1234ble]*-*-*. + * gcc.dg/pragma-isr2.c, gcc.dg/pragma-isr-trapa.c: New tests. + * gcc.dg/pragma-isr-trapa2.c: Likewise. + * gcc.dg/pragma-isr-nosave_low_regs.c: Likewise. + * gcc.dg/pragma-isr-trap_exit.c: Likewise. + * gcc.dg/attr-isr.c, gcc.dg/attr-isr-trapa.c: Likewise. + * gcc.dg/attr-isr-trap_exit.c: Likewise. + * gcc.dg/attr-isr-nosave_low_regs.c: Likewise. + 2006-01-30 Richard Guenther PR c++/23372 diff --git a/gcc/testsuite/gcc.dg/attr-isr-nosave_low_regs.c b/gcc/testsuite/gcc.dg/attr-isr-nosave_low_regs.c new file mode 100644 index 00000000000..5f3acdf3d78 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-isr-nosave_low_regs.c @@ -0,0 +1,28 @@ +/* { dg-do compile { target sh-*-* sh[1234ble]*-*-*} } */ +/* { dg-options "-O" } */ + +extern void bar (); + +void foo () +{ +} + +#pragma interrupt +void ( __attribute__ ((nosave_low_regs)) isr) () +{ + bar (); +} + +void delay(int a) +{ +} + +/* { dg-final { scan-assembler-times "rte" 1} } */ +/* A call will clobber all call-saved registers, but because of + #pragma nosave_low_regs, r0..r7 need not be saved/restored. + One of these registers will also do fine to hold the function address. + Call-saved registers r8..r13 also don't need to be restored. */ +/* { dg-final { scan-assembler-not "\[^f\]r\[0-9\]\[ \t\]*," } } */ +/* { dg-final { scan-assembler-not "\[^f\]r\[89\]" } } */ +/* { dg-final { scan-assembler-not "\[^f\]r1\[,0-3\]" } } */ +/* { dg-final { scan-assembler-times "macl" 2} } */ diff --git a/gcc/testsuite/gcc.dg/attr-isr-trap_exit.c b/gcc/testsuite/gcc.dg/attr-isr-trap_exit.c new file mode 100644 index 00000000000..880db37ce73 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-isr-trap_exit.c @@ -0,0 +1,23 @@ +/* { dg-do compile { target sh-*-* sh[1234ble]*-*-*} } */ +/* { dg-options "-O" } */ +/* Check that trapa / interrput_handler attributes can paired in + either order. */ +void h0() __attribute__ ((trap_exit (4))) __attribute__ ((interrupt_handler)); +void h1() __attribute__ ((interrupt_handler)) __attribute__ ((trap_exit (5))); + +void foo () +{ +} + +void h0 () {} +/* { dg-final { scan-assembler "trapa\[ \t\]\[ \t\]*#4"} } */ +/* { dg-final { scan-assembler-times "trapa" 1} } */ + +void delay(int a) +{ +} +int main() +{ + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/attr-isr-trapa.c b/gcc/testsuite/gcc.dg/attr-isr-trapa.c new file mode 100644 index 00000000000..d17680589f8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-isr-trapa.c @@ -0,0 +1,17 @@ +/* { dg-do compile { target sh-*-* sh[1234ble]*-*-*} } */ +/* { dg-options "-O" } */ +extern void foo (); + +void +(__attribute__ ((trapa_handler)) isr) () +{ + foo (); +} + +/* { dg-final { scan-assembler-times "rte" 1} } */ +/* No interrupt-specific saves should be needed. / +/* { dg-final { scan-assembler-not "\[^f\]r\[0-7\]\[ \t,\]\[^\n\]*r15" } } */ +/* { dg-final { scan-assembler-not "@r15\[^\n\]*\[^f\]r\[0-7\]\n" } } */ +/* { dg-final { scan-assembler-not "\[^f\]r\[8-9\]" } } */ +/* { dg-final { scan-assembler-not "\[^f\]r1\[,0-3\]" } } */ +/* { dg-final { scan-assembler-not "macl" } } */ diff --git a/gcc/testsuite/gcc.dg/attr-isr.c b/gcc/testsuite/gcc.dg/attr-isr.c new file mode 100644 index 00000000000..113ac21d43c --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-isr.c @@ -0,0 +1,18 @@ +/* { dg-do compile { target sh-*-* sh[1234ble]*-*-*} } */ +/* { dg-options "-O" } */ +extern void foo (); + +void +(__attribute ((interrupt_handler)) isr)() +{ + foo (); +} + +/* { dg-final { scan-assembler-times "rte" 1} } */ +/* The call will clobber r0..r7, which will need not be saved/restored. + One of these registers will do fine to hold the function address, + hence the all-saved registers r8..r13 don't need to be restored. */ +/* { dg-final { scan-assembler-times "r15\[+\],\[ \t\]*r\[0-9\]\[ \t\]*\n" 8 } } */ +/* { dg-final { scan-assembler-times "\[^f\]r\[0-9\]\[ \t\]*," 8 } } */ +/* { dg-final { scan-assembler-not "\[^f\]r1\[0-3\]" } } */ +/* { dg-final { scan-assembler-times "macl" 2} } */ diff --git a/gcc/testsuite/gcc.dg/pragma-isr-nosave_low_regs.c b/gcc/testsuite/gcc.dg/pragma-isr-nosave_low_regs.c new file mode 100644 index 00000000000..5e049224a7e --- /dev/null +++ b/gcc/testsuite/gcc.dg/pragma-isr-nosave_low_regs.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target sh-*-* sh[1234ble]*-*-*} } */ +/* { dg-options "-O" } */ +extern void foo (); +#pragma interrupt +#pragma nosave_low_regs +void +isr() +{ + foo (); +} + +/* { dg-final { scan-assembler-times "rte" 1} } */ +/* A call will clobber all call-saved registers, but because of + #pragma nosave_low_regs, r0..r7 need not be saved/restored. + One of these registers will also do fine to hold the function address. + Call-saved registers r8..r13 also don't need to be restored. */ +/* { dg-final { scan-assembler-not "\[^f\]r\[0-9\]\[ \t\]*," } } */ +/* { dg-final { scan-assembler-not "\[^f\]r\[89\]" } } */ +/* { dg-final { scan-assembler-not "\[^f\]r1\[,0-3\]" } } */ +/* { dg-final { scan-assembler-times "macl" 2} } */ diff --git a/gcc/testsuite/gcc.dg/pragma-isr-trap_exit.c b/gcc/testsuite/gcc.dg/pragma-isr-trap_exit.c new file mode 100644 index 00000000000..9b3233a36b5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pragma-isr-trap_exit.c @@ -0,0 +1,17 @@ +/* { dg-do compile { target sh-*-* sh[1234ble]*-*-*} } */ +/* { dg-options "-O" } */ +/* This test case will check whether trapa is generated only for isr. */ +#pragma interrupt +void isr() __attribute__ ((trap_exit (4))); +void isr() +{ +} +void delay(int a) +{ +} +int main() +{ + return 0; +} + +/* { dg-final { scan-assembler-times "trapa\[ \t\]\[ \t\]*#4" 1} } */ diff --git a/gcc/testsuite/gcc.dg/pragma-isr-trapa.c b/gcc/testsuite/gcc.dg/pragma-isr-trapa.c new file mode 100644 index 00000000000..cd019d6e9cf --- /dev/null +++ b/gcc/testsuite/gcc.dg/pragma-isr-trapa.c @@ -0,0 +1,17 @@ +/* { dg-do compile { target sh-*-* sh[1234ble]*-*-*} } */ +/* { dg-options "-O" } */ +extern void foo (); +#pragma trapa +void +isr() +{ + foo (); +} + +/* { dg-final { scan-assembler-times "rte" 1} } */ +/* No interrupt-specific saves should be needed. / +/* { dg-final { scan-assembler-not "r\[0-7\]\[ \t,\]\[^\n\]*r15" } } */ +/* { dg-final { scan-assembler-not "@r15\[^\n\]*r\[0-7\]\n" } } */ +/* { dg-final { scan-assembler-not "r\[8-9\]" } } */ +/* { dg-final { scan-assembler-not "r1\[,0-3\]" } } */ +/* { dg-final { scan-assembler-not "macl" } } */ diff --git a/gcc/testsuite/gcc.dg/pragma-isr-trapa2.c b/gcc/testsuite/gcc.dg/pragma-isr-trapa2.c new file mode 100644 index 00000000000..21c940b702c --- /dev/null +++ b/gcc/testsuite/gcc.dg/pragma-isr-trapa2.c @@ -0,0 +1,22 @@ +/* { dg-do compile { target sh-*-* sh4*-*-*} } */ +/* { dg-options "-O -m4" } */ + +extern void foo (); +#pragma trapa +void +isr() +{ + foo (); +} + +/* { dg-final { scan-assembler-times "rte" 1} } */ +/* No interrupt-specific saves should be needed. + The function call will require to load the address first into a register, + then use that for a jsr or jmp. It will also need to load a constant + address in order to load fpscr. */ +/* { dg-final { scan-assembler-times "r\[0-7\]\n" 3 } } */ +/* { dg-final { scan-assembler-not "r\[8-9\]" } } */ +/* { dg-final { scan-assembler-not "r1\[,0-3\]" } } */ +/* { dg-final { scan-assembler-not "macl" } } */ +/* fpscr needs to be saved, loaded and restored. */ +/* { dg-final { scan-assembler-times "\[^_\]fpscr" 3 } } */ diff --git a/gcc/testsuite/gcc.dg/pragma-isr.c b/gcc/testsuite/gcc.dg/pragma-isr.c index de16639ffb8..07d8fa7f1f9 100644 --- a/gcc/testsuite/gcc.dg/pragma-isr.c +++ b/gcc/testsuite/gcc.dg/pragma-isr.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target h8300-*-* sh-*-*} } */ +/* { dg-do compile { target h8300-*-* sh-*-* sh[1234ble]*-*-*} } */ /* { dg-options "-O3" } */ /* Test case will check whether rte is generated for two ISRs*/ extern void foo(); diff --git a/gcc/testsuite/gcc.dg/pragma-isr2.c b/gcc/testsuite/gcc.dg/pragma-isr2.c new file mode 100644 index 00000000000..7dba7f9bf61 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pragma-isr2.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target h8300-*-* sh-*-* sh[1234ble]*-*-*} } */ +/* { dg-options "-O" } */ +/* This test case will check whether rte is generated only for isr. */ +#pragma interrupt +void isr() +{ +} +void delay(int a) +{ +} +int main() +{ + return 0; +} + +/* { dg-final { scan-assembler-times "rte" 1} } */ -- 2.11.4.GIT