From 4408efce8bfbf2dc378dbc77416f5fd0d96b3f81 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Thu, 5 Jun 1997 09:52:34 -0600 Subject: [PATCH] sh.c (trap_exit, sp_switch): New variables. * sh.c (trap_exit, sp_switch): New variables. (print_operand, case '@'): If trap_exit is nonzero, then use a trapa instead of an rte/rts to exit the current function. (sh_expand_prologue): Switch stacks at function entry as needed. (sh_expand_epilogue): Similarly at function exit. (function_epilogue): Clear trap_exit and sp_switch too. (sh_valid_machine_decl_attribute): New function. * sh.h (VALID_MACHINE_DECL_ATTRIBUTE): Define. (sp_switch): Declare. * sh.md (sp_switch_1, sp_switch_2): New named patterns. From-SVN: r14148 --- gcc/config/sh/sh.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++-- gcc/config/sh/sh.h | 12 +++++++ gcc/config/sh/sh.md | 24 +++++++++++++ 3 files changed, 130 insertions(+), 3 deletions(-) diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index dd540b7..fb723ba 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -43,6 +43,16 @@ Boston, MA 02111-1307, USA. */ 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; @@ -160,7 +170,7 @@ print_operand_address (stream, x) according to modifier code. '.' print a .s if insn needs delay slot - '@' print rte or rts depending upon pragma interruptness + '@' print trap, rte or rts depending upon pragma interruptness '#' output a nop if there is nothing to put in the delay slot 'O' print a constant without the # 'R' print the LSW of a dp value - changes if in little endian @@ -181,7 +191,9 @@ print_operand (stream, x, code) fprintf (stream, ".s"); break; case '@': - if (pragma_interrupt) + if (trap_exit) + fprintf (stream, "trapa #%d", trap_exit); + else if (pragma_interrupt) fprintf (stream, "rte"); else fprintf (stream, "rts"); @@ -2670,6 +2682,10 @@ sh_expand_prologue () } } + /* If we're supposed to switch stacks at function entry, do so now. */ + if (sp_switch) + emit_insn (gen_sp_switch_1 ()); + push_regs (live_regs_mask, live_regs_mask2); output_stack_adjust (-get_frame_size (), stack_pointer_rtx, 3); @@ -2712,6 +2728,10 @@ sh_expand_epilogue () output_stack_adjust (extra_push + current_function_pretend_args_size, stack_pointer_rtx, 7); + + /* Switch back to the normal stack if necessary. */ + if (sp_switch) + emit_insn (gen_sp_switch_2 ()); } /* Clear variables at function end. */ @@ -2721,7 +2741,8 @@ function_epilogue (stream, size) FILE *stream; int size; { - pragma_interrupt = pragma_trapa = pragma_nosave_low_regs = 0; + trap_exit = pragma_interrupt = pragma_trapa = pragma_nosave_low_regs = 0; + sp_switch = NULL_RTX; } rtx @@ -2847,6 +2868,76 @@ handle_pragma (file, t) return retval; } +/* Return nonzero if ATTR is a valid attribute for DECL. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. + + Supported attributes: + + interrupt_handler -- specifies this function is an interrupt handler. + + sp_switch -- specifies an alternate stack for an interrupt handler + to run on. + + trap_exit -- use a trapa to exit an interrupt function intead of + an rte instruction. */ + +int +sh_valid_machine_decl_attribute (decl, attributes, attr, args) + tree decl; + tree attributes; + tree attr; + tree args; +{ + int retval = 0; + + if (TREE_CODE (decl) != FUNCTION_DECL) + return 0; + + if (is_attribute_p ("interrupt_handler", attr)) + { + pragma_interrupt = 1; + return 1; + } + + if (is_attribute_p ("sp_switch", attr)) + { + /* The sp_switch attribute only has meaning for interrupt functions. */ + if (!pragma_interrupt) + return 0; + + /* sp_switch must have an argument. */ + if (!args || TREE_CODE (args) != TREE_LIST) + return 0; + + /* The argument must be a constant string. */ + if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) + return 0; + + sp_switch = gen_rtx (SYMBOL_REF, VOIDmode, + TREE_STRING_POINTER (TREE_VALUE (args))); + return 1; + } + + if (is_attribute_p ("trap_exit", attr)) + { + /* The trap_exit attribute only has meaning for interrupt functions. */ + if (!pragma_interrupt) + return 0; + + /* trap_exit must have an argument. */ + if (!args || TREE_CODE (args) != TREE_LIST) + return 0; + + /* The argument must be a constant integer. */ + if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST) + return 0; + + trap_exit = TREE_INT_CST_LOW (TREE_VALUE (args)); + return 1; + } +} + /* Predicates used by the templates. */ diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index 022c9bc..ce5e26a 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -1639,6 +1639,18 @@ extern char *output_far_jump(); extern int pragma_interrupt; +/* Set to an RTX containing the address of the stack to switch to + for interrupt functions. */ +extern struct rtx_def *sp_switch; + +/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS + is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ +extern int sh_valid_machine_decl_attribute (); +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ +sh_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + + #define MOVE_RATIO (TARGET_SMALLCODE ? 2 : 16) /* Instructions with unfilled delay slots take up an extra two bytes for diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index e5ee868..d0f79ff 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -2827,3 +2827,27 @@ && REGNO (SUBREG_REG (operands[2])) >= FIRST_FP_REG)) && reg_unused_after (operands[0], insn)" "fmov.s @(%0,%1),%2") + +;; Switch to a new stack with its address in sp_switch (a SYMBOL_REF). */ +(define_insn "sp_switch_1" + [(const_int 1)] + "" + "* +{ + 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); + return \"mov r0,r15\"; +}" + [(set_attr "length" "10")]) + (set_attr "type" "move")]) + +;; Switch back to the original stack for interrupt funtions with the +;; sp_switch attribute. */ +(define_insn "sp_switch_2" + [(const_int 2)] + "" + "mov.l @r15+,r15\;mov.l @r15+,r0" + [(set_attr "length" "4")]) -- 2.7.4