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]

Support for ARM interrupt handler functions.


Hi Richard, 

  I have created a patch to add support for an "interrupt" function
  attribute for the ARM port.  I would like to check it in, but I
  wanted to see if you (or anyone else) had any comments or
  reservations first.

  Interrupt handler functions are basically just the same as normal
  functions except that they have an exit instruction of:

        subs pc, lr, #4

  I also disable sibcall and tailcall optimisations for these
  functions.  Note at the request of Intel, who originally asked for
  this work, the attribute can also be called "irq".

  As well as adding support for the attribute, the patch also tidies
  up the prologue and epilogue generation code somewhat, so that now
  there is a single function which computes which registers needs to
  be saved in the prologue and restored in the epilogue.  This
  function is then called from all of the places that used to perform 
  these calculations individually.

  Note - I have tried to make sure that the patch does not break any
  of the exception handling code, but it is hard to know if I got this
  right.  It seems that exception handling for the ARM is not really
  working at the moment.  Certainly there are lots of failures in the
  G++ testsuite.   But I think that my patch does not introduce any
  new bugs.

Cheers
	Nick

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

	* config/arm/arm.c (use_return_insn): 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.
	(arm_ISR_p): New Function: Return true if the current function
	is an interrupt handler.
	(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.
	(output_arm_prologue): Emit comments when the function is an
	interrupt handler or an exception handler.
	(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.
	(output_thumb_prologue): Remove unneeded local variable
	'store_arg_regs'.

	* config/arm/arm.h (EXCEPTION_LR_REGNUM): Define.

	* config/arm/arm-protos.h: Add prototype for
	arm_function_ok_for_sibcall.

	* extend.texi: Document "interrupt" and "naked" attributes for
	the ARM.

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/13 18:48:12
*************** static void      init_fpa_table			PARAMS
*** 69,75 ****
  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 *));
--- 69,75 ----
  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));
  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	 push_minipool_barrier	     
*** 94,99 ****
--- 94,101 ----
  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 int	 arm_ISR_p			PARAMS ((void));
+ static unsigned int arm_compute_save_reg_mask	PARAMS ((void));
  
  #undef Hint
  #undef Mmode
*************** use_return_insn (iscond)
*** 712,717 ****
--- 714,723 ----
    if (arm_naked_function_p (current_function_decl))
      return 0;
  
+   /* If the function is an ISR, then we need a special exit sequence.  */
+   if (arm_ISR_p ())
+     return 0;
+ 
    return 1;
  }
  
*************** arm_valid_type_attribute_p (type, attrib
*** 1662,1667 ****
--- 1668,1679 ----
    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 args == NULL_TREE;
+  
    return 0;
  }
  
*************** arm_comp_type_attributes (type1, type2)
*** 1697,1702 ****
--- 1709,1724 ----
  	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 ****
--- 1865,1875 ----
    if (decl == NULL || TARGET_THUMB)
      return 0;
  
+   /* Never tailcall from an ISR routine -
+      it needs a special exit sequence.  */
+   if (arm_ISR_p ())
+     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 ****
--- 3815,3823 ----
       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, 
*** 3809,3814 ****
--- 3839,3848 ----
      return TREE_CODE (decl) == FUNCTION_DECL;
  #endif /* ARM_PE */
    
+   if (is_attribute_p ("isr", attr)
+       || is_attribute_p ("interrupt", attr))
+     return TREE_CODE (decl) == FUNCTION_DECL;
+ 
    return 0;
  }
  
*************** arm_naked_function_p (func)
*** 3826,3831 ****
--- 3860,3879 ----
    return a != NULL_TREE;
  }
  
+ /* Return non-zero if FUNC is an interrupt service routine.  */
+ 
+ static int
+ arm_ISR_p ()
+ {
+   tree a;
+ 
+   a = lookup_attribute ("isr", DECL_MACHINE_ATTRIBUTES (current_function_decl));
+   if (a == NULL_TREE)
+     a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (current_function_decl));
+   
+   return a != NULL_TREE;
+ }
+ 
  /* Routines for use in generating RTL.  */
  rtx
  arm_gen_load_multiple (base_regno, count, from, up, write_back, unchanging_p,
*************** 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;
--- 5767,5781 ----
  
  /* 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.  */
--- 5794,5800 ----
  	not_first = TRUE;
        }
  
!   fprintf (stream, "}%s\n", TARGET_APCS_32 ? "" : "^");
  }
  
  /* Output a 'call' insn.  */
*************** output_ascii_pseudo_op (stream, p, len)
*** 6519,6525 ****
--- 6566,6647 ----
    fputs ("\"\n", stream);
  }
  
+ /* Compute a bit mask of which registers need to be
+    saved on the stack for the current function.  */
+ 
+ static unsigned int
+ arm_compute_save_reg_mask ()
+ {
+   unsigned int save_reg_mask = 0;
+   unsigned int reg;
+   
+   if (arm_ISR_p ())
+     {
+       /* Deciding which registers to save for an interrupt service
+ 	 routine is tricky.  We must save all registers that we corrupt,
+ 	 even if they are call used.  If we call another function then
+ 	 we have to save every register that that function might corrupt
+ 	 as well.  In practice this means all the call-used registers and
+ 	 any touched call-saved registers.  */
+       for (reg = 0; reg <= 12; reg++)
+ 	if (regs_ever_live [reg])
+ 	  save_reg_mask |= (1 << reg);
+       
+       if (! current_function_is_leaf)
+ 	for (reg = 0; reg <= 12; reg++)
+ 	  if (call_used_regs [reg])
+ 	    save_reg_mask |= (1 << reg);
+     }
+   else
+     {
+       /* If this function doesn't return, then there
+ 	 is no need to push the call-saved regs.  */
+       if (! arm_volatile_func ())
+ 	{
+ 	  /* 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;
+ 
+   /* 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)
       rtx operand;
*************** output_return_instruction (operand, real
*** 6527,6534 ****
       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))
--- 6649,6656 ----
       int reverse;
  {
    char instr[100];
!   int reg;
!   unsigned int live_regs_mask;
  
    /* If a function is naked, don't use the "return" insn.  */
    if (arm_naked_function_p (current_function_decl))
*************** output_return_instruction (operand, real
*** 6536,6542 ****
    
    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.  */
--- 6658,6664 ----
    
    return_used_this_function = 1;
    
!   if (TARGET_ABORT_NORETURN && arm_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.  */
*************** output_return_instruction (operand, real
*** 6558,6667 ****
    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");
--- 6680,6792 ----
    if (current_function_calls_alloca && ! really_return)
      abort ();
    
!   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)
!     output_asm_insn (reverse
! 		     ? "ldr%?%D0\t%|lr, [%|sp], #4" 
  		     : "ldr%?%d0\t%|lr, [%|sp], #4", &operand);
!   else if ((live_regs_mask  == (1 << 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_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 (! arm_ISR_p ())
! 	  {
! 	    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)
!         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 <= 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
! 	      && ! arm_ISR_p ()
! 	      && really_return)
! 	    strcat (instr, reg_names [PC_REGNUM]);
  	  else
! 	    strcat (instr, reg_names [LR_REGNUM]);
  
  	  strcat (instr, (TARGET_APCS_32 || !really_return) ? "}" : "}^");
+ 	}
+ 
        output_asm_insn (instr, & operand);
  
!       if (really_return)
  	{
+ 	  if (arm_ISR_p ())
+ 	    {
+ 	      strcpy (instr, "sub%?s");
+ 	      strcat (instr, reverse ? "%D0" : "%d0");
+ 	      strcat (instr, "\t%|");
+ 	      strcat (instr, reg_names [PC_REGNUM]);
+ 	      strcat (instr, ", %|");
+ 	      strcat (instr, reg_names [LR_REGNUM]);
+ 	      strcat (instr, ", #4");
+ 
+ 	      output_asm_insn (instr, & operand);
+ 	    }
+ 	  else if (TARGET_INTERWORK)
+ 	    {
  	      strcpy (instr, "bx%?");
  	      strcat (instr, reverse ? "%D0" : "%d0");
  	      strcat (instr, "\t%|");
! 	      strcat (instr, reg_names [LR_REGNUM]);
  
  	      output_asm_insn (instr, & operand);
  	    }
  	}
+     }
    else if (really_return)
      {
!       if (arm_ISR_p ())
! 	sprintf (instr, "sub%%?%%%s0s\t%%|pc, %%|lr, #4", reverse ? "D" : "d");
! 
!       else 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");
*************** 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 *
--- 6854,6901 ----
    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 ();
    
    if (arm_naked_function_p (current_function_decl))
+     {
+       asm_fprintf (f, "\t%@ Naked Function: prologue and epilogue provided by programmer.\n");
        return;
!     }
    
    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 (arm_volatile_func ())
!     asm_fprintf (f, "\t%@ Volatile function (ie it does not return).\n");
  
!   if (arm_ISR_p ())
!     asm_fprintf (f, "\t%@ Interrupt Service Routine.\n");
  
!   if (cfun->machine->eh_epilogue_sp_ofs != NULL_RTX)
!     asm_fprintf (f, "\t%@ Exception Handler.\n");
  
  #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,6824 ****
       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 "";
--- 6903,6915 ----
       int really_return;
  {
    int reg;
!   unsigned int 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 ();
    rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
    FILE * f = asm_out_file;
  
    if (use_return_insn (FALSE) && return_used_this_function)
      return "";
*************** arm_output_epilogue (really_return)
*** 6827,6876 ****
    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)
      {
--- 6918,6946 ----
    if (arm_naked_function_p (current_function_decl))
      return "";
  
    /* 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 && arm_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 "";
      }
  
!   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,6957 ****
  			 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
-     {
        /* Restore stack pointer if necessary.  */
        if (frame_size + current_function_outgoing_args_size != 0)
  	{
--- 6989,7032 ----
  			 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 || eh_ofs || TARGET_INTERWORK || arm_ISR_p ())
! 	live_regs_mask &= ~ (1 << PC_REGNUM);
!       else
! 	live_regs_mask &= ~ (1 << LR_REGNUM);
!       
!       print_multi_reg (f, "ldmea\t%r", FP_REGNUM, live_regs_mask);
!       
        if (eh_ofs)
  	asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
  		     REGNO (eh_ofs));
+       
+       if (arm_ISR_p ())
+ 	asm_fprintf (f, "\tsubs\t%r, %r, #4\n", PC_REGNUM, LR_REGNUM);
+       else if (TARGET_INTERWORK)
+ 	asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
+       else if (! really_return)
+ 	;
+       else /* eh_ofs == true */
  	/* 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);
      }
    else
      {
        /* Restore stack pointer if necessary.  */
        if (frame_size + current_function_outgoing_args_size != 0)
  	{
*************** arm_output_epilogue (really_return)
*** 7000,7078 ****
  			 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)
  	    {
  	      /* Unwind the pre-pushed regs.  */
--- 7075,7106 ----
  			 start_reg, reg - start_reg, SP_REGNUM);
  	}
  
!       /* If we can, restore the LR into the PC.  */
!       if (! arm_ISR_p ()
! 	  && ! TARGET_INTERWORK
! 	  && ! eh_ofs
! 	  && 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)
  	{
  	  /* Unwind the pre-pushed regs.  */
*************** arm_output_epilogue (really_return)
*** 7088,7100 ****
  	  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);
! 	    }
  	}
      }
  
--- 7116,7129 ----
        if (really_return)
  	{
  	  /* And finally, go home.  */
! 	  if (arm_ISR_p ())
! 	    asm_fprintf (f, "\tsubs\t%r, %r, #4\n", PC_REGNUM, LR_REGNUM);
! 	  else if (TARGET_INTERWORK)
! 	    asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
! 	  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);
  	}
      }
  
*************** 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;
--- 7327,7353 ----
    return par;
  }
  
+ /* Generate the prologue instructions for entry into an ARM function.  */
+ 
  void
  arm_expand_prologue ()
  {
    int reg;
!   rtx amount;
!   unsigned int live_regs_mask = 0;
    rtx insn;
  
    /* Naked functions don't have prologues.  */
    if (arm_naked_function_p (current_function_decl))
      return;
  
!   /* Compute which register we will have to save onto the stack.  */
!   live_regs_mask = arm_compute_save_reg_mask ();
    
    if (frame_pointer_needed)
      {
!       /* 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
--- 7355,7362 ----
  
    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 --)
--- 7368,7380 ----
  
    if (live_regs_mask)
      {
        insn = emit_multi_reg_push (live_regs_mask);
        RTX_FRAME_RELATED_P (insn) = 1;
      }
        
!   if (! arm_volatile_func ())
      {
+       /* 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 ****
--- 7423,7429 ----
  
    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 ****
--- 7431,7438 ----
        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,
*************** thumb_expand_prologue ()
*** 9029,9034 ****
--- 9037,9045 ----
    if (arm_naked_function_p (current_function_decl))
      return;
  
+   if (arm_ISR_p ())
+     error ("Interrupt Service Routines cannot be coded in Thumb mode.");
+     
    if (frame_pointer_needed)
      emit_insn (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx));
  
*************** output_thumb_prologue (f)
*** 9148,9154 ****
  {
    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))
--- 9159,9164 ----
*************** 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;
  	  
--- 9199,9207 ----
        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.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/13 18:48:12
*************** extern const char * structure_size_strin
*** 888,893 ****
--- 888,896 ----
  /* 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.  */

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/13 18:48:11
*************** extern int    arm_comp_type_attributes	P
*** 42,47 ****
--- 42,48 ----
  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 -r1.63 extend.texi
*** extend.texi	2000/09/06 21:24:56	1.63
--- extend.texi	2000/09/13 19:01:29
*************** 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,1731 ----
  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.
+ 
  @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
--- 1745,1750 ----
*************** 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
--- 1753,1762 ----
  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]