This is the mail archive of the gcc@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]
Other format: [Raw text]

Re: ARM interrupts


Hi Eric,

> When I compile the following c program:
> 
>  void at91_default_irq_handler() __attribute__ ((interrupt ("FIQ")));
>  void at91_default_irq_handler() {}
> 
> Then I get the following assembly code:
> 
> entry code:
> 1) str ip, [sp, #-4]!
> 2) mov ip, sp
> 3) sub lr, lr, #4
> 4) stmfd sp!, {fp, ip, lr, pc}
> 5) sub fp, ip, #4
> 6) ldmea fp, {fp, ip, pc}^
 
> Who can explain this?

It is a bug in the compiler.  Gcc thought that it was able to use a
single instruction to return from the interrupt handler.  It had
forgotten to allow for the fact that IP had to be pushed before the
stack frame could be created.

Please try applying the following patch to your sources and rebuilding
gcc.  It should fix the problem.

Cheers
        Nick

2003-01-23  Nick Clifton  <nickc@redhat.com>

	* config/arm/arm.c (use_return_insn): Do not allow interrupt
	handlers with a stack frame to use a single instruction return
	- they need to pop the IP register. 
	(arm_expand_prologue): Do not pre-bias the LR register for
	interrupt handlers unless they are going to use a single
	instruction return.


Index: gcc/config/arm/arm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.247
diff -c -3 -p -w -r1.247 arm.c
*** gcc/config/arm/arm.c	22 Jan 2003 16:01:42 -0000	1.247
--- gcc/config/arm/arm.c	23 Jan 2003 10:31:33 -0000
*************** use_return_insn (iscond)
*** 935,940 ****
--- 935,944 ----
    if (func_type & (ARM_FT_VOLATILE | ARM_FT_NAKED))
      return 0;
  
+   /* So do interrupt functions that use the frame pointer.  */
+   if (IS_INTERRUPT (func_type) && frame_pointer_needed)
+     return 0;
+   
    /* As do variadic functions.  */
    if (current_function_pretend_args_size
        || cfun->machine->uses_anonymous_args
*************** arm_expand_prologue ()
*** 8639,8656 ****
        RTX_FRAME_RELATED_P (insn) = 1;
      }
  
!   /* If this is an interrupt service routine, and the link register is
!      going to be pushed, subtracting four now will mean that the
!      function return can be done with a single instruction.  */
    if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
!       && (live_regs_mask & (1 << LR_REGNUM)) != 0)
!     {
        emit_insn (gen_rtx_SET (SImode, 
  			      gen_rtx_REG (SImode, LR_REGNUM),
  			      gen_rtx_PLUS (SImode,
  				    gen_rtx_REG (SImode, LR_REGNUM),
  				    GEN_INT (-4))));
-     }
  
    if (live_regs_mask)
      {
--- 8643,8661 ----
        RTX_FRAME_RELATED_P (insn) = 1;
      }
  
!   /* If this is an interrupt service routine, and the link register
!      is going to be pushed, and we are not creating a stack frame,
!      (which would involve an extra push of IP and a pop in the epilogue)
!      subtracting four from LR now will mean that the function return
!      can be done with a single instruction.  */
    if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
!       && (live_regs_mask & (1 << LR_REGNUM)) != 0
!       && ! frame_pointer_needed)
      emit_insn (gen_rtx_SET (SImode, 
  			    gen_rtx_REG (SImode, LR_REGNUM),
  			    gen_rtx_PLUS (SImode,
  					  gen_rtx_REG (SImode, LR_REGNUM),
  					  GEN_INT (-4))));
  
    if (live_regs_mask)
      {


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