re PR target/14798 (In case of SH target with -O2 option #pragma interrupt doesn't get resetted.)

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.

From-SVN: r110398
This commit is contained in:
J"orn Rennecke 2006-01-30 15:07:43 +00:00 committed by Joern Rennecke
parent 52a64bd38e
commit a6ab9fc087
18 changed files with 427 additions and 107 deletions

View 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

View 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

69
gcc/config/sh/sh-c.c Normal file
View file

@ -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");
}

View 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;
}
/* 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;
}

View 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;
/* Instructions with unfilled delay slots take up an
extra two bytes for the nop in the delay slot.

View 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")])

View 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 \

View 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

View file

@ -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} } */

View file

@ -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;
}

View file

@ -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" } } */

View file

@ -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} } */

View file

@ -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} } */

View file

@ -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} } */

View file

@ -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" } } */

View file

@ -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 } } */

View 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();

View file

@ -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} } */