https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124798

            Bug ID: 124798
           Summary: no_caller_saved_registers attribute vs. spills in the
                    caller
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jakub at gcc dot gnu.org
  Target Milestone: ---

Seems we spill exactly the same registers in a caller to
no_caller_saved_registers functions like we do for functions without that
attribute.  Can't we rely on the different calling convention?

[[gnu::no_caller_saved_registers]] void foo (void);
[[gnu::no_callee_saved_registers]] void bar (void);
[[gnu::preserve_none]] void baz (void);
void corge (void);

void
qux (void)
{
  int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p;
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : "=r" (a), "=r" (b), "=r" (c),
"=r" (d), "=r" (e), "=r" (f), "=r" (g), "=r" (h));
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : "=r" (i), "=r" (j), "=r" (k),
"=r" (l), "=r" (m), "=r" (n), "=r" (o), "=r" (p));
  foo ();
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : : "r" (a), "r" (b), "r" (c), "r"
(d), "r" (e), "r" (f), "r" (g), "r" (h));
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : : "r" (i), "r" (j), "r" (k), "r"
(l), "r" (m), "r" (n), "r" (o), "r" (p));
}

void
fred (void)
{
  int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p;
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : "=r" (a), "=r" (b), "=r" (c),
"=r" (d), "=r" (e), "=r" (f), "=r" (g), "=r" (h));
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : "=r" (i), "=r" (j), "=r" (k),
"=r" (l), "=r" (m), "=r" (n), "=r" (o), "=r" (p));
  bar ();
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : : "r" (a), "r" (b), "r" (c), "r"
(d), "r" (e), "r" (f), "r" (g), "r" (h));
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : : "r" (i), "r" (j), "r" (k), "r"
(l), "r" (m), "r" (n), "r" (o), "r" (p));
}

void
garply (void)
{
  int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p;
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : "=r" (a), "=r" (b), "=r" (c),
"=r" (d), "=r" (e), "=r" (f), "=r" (g), "=r" (h));
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : "=r" (i), "=r" (j), "=r" (k),
"=r" (l), "=r" (m), "=r" (n), "=r" (o), "=r" (p));
  baz ();
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : : "r" (a), "r" (b), "r" (c), "r"
(d), "r" (e), "r" (f), "r" (g), "r" (h));
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : : "r" (i), "r" (j), "r" (k), "r"
(l), "r" (m), "r" (n), "r" (o), "r" (p));
}

void
plugh (void)
{
  int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p;
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : "=r" (a), "=r" (b), "=r" (c),
"=r" (d), "=r" (e), "=r" (f), "=r" (g), "=r" (h));
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : "=r" (i), "=r" (j), "=r" (k),
"=r" (l), "=r" (m), "=r" (n), "=r" (o), "=r" (p));
  corge ();
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : : "r" (a), "r" (b), "r" (c), "r"
(d), "r" (e), "r" (f), "r" (g), "r" (h));
  asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" : : "r" (i), "r" (j), "r" (k), "r"
(l), "r" (m), "r" (n), "r" (o), "r" (p));
}

I see qux and plugh spilling 10 registers across the calls, i.e. relying on
just %rbx, %rbp, %r12 to %r15 being preserved, while the other two functions
spilling 15 registers and relying just on %rbp being preserved.
Can't qux rely also on %rcx/%rdi/%rsi/%rbx/%r8/%r9/%r10/%r11?  Whether it can
rely on %rax in functions returning void (if returning something in %rax that
obviously isn't preserved)?  Or %rdx in functions not returning something in
%rdx:%rax pair?

Reply via email to