Skip to content

[sil] Add a new attribute called @closureCaptured to SILFunctionArguments that are closure capture arguments. #62592

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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 35 additions & 10 deletions include/swift/SIL/SILArgument.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,18 +332,21 @@ class SILPhiArgument : public SILArgument {
class SILFunctionArgument : public SILArgument {
friend class SILBasicBlock;

bool noImplicitCopy = false;
LifetimeAnnotation lifetimeAnnotation = LifetimeAnnotation::None;
USE_SHARED_UINT32;

SILFunctionArgument(
SILBasicBlock *parentBlock, SILType type,
ValueOwnershipKind ownershipKind, const ValueDecl *decl = nullptr,
bool isNoImplicitCopy = false,
LifetimeAnnotation lifetimeAnnotation = LifetimeAnnotation::None)
LifetimeAnnotation lifetimeAnnotation = LifetimeAnnotation::None,
bool isCapture = false)
: SILArgument(ValueKind::SILFunctionArgument, parentBlock, type,
ownershipKind, decl),
noImplicitCopy(isNoImplicitCopy),
lifetimeAnnotation(lifetimeAnnotation) {}
ownershipKind, decl) {
sharedUInt32().SILFunctionArgument.noImplicitCopy = isNoImplicitCopy;
sharedUInt32().SILFunctionArgument.lifetimeAnnotation = lifetimeAnnotation;
sharedUInt32().SILFunctionArgument.closureCapture = isCapture;
}

// A special constructor, only intended for use in
// SILBasicBlock::replaceFunctionArg.
explicit SILFunctionArgument(SILType type, ValueOwnershipKind ownershipKind,
Expand All @@ -352,16 +355,28 @@ class SILFunctionArgument : public SILArgument {
}

public:
bool isNoImplicitCopy() const { return noImplicitCopy; }
bool isNoImplicitCopy() const {
return sharedUInt32().SILFunctionArgument.noImplicitCopy;
}

void setNoImplicitCopy(bool newValue) {
sharedUInt32().SILFunctionArgument.noImplicitCopy = newValue;
}

void setNoImplicitCopy(bool newValue) { noImplicitCopy = newValue; }
bool isClosureCapture() const {
return sharedUInt32().SILFunctionArgument.closureCapture;
}
void setClosureCapture(bool newValue) {
sharedUInt32().SILFunctionArgument.closureCapture = newValue;
}

LifetimeAnnotation getLifetimeAnnotation() const {
return lifetimeAnnotation;
return LifetimeAnnotation::Case(
sharedUInt32().SILFunctionArgument.lifetimeAnnotation);
}

void setLifetimeAnnotation(LifetimeAnnotation newValue) {
lifetimeAnnotation = newValue;
sharedUInt32().SILFunctionArgument.lifetimeAnnotation = newValue;
}

Lifetime getLifetime() const {
Expand Down Expand Up @@ -390,6 +405,16 @@ class SILFunctionArgument : public SILArgument {
return getArgumentConvention() == convention;
}

/// Copy all flags stored in this->sharedUInt32() into arg.
///
/// By using this API, cloners can be sure they are updated for the addition
/// of further flags.
void copyFlags(SILFunctionArgument *arg) {
setNoImplicitCopy(arg->isNoImplicitCopy());
setLifetimeAnnotation(arg->getLifetimeAnnotation());
setClosureCapture(arg->isClosureCapture());
}

static bool classof(const SILInstruction *) = delete;
static bool classof(const SILUndef *) = delete;
static bool classof(SILNodePointer node) {
Expand Down
4 changes: 3 additions & 1 deletion include/swift/SIL/SILNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,10 @@ class alignas(8) SILNode :
SHARED_FIELD(FloatLiteralInst, uint32_t numBits);
SHARED_FIELD(StringLiteralInst, uint32_t length);
SHARED_FIELD(PointerToAddressInst, uint32_t alignment);
SHARED_FIELD(SILFunctionArgument, uint32_t noImplicitCopy : 1,
lifetimeAnnotation : 2, closureCapture : 1);

// Do not use `_sharedUInt32_private` outside of SILNode.
// Do not use `_sharedUInt32_private` outside of SILNode.
} _sharedUInt32_private;

static_assert(sizeof(SharedUInt32Fields) == sizeof(uint32_t),
Expand Down
3 changes: 1 addition & 2 deletions lib/SIL/IR/SILBasicBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,7 @@ void SILBasicBlock::cloneArgumentList(SILBasicBlock *Other) {
for (auto *FuncArg : Other->getSILFunctionArguments()) {
auto *NewArg =
createFunctionArgument(FuncArg->getType(), FuncArg->getDecl());
NewArg->setNoImplicitCopy(FuncArg->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(FuncArg->getLifetimeAnnotation());
NewArg->copyFlags(FuncArg);
}
return;
}
Expand Down
23 changes: 16 additions & 7 deletions lib/SIL/IR/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ struct SILValuePrinterInfo {
Optional<ValueOwnershipKind> OwnershipKind;
bool IsNoImplicitCopy = false;
LifetimeAnnotation Lifetime = LifetimeAnnotation::None;
bool IsCapture = false;

SILValuePrinterInfo(ID ValueID) : ValueID(ValueID), Type(), OwnershipKind() {}
SILValuePrinterInfo(ID ValueID, SILType Type)
Expand All @@ -169,13 +170,15 @@ struct SILValuePrinterInfo {
: ValueID(ValueID), Type(Type), OwnershipKind(OwnershipKind) {}
SILValuePrinterInfo(ID ValueID, SILType Type,
ValueOwnershipKind OwnershipKind, bool IsNoImplicitCopy,
LifetimeAnnotation Lifetime)
LifetimeAnnotation Lifetime, bool IsCapture)
: ValueID(ValueID), Type(Type), OwnershipKind(OwnershipKind),
IsNoImplicitCopy(IsNoImplicitCopy), Lifetime(Lifetime) {}
IsNoImplicitCopy(IsNoImplicitCopy), Lifetime(Lifetime),
IsCapture(IsCapture) {}
SILValuePrinterInfo(ID ValueID, SILType Type, bool IsNoImplicitCopy,
LifetimeAnnotation Lifetime)
LifetimeAnnotation Lifetime, bool IsCapture)
: ValueID(ValueID), Type(Type), OwnershipKind(),
IsNoImplicitCopy(IsNoImplicitCopy), Lifetime(Lifetime) {}
IsNoImplicitCopy(IsNoImplicitCopy), Lifetime(Lifetime),
IsCapture(IsCapture) {}
};

/// Return the fully qualified dotted path for DeclContext.
Expand Down Expand Up @@ -659,6 +662,8 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
*this << "@_lexical ";
break;
}
if (i.IsCapture)
*this << "@closureCapture ";
if (i.OwnershipKind && *i.OwnershipKind != OwnershipKind::None) {
*this << "@" << i.OwnershipKind.value() << " ";
}
Expand Down Expand Up @@ -693,14 +698,18 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
}
SILValuePrinterInfo getIDAndType(SILFunctionArgument *arg) {
return {Ctx.getID(arg), arg->getType(), arg->isNoImplicitCopy(),
arg->getLifetimeAnnotation()};
arg->getLifetimeAnnotation(), arg->isClosureCapture()};
}
SILValuePrinterInfo getIDAndTypeAndOwnership(SILValue V) {
return {Ctx.getID(V), V ? V->getType() : SILType(), V->getOwnershipKind()};
}
SILValuePrinterInfo getIDAndTypeAndOwnership(SILFunctionArgument *arg) {
return {Ctx.getID(arg), arg->getType(), arg->getOwnershipKind(),
arg->isNoImplicitCopy(), arg->getLifetimeAnnotation()};
return {Ctx.getID(arg),
arg->getType(),
arg->getOwnershipKind(),
arg->isNoImplicitCopy(),
arg->getLifetimeAnnotation(),
arg->isClosureCapture()};
}

//===--------------------------------------------------------------------===//
Expand Down
9 changes: 7 additions & 2 deletions lib/SIL/Parser/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6495,16 +6495,20 @@ bool SILParser::parseSILBasicBlock(SILBuilder &B) {
return true;

bool foundNoImplicitCopy = false;
bool foundClosureCapture = false;
bool foundLexical = false;
bool foundEagerMove = false;
while (auto attributeName = parseOptionalAttribute(
{"noImplicitCopy", "_lexical", "_eagerMove"})) {
while (auto attributeName =
parseOptionalAttribute({"noImplicitCopy", "_lexical",
"_eagerMove", "closureCapture"})) {
if (*attributeName == "noImplicitCopy")
foundNoImplicitCopy = true;
else if (*attributeName == "_lexical")
foundLexical = true;
else if (*attributeName == "_eagerMove")
foundEagerMove = true;
else if (*attributeName == "closureCapture")
foundClosureCapture = true;
else {
llvm_unreachable("Unexpected attribute!");
}
Expand Down Expand Up @@ -6533,6 +6537,7 @@ bool SILParser::parseSILBasicBlock(SILBuilder &B) {
if (IsEntry) {
auto *fArg = BB->createFunctionArgument(Ty);
fArg->setNoImplicitCopy(foundNoImplicitCopy);
fArg->setClosureCapture(foundClosureCapture);
fArg->setLifetimeAnnotation(lifetime);
Arg = fArg;

Expand Down
9 changes: 6 additions & 3 deletions lib/SILGen/SILGenBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,13 +436,15 @@ ManagedValue SILGenBuilder::createLoadCopy(SILLocation loc, ManagedValue v,
static ManagedValue createInputFunctionArgument(
SILGenBuilder &B, SILType type, SILLocation loc, ValueDecl *decl = nullptr,
bool isNoImplicitCopy = false,
LifetimeAnnotation lifetimeAnnotation = LifetimeAnnotation::None) {
LifetimeAnnotation lifetimeAnnotation = LifetimeAnnotation::None,
bool isClosureCapture = false) {
auto &SGF = B.getSILGenFunction();
SILFunction &F = B.getFunction();
assert((F.isBare() || decl) &&
"Function arguments of non-bare functions must have a decl");
auto *arg = F.begin()->createFunctionArgument(type, decl);
arg->setNoImplicitCopy(isNoImplicitCopy);
arg->setClosureCapture(isClosureCapture);
arg->setLifetimeAnnotation(lifetimeAnnotation);
switch (arg->getArgumentConvention()) {
case SILArgumentConvention::Indirect_In_Guaranteed:
Expand Down Expand Up @@ -477,9 +479,10 @@ static ManagedValue createInputFunctionArgument(

ManagedValue SILGenBuilder::createInputFunctionArgument(
SILType type, ValueDecl *decl, bool isNoImplicitCopy,
LifetimeAnnotation lifetimeAnnotation) {
LifetimeAnnotation lifetimeAnnotation, bool isClosureCapture) {
return ::createInputFunctionArgument(*this, type, SILLocation(decl), decl,
isNoImplicitCopy, lifetimeAnnotation);
isNoImplicitCopy, lifetimeAnnotation,
isClosureCapture);
}

ManagedValue
Expand Down
3 changes: 2 additions & 1 deletion lib/SILGen/SILGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,8 @@ class SILGenBuilder : public SILBuilder {
/// function argument for an out parameter.
ManagedValue createInputFunctionArgument(
SILType type, ValueDecl *decl, bool isNoImplicitCopy = false,
LifetimeAnnotation lifetimeAnnotation = LifetimeAnnotation::None);
LifetimeAnnotation lifetimeAnnotation = LifetimeAnnotation::None,
bool isClosureCapture = false);

/// Create a SILArgument for an input parameter. Uses \p loc to create any
/// copies necessary. Asserts if used to create a function argument for an out
Expand Down
13 changes: 9 additions & 4 deletions lib/SILGen/SILGenProlog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,8 +520,10 @@ static void emitCaptureArguments(SILGenFunction &SGF,
auto &lowering = SGF.getTypeLowering(type);
// Constant decls are captured by value.
SILType ty = lowering.getLoweredType();
ManagedValue val = ManagedValue::forUnmanaged(
SGF.F.begin()->createFunctionArgument(ty, VD));
auto *arg = SGF.F.begin()->createFunctionArgument(ty, VD);
arg->setClosureCapture(true);

ManagedValue val = ManagedValue::forUnmanaged(arg);

// If the original variable was settable, then Sema will have treated the
// VarDecl as an lvalue, even in the closure's use. As such, we need to
Expand Down Expand Up @@ -575,8 +577,9 @@ static void emitCaptureArguments(SILGenFunction &SGF,
SGF.SGM.Types.getLoweredRValueType(TypeExpansionContext::minimal(),
type),
SGF.F.getGenericEnvironment(), /*mutable*/ true);
SILValue box = SGF.F.begin()->createFunctionArgument(
auto *box = SGF.F.begin()->createFunctionArgument(
SILType::getPrimitiveObjectType(boxTy), VD);
box->setClosureCapture(true);
SILValue addr = SGF.B.createProjectBox(VD, box, 0);
SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(addr, box);
SILDebugVariable DbgVar(VD->isLet(), ArgNo);
Expand All @@ -595,7 +598,9 @@ static void emitCaptureArguments(SILGenFunction &SGF,
if (isInOut || SGF.SGM.M.useLoweredAddresses()) {
ty = ty.getAddressType();
}
SILValue arg = SGF.F.begin()->createFunctionArgument(ty, VD);
auto *fArg = SGF.F.begin()->createFunctionArgument(ty, VD);
fArg->setClosureCapture(true);
SILValue arg = SILValue(fArg);
if (isInOut && (ty.isMoveOnly() && !ty.isMoveOnlyWrapped())) {
arg = SGF.B.createMarkMustCheckInst(
Loc, arg, MarkMustCheckInst::CheckKind::NoImplicitCopy);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,8 +393,7 @@ void FunctionSignatureTransform::ArgumentExplosionFinalizeOptimizedFunction() {
auto *Argument =
BB->insertFunctionArgument(ArgOffset, Node->getType(), OwnershipKind,
BB->getArgument(OldArgIndex)->getDecl());
Argument->setNoImplicitCopy(AD.Arg->isNoImplicitCopy());
Argument->setLifetimeAnnotation(AD.Arg->getLifetimeAnnotation());
Argument->copyFlags(AD.Arg);
LeafValues.push_back(Argument);
TransformDescriptor.AIM[TotalArgIndex - 1] = AD.Index;
++ArgOffset;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,7 @@ void ExistentialSpecializerCloner::cloneArguments(
LoweredTy.getCategoryType(ArgDesc.Arg->getType().getCategory());
auto *NewArg =
ClonedEntryBB->createFunctionArgument(MappedTy, ArgDesc.Decl);
NewArg->setNoImplicitCopy(ArgDesc.Arg->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(ArgDesc.Arg->getLifetimeAnnotation());
NewArg->setOwnershipKind(ValueOwnershipKind(
NewF, MappedTy, ArgDesc.Arg->getArgumentConvention()));
NewArg->copyFlags(ArgDesc.Arg);
entryArgs.push_back(NewArg);
continue;
}
Expand All @@ -182,8 +179,7 @@ void ExistentialSpecializerCloner::cloneArguments(
GenericSILType, ArgDesc.Decl,
ValueOwnershipKind(NewF, GenericSILType,
ArgDesc.Arg->getArgumentConvention()));
NewArg->setNoImplicitCopy(ArgDesc.Arg->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(ArgDesc.Arg->getLifetimeAnnotation());
NewArg->copyFlags(ArgDesc.Arg);
// Determine the Conformances.
SILType ExistentialType = ArgDesc.Arg->getType().getObjectType();
CanType OpenedType = NewArg->getType().getASTType();
Expand Down Expand Up @@ -408,8 +404,7 @@ void ExistentialTransform::populateThunkBody() {
auto argumentType = ArgDesc.Arg->getType();
auto *NewArg =
ThunkBody->createFunctionArgument(argumentType, ArgDesc.Decl);
NewArg->setNoImplicitCopy(ArgDesc.Arg->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(ArgDesc.Arg->getLifetimeAnnotation());
NewArg->copyFlags(ArgDesc.Arg);
}

/// Builder to add new instructions in the Thunk.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -568,8 +568,7 @@ void FunctionSignatureTransform::createFunctionSignatureOptimizedFunction() {
for (auto &ArgDesc : TransformDescriptor.ArgumentDescList) {
auto *NewArg =
ThunkBody->createFunctionArgument(ArgDesc.Arg->getType(), ArgDesc.Decl);
NewArg->setNoImplicitCopy(ArgDesc.Arg->isNoImplicitCopy());
NewArg->setLifetimeAnnotation(ArgDesc.Arg->getLifetimeAnnotation());
NewArg->copyFlags(ArgDesc.Arg);
}

SILLocation Loc = RegularLocation::getAutoGeneratedLocation();
Expand Down
5 changes: 1 addition & 4 deletions lib/SILOptimizer/IPO/CapturePropagation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,7 @@ void CapturePropagationCloner::cloneClosure(

auto *MappedValue = ClonedEntryBB->createFunctionArgument(
remapType(Arg->getType()), Arg->getDecl());
MappedValue->setNoImplicitCopy(
cast<SILFunctionArgument>(Arg)->isNoImplicitCopy());
MappedValue->setLifetimeAnnotation(
cast<SILFunctionArgument>(Arg)->getLifetimeAnnotation());
MappedValue->copyFlags(cast<SILFunctionArgument>(Arg));
entryArgs.push_back(MappedValue);
}
assert(OrigEntryBB->args_size() - ArgIdx == PartialApplyArgs.size()
Expand Down
5 changes: 1 addition & 4 deletions lib/SILOptimizer/IPO/ClosureSpecializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -808,10 +808,7 @@ void ClosureSpecCloner::populateCloned() {
auto typeInContext = Cloned->getLoweredType(Arg->getType());
auto *MappedValue =
ClonedEntryBB->createFunctionArgument(typeInContext, Arg->getDecl());
MappedValue->setNoImplicitCopy(
cast<SILFunctionArgument>(Arg)->isNoImplicitCopy());
MappedValue->setLifetimeAnnotation(
cast<SILFunctionArgument>(Arg)->getLifetimeAnnotation());
MappedValue->copyFlags(cast<SILFunctionArgument>(Arg));
entryArgs.push_back(MappedValue);
}

Expand Down
10 changes: 2 additions & 8 deletions lib/SILOptimizer/Mandatory/CapturePromotion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -493,10 +493,7 @@ void ClosureCloner::populateCloned() {
// Simply create a new argument which copies the original argument
auto *mappedValue = clonedEntryBB->createFunctionArgument(
(*ai)->getType(), (*ai)->getDecl());
mappedValue->setNoImplicitCopy(
cast<SILFunctionArgument>(*ai)->isNoImplicitCopy());
mappedValue->setLifetimeAnnotation(
cast<SILFunctionArgument>(*ai)->getLifetimeAnnotation());
mappedValue->copyFlags(cast<SILFunctionArgument>(*ai));
entryArgs.push_back(mappedValue);
continue;
}
Expand All @@ -510,10 +507,7 @@ void ClosureCloner::populateCloned() {
.getObjectType();
auto *newArg =
clonedEntryBB->createFunctionArgument(boxedTy, (*ai)->getDecl());
newArg->setNoImplicitCopy(
cast<SILFunctionArgument>(*ai)->isNoImplicitCopy());
newArg->setLifetimeAnnotation(
cast<SILFunctionArgument>(*ai)->getLifetimeAnnotation());
newArg->copyFlags(cast<SILFunctionArgument>(*ai));
SILValue mappedValue = newArg;

// If SIL ownership is enabled, we need to perform a borrow here if we have
Expand Down
10 changes: 2 additions & 8 deletions lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -801,10 +801,7 @@ PromotedParamCloner::populateCloned() {
Cloned->getModule().Types, 0);
auto *promotedArg =
ClonedEntryBB->createFunctionArgument(promotedTy, (*I)->getDecl());
promotedArg->setNoImplicitCopy(
cast<SILFunctionArgument>(*I)->isNoImplicitCopy());
promotedArg->setLifetimeAnnotation(
cast<SILFunctionArgument>(*I)->getLifetimeAnnotation());
promotedArg->copyFlags(cast<SILFunctionArgument>(*I));
OrigPromotedParameters.insert(*I);

NewPromotedArgs[ArgNo] = promotedArg;
Expand All @@ -819,10 +816,7 @@ PromotedParamCloner::populateCloned() {
// Create a new argument which copies the original argument.
auto *newArg = ClonedEntryBB->createFunctionArgument((*I)->getType(),
(*I)->getDecl());
newArg->setNoImplicitCopy(
cast<SILFunctionArgument>(*I)->isNoImplicitCopy());
newArg->setLifetimeAnnotation(
cast<SILFunctionArgument>(*I)->getLifetimeAnnotation());
newArg->copyFlags(cast<SILFunctionArgument>(*I));
entryArgs.push_back(newArg);
}
++ArgNo;
Expand Down
Loading