Skip to content

Commit f765d28

Browse files
committed
SILGen: Handle struct fields and addressors as addressable storage.
When accessing stored properties out of an addressable variable or parameter binding, the stored property's address inside the addressable storage of the aggregate is itself addressable. Also, if a computed property is implemented using an addressor, treat that as a sign that the returned address should be used as addressable storage as well. rdar://152280207
1 parent 2e18973 commit f765d28

File tree

6 files changed

+388
-56
lines changed

6 files changed

+388
-56
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 214 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3540,27 +3540,198 @@ Expr *ArgumentSource::findStorageReferenceExprForBorrow() && {
35403540
ManagedValue
35413541
SILGenFunction::tryEmitAddressableParameterAsAddress(ArgumentSource &&arg,
35423542
ValueOwnership ownership) {
3543+
if (!arg.isExpr()) {
3544+
return ManagedValue();
3545+
}
3546+
35433547
// If the function takes an addressable parameter, and its argument is
35443548
// a reference to an addressable declaration with compatible ownership,
35453549
// forward the address along in-place.
3546-
if (arg.isExpr()) {
3547-
auto origExpr = std::move(arg).asKnownExpr();
3548-
auto expr = origExpr;
3550+
auto origExpr = std::move(arg).asKnownExpr();
3551+
auto expr = origExpr;
3552+
3553+
// If the expression does not have a stable address to return, then restore
3554+
// the ArgumentSource and return a null value to the caller.
3555+
auto notAddressable = [&] {
3556+
arg = ArgumentSource(origExpr);
3557+
return ManagedValue();
3558+
};
3559+
3560+
if (auto le = dyn_cast<LoadExpr>(expr)) {
3561+
expr = le->getSubExpr();
3562+
}
3563+
if (auto dre = dyn_cast<DeclRefExpr>(expr)) {
3564+
if (auto param = dyn_cast<VarDecl>(dre->getDecl())) {
3565+
if (auto addr = getLocalVariableAddressableBuffer(param, expr,
3566+
ownership)) {
3567+
return ManagedValue::forBorrowedAddressRValue(addr);
3568+
}
3569+
}
3570+
}
3571+
3572+
// Property or subscript member accesses may also be addressable.
3573+
3574+
AccessKind accessKind;
3575+
switch (ownership) {
3576+
case ValueOwnership::Shared:
3577+
case ValueOwnership::Default:
3578+
accessKind = AccessKind::Read;
3579+
break;
3580+
case ValueOwnership::Owned:
3581+
case ValueOwnership::InOut:
3582+
accessKind = AccessKind::ReadWrite;
3583+
break;
3584+
}
3585+
3586+
LookupExpr *lookupExpr;
3587+
AbstractStorageDecl *memberStorage;
3588+
SubstitutionMap subs;
3589+
AccessSemantics accessSemantics;
3590+
PreparedArguments indices;
3591+
3592+
if (auto mre = dyn_cast<MemberRefExpr>(expr)) {
3593+
lookupExpr = mre;
3594+
memberStorage = dyn_cast<VarDecl>(mre->getMember().getDecl());
3595+
subs = mre->getMember().getSubstitutions();
3596+
accessSemantics = mre->getAccessSemantics();
3597+
} else if (auto se = dyn_cast<SubscriptExpr>(expr)) {
3598+
lookupExpr = se;
3599+
auto subscriptDecl = cast<SubscriptDecl>(se->getMember().getDecl());
3600+
memberStorage = subscriptDecl;
3601+
subs = se->getMember().getSubstitutions();
3602+
accessSemantics = se->getAccessSemantics();
35493603

3550-
if (auto le = dyn_cast<LoadExpr>(expr)) {
3551-
expr = le->getSubExpr();
3552-
}
3553-
if (auto dre = dyn_cast<DeclRefExpr>(expr)) {
3554-
if (auto param = dyn_cast<VarDecl>(dre->getDecl())) {
3555-
if (auto addr = getLocalVariableAddressableBuffer(param, expr,
3556-
ownership)) {
3557-
return ManagedValue::forBorrowedAddressRValue(addr);
3558-
}
3604+
indices = PreparedArguments(
3605+
subscriptDecl->getInterfaceType()->castTo<AnyFunctionType>()
3606+
->getParams(),
3607+
se->getArgs());
3608+
} else {
3609+
return notAddressable();
3610+
}
3611+
3612+
if (!memberStorage) {
3613+
return notAddressable();
3614+
}
3615+
3616+
auto strategy = memberStorage->getAccessStrategy(accessSemantics, accessKind,
3617+
SGM.M.getSwiftModule(), F.getResilienceExpansion(),
3618+
std::make_pair<>(expr->getSourceRange(), FunctionDC),
3619+
/*old abi (doesn't matter here)*/ false);
3620+
3621+
switch (strategy.getKind()) {
3622+
case AccessStrategy::Storage: {
3623+
auto vd = cast<VarDecl>(memberStorage);
3624+
// TODO: Is it possible and/or useful for class storage to be
3625+
// addressable?
3626+
if (!vd->getDeclContext()->getInnermostTypeContext()
3627+
->getDeclaredTypeInContext()->getStructOrBoundGenericStruct()) {
3628+
return notAddressable();
3629+
}
3630+
3631+
// If the storage holds the fully-abstracted representation of the
3632+
// type, then we can use its address.
3633+
auto absBaseTy = getLoweredType(AbstractionPattern::getOpaque(),
3634+
lookupExpr->getBase()->getType()->getWithoutSpecifierType());
3635+
auto memberTy = absBaseTy.getFieldType(vd, &F);
3636+
auto absMemberTy = getLoweredType(AbstractionPattern::getOpaque(),
3637+
lookupExpr->getType()->getWithoutSpecifierType());
3638+
3639+
if (memberTy.getAddressType() != absMemberTy.getAddressType()) {
3640+
// The storage is not fully abstracted, so it can't serve as a
3641+
// stable address.
3642+
return notAddressable();
3643+
}
3644+
3645+
// Otherwise, we can project the field address from the stable address
3646+
// of the base, if it has one. Try to get the stable address for the
3647+
// base.
3648+
auto baseAddr = tryEmitAddressableParameterAsAddress(
3649+
ArgumentSource(lookupExpr->getBase()), ownership);
3650+
3651+
if (!baseAddr) {
3652+
return notAddressable();
3653+
}
3654+
3655+
// Project the field's address.
3656+
auto fieldAddr = B.createStructElementAddr(lookupExpr,
3657+
baseAddr.getValue(), vd);
3658+
return ManagedValue::forBorrowedAddressRValue(fieldAddr);
3659+
}
3660+
3661+
case AccessStrategy::DirectToAccessor:
3662+
case AccessStrategy::DispatchToAccessor: {
3663+
// Non-addressor accessors don't produce stable addresses.
3664+
if (strategy.getAccessor() != AccessorKind::Address
3665+
&& strategy.getAccessor() != AccessorKind::MutableAddress) {
3666+
return notAddressable();
3667+
}
3668+
// TODO: Non-yielding borrow/mutate accessors can also be considered
3669+
// addressable when we have those.
3670+
3671+
auto addressor = memberStorage->getAccessor(strategy.getAccessor());
3672+
auto addressorRef = SILDeclRef(addressor, SILDeclRef::Kind::Func);
3673+
auto absMemberTy = getLoweredType(AbstractionPattern::getOpaque(),
3674+
lookupExpr->getType()->getWithoutSpecifierType())
3675+
.getAddressType();
3676+
3677+
// Evaluate the base in the current formal access scope.
3678+
ManagedValue base;
3679+
// If the addressor wants the base addressable, try to honor that
3680+
// request.
3681+
auto addressorSelf = addressor->getImplicitSelfDecl();
3682+
if (addressorSelf->isAddressable()
3683+
|| getTypeLowering(lookupExpr->getBase()->getType()
3684+
->getWithoutSpecifierType())
3685+
.getRecursiveProperties().isAddressableForDependencies()) {
3686+
ValueOwnership baseOwnership = addressorSelf->isInOut()
3687+
? ValueOwnership::InOut
3688+
: ValueOwnership::Shared;
3689+
3690+
base = tryEmitAddressableParameterAsAddress(
3691+
ArgumentSource(lookupExpr->getBase()), baseOwnership);
3692+
}
3693+
3694+
// Otherwise, project the base as an lvalue.
3695+
if (!base) {
3696+
SGFAccessKind silAccess;
3697+
switch (accessKind) {
3698+
case AccessKind::Read:
3699+
silAccess = SGFAccessKind::BorrowedAddressRead;
3700+
break;
3701+
case AccessKind::ReadWrite:
3702+
case AccessKind::Write:
3703+
silAccess = SGFAccessKind::ReadWrite;
3704+
break;
35593705
}
3706+
3707+
LValue lv = emitLValue(lookupExpr, silAccess);
3708+
3709+
drillToLastComponent(lookupExpr->getBase(), std::move(lv), base);
35603710
}
3561-
arg = ArgumentSource(origExpr);
3711+
3712+
// Materialize the base outside of the scope of the addressor call,
3713+
// since the returned address may depend on the materialized
3714+
// representation, even if it isn't transitively addressable.
3715+
auto baseTy = lookupExpr->getBase()->getType()->getCanonicalType();
3716+
ArgumentSource baseArg = prepareAccessorBaseArgForFormalAccess(
3717+
lookupExpr->getBase(), base, baseTy, addressorRef);
3718+
3719+
// Invoke the addressor to directly produce the address.
3720+
return emitAddressorAccessor(lookupExpr,
3721+
addressorRef, subs,
3722+
std::move(baseArg),
3723+
/*super*/ false, /*direct accessor use*/ true,
3724+
std::move(indices),
3725+
absMemberTy, /*on self*/ false);
35623726
}
3563-
return ManagedValue();
3727+
3728+
case AccessStrategy::MaterializeToTemporary:
3729+
case AccessStrategy::DispatchToDistributedThunk:
3730+
// These strategies never produce a value with a stable address.
3731+
return notAddressable();
3732+
}
3733+
3734+
llvm_unreachable("uncovered switch!");
35643735
}
35653736

35663737
namespace {
@@ -7285,6 +7456,34 @@ ArgumentSource AccessorBaseArgPreparer::prepare() {
72857456
return prepareAccessorObjectBaseArg();
72867457
}
72877458

7459+
ArgumentSource SILGenFunction::prepareAccessorBaseArgForFormalAccess(
7460+
SILLocation loc,
7461+
ManagedValue base,
7462+
CanType baseFormalType,
7463+
SILDeclRef accessor) {
7464+
if (!base) {
7465+
return ArgumentSource();
7466+
}
7467+
7468+
base = base.formalAccessBorrow(*this, loc);
7469+
// If the base needs to be materialized, do so in
7470+
// the outer formal evaluation scope, since an addressor or
7471+
// other dependent value may want to point into the materialization.
7472+
auto &baseInfo = getConstantInfo(getTypeExpansionContext(), accessor);
7473+
7474+
if (!baseInfo.FormalPattern.isForeign()) {
7475+
auto baseFnTy = baseInfo.SILFnType;
7476+
7477+
if (baseFnTy->getSelfParameter().isFormalIndirect()
7478+
&& base.getType().isObject()
7479+
&& silConv.useLoweredAddresses()) {
7480+
base = base.formallyMaterialize(*this, loc);
7481+
}
7482+
}
7483+
7484+
return prepareAccessorBaseArg(loc, base, baseFormalType, accessor);
7485+
}
7486+
72887487
ArgumentSource SILGenFunction::prepareAccessorBaseArg(SILLocation loc,
72897488
ManagedValue base,
72907489
CanType baseFormalType,
@@ -7604,10 +7803,7 @@ ManagedValue SILGenFunction::emitAddressorAccessor(
76047803

76057804
emission.addCallSite(loc, std::move(subscriptIndices));
76067805

7607-
// Unsafe{Mutable}Pointer<T> or
7608-
// (Unsafe{Mutable}Pointer<T>, Builtin.UnknownPointer) or
7609-
// (Unsafe{Mutable}Pointer<T>, Builtin.NativePointer) or
7610-
// (Unsafe{Mutable}Pointer<T>, Builtin.NativePointer?) or
7806+
// Result must be Unsafe{Mutable}Pointer<T>
76117807
SmallVector<ManagedValue, 2> results;
76127808
emission.apply().getAll(results);
76137809

lib/SILGen/SILGenExpr.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2756,8 +2756,6 @@ RValue RValueEmitter::visitMemberRefExpr(MemberRefExpr *e,
27562756
"RValueEmitter shouldn't be called on lvalues");
27572757
assert(isa<VarDecl>(e->getMember().getDecl()));
27582758

2759-
// Everything else should use the l-value logic.
2760-
27612759
// Any writebacks for this access are tightly scoped.
27622760
FormalEvaluationScope scope(SGF);
27632761

lib/SILGen/SILGenFunction.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class ConsumableManagedValue;
4444
class LogicalPathComponent;
4545
class LValue;
4646
class ManagedValue;
47+
class PathComponent;
4748
class PreparedArguments;
4849
class RValue;
4950
class CalleeTypeInfo;
@@ -1978,6 +1979,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
19781979
ArgumentSource prepareAccessorBaseArg(SILLocation loc, ManagedValue base,
19791980
CanType baseFormalType,
19801981
SILDeclRef accessor);
1982+
ArgumentSource prepareAccessorBaseArgForFormalAccess(SILLocation loc,
1983+
ManagedValue base,
1984+
CanType baseFormalType,
1985+
SILDeclRef accessor);
19811986

19821987
RValue emitGetAccessor(
19831988
SILLocation loc, SILDeclRef getter, SubstitutionMap substitutions,
@@ -2201,7 +2206,12 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
22012206

22022207
RValue emitLoadOfLValue(SILLocation loc, LValue &&src, SGFContext C,
22032208
bool isBaseLValueGuaranteed = false);
2204-
2209+
PathComponent &&
2210+
drillToLastComponent(SILLocation loc,
2211+
LValue &&lv,
2212+
ManagedValue &addr,
2213+
TSanKind tsanKind = TSanKind::None);
2214+
22052215
/// Emit a reference to a method from within another method of the type.
22062216
std::tuple<ManagedValue, SILType>
22072217
emitSiblingMethodRef(SILLocation loc,

0 commit comments

Comments
 (0)