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.

Reply via email to