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

            Bug ID: 119873
           Summary: s390x musttail call failure on s390x
           Product: gcc
           Version: 15.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: ---

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long long uint64_t;
struct TcFieldData {
  constexpr TcFieldData() : data(0) {}
  constexpr TcFieldData(uint16_t coded_tag, uint8_t hasbit_idx, uint8_t
aux_idx,
                        uint16_t offset)
      : data(uint64_t{offset} << 48 | uint64_t{aux_idx} << 24 |
uint64_t{hasbit_idx} << 16 | uint64_t{coded_tag}) {}
  uint64_t data;
};

const char *foo (void *, void *, void *, void *, uint64_t, TcFieldData);
[[gnu::noinline]] const char *bar (void *, void *, void *, void *, uint64_t,
TcFieldData) { return nullptr; }

const char *
baz (void *a, void *b, void *c, void *d, uint64_t e, TcFieldData f)
{
  [[clang::musttail]] return bar (a, b, c, d, e, f);
}

const char *
qux (void *a, void *b, void *c, void *d, uint64_t e, TcFieldData f)
{
  [[clang::musttail]] return foo (a, b, c, d, e, f);
}

from protobuf fails to compile on s390x-linux e.g. at -O2, with
/tmp/0.C: In function ‘const char* qux(void*, void*, void*, void*, uint64_t,
TcFieldData)’:
/tmp/0.C:24:34: error: cannot tail-call: target is not able to optimize the
call into a sibling call
   24 |   [[clang::musttail]] return foo (a, b, c, d, e, f);
      |                              ~~~~^~~~~~~~~~~~~~~~~~

If I understand it right, this is because
  /* Register 6 on s390 is available as an argument register but unfortunately
     "caller saved". This makes functions needing this register for arguments
     not suitable for sibcalls.  */
  return !s390_call_saved_register_used (exp);

I wonder if it couldn't be allowed if the argument passed in %r6 register is
passed through from the caller to the callee unmodified,
i.e. if in exp the argument in %r6 register is SSA_NAME which is
SSA_NAME_IS_DEFAULT_DEF with PARM_DECL which has %r6 as DECL_INCOMING_RTL.
Of course, if one passes something else, I can understand why it can't be tail
called.

Note, looking at what clang does, it silently ignores the musttail attribute,
calls the function normally, without diagnosing it.
I think the gcc behavior is better, at least the user is told that it can't be
tail called.  clang does the same for many reasons, but not in this case.

Reply via email to