This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Tool/software: Linux
GCC erroneously optimizes a call from one interrupt function to another, using standard calling convention.
This results in an eventual stack overflow, as the interrupt returns using reti, not ret.
In this particular example, fn_8 and fn_11 are separate functions, but the compiler slips a call() into the second in a hapless attempt to optimize
This is a pretty bad compiler bug.
I was able to work around it by swapping the order of the calls in the fn_08, but that is a hack workaround.
Source:
__attribute((interrupt)) void fn_11(){ TX_INV_MARK += u.tx.offset_fix; TX_BIT_DOWN_IRQ = u.tx.bit_down_irq; } __attribute((interrupt)) void fn_08(){ TX_INV_MARK += u.tx.offset_fix; TX_BIT_DOWN_IRQ = u.tx.bit_down_irq; }
Assembler (call is bolded):
__attribute((interrupt)) void fn_11(){ e910: 0c 15 pushm #1, r12 ;16-bit words 0000e912 <.LCFI12>: TX_INV_MARK += u.tx.offset_fix; e912: 3c 40 68 21 mov #8552, r12 ;#0x2168 e916: 92 5c 08 00 add 8(r12), &0x0392 ; e91a: 92 03 0000e91c <.Loc.382.3>: TX_BIT_DOWN_IRQ = u.tx.bit_down_irq; e91c: 92 4c 02 00 mov 2(r12), &0x200c ; e920: 0c 20 0000e922 <.Loc.383.3>: } 0000ea54 <fn_08>: ea54: bf 15 pushm #12, r15 ;16-bit words 0000ea56 <.LCFI13>: ea56: b0 12 10 e9 call #-5872 ;#0xe910 ea5a: b4 17 popm #12, r15 ;16-bit words ea5c: 00 13 reti
Why would you change the interrupt vectors while servicing an interrupt? I can't imagine that.
In any case, if things are so dynamic that you can't tell what code you want to execute until the interrupt happens, have the ISR call the appropriate code via a pointer to a function.
Peter,
I don't think you are understanding my approach.
The code at the interrupt vector itself does not change.
I am NOT manipulating the vector itself, as David Schultz had proposed.
The instruction at the vector is merely a branch whose destination address changes based on a RAM variable.
There is no difference between this and the state variable you are proposing, except this solution does not require a costly switch or if statement.
The RAM variable simply stores the next function to call on the next interrupt.
And when you look at the assembler, you will see that this is the most effective approach.
This is established practice for me on the G2553 with an older compiler.
It's just that the newer compiler for the FR2422 is generating erroneous code, which should be addressed by Mitto.
-Dave
Hi Dave,
Thanks for reporting this bug, we will aim to fix this in a release later in the year.
The specific optimization that causes this behaviour is "Identical Code Folding". You can turn this off for functions by passing "-fno-ipa-icf-functions" on the command line.
I tried to see if you could turn this optimization off for individual functions, using the "optimize" attribute (i.e. __attribute__((interrupt,optimize("no-ipa-icf-functions"))). Unfortunately this has no effect. It appears the optimization can only be turned off per source file.
Hi Dave,
Since the way you make use of interrupt functions is quite uncommon, I wanted to get your opinion on how we may extend the optimization of identical interrupt functions.
If your two identical interrupt functions were folded by creating an alias (instead of by creating a wrapper, which is what is happening at the moment), might that cause any problems for your program?
Using the code snippet from your original post as an example, the proposed behaviour would be roughly equivalent to this:
__attribute((interrupt)) void fn_11(){ TX_INV_MARK += u.tx.offset_fix; TX_BIT_DOWN_IRQ = u.tx.bit_down_irq; } __attribute((interrupt,alias("fn_11"))) void fn_08();
So GCC would detect that the interrupt functions are equivalent and alias them, so they would have the same address.
Does your program require these interrupt functions with identical contents to have different addresses? Would this proposal cause any issues?
Thanks.
P.S. In the next release we have simply disabled "identical code folding" for interrupt functions, but we are continuing to investigate this possibility of aliasing them for a future release.
Josef,
Thanks for reaching out to me.
This particular code I wrote would not break on this aliasing technique.
Let's say fn_11() and fn_8() are part of a background interrupt driven process P, but in separate control branches. Let's say I need another process Q to know the state of P. Then I would expect fn_11 and fn_8 to have different addresses. That way Q would know what branch P was in.
The expectation that the addresses are different comes naturally since most functions are different. Thus it becomes surprising that different functions, even with identical contents, would have the same address. A similar context for this situation actually exists with aliasing constant values too. You may maintain a pointer to a constant value and you may be concerned more with which constant you are pointing to as well as the actual value.
Hi Dave,
Thanks for providing some further information.
My thoughts are that we cannot safely alias interrupt functions. As you say, the user would expect different interrupts to have different addresses, and there is nothing in the MSP430 ABI to stipulate that interrupt functions with global visibility could be manipulated in this way.
Aliasing could possibly work for interrupt functions that are declared static, but I don't think this is something worth pursuing at this time.
Regards,
**Attention** This is a public forum