OSDN Git Service

PR target/14798:
authoramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 30 Jan 2006 15:07:43 +0000 (15:07 +0000)
committeramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 30 Jan 2006 15:07:43 +0000 (15:07 +0000)
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

18 files changed:
gcc/ChangeLog
gcc/config.gcc
gcc/config/sh/sh-c.c [new file with mode: 0644]
gcc/config/sh/sh.c
gcc/config/sh/sh.h
gcc/config/sh/sh.md
gcc/config/sh/t-sh
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/attr-isr-nosave_low_regs.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-isr-trap_exit.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-isr-trapa.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-isr.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pragma-isr-nosave_low_regs.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pragma-isr-trap_exit.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pragma-isr-trapa.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pragma-isr-trapa2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pragma-isr.c
gcc/testsuite/gcc.dg/pragma-isr2.c [new file with mode: 0644]

index dcd3684..0a44292 100644 (file)
@@ -1,3 +1,39 @@
+2006-01-30  J"orn Rennecke <joern.rennecke@st.com>
+
+       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  <rguenther@suse.de>
 
        PR c++/23372
index 252f10c..0ac27c3 100644 (file)
@@ -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 (file)
index 0000000..7b9ec1c
--- /dev/null
@@ -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 <joern.rennecke@st.com>.
+
+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 (&current_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");
+}
index a9cafec..6dfe282 100644 (file)
@@ -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;
 }
 \f
-/* 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;
 }
index 87117f4..72cd563 100644 (file)
@@ -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;
-
 \f
 /* Instructions with unfilled delay slots take up an
    extra two bytes for the nop in the delay slot.
index 38cd3bd..e2e477f 100644 (file)
@@ -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")])
index c5eb397..db86ad1 100644 (file)
@@ -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 \
index c7b6411..56b8eae 100644 (file)
@@ -1,3 +1,15 @@
+2006-01-30  J"orn Rennecke <joern.rennecke@st.com>
+
+       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  <rguenther@suse.de>
 
        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 (file)
index 0000000..5f3acdf
--- /dev/null
@@ -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 (file)
index 0000000..880db37
--- /dev/null
@@ -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 (file)
index 0000000..d176805
--- /dev/null
@@ -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 (file)
index 0000000..113ac21
--- /dev/null
@@ -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 (file)
index 0000000..5e04922
--- /dev/null
@@ -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 (file)
index 0000000..9b3233a
--- /dev/null
@@ -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 (file)
index 0000000..cd019d6
--- /dev/null
@@ -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 (file)
index 0000000..21c940b
--- /dev/null
@@ -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 } } */
index de16639..07d8fa7 100644 (file)
@@ -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 (file)
index 0000000..7dba7f9
--- /dev/null
@@ -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} } */