[move-only] Implement escaping closure semantics.

NOTE: A few of the test patterns need to be made better, but this patch series
is large enough, I want to get it into tree and iterate.
This commit is contained in:
Michael Gottesman
2023-02-20 05:41:12 -08:00
parent 50af8fd493
commit 1dd896ded9
20 changed files with 487 additions and 359 deletions

View File

@@ -13,6 +13,7 @@
#define DEBUG_TYPE "allocbox-to-stack"
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/AST/SemanticAttrs.h"
#include "swift/Basic/BlotMapVector.h"
#include "swift/Basic/GraphNodeWorklist.h"
#include "swift/SIL/ApplySite.h"
@@ -524,7 +525,8 @@ static void replaceProjectBoxUsers(SILValue heapBox, SILValue stackBox) {
}
}
static void hoistMarkMustCheckInsts(SingleValueInstruction *stackBox) {
static void hoistMarkMustCheckInsts(SILValue stackBox,
MarkMustCheckInst::CheckKind checkKind) {
StackList<Operand *> worklist(stackBox->getFunction());
for (auto *use : stackBox->getUses()) {
@@ -559,15 +561,17 @@ static void hoistMarkMustCheckInsts(SingleValueInstruction *stackBox) {
mmci->eraseFromParent();
}
SILBuilderWithScope builder(stackBox);
builder.insertAfter(stackBox, [&](SILBuilder &b) {
auto *undef = SILUndef::get(stackBox->getType(), stackBox->getModule());
auto *mmci = b.createMarkMustCheckInst(
stackBox->getLoc(), undef,
MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
stackBox->replaceAllUsesWith(mmci);
mmci->setOperand(stackBox);
});
auto *next = stackBox->getNextInstruction();
auto loc = next->getLoc();
if (isa<TermInst>(next))
loc = RegularLocation::getDiagnosticsOnlyLocation(loc, next->getModule());
SILBuilderWithScope builder(next);
auto *undef = SILUndef::get(stackBox->getType(), *stackBox->getModule());
auto *mmci = builder.createMarkMustCheckInst(loc, undef, checkKind);
stackBox->replaceAllUsesWith(mmci);
mmci->setOperand(stackBox);
}
/// rewriteAllocBoxAsAllocStack - Replace uses of the alloc_box with a
@@ -639,7 +643,8 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI) {
// alloc_stack and convert them to [consumable_but_not_assignable]. This is
// because we are semantically converting from escaping semantics to
// non-escaping semantics.
hoistMarkMustCheckInsts(StackBox);
hoistMarkMustCheckInsts(
StackBox, MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
assert(ABI->getBoxType()->getLayout()->getFields().size() == 1
&& "promoting multi-field box not implemented");
@@ -1016,6 +1021,24 @@ specializeApplySite(SILOptFunctionBuilder &FuncBuilder, ApplySite Apply,
Cloner.populateCloned();
ClonedFn = Cloner.getCloned();
pass.T->addFunctionToPassManagerWorklist(ClonedFn, F);
// Set the moveonly ignore flag so we do not emit an error on the original
// function even though it is still around.
F->addSemanticsAttr(semantics::NO_MOVEONLY_DIAGNOSTICS);
// If any of our promoted callee arg indices were originally noncopyable let
// boxes, convert them from having escaping to having non-escaping
// semantics.
for (unsigned index : PromotedCalleeArgIndices) {
if (F->getArgument(index)->getType().isBoxedNonCopyableType(*F)) {
auto boxType = F->getArgument(index)->getType().castTo<SILBoxType>();
bool isMutable = boxType->getLayout()->getFields()[0].isMutable();
auto checkKind =
isMutable ? MarkMustCheckInst::CheckKind::AssignableButNotConsumable
: MarkMustCheckInst::CheckKind::NoConsumeOrAssign;
hoistMarkMustCheckInsts(ClonedFn->getArgument(index), checkKind);
}
}
}
// Now create the new ApplySite using the cloned function.