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

--- Comment #12 from Lukas Grätz <lukas.gra...@tu-darmstadt.de> ---
(In reply to H.J. Lu from comment #10)
> The C++ test issue is caused by missing callee-saved registers for
> exception supports in noreturn functions in libstdc++.  I fixed it by
> keeping callee-saved registers when exception is enabled.


I guess that exception throwing needs callee-saved registers, because it uses
stack unwinding to do something very similar to a return.


void f1(void) {
  CODE, compiler translation uses callee-saved %r12
  f2();
  CODE, compiler translation uses callee-saved %r12
}

void f2(void) {
  f3();
}

void f3(void) {
  CODE, compiler translation uses callee-saved %r12
  f4();
  while(1);
}

void f4(void) {
  CODE, uses loop unwinding functions
        a) restores all callee-saved registers in f3(), f2()
        b) restores %rsp and %rip from stack of f2()
  unreachable();
}

In effect, b) is a return from the call f2() in f1(), although it happens in
f4().

%r12 needs only to be saved in f1() and f3(). Gcc with -O2 would do that.
However, with your patch, %r12 would not be saved in f3() anymore. This can
lead to crashing in the second CODE block in f1().

The solution should require __attribute__((nothrow)) in addition to noreturn in
your optimization patch. The b) in f4() should/would be treated as a throw. So
none of f1(), f2(), f3() should have the attribute nothrow.

So in the example of this report, the signature of value() should be modified
to:

extern __attribute__((nothrow)) unsigned value(int i, int j, int k);

Only then it is safe to skip saving callee-saved registers. "nothrow" should
also be added to bar() and fn() in your test case pr38534-2.c.

Reply via email to