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:
parent
52a64bd38e
commit
a6ab9fc087
18 changed files with 427 additions and 107 deletions
|
@ -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
|
||||
|
|
|
@ -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
69
gcc/config/sh/sh-c.c
Normal 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 (¤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");
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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")])
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
28
gcc/testsuite/gcc.dg/attr-isr-nosave_low_regs.c
Normal file
28
gcc/testsuite/gcc.dg/attr-isr-nosave_low_regs.c
Normal 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} } */
|
23
gcc/testsuite/gcc.dg/attr-isr-trap_exit.c
Normal file
23
gcc/testsuite/gcc.dg/attr-isr-trap_exit.c
Normal 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;
|
||||
}
|
||||
|
17
gcc/testsuite/gcc.dg/attr-isr-trapa.c
Normal file
17
gcc/testsuite/gcc.dg/attr-isr-trapa.c
Normal 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" } } */
|
18
gcc/testsuite/gcc.dg/attr-isr.c
Normal file
18
gcc/testsuite/gcc.dg/attr-isr.c
Normal 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} } */
|
20
gcc/testsuite/gcc.dg/pragma-isr-nosave_low_regs.c
Normal file
20
gcc/testsuite/gcc.dg/pragma-isr-nosave_low_regs.c
Normal 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} } */
|
17
gcc/testsuite/gcc.dg/pragma-isr-trap_exit.c
Normal file
17
gcc/testsuite/gcc.dg/pragma-isr-trap_exit.c
Normal 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} } */
|
17
gcc/testsuite/gcc.dg/pragma-isr-trapa.c
Normal file
17
gcc/testsuite/gcc.dg/pragma-isr-trapa.c
Normal 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" } } */
|
22
gcc/testsuite/gcc.dg/pragma-isr-trapa2.c
Normal file
22
gcc/testsuite/gcc.dg/pragma-isr-trapa2.c
Normal 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 } } */
|
|
@ -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();
|
||||
|
|
16
gcc/testsuite/gcc.dg/pragma-isr2.c
Normal file
16
gcc/testsuite/gcc.dg/pragma-isr2.c
Normal 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} } */
|
Loading…
Add table
Reference in a new issue