https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115853
Bug ID: 115853
Summary: Unnecessary push to stack in __attribute((noreturn))
Reset_Handler(), leading to permanent wasted SRAM
Product: gcc
Version: 13.3.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: rlcamp.pdx at gmail dot com
Target Milestone: ---
The following code:
extern int main(void);
__attribute__((noreturn)) static void Reset_Handler(void) {
/* usual setup stuff omitted */
main();
while (1) asm volatile("wfi" :::);
__builtin_unreachable();
}
void (* exception_table[])(void) = { Reset_Handler };
when compiled with (version 13.3.1, or any other version afaict)
arm-none-eabi-gcc -Os -mcpu=cortex-m4, produces the following instructions
(copied and pasted from https://c.godbolt.org/z/dPGWe1jKf, but initially
observed in the wild):
Reset_Handler:
push {r3, lr}
bl main
.L2:
wfi
b .L2
exception_table:
.word Reset_Handler
The push of two registers to the stack causes the call stack to be 8 bytes
deeper than necessary, forever, which in some use cases on chips with small
SRAM can be significant. There doesn't seem to be any valid code path which
would lead to use of those values, and they are likely to be garbage values
anyway. Notably, in more complicated Reset_Handler code, the absence of
__attribute((noreturn)) DOES result in more registers being pushed to the stack
vs when it is present, so the compiler is definitely acknowledging the
attribute, but it is not applying all of the optimization it is entitled to do.