Skip to content

Commit c1b31b4

Browse files
committed
Make the general path of emitRValueForStorageLoad use LValues.
Beyond just being better code, this also fixes problems where the duplicate code didn't handle e.g. _read accessors. I believe this finishes unblocking _read in the stdlib (rdar://45230566).
1 parent 71e2e8e commit c1b31b4

File tree

2 files changed

+43
-116
lines changed

2 files changed

+43
-116
lines changed

lib/SILGen/SILGenLValue.cpp

Lines changed: 18 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -3776,108 +3776,6 @@ getFormalStorageAbstractionPattern(SILGenFunction &SGF, AbstractStorageDecl *fie
37763776
return SGF.SGM.Types.getAbstractionPattern(sub);
37773777
}
37783778

3779-
static SILDeclRef getRValueAccessorDeclRef(SILGenFunction &SGF,
3780-
AbstractStorageDecl *storage,
3781-
AccessStrategy strategy) {
3782-
switch (strategy.getKind()) {
3783-
case AccessStrategy::BehaviorStorage:
3784-
llvm_unreachable("shouldn't load an rvalue via behavior storage!");
3785-
3786-
case AccessStrategy::Storage:
3787-
llvm_unreachable("should already have been filtered out!");
3788-
3789-
case AccessStrategy::MaterializeToTemporary:
3790-
llvm_unreachable("never used for read accesses");
3791-
3792-
case AccessStrategy::DirectToAccessor:
3793-
case AccessStrategy::DispatchToAccessor: {
3794-
auto accessor = strategy.getAccessor();
3795-
return SGF.SGM.getAccessorDeclRef(storage->getAccessor(accessor));
3796-
}
3797-
}
3798-
llvm_unreachable("should already have been filtered out!");
3799-
}
3800-
3801-
static RValue getTargetRValue(SILGenFunction &SGF, SILLocation loc,
3802-
ManagedValue value,
3803-
AbstractionPattern origFormalType,
3804-
CanType substFormalType,
3805-
SGFContext C) {
3806-
SILType loweredSubstType = SGF.getLoweredType(substFormalType);
3807-
3808-
bool hasAbstraction =
3809-
(loweredSubstType.getObjectType() != value.getType().getObjectType());
3810-
3811-
if (value.isLValue() ||
3812-
(value.getType().isAddress() && !loweredSubstType.isAddress())) {
3813-
auto isTake =
3814-
IsTake_t(!value.isLValue() && !value.isPlusZeroRValueOrTrivial());
3815-
value = SGF.emitLoad(loc,
3816-
(isTake ? value.forward(SGF)
3817-
: value.getUnmanagedValue()),
3818-
SGF.getTypeLowering(value.getType()),
3819-
(hasAbstraction ? SGFContext() : C),
3820-
isTake);
3821-
}
3822-
3823-
RValue result(SGF, loc, substFormalType, value);
3824-
if (hasAbstraction) {
3825-
result = SGF.emitOrigToSubstValue(loc, std::move(result), origFormalType,
3826-
substFormalType, C);
3827-
}
3828-
return result;
3829-
}
3830-
3831-
static RValue
3832-
emitRValueWithAccessor(SILGenFunction &SGF, SILLocation loc,
3833-
AbstractStorageDecl *storage,
3834-
SubstitutionMap substitutions,
3835-
ArgumentSource &&baseRV,
3836-
PreparedArguments &&subscriptIndices,
3837-
bool isSuper, AccessStrategy strategy,
3838-
SILDeclRef accessor,
3839-
AbstractionPattern origFormalType,
3840-
CanType substFormalType,
3841-
SGFContext C) {
3842-
assert(strategy.getKind() == AccessStrategy::DirectToAccessor ||
3843-
strategy.getKind() == AccessStrategy::DispatchToAccessor);
3844-
bool isDirectUse = (strategy.getKind() == AccessStrategy::DirectToAccessor);
3845-
3846-
// The easy path here is if we don't need to use an addressor.
3847-
if (strategy.getAccessor() == AccessorKind::Get) {
3848-
return SGF.emitGetAccessor(loc, accessor, substitutions,
3849-
std::move(baseRV), isSuper, isDirectUse,
3850-
std::move(subscriptIndices), C);
3851-
}
3852-
3853-
assert(strategy.getAccessor() == AccessorKind::Address);
3854-
3855-
auto &storageTL = SGF.getTypeLowering(origFormalType, substFormalType);
3856-
SILType storageType = storageTL.getLoweredType().getAddressType();
3857-
3858-
auto addressorResult =
3859-
SGF.emitAddressorAccessor(loc, accessor, substitutions,
3860-
std::move(baseRV), isSuper, isDirectUse,
3861-
std::move(subscriptIndices), storageType);
3862-
3863-
RValue result = getTargetRValue(SGF, loc, addressorResult.first,
3864-
origFormalType, substFormalType, C);
3865-
3866-
switch (cast<AccessorDecl>(accessor.getDecl())->getAddressorKind()) {
3867-
case AddressorKind::NotAddressor: llvm_unreachable("inconsistent");
3868-
case AddressorKind::Unsafe:
3869-
// Nothing to do.
3870-
break;
3871-
case AddressorKind::Owning:
3872-
case AddressorKind::NativeOwning:
3873-
// Emit the release immediately.
3874-
SGF.B.emitDestroyValueOperation(loc, addressorResult.second.forward(SGF));
3875-
break;
3876-
}
3877-
3878-
return result;
3879-
}
3880-
38813779
/// Produce a singular RValue for a load from the specified property. This is
38823780
/// designed to work with RValue ManagedValue bases that are either +0 or +1.
38833781
RValue SILGenFunction::emitRValueForStorageLoad(
@@ -3892,21 +3790,25 @@ RValue SILGenFunction::emitRValueForStorageLoad(
38923790

38933791
// If we should call an accessor of some kind, do so.
38943792
if (strategy.getKind() != AccessStrategy::Storage) {
3895-
auto accessor = getRValueAccessorDeclRef(*this, storage, strategy);
3896-
ArgumentSource baseRV = prepareAccessorBaseArg(loc, base,
3897-
baseFormalType,
3898-
accessor);
3899-
3900-
AbstractionPattern origFormalType =
3901-
getFormalStorageAbstractionPattern(*this, storage);
3902-
auto substFormalType = propTy->getCanonicalType();
3903-
3904-
return emitRValueWithAccessor(*this, loc, storage, substitutions,
3905-
std::move(baseRV),
3906-
std::move(subscriptIndices),
3907-
isSuper, strategy, accessor,
3908-
origFormalType, substFormalType, C);
3793+
auto accessKind = SGFAccessKind::OwnedObjectRead;
3794+
3795+
LValue lv = [&] {
3796+
if (!base) return LValue();
3797+
3798+
auto baseAccess = getBaseAccessKind(SGM, storage, accessKind,
3799+
strategy, baseFormalType);
3800+
return LValue::forValue(baseAccess, base, baseFormalType);
3801+
}();
3802+
3803+
lv.addMemberComponent(*this, loc, storage, substitutions, LValueOptions(),
3804+
isSuper, accessKind, strategy,
3805+
propTy->getCanonicalType(),
3806+
std::move(subscriptIndices),
3807+
/*index for diagnostics*/ nullptr);
3808+
3809+
return emitLoadOfLValue(loc, std::move(lv), C, isBaseGuaranteed);
39093810
}
3811+
39103812
assert(isa<VarDecl>(storage) && "only properties should have storage");
39113813
auto field = cast<VarDecl>(storage);
39123814
assert(field->hasStorage() &&

test/SILGen/read_accessor.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,28 @@ struct TupleReader {
136136
}
137137
}
138138
}
139+
140+
struct TestKeyPath {
141+
var readable: String {
142+
_read {
143+
yield ""
144+
}
145+
}
146+
147+
func useKeyPath() -> String {
148+
return self[keyPath: \.readable]
149+
}
150+
}
151+
// Key-path getter for TestKeyPath.readable
152+
// CHECK-LABEL: sil shared [thunk] @$s13read_accessor11TestKeyPathV8readableSSvpACTK
153+
// CHECK: bb0(%0 : @trivial $*String, %1 : @trivial $*TestKeyPath):
154+
// CHECK-NEXT: [[SELF:%.*]] = load [trivial] %1
155+
// CHECK-NEXT: // function_ref
156+
// CHECK-NEXT: [[READ:%.*]] = function_ref @$s13read_accessor11TestKeyPathV8readableSSvr
157+
// CHECK-NEXT: ([[VALUE:%.*]], [[TOKEN:%.*]]) = begin_apply [[READ]]([[SELF]])
158+
// CHECK-NEXT: [[COPY:%.*]] = copy_value [[VALUE]]
159+
// CHECK-NEXT: end_apply [[TOKEN]]
160+
// CHECK-NEXT: store [[COPY]] to [init] %0 : $*String
161+
// CHECK-NEXT: [[RET:%.*]] = tuple ()
162+
// CHECK-NEXT: return [[RET]] : $()
163+
// CHECK-LABEL: } // end sil function '$s13read_accessor11TestKeyPathV8readableSSvpACTK'

0 commit comments

Comments
 (0)