Skip to content

Commit 19bd65c

Browse files
committed
OpaqueValues: add support for property wrappers
resolves rdar://163071245
1 parent 12a915f commit 19bd65c

15 files changed

+210
-95
lines changed

include/swift/SIL/SILFunctionConventions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,9 @@ class SILFunctionConventions {
515515
- getNumIndirectSILErrorResults()];
516516
}
517517

518+
/// WARNING: Do not use this from SILGen!
519+
/// Use methods such as `isSILIndirect` or query the ParameterInfo instead.
520+
///
518521
/// Return the SIL argument convention of apply/entry argument at
519522
/// the given argument index.
520523
SILArgumentConvention getSILArgumentConvention(unsigned index) const;

lib/SIL/IR/SILArgument.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ SILParameterInfo SILFunctionArgument::getKnownParameterInfo() const {
8787
return getFunction()->getConventions().getParamInfoForSILArg(getIndex());
8888
}
8989

90+
/// WARNING: Do not use this from SILGen!
91+
/// Use methods such as `isSILIndirect` or query the ParameterInfo instead.
9092
SILArgumentConvention
9193
SILFunctionConventions::getSILArgumentConvention(unsigned index) const {
9294
assert(index < getNumSILArguments());

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3189,9 +3189,9 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
31893189
CanSILFunctionType initTy = initFn->getType().castTo<SILFunctionType>();
31903190
SILFunctionConventions initConv(initTy, AI->getModule());
31913191

3192-
require(initConv.getNumIndirectSILResults() ==
3192+
require(initConv.getResults().size() ==
31933193
AI->getNumInitializedProperties(),
3194-
"init function has invalid number of indirect results");
3194+
"init function has invalid number of results");
31953195
checkAssigOrInitInstAccessorArgs(Src->getType(), initConv);
31963196
}
31973197

lib/SILGen/SILGenConstructor.cpp

Lines changed: 56 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1822,35 +1822,46 @@ void SILGenFunction::emitPropertyWrappedFieldInitAccessor(
18221822
RegularLocation Loc(value);
18231823
Loc.markAutoGenerated();
18241824

1825-
auto loweredFuncDeclTy = F.getLoweredFunctionType();
1826-
bool isLocalContext = vd->getDeclContext()->isLocalContext();
1827-
1828-
auto createArgument = [&](VarDecl *property, SILType type,
1829-
bool markUninitialized = false) {
1830-
auto *arg = ParamDecl::createImplicit(
1831-
getASTContext(), property->getBaseIdentifier(),
1832-
property->getBaseIdentifier(), property->getInterfaceType(),
1833-
declContext, ParamSpecifier::InOut);
1834-
1835-
RegularLocation loc(property);
1836-
loc.markAutoGenerated();
1837-
1838-
SILValue argValue = F.begin()->createFunctionArgument(type, arg);
1839-
if (markUninitialized) {
1840-
argValue = B.createMarkUninitializedOut(loc, argValue);
1841-
}
1825+
auto backingStorage = vd->getPropertyWrapperBackingProperty();
1826+
Type returnTy = vd->getPropertyWrapperBackingPropertyType();
1827+
1828+
/// This thunk uses its own return convention, unlike a usual function,
1829+
/// by always returning its result indirect, even if the type is trivial.
1830+
///
1831+
/// Because of that, much of the work that would normally be handled in SILGen
1832+
/// using standard function conventions is done manually here, when
1833+
/// -enable-sil-opaque-values is disabled. Part of the reason for this is
1834+
/// that calls to this accessor are lowered after DefiniteInitialization.
1835+
if (useLoweredAddresses()) {
1836+
returnTy = TupleType::getEmpty(F.getASTContext());
1837+
1838+
auto loweredFuncDeclTy = F.getLoweredFunctionType();
1839+
auto createArgument = [&](VarDecl *property, SILType type,
1840+
bool markUninitialized = false) {
1841+
auto *arg = ParamDecl::createImplicit(
1842+
getASTContext(), property->getBaseIdentifier(),
1843+
property->getBaseIdentifier(), property->getInterfaceType(),
1844+
declContext, ParamSpecifier::InOut);
1845+
1846+
RegularLocation loc(property);
1847+
loc.markAutoGenerated();
1848+
1849+
SILValue argValue = F.begin()->createFunctionArgument(type, arg);
1850+
if (markUninitialized) {
1851+
argValue = B.createMarkUninitializedOut(loc, argValue);
1852+
}
18421853

1843-
VarLocs[arg] = VarLoc(argValue, SILAccessEnforcement::Static);
1844-
InitAccessorArgumentMappings[property] = arg;
1845-
};
1854+
VarLocs[arg] = VarLoc(argValue, SILAccessEnforcement::Static);
1855+
InitAccessorArgumentMappings[property] = arg;
1856+
};
18461857

1847-
// Emit @out backing storage argument
1848-
auto backingStorage = vd->getPropertyWrapperBackingProperty();
1849-
auto backingStorageTy = getSILTypeInContext(
1850-
loweredFuncDeclTy->getResults()[0], loweredFuncDeclTy);
1851-
createArgument(backingStorage, backingStorageTy, /*markUninitialized=*/true);
1858+
// Emit @out backing storage argument
1859+
auto backingStorageTy = getSILTypeInContext(
1860+
loweredFuncDeclTy->getResults()[0], loweredFuncDeclTy);
1861+
createArgument(backingStorage, backingStorageTy, /*markUninitialized=*/true);
1862+
}
18521863

1853-
// Emit `newValue` argument
1864+
// Create the `newValue` argument
18541865
ParameterList *params = nullptr;
18551866
auto newValueParam = new (ctx)
18561867
ParamDecl(SourceLoc(), SourceLoc(), ctx.getIdentifier("$input_value"),
@@ -1864,9 +1875,10 @@ void SILGenFunction::emitPropertyWrappedFieldInitAccessor(
18641875

18651876
// Nominal contexts have an extra trailing metatype argument,
18661877
// local contexts do not
1878+
const bool isLocalContext = vd->getDeclContext()->isLocalContext();
18671879
auto numIgnoredParams = isLocalContext ? 0 : 1;
18681880
emitBasicProlog(declContext, params,
1869-
/*selfParam=*/nullptr, TupleType::getEmpty(F.getASTContext()),
1881+
/*selfParam=*/nullptr, returnTy,
18701882
/*errorType=*/std::nullopt,
18711883
/*throwsLoc=*/SourceLoc(),
18721884
/*ignored parameters*/ numIgnoredParams);
@@ -1875,9 +1887,14 @@ void SILGenFunction::emitPropertyWrappedFieldInitAccessor(
18751887
if (!isLocalContext)
18761888
emitConstructorMetatypeArg(*this, vd);
18771889

1878-
prepareEpilog(declContext, TupleType::getEmpty(F.getASTContext()),
1890+
prepareEpilog(declContext, returnTy,
18791891
std::nullopt, CleanupLocation(Loc));
18801892

1893+
if (EmitProfilerIncrement)
1894+
emitProfilerIncrement(value);
1895+
1896+
FullExpr scope(Cleanups, CleanupLocation(value));
1897+
18811898
// Create an opaque value binding that maps 'newValue' to the wrapper's
18821899
// wrappedValue AST placeholder. This makes the argument available when
18831900
// init(wrappedValue:) is emitted
@@ -1889,16 +1906,19 @@ void SILGenFunction::emitPropertyWrappedFieldInitAccessor(
18891906
maybeEmitValueOfLocalVarDecl(newValueParam, AccessKind::Read));
18901907
assert(value == initInfo.getInitFromWrappedValue());
18911908

1892-
// Prepare InitializationPtr for the @out return buffer
1893-
FullExpr scope(Cleanups, CleanupLocation(value));
1894-
auto backingStorageArg = InitAccessorArgumentMappings[backingStorage];
1895-
auto backingStorageAddr = VarLocs[backingStorageArg].value;
1896-
InitializationPtr init(new KnownAddressInitialization(backingStorageAddr));
1909+
if (useLoweredAddresses()) {
1910+
// Prepare InitializationPtr for the @out return buffer
1911+
auto backingStorageArg = InitAccessorArgumentMappings[backingStorage];
1912+
auto backingStorageAddr = VarLocs[backingStorageArg].value;
1913+
InitializationPtr init(new KnownAddressInitialization(backingStorageAddr));
18971914

1898-
// Intialize the @out buffer with the given expression
1899-
emitExprInto(value, init.get());
1915+
// Intialize the @out buffer with the given expression
1916+
emitExprInto(value, init.get());
1917+
} else {
1918+
emitReturnExpr(Loc, value);
1919+
}
19001920

19011921
// Emit epilog/cleanups
19021922
emitEpilog(Loc);
19031923
mergeCleanupBlocks();
1904-
}
1924+
}

lib/SILGen/SILGenFunction.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1883,9 +1883,10 @@ SILGenFunction::emitApplyOfSetterToBase(SILLocation loc, SILDeclRef setter,
18831883
assert(base);
18841884

18851885
SILValue capturedBase;
1886-
unsigned argIdx = setterConv.getNumSILArguments() - 1;
1886+
unsigned argIdx = setterConv.getSILArgIndexOfSelf();
1887+
auto paramInfo = setterConv.getParamInfoForSILArg(argIdx);
18871888

1888-
if (setterConv.getSILArgumentConvention(argIdx).isInoutConvention()) {
1889+
if (paramInfo.isIndirectMutating()) {
18891890
capturedBase = base.getValue();
18901891
} else if (base.getType().isAddress() &&
18911892
base.getType().getObjectType() ==
@@ -1975,9 +1976,9 @@ void SILGenFunction::emitAssignOrInit(SILLocation loc, ManagedValue selfValue,
19751976
SILFunctionConventions initConv(initTy, SGM.M);
19761977

19771978
auto newValueArgIdx = initConv.getSILArgIndexOfFirstParam();
1979+
auto newValueParamInfo = initConv.getParamInfoForSILArg(newValueArgIdx);
19781980
// If we need the argument in memory, materialize an address.
1979-
if (initConv.getSILArgumentConvention(newValueArgIdx)
1980-
.isIndirectConvention() &&
1981+
if (initConv.isSILIndirect(newValueParamInfo) &&
19811982
!newValue.getType().isAddress()) {
19821983
newValue = newValue.materialize(*this, loc);
19831984
}

lib/SILGen/SILGenLValue.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,8 +1528,10 @@ namespace {
15281528
return cast<AccessorDecl>(Accessor.getFuncDecl());
15291529
}
15301530

1531-
ManagedValue emitValue(SILGenFunction &SGF, SILLocation loc, VarDecl *field,
1532-
ArgumentSource &&value, AccessorKind accessorKind) {
1531+
ManagedValue emitValueForAssignOrInit(SILGenFunction &SGF, SILLocation loc,
1532+
VarDecl *field,
1533+
ArgumentSource &&value,
1534+
AccessorKind accessorKind) {
15331535
auto accessorInfo = SGF.getConstantInfo(
15341536
SGF.getTypeExpansionContext(),
15351537
SILDeclRef(field->getOpaqueAccessor(accessorKind)));
@@ -1553,7 +1555,8 @@ namespace {
15531555
assert(value.isRValue());
15541556
ManagedValue Mval =
15551557
std::move(value).asKnownRValue(SGF).getAsSingleValue(SGF, loc);
1556-
auto param = accessorTy->getParameters()[0];
1558+
auto paramIdx = accessorConv.getSILArgIndexOfFirstParam();
1559+
auto param = accessorConv.getParamInfoForSILArg(paramIdx);
15571560
SILType loweredSubstArgType = Mval.getType();
15581561
if (param.isIndirectInOut()) {
15591562
loweredSubstArgType =
@@ -1572,11 +1575,8 @@ namespace {
15721575
fieldTy->getCanonicalType());
15731576
}
15741577

1575-
auto newValueArgIdx = accessorConv.getNumIndirectSILResults();
15761578
// If we need the argument in memory, materialize an address.
1577-
if (accessorConv.getSILArgumentConvention(newValueArgIdx)
1578-
.isIndirectConvention() &&
1579-
!Mval.getType().isAddress()) {
1579+
if (accessorConv.isSILIndirect(param) && !Mval.getType().isAddress()) {
15801580
Mval = Mval.materialize(SGF, loc);
15811581
}
15821582

@@ -1610,7 +1610,7 @@ namespace {
16101610
override {
16111611
VarDecl *field = cast<VarDecl>(Storage);
16121612
auto Mval =
1613-
emitValue(SGF, loc, field, std::move(value), AccessorKind::Init);
1613+
emitValueForAssignOrInit(SGF, loc, field, std::move(value), AccessorKind::Init);
16141614
SGF.emitAssignOrInit(loc, base, field, Mval, Substitutions);
16151615
}
16161616

@@ -1875,7 +1875,7 @@ namespace {
18751875

18761876
// Create the assign_or_init SIL instruction
18771877
auto Mval =
1878-
emitValue(SGF, loc, field, std::move(value), AccessorKind::Set);
1878+
emitValueForAssignOrInit(SGF, loc, field, std::move(value), AccessorKind::Set);
18791879
auto selfOrLocal = selfMetatype ? base.getValue() : proj.forward(SGF);
18801880
SGF.B.createAssignOrInit(loc, field, selfOrLocal, Mval.forward(SGF),
18811881
initFn.getValue(), setterFn,

lib/SILGen/SILGenProlog.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,19 +1331,18 @@ static void emitCaptureArguments(SILGenFunction &SGF,
13311331
case CaptureKind::Immutable: {
13321332
auto argIndex = SGF.F.begin()->getNumArguments();
13331333
// Non-escaping stored decls are captured as the address of the value.
1334-
auto argConv = SGF.F.getConventions().getSILArgumentConvention(argIndex);
1335-
bool isInOut = (argConv == SILArgumentConvention::Indirect_Inout ||
1336-
argConv == SILArgumentConvention::Indirect_InoutAliasable);
1337-
auto param = SGF.F.getConventions().getParamInfoForSILArg(argIndex);
1338-
if (SGF.F.getConventions().isSILIndirect(param)) {
1334+
auto fnConv = SGF.F.getConventions();
1335+
auto paramInfo = fnConv.getParamInfoForSILArg(argIndex);
1336+
if (fnConv.isSILIndirect(paramInfo)) {
13391337
ty = ty.getAddressType();
13401338
}
13411339
auto *fArg = SGF.F.begin()->createFunctionArgument(ty, VD);
13421340
fArg->setClosureCapture(true);
13431341
arg = SILValue(fArg);
13441342

13451343
if (isNoImplicitCopy && !arg->getType().isMoveOnly()) {
1346-
switch (argConv) {
1344+
// FIXME: this incompatible with -enable-sil-opaque-values
1345+
switch (fnConv.getSILArgumentConvention(argIndex)) {
13471346
case SILArgumentConvention::Indirect_Inout:
13481347
case SILArgumentConvention::Indirect_InoutAliasable:
13491348
case SILArgumentConvention::Indirect_In:
@@ -1377,6 +1376,7 @@ static void emitCaptureArguments(SILGenFunction &SGF,
13771376
// in SIL since it is illegal to capture an inout value in an escaping
13781377
// closure. The later code knows how to handle that we have the
13791378
// mark_unresolved_non_copyable_value here.
1379+
bool isInOut = paramInfo.isIndirectMutating();
13801380
if (isInOut && arg->getType().isMoveOnly()) {
13811381
arg = SGF.B.createMarkUnresolvedNonCopyableValueInst(
13821382
Loc, arg,

0 commit comments

Comments
 (0)