This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

ARM: Support for interrupt functions - mk II


Hi Richard,

  Here is a revised patch to implement support for interrupt functions
  in the ARM backend.  This patch has the following additions and
  changes:

    * Much better register saving upon function entry.  I think my
      brain must have seized when I wrote the first version of this
      patch, since I completely forgot about the register banks, and
      made interrupt functions save every register that they corrupt.
      Now this only done for FIQ handlers that use any of r8 - r12.

    * Support for different types of ARM interrupt.  The interrupt
      attribute can now take an optional parameter which describes the
      kind of interrupt to be handled.  Possible values are: IRD, FIQ,
      ABORT, SWI and UNDEF.  This affects the instruction used to exit
      from the function, and the registers saved for FIQ handlers.

    * A workaround for the corruption of the static chain pointer in
      nested functions.  The compiler will now try to find a temporary
      register in which to save the static chain register whilst
      creating a stack frame, and if it cannot find one it will issue
      an error message.  (Rather than silently creating bad code).

    * A new target specific machine variable - the arm function type.
      This records the type of the current function (normal, interrupt
      handler, exception handler etc).  The value for this type is
      only computed once per function then tested in all the places
      where there used to be individual code for determining function
      properties.

  I hope that you like it!

Cheers
	Nick

2000-09-19  Nick Clifton  <nickc@redhat.com>

	* config/arm/arm.h (EXCEPTION_LR_REGNUM): Define.
	(STATIC_CHAIN_REGNUM): Use IP instead of r8.
	(enum arm_func_type): New enum type.
	(IS_VOLATILE): Define.
	(IS_NAKED): Define.
	(IS_INTERRUPT): Define.
	(machine_function): Add 'func_type' field.

	* config/arm/arm.c (arm_naked_function_p): Delete.
	(struct isr_attribute_arg): New structure type.
	(array isr_attribute_args): New static variable.
	(arm_isr_value): New function: Parses the argument to a
	function's interrupt attribute.
	(arm_compute_function_type): New function: Determine the type
	of the current function.
	(arm_current_func_type): New function: Returns the type of the
	current function.
	(use_return_insn): Use arm_func_type.  Do not use a return
	insn for interrupt handlers.
	(arm_valid_attribute_p): Accept "interrupt" or "irq" as a
	function attribute.
	(arm_comp_type_attributes): Check for mismatched interrupt
	attributes.
	(arm_function_ok_for_sibcall): Do not allow sibcall
	optimisations for interrupt handlers.
	(arm_valid_machine_decl_attribute): Allow "interrupt" or "irq"
	function attributes - with arguments.
	(print_multi_reg): Remove unnecessary parameter 'hat'.
	(arm_compute_save_reg_mask): New Function: Compute a bit mask
	of ARM integer registers that need to be saved upon function
	entry.
	(output_return_instruction): Call arm_compute_save_reg_mask.
	Generate correct function exit instruction for interrupt
	handlers.
	(arm_volatile_func): Delete.
	(output_arm_prologue): Emit comments describing type of the
	current function.
	(arm_output_epilogue): Call arm_compute_save_reg_mask.
	Generate correct function exit instruction for interrupt
	handlers.
	(arm_expand_prologue): Call arm_compute_save_reg_mask.
	(thumb_expand_prologue): Warn that Thumb encoded interrupt
	handlers are not supported.
	(arm_init_machine_status): Initialise 'func_type' to
	FT_UNKNOWN.
	(thumb_expand_prologue): Use arm_current_func_type.
	(output_thumb_prologue): Remove unneeded local variable
	'store_arg_regs'.

	* config/arm/arm-protos.h (arm_func_type): Add prototype.
	(arm_function_ok_for_sibcall): Add prototype.

	* extend.texi: Document "interrupt" and "naked" attributes for
	the ARM.  Document the optional parameter to the interrupt
	function attribute on the ARM.

Index: config/arm/arm.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/arm/arm.h,v
retrieving revision 1.84
diff -p -w -r1.84 arm.h
*** arm.h	2000/09/10 19:37:51	1.84
--- arm.h	2000/09/19 22:21:54
*************** extern const char * structure_size_strin
*** 888,897 ****
  /* The number of the last "lo" register (thumb).  */
  #define LAST_LO_REGNUM  	 7
  
  /* The native (Norcroft) Pascal compiler for the ARM passes the static chain
     as an invisible last argument (possible since varargs don't exist in
     Pascal), so the following is not true.  */
! #define STATIC_CHAIN_REGNUM	(TARGET_ARM ? 8 : 9)
  
  /* Define this to be where the real frame pointer is if it is not possible to
     work out the offset between the frame pointer and the automatic variables
--- 888,900 ----
  /* The number of the last "lo" register (thumb).  */
  #define LAST_LO_REGNUM  	 7
  
+ /* The register that holds the return address in exception handlers.  */
+ #define EXCEPTION_LR_REGNUM	2
+ 
  /* The native (Norcroft) Pascal compiler for the ARM passes the static chain
     as an invisible last argument (possible since varargs don't exist in
     Pascal), so the following is not true.  */
! #define STATIC_CHAIN_REGNUM	(TARGET_ARM ? 12 : 9)
  
  /* Define this to be where the real frame pointer is if it is not possible to
     work out the offset between the frame pointer and the automatic variables
*************** enum reg_class
*** 1376,1385 ****
  #define CALL_NORMAL		0x00000000	/* No special processing.  */
  #define CALL_LONG		0x00000001	/* Always call indirect.  */
  #define CALL_SHORT		0x00000002	/* Never call indirect.  */
  
! /* A C structure for machine-specific, per-function data.  This is added
!    to the cfun structure.  */
! struct machine_function
  {
    /* Records __builtin_return address.  */
    struct rtx_def *ra_rtx;
--- 1379,1412 ----
  #define CALL_NORMAL		0x00000000	/* No special processing.  */
  #define CALL_LONG		0x00000001	/* Always call indirect.  */
  #define CALL_SHORT		0x00000002	/* Never call indirect.  */
+ 
+ /* This enum describes the different types of function supported
+    by the ARM backend.  This is important for determine the
+    function prologue and epilogue sequences.  */
+ typedef enum arm_func_type
+ {
+   FT_UNKNOWN,		/* Ttpe has not yet been determined.  */
+   FT_NORMAL,		/* Your normal, straightforward function.  */
+   FT_INTERWORKED,	/* A function that supports interworking.  */
+   FT_NAKED,		/* A naked funciton - no prologue or epilogue.  */
+   FT_VOLATILE,		/* A volatile function - does not return.  */
+   FT_ISR,		/* An interrupt service routine.  */
+   FT_FIQ,		/* A fast interrupt service routine.  */
+   FT_EXCEPTION,		/* An ARM exception handler (subcase of ISR).  */
+   FT_EXCEPTION_HANDLER	/* A C++ exception handler.  */
+ }
+ arm_func_type;
  
! #define IS_VOLATILE     (arm_current_func_type () == FT_VOLATILE)
! #define IS_NAKED        (arm_current_func_type () == FT_NAKED)
! #define IS_INTERRUPT				\
!   (  arm_current_func_type () == FT_ISR		\
!   || arm_current_func_type () == FT_FIQ		\
!   || arm_current_func_type () == FT_EXCEPTION)
! 
! /* A C structure for machine-specific, per-function data.
!    This is added to the cfun structure.  */
! typedef struct machine_function
  {
    /* Records __builtin_return address.  */
    struct rtx_def *ra_rtx;
*************** struct machine_function
*** 1389,1395 ****
    int far_jump_used;
    /* Records if ARG_POINTER was ever live.  */
    int arg_pointer_live;
! };
  
  /* A C type for declaring a variable that is used as the first argument of
     `FUNCTION_ARG' and other related values.  For some target machines, the
--- 1416,1425 ----
    int far_jump_used;
    /* Records if ARG_POINTER was ever live.  */
    int arg_pointer_live;
!   /* Records the type of the current function.  */
!   arm_func_type func_type;
! }
! machine_function;
  
  /* A C type for declaring a variable that is used as the first argument of
     `FUNCTION_ARG' and other related values.  For some target machines, the
*************** typedef struct
*** 1598,1604 ****
     other its replacement, at the start of a routine.  */
  #define ARM_INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)		\
  {									\
!   int volatile_func = arm_volatile_func ();				\
    if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\
      (OFFSET) = 0;							\
    else if ((FROM) == FRAME_POINTER_REGNUM				\
--- 1628,1634 ----
     other its replacement, at the start of a routine.  */
  #define ARM_INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)		\
  {									\
!   int volatile_func = IS_VOLATILE;					\
    if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\
      (OFFSET) = 0;							\
    else if ((FROM) == FRAME_POINTER_REGNUM				\

Index: config/arm/arm.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/arm/arm.c,v
retrieving revision 1.107
diff -p -w -r1.107 arm.c
*** arm.c	2000/09/08 14:26:29	1.107
--- arm.c	2000/09/19 22:21:55
*************** typedef struct minipool_fixup   Mfix;
*** 53,84 ****
  #define Hint     HOST_WIDE_INT
  #define Mmode    enum machine_mode
  #define Ulong    unsigned long
  
  /* Forward function declarations.  */
  static void      arm_add_gc_roots 		PARAMS ((void));
  static int       arm_gen_constant		PARAMS ((enum rtx_code, Mmode, Hint, rtx, rtx, int, int));
- static int       arm_naked_function_p		PARAMS ((tree));
  static Ulong     bit_count 			PARAMS ((signed int));
  static int       const_ok_for_op 		PARAMS ((Hint, enum rtx_code));
  static int       eliminate_lr2ip		PARAMS ((rtx *));
  static rtx	 emit_multi_reg_push		PARAMS ((int));
  static rtx	 emit_sfm			PARAMS ((int, int));
! static const char * fp_const_from_val		PARAMS ((REAL_VALUE_TYPE *));
  static arm_cc    get_arm_condition_code		PARAMS ((rtx));
  static void      init_fpa_table			PARAMS ((void));
  static Hint      int_log2			PARAMS ((Hint));
  static rtx       is_jump_table 			PARAMS ((rtx));
! static const char * output_multi_immediate	PARAMS ((rtx *, const char *, const char *, int, Hint));
! static void      print_multi_reg		PARAMS ((FILE *, const char *, int, int, int));
  static Mmode     select_dominance_cc_mode	PARAMS ((rtx, rtx, Hint));
! static const char * shift_op			PARAMS ((rtx, Hint *));
  static void      arm_init_machine_status	PARAMS ((struct function *));
  static void      arm_mark_machine_status        PARAMS ((struct function *));
  static int       number_of_first_bit_set        PARAMS ((int));
  static void      replace_symbols_in_block       PARAMS ((tree, rtx, rtx));
  static void      thumb_exit                     PARAMS ((FILE *, int, rtx));
  static void      thumb_pushpop                  PARAMS ((FILE *, int, int));
! static const char * thumb_condition_code        PARAMS ((rtx, int));
  static rtx	 is_jump_table		        PARAMS ((rtx));
  static Hint	 get_jump_table_size	        PARAMS ((rtx));
  static Mnode *   move_minipool_fix_forward_ref  PARAMS ((Mnode *, Mnode *, Hint));
--- 53,85 ----
  #define Hint     HOST_WIDE_INT
  #define Mmode    enum machine_mode
  #define Ulong    unsigned long
+ #define Ccstar   const char *
+ #define AFT      arm_func_type
  
  /* Forward function declarations.  */
  static void      arm_add_gc_roots 		PARAMS ((void));
  static int       arm_gen_constant		PARAMS ((enum rtx_code, Mmode, Hint, rtx, rtx, int, int));
  static Ulong     bit_count 			PARAMS ((signed int));
  static int       const_ok_for_op 		PARAMS ((Hint, enum rtx_code));
  static int       eliminate_lr2ip		PARAMS ((rtx *));
  static rtx	 emit_multi_reg_push		PARAMS ((int));
  static rtx	 emit_sfm			PARAMS ((int, int));
! static Ccstar    fp_const_from_val		PARAMS ((REAL_VALUE_TYPE *));
  static arm_cc    get_arm_condition_code		PARAMS ((rtx));
  static void      init_fpa_table			PARAMS ((void));
  static Hint      int_log2			PARAMS ((Hint));
  static rtx       is_jump_table 			PARAMS ((rtx));
! static Ccstar    output_multi_immediate		PARAMS ((rtx *, Ccstar, Ccstar, int, Hint));
! static void      print_multi_reg		PARAMS ((FILE *, Ccstar, int, int));
  static Mmode     select_dominance_cc_mode	PARAMS ((rtx, rtx, Hint));
! static Ccstar    shift_op			PARAMS ((rtx, Hint *));
  static void      arm_init_machine_status	PARAMS ((struct function *));
  static void      arm_mark_machine_status        PARAMS ((struct function *));
  static int       number_of_first_bit_set        PARAMS ((int));
  static void      replace_symbols_in_block       PARAMS ((tree, rtx, rtx));
  static void      thumb_exit                     PARAMS ((FILE *, int, rtx));
  static void      thumb_pushpop                  PARAMS ((FILE *, int, int));
! static Ccstar    thumb_condition_code        	PARAMS ((rtx, int));
  static rtx	 is_jump_table		        PARAMS ((rtx));
  static Hint	 get_jump_table_size	        PARAMS ((rtx));
  static Mnode *   move_minipool_fix_forward_ref  PARAMS ((Mnode *, Mnode *, Hint));
*************** static void	 push_minipool_barrier	     
*** 94,103 ****
--- 95,109 ----
  static void	 push_minipool_fix		PARAMS ((rtx, Hint, rtx *, Mmode, rtx));
  static void	 note_invalid_constants	        PARAMS ((rtx, Hint));
  static int       current_file_function_operand	PARAMS ((rtx));
+ static Ulong     arm_compute_save_reg_mask	PARAMS ((void));
+ static AFT       arm_isr_value 			PARAMS ((tree));
+ static AFT 	 arm_compute_func_type		PARAMS ((void));
  
  #undef Hint
  #undef Mmode
  #undef Ulong
+ #undef Ccstar
+ #undef AFT
  
  /* The maximum number of insns skipped which will be conditionalised if
     possible.  */
*************** arm_add_gc_roots ()
*** 665,671 ****
--- 671,782 ----
    /* XXX: What about the minipool tables?  */
  }
  
+ typedef struct
+ {
+   const char * 	arg;
+   arm_func_type	return_value;
+ }
+ isr_attribute_arg;
+ 
+ static isr_attribute_arg isr_attribute_args [] =
+ {
+   { "IRQ",   FT_ISR },
+   { "irq",   FT_ISR },
+   { "FIQ",   FT_FIQ },
+   { "fiq",   FT_FIQ },
+   { "ABORT", FT_ISR },
+   { "abort", FT_ISR },
+   { "ABORT", FT_ISR },
+   { "abort", FT_ISR },
+   { "UNDEF", FT_EXCEPTION },
+   { "undef", FT_EXCEPTION },
+   { "SWI",   FT_EXCEPTION },
+   { "swi",   FT_EXCEPTION },
+   { NULL,    FT_NORMAL }
+ };
+ 
+ /* Returns the (interrupt) function type of the current
+    function, or zero if the type cannot be determined.  */
+ 
+ static arm_func_type
+ arm_isr_value (argument)
+      tree argument;
+ {
+   isr_attribute_arg * ptr;
+   const char *        arg;
+ 
+   /* No argument - default to IRQ.  */
+   if (argument == NULL_TREE)
+     return FT_ISR;
+ 
+   /* Get the value of the argument.  */
+   if (TREE_VALUE (argument) == NULL_TREE
+       || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)
+     return 0;
+ 
+   arg = TREE_STRING_POINTER (TREE_VALUE (argument));
+ 
+   /* Check it against the list of known arguments.  */
+   for (ptr = isr_attribute_args; ptr->arg != NULL; ptr ++)
+     if (strcmp (arg, ptr->arg) == 0)
+ 	return ptr->return_value;
+ 
+   /* An unrecognised interrupt type - just return 0 for now.  */
+   return 0;
+ }
+ 
+ /* Computes the type of the current function.  */
+ 
+ static arm_func_type
+ arm_compute_func_type ()
+ {
+   tree a;
+   tree attr;
+   
+   if (cfun->machine->eh_epilogue_sp_ofs != NULL_RTX)
+     return FT_EXCEPTION_HANDLER;
+ 
+   /* Decide if the current function is volatile.  Such functions
+      never return, and many memory cycles can be saved by not storing
+      register values that will never be needed again.  This optimization
+      was added to speed up context switching in a kernel application.  */
+   if (optimize > 0
+       && current_function_nothrow
+       && TREE_THIS_VOLATILE (current_function_decl))
+     return FT_VOLATILE;
+ 
+   if (TREE_CODE (current_function_decl) != FUNCTION_DECL)
+     abort ();
+ 
+   attr = DECL_MACHINE_ATTRIBUTES (current_function_decl);
+   
+   a = lookup_attribute ("naked", attr);
+   if (a != NULL_TREE)
+     return FT_NAKED;
+ 
+   a = lookup_attribute ("isr", attr);
+   if (a == NULL_TREE)
+     a = lookup_attribute ("interrupt", attr);
+   
+   if (a == NULL_TREE)
+     return TARGET_INTERWORK ? FT_INTERWORKED : FT_NORMAL;
+ 
+   return arm_isr_value (TREE_VALUE (a));
+ }
+ 
+ /* Returns the type of the current function.  */
+ 
+ arm_func_type
+ arm_current_func_type ()
+ {
+   if (cfun->machine->func_type == FT_UNKNOWN)
+     cfun->machine->func_type = arm_compute_func_type ();
+ 
+   return cfun->machine->func_type;
+ }
+ 
  /* Return 1 if it is possible to return using a single instruction.  */
+ 
  int
  use_return_insn (iscond)
       int iscond;
*************** use_return_insn (iscond)
*** 708,719 ****
        if (regs_ever_live[regno] && ! call_used_regs[regno])
  	return 0;
  
    /* If a function is naked, don't use the "return" insn.  */
-   if (arm_naked_function_p (current_function_decl))
      return 0;
  
    return 1;
  }
  
  /* Return TRUE if int I is a valid immediate ARM constant.  */
  
--- 819,840 ----
        if (regs_ever_live[regno] && ! call_used_regs[regno])
  	return 0;
  
+   switch (arm_current_func_type ())
+     {
+     case FT_NAKED:
        /* If a function is naked, don't use the "return" insn.  */
        return 0;
  
+     case FT_ISR:
+     case FT_FIQ:
+     case FT_EXCEPTION:
+       /* If the function is an ISR, then we need a special exit sequence.  */
+       return 0;
+ 
+     default:
        return 1;
      }
+ }
  
  /* Return TRUE if int I is a valid immediate ARM constant.  */
  
*************** arm_valid_type_attribute_p (type, attrib
*** 1662,1667 ****
--- 1783,1794 ----
    if (is_attribute_p ("short_call", identifier))
      return (args == NULL_TREE);
    
+   /* Interrupt Service Routines have special
+      prologue and epilogue requirements.  */ 
+   if (is_attribute_p ("isr", identifier)
+       || is_attribute_p ("interrupt", identifier))
+     return arm_isr_value (args);
+  
    return 0;
  }
  
*************** arm_comp_type_attributes (type1, type2)
*** 1697,1702 ****
--- 1824,1839 ----
  	return 0;
      }
    
+   /* Check for mismatched ISR attribute.  */
+   l1 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type1)) != NULL;
+   if (! l1)
+     l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type1)) != NULL;
+   l2 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type2)) != NULL;
+   if (! l2)
+     l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type2)) != NULL;
+   if (l1 != l2)
+     return 0;
+   
    return 1;
  }
  
*************** arm_function_ok_for_sibcall (decl)
*** 1843,1848 ****
--- 1980,1990 ----
    if (decl == NULL || TARGET_THUMB)
      return 0;
  
+   /* Never tailcall from an ISR routine -
+      it needs a special exit sequence.  */
+   if (IS_INTERRUPT)
+     return 0;
+ 
    /* Get the calling method.  */
    if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
      call_type = CALL_SHORT;
*************** multi_register_push (op, mode)
*** 3788,3793 ****
--- 3930,3938 ----
       don't output any prologue or epilogue code, the user is assumed
       to do the right thing.
     
+    isr:
+      Interrupt Service Routine.
+ 
     interfacearm:
       Always assume that this function will be entered in ARM mode,
       not Thumb mode, and that the caller wishes to be returned to in
*************** arm_valid_machine_decl_attribute (decl, 
*** 3798,3803 ****
--- 3943,3954 ----
       tree attr;
       tree args;
  {
+   /* The interrupt attribute can take args, so check for it before
+      rejecting other attributes on the grounds that they did have args.  */
+   if (is_attribute_p ("isr", attr)
+       || is_attribute_p ("interrupt", attr))
+     return TREE_CODE (decl) == FUNCTION_DECL;
+   
    if (args != NULL_TREE)
      return 0;
  
*************** arm_valid_machine_decl_attribute (decl, 
*** 3812,3830 ****
    return 0;
  }
  
- /* Return non-zero if FUNC is a naked function.  */
- static int
- arm_naked_function_p (func)
-      tree func;
- {
-   tree a;
- 
-   if (TREE_CODE (func) != FUNCTION_DECL)
-     abort ();
-   
-   a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func));
-   return a != NULL_TREE;
- }
  
  /* Routines for use in generating RTL.  */
  rtx
--- 3963,3968 ----
*************** fp_const_from_val (r)
*** 5719,5734 ****
  
  /* Output the operands of a LDM/STM instruction to STREAM.
     MASK is the ARM register set mask of which only bits 0-15 are important.
!    INSTR is the possibly suffixed base register.  HAT unequals zero if a hat
!    must follow the register list.  */
  
  static void
! print_multi_reg (stream, instr, reg, mask, hat)
       FILE * stream;
       const char * instr;
       int reg;
       int mask;
-      int hat;
  {
    int i;
    int not_first = FALSE;
--- 5857,5871 ----
  
  /* Output the operands of a LDM/STM instruction to STREAM.
     MASK is the ARM register set mask of which only bits 0-15 are important.
!    REG is the base register, either the frame pointer or the stack pointer,
!    INSTR is the possibly suffixed load or store instruction.   */
  
  static void
! print_multi_reg (stream, instr, reg, mask)
       FILE * stream;
       const char * instr;
       int reg;
       int mask;
  {
    int i;
    int not_first = FALSE;
*************** print_multi_reg (stream, instr, reg, mas
*** 5747,5753 ****
  	not_first = TRUE;
        }
  
!   fprintf (stream, "}%s\n", hat ? "^" : "");
  }
  
  /* Output a 'call' insn.  */
--- 5884,5890 ----
  	not_first = TRUE;
        }
  
!   fprintf (stream, "}%s\n", TARGET_APCS_32 ? "" : "^");
  }
  
  /* Output a 'call' insn.  */
*************** output_ascii_pseudo_op (stream, p, len)
*** 6519,6524 ****
--- 6656,6738 ----
    fputs ("\"\n", stream);
  }
  
+ /* Compute a bit mask of which registers need to be
+    saved on the stack for the current function.  */
+ 
+ static unsigned long
+ arm_compute_save_reg_mask ()
+ {
+   unsigned int save_reg_mask = 0;
+   unsigned int reg;
+ 
+   switch (arm_current_func_type ())
+     {
+     case FT_ISR:
+     case FT_EXCEPTION:
+       /* Interrupt and exception handlers work with their own set of
+ 	 banked registers, so there is no need to save any of them
+ 	 onto the stack upon function entry.  */
+       break;
+ 
+     case FT_FIQ:
+       /* FIQ handlers only have registers r0 - r7 banked, so
+ 	 if they corrupt any others, they must save them.  */
+       for (reg = 8; reg <= 12; reg++)
+ 	if (regs_ever_live[reg])
+ 	  save_reg_mask |= (1 << reg);
+       break;
+ 
+     default:
+       /* In the normal case we need only save those registers which
+ 	 are call saved and which are used by this function.  */
+       for (reg = 0; reg <= 10; reg++)
+ 	if (regs_ever_live[reg] && ! call_used_regs [reg])
+ 	  save_reg_mask |= (1 << reg);
+ 
+       /* Handle the frame pointer as a special case.  */
+       if (! TARGET_APCS_FRAME
+ 	  && ! frame_pointer_needed
+ 	  && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
+ 	  && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
+ 	save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
+ 
+       /* Fall through.  */
+ 
+     case FT_VOLATILE:
+       /* Volatile functions do not return, so there is no need to
+ 	 save any of the call saved registers.   Not sure about
+ 	 the PIC base register though, so handle it here, just in
+ 	 case.  */
+ 
+       /* If we aren't loading the PIC register, don't
+ 	 stack it even though it may be live.  */
+       if (flag_pic
+ 	  && ! TARGET_SINGLE_PIC_BASE 
+ 	  && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
+ 	save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
+     }
+ 
+   /* If we are creating a stack frame, then we must save the frame pointer,
+      IP (which will hold the old stack pointer), LR and the PC.  */
+   if (frame_pointer_needed)
+     save_reg_mask |=
+ 	(1 << ARM_HARD_FRAME_POINTER_REGNUM)
+ 	| (1 << IP_REGNUM)
+ 	| (1 << LR_REGNUM)
+ 	| (1 << PC_REGNUM);
+   /* If we use the link register we must save it on the stack.
+      In addition if a DI mode load/store multiple instruction is generated
+      somewhere in the function, and the base register is r3, then r4 can
+      become a live register without LR doing so.  In order to generate this
+      instruction we will be forced to corrupt LR, so we must save it here.  */
+   else if (save_reg_mask || regs_ever_live [LR_REGNUM])
+     save_reg_mask |= 1 << LR_REGNUM;
+ 
+   return save_reg_mask;
+ }
+ 
+ /* Generate a function exit sequence.  If REALLY_RETURN is true, then do
+    everything bar the final return instruction.  */
  
  const char *
  output_return_instruction (operand, really_return, reverse)
*************** output_return_instruction (operand, real
*** 6526,6542 ****
       int really_return;
       int reverse;
  {
    char instr[100];
!   int reg, live_regs = 0;
!   int volatile_func = arm_volatile_func ();
  
    /* If a function is naked, don't use the "return" insn.  */
-   if (arm_naked_function_p (current_function_decl))
      return "";
    
!   return_used_this_function = 1;
!   
!   if (TARGET_ABORT_NORETURN && volatile_func)
      {
        /* If this function was declared non-returning, and we have found a tail 
  	 call, then we have to trust that the called function won't return.  */
--- 6740,6761 ----
       int really_return;
       int reverse;
  {
+   char conditional[10];
    char instr[100];
!   int reg;
!   unsigned long live_regs_mask;
! 
!   /* Construct the conditional part of the instruction(s) to be emitted.  */
!   sprintf (conditional, "%%?%%%c0", reverse ? 'D' : 'd');
    
+   switch (arm_current_func_type ())
+     {
+     case FT_NAKED:
        /* If a function is naked, don't use the "return" insn.  */
        return "";
    
!     case FT_VOLATILE:
!       if (TARGET_ABORT_NORETURN)
  	{
  	  /* If this function was declared non-returning, and we have found a tail 
  	     call, then we have to trust that the called function won't return.  */
*************** output_return_instruction (operand, real
*** 6549,6690 ****
  	  ops[1] = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" 
  				       : "abort");
  	  assemble_external_libcall (ops[1]);
! 	  output_asm_insn (reverse ? "bl%D0\t%a1" : "bl%d0\t%a1", ops);
  	}
!       
        return "";
      }
        
    if (current_function_calls_alloca && ! really_return)
      abort ();
-   
-   for (reg = 0; reg <= 10; reg++)
-     if (regs_ever_live[reg] && ! call_used_regs[reg])
-       live_regs++;
- 
-   if (! TARGET_APCS_FRAME
-       && ! frame_pointer_needed
-       && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
-       && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
-     live_regs++;
  
!   if (flag_pic && ! TARGET_SINGLE_PIC_BASE
!       && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
!     live_regs++;
! 
!   if (live_regs || regs_ever_live[LR_REGNUM])
!     live_regs++;
! 
!   if (frame_pointer_needed)
!     live_regs += 4;
  
    /* On some ARM architectures it is faster to use LDR rather than LDM to
       load a single register.  On other architectures, the cost is the same.  */
!   if (live_regs == 1
!       && regs_ever_live[LR_REGNUM]
        && ! really_return)
!     output_asm_insn (reverse ? "ldr%?%D0\t%|lr, [%|sp], #4" 
! 		     : "ldr%?%d0\t%|lr, [%|sp], #4", &operand);
!   else if (live_regs == 1
! 	   && regs_ever_live[LR_REGNUM]
  	   && TARGET_APCS_32)
!     output_asm_insn (reverse ? "ldr%?%D0\t%|pc, [%|sp], #4"
! 		     : "ldr%?%d0\t%|pc, [%|sp], #4", &operand);
!   else if (live_regs)
      {
!       if (! regs_ever_live[LR_REGNUM])
!         live_regs++;
  
        if (frame_pointer_needed)
!         strcpy (instr,
! 		reverse ? "ldm%?%D0ea\t%|fp, {" : "ldm%?%d0ea\t%|fp, {");
        else
!         strcpy (instr, 
! 		reverse ? "ldm%?%D0fd\t%|sp!, {" : "ldm%?%d0fd\t%|sp!, {");
  
!       for (reg = 0; reg <= 10; reg++)
!         if (regs_ever_live[reg]
! 	    && (! call_used_regs[reg]
! 		|| (flag_pic && ! TARGET_SINGLE_PIC_BASE
! 		    && reg == PIC_OFFSET_TABLE_REGNUM)))
            {
  	    strcat (instr, "%|");
              strcat (instr, reg_names[reg]);
- 	    if (--live_regs)
                strcat (instr, ", ");
            }
  
!       if (frame_pointer_needed)
          {
! 	  strcat (instr, "%|");
!           strcat (instr, reg_names[11]);
!           strcat (instr, ", ");
! 	  strcat (instr, "%|");
!           strcat (instr, reg_names[13]);
!           strcat (instr, ", ");
! 	  strcat (instr, "%|");
! 	  strcat (instr, TARGET_INTERWORK || (! really_return)
! 		  ? reg_names[LR_REGNUM] : reg_names[PC_REGNUM] );
          }
        else
  	{
- 	  if (! TARGET_APCS_FRAME
- 	      && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
- 	      && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
- 	    {
- 	      strcat (instr, "%|");
- 	      strcat (instr, reg_names[HARD_FRAME_POINTER_REGNUM]);
- 	      strcat (instr, ", ");
- 	    }
- 	  
  	  strcat (instr, "%|");
  	  
! 	  if (TARGET_INTERWORK && really_return)
! 	    strcat (instr, reg_names[IP_REGNUM]);
  	  else
! 	    strcat (instr, really_return ? reg_names[PC_REGNUM] : reg_names[LR_REGNUM]);
! 	}
        
        strcat (instr, (TARGET_APCS_32 || !really_return) ? "}" : "}^");
!       output_asm_insn (instr, &operand);
  
!       if (TARGET_INTERWORK && really_return)
  	{
! 	  strcpy (instr, "bx%?");
! 	  strcat (instr, reverse ? "%D0" : "%d0");
! 	  strcat (instr, "\t%|");
! 	  strcat (instr, frame_pointer_needed ? "lr" : "ip");
  
  	  output_asm_insn (instr, & operand);
  	}
      }
    else if (really_return)
      {
!       if (TARGET_INTERWORK)
! 	sprintf (instr, "bx%%?%%%s0\t%%|lr", reverse ? "D" : "d");
        else
! 	sprintf (instr, "mov%%?%%%s0%s\t%%|pc, %%|lr",
! 		 reverse ? "D" : "d", TARGET_APCS_32 ? "" : "s");
        
        output_asm_insn (instr, & operand);
-     }
  
    return "";
  }
  
- /* Return nonzero if optimizing and the current function is volatile.
-    Such functions never return, and many memory cycles can be saved
-    by not storing register values that will never be needed again.
-    This optimization was added to speed up context switching in a
-    kernel application.  */
- int
- arm_volatile_func ()
- {
-   return (optimize > 0
- 	  && current_function_nothrow
- 	  && TREE_THIS_VOLATILE (current_function_decl));
- }
- 
  /* Write the function name into the code section, directly preceding
     the function prologue.
  
--- 6768,6926 ----
  	      ops[1] = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" 
  					   : "abort");
  	      assemble_external_libcall (ops[1]);
! 	      sprintf (instr, "bl%s\t%%a1", conditional);
! 	      output_asm_insn (instr, ops);
  	    }
! 	}
        return "";
+ 
+     default:
+       break;
      }
        
    if (current_function_calls_alloca && ! really_return)
      abort ();
    
!   return_used_this_function = 1;
!   live_regs_mask = arm_compute_save_reg_mask ();
  
    /* On some ARM architectures it is faster to use LDR rather than LDM to
       load a single register.  On other architectures, the cost is the same.  */
!   if ((live_regs_mask  == (1 << LR_REGNUM))
        && ! really_return)
!     {
!       sprintf (instr, "ldr%s\t%%|lr, [%%|sp], #4", conditional);
!     }
!   else if ((live_regs_mask  == (1 << LR_REGNUM))
  	   && TARGET_APCS_32)
!     {
!       sprintf (instr, "ldr%s\t%%|pc, [%%|sp], #4", conditional);
!     }
!   else if (live_regs_mask)
      {
!       if ((live_regs_mask & (1 << IP_REGNUM)) == (1 << IP_REGNUM))
! 	/* There are two possible reasons for the IP register being saved.
! 	   Either a stack frame was created, in which case IP contains the
! 	   old stack pointer, or an ISR routine corrupted it.  If this in an
! 	   ISR routine then just restore IP, otherwise restore IP into SP.  */
! 	if (! IS_INTERRUPT)
! 	  {
! 	    live_regs_mask &= ~ (1 << IP_REGNUM);
! 	    live_regs_mask |=   (1 << SP_REGNUM);
! 	  }
  
+       /* Generate the load multiple instruction to restore the registers.  */
        if (frame_pointer_needed)
! 	sprintf (instr, "ldm%sea\t%%|fp, {", conditional);
        else
! 	sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
  
!       for (reg = 0; reg <= SP_REGNUM; reg++)
! 	if (live_regs_mask & (1 << reg))
  	  {
  	    strcat (instr, "%|");
  	    strcat (instr, reg_names[reg]);
  	    strcat (instr, ", ");
  	  }
  
!       if ((live_regs_mask & (1 << LR_REGNUM)) == 0)
  	{
! 	  /* If we are not restoring the LR register then we will
! 	     have added one too many commas to the list above.
! 	     Replace it with a closing brace.  */
! 	  instr [strlen (instr) - 2] =  '}';
  	}
        else
  	{
  	  strcat (instr, "%|");
  
! 	  /* At this point there should only be one or two registers left in
! 	     live_regs_mask: always LR, and possibly PC if we created a stack
! 	     frame.  LR contains the return address.  If we do not have any
! 	     special requirements for function exit (eg interworking, or ISR)
! 	     then we can load this value directly into the PC and save an
! 	     instruction.  */
! 	  if (! TARGET_INTERWORK
! 	      && ! IS_INTERRUPT
! 	      && really_return)
! 	    strcat (instr, reg_names [PC_REGNUM]);
  	  else
! 	    strcat (instr, reg_names [LR_REGNUM]);
  
  	  strcat (instr, (TARGET_APCS_32 || !really_return) ? "}" : "}^");
! 	}
  
!       if (really_return)
! 	{
! 	  /* See if we need to generate an extra instruction to
! 	     perform the actual function return.  */
! 	  switch (arm_current_func_type ())
  	    {
! 	    case FT_ISR:
! 	    case FT_FIQ:
! 	      output_asm_insn (instr, & operand);
! 
! 	      strcpy (instr, "sub");
! 	      strcat (instr, conditional);
! 	      strcat (instr, "s\t%|pc, %|lr, #4");
! 	      break;
! 
! 	    case FT_EXCEPTION:
! 	      output_asm_insn (instr, & operand);
  
+ 	      strcpy (instr, "mov");
+ 	      strcat (instr, conditional);
+ 	      strcat (instr, "s\t%|pc, %|lr");
+ 	      break;
+ 
+ 	    case FT_INTERWORKED:
  	      output_asm_insn (instr, & operand);
+ 
+ 	      strcpy (instr, "bx");
+ 	      strcat (instr, conditional);
+ 	      strcat (instr, "\t%|lr");
+ 	      break;
+ 
+ 	    default:
+ 	      /* The return has already been handled
+ 		 by loading the LR into the PC.  */
+ 	      break;
+ 	    }
  	}
      }
    else if (really_return)
      {
!       switch (arm_current_func_type ())
! 	{
! 	case FT_ISR:
! 	case FT_FIQ:
! 	  sprintf (instr, "sub%ss\t%%|pc, %%|lr, #4", conditional);
! 	  break;
! 
! 	case FT_INTERWORKED:
! 	  sprintf (instr, "bx%s\t%%|lr", conditional);
! 	  break;
! 
! 	case FT_EXCEPTION:
! 	  sprintf (instr, "mov%ss\t%%|pc, %%|lr", conditional);
! 	  break;
! 
! 	default:
! 	  sprintf (instr, "mov%s%s\t%%|pc, %%|lr",
! 		   conditional, TARGET_APCS_32 ? "" : "s");
! 	  break;
! 	}
!     }
    else
!     /* Nothing to load off the stack, and
!        no return instruction to generate.  */
!     return "";
  
    output_asm_insn (instr, & operand);
        
    return "";
  }
  
  /* Write the function name into the code section, directly preceding
     the function prologue.
  
*************** arm_poke_function_name (stream, name)
*** 6729,6808 ****
    x = GEN_INT (HOST_UINT(0xff000000) + alignlength);
    ASM_OUTPUT_INT (stream, x);
  }
  
- /* The amount of stack adjustment that happens here, in output_return and in
-    output_epilogue must be exactly the same as was calculated during reload,
-    or things will point to the wrong place.  The only time we can safely
-    ignore this constraint is when a function has no arguments on the stack,
-    no stack frame requirement and no live registers execpt for `lr'.  If we
-    can guarantee that by making all function calls into tail calls and that
-    lr is not clobbered in any other way, then there is no need to push lr
-    onto the stack.  */
  void
  output_arm_prologue (f, frame_size)
       FILE * f;
       int frame_size;
  {
!   int reg, live_regs_mask = 0;
!   int volatile_func = arm_volatile_func ();
! 
!   /* Nonzero if we must stuff some register arguments onto the stack as if
!      they were passed there.  */
!   int store_arg_regs = 0;
! 
    if (arm_ccfsm_state || arm_target_insn)
!     abort ();					/* Sanity check.  */
  
!   if (arm_naked_function_p (current_function_decl))
      return;
! 
!   return_used_this_function = 0;
    
    asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %d\n",
  	       current_function_args_size,
  	       current_function_pretend_args_size, frame_size);
    asm_fprintf (f, "\t%@ frame_needed = %d, current_function_anonymous_args = %d\n",
  	       frame_pointer_needed,
  	       current_function_anonymous_args);
  
-   if (volatile_func)
-     asm_fprintf (f, "\t%@ Volatile function.\n");
- 
-   if (current_function_anonymous_args && current_function_pretend_args_size)
-     store_arg_regs = 1;
- 
-   for (reg = 0; reg <= 10; reg++)
-     if (regs_ever_live[reg] && ! call_used_regs[reg])
-       live_regs_mask |= (1 << reg);
- 
-   if (! TARGET_APCS_FRAME
-       && ! frame_pointer_needed
-       && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
-       && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
-     live_regs_mask |= (1 << HARD_FRAME_POINTER_REGNUM);
- 
-   if (flag_pic && ! TARGET_SINGLE_PIC_BASE
-       && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
-     live_regs_mask |= (1 << PIC_OFFSET_TABLE_REGNUM);
- 
-   if (frame_pointer_needed)
-     live_regs_mask |= 0xD800;
-   else if (regs_ever_live[LR_REGNUM])
-     {
-       live_regs_mask |= 1 << LR_REGNUM;
-     }
- 
-   if (live_regs_mask)
-     /* If a di mode load/store multiple is used, and the base register
-        is r3, then r4 can become an ever live register without lr
-        doing so,  in this case we need to push lr as well, or we
-        will fail to get a proper return.  */
-     live_regs_mask |= 1 << LR_REGNUM;
- 
  #ifdef AOF_ASSEMBLER
    if (flag_pic)
      asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, PIC_OFFSET_TABLE_REGNUM);
  #endif
  }
  
  const char *
--- 6965,7027 ----
    x = GEN_INT (HOST_UINT(0xff000000) + alignlength);
    ASM_OUTPUT_INT (stream, x);
  }
+ 
+ /* Place some comments into the assembler stream
+    describing the current function.  */
  
  void
  output_arm_prologue (f, frame_size)
       FILE * f;
       int frame_size;
  {
!   /* Sanity check.  */
    if (arm_ccfsm_state || arm_target_insn)
!     abort ();
  
!   switch (arm_current_func_type ())
!     {
!     default:
!     case FT_NORMAL:
!       if (current_function_needs_context)
! 	asm_fprintf (f, "\t%@ Nested Function (that uses the static chain).\n");
!       break;
!     case FT_INTERWORKED:
!       asm_fprintf (f, "\t%@ Function supports interworking.\n");
!       break;
!     case FT_NAKED:
!       asm_fprintf (f, "\t%@ Naked Function: prologue and epilogue provided by programmer.\n");
        return;
!     case FT_VOLATILE:
!       asm_fprintf (f, "\t%@ Volatile: function does not return.\n");
!       break;
!     case FT_ISR:
!       asm_fprintf (f, "\t%@ Interrupt Service Routine.\n");
!       break;
!     case FT_FIQ:
!       asm_fprintf (f, "\t%@ Fast Interrupt Service Routine.\n");
!       break;
!     case FT_EXCEPTION:
!       asm_fprintf (f, "\t%@ ARM Exception Handler.\n");
!       break;
!     case FT_EXCEPTION_HANDLER:
!       asm_fprintf (f, "\t%@ C++ Exception Handler.\n");
!       break;
!     }
    
    asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %d\n",
  	       current_function_args_size,
  	       current_function_pretend_args_size, frame_size);
+   
    asm_fprintf (f, "\t%@ frame_needed = %d, current_function_anonymous_args = %d\n",
  	       frame_pointer_needed,
  	       current_function_anonymous_args);
    
  #ifdef AOF_ASSEMBLER
    if (flag_pic)
      asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, PIC_OFFSET_TABLE_REGNUM);
  #endif
+ 
+   return_used_this_function = 0;  
  }
  
  const char *
*************** arm_output_epilogue (really_return)
*** 6810,6876 ****
       int really_return;
  {
    int reg;
!   int live_regs_mask = 0;
    /* If we need this, then it will always be at least this much.  */
    int floats_offset = 12;
    rtx operands[3];
    int frame_size = get_frame_size ();
-   rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
    FILE * f = asm_out_file;
!   int volatile_func = arm_volatile_func ();
!   int return_regnum;
  
    if (use_return_insn (FALSE) && return_used_this_function)
      return "";
  
    /* Naked functions don't have epilogues.  */
-   if (arm_naked_function_p (current_function_decl))
      return "";
  
!   /* If we are throwing an exception, the address we want to jump to is in
!      R1; otherwise, it's in LR.  */
!   return_regnum = eh_ofs ? 2 : LR_REGNUM;
! 
!   /* If we are throwing an exception, then we really must be doing a return,
!      so we can't tail-call.  */
!   if (eh_ofs && ! really_return)
      abort();
  
    /* A volatile function should never return.  Call abort.  */
!   if (TARGET_ABORT_NORETURN && volatile_func)
      {
        rtx op;
        op = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" : "abort");
        assemble_external_libcall (op);
        output_asm_insn ("bl\t%a0", &op);
        return "";
      }
  
!   for (reg = 0; reg <= 10; reg++)
!     if (regs_ever_live[reg] && ! call_used_regs[reg])
!       {
!         live_regs_mask |= (1 << reg);
! 	floats_offset += 4;
        }
  
!   /* Handle the frame pointer as a special case.  */
!   if (! TARGET_APCS_FRAME
!       && ! frame_pointer_needed
!       && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
!       && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
!     {
!       live_regs_mask |= (1 << HARD_FRAME_POINTER_REGNUM);
!       floats_offset += 4;
!     }
  
!   /* If we aren't loading the PIC register, don't stack it even though it may
!      be live.  */
!   if (flag_pic && ! TARGET_SINGLE_PIC_BASE 
!       && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
!     {
!       live_regs_mask |= (1 << PIC_OFFSET_TABLE_REGNUM);
        floats_offset += 4;
-     }
  
    if (frame_pointer_needed)
      {
--- 7029,7082 ----
       int really_return;
  {
    int reg;
!   unsigned long live_regs_mask;
    /* If we need this, then it will always be at least this much.  */
    int floats_offset = 12;
    rtx operands[3];
    int frame_size = get_frame_size ();
    FILE * f = asm_out_file;
!   rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
  
    if (use_return_insn (FALSE) && return_used_this_function)
      return "";
  
+   switch (arm_current_func_type ())
+     {
+     case FT_NAKED:
        /* Naked functions don't have epilogues.  */
        return "";
  
!     case FT_EXCEPTION_HANDLER:
!       /* If we are throwing an exception, then we really must
! 	 be doing a return,  so we can't tail-call.  */
!       if (! really_return)
  	abort ();
+       break;
  
+     case FT_VOLATILE:
        /* A volatile function should never return.  Call abort.  */
!       if (TARGET_ABORT_NORETURN)
  	{
  	  rtx op;
+ 	  
  	  op = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" : "abort");
  	  assemble_external_libcall (op);
  	  output_asm_insn ("bl\t%a0", &op);
+ 	  
  	  return "";
  	}
+       break;
        
!     default:
!       break;
      }
    
!   live_regs_mask = arm_compute_save_reg_mask ();
    
!   /* Compute how far away the floats will be.  */
!   for (reg = 0; reg <= LAST_ARM_REGNUM; reg ++)
!     if (live_regs_mask & (1 << reg))
        floats_offset += 4;
    
    if (frame_pointer_needed)
      {
*************** arm_output_epilogue (really_return)
*** 6919,6954 ****
  			 FP_REGNUM, floats_offset);
  	}
        
!       if (TARGET_INTERWORK)
! 	{
! 	  live_regs_mask |= 0x6800;
! 	  print_multi_reg (f, "ldmea\t%r", FP_REGNUM, live_regs_mask, FALSE);
! 	  if (eh_ofs)
! 	    asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
! 			 REGNO (eh_ofs));
! 	  if (really_return)
! 	    asm_fprintf (f, "\tbx\t%r\n", return_regnum);
! 	}
!       else if (eh_ofs || ! really_return)
! 	{
! 	  live_regs_mask |= 0x6800;
! 	  print_multi_reg (f, "ldmea\t%r", FP_REGNUM, live_regs_mask, FALSE);
! 	  if (eh_ofs)
! 	    {
! 	      asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
! 			   REGNO (eh_ofs));
! 	      /* Even in 26-bit mode we do a mov (rather than a movs)
! 		 because we don't have the PSR bits set in the
! 		 address.  */
! 	      asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum);
! 	    }
! 	}
        else
! 	{
! 	  live_regs_mask |= 0xA800;
! 	  print_multi_reg (f, "ldmea\t%r", FP_REGNUM, live_regs_mask,
! 			   TARGET_APCS_32 ? FALSE : TRUE);
! 	}
      }
    else
      {
--- 7125,7151 ----
  			 FP_REGNUM, floats_offset);
  	}
        
!       /* live_regs_mask should contain the IP, which at the time of stack
! 	 frame generation actually contains the old stack pointer.  So a
! 	 quick way to unwind the stack is just pop the IP register directly
! 	 into the stack pointer.  */
!       if ((live_regs_mask & (1 << IP_REGNUM)) == 0)
! 	abort ();
!       live_regs_mask &= ~ (1 << IP_REGNUM);
!       live_regs_mask |=   (1 << SP_REGNUM);
! 
!       /* There are two registers left in live_regs_mask - LR and PC.  We
! 	 only need to restore the LR register (the return address), but to
! 	 save time we can load it directly into the PC, unless we need a
! 	 special function exit sequence, or we are not really returning.  */
!       if (really_return && arm_current_func_type () == FT_NORMAL)
! 	/* Delete the LR from the register mask, so that the LR on
! 	   the stack is loaded into the PC in the register mask.  */
! 	live_regs_mask &= ~ (1 << LR_REGNUM);
        else
! 	live_regs_mask &= ~ (1 << PC_REGNUM);
!       
!       print_multi_reg (f, "ldmea\t%r", FP_REGNUM, live_regs_mask);
      }
    else
      {
*************** arm_output_epilogue (really_return)
*** 7000,7077 ****
  			 start_reg, reg - start_reg, SP_REGNUM);
  	}
  
!       if (current_function_pretend_args_size == 0 && regs_ever_live[LR_REGNUM])
  	{
! 	  if (TARGET_INTERWORK)
! 	    {
! 	      live_regs_mask |= 1 << LR_REGNUM;
  
! 	      /* Handle LR on its own.  */
  	      if (live_regs_mask == (1 << LR_REGNUM))
  		{
  		  if (eh_ofs)
- 		    asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM,
- 				 SP_REGNUM);
- 		  else
- 		    asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM,
- 				 SP_REGNUM);
- 		}
- 	      else if (live_regs_mask != 0)
- 		print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, live_regs_mask,
- 				 FALSE);
- 
- 	      if (eh_ofs)
- 		asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
- 			     REGNO (eh_ofs));
- 
- 	      if (really_return)
- 		asm_fprintf (f, "\tbx\t%r\n", return_regnum);
- 	    }
- 	  else if (eh_ofs)
- 	    {
- 	      if (live_regs_mask == 0)
  		asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM);
  	      else
- 		print_multi_reg (f, "\tldmfd\t%r!", SP_REGNUM,
- 				 live_regs_mask | (1 << LR_REGNUM), FALSE);
- 		
- 	      asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
- 			   REGNO (eh_ofs));
- 	      /* Jump to the target; even in 26-bit mode.  */
- 	      asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum);
- 	    }
- 	  else if (TARGET_APCS_32 && live_regs_mask == 0 && ! really_return)
  	    asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
- 	  else if (TARGET_APCS_32 && live_regs_mask == 0 && really_return)
- 	    asm_fprintf (f, "\tldr\t%r, [%r], #4\n", PC_REGNUM, SP_REGNUM);
- 	  else if (! really_return)
- 	    print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM,
- 			     live_regs_mask | (1 << LR_REGNUM), FALSE);
- 	  else
- 	    print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM,
- 			     live_regs_mask | (1 << PC_REGNUM),
- 			     TARGET_APCS_32 ? FALSE : TRUE);
  	}
!       else
! 	{
! 	  if (live_regs_mask || regs_ever_live[LR_REGNUM])
! 	    {
! 	      /* Restore the integer regs, and the return address into lr.  */
! 	      live_regs_mask |= 1 << LR_REGNUM;
! 
! 	      if (live_regs_mask == (1 << LR_REGNUM))
! 		{
! 		  if (eh_ofs)
! 		    asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM,
! 				 SP_REGNUM);
! 		  else
! 		    asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM,
! 				 SP_REGNUM);
! 		}
! 	      else if (live_regs_mask != 0)
! 		print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, live_regs_mask,
! 				 FALSE);
! 	    }
  
  	  if (current_function_pretend_args_size)
  	    {
--- 7197,7225 ----
  			 start_reg, reg - start_reg, SP_REGNUM);
  	}
  
!       /* If we can, restore the LR into the PC.  */
!       if (arm_current_func_type () == FT_NORMAL
! 	  && really_return
! 	  && current_function_pretend_args_size == 0
! 	  && regs_ever_live [LR_REGNUM])
  	{
! 	  live_regs_mask &= ~ (1 << LR_REGNUM);
! 	  live_regs_mask |=   (1 << PC_REGNUM);
! 	}
  
!       /* Load the registers off the stack.  If we only have one register
! 	 to load use the LDR instruction - it is faster.  */
        if (live_regs_mask == (1 << LR_REGNUM))
  	{
+ 	  /* The excpetion handler ignores the LR, so we do
+ 	     not really need to load it off the stack.  */
  	  if (eh_ofs)
  	    asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM);
  	  else
  	    asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
  	}	  
!       else if (live_regs_mask)
! 	print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, live_regs_mask);
  
        if (current_function_pretend_args_size)
  	{
*************** arm_output_epilogue (really_return)
*** 7080,7100 ****
  	      operands[2] = GEN_INT (current_function_pretend_args_size);
  	      output_add_immediate (operands);
  	    }
  
! 	  if (eh_ofs)
  	    asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
  			 REGNO (eh_ofs));
  
  	  if (really_return)
  	    {
! 	      /* And finally, go home.  */
! 	      if (TARGET_INTERWORK)
! 		asm_fprintf (f, "\tbx\t%r\n", return_regnum);
! 	      else if (TARGET_APCS_32 || eh_ofs)
! 		asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum);
  	      else
! 		asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, return_regnum);
! 	    }
  	}
      }
  
--- 7228,7281 ----
  	  operands[2] = GEN_INT (current_function_pretend_args_size);
  	  output_add_immediate (operands);
  	}
+     }
  
!   if (arm_current_func_type () == FT_EXCEPTION_HANDLER)
!     /* Adjust the stack to remove the exception handler stuff.  */
      asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
  		 REGNO (eh_ofs));
  
    if (really_return)
      {
!       /* Generate the return instruction.  */
!       switch (arm_current_func_type ())
! 	{
! 	case FT_EXCEPTION_HANDLER:
! 	  /* Even in 26-bit mode we do a mov (rather than a movs)
! 	     because we don't have the PSR bits set in the address.  */
! 	  asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, EXCEPTION_LR_REGNUM);
! 	  break;
! 
! 	case FT_ISR:
! 	case FT_FIQ:
! 	  asm_fprintf (f, "\tsubs\t%r, %r, #4\n", PC_REGNUM, LR_REGNUM);
! 	  break;
! 
! 	case FT_EXCEPTION:
! 	  asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
! 	  break;
! 
! 	case FT_INTERWORKED:
! 	  asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
! 	  break;
! 
! 	default:
! 	  if (frame_pointer_needed)
! 	    /* If we used the frame pointer then the return adddress
! 	       will have been loaded off the stack directly into the
! 	       PC, so there is no need to issue a MOV instruction
! 	       here.  */
! 	    ;
! 	  else if (current_function_pretend_args_size == 0
! 		   && regs_ever_live [LR_REGNUM])
! 	    /* Similarly we may have been able to load LR into the PC
! 	       even if we did not create a stack frame.  */
! 	    ;
! 	  else if (TARGET_APCS_32)
! 	    asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
  	  else
! 	    asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
! 	  break;
  	}
      }
    
*************** emit_sfm (base_reg, count)
*** 7298,7345 ****
    return par;
  }
  
  void
  arm_expand_prologue ()
  {
    int reg;
!   rtx amount = GEN_INT (-(get_frame_size ()
! 			  + current_function_outgoing_args_size));
!   int live_regs_mask = 0;
!   int store_arg_regs = 0;
!   /* If this function doesn't return, then there is no need to push
!      the call-saved regs.  */
!   int volatile_func = arm_volatile_func ();
    rtx insn;
  
    /* Naked functions don't have prologues.  */
!   if (arm_naked_function_p (current_function_decl))
      return;
  
!   if (current_function_anonymous_args && current_function_pretend_args_size)
!     store_arg_regs = 1;
  
!   if (! volatile_func)
      {
!       for (reg = 0; reg <= 10; reg++)
! 	if (regs_ever_live[reg] && ! call_used_regs[reg])
! 	  live_regs_mask |= 1 << reg;
  
!       if (! TARGET_APCS_FRAME
! 	  && ! frame_pointer_needed
! 	  && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
! 	  && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
! 	live_regs_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
        
!       if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
! 	live_regs_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
  
!       if (regs_ever_live[LR_REGNUM])
! 	live_regs_mask |= 1 << LR_REGNUM;
      }
  
!   if (frame_pointer_needed)
!     {
!       live_regs_mask |= 0xD800;
        insn = emit_insn (gen_movsi (gen_rtx_REG (SImode, IP_REGNUM),
  				   stack_pointer_rtx));
        RTX_FRAME_RELATED_P (insn) = 1;
--- 7479,7527 ----
    return par;
  }
  
+ /* Generate the prologue instructions for entry into an ARM function.  */
+ 
  void
  arm_expand_prologue ()
  {
    int reg;
!   rtx amount;
!   unsigned long live_regs_mask = 0;
    rtx insn;
+   int saved_ip_reg = 0;
    
    /* Naked functions don't have prologues.  */
!   if (IS_NAKED)
      return;
  
!   /* Compute which register we will have to save onto the stack.  */
!   live_regs_mask = arm_compute_save_reg_mask ();
    
!   if (frame_pointer_needed)
      {
!       if (current_function_needs_context)
! 	{
! 	  /* The static chain pointer is the IP register, which we are
! 	     about to corrupt by creayting the stack frame.  See if we
! 	     can find an alternate register to hold it during the prologue.
! 	     We need a call-used register, and the only ones available are
! 	     the argument registers.  */
! 	  for (reg = NUM_ARG_REGS; reg; reg--)
! 	    if (regs_ever_live [ARG_REGISTER (reg)] == 0)
! 	      break;
  
! 	  if (reg == 0)
! 	    fatal ("Nested function too complex - unable to find free temporary register");
  
! 	  saved_ip_reg = ARG_REGISTER (reg);
  
! 	  insn = emit_insn (gen_movsi (gen_rtx_REG (SImode, saved_ip_reg),
! 				       gen_rtx_REG (SImode, IP_REGNUM)));
! 	  /* RTX_FRAME_RELATED_P (insn) = 1; */
  	}
  
!       /* Move the current stack pointer into the IP register,
! 	 so that it can be saved into the stack frame.  */
        insn = emit_insn (gen_movsi (gen_rtx_REG (SImode, IP_REGNUM),
  				   stack_pointer_rtx));
        RTX_FRAME_RELATED_P (insn) = 1;
*************** arm_expand_prologue ()
*** 7347,7353 ****
  
    if (current_function_pretend_args_size)
      {
!       if (store_arg_regs)
  	insn = emit_multi_reg_push
  	  ((0xf0 >> (current_function_pretend_args_size / 4)) & 0xf);
        else
--- 7529,7536 ----
  
    if (current_function_pretend_args_size)
      {
!       /* Push the argument registers, or reserve space for them.  */
!       if (current_function_anonymous_args)
  	insn = emit_multi_reg_push
  	  ((0xf0 >> (current_function_pretend_args_size / 4)) & 0xf);
        else
*************** arm_expand_prologue ()
*** 7359,7375 ****
  
    if (live_regs_mask)
      {
-       /* If we have to push any regs, then we must push lr as well, or
- 	 we won't get a proper return.  */
-       live_regs_mask |= 1 << LR_REGNUM;
        insn = emit_multi_reg_push (live_regs_mask);
        RTX_FRAME_RELATED_P (insn) = 1;
      }
        
!   /* For now the integer regs are still pushed in output_arm_epilogue ().  */
! 
!   if (! volatile_func)
      {
        if (arm_fpu_arch == FP_SOFT2)
  	{
  	  for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg --)
--- 7542,7554 ----
  
    if (live_regs_mask)
      {
        insn = emit_multi_reg_push (live_regs_mask);
        RTX_FRAME_RELATED_P (insn) = 1;
      }
        
!   if (! IS_VOLATILE)
      {
+       /* Save any floating point call-saved registers used by this function.  */
        if (arm_fpu_arch == FP_SOFT2)
  	{
  	  for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg --)
*************** arm_expand_prologue ()
*** 7418,7423 ****
--- 7597,7603 ----
  
    if (frame_pointer_needed)
      {
+       /* Create the new frame pointer.  */
        insn = GEN_INT (-(4 + current_function_pretend_args_size));
        insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
  				    gen_rtx_REG (SImode, IP_REGNUM),
*************** arm_expand_prologue ()
*** 7425,7430 ****
--- 7605,7612 ----
        RTX_FRAME_RELATED_P (insn) = 1;
      }
  
+   amount = GEN_INT (-(get_frame_size ()
+ 		      + current_function_outgoing_args_size));
    if (amount != const0_rtx)
      {
        insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
*************** arm_expand_prologue ()
*** 7445,7450 ****
--- 7627,7647 ----
  	}
      }
  
+   if (frame_pointer_needed && current_function_needs_context)
+     {
+       /* We were forced to move the static chain pointer into saved_ip_reg.
+ 	 Restore it now so that it will be where the rest of the code
+ 	 expects it.  This may be inefficient, but it should work.  */
+       insn = emit_insn (gen_movsi (gen_rtx_REG (SImode, IP_REGNUM),
+ 				   gen_rtx_REG (SImode, saved_ip_reg)));
+       /* RTX_FRAME_RELATED_P (insn) = 1; */
+       
+       /* Emit a blockage to prevent code which might try to use the
+ 	 static chain register from executing before the register is
+ 	 valid.  */
+       emit_insn (gen_blockage ());
+     }
+ 
    /* If we are profiling, make sure no instructions are scheduled before
       the call to mcount.  Similarly if the user has requested no
       scheduling in the prolog.  */
*************** static void
*** 8955,8961 ****
  arm_mark_machine_status (p)
       struct function * p;
  {
!   struct machine_function *machine = p->machine;
  
    ggc_mark_rtx (machine->ra_rtx);
    ggc_mark_rtx (machine->eh_epilogue_sp_ofs);
--- 9152,9158 ----
  arm_mark_machine_status (p)
       struct function * p;
  {
!   machine_function *machine = p->machine;
  
    ggc_mark_rtx (machine->ra_rtx);
    ggc_mark_rtx (machine->eh_epilogue_sp_ofs);
*************** arm_init_machine_status (p)
*** 8966,8972 ****
       struct function * p;
  {
    p->machine =
!     (struct machine_function *) xcalloc (1, sizeof (struct machine_function));
  }
  
  /* Return an RTX indicating where the return address to the
--- 9163,9171 ----
       struct function * p;
  {
    p->machine =
!     (machine_function *) xcalloc (1, sizeof (struct machine_function));
!   
!   ((machine_function *) p->machine)->func_type = FT_UNKNOWN;
  }
  
  /* Return an RTX indicating where the return address to the
*************** thumb_expand_prologue ()
*** 9025,9034 ****
    HOST_WIDE_INT amount = (get_frame_size ()
  			  + current_function_outgoing_args_size);
    
    /* Naked functions don't have prologues.  */
-   if (arm_naked_function_p (current_function_decl))
      return;
  
    if (frame_pointer_needed)
      emit_insn (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx));
  
--- 9224,9245 ----
    HOST_WIDE_INT amount = (get_frame_size ()
  			  + current_function_outgoing_args_size);
  
+   switch (arm_current_func_type ())
+     {
+     case FT_NAKED:
        /* Naked functions don't have prologues.  */
        return;
  
+     case FT_ISR:
+     case FT_FIQ:
+     case FT_EXCEPTION:
+       error ("Interrupt Service Routines cannot be coded in Thumb mode.");
+       return;
+ 
+     default:
+       break;
+     }
+     
    if (frame_pointer_needed)
      emit_insn (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx));
  
*************** thumb_expand_epilogue ()
*** 9112,9118 ****
  			  + current_function_outgoing_args_size);
  
    /* Naked functions don't have epilogues.  */
!   if (arm_naked_function_p (current_function_decl))
      return;
  
    if (frame_pointer_needed)
--- 9323,9329 ----
  			  + current_function_outgoing_args_size);
  
    /* Naked functions don't have epilogues.  */
!   if (IS_NAKED)
      return;
  
    if (frame_pointer_needed)
*************** output_thumb_prologue (f)
*** 9148,9157 ****
  {
    int live_regs_mask = 0;
    int high_regs_pushed = 0;
-   int store_arg_regs = 0;
    int regno;
  
!   if (arm_naked_function_p (current_function_decl))
      return;
  
    if (is_called_in_ARM_mode (current_function_decl))
--- 9359,9367 ----
  {
    int live_regs_mask = 0;
    int high_regs_pushed = 0;
    int regno;
  
!   if (IS_NAKED)
      return;
  
    if (is_called_in_ARM_mode (current_function_decl))
*************** output_thumb_prologue (f)
*** 9189,9200 ****
        asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
      }
      
-   if (current_function_anonymous_args && current_function_pretend_args_size)
-     store_arg_regs = 1;
- 
    if (current_function_pretend_args_size)
      {
!       if (store_arg_regs)
  	{
  	  int num_pushes;
  	  
--- 9399,9407 ----
        asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
      }
      
    if (current_function_pretend_args_size)
      {
!       if (current_function_anonymous_args)
  	{
  	  int num_pushes;
  	  
Index: config/arm/arm-protos.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/arm/arm-protos.h,v
retrieving revision 1.13
diff -p -w -r1.13 arm-protos.h
*** arm-protos.h	2000/09/07 22:24:32	1.13
--- arm-protos.h	2000/09/19 22:21:54
*************** extern void   arm_expand_prologue	PARAMS
*** 34,39 ****
--- 34,40 ----
  /* Used in arm.md, but defined in output.c.  */
  extern void   assemble_align		PARAMS ((int)); 
  extern const char * arm_strip_name_encoding	PARAMS ((const char *));
+ extern arm_func_type 	 arm_current_func_type		PARAMS ((void));
  
  #ifdef TREE_CODE
  extern int    arm_return_in_memory	PARAMS ((tree));
*************** extern int    arm_comp_type_attributes	P
*** 42,47 ****
--- 43,49 ----
  extern int    arm_valid_type_attribute_p	PARAMS ((tree, tree, tree, tree));
  extern void   arm_set_default_type_attributes	PARAMS ((tree));
  extern void   arm_encode_call_attribute		PARAMS ((tree, int));
+ extern int    arm_function_ok_for_sibcall	PARAMS ((tree));
  #endif
  #ifdef RTX_CODE
  extern int    const_ok_for_arm		PARAMS ((HOST_WIDE_INT));

Index: extend.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/extend.texi,v
retrieving revision 1.63
diff -p -w -r1.63 extend.texi
*** extend.texi	2000/09/06 21:24:56	1.63
--- extend.texi	2000/09/19 22:21:54
*************** You must use GAS and GLD from GNU binuti
*** 1712,1723 ****
  this option to work correctly.
  
  @item interrupt_handler
! @cindex interrupt handler functions on the H8/300 processors
  Use this option on the H8/300 and H8/300H to indicate that the specified
  function is an interrupt handler.  The compiler will generate function
  entry and exit sequences suitable for use in an interrupt handler when this
  attribute is present.
  
  @item eightbit_data
  @cindex eight bit data on the H8/300 and H8/300H
  Use this option on the H8/300 and H8/300H to indicate that the specified
--- 1712,1740 ----
  this option to work correctly.
  
  @item interrupt_handler
! @cindex interrupt handler functions
  Use this option on the H8/300 and H8/300H to indicate that the specified
  function is an interrupt handler.  The compiler will generate function
  entry and exit sequences suitable for use in an interrupt handler when this
  attribute is present.
  
+ @item interrupt
+ @cindex interrupt handler functions
+ Use this option on the ARM, AVR and M32R/D ports to indicate that the
+ specified function is an interrupt handler.  The compiler will generate
+ function entry and exit sequences suitable for use in an interrupt
+ handler when this attribute is present.  Note on the AVR interrupts will
+ be enabled inside the function.
+ 
+ Note, for the ARM you can specify the kind of interrupt to be handled by
+ adding an optional parameter to the interrupt attribute like this:
+ 
+ @smallexample
+ void f () __attribute__ ((interrupt ("IRQ")));
+ @end smallexample
+ 
+ Permissable values for this parameter are: IRQ, FIQ, SWI, ABORT and UNDEF.
+ 
  @item eightbit_data
  @cindex eight bit data on the H8/300 and H8/300H
  Use this option on the H8/300 and H8/300H to indicate that the specified
*************** The compiler will generate more efficien
*** 1737,1755 ****
  on data in the tiny data section.  Note the tiny data area is limited to
  slightly under 32kbytes of data.
  
- @item interrupt
- @cindex interrupt handlers on the M32R/D
- Use this option on the M32R/D to indicate that the specified
- function is an interrupt handler.  The compiler will generate function
- entry and exit sequences suitable for use in an interrupt handler when this
- attribute is present.
- 
- Interrupt handler functions on the AVR processors
- Use this option on the AVR to indicate that the specified
- function is an interrupt handler.  The compiler will generate function
- entry and exit sequences suitable for use in an interrupt handler when this
- attribute is present. Interrupts will be enabled inside function.
- 
  @item signal
  @cindex signal handler functions on the AVR processors
  Use this option on the AVR to indicate that the specified
--- 1754,1759 ----
*************** entry and exit sequences suitable for us
*** 1758,1767 ****
  attribute is present. Interrupts will be disabled inside function.
  
  @item naked
! @cindex function without a prologue/epilogue code on the AVR processors
! Use this option on the AVR to indicate that the specified
! function don't have a prologue/epilogue.  The compiler don't generate
! function entry and exit sequences.
  
  @item model (@var{model-name})
  @cindex function addressability on the M32R/D
--- 1762,1771 ----
  attribute is present. Interrupts will be disabled inside function.
  
  @item naked
! @cindex function without a prologue/epilogue code
! Use this option on the ARm or AVR ports to indicate that the specified
! function does not need either a prologue or an epilogue sequence.  It is
! up to the programmer to provide these sequences.
  
  @item model (@var{model-name})
  @cindex function addressability on the M32R/D

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]