Skip to content

Commit 3da14e6

Browse files
committed
Refactor and generalize distributed actor transport SIL generation.
Refactor the code that generates SIL to call into the distributed actor transport to eliminate duplication and better cope with concrete actor transports. Centralize the knowledge of which actor transport is used with a given distributed actor type.
1 parent 22609ac commit 3da14e6

File tree

10 files changed

+209
-264
lines changed

10 files changed

+209
-264
lines changed

include/swift/AST/KnownSDKTypes.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ KNOWN_SDK_TYPE_DECL(Concurrency, TaskLocal, ClassDecl, 1)
4545

4646
// Distributed actors
4747
KNOWN_SDK_TYPE_DECL(Distributed, DistributedActor, ProtocolDecl, 0)
48-
KNOWN_SDK_TYPE_DECL(Distributed, ActorTransport, ProtocolDecl, 0)
4948
KNOWN_SDK_TYPE_DECL(Distributed, ActorIdentity, ProtocolDecl, 0)
5049
KNOWN_SDK_TYPE_DECL(Distributed, AnyActorIdentity, StructDecl, 0)
5150

include/swift/SILOptimizer/Utils/DistributedActor.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,43 @@
1313
#ifndef SWIFT_SILOPTIMIZER_UTILS_DISTRIBUTED_ACTOR_H
1414
#define SWIFT_SILOPTIMIZER_UTILS_DISTRIBUTED_ACTOR_H
1515

16+
#include "llvm/ADT/ArrayRef.h"
17+
#include "llvm/ADT/Optional.h"
18+
#include <utility>
19+
1620
namespace swift {
1721

1822
class ASTContext;
1923
class ConstructorDecl;
2024
class ClassDecl;
25+
class DeclName;
26+
class SILBasicBlock;
2127
class SILBuilder;
2228
class SILArgument;
2329
class SILFunction;
2430
class SILLocation;
31+
class SILType;
2532
class SILValue;
2633

2734
/// Finds the first `ActorTransport`-compatible parameter of the given function.
2835
/// \returns nullptr if the function does not have such a parameter.
2936
SILArgument *findFirstActorTransportArg(SILFunction &F);
3037

38+
/// Emit a call to a witness of the actor transport protocol.
39+
///
40+
/// \param methodName The name of the method on the ActorTransport protocol.
41+
/// \param transport The transport on which to invoke the method
42+
/// \param actorType If non-empty, the type of the distributed actor that is
43+
/// provided as one of the arguments.
44+
/// \param args The arguments provided to the call, not including the transport.
45+
/// \param tryTargets For a call that can throw, the normal and error basic
46+
/// blocks that the call will branch to.
47+
void emitActorTransportWitnessCall(
48+
SILBuilder &B, SILLocation loc, DeclName methodName,
49+
SILValue transport, SILType actorType, llvm::ArrayRef<SILValue> args,
50+
llvm::Optional<std::pair<SILBasicBlock *, SILBasicBlock *>> tryTargets =
51+
llvm::None);
52+
3153
/// Emits code that notifies the distributed actor's transport that the
3254
/// actor is ready for execution.
3355
/// \param B the builder to use when emitting the code.

lib/SILGen/SILGenDistributed.cpp

Lines changed: 42 additions & 210 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,15 @@ static VarDecl* lookupProperty(NominalTypeDecl *ty, DeclName name) {
5252
static void initializeProperty(SILGenFunction &SGF, SILLocation loc,
5353
SILValue actorSelf,
5454
VarDecl* prop, SILValue value) {
55-
auto fieldAddr = SGF.B.createRefElementAddr(loc, actorSelf, prop,
56-
SGF.getLoweredType(prop->getInterfaceType()));
57-
SGF.B.createCopyAddr(loc,
58-
/*src*/value,
59-
/*dest*/fieldAddr,
60-
IsNotTake, IsInitialization);
55+
CanType propType = SGF.F.mapTypeIntoContext(prop->getInterfaceType())
56+
->getCanonicalType();
57+
SILType loweredPropType = SGF.getLoweredType(propType);
58+
auto fieldAddr = SGF.B.createRefElementAddr(loc, actorSelf, prop, loweredPropType);
59+
60+
if (fieldAddr->getType().isAddress())
61+
SGF.B.createCopyAddr(loc, value, fieldAddr, IsNotTake, IsInitialization);
62+
else
63+
SGF.B.emitStoreValueOperation(loc, value, fieldAddr, StoreOwnershipQualifier::Init);
6164
}
6265

6366
/******************************************************************************/
@@ -116,34 +119,7 @@ static void emitTransportInit(SILGenFunction &SGF,
116119
VarDecl *var = lookupProperty(classDecl, C.Id_actorTransport);
117120
assert(var);
118121

119-
// If the argument is not existential, it will be a concrete type
120-
// that can be erased to that existential.
121-
SILValue transportValue = transportArg;
122-
if (!transportArg->getType().isExistentialType()) {
123-
auto &existentialTL = SGF.getTypeLowering(var->getInterfaceType());
124-
auto concreteFormalType = transportArg->getType().getASTType();
125-
126-
auto archetype = OpenedArchetypeType::getAny(var->getInterfaceType());
127-
AbstractionPattern abstractionPattern(archetype);
128-
auto &concreteTL = SGF.getTypeLowering(abstractionPattern,
129-
concreteFormalType);
130-
131-
auto module = dc->getParentModule();
132-
auto actorTransportProto = C.getProtocol(KnownProtocolKind::ActorTransport);
133-
ProtocolConformanceRef conformances[] = {
134-
module->lookupConformance(concreteFormalType, actorTransportProto) };
135-
ManagedValue mv =
136-
SGF.emitExistentialErasure(loc, concreteFormalType,
137-
concreteTL, existentialTL,
138-
C.AllocateCopy(conformances),
139-
SGFContext(),
140-
[&](SGFContext C) -> ManagedValue {
141-
return ManagedValue::forBorrowedRValue(transportArg);
142-
});
143-
transportValue = mv.getValue();
144-
}
145-
146-
initializeProperty(SGF, loc, actorSelf.getValue(), var, transportValue);
122+
initializeProperty(SGF, loc, actorSelf.getValue(), var, transportArg);
147123
}
148124

149125
/// Emits the distributed actor's identity (`id`) initialization.
@@ -161,85 +137,27 @@ static void emitIdentityInit(SILGenFunction &SGF, ConstructorDecl *ctor,
161137
auto *dc = ctor->getDeclContext();
162138
auto classDecl = dc->getSelfClassDecl();
163139

164-
ProtocolDecl *transportProto = C.getProtocol(KnownProtocolKind::ActorTransport);
165-
ProtocolDecl *distributedActorProto = C.getProtocol(KnownProtocolKind::DistributedActor);
166-
167-
assert(distributedActorProto);
168-
assert(transportProto);
169-
170-
SILValue transportValue = findFirstActorTransportArg(F);
171-
172-
// --- Open the transport existential, if needed.
173-
auto transportASTType = transportValue->getType().getASTType();
174-
if (transportASTType->isAnyExistentialType()) {
175-
OpenedArchetypeType *Opened;
176-
transportASTType =
177-
transportASTType->openAnyExistentialType(Opened)->getCanonicalType();
178-
transportValue = B.createOpenExistentialAddr(
179-
loc, transportValue, F.getLoweredType(transportASTType),
180-
OpenedExistentialAccess::Immutable);
181-
}
182-
183140
// --- prepare `Self.self` metatype
184141
auto *selfTyDecl = ctor->getParent()->getSelfNominalTypeDecl();
185-
// This would be bad: since not ok for generic
186-
// auto selfMetatype = SGF.getLoweredType(selfTyDecl->getInterfaceType());
187-
auto selfMetatype =
188-
SGF.getLoweredType(F.mapTypeIntoContext(selfTyDecl->getInterfaceType()));
189-
// selfVarDecl.getType() // TODO: do this; then dont need the self type decl
142+
auto selfTy = F.mapTypeIntoContext(selfTyDecl->getDeclaredInterfaceType());
143+
auto selfMetatype = SGF.getLoweredType(MetatypeType::get(selfTy));
190144
SILValue selfMetatypeValue = B.createMetatype(loc, selfMetatype);
191145

192-
// === Make the transport.assignIdentity call
193-
// --- prepare the witness_method
194-
// Note: it does not matter on what module we perform the lookup,
195-
// it is currently ignored. So the Stdlib module is good enough.
196-
auto *module = SGF.getModule().getSwiftModule();
197-
198-
// the conformance here is just an abstract thing so we can simplify
199-
auto transportConfRef = ProtocolConformanceRef(transportProto);
200-
assert(!transportConfRef.isInvalid() && "Missing conformance to `ActorTransport`");
201-
202-
auto selfTy = F.mapTypeIntoContext(selfTyDecl->getDeclaredInterfaceType()); // TODO: thats just self var devl getType
203-
204-
auto distributedActorConfRef = module->lookupConformance(
205-
selfTy,
206-
distributedActorProto);
207-
assert(!distributedActorConfRef.isInvalid() && "Missing conformance to `DistributedActor`");
208-
209-
auto assignIdentityMethod =
210-
cast<FuncDecl>(transportProto->getSingleRequirement(C.Id_assignIdentity));
211-
auto assignIdentityRef = SILDeclRef(assignIdentityMethod, SILDeclRef::Kind::Func);
212-
auto assignIdentitySILTy =
213-
SGF.getConstantInfo(SGF.getTypeExpansionContext(), assignIdentityRef)
214-
.getSILType();
215-
216-
auto assignWitnessMethod = B.createWitnessMethod(
217-
loc,
218-
/*lookupTy*/transportASTType,
219-
/*Conformance*/transportConfRef,
220-
/*member*/assignIdentityRef,
221-
/*methodTy*/assignIdentitySILTy);
222-
223-
// --- prepare conformance subs
224-
auto genericSig = assignIdentityMethod->getGenericSignature();
225-
226-
SubstitutionMap subs =
227-
SubstitutionMap::get(genericSig,
228-
{transportASTType, selfTy},
229-
{transportConfRef, distributedActorConfRef});
230-
231-
VarDecl *var = lookupProperty(classDecl, C.Id_id);
146+
SILValue transport = findFirstActorTransportArg(F);
232147

233148
// --- create a temporary storage for the result of the call
234149
// it will be deallocated automatically as we exit this scope
235-
auto resultTy = SGF.getLoweredType(var->getInterfaceType());
150+
VarDecl *var = lookupProperty(classDecl, C.Id_id);
151+
auto resultTy = SGF.getLoweredType(
152+
F.mapTypeIntoContext(var->getInterfaceType()));
236153
auto temp = SGF.emitTemporaryAllocation(loc, resultTy);
237154

238-
// ---- actually call transport.assignIdentity(Self.self)
239-
B.createApply(
240-
loc, assignWitnessMethod, subs,
241-
{ temp, selfMetatypeValue, transportValue});
155+
// --- emit the call itself.
156+
emitActorTransportWitnessCall(
157+
B, loc, C.Id_assignIdentity, transport, SGF.getLoweredType(selfTy),
158+
{ temp, selfMetatypeValue });
242159

160+
// --- initialize the property.
243161
initializeProperty(SGF, loc, borrowedSelfArg.getValue(), var, temp);
244162
}
245163

@@ -282,74 +200,15 @@ static void createDistributedActorFactory_resolve(
282200
SILValue transportValue, Type selfTy, SILValue selfMetatypeValue,
283201
SILType resultTy, SILBasicBlock *normalBB, SILBasicBlock *errorBB) {
284202
auto &B = SGF.B;
285-
auto &SGM = SGF.SGM;
286-
auto &F = SGF.F;
287-
SILGenFunctionBuilder builder(SGM);
288203

289204
auto loc = SILLocation(fd);
290205
loc.markAutoGenerated();
291206

292-
ProtocolDecl *distributedActorProto =
293-
C.getProtocol(KnownProtocolKind::DistributedActor);
294-
ProtocolDecl *transportProto =
295-
C.getProtocol(KnownProtocolKind::ActorTransport);
296-
assert(distributedActorProto);
297-
assert(transportProto);
298-
299-
// // --- Open the transport existential
300-
OpenedArchetypeType *Opened;
301-
auto transportASTType = transportValue->getType().getASTType();
302-
auto openedTransportType =
303-
transportASTType->openAnyExistentialType(Opened)->getCanonicalType();
304-
auto openedTransportSILType = F.getLoweredType(openedTransportType);
305-
auto transportArchetypeValue =
306-
B.createOpenExistentialAddr(loc, transportValue, openedTransportSILType,
307-
OpenedExistentialAccess::Immutable);
308-
309-
// --- prepare the witness_method
310-
// Note: it does not matter on what module we perform the lookup,
311-
// it is currently ignored. So the Stdlib module is good enough.
312-
auto *module = SGF.getModule().getSwiftModule();
313-
314-
// the conformance here is just an abstract thing so we can simplify
315-
auto transportConfRef = ProtocolConformanceRef(transportProto);
316-
assert(!transportConfRef.isInvalid() &&
317-
"Missing conformance to `ActorTransport`");
318-
319-
auto distributedActorConfRef =
320-
module->lookupConformance(selfTy, distributedActorProto);
321-
assert(!distributedActorConfRef.isInvalid() &&
322-
"Missing conformance to `DistributedActor`");
323-
324-
auto resolveMethod =
325-
cast<FuncDecl>(transportProto->getSingleRequirement(C.Id_resolve));
326-
auto resolveRef = SILDeclRef(resolveMethod, SILDeclRef::Kind::Func);
327-
auto constantInfo =
328-
SGF.getConstantInfo(SGF.getTypeExpansionContext(), resolveRef);
329-
auto resolveSILTy = constantInfo.getSILType();
330-
331-
auto resolveWitnessMethod =
332-
B.createWitnessMethod(loc,
333-
/*lookupTy*/ openedTransportType,
334-
/*Conformance*/ transportConfRef,
335-
/*member*/ resolveRef,
336-
/*methodTy*/ resolveSILTy);
337-
338-
// // --- prepare conformance subs
339-
auto genericSig = resolveMethod->getGenericSignature();
340-
341-
SubstitutionMap subs =
342-
SubstitutionMap::get(genericSig, {openedTransportType, selfTy},
343-
{transportConfRef, distributedActorConfRef});
344-
345207
// // ---- actually call transport.resolve(id, as: Self.self)
346-
347-
SmallVector<SILValue, 3> params;
348-
params.push_back(identityValue);
349-
params.push_back(selfMetatypeValue);
350-
params.push_back(transportArchetypeValue); // self for the call, as last param
351-
352-
B.createTryApply(loc, resolveWitnessMethod, subs, params, normalBB, errorBB);
208+
emitActorTransportWitnessCall(
209+
B, loc, C.Id_resolve, transportValue, SGF.getLoweredType(selfTy),
210+
{ identityValue, selfMetatypeValue },
211+
std::make_pair(normalBB, errorBB));
353212
}
354213

355214
/// Function body of:
@@ -374,8 +233,6 @@ void SILGenFunction::emitDistributedActorFactory(FuncDecl *fd) {
374233

375234
// --- Parameter: transport
376235
SILArgument *transportArg = F.getArgument(1);
377-
assert(
378-
transportArg->getType().getASTType()->isEqual(C.getActorTransportType()));
379236

380237
SILValue selfArgValue = F.getSelfArgument();
381238
ManagedValue selfArg = ManagedValue::forUnmanaged(selfArgValue);
@@ -496,53 +353,28 @@ void SILGenFunction::emitResignIdentityCall(SILLocation loc,
496353
ASTContext &ctx = getASTContext();
497354

498355
FormalEvaluationScope scope(*this);
499-
356+
500357
// ==== locate: self.id
501358
auto *idVarDeclRef = lookupProperty(actorDecl, ctx.Id_id);
502-
auto idRef =
503-
B.createRefElementAddr(loc, actorSelf, idVarDeclRef,
504-
getLoweredType(idVarDeclRef->getType()));
505-
359+
CanType idType = F.mapTypeIntoContext(
360+
idVarDeclRef->getInterfaceType())->getCanonicalType();
361+
auto idRef = B.createRefElementAddr(loc, actorSelf, idVarDeclRef,
362+
getLoweredType(idType));
363+
506364
// ==== locate: self.actorTransport
507365
auto transportVarDeclRef = lookupProperty(actorDecl, ctx.Id_actorTransport);
366+
CanType transportType = F.mapTypeIntoContext(
367+
transportVarDeclRef->getInterfaceType())->getCanonicalType();
508368
auto transportRef =
509-
B.createRefElementAddr(loc, actorSelf, transportVarDeclRef,
510-
getLoweredType(transportVarDeclRef->getType()));
511-
512-
// ==== locate: self.transport.resignIdentity(...)
513-
auto *transportDecl = ctx.getActorTransportDecl();
514-
auto resignFnDecls = transportDecl->lookupDirect(ctx.Id_resignIdentity);
515-
assert(resignFnDecls.size() == 1);
516-
auto *resignFnDecl = resignFnDecls.front();
517-
auto resignFnRef = SILDeclRef(resignFnDecl);
518-
519-
// ==== perform the call
520-
auto openedTransport =
521-
OpenedArchetypeType::get(transportVarDeclRef->getType());
522-
auto transportAddr =
523-
B.createOpenExistentialAddr(loc, /*operand=*/transportRef.getValue(),
524-
getLoweredType(openedTransport),
525-
OpenedExistentialAccess::Immutable);
526-
527-
auto resignFnType =
528-
SGM.M.Types.getConstantFunctionType(TypeExpansionContext::minimal(),
529-
resignFnRef);
530-
531-
auto conformance = ProtocolConformanceRef(transportDecl);
532-
auto witness =
533-
B.createWitnessMethod(loc, openedTransport,
534-
conformance, resignFnRef,
535-
SILType::getPrimitiveObjectType(resignFnType));
536-
537-
auto subs = SubstitutionMap::getProtocolSubstitutions(transportDecl,
538-
openedTransport,
539-
conformance);
540-
541-
SmallVector<SILValue, 2> params;
542-
params.push_back(idRef.getValue());
543-
params.push_back(transportAddr); // self for the call, as last param
544-
545-
B.createApply(loc, witness, subs, params);
369+
B.createRefElementAddr(loc, actorSelf, transportVarDeclRef,
370+
getLoweredType(transportType));
371+
372+
// Perform the call.
373+
emitActorTransportWitnessCall(
374+
B, loc, ctx.Id_resignIdentity,
375+
transportRef.getValue(),
376+
SILType(),
377+
{ idRef.getValue() });
546378
}
547379

548380
void

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,10 @@ void LifetimeChecker::handleLoadUseFailureForActorInit(
20832083
return;
20842084
}
20852085

2086+
// Skip autogenerated instructions.
2087+
if (Use.Inst->getLoc().isAutoGenerated())
2088+
return;
2089+
20862090
// Everything else is disallowed!
20872091
switch(ActorKind) {
20882092
case ActorInitKind::None:

0 commit comments

Comments
 (0)