Bug 16634 - arm-elf-gcc problems when generating code for __attribute__ ((interrupt ("IRQ")))
Summary: arm-elf-gcc problems when generating code for __attribute__ ((interrupt ("IRQ...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 3.4.0
: P4 normal
Target Milestone: 4.3.5
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
: 25428 29004 (view as bug list)
Depends on:
Blocks:
 
Reported: 2004-07-19 19:27 UTC by Bob Mittmann
Modified: 2010-01-09 23:27 UTC (History)
10 users (show)

See Also:
Host:
Target: arm-elf-gcc
Build:
Known to work:
Known to fail:
Last reconfirmed: 2006-08-08 23:47:42


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Bob Mittmann 2004-07-19 19:27:21 UTC
The gcc 3.4.0 still have problems on generating the entry/exit code for
interrupts, if we supress the "apcs-frame" option. When the code is compiled
with "-mno-apcs-frame" the entry code subtracts 4 from the "lr" before pushing
it into stack, and do it again on the exit code.

__attribute__ ((interrupt ("IRQ"))) void int_handler(void)
{
	foo();
}
 
arm-elf-gcc -mcpu=arm7tdmi -mno-apcs-frame -mthumb-interwork -Wall -O2 -c test.c
00000000 <int_handler>:
   0:   e24ee004        sub     lr, lr, #4      ; 0x4
   4:   e92d500f        stmdb   sp!, {r0, r1, r2, r3, ip, lr}
   8:   ebfffffe        bl      0 <int_handler>
   c:   e8bd500f        ldmia   sp!, {r0, r1, r2, r3, ip, lr}
  10:   e25ef004        subs    pc, lr, #4      ; 0x4


arm-elf-gcc -mcpu=arm7tdmi -mapcs-frame -mthumb-interwork -Wall -O2 -c test.c
00000000 <int_handler>:
   0:   e52dc004        str     ip, [sp, -#4]!
   4:   e1a0c00d        mov     ip, sp
   8:   e92dd80f        stmdb   sp!, {r0, r1, r2, r3, fp, ip, lr, pc}
   c:   e24cb004        sub     fp, ip, #4      ; 0x4
  10:   ebfffffe        bl      0 <int_handler>
  14:   e89d680f        ldmia   sp, {r0, r1, r2, r3, fp, sp, lr}
  18:   e8bd1000        ldmia   sp!, {ip}
  1c:   e25ef004        subs    pc, lr, #4      ; 0x4
Comment 1 Paul Brook 2006-08-08 23:05:11 UTC
*** Bug 25428 has been marked as a duplicate of this bug. ***
Comment 2 Paul Brook 2006-08-08 23:47:42 UTC
Patch here:
http://gcc.gnu.org/ml/gcc-patches/2006-08/msg00230.html
Comment 3 Richard Earnshaw 2006-09-11 10:41:42 UTC
*** Bug 29004 has been marked as a duplicate of this bug. ***
Comment 4 Martin Michlmayr 2006-09-11 11:31:25 UTC
(In reply to comment #2)
> Patch here:
> http://gcc.gnu.org/ml/gcc-patches/2006-08/msg00230.html

What's the status of this patch?
Comment 5 Tomas Lauridsen 2006-11-14 16:28:29 UTC
(In reply to comment #4)
> What's the status of this patch?

The bug is also present in arm-elf-gcc version 4.1.0
However, adding the -fno-omit-frame-pointer parameter, make
the compiler emit the correct code in the mentioned code example.
Comment 6 Paul Brook 2007-01-04 00:09:58 UTC
Subject: Bug 16634

Author: pbrook
Date: Thu Jan  4 00:09:48 2007
New Revision: 120413

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=120413
Log:
2007-01-03  Paul Brook  <paul@codesourcery.com>

	PR target/16634
	gcc/
	* config/arm/arm.c (output_return_instruction): Pop PC in interrupt
	functions.
	(use_return_insn): Return 0 for Thumb interrupt functions.
	(print_multi_reg): Add rfe argument for IRQ returns.
	(arm_output_epilogue): Pop interrupt return address directly into PC.
	(arm_expand_prologue): Only adjust IRQ return address in Arm mode.


Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/arm/arm.c

Comment 7 David Caldwell 2007-05-03 03:14:24 UTC
This still fails in gcc 4.1.2 under certain conditions. I can provide a test case if necessary.
Comment 8 Søren Holm 2007-08-06 09:08:07 UTC
also fails on 4.2.1
Comment 9 Ralf Guetlein 2007-11-08 21:42:08 UTC
(In reply to comment #8)
> also fails on 4.2.1

is this bug still present in 4.2.2?

Acc. to my obervations the error only shows up when not all auto variables can be mapped to registers, and additional variables are located on stack. As a work-around, if a more complex interrupt handler is needed, place the code in a subfunction and call this function from the interrupt handler. In this case no stack is reserved in the interrupt handler, and the generated code is OK. Care must be taken, of course, that the optimizer does not inline the code for IntFunc().

Example:
void IntFunc(void);

__attribute__((interrupt("IRQ")) void IntHandler(void)
{
  IntFunc();
}

__attribute__(noinline)) void IntFunc(void)
{
  // interrupt code here!
}

Comment 10 Marco Ziech 2008-02-07 13:54:14 UTC
(In reply to comment #9)
> is this bug still present in 4.2.2?

I can confirm this bug still exists in 4.2.2 and 4.2.3.

> Acc. to my obervations the error only shows up when not all auto variables can
> be mapped to registers, and additional variables are located on stack. As a
> work-around, if a more complex interrupt handler is needed, place the code in a
> subfunction and call this function from the interrupt handler. In this case no
> stack is reserved in the interrupt handler, and the generated code is OK. Care
> must be taken, of course, that the optimizer does not inline the code for
> IntFunc().

Your subfunction workaround actually did the trick. The generated return instruction is "ldm sp!, {r0, r1, r2, r3, ip, pc}^". However, if a more complex interrupt handler is implemented the wrong return instruction generated. The results seem a bit unpredictable so I currently use plain assembler for my interrupts.

Example:
extern __attribute__ ((interrupt ("IRQ"))) void base_int_ctrl_top_irq_handler(void)
{
    int_ctrl_status_t status;
    
    status.val = READ_REG_U32(ADDR_STATUS_NIRQ);
    
    if (status.bf.x) {
        puts("Spurious x IRQ!");
    } else if (status.bf.y) {
        puts("Spurious y IRQ!");
    } else if (status.bf.timer) {
        base_timer_interrupt();
    } else if (status.bf.z) {
        puts("Spurious z IRQ!");
    } else {
        puts("Spurious unknown IRQ!");
    }
}

Generated assembly for return:
pop	{r0, r1, r2, r3, ip, lr}
subs	pc, lr, #4	; 0x4
(and lr was already decremented by 4 when the handler was entered)

So your observations are correct.

Bug #27859 seems to be a duplicate of this bug and contains a patch. However, this patch is probably not optimal since it just replaces the final "subs" by a "movs" while the best solution seems to be the "ldmfd ..." instruction above.
Comment 11 Søren Holm 2009-02-12 21:58:46 UTC
Since this is not marked to be fixes I assume is hasn't been fixed in 4.3.3. Wat is wrong with Pauls patch since it hasn't been included ?
Comment 12 Ramana Radhakrishnan 2010-01-09 23:27:10 UTC
The code generated on trunk, 4.4 and 4.3 with arm-eabi-gcc at O2 for the test in Comment #0 is 

int_handler:
        @ Interrupt Service Routine.
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 0, uses_anonymous_args = 0
        sub     lr, lr, #4
        stmfd   sp!, {r0, r1, r2, r3, ip, lr}
        bl      foo
        ldmfd   sp!, {r0, r1, r2, r3, ip, pc}^

which appears to be the expected code generated. 


This appears to be fixed. If there is a problem please open a separate bug report. I tried the testcase in Comment #10 but that doesn't even compile . Attempting to reverse create a testcase using similar structs didn't show the problem.