Skip to content

Commit e4e9b14

Browse files
authored
Merge pull request #34540 from eeckstein/concurrency
[concurrency] SILGen: emit hop_to_executor instructions
2 parents db58c7e + c5bbe51 commit e4e9b14

File tree

9 files changed

+160
-4
lines changed

9 files changed

+160
-4
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ class ActorIsolation {
149149
}
150150
};
151151

152+
/// Determine how the given value declaration is isolated.
153+
ActorIsolation getActorIsolation(ValueDecl *value);
154+
152155
void simple_display(llvm::raw_ostream &out, const ActorIsolation &state);
153156

154157
} // end namespace swift

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ INTERIOR_POINTER_PROJECTION(RefTailAddr)
168168
CONSTANT_OWNERSHIP_INST(Guaranteed, MustBeLive, OpenExistentialValue)
169169
CONSTANT_OWNERSHIP_INST(Guaranteed, MustBeLive, OpenExistentialBoxValue)
170170
CONSTANT_OWNERSHIP_INST(Guaranteed, MustBeLive, OpenExistentialBox)
171+
CONSTANT_OWNERSHIP_INST(Guaranteed, MustBeLive, HopToExecutor)
171172
CONSTANT_OWNERSHIP_INST(Owned, MustBeInvalidated, AutoreleaseValue)
172173
CONSTANT_OWNERSHIP_INST(Owned, MustBeInvalidated, DeallocBox)
173174
CONSTANT_OWNERSHIP_INST(Owned, MustBeInvalidated, DeallocExistentialBox)
@@ -193,7 +194,6 @@ CONSTANT_OWNERSHIP_INST(None, MustBeLive, EndAccess)
193194
CONSTANT_OWNERSHIP_INST(None, MustBeLive, EndApply)
194195
CONSTANT_OWNERSHIP_INST(None, MustBeLive, EndUnpairedAccess)
195196
CONSTANT_OWNERSHIP_INST(None, MustBeLive, GetAsyncContinuationAddr)
196-
CONSTANT_OWNERSHIP_INST(None, MustBeLive, HopToExecutor)
197197
CONSTANT_OWNERSHIP_INST(None, MustBeLive, IndexAddr)
198198
CONSTANT_OWNERSHIP_INST(None, MustBeLive, IndexRawPointer)
199199
CONSTANT_OWNERSHIP_INST(None, MustBeLive, InitBlockStorageHeader)

lib/SILGen/SILGenApply.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4366,6 +4366,9 @@ RValue SILGenFunction::emitApply(ResultPlanPtr &&resultPlan,
43664366
return rawDirectResults[0];
43674367
}();
43684368

4369+
if (substFnType->isAsync())
4370+
emitHopToCurrentExecutor(loc);
4371+
43694372
// Pop the argument scope.
43704373
argScope.pop();
43714374

lib/SILGen/SILGenFunction.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,12 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
466466
/// The metatype argument to an allocating constructor, if we're emitting one.
467467
SILValue AllocatorMetatype;
468468

469+
/// If set, the current function is an async function which is isolated to
470+
/// this actor.
471+
/// If set, hop_to_executor instructions must be inserted at the begin of the
472+
/// function and after all suspension points.
473+
SILValue actor;
474+
469475
/// True if 'return' without an operand or falling off the end of the current
470476
/// function is valid.
471477
bool allowsVoidReturn() const { return ReturnDest.getBlock()->args_empty(); }
@@ -751,6 +757,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
751757
CanAnyFunctionType outputSubstType,
752758
bool baseLessVisibleThanDerived);
753759

760+
/// If the current function is actor isolated, insert a hop_to_executor
761+
/// instruction.
762+
void emitHopToCurrentExecutor(SILLocation loc);
763+
754764
//===--------------------------------------------------------------------===//
755765
// Control flow
756766
//===--------------------------------------------------------------------===//

lib/SILGen/SILGenPoly.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4480,6 +4480,15 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
44804480
F.verify();
44814481
}
44824482

4483+
//===----------------------------------------------------------------------===//
4484+
// Concurrency
4485+
//===----------------------------------------------------------------------===//
4486+
4487+
void SILGenFunction::emitHopToCurrentExecutor(SILLocation loc) {
4488+
if (actor)
4489+
B.createHopToExecutor(loc, actor);
4490+
}
4491+
44834492
//===----------------------------------------------------------------------===//
44844493
// Protocol witnesses
44854494
//===----------------------------------------------------------------------===//

lib/SILGen/SILGenProlog.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "Initialization.h"
1515
#include "ManagedValue.h"
1616
#include "Scope.h"
17+
#include "ArgumentSource.h"
1718
#include "swift/SIL/SILArgument.h"
1819
#include "swift/AST/CanTypeVisitor.h"
1920
#include "swift/AST/GenericEnvironment.h"
@@ -449,6 +450,48 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
449450
}
450451
}
451452
}
453+
454+
if (auto *funcDecl =
455+
dyn_cast_or_null<AbstractFunctionDecl>(FunctionDC->getAsDecl())) {
456+
auto actorIsolation = getActorIsolation(funcDecl);
457+
switch (actorIsolation.getKind()) {
458+
case ActorIsolation::Unspecified:
459+
case ActorIsolation::Independent:
460+
case ActorIsolation::IndependentUnsafe:
461+
break;
462+
case ActorIsolation::ActorInstance: {
463+
assert(selfParam && "no self parameter for ActorInstance isolation");
464+
ManagedValue selfArg = ManagedValue::forUnmanaged(F.getSelfArgument());
465+
ManagedValue borrowedSelf = selfArg.borrow(*this, F.getLocation());
466+
actor = borrowedSelf.getValue();
467+
break;
468+
}
469+
case ActorIsolation::GlobalActor: {
470+
CanType actorType = CanType(actorIsolation.getGlobalActor());
471+
NominalTypeDecl *nominal = actorType->getNominalOrBoundGenericNominal();
472+
VarDecl *sharedInstanceDecl = nominal->getGlobalActorInstance();
473+
assert(sharedInstanceDecl && "no shared actor field in global actor");
474+
SubstitutionMap subs =
475+
actorType->getContextSubstitutionMap(SGM.SwiftModule, nominal);
476+
SILLocation loc = F.getLocation();
477+
Type instanceType =
478+
actorType->getTypeOfMember(SGM.SwiftModule, sharedInstanceDecl);
479+
480+
ManagedValue actorMetaType =
481+
ManagedValue::forUnmanaged(B.createMetatype(loc,
482+
SILType::getPrimitiveObjectType(
483+
CanMetatypeType::get(actorType, MetatypeRepresentation::Thin))));
484+
485+
RValue actorInstanceRV = emitRValueForStorageLoad(loc, actorMetaType,
486+
actorType, /*isSuper*/ false, sharedInstanceDecl, PreparedArguments(),
487+
subs, AccessSemantics::Ordinary, instanceType, SGFContext());
488+
ManagedValue actorInstance = std::move(actorInstanceRV).getScalarValue();
489+
actor = actorInstance.borrow(*this, loc).getValue();
490+
break;
491+
}
492+
}
493+
}
494+
emitHopToCurrentExecutor(F.getLocation());
452495
}
453496

454497
static void emitIndirectResultParameters(SILGenFunction &SGF, Type resultType,

lib/SILGen/SILGenStmt.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,9 @@ SILGenFunction::getTryApplyErrorDest(SILLocation loc,
12221222
assert(B.hasValidInsertionPoint() && B.insertingAtEndOfBlock());
12231223
SILGenSavedInsertionPoint savedIP(*this, destBB, FunctionSection::Postmatter);
12241224

1225+
if (fnTy->isAsync())
1226+
emitHopToCurrentExecutor(loc);
1227+
12251228
// If we're suppressing error paths, just wrap it up as unreachable
12261229
// and return.
12271230
if (suppressErrorPath) {

lib/Sema/TypeCheckConcurrency.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@ void addAsyncNotes(FuncDecl *func);
4040
/// Check actor isolation rules.
4141
void checkActorIsolation(const Expr *expr, const DeclContext *dc);
4242

43-
/// Determine how the given value declaration is isolated.
44-
ActorIsolation getActorIsolation(ValueDecl *value);
45-
4643
/// The isolation restriction in effect for a given declaration that is
4744
/// referenced from source.
4845
class ActorIsolationRestriction {

test/SILGen/hop_to_executor.swift

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s -module-name test -swift-version 5 -enable-experimental-concurrency | %FileCheck %s
2+
// REQUIRES: concurrency
3+
4+
5+
actor class MyActor {
6+
7+
private var p: Int
8+
9+
// CHECK-LABEL: sil hidden [ossa] @$s4test7MyActorC6calleeyySiYF : $@convention(method) @async (Int, @guaranteed MyActor) -> () {
10+
// CHECK-NOT: hop_to_executor
11+
// CHECK: } // end sil function '$s4test7MyActorC6calleeyySiYF'
12+
@actorIndependent
13+
func callee(_ x: Int) async {
14+
print(x)
15+
}
16+
17+
// CHECK-LABEL: sil hidden [ossa] @$s4test7MyActorC14throwingCalleeyySiYKF : $@convention(method) @async (Int, @guaranteed MyActor) -> @error Error {
18+
// CHECK-NOT: hop_to_executor
19+
// CHECK: } // end sil function '$s4test7MyActorC14throwingCalleeyySiYKF'
20+
@actorIndependent
21+
func throwingCallee(_ x: Int) async throws {
22+
print(x)
23+
}
24+
25+
// CHECK-LABEL: sil hidden [ossa] @$s4test7MyActorC0A13AsyncFunctionyyYKF : $@convention(method) @async (@guaranteed MyActor) -> @error Error {
26+
// CHECK: hop_to_executor %0 : $MyActor
27+
// CHECK: = apply {{.*}} : $@convention(method) @async (Int, @guaranteed MyActor) -> ()
28+
// CHECK-NEXT: hop_to_executor %0 : $MyActor
29+
// CHECK: try_apply {{.*}}, normal bb1, error bb2
30+
// CHECK: bb1({{.*}}):
31+
// CHECK-NEXT: hop_to_executor %0 : $MyActor
32+
// CHECK: bb2({{.*}}):
33+
// CHECK-NEXT: hop_to_executor %0 : $MyActor
34+
// CHECK: } // end sil function '$s4test7MyActorC0A13AsyncFunctionyyYKF'
35+
func testAsyncFunction() async throws {
36+
await callee(p)
37+
try await throwingCallee(p)
38+
}
39+
40+
// CHECK-LABEL: sil hidden [ossa] @$s4test7MyActorC0A22ConsumingAsyncFunctionyyYF : $@convention(method) @async (@owned MyActor) -> () {
41+
// CHECK: [[BORROWED_SELF:%[0-9]+]] = begin_borrow %0 : $MyActor
42+
// CHECK: hop_to_executor [[BORROWED_SELF]] : $MyActor
43+
// CHECK: = apply {{.*}} : $@convention(method) @async (Int, @guaranteed MyActor) -> ()
44+
// CHECK-NEXT: hop_to_executor [[BORROWED_SELF]] : $MyActor
45+
// CHECK: } // end sil function '$s4test7MyActorC0A22ConsumingAsyncFunctionyyYF'
46+
__consuming func testConsumingAsyncFunction() async {
47+
await callee(p)
48+
}
49+
50+
init() {
51+
p = 27
52+
}
53+
}
54+
55+
@globalActor
56+
struct GlobalActor {
57+
static var shared: MyActor = MyActor()
58+
}
59+
60+
// CHECK-LABEL: sil hidden [ossa] @$s4test0A11GlobalActoryyYF : $@convention(thin) () -> () {
61+
// CHECK: [[F:%[0-9]+]] = function_ref @$s4test11GlobalActorV6sharedAA02MyC0Cvau : $@convention(thin) () -> Builtin.RawPointer
62+
// CHECK: [[P:%[0-9]+]] = apply [[F]]() : $@convention(thin) () -> Builtin.RawPointer
63+
// CHECK: [[A:%[0-9]+]] = pointer_to_address %2 : $Builtin.RawPointer to [strict] $*MyActor
64+
// CHECK: [[ACC:%[0-9]+]] = begin_access [read] [dynamic] [[A]] : $*MyActor
65+
// CHECK: [[L:%[0-9]+]] = load [copy] [[ACC]] : $*MyActor
66+
// CHECK: [[B:%[0-9]+]] = begin_borrow [[L]] : $MyActor
67+
// CHECK: hop_to_executor [[B]] : $MyActor
68+
// CHECK: } // end sil function '$s4test0A11GlobalActoryyYF'
69+
@GlobalActor
70+
func testGlobalActor() async {
71+
}
72+
73+
@globalActor
74+
struct GenericGlobalActorWithGetter<T> {
75+
static var shared: MyActor { return MyActor() }
76+
}
77+
78+
// CHECK-LABEL: sil hidden [ossa] @$s4test0A28GenericGlobalActorWithGetteryyYF : $@convention(thin) () -> () {
79+
// CHECK: [[MT:%[0-9]+]] = metatype $@thin GenericGlobalActorWithGetter<Int>.Type
80+
// CHECK: [[F:%[0-9]+]] = function_ref @$s4test28GenericGlobalActorWithGetterV6sharedAA02MyD0CvgZ : $@convention(method) <τ_0_0> (@thin GenericGlobalActorWithGetter<τ_0_0>.Type) -> @owned MyActor
81+
// CHECK: [[A:%[0-9]+]] = apply [[F]]<Int>([[MT]]) : $@convention(method) <τ_0_0> (@thin GenericGlobalActorWithGetter<τ_0_0>.Type) -> @owned MyActor
82+
// CHECK: [[B:%[0-9]+]] = begin_borrow [[A]] : $MyActor
83+
// CHECK: hop_to_executor [[B]] : $MyActor
84+
// CHECK: } // end sil function '$s4test0A28GenericGlobalActorWithGetteryyYF'
85+
@GenericGlobalActorWithGetter<Int>
86+
func testGenericGlobalActorWithGetter() async {
87+
}
88+

0 commit comments

Comments
 (0)