Skip to content

Commit 41971fe

Browse files
committed
SILGen: Introduce MaterializedLValue abstraction
This is used when materializing an LValue to share state between the read and write phases of the access, replacing the 'temporary' and 'extraInfo' parameters that were previously being passed around. It adds two new fields, origSelfType and genericSig, which will be used in an upcoming patch to actually apply the callback with the current generic signature. This will finally allow us to make use of materializeForSet implementations in protocol extensions, which is a prerequisite for enabling resilient default implementations of property and subscript requirements.
1 parent 0bc2cc4 commit 41971fe

File tree

4 files changed

+87
-50
lines changed

4 files changed

+87
-50
lines changed

lib/SILGen/LValue.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,9 @@ class LogicalPathComponent : public PathComponent {
258258
///
259259
/// \param base - always an address, but possibly an r-value
260260
virtual void writeback(SILGenFunction &gen, SILLocation loc,
261-
ManagedValue base, ManagedValue temporary,
262-
ArrayRef<SILValue> otherInfo, bool isFinal);
261+
ManagedValue base,
262+
MaterializedLValue materialized,
263+
bool isFinal);
263264
};
264265

265266
inline LogicalPathComponent &PathComponent::asLogical() {

lib/SILGen/SILGenApply.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4378,7 +4378,7 @@ SILGenFunction::getMaterializeForSetDeclRef(AbstractStorageDecl *storage,
43784378
/*foreign*/ false);
43794379
}
43804380

4381-
std::pair<SILValue, SILValue> SILGenFunction::
4381+
MaterializedLValue SILGenFunction::
43824382
emitMaterializeForSetAccessor(SILLocation loc, SILDeclRef materializeForSet,
43834383
ArrayRef<Substitution> substitutions,
43844384
ArgumentSource &&selfValue,
@@ -4400,6 +4400,7 @@ emitMaterializeForSetAccessor(SILLocation loc, SILDeclRef materializeForSet,
44004400
bool hasCaptures = callee.hasCaptures();
44014401
bool hasSelf = (bool)selfValue;
44024402
CanAnyFunctionType accessType = callee.getSubstFormalType();
4403+
CanAnyFunctionType origAccessType = callee.getOrigFormalType();
44034404

44044405
CallEmission emission(*this, std::move(callee), std::move(writebackScope));
44054406
// Self ->
@@ -4440,7 +4441,16 @@ emitMaterializeForSetAccessor(SILLocation loc, SILDeclRef materializeForSet,
44404441
// Project out the optional callback.
44414442
SILValue optionalCallback = results[1].getUnmanagedValue();
44424443

4443-
return { address, optionalCallback };
4444+
CanType origSelfType = origAccessType->getInput()
4445+
->getRValueInstanceType()
4446+
->getCanonicalType();
4447+
CanGenericSignature genericSig;
4448+
if (auto genericFnType = dyn_cast<GenericFunctionType>(origAccessType))
4449+
genericSig = genericFnType.getGenericSignature();
4450+
4451+
return MaterializedLValue(ManagedValue::forUnmanaged(address),
4452+
origSelfType, genericSig,
4453+
optionalCallback, callbackStorage);
44444454
}
44454455

44464456
SILDeclRef SILGenFunction::getAddressorDeclRef(AbstractStorageDecl *storage,

lib/SILGen/SILGenFunction.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,34 @@ enum class CaptureEmission {
268268
PartialApplication,
269269
};
270270

271+
/// Represents an LValue opened for mutating access.
272+
///
273+
/// This is used by LogicalPathComponent::getMaterialized() and
274+
/// SILGenFunction::emitMaterializeForSetAccessor().
275+
struct MaterializedLValue {
276+
ManagedValue temporary;
277+
278+
// Only set if a callback is required
279+
CanType origSelfType;
280+
CanGenericSignature genericSig;
281+
SILValue callback;
282+
SILValue callbackStorage;
283+
284+
MaterializedLValue() {}
285+
explicit MaterializedLValue(ManagedValue temporary)
286+
: temporary(temporary) {}
287+
MaterializedLValue(ManagedValue temporary,
288+
CanType origSelfType,
289+
CanGenericSignature genericSig,
290+
SILValue callback,
291+
SILValue callbackStorage)
292+
: temporary(temporary),
293+
origSelfType(origSelfType),
294+
genericSig(genericSig),
295+
callback(callback),
296+
callbackStorage(callbackStorage) {}
297+
};
298+
271299
/// SILGenFunction - an ASTVisitor for producing SIL from function bodies.
272300
class LLVM_LIBRARY_VISIBILITY SILGenFunction
273301
: public ASTVisitor<SILGenFunction>
@@ -1071,7 +1099,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
10711099

10721100
SILDeclRef getMaterializeForSetDeclRef(AbstractStorageDecl *decl,
10731101
bool isDirectAccessorUse);
1074-
std::pair<SILValue, SILValue>
1102+
MaterializedLValue
10751103
emitMaterializeForSetAccessor(SILLocation loc, SILDeclRef materializeForSet,
10761104
ArrayRef<Substitution> substitutions,
10771105
ArgumentSource &&optionalSelfValue,

lib/SILGen/SILGenLValue.cpp

Lines changed: 43 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ struct LLVM_LIBRARY_VISIBILITY LValueWriteback {
4545
SILLocation loc;
4646
std::unique_ptr<LogicalPathComponent> component;
4747
ManagedValue base;
48-
ManagedValue temp;
49-
SmallVector<SILValue, 2> ExtraInfo;
48+
MaterializedLValue materialized;
5049
CleanupHandle cleanup;
5150

5251
~LValueWriteback() {}
@@ -56,13 +55,12 @@ struct LLVM_LIBRARY_VISIBILITY LValueWriteback {
5655
LValueWriteback() = default;
5756
LValueWriteback(SILLocation loc,
5857
std::unique_ptr<LogicalPathComponent> &&comp,
59-
ManagedValue base, ManagedValue temp,
60-
ArrayRef<SILValue> extraInfo,
58+
ManagedValue base,
59+
MaterializedLValue materialized,
6160
CleanupHandle cleanup)
62-
: loc(loc), component(std::move(comp)), base(base), temp(temp),
63-
cleanup(cleanup) {
64-
ExtraInfo.append(extraInfo.begin(), extraInfo.end());
65-
}
61+
: loc(loc), component(std::move(comp)),
62+
base(base), materialized(materialized),
63+
cleanup(cleanup) { }
6664

6765
void diagnoseConflict(const LValueWriteback &rhs, SILGenFunction &SGF) const {
6866
// If the two writebacks we're comparing are of different kinds (e.g.
@@ -82,7 +80,7 @@ struct LLVM_LIBRARY_VISIBILITY LValueWriteback {
8280

8381
void performWriteback(SILGenFunction &gen, bool isFinal) {
8482
Scope S(gen.Cleanups, CleanupLocation::get(loc));
85-
component->writeback(gen, loc, base, temp, ExtraInfo, isFinal);
83+
component->writeback(gen, loc, base, materialized, isFinal);
8684
}
8785
};
8886
}
@@ -116,16 +114,16 @@ void SILGenFunction::freeWritebackStack() {
116114
static void pushWriteback(SILGenFunction &gen,
117115
SILLocation loc,
118116
std::unique_ptr<LogicalPathComponent> &&comp,
119-
ManagedValue base, ManagedValue temp,
120-
ArrayRef<SILValue> extraInfo) {
117+
ManagedValue base,
118+
MaterializedLValue materialized) {
121119
assert(gen.InWritebackScope);
122120

123121
// Push a cleanup to execute the writeback consistently.
124122
auto &stack = gen.getWritebackStack();
125123
gen.Cleanups.pushCleanup<LValueWritebackCleanup>(stack.size());
126124
auto cleanup = gen.Cleanups.getTopCleanup();
127125

128-
stack.emplace_back(loc, std::move(comp), base, temp, extraInfo, cleanup);
126+
stack.emplace_back(loc, std::move(comp), base, materialized, cleanup);
129127
}
130128

131129
//===----------------------------------------------------------------------===//
@@ -244,18 +242,23 @@ ManagedValue LogicalPathComponent::getMaterialized(SILGenFunction &gen,
244242
std::move(*this));
245243

246244
// Push a writeback for the temporary.
247-
pushWriteback(gen, loc, std::move(clonedComponent), base, temporary, {});
245+
pushWriteback(gen, loc, std::move(clonedComponent), base,
246+
MaterializedLValue(temporary));
248247
return temporary.borrow();
249248
}
250249

251250
void LogicalPathComponent::writeback(SILGenFunction &gen, SILLocation loc,
252-
ManagedValue base, ManagedValue temporary,
253-
ArrayRef<SILValue> otherInfo, bool isFinal) {
254-
assert(otherInfo.empty() && "unexpected otherInfo parameter!");
251+
ManagedValue base,
252+
MaterializedLValue materialized,
253+
bool isFinal) {
254+
assert(!materialized.callback &&
255+
"unexpected materialized lvalue with callback!");
255256

256257
// Load the value from the temporary unless the type is address-only
257258
// and this is the final use, in which case we can just consume the
258259
// value as-is.
260+
auto temporary = materialized.temporary;
261+
259262
assert(temporary.getType().isAddress());
260263
auto &tempTL = gen.getTypeLowering(temporary.getType());
261264
if (!tempTL.isAddressOnly() || !isFinal) {
@@ -859,52 +862,44 @@ namespace {
859862

860863
auto args = std::move(*this).prepareAccessorArgs(gen, loc, borrowedBase,
861864
materializeForSet);
862-
auto addressAndCallback =
865+
MaterializedLValue materialized =
863866
gen.emitMaterializeForSetAccessor(loc, materializeForSet, substitutions,
864867
std::move(args.base), IsSuper,
865868
IsDirectAccessorUse,
866869
std::move(args.subscripts),
867870
buffer, callbackStorage);
868871

869-
SILValue address = addressAndCallback.first;
870-
871872
// Mark a value-dependence on the base. We do this regardless
872873
// of whether the base is trivial because even a trivial base
873874
// may be value-dependent on something non-trivial.
874875
if (base) {
875-
address = gen.B.createMarkDependence(loc, address, base.getValue());
876+
SILValue temporary = materialized.temporary.getValue();
877+
materialized.temporary = ManagedValue::forUnmanaged(
878+
gen.B.createMarkDependence(loc, temporary, base.getValue()));
876879
}
877880

878-
SILValue extraInfo[] = {
879-
addressAndCallback.second,
880-
callbackStorage,
881-
};
882-
883881
// TODO: maybe needsWriteback should be a thin function pointer
884882
// to which we pass the base? That would let us use direct
885883
// access for stored properties with didSet.
886-
pushWriteback(gen, loc, std::move(clonedComponent), base,
887-
ManagedValue::forUnmanaged(address), extraInfo);
884+
pushWriteback(gen, loc, std::move(clonedComponent), base, materialized);
888885

889-
return ManagedValue::forLValue(address);
886+
return ManagedValue::forLValue(materialized.temporary.getValue());
890887
}
891888

892889
void writeback(SILGenFunction &gen, SILLocation loc,
893-
ManagedValue base, ManagedValue temporary,
894-
ArrayRef<SILValue> extraInfo, bool isFinal) override {
895-
// If we don't have extraInfo, we don't have to conditionalize
890+
ManagedValue base, MaterializedLValue materialized,
891+
bool isFinal) override {
892+
// If we don't have a callback, we don't have to conditionalize
896893
// the writeback.
897-
if (extraInfo.empty()) {
898-
LogicalPathComponent::writeback(gen, loc, base, temporary, extraInfo,
894+
if (!materialized.callback) {
895+
LogicalPathComponent::writeback(gen, loc,
896+
base, materialized,
899897
isFinal);
900898
return;
901899
}
902900

903-
// Otherwise, extraInfo holds an optional callback and the
901+
// Otherwise, 'materialized' holds an optional callback and the
904902
// callback storage.
905-
assert(extraInfo.size() == 2);
906-
SILValue optionalCallback = extraInfo[0];
907-
SILValue callbackStorage = extraInfo[1];
908903

909904
// Mark the writeback as auto-generated so that we don't get
910905
// warnings if we manage to devirtualize materializeForSet.
@@ -914,7 +909,7 @@ namespace {
914909

915910
SILBasicBlock *contBB = gen.createBasicBlock();
916911
SILBasicBlock *writebackBB = gen.createBasicBlock(gen.B.getInsertionBB());
917-
gen.B.createSwitchEnum(loc, optionalCallback, /*defaultDest*/ nullptr,
912+
gen.B.createSwitchEnum(loc, materialized.callback, /*defaultDest*/ nullptr,
918913
{ { ctx.getOptionalSomeDecl(), writebackBB },
919914
{ ctx.getOptionalNoneDecl(), contBB } });
920915

@@ -926,8 +921,8 @@ namespace {
926921
SILType::getPrimitiveObjectType(TupleType::getEmpty(ctx));
927922

928923
SILType callbackSILType = gen.getLoweredType(
929-
optionalCallback->getType().getSwiftRValueType()
930-
.getAnyOptionalObjectType());
924+
materialized.callback->getType().getSwiftRValueType()
925+
.getAnyOptionalObjectType());
931926

932927
// The callback is a BB argument from the switch_enum.
933928
SILValue callback =
@@ -959,12 +954,14 @@ namespace {
959954
}
960955

961956
SILValue temporaryPointer =
962-
gen.B.createAddressToPointer(loc, temporary.getValue(),
957+
gen.B.createAddressToPointer(loc,
958+
materialized.temporary.getValue(),
963959
SILType::getRawPointerType(ctx));
964960

961+
// Apply the callback.
965962
gen.B.createApply(loc, callback, {
966963
temporaryPointer,
967-
callbackStorage,
964+
materialized.callbackStorage,
968965
baseAddress,
969966
baseMetatype
970967
}, false);
@@ -1119,8 +1116,9 @@ namespace {
11191116
}
11201117

11211118
void writeback(SILGenFunction &gen, SILLocation loc,
1122-
ManagedValue base, ManagedValue temporary,
1123-
ArrayRef<SILValue> otherInfo, bool isFinal) override {
1119+
ManagedValue base,
1120+
MaterializedLValue materialized,
1121+
bool isFinal) override {
11241122
// If this is final, we can consume the owner (stored as
11251123
// 'base'). If it isn't, we actually need to retain it, because
11261124
// we've still got a release active.
@@ -1194,7 +1192,7 @@ namespace {
11941192
std::unique_ptr<LogicalPathComponent>
11951193
component(new UnpinPseudoComponent(getTypeData()));
11961194
pushWriteback(gen, loc, std::move(component), result.second,
1197-
ManagedValue(), {});
1195+
MaterializedLValue());
11981196
return result.first;
11991197
}
12001198
}

0 commit comments

Comments
 (0)