These checks were added to the original test by:
https://github.com/gcc-mirror/gcc/commit/0f149d5215a22a03406a82ec1669bf65b329a4df
Since 6b545db83c5a4e2c79e0b289e840be2c5fbbf327, clang has learned
to see through this tail call prevention.
First seen by us on our SVE bot which runs the test suite at -O3:
https://lab.llvm.org/buildbot/#/builders/197/builds/4192
Clang is correct here, this is why:
int check_fa_work (const char *c, const char *f)
{
const char d = 0;
if (c >= &d)
return c >= f && f >= &d;
else
return c <= f && f <= &d;
}This function only ever returns 0 or 1 due to the &&.
int check_fa_mid (const char *c)
{
const char *f = __builtin_frame_address (0);
/* Prevent a tail call to check_fa_work, eliding the current stack frame. */
return check_fa_work (c, f) != 0;
}This function returns whether the result of check_fa_work is not equal to 0.
Clang has realised that if check_fa_work returns 0, check_fa_mid does also.
Same for 1. Meaning you can tail call check_fa_work.
check_fa_work returns 0, 0 != 0 is False, so check_fa_mid returns 0
check_fa_work returns 1, 1 != 0 is True, so check_fa_mid returns 1
Giving you asm like:
check_fa_mid: // @check_fa_mid
stp x29, x30, [sp, #-16]! // 16-byte Folded Spill
mov x29, sp
mov x1, x29
ldp x29, x30, [sp], #16 // 16-byte Folded Reload
b check_fa_workWhich means we have one less frame and the test fails.
A correct way to do it would be "==" which would have to invert the result.
However we cannot modify the test files, so disable the test instead.
I have filed a bug with gcc:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109146