-
Notifications
You must be signed in to change notification settings - Fork 10.6k
[inlining] Fix two bugs around inlining of coroutines. #27928
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -102,16 +102,20 @@ class BeginApplySite { | |
| return BeginApplySite(BeginApply, Loc, Builder); | ||
| } | ||
|
|
||
| void preprocess(SILBasicBlock *returnToBB) { | ||
| void preprocess(SILBasicBlock *returnToBB, | ||
| SmallVectorImpl<SILInstruction *> &endBorrowInsertPts) { | ||
| SmallVector<EndApplyInst *, 1> endApplyInsts; | ||
| SmallVector<AbortApplyInst *, 1> abortApplyInsts; | ||
| BeginApply->getCoroutineEndPoints(endApplyInsts, abortApplyInsts); | ||
| while (!endApplyInsts.empty()) { | ||
| auto *endApply = endApplyInsts.pop_back_val(); | ||
| collectEndApply(endApply); | ||
| endBorrowInsertPts.push_back(&*std::next(endApply->getIterator())); | ||
| } | ||
| while (!abortApplyInsts.empty()) { | ||
| collectAbortApply(abortApplyInsts.pop_back_val()); | ||
| auto *abortApply = abortApplyInsts.pop_back_val(); | ||
| collectAbortApply(abortApply); | ||
| endBorrowInsertPts.push_back(&*std::next(abortApply->getIterator())); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -428,29 +432,38 @@ SILInlineCloner::cloneInline(ArrayRef<SILValue> AppliedArgs) { | |
|
|
||
| SmallVector<SILValue, 4> entryArgs; | ||
| entryArgs.reserve(AppliedArgs.size()); | ||
| SmallBitVector borrowedArgs(AppliedArgs.size()); | ||
|
|
||
| auto calleeConv = getCalleeFunction()->getConventions(); | ||
| for (unsigned argIdx = 0, endIdx = AppliedArgs.size(); argIdx < endIdx; | ||
| ++argIdx) { | ||
| SILValue callArg = AppliedArgs[argIdx]; | ||
| for (auto p : llvm::enumerate(AppliedArgs)) { | ||
| SILValue callArg = p.value(); | ||
| unsigned idx = p.index(); | ||
| // Insert begin/end borrow for guaranteed arguments. | ||
| if (argIdx >= calleeConv.getSILArgIndexOfFirstParam() | ||
| && calleeConv.getParamInfoForSILArg(argIdx).isGuaranteed()) { | ||
| callArg = borrowFunctionArgument(callArg, Apply); | ||
| if (idx >= calleeConv.getSILArgIndexOfFirstParam() && | ||
| calleeConv.getParamInfoForSILArg(idx).isGuaranteed()) { | ||
| if (SILValue newValue = borrowFunctionArgument(callArg, Apply)) { | ||
| callArg = newValue; | ||
| borrowedArgs[idx] = true; | ||
| } | ||
| } | ||
| entryArgs.push_back(callArg); | ||
| } | ||
|
|
||
| // Create the return block and set ReturnToBB for use in visitTerminator | ||
| // callbacks. | ||
| SILBasicBlock *callerBB = Apply.getParent(); | ||
| SILBasicBlock *callerBlock = Apply.getParent(); | ||
| SILBasicBlock *throwBlock = nullptr; | ||
| SmallVector<SILInstruction *, 1> endBorrowInsertPts; | ||
|
|
||
| switch (Apply.getKind()) { | ||
| case FullApplySiteKind::ApplyInst: { | ||
| auto *AI = dyn_cast<ApplyInst>(Apply); | ||
|
|
||
| // Split the BB and do NOT create a branch between the old and new | ||
| // BBs; we will create the appropriate terminator manually later. | ||
| ReturnToBB = | ||
| callerBB->split(std::next(Apply.getInstruction()->getIterator())); | ||
| callerBlock->split(std::next(Apply.getInstruction()->getIterator())); | ||
| endBorrowInsertPts.push_back(&*ReturnToBB->begin()); | ||
|
|
||
| // Create an argument on the return-to BB representing the returned value. | ||
| auto *retArg = | ||
|
|
@@ -459,22 +472,49 @@ SILInlineCloner::cloneInline(ArrayRef<SILValue> AppliedArgs) { | |
| AI->replaceAllUsesWith(retArg); | ||
| break; | ||
| } | ||
| case FullApplySiteKind::BeginApplyInst: | ||
| case FullApplySiteKind::BeginApplyInst: { | ||
| ReturnToBB = | ||
| callerBB->split(std::next(Apply.getInstruction()->getIterator())); | ||
| BeginApply->preprocess(ReturnToBB); | ||
| callerBlock->split(std::next(Apply.getInstruction()->getIterator())); | ||
| // For begin_apply, we insert the end_borrow in the end_apply, abort_apply | ||
| // blocks to ensure that our borrowed values live over both the body and | ||
| // resume block of our coroutine. | ||
| BeginApply->preprocess(ReturnToBB, endBorrowInsertPts); | ||
| break; | ||
|
|
||
| case FullApplySiteKind::TryApplyInst: | ||
| ReturnToBB = cast<TryApplyInst>(Apply)->getNormalBB(); | ||
| } | ||
| case FullApplySiteKind::TryApplyInst: { | ||
| auto *tai = cast<TryApplyInst>(Apply); | ||
| ReturnToBB = tai->getNormalBB(); | ||
| endBorrowInsertPts.push_back(&*ReturnToBB->begin()); | ||
| throwBlock = tai->getErrorBB(); | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| // Then insert end_borrow in our end borrow block and in the throw | ||
| // block if we have one. | ||
| if (borrowedArgs.any()) { | ||
| for (unsigned i : indices(AppliedArgs)) { | ||
| if (!borrowedArgs.test(i)) { | ||
| continue; | ||
| } | ||
|
|
||
| for (auto *insertPt : endBorrowInsertPts) { | ||
| SILBuilderWithScope returnBuilder(insertPt, getBuilder()); | ||
| returnBuilder.createEndBorrow(Apply.getLoc(), entryArgs[i]); | ||
| } | ||
|
|
||
| if (throwBlock) { | ||
| SILBuilderWithScope throwBuilder(throwBlock->begin(), getBuilder()); | ||
| throwBuilder.createEndBorrow(Apply.getLoc(), entryArgs[i]); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Visit original BBs in depth-first preorder, starting with the | ||
| // entry block, cloning all instructions and terminators. | ||
| // | ||
| // NextIter is initialized during `fixUp`. | ||
| cloneFunctionBody(getCalleeFunction(), callerBB, entryArgs); | ||
| cloneFunctionBody(getCalleeFunction(), callerBlock, entryArgs); | ||
|
|
||
| // For non-throwing applies, the inlined body now unconditionally branches to | ||
| // the returned-to-code, which was previously part of the call site's basic | ||
|
|
@@ -560,25 +600,11 @@ SILValue SILInlineCloner::borrowFunctionArgument(SILValue callArg, | |
| FullApplySite AI) { | ||
| if (!AI.getFunction()->hasOwnership() | ||
| || callArg.getOwnershipKind() != ValueOwnershipKind::Owned) { | ||
| return callArg; | ||
| return SILValue(); | ||
| } | ||
|
|
||
| SILBuilderWithScope beginBuilder(AI.getInstruction(), getBuilder()); | ||
| auto *borrow = beginBuilder.createBeginBorrow(AI.getLoc(), callArg); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code was moved into the caller code. As a result, we only insert the begin_borrow here. This allowed me to handle all of the cases together. As a benefit, I was able to sink these cases into the exhaustive switch! Ensuring that it will be updated in the future if new applies are added. |
||
| if (auto *tryAI = dyn_cast<TryApplyInst>(AI)) { | ||
| SILBuilderWithScope returnBuilder(tryAI->getNormalBB()->begin(), | ||
| getBuilder()); | ||
| returnBuilder.createEndBorrow(AI.getLoc(), borrow, callArg); | ||
|
|
||
| SILBuilderWithScope throwBuilder(tryAI->getErrorBB()->begin(), | ||
| getBuilder()); | ||
| throwBuilder.createEndBorrow(AI.getLoc(), borrow, callArg); | ||
| } else { | ||
| SILBuilderWithScope returnBuilder( | ||
| std::next(AI.getInstruction()->getIterator()), getBuilder()); | ||
| returnBuilder.createEndBorrow(AI.getLoc(), borrow, callArg); | ||
| } | ||
| return borrow; | ||
| return beginBuilder.createBeginBorrow(AI.getLoc(), callArg); | ||
| } | ||
|
|
||
| void SILInlineCloner::visitDebugValueInst(DebugValueInst *Inst) { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
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 did this since I wanted to make it so that the function could fail. This made it so that we eliminated unneeded assigns of callArg -> callArg and also allows me to use the invariant that this is not a borrowed argument if we return SILValue().
This then allowed me to rewrite the end_borrow code to be abstracted over all of the different applies that we need to handle and include the meat of this code in an exhaustive switch!