aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog36
-rw-r--r--gcc/config.gcc5
-rw-r--r--gcc/config/sh/sh-c.c69
-rw-r--r--gcc/config/sh/sh.c198
-rw-r--r--gcc/config/sh/sh.h9
-rw-r--r--gcc/config/sh/sh.md21
-rw-r--r--gcc/config/sh/t-sh4
-rw-r--r--gcc/testsuite/ChangeLog12
-rw-r--r--gcc/testsuite/gcc.dg/attr-isr-nosave_low_regs.c28
-rw-r--r--gcc/testsuite/gcc.dg/attr-isr-trap_exit.c23
-rw-r--r--gcc/testsuite/gcc.dg/attr-isr-trapa.c17
-rw-r--r--gcc/testsuite/gcc.dg/attr-isr.c18
-rw-r--r--gcc/testsuite/gcc.dg/pragma-isr-nosave_low_regs.c20
-rw-r--r--gcc/testsuite/gcc.dg/pragma-isr-trap_exit.c17
-rw-r--r--gcc/testsuite/gcc.dg/pragma-isr-trapa.c17
-rw-r--r--gcc/testsuite/gcc.dg/pragma-isr-trapa2.c22
-rw-r--r--gcc/testsuite/gcc.dg/pragma-isr.c2
-rw-r--r--gcc/testsuite/gcc.dg/pragma-isr2.c16
18 files changed, 427 insertions, 107 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index dcd3684..0a44292 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 252f10c..0ac27c3 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 0000000..7b9ec1c
--- /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 <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");
+}
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index a9cafec..6dfe282 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 87117f4..72cd563 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 38cd3bd..e2e477f 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 c5eb397..db86ad1 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 c7b6411..56b8eae 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..5f3acdf
--- /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 0000000..880db37
--- /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 0000000..d176805
--- /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 0000000..113ac21
--- /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 0000000..5e04922
--- /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 0000000..9b3233a
--- /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 0000000..cd019d6
--- /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 0000000..21c940b
--- /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 de16639..07d8fa7 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 0000000..7dba7f9
--- /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} } */