Skip to content

aarch64-pc-windows: failed to perform tail call elimination on a call site marked musttail #133098

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
zmodem opened this issue Mar 26, 2025 · 4 comments · Fixed by #134671
Closed

Comments

@zmodem
Copy link
Collaborator

zmodem commented Mar 26, 2025

Consider:

$ cat /tmp/a.ii
struct S {};

struct T {
  S Foo(S);
  S Get(S);
};

S T::Get(S key) {
  [[clang::musttail]] return Foo(key);
}

$ clang -cc1 -triple aarch64-pc-windows-msvc19.34.0 -emit-obj /tmp/a.ii
fatal error: error in backend: failed to perform tail call elimination on a call site marked musttail

(Other aarch64 triples, such as aarch64-unknown-unknown, work.)

@llvmbot
Copy link
Member

llvmbot commented Mar 26, 2025

@llvm/issue-subscribers-backend-aarch64

Author: Hans Wennborg (zmodem)

Consider:
$ cat /tmp/a.ii
struct S {};

struct T {
  S Foo(S);
  S Get(S);
};

S T::Get(S key) {
  [[clang::musttail]] return Foo(key);
}

$ clang -cc1 -triple aarch64-pc-windows-msvc19.34.0 -emit-obj /tmp/a.ii
fatal error: error in backend: failed to perform tail call elimination on a call site marked musttail

(Other aarch64 triples, such as aarch64-unknown-unknown, work.)

@zmodem
Copy link
Collaborator Author

zmodem commented Mar 31, 2025

Slightly shorter: (dropped the arguments)

$ cat /tmp/a.ii
struct S {};

struct T {
  S Foo();
  S Get();
};

S T::Get() {
  [[clang::musttail]] return Foo();
}

@zmodem
Copy link
Collaborator Author

zmodem commented Mar 31, 2025

@zmodem
Copy link
Collaborator Author

zmodem commented Apr 3, 2025

(Mostly notes to self.)

I think checking that both the caller and callee have the inreg attribute on the same argument is not enough; the values of the inreg arguments also have to be the same.

For example, this would not work:

target triple = "aarch64-pc-windows-msvc19.34.0"
  
%struct.S = type { i8 }
declare void @bar(ptr, ptr inreg sret(%struct.S))

define void @foo(ptr %a, ptr inreg sret(%struct.S) %b) {
  musttail call void @bar(ptr %b, ptr inreg sret(%struct.S) %a)
  ret void
}

@foo is supposed to return %b (in x0), but if it tail calls @bar the returned value will be%a instead.

zmodem added a commit that referenced this issue Apr 8, 2025
)

Tail calls were disabled from callers with inreg parameters in 5dc8aeb
with a fixme to check if the callee also takes an inreg parameter.

The issue is that inreg parameters (which are passed in x0 or x1 for
free and member functions respectively) are supposed to be returned (in
x0) at the end of the function. In case of a tail call, that means the
callee needs to return the same value as the caller would.

We can check for that case, and it's not as niche as it sounds, as
that's how Clang will lower one function with an sret return value
calling another, such as:

```
struct T { int x; };
struct S {
    T foo();
    T bar();
};
T S::foo() { return bar(); } // foo's sret argument will get passed directly to bar
```

Fixes #133098
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants