On architectures such as ARM, where a link register is used to save the return address, this value does not need to be saved in a function that only calls noreturn functions. For example, if I build the following source: __attribute__((noreturn)) extern void bar (void); int x; void foo (void) { if (x) bar (); } Using the options "-O2", the link register is saved: stmfd sp!, {r3, lr} ... ldmeqfd sp!, {r3, pc} However, this is unnecessary since the only way the link register cannot be corrupted since any calls to "bar" will not return. Note that I am not filing this as an ARM target bug since the issue appears to be a general problem related to dataflow analysis not tracking the difference between calls to normal functions and calls to noreturn functions. At any rate, I see a similar problem in our custom target as well.
Actually noreturns are handled special in the compiler. I filed this bug over 6 years ago and it was closed as invalid back then.
Similarly observed for cris-elf with -O2, r194929, JFTR. If this changes, some attribute markup should be added to keep return-addresses for noreturn functions, for sake of stack-traces. Also return-addresses need to be generally kept when -fexceptions and similar are in effect, as noreturn functions can still throw.
On SH there's a similar issue. E.g. compiling void exit (int __status) __attribute__ ((noreturn)); int test (int a, int b, int c) { if (a == b) return 5; if (a) exit (0); return 0; } with -O2 -m4 results in: _test: cmp/eq r5,r4 bt/s .L3 tst r4,r4 bf/s .L10 mov #0,r0 rts nop .L3: rts mov #5,r0 .L10: mov.l .L11,r1 sts.l pr,@-r15 // push return address register jsr @r1 // jump to subroutine mov #0,r4 .L12: .align 2 .L11: .long _exit The jsr should be a simple jmp and the pr push is not required (as with leaf function calls).
Sorry, we're not going to change this. Removing the saved lr value would break back-tracing out of functions that called abort().