Skip to content

Commit 761faaa

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 1869832 commit 761faaa

File tree

7 files changed

+395
-81
lines changed

7 files changed

+395
-81
lines changed

lib/SILGen/SILGenApply.cpp

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

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

35653736
namespace {
@@ -7284,6 +7455,34 @@ ArgumentSource AccessorBaseArgPreparer::prepare() {
72847455
return prepareAccessorObjectBaseArg();
72857456
}
72867457

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

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

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

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -477,29 +477,6 @@ static ManagedValue emitBuiltinUnprotectedAddressOf(SILGenFunction &SGF,
477477
/*stackProtected=*/ false);
478478
}
479479

480-
// Like `tryEmitAddressableParameterAsAddress`, but also handles struct element projections.
481-
static SILValue emitAddressOf(Expr *e, SILGenFunction &SGF, SILLocation loc) {
482-
483-
if (auto *memberRef = dyn_cast<MemberRefExpr>(e)) {
484-
VarDecl *fieldDecl = dyn_cast<VarDecl>(memberRef->getDecl().getDecl());
485-
if (!fieldDecl)
486-
return SILValue();
487-
SILValue addr = emitAddressOf(memberRef->getBase(), SGF, loc);
488-
if (!addr)
489-
return SILValue();
490-
if (addr->getType().getStructOrBoundGenericStruct() != fieldDecl->getDeclContext())
491-
return SILValue();
492-
return SGF.B.createStructElementAddr(loc, addr, fieldDecl);
493-
}
494-
495-
if (auto addressableAddr = SGF.tryEmitAddressableParameterAsAddress(
496-
ArgumentSource(e),
497-
ValueOwnership::Shared)) {
498-
return addressableAddr.getValue();
499-
}
500-
return SILValue();
501-
}
502-
503480
/// Specialized emitter for Builtin.addressOfBorrow.
504481
static ManagedValue emitBuiltinAddressOfBorrowBuiltins(SILGenFunction &SGF,
505482
SILLocation loc,
@@ -514,11 +491,15 @@ static ManagedValue emitBuiltinAddressOfBorrowBuiltins(SILGenFunction &SGF,
514491

515492
auto argument = (*argsOrError)[0];
516493

494+
SILValue addr;
517495
// Try to borrow the argument at +0 indirect.
518496
// If the argument is a reference to a borrowed addressable parameter, then
519497
// use that parameter's stable address.
520-
SILValue addr = emitAddressOf(argument, SGF, loc);
521-
if (!addr) {
498+
if (auto addressableAddr = SGF.tryEmitAddressableParameterAsAddress(
499+
ArgumentSource(argument),
500+
ValueOwnership::Shared)) {
501+
addr = addressableAddr.getValue();
502+
} else {
522503
// We otherwise only support the builtin applied to values that
523504
// are naturally emitted borrowed in memory. (But it would probably be good
524505
// to phase this out since it's not really well-defined how long

lib/SILGen/SILGenExpr.cpp

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

2757-
// Everything else should use the l-value logic.
2758-
27592757
// Any writebacks for this access are tightly scoped.
27602758
FormalEvaluationScope scope(SGF);
27612759

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)