This is an archive of the discontinued LLVM Phabricator instance.

[Coroutines] Don't add musttail call if WebAssembly are enabled
AbandonedPublic

Authored by ChuanqiXu on Jun 20 2022, 1:48 AM.

Details

Reviewers
tlively
Summary

The C++20 Coroutines couldn't be compiled to WebAssembly due to an optimization named symmetric transfer requires the support for musttail calls but WebAssembly doesn't support it yet. So the revision tried to disable the optimization for WebAssembly to make we could compile standard C++20 codes in that platform.

Diff Detail

Event Timeline

ChuanqiXu created this revision.Jun 20 2022, 1:48 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 20 2022, 1:48 AM
ChuanqiXu requested review of this revision.Jun 20 2022, 1:48 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 20 2022, 1:48 AM
xgupta added a subscriber: xgupta.Jun 21 2022, 4:51 AM

Thanks for taking a look at this!

llvm/lib/Transforms/Coroutines/CoroSplit.cpp
1570

It would be good if we could call out to the TargetTransformInfo to ask the backend whether it supports tail calls. Then we could gracefully handle the case where the WebAssembly tail-call target feature is enabled.

Afaict, symmetric transfer is guaranteed by the C++20 standard.

https://eel.is/c++draft/expr.await#note-1 states

[...] Any number of coroutines can be successively resumed in this fashion, eventually returning control flow to the current coroutine caller or resumer [...]

Without symmetric transfer or an equivalent optimization, this statement wouldn't hold true, because we would run out of stack space before resuming an arbitrary number of coroutines

avogelsgesang added a comment.EditedJun 21 2022, 1:35 PM

Also, note that cppcoro (afaict, the de-facto reference implementation for C++20 coroutine types) mentions in a comment, that

[...] the compiler supports returning a coroutine_handle from the await_suspend() method as a way of transferring execution to another coroutine with a guaranteed tail-call.

(emphasis mine)

ChuanqiXu updated this revision to Diff 438896.Jun 21 2022, 8:15 PM

Fix typos.

Afaict, symmetric transfer is guaranteed by the C++20 standard.

https://eel.is/c++draft/expr.await#note-1 states

[...] Any number of coroutines can be successively resumed in this fashion, eventually returning control flow to the current coroutine caller or resumer [...]

Without symmetric transfer or an equivalent optimization, this statement wouldn't hold true, because we would run out of stack space before resuming an arbitrary number of coroutines

Oh, my bad. Thanks for reporting this. But it is still odd to me since it is not supported by all archs and C++ is intended to be target independent. I've sent this question to WG21. I would take an eye on this. And let's not block this one to not prevent C++ coroutines to be used in more targets.

ChuanqiXu added inline comments.Jun 21 2022, 8:21 PM
llvm/lib/Transforms/Coroutines/CoroSplit.cpp
1570

I tried to look TargetTransformInfo at first but I don't find the wanted methods. Then I don't find similar things in CodeGen and Target as well. So it looks like there is not on-the-shelf tool. I prefer the current method as a workaround and replace this workaround later if we or anyone implemented thing interface we want.

I think it would make sense to add a new method to TTI for this, since hardcoding an exception for Wasm is not going to be future-proof at all. The tail-call target feature, while not standard yet, is very close to being standardized and shipped in browsers. It's already available behind a flag in Chrome and Node. Also, if possible, it would be good to perform a different transformation that can still do symmetric transfer without tail calls if the prevailing view is that symmetric transfer is guaranteed by the spec (but simply omitting musttail for now seems like a reasonable stopgap measure).

ChuanqiXu abandoned this revision.Jun 27 2022, 7:08 PM

I think it would make sense to add a new method to TTI for this, since hardcoding an exception for Wasm is not going to be future-proof at all. The tail-call target feature, while not standard yet, is very close to being standardized and shipped in browsers. It's already available behind a flag in Chrome and Node.

Yeah, it makes sense.

Also, if possible, it would be good to perform a different transformation that can still do symmetric transfer without tail calls if the prevailing view is that symmetric transfer is guaranteed by the spec (but simply omitting musttail for now seems like a reasonable stopgap measure).

Maybe it is possible to perform symmetric transfer without tail call. But the complexity of implementation and efficiency may be a problem. So the first step might omit it simply and I'll file an issue for it.