This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: ARM interrupts
- From: Nick Clifton <nickc at redhat dot com>
- To: Eric de Jong <eric2work at yahoo dot com>
- Cc: gcc at gnu dot org, ericdejong at gmx dot net
- Date: 23 Jan 2003 10:37:39 +0000
- Subject: Re: ARM interrupts
- References: <20030122155635.72386.qmail@web40104.mail.yahoo.com>
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)
{