@@ -51,7 +51,6 @@ namespace {
5151// / inserts the derivations, turning those hops into hops to executors.
5252// / IRGen expects hops to be to executors before it runs.
5353class LowerHopToActor {
54- SILFunction *F;
5554 DominanceInfo *Dominance;
5655
5756 // / A map from an actor value to the dominating instruction that
@@ -72,11 +71,7 @@ class LowerHopToActor {
7271 SILValue actor, bool makeOptional);
7372
7473public:
75- LowerHopToActor (SILFunction *f,
76- DominanceInfo *dominance)
77- : F(f),
78- Dominance (dominance)
79- { }
74+ LowerHopToActor (DominanceInfo *dominance) : Dominance(dominance) {}
8075
8176 // / The entry point to the transformation.
8277 bool run ();
@@ -194,6 +189,118 @@ static AccessorDecl *getUnownedExecutorGetter(ASTContext &ctx,
194189 return nullptr ;
195190}
196191
192+ // / Emit the instructions to derive an executor value from an actor value.
193+ static SILValue getExecutorForActor (SILBuilder &B, SILLocation loc,
194+ SILValue actor) {
195+ auto *F = actor->getFunction ();
196+ auto &ctx = F->getASTContext ();
197+ auto executorType = SILType::getPrimitiveObjectType (ctx.TheExecutorType );
198+
199+ // If the actor type is a default actor, go ahead and devirtualize here.
200+ auto module = F->getModule ().getSwiftModule ();
201+ CanType actorType = actor->getType ().getASTType ();
202+
203+ // Determine if the actor is a "default actor" in which case we'll build a
204+ // default actor executor ref inline, rather than calling out to the
205+ // user-provided executor function.
206+ if (isDefaultActorType (actorType, module , F->getResilienceExpansion ())) {
207+ auto builtinName = ctx.getIdentifier (
208+ getBuiltinName (BuiltinValueKind::BuildDefaultActorExecutorRef));
209+ auto builtinDecl = cast<FuncDecl>(getBuiltinValueDecl (ctx, builtinName));
210+ auto subs = SubstitutionMap::get (builtinDecl->getGenericSignature (),
211+ {actorType}, LookUpConformanceInModule ());
212+ return B.createBuiltin (loc, builtinName, executorType, subs, {actor});
213+ }
214+
215+ // Otherwise, go through (Distributed)Actor.unownedExecutor.
216+ auto actorKind = actorType->isDistributedActor ()
217+ ? KnownProtocolKind::DistributedActor
218+ : KnownProtocolKind::Actor;
219+ auto actorProtocol = ctx.getProtocol (actorKind);
220+ auto req = getUnownedExecutorGetter (ctx, actorProtocol);
221+ assert (req && " Concurrency library broken" );
222+ SILDeclRef fn (req, SILDeclRef::Kind::Func);
223+
224+ // Open an existential actor type.
225+ if (actorType->isExistentialType ()) {
226+ actorType = ExistentialArchetypeType::get (actorType)->getCanonicalType ();
227+ SILType loweredActorType = F->getLoweredType (actorType);
228+ actor = B.createOpenExistentialRef (loc, actor, loweredActorType);
229+ }
230+
231+ auto actorConf = lookupConformance (actorType, actorProtocol);
232+ assert (actorConf && " hop_to_executor with actor that doesn't conform to "
233+ " Actor or DistributedActor" );
234+
235+ auto subs = SubstitutionMap::get (req->getGenericSignature (), {actorType},
236+ {actorConf});
237+ auto fnType = F->getModule ().Types .getConstantFunctionType (*F, fn);
238+
239+ auto witness = B.createWitnessMethod (loc, actorType, actorConf, fn,
240+ SILType::getPrimitiveObjectType (fnType));
241+ auto witnessCall = B.createApply (loc, witness, subs, {actor});
242+
243+ // The protocol requirement returns an UnownedSerialExecutor; extract
244+ // the Builtin.Executor from it.
245+ auto executorDecl = ctx.getUnownedSerialExecutorDecl ();
246+ auto executorProps = executorDecl->getStoredProperties ();
247+ assert (executorProps.size () == 1 );
248+ return B.createStructExtract (loc, witnessCall, executorProps[0 ]);
249+ }
250+
251+ static SILValue getExecutorForOptionalActor (SILBuilder &B, SILLocation loc,
252+ SILValue actor) {
253+ auto &ctx = B.getASTContext ();
254+ auto executorType = SILType::getPrimitiveObjectType (ctx.TheExecutorType );
255+ auto optionalExecutorType = SILType::getOptionalType (executorType);
256+
257+ // Unwrap the optional and call 'unownedExecutor'.
258+ auto *someDecl = ctx.getOptionalSomeDecl ();
259+ auto *curBB = B.getInsertionBB ();
260+ auto *contBB = B.getInsertionPoint () == curBB->end ()
261+ ? B.getFunction ().createBasicBlockAfter (curBB)
262+ : curBB->split (B.getInsertionPoint ());
263+ auto *someBB = B.getFunction ().createBasicBlockAfter (curBB);
264+ auto *noneBB = B.getFunction ().createBasicBlockAfter (someBB);
265+
266+ // unmarked executor
267+ SILValue result = contBB->createPhiArgument (optionalExecutorType,
268+ actor->getOwnershipKind ());
269+
270+ SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 1 > caseBBs;
271+ caseBBs.push_back (std::make_pair (someDecl, someBB));
272+ B.setInsertionPoint (curBB);
273+ auto *switchEnum = B.createSwitchEnum (loc, actor, noneBB, caseBBs);
274+
275+ SILValue unwrappedActor;
276+ if (B.hasOwnership ()) {
277+ unwrappedActor = switchEnum->createOptionalSomeResult ();
278+ B.setInsertionPoint (someBB);
279+ } else {
280+ B.setInsertionPoint (someBB);
281+ unwrappedActor = B.createUncheckedEnumData (loc, actor, someDecl);
282+ }
283+
284+ // Call 'unownedExecutor' in the some block and wrap the result into
285+ // an optional.
286+ SILValue unwrappedExecutor = getExecutorForActor (B, loc, unwrappedActor);
287+ SILValue someValue =
288+ B.createOptionalSome (loc, unwrappedExecutor, optionalExecutorType);
289+ B.createBranch (loc, contBB, {someValue});
290+
291+ // In the none case, create a nil executor value, which represents
292+ // the generic executor.
293+ B.setInsertionPoint (noneBB);
294+ SILValue noneValue = B.createOptionalNone (loc, optionalExecutorType);
295+ B.createBranch (loc, contBB, {noneValue});
296+ if (contBB->begin () == contBB->end ()) {
297+ B.setInsertionPoint (contBB);
298+ } else {
299+ B.setInsertionPoint (contBB->begin ());
300+ }
301+ return result;
302+ }
303+
197304SILValue LowerHopToActor::emitGetExecutor (SILBuilderWithScope &B,
198305 SILLocation loc, SILValue actor,
199306 bool makeOptional) {
@@ -204,125 +311,31 @@ SILValue LowerHopToActor::emitGetExecutor(SILBuilderWithScope &B,
204311 // If the operand is already a BuiltinExecutorType, just wrap it
205312 // in an optional.
206313 if (makeOptional && actor->getType ().is <BuiltinExecutorType>()) {
207- return B.createOptionalSome (
208- loc, actor,
209- SILType::getOptionalType (actor->getType ()));
314+ return B.createOptionalSome (loc, actor,
315+ SILType::getOptionalType (actor->getType ()));
210316 }
211317
212- auto &ctx = F->getASTContext ();
213- auto executorType = SILType::getPrimitiveObjectType (ctx.TheExecutorType );
214- auto optionalExecutorType = SILType::getOptionalType (executorType);
215-
216- // / Emit the instructions to derive an executor value from an actor value.
217- auto getExecutorFor = [&](SILValue actor) -> SILValue {
218- // If the actor type is a default actor, go ahead and devirtualize here.
219- auto module = F->getModule ().getSwiftModule ();
220- CanType actorType = actor->getType ().getASTType ();
221-
222- // Determine if the actor is a "default actor" in which case we'll build a default
223- // actor executor ref inline, rather than calling out to the user-provided executor function.
224- if (isDefaultActorType (actorType, module , F->getResilienceExpansion ())) {
225- auto builtinName = ctx.getIdentifier (
226- getBuiltinName (BuiltinValueKind::BuildDefaultActorExecutorRef));
227- auto builtinDecl = cast<FuncDecl>(getBuiltinValueDecl (ctx, builtinName));
228- auto subs = SubstitutionMap::get (builtinDecl->getGenericSignature (),
229- {actorType},
230- LookUpConformanceInModule ());
231- return B.createBuiltin (loc, builtinName, executorType, subs, {actor});
232- }
233-
234- // Otherwise, go through (Distributed)Actor.unownedExecutor.
235- auto actorKind = actorType->isDistributedActor () ?
236- KnownProtocolKind::DistributedActor :
237- KnownProtocolKind::Actor;
238- auto actorProtocol = ctx.getProtocol (actorKind);
239- auto req = getUnownedExecutorGetter (ctx, actorProtocol);
240- assert (req && " Concurrency library broken" );
241- SILDeclRef fn (req, SILDeclRef::Kind::Func);
242-
243- // Open an existential actor type.
244- if (actorType->isExistentialType ()) {
245- actorType = ExistentialArchetypeType::get (actorType)->getCanonicalType ();
246- SILType loweredActorType = F->getLoweredType (actorType);
247- actor = B.createOpenExistentialRef (loc, actor, loweredActorType);
248- }
249-
250- auto actorConf = lookupConformance (actorType, actorProtocol);
251- assert (actorConf &&
252- " hop_to_executor with actor that doesn't conform to Actor or DistributedActor" );
253-
254- auto subs = SubstitutionMap::get (req->getGenericSignature (),
255- {actorType}, {actorConf});
256- auto fnType = F->getModule ().Types .getConstantFunctionType (*F, fn);
257-
258- auto witness =
259- B.createWitnessMethod (loc, actorType, actorConf, fn,
260- SILType::getPrimitiveObjectType (fnType));
261- auto witnessCall = B.createApply (loc, witness, subs, {actor});
262-
263- // The protocol requirement returns an UnownedSerialExecutor; extract
264- // the Builtin.Executor from it.
265- auto executorDecl = ctx.getUnownedSerialExecutorDecl ();
266- auto executorProps = executorDecl->getStoredProperties ();
267- assert (executorProps.size () == 1 );
268- return B.createStructExtract (loc, witnessCall, executorProps[0 ]);
269- };
270-
271318 bool needEndBorrow = false ;
272319 SILValue unmarkedExecutor;
273320 if (auto wrappedActor = actorType->getOptionalObjectType ()) {
274321 assert (makeOptional);
275-
276- if (B. hasOwnership () && actor->getOwnershipKind () == OwnershipKind::Owned ) {
322+ if (B. hasOwnership () &&
323+ actor->getOwnershipKind () != OwnershipKind::Guaranteed ) {
277324 actor = B.createBeginBorrow (loc, actor);
278325 needEndBorrow = true ;
279326 }
280327
281- // Unwrap the optional and call 'unownedExecutor'.
282- auto *someDecl = B.getASTContext ().getOptionalSomeDecl ();
283- auto *curBB = B.getInsertionPoint ()->getParent ();
284- auto *contBB = curBB->split (B.getInsertionPoint ());
285- auto *someBB = B.getFunction ().createBasicBlockAfter (curBB);
286- auto *noneBB = B.getFunction ().createBasicBlockAfter (someBB);
287-
288- unmarkedExecutor = contBB->createPhiArgument (
289- optionalExecutorType, actor->getOwnershipKind ());
290-
291- SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 1 > caseBBs;
292- caseBBs.push_back (std::make_pair (someDecl, someBB));
293- B.setInsertionPoint (curBB);
294- auto *switchEnum = B.createSwitchEnum (loc, actor, noneBB, caseBBs);
295-
296- SILValue unwrappedActor;
297- if (B.hasOwnership ()) {
298- unwrappedActor = switchEnum->createOptionalSomeResult ();
299- B.setInsertionPoint (someBB);
300- } else {
301- B.setInsertionPoint (someBB);
302- unwrappedActor = B.createUncheckedEnumData (loc, actor, someDecl);
303- }
304-
305- // Call 'unownedExecutor' in the some block and wrap the result into
306- // an optional.
307- SILValue unwrappedExecutor = getExecutorFor (unwrappedActor);
308- SILValue someValue =
309- B.createOptionalSome (loc, unwrappedExecutor, optionalExecutorType);
310- B.createBranch (loc, contBB, {someValue});
311-
312- // In the none case, create a nil executor value, which represents
313- // the generic executor.
314- B.setInsertionPoint (noneBB);
315- SILValue noneValue = B.createOptionalNone (loc, optionalExecutorType);
316- B.createBranch (loc, contBB, {noneValue});
317- B.setInsertionPoint (contBB->begin ());
328+ unmarkedExecutor = getExecutorForOptionalActor (B, loc, actor);
318329 } else {
319- unmarkedExecutor = getExecutorFor (actor);
330+ unmarkedExecutor = getExecutorForActor (B, loc, actor);
331+ }
320332
321- // Inject the result into an optional if requested.
322- if (makeOptional) {
323- unmarkedExecutor = B.createOptionalSome (loc, unmarkedExecutor,
324- SILType::getOptionalType (unmarkedExecutor->getType ()));
325- }
333+ // Inject the result into an optional if requested and if our executor is not
334+ // yet optional.
335+ if (makeOptional && !unmarkedExecutor->getType ().getOptionalObjectType ()) {
336+ unmarkedExecutor = B.createOptionalSome (
337+ loc, unmarkedExecutor,
338+ SILType::getOptionalType (unmarkedExecutor->getType ()));
326339 }
327340
328341 // Mark the dependence of the resulting value on the actor value to
@@ -342,7 +355,7 @@ class LowerHopToActorPass : public SILFunctionTransform {
342355 void run () override {
343356 auto fn = getFunction ();
344357 auto domTree = getAnalysis<DominanceAnalysis>()->get (fn);
345- LowerHopToActor pass (getFunction (), domTree);
358+ LowerHopToActor pass (domTree);
346359 if (pass.run ())
347360 invalidateAnalysis (SILAnalysis::InvalidationKind::BranchesAndInstructions);
348361 }
0 commit comments