-
Notifications
You must be signed in to change notification settings - Fork 10.5k
SILInliner: Initial support for begin_apply #17026
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
SILInliner: Initial support for begin_apply #17026
Conversation
@swift-ci Please test |
// Handle direct and indirect results. | ||
for (auto YieldedValue : BeginApply->getYieldedValues()) { | ||
// Insert an alloc_stack for indirect results. | ||
if (YieldedValue->getType().isAddress()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this just a placeholder? Because this shouldn't be necessary — the indirect yield comes from a value that should be live after inlining — and it's not semantically valid to introduce a copy if e.g. the yielded value is inout
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wrote this under the assumption we yield indirect values only @in
.
I agree. I could have just used the inlined alloc_stack instead.
I am not sure how inout yields work. What is being yielded on the callee side? I would assume the following: We create a temporary location in the callee that is then replaced by the caller's location if we inline. Is the following a correct use of an inout yield?
Caller:
%caller_loc = alloc_stack
copy_addr %something to [initialization] %caller_loc
(%caller_loc, %token)= begin_apply %coroutine()
Callee:
sil [transparent] @coroutine : $@yield_once() -> (@yields @inout Something) {
entry:
%temp = alloc_stack $Something
copy_addr %something to %temp
yield %temp : $*Something, resume resume, unwind unwind
resume:
apply %some_use(%temp)
Couldn't this just as well be expressed as a parameter that we pass inout to the begin_apply?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, right the interesting case is this:
Caller:
(%caller_loc, %token)= begin_apply %coroutine()
copy_addr %something to %caller_loc // This is now available on the resume path of the callee.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should think of the yield
like a function call. The coroutine can produce any address it wants as the yield
value, and the caller just receives an opaque pointer — just like a function can pass any address it wants as an inout
argument, and the callee just receives an opaque pointer.
The convention on the yielded address is what the caller is expected to have done before it resumes the coroutine; it becomes invalid after the coroutine resumes. Among other things, this means that if the caller wants to save a value that was yielded @in
to it, it's required to move the value into caller-owned memory. In the inliner, you aren't reordering code in the caller, so you can just assume that kind of lifetime issue is handled correctly; it's the code-motion and copy-propagation optimizations that will have to worry about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, thanks.
Fixed both issues in #18477
auto *RetArg = ReturnToBB->createPHIArgument(YieldedValue->getType(), | ||
ValueOwnershipKind::Owned); | ||
// Replace all uses of the ApplyInst with the new argument. | ||
YieldedValue->replaceAllUsesWith(RetArg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you thinking that you'll phi
together all the yield sites? Because that's going to break a lot of structural properties in the inlined coroutine if there are values live across the yield
. If there are multiple yield
sites, you just have to clone code in the caller in general. It might be okay to just not inline these cases in the short term, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I overlooked that. You are correct that I have to disallow inlining if the values live across the yield are not dominating all yields with the current approach (or I think I could rewrite the code such that's they to dominate for address values and add phis and undefs for direct values). I tried not to replicate caller code.
Add support for inlining begin_apply instructions to the inliner.
rdar://35399839