Bug 55747

Summary: Extra registers are saved in functions that only call noreturn functions
Product: gcc Reporter: Joshua Conner <josh.m.conner>
Component: rtl-optimizationAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED WONTFIX    
Severity: enhancement CC: hp
Priority: P3    
Version: 4.8.0   
Target Milestone: ---   
Host: Target: sh*-*-* arm*-*-* cris*-*-*
Build: Known to work:
Known to fail: Last reconfirmed: 2013-01-06 00:00:00

Description Joshua Conner 2012-12-20 01:12:40 UTC
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.
Comment 1 Andrew Pinski 2012-12-20 01:22:11 UTC
Actually noreturns are handled special in the compiler.  I filed this bug over 6 years ago and it was closed as invalid back then.
Comment 2 Hans-Peter Nilsson 2013-01-06 08:26:11 UTC
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.
Comment 3 Oleg Endo 2013-10-04 18:46:21 UTC
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).
Comment 4 Richard Earnshaw 2013-10-04 20:08:41 UTC
Sorry, we're not going to change this.  Removing the saved lr value would break back-tracing out of functions that called abort().