Skip to content

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

Merged

Conversation

aschwaighofer
Copy link
Contributor

Add support for inlining begin_apply instructions to the inliner.

rdar://35399839

@aschwaighofer
Copy link
Contributor Author

@swift-ci Please test

@aschwaighofer aschwaighofer merged commit 35c697c into swiftlang:master Jun 7, 2018
// Handle direct and indirect results.
for (auto YieldedValue : BeginApply->getYieldedValues()) {
// Insert an alloc_stack for indirect results.
if (YieldedValue->getType().isAddress()) {
Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor Author

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.

Copy link
Contributor

@rjmccall rjmccall Aug 2, 2018

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.

Copy link
Contributor Author

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);
Copy link
Contributor

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.

Copy link
Contributor Author

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.

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

Successfully merging this pull request may close these issues.

2 participants