Skip to content

Commit da80d4b

Browse files
authored
Merge pull request #9637 from slavapestov/silgen-existential-lvalue-plumbing
SILGen plumbing for existential lvalue access fixes
2 parents df76500 + 31efc6a commit da80d4b

File tree

4 files changed

+211
-20
lines changed

4 files changed

+211
-20
lines changed

lib/SILGen/LValue.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class PathComponent {
9797
TupleElementKind, // tuple_element_addr
9898
StructElementKind, // struct_element_addr
9999
OptionalObjectKind, // optional projection
100-
OpenedExistentialKind, // opened opaque existential
100+
OpenOpaqueExistentialKind, // opened opaque existential
101101
AddressorKind, // var/subscript addressor
102102
ValueKind, // random base pointer as an lvalue
103103
KeyPathApplicationKind, // applying a key path
@@ -107,6 +107,7 @@ class PathComponent {
107107
OwnershipKind, // weak pointer remapping
108108
AutoreleasingWritebackKind, // autorelease pointer on set
109109
WritebackPseudoKind, // a fake component to customize writeback
110+
OpenClassExistentialKind, // opened class existential
110111
// Translation LValue kinds (a subtype of logical)
111112
OrigToSubstKind, // generic type substitution
112113
SubstToOrigKind, // generic type substitution

lib/SILGen/SILGenExpr.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4001,29 +4001,33 @@ void SILGenFunction::emitOpenExistentialExprImpl(
40014001
llvm::function_ref<void(Expr *)> emitSubExpr) {
40024002
Optional<FormalEvaluationScope> writebackScope;
40034003

4004+
Type opaqueValueType = E->getOpaqueValue()->getType()->getRValueType();
4005+
40044006
// Emit the existential value.
4005-
ManagedValue existentialValue;
4007+
SILGenFunction::OpaqueValueState state;
4008+
40064009
AccessKind accessKind;
40074010
if (E->getExistentialValue()->getType()->is<LValueType>()) {
40084011
// Create a writeback scope for the access to the existential lvalue.
40094012
writebackScope.emplace(*this);
40104013

40114014
accessKind = E->getExistentialValue()->getLValueAccessKind();
4012-
existentialValue = emitAddressOfLValue(
4013-
E->getExistentialValue(),
4014-
emitLValue(E->getExistentialValue(), accessKind),
4015-
accessKind);
4015+
auto lv = emitLValue(E->getExistentialValue(), accessKind);
4016+
lv = emitOpenExistentialLValue(E, std::move(lv),
4017+
CanArchetypeType(E->getOpenedArchetype()),
4018+
accessKind);
4019+
auto addr = emitAddressOfLValue(E, std::move(lv), accessKind);
4020+
state = {addr, false, false};
40164021
} else {
40174022
accessKind = AccessKind::Read;
4018-
existentialValue = emitRValueAsSingleValue(
4019-
E->getExistentialValue(),
4020-
SGFContext::AllowGuaranteedPlusZero);
4021-
}
4023+
auto existentialValue = emitRValueAsSingleValue(
4024+
E->getExistentialValue(),
4025+
SGFContext::AllowGuaranteedPlusZero);
40224026

4023-
Type opaqueValueType = E->getOpaqueValue()->getType()->getRValueType();
4024-
SILGenFunction::OpaqueValueState state = emitOpenExistential(
4027+
state = emitOpenExistential(
40254028
E, existentialValue, E->getOpenedArchetype(),
40264029
getLoweredType(opaqueValueType), accessKind);
4030+
}
40274031

40284032
// Register the opaque value for the projected existential.
40294033
SILGenFunction::OpaqueValueRAII opaqueValueRAII(

lib/SILGen/SILGenFunction.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
957957
/// \param openedArchetype The opened existential archetype.
958958
/// \param loweredOpenedType The lowered type of the projection, which in
959959
/// practice will be the openedArchetype, possibly wrapped in a metatype.
960-
SILGenFunction::OpaqueValueState
960+
OpaqueValueState
961961
emitOpenExistential(SILLocation loc,
962962
ManagedValue existentialValue,
963963
ArchetypeType *openedArchetype,
@@ -1284,6 +1284,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
12841284
ManagedValue emitAddressOfLValue(SILLocation loc, LValue &&src,
12851285
AccessKind accessKind,
12861286
TSanKind tsanKind = TSanKind::None);
1287+
LValue emitOpenExistentialLValue(SILLocation loc,
1288+
LValue &&existentialLV,
1289+
CanArchetypeType openedArchetype,
1290+
AccessKind accessKind);
12871291

12881292
RValue emitLoadOfLValue(SILLocation loc, LValue &&src, SGFContext C,
12891293
bool isGuaranteedValid = false);

lib/SILGen/SILGenLValue.cpp

Lines changed: 189 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,63 @@ ManagedValue LogicalPathComponent::getMaterialized(SILGenFunction &SGF,
223223
SILLocation loc,
224224
ManagedValue base,
225225
AccessKind kind) && {
226+
if (getTypeOfRValue().getSwiftRValueType()->hasOpenedExistential()) {
227+
if (kind == AccessKind::Read) {
228+
// Emit a 'get' into the temporary.
229+
RValue value =
230+
std::move(*this).get(SGF, loc, base, SGFContext());
231+
232+
// Create a temporary.
233+
std::unique_ptr<TemporaryInitialization> temporaryInit =
234+
SGF.emitFormalAccessTemporary(loc,
235+
SGF.getTypeLowering(getTypeOfRValue()));
236+
237+
std::move(value).forwardInto(SGF, loc, temporaryInit.get());
238+
239+
return temporaryInit->getManagedAddress();
240+
}
241+
242+
assert(SGF.InWritebackScope &&
243+
"materializing l-value for modification without writeback scope");
244+
245+
// Clone anything else about the component that we might need in the
246+
// writeback.
247+
auto clonedComponent = clone(SGF, loc);
248+
249+
SILValue mv;
250+
{
251+
FormalEvaluationScope Scope(SGF);
252+
253+
// Otherwise, we need to emit a get and set. Borrow the base for
254+
// the getter.
255+
ManagedValue getterBase =
256+
base ? base.formalAccessBorrow(SGF, loc) : ManagedValue();
257+
258+
// Emit a 'get' into a temporary and then pop the borrow of base.
259+
RValue value =
260+
std::move(*this).get(SGF, loc, getterBase, SGFContext());
261+
262+
mv = std::move(value).forwardAsSingleValue(SGF, loc);
263+
}
264+
265+
auto &TL = SGF.getTypeLowering(getTypeOfRValue());
266+
267+
// Create a temporary.
268+
std::unique_ptr<TemporaryInitialization> temporaryInit =
269+
SGF.emitFormalAccessTemporary(loc, TL);
270+
271+
SGF.emitSemanticStore(loc, mv, temporaryInit->getAddress(),
272+
TL, IsInitialization);
273+
temporaryInit->finishInitialization(SGF);
274+
275+
auto temporary = temporaryInit->getManagedAddress();
276+
277+
// Push a writeback for the temporary.
278+
pushWriteback(SGF, loc, std::move(clonedComponent), base,
279+
MaterializedLValue(temporary));
280+
return temporary.unmanagedBorrow();
281+
}
282+
226283
// If this is just for a read, emit a load into a temporary memory
227284
// location.
228285
if (kind == AccessKind::Read) {
@@ -579,20 +636,34 @@ namespace {
579636
public:
580637
OpenOpaqueExistentialComponent(CanArchetypeType openedArchetype)
581638
: PhysicalPathComponent(getOpenedArchetypeTypeData(openedArchetype),
582-
OpenedExistentialKind) {}
639+
OpenOpaqueExistentialKind) {}
583640

584641
ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
585642
AccessKind accessKind) && override {
586643
assert(base.getType().isExistentialType() &&
587644
"base for open existential component must be an existential");
588645
assert(base.getType().isAddress() &&
589646
"base value of open-existential component was not an address?");
590-
assert(base.getType().getPreferredExistentialRepresentation(SGF.SGM.M)
591-
== ExistentialRepresentation::Opaque);
647+
SILValue addr;
592648

593-
SILValue addr = SGF.B.createOpenExistentialAddr(
649+
auto rep = base.getType().getPreferredExistentialRepresentation(SGF.SGM.M);
650+
switch (rep) {
651+
case ExistentialRepresentation::Opaque:
652+
addr = SGF.B.createOpenExistentialAddr(
594653
loc, base.getValue(), getTypeOfRValue().getAddressType(),
595654
getOpenedExistentialAccessFor(accessKind));
655+
break;
656+
case ExistentialRepresentation::Boxed: {
657+
auto &TL = SGF.getTypeLowering(base.getType());
658+
auto error = SGF.emitLoad(loc, base.getValue(), TL,
659+
SGFContext(), IsNotTake);
660+
addr = SGF.B.createOpenExistentialBox(
661+
loc, error.getValue(), getTypeOfRValue().getAddressType());
662+
break;
663+
}
664+
default:
665+
llvm_unreachable("Bad existential representation for address-only type");
666+
}
596667

597668
SGF.setArchetypeOpeningSite(cast<ArchetypeType>(getSubstFormalType()),
598669
addr);
@@ -604,6 +675,89 @@ namespace {
604675
}
605676
};
606677

678+
/// A local path component for the payload of a class existential.
679+
///
680+
/// TODO: Could be physical if we had a way to project out the
681+
/// payload.
682+
class OpenClassExistentialComponent : public LogicalPathComponent {
683+
static LValueTypeData getOpenedArchetypeTypeData(CanArchetypeType type) {
684+
return {
685+
AbstractionPattern::getOpaque(), type,
686+
SILType::getPrimitiveObjectType(type)
687+
};
688+
}
689+
public:
690+
OpenClassExistentialComponent(CanArchetypeType openedArchetype)
691+
: LogicalPathComponent(getOpenedArchetypeTypeData(openedArchetype),
692+
OpenClassExistentialKind) {}
693+
694+
AccessKind getBaseAccessKind(SILGenFunction &SGF,
695+
AccessKind kind) const override {
696+
// Always use the same access kind for the base.
697+
return kind;
698+
}
699+
700+
void diagnoseWritebackConflict(LogicalPathComponent *RHS,
701+
SILLocation loc1, SILLocation loc2,
702+
SILGenFunction &SGF) override {
703+
// no useful writeback diagnostics at this point
704+
}
705+
706+
RValue get(SILGenFunction &SGF, SILLocation loc,
707+
ManagedValue base, SGFContext c) && override {
708+
auto refType = base.getType().getObjectType();
709+
auto &TL = SGF.getTypeLowering(refType);
710+
711+
// Load the original value.
712+
auto result = SGF.emitLoad(loc, base.getValue(), TL,
713+
SGFContext(), IsNotTake);
714+
715+
assert(refType.isExistentialType() &&
716+
"base for open existential component must be an existential");
717+
assert(refType.getPreferredExistentialRepresentation(SGF.SGM.M)
718+
== ExistentialRepresentation::Class);
719+
auto ref = SGF.B.createOpenExistentialRef(
720+
loc, result, getTypeOfRValue());
721+
722+
SGF.setArchetypeOpeningSite(cast<ArchetypeType>(getSubstFormalType()),
723+
ref.getValue());
724+
725+
return RValue(SGF, loc, getSubstFormalType(), ref);
726+
}
727+
728+
void set(SILGenFunction &SGF, SILLocation loc,
729+
RValue &&value, ManagedValue base) && override {
730+
auto payload = std::move(value).forwardAsSingleValue(SGF, loc);
731+
732+
SmallVector<ProtocolConformanceRef, 2> conformances;
733+
for (auto proto : cast<ArchetypeType>(getSubstFormalType())->getConformsTo())
734+
conformances.push_back(ProtocolConformanceRef(proto));
735+
736+
auto ref = SGF.B.createInitExistentialRef(
737+
loc,
738+
base.getType().getObjectType(),
739+
getSubstFormalType(),
740+
payload,
741+
SGF.getASTContext().AllocateCopy(conformances));
742+
743+
auto &TL = SGF.getTypeLowering(base.getType());
744+
SGF.emitSemanticStore(loc, ref,
745+
base.getValue(), TL, IsNotInitialization);
746+
}
747+
748+
std::unique_ptr<LogicalPathComponent>
749+
clone(SILGenFunction &SGF, SILLocation loc) const override {
750+
LogicalPathComponent *clone =
751+
new OpenClassExistentialComponent(
752+
cast<ArchetypeType>(getSubstFormalType()));
753+
return std::unique_ptr<LogicalPathComponent>(clone);
754+
}
755+
756+
void print(raw_ostream &OS) const override {
757+
OS << "OpenClassExistentialComponent(...)\n";
758+
}
759+
};
760+
607761
/// A physical path component which returns a literal address.
608762
class ValueComponent : public PhysicalPathComponent {
609763
ManagedValue Value;
@@ -1914,9 +2068,11 @@ LValue SILGenLValue::visitOpaqueValueExpr(OpaqueValueExpr *e,
19142068
SGF.OpaqueValueExprs.erase(known);
19152069

19162070
// Do formal evaluation of the underlying existential lvalue.
1917-
LValue lv = visitRec(opened->getExistentialValue(), accessKind);
1918-
lv.add<OpenOpaqueExistentialComponent>(
1919-
cast<ArchetypeType>(opened->getOpenedArchetype()->getCanonicalType()));
2071+
auto lv = visitRec(opened->getExistentialValue(), accessKind);
2072+
lv = SGF.emitOpenExistentialLValue(
2073+
opened, std::move(lv),
2074+
CanArchetypeType(opened->getOpenedArchetype()),
2075+
accessKind);
19202076
return lv;
19212077
}
19222078

@@ -2817,6 +2973,32 @@ ManagedValue SILGenFunction::emitAddressOfLValue(SILLocation loc,
28172973
return ManagedValue::forLValue(addr.getValue());
28182974
}
28192975

2976+
LValue
2977+
SILGenFunction::emitOpenExistentialLValue(SILLocation loc,
2978+
LValue &&lv,
2979+
CanArchetypeType openedArchetype,
2980+
AccessKind accessKind) {
2981+
// Open up the existential.
2982+
auto rep = lv.getTypeOfRValue()
2983+
.getPreferredExistentialRepresentation(SGM.M);
2984+
switch (rep) {
2985+
case ExistentialRepresentation::Opaque:
2986+
case ExistentialRepresentation::Boxed: {
2987+
lv.add<OpenOpaqueExistentialComponent>(openedArchetype);
2988+
break;
2989+
}
2990+
case ExistentialRepresentation::Class: {
2991+
lv.add<OpenClassExistentialComponent>(openedArchetype);
2992+
break;
2993+
}
2994+
default:
2995+
llvm_unreachable("Cannot perform lvalue access of "
2996+
"non-opaque, non-class existential");
2997+
}
2998+
2999+
return std::move(lv);
3000+
}
3001+
28203002
void SILGenFunction::emitAssignToLValue(SILLocation loc, RValue &&src,
28213003
LValue &&dest) {
28223004
FormalEvaluationScope scope(*this);

0 commit comments

Comments
 (0)