Skip to content

Commit e308865

Browse files
authored
Merge pull request #34393 from eeckstein/concurrency
[Concurrency] SIL: add hop_to_executor instruction
2 parents 2dff04b + f18a9b8 commit e308865

File tree

18 files changed

+146
-1
lines changed

18 files changed

+146
-1
lines changed

docs/SIL.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2885,6 +2885,27 @@ initialized with the resume value, and that value is then owned by the current
28852885
function. If ``await_async_continuation`` instead resumes to its ``error``
28862886
successor, then the memory remains uninitialized.
28872887

2888+
hop_to_executor
2889+
```````````````
2890+
2891+
::
2892+
2893+
sil-instruction ::= 'hop_to_executor' sil-operand
2894+
2895+
hop_to_executor %0 : $T
2896+
2897+
// $T must conform to the Actor protocol
2898+
2899+
Ensures that all instructions, which need to run on the actor's executor
2900+
actually run on that executor.
2901+
This instruction can only be used inside an ``@async`` function.
2902+
2903+
Checks if the current executor is the one which is bound to the operand actor.
2904+
If not, begins a suspension point and enqueues the continuation to the executor
2905+
which is bound to the operand actor.
2906+
2907+
The operand is a guaranteed operand, i.e. not consumed.
2908+
28882909
dealloc_stack
28892910
`````````````
28902911
::

include/swift/SIL/SILBuilder.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1935,6 +1935,10 @@ class SILBuilder {
19351935
getSILDebugLocation(Loc), Operand, Index));
19361936
}
19371937

1938+
//===--------------------------------------------------------------------===//
1939+
// Concurrency instructions
1940+
//===--------------------------------------------------------------------===//
1941+
19381942
GetAsyncContinuationInst *createGetAsyncContinuation(SILLocation Loc,
19391943
SILType ContinuationTy) {
19401944
return insert(new (getModule()) GetAsyncContinuationInst(getSILDebugLocation(Loc),
@@ -1949,6 +1953,11 @@ class SILBuilder {
19491953
ContinuationTy));
19501954
}
19511955

1956+
HopToExecutorInst *createHopToExecutor(SILLocation Loc, SILValue Actor) {
1957+
return insert(new (getModule()) HopToExecutorInst(getSILDebugLocation(Loc),
1958+
Actor, hasOwnership()));
1959+
}
1960+
19521961
//===--------------------------------------------------------------------===//
19531962
// Terminator SILInstruction Creation Methods
19541963
//===--------------------------------------------------------------------===//

include/swift/SIL/SILCloner.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2964,6 +2964,17 @@ ::visitAwaitAsyncContinuationInst(AwaitAsyncContinuationInst *Inst) {
29642964
: nullptr));
29652965
}
29662966

2967+
template <typename ImplClass>
2968+
void SILCloner<ImplClass>
2969+
::visitHopToExecutorInst(HopToExecutorInst *Inst) {
2970+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
2971+
recordClonedInstruction(Inst,
2972+
getBuilder().createHopToExecutor(
2973+
getOpLocation(Inst->getLoc()),
2974+
getOpValue(Inst->getActor())));
2975+
}
2976+
2977+
29672978
} // end namespace swift
29682979

29692980
#endif

include/swift/SIL/SILInstruction.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3102,6 +3102,21 @@ class GetAsyncContinuationAddrInst final
31023102
{}
31033103
};
31043104

3105+
/// Begins a suspension point and enqueues the continuation to the executor
3106+
/// which is bound to the operand actor.
3107+
class HopToExecutorInst
3108+
: public UnaryInstructionBase<SILInstructionKind::HopToExecutorInst,
3109+
NonValueInstruction>
3110+
{
3111+
friend SILBuilder;
3112+
3113+
HopToExecutorInst(SILDebugLocation DebugLoc, SILValue Actor, bool HasOwnership)
3114+
: UnaryInstructionBase(DebugLoc, Actor) { }
3115+
3116+
public:
3117+
SILValue getActor() const { return getOperand(); }
3118+
};
3119+
31053120
/// Instantiates a key path object.
31063121
class KeyPathInst final
31073122
: public InstructionBase<SILInstructionKind::KeyPathInst,

include/swift/SIL/SILNodes.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,9 @@ NON_VALUE_INST(BindMemoryInst, bind_memory,
834834
NON_VALUE_INST(FixLifetimeInst, fix_lifetime,
835835
SILInstruction, MayHaveSideEffects, DoesNotRelease)
836836

837+
NON_VALUE_INST(HopToExecutorInst, hop_to_executor,
838+
SILInstruction, MayHaveSideEffects, DoesNotRelease)
839+
837840
NON_VALUE_INST(DestroyValueInst, destroy_value,
838841
SILInstruction, MayHaveSideEffects, MayRelease)
839842
NON_VALUE_INST(EndBorrowInst, end_borrow,

lib/IRGen/IRGenSIL.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,10 @@ class IRGenSILFunction :
11361136
llvm_unreachable("not implemented");
11371137
}
11381138

1139+
void visitHopToExecutorInst(HopToExecutorInst *i) {
1140+
//TODO(async)
1141+
}
1142+
11391143
void visitKeyPathInst(KeyPathInst *I);
11401144

11411145
void visitDifferentiableFunctionInst(DifferentiableFunctionInst *i);

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ CONSTANT_OWNERSHIP_INST(None, MustBeLive, EndAccess)
193193
CONSTANT_OWNERSHIP_INST(None, MustBeLive, EndApply)
194194
CONSTANT_OWNERSHIP_INST(None, MustBeLive, EndUnpairedAccess)
195195
CONSTANT_OWNERSHIP_INST(None, MustBeLive, GetAsyncContinuationAddr)
196+
CONSTANT_OWNERSHIP_INST(None, MustBeLive, HopToExecutor)
196197
CONSTANT_OWNERSHIP_INST(None, MustBeLive, IndexAddr)
197198
CONSTANT_OWNERSHIP_INST(None, MustBeLive, IndexRawPointer)
198199
CONSTANT_OWNERSHIP_INST(None, MustBeLive, InitBlockStorageHeader)

lib/SIL/IR/SILPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,6 +2096,10 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
20962096
}
20972097
}
20982098

2099+
void visitHopToExecutorInst(HopToExecutorInst *HTEI) {
2100+
*this << getIDAndType(HTEI->getActor());
2101+
}
2102+
20992103
void visitSwitchValueInst(SwitchValueInst *SII) {
21002104
*this << getIDAndType(SII->getOperand());
21012105
for (unsigned i = 0, e = SII->getNumCases(); i < e; ++i) {

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2951,6 +2951,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
29512951
UNARY_INSTRUCTION(EndBorrow)
29522952
UNARY_INSTRUCTION(DestructureStruct)
29532953
UNARY_INSTRUCTION(DestructureTuple)
2954+
UNARY_INSTRUCTION(HopToExecutor)
29542955
REFCOUNTING_INSTRUCTION(UnmanagedReleaseValue)
29552956
REFCOUNTING_INSTRUCTION(UnmanagedRetainValue)
29562957
REFCOUNTING_INSTRUCTION(UnmanagedAutoreleaseValue)

lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ static bool hasOpaqueArchetype(TypeExpansionContext context,
339339
case SILInstructionKind::GetAsyncContinuationInst:
340340
case SILInstructionKind::GetAsyncContinuationAddrInst:
341341
case SILInstructionKind::AwaitAsyncContinuationInst:
342+
case SILInstructionKind::HopToExecutorInst:
342343
// Handle by operand and result check.
343344
break;
344345

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
895895
case SILInstructionKind::LinearFunctionExtractInst:
896896
case SILInstructionKind::DifferentiabilityWitnessFunctionInst:
897897
case SILInstructionKind::AwaitAsyncContinuationInst:
898+
case SILInstructionKind::HopToExecutorInst:
898899
#define COMMON_ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name) \
899900
case SILInstructionKind::Name##ToRefInst: \
900901
case SILInstructionKind::RefTo##Name##Inst: \

lib/Serialization/DeserializeSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,6 +1863,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
18631863
UNARY_INSTRUCTION(IsUnique)
18641864
UNARY_INSTRUCTION(AbortApply)
18651865
UNARY_INSTRUCTION(EndApply)
1866+
UNARY_INSTRUCTION(HopToExecutor)
18661867
#undef UNARY_INSTRUCTION
18671868
#undef REFCOUNTING_INSTRUCTION
18681869

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5656
/// describe what change you made. The content of this comment isn't important;
5757
/// it just ensures a conflict if two people change the module format.
5858
/// Don't worry about adhering to the 80-column limit for this line.
59-
const uint16_t SWIFTMODULE_VERSION_MINOR = 584; // builtin protocol conformances
59+
const uint16_t SWIFTMODULE_VERSION_MINOR = 585; // hop_to_executor instruction
6060

6161
/// A standard hash seed used for all string hashes in a serialized module.
6262
///

lib/Serialization/SerializeSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,6 +1349,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
13491349
case SILInstructionKind::IsUniqueInst:
13501350
case SILInstructionKind::BeginCOWMutationInst:
13511351
case SILInstructionKind::EndCOWMutationInst:
1352+
case SILInstructionKind::HopToExecutorInst:
13521353
case SILInstructionKind::AbortApplyInst:
13531354
case SILInstructionKind::EndApplyInst:
13541355
case SILInstructionKind::ReturnInst:

test/SIL/Parser/concurrency.sil

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-sil-opt -enable-objc-interop -enable-experimental-concurrency -enable-sil-verify-all=true %s | %target-sil-opt -enable-objc-interop -enable-experimental-concurrency -enable-sil-verify-all=true | %FileCheck %s
2+
// REQUIRES: concurrency
3+
4+
sil_stage raw // CHECK: sil_stage raw
5+
6+
import Builtin
7+
import Swift
8+
9+
actor class Actor { }
10+
11+
// CHECK-LABEL: sil @test_hop_to_executor
12+
sil @test_hop_to_executor : $@convention(thin) (@guaranteed Actor) -> () {
13+
bb0(%0 : $Actor):
14+
// CHECK: hop_to_executor %0 : $Actor
15+
hop_to_executor %0 : $Actor
16+
%2 = tuple ()
17+
return %2 : $()
18+
}
19+
20+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
sil_stage raw // CHECK: sil_stage canonical
2+
3+
import Builtin
4+
import Swift
5+
6+
actor class Act { }
7+
8+
@_transparent public func serialize_all() {
9+
}
10+
11+
// CHECK-LABEL: sil public_external [transparent] [serialized] @test_hop_to_executor
12+
sil [transparent] [serialized] @test_hop_to_executor : $@convention(thin) (@guaranteed Act) -> () {
13+
bb0(%0 : $Act):
14+
// CHECK: hop_to_executor %0 : $Act
15+
hop_to_executor %0 : $Act
16+
%2 = tuple ()
17+
return %2 : $()
18+
}
19+
20+
sil [transparent] [serialized] @$s15def_concurrency13serialize_allyyF : $@convention(thin) () -> () {
21+
bb0:
22+
%91 = function_ref @test_hop_to_executor : $@convention(thin) (@guaranteed Act) -> ()
23+
24+
%r = tuple ()
25+
return %r : $()
26+
}
27+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -emit-module -Xfrontend -enable-experimental-concurrency -Xfrontend -disable-diagnostic-passes -whole-module-optimization -Xfrontend -enable-objc-interop -o %t/def_concurrency.swiftmodule %S/Inputs/def_concurrency.sil
3+
// RUN: llvm-bcanalyzer %t/def_concurrency.swiftmodule | %FileCheck %s
4+
// RUN: %target-build-swift -emit-sil -I %t %s -o %t/concurrency_sil.sil
5+
// RUN: %target-sil-opt -I %t %t/concurrency_sil.sil -performance-linker | %FileCheck %S/Inputs/def_concurrency.sil
6+
7+
// This test currently is written such that no optimizations are assumed.
8+
// REQUIRES: swift_test_mode_optimize_none
9+
// REQUIRES: concurrency
10+
11+
// CHECK-NOT: UnknownCode
12+
13+
import def_concurrency
14+
15+
func test_all() {
16+
serialize_all()
17+
}

tools/sil-opt/SILOpt.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ static llvm::cl::opt<bool>
9999
DisableObjCInterop("disable-objc-interop",
100100
llvm::cl::desc("Disable Objective-C interoperability."));
101101

102+
static llvm::cl::opt<bool>
103+
EnableExperimentalConcurrency("enable-experimental-concurrency",
104+
llvm::cl::desc("Enable experimental concurrency model."));
105+
102106
static llvm::cl::opt<bool>
103107
VerifyExclusivity("enable-verify-exclusivity",
104108
llvm::cl::desc("Verify the access markers used to enforce exclusivity."));
@@ -341,6 +345,10 @@ int main(int argc, char **argv) {
341345
Invocation.getLangOptions().DisableAvailabilityChecking = true;
342346
Invocation.getLangOptions().EnableAccessControl = false;
343347
Invocation.getLangOptions().EnableObjCAttrRequiresFoundation = false;
348+
349+
Invocation.getLangOptions().EnableExperimentalConcurrency =
350+
EnableExperimentalConcurrency;
351+
344352
Invocation.getLangOptions().EnableObjCInterop =
345353
EnableObjCInterop ? true :
346354
DisableObjCInterop ? false : llvm::Triple(Target).isOSDarwin();

0 commit comments

Comments
 (0)