Skip to content

Commit 14350f8

Browse files
authored
Merge pull request #34876 from eeckstein/silgen-async-handler
[concurrency] SILGen: emit @asyncHandler functions.
2 parents d01aa21 + 8e03bd3 commit 14350f8

File tree

12 files changed

+175
-24
lines changed

12 files changed

+175
-24
lines changed

include/swift/AST/ASTMangler.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class ASTMangler : public Mangler {
7777
public:
7878
enum class SymbolKind {
7979
Default,
80+
AsyncHandlerBody,
8081
DynamicThunk,
8182
SwiftAsObjCThunk,
8283
ObjCAsSwiftThunk,
@@ -323,16 +324,24 @@ class ASTMangler : public Mangler {
323324

324325
void appendAnyGenericType(const GenericTypeDecl *decl);
325326

326-
void appendFunction(AnyFunctionType *fn, bool isFunctionMangling = false,
327-
const ValueDecl *forDecl = nullptr);
327+
enum FunctionManglingKind {
328+
NoFunctionMangling,
329+
FunctionMangling,
330+
AsyncHandlerBodyMangling
331+
};
332+
333+
void appendFunction(AnyFunctionType *fn,
334+
FunctionManglingKind functionMangling = NoFunctionMangling,
335+
const ValueDecl *forDecl = nullptr);
328336
void appendFunctionType(AnyFunctionType *fn, bool isAutoClosure = false,
329337
const ValueDecl *forDecl = nullptr);
330338
void appendClangType(AnyFunctionType *fn);
331339
template <typename FnType>
332340
void appendClangType(FnType *fn, llvm::raw_svector_ostream &os);
333341

334342
void appendFunctionSignature(AnyFunctionType *fn,
335-
const ValueDecl *forDecl = nullptr);
343+
const ValueDecl *forDecl,
344+
FunctionManglingKind functionMangling);
336345

337346
void appendFunctionInputType(ArrayRef<AnyFunctionType::Param> params,
338347
const ValueDecl *forDecl = nullptr);
@@ -383,7 +392,10 @@ class ASTMangler : public Mangler {
383392
GenericSignature &genericSig,
384393
GenericSignature &parentGenericSig);
385394

386-
void appendDeclType(const ValueDecl *decl, bool isFunctionMangling = false);
395+
396+
397+
void appendDeclType(const ValueDecl *decl,
398+
FunctionManglingKind functionMangling = NoFunctionMangling);
387399

388400
bool tryAppendStandardSubstitution(const GenericTypeDecl *type);
389401

@@ -400,7 +412,7 @@ class ASTMangler : public Mangler {
400412

401413
void appendEntity(const ValueDecl *decl, StringRef EntityOp, bool isStatic);
402414

403-
void appendEntity(const ValueDecl *decl);
415+
void appendEntity(const ValueDecl *decl, bool isAsyncHandlerBody = false);
404416

405417
void appendProtocolConformance(const ProtocolConformance *conformance);
406418
void appendProtocolConformanceRef(const RootProtocolConformance *conformance);

include/swift/AST/ExtInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,10 @@ class SILExtInfo {
828828
return builder.withNoEscape(noEscape).build();
829829
}
830830

831+
SILExtInfo withAsync(bool isAsync = true) const {
832+
return builder.withAsync(isAsync).build();
833+
}
834+
831835
bool isEqualTo(SILExtInfo other, bool useClangTypes) const {
832836
return builder.isEqualTo(other.builder, useClangTypes);
833837
}

include/swift/SIL/SILDeclRef.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ struct SILDeclRef {
221221
enum class ManglingKind {
222222
Default,
223223
DynamicThunk,
224+
AsyncHandlerBody
224225
};
225226

226227
/// Produce a mangled form of this constant.

lib/AST/ASTMangler.cpp

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ std::string ASTMangler::mangleClosureEntity(const AbstractClosureExpr *closure,
8888

8989
std::string ASTMangler::mangleEntity(const ValueDecl *decl, SymbolKind SKind) {
9090
beginMangling();
91-
appendEntity(decl);
91+
appendEntity(decl, SKind == SymbolKind::AsyncHandlerBody);
9292
appendSymbolKind(SKind);
9393
return finalize();
9494
}
@@ -657,7 +657,7 @@ std::string ASTMangler::mangleTypeAsUSR(Type Ty) {
657657
Ty = getTypeForDWARFMangling(Ty);
658658

659659
if (auto *fnType = Ty->getAs<AnyFunctionType>()) {
660-
appendFunction(fnType, false);
660+
appendFunction(fnType);
661661
} else {
662662
appendType(Ty);
663663
}
@@ -744,6 +744,7 @@ std::string ASTMangler::mangleOpaqueTypeDecl(const ValueDecl *decl) {
744744
void ASTMangler::appendSymbolKind(SymbolKind SKind) {
745745
switch (SKind) {
746746
case SymbolKind::Default: return;
747+
case SymbolKind::AsyncHandlerBody: return;
747748
case SymbolKind::DynamicThunk: return appendOperator("TD");
748749
case SymbolKind::SwiftAsObjCThunk: return appendOperator("To");
749750
case SymbolKind::ObjCAsSwiftThunk: return appendOperator("TO");
@@ -2249,7 +2250,8 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) {
22492250
addSubstitution(cast<TypeAliasDecl>(decl));
22502251
}
22512252

2252-
void ASTMangler::appendFunction(AnyFunctionType *fn, bool isFunctionMangling,
2253+
void ASTMangler::appendFunction(AnyFunctionType *fn,
2254+
FunctionManglingKind functionMangling,
22532255
const ValueDecl *forDecl) {
22542256
// Append parameter labels right before the signature/type.
22552257
auto parameters = fn->getParams();
@@ -2269,8 +2271,8 @@ void ASTMangler::appendFunction(AnyFunctionType *fn, bool isFunctionMangling,
22692271
appendOperator("y");
22702272
}
22712273

2272-
if (isFunctionMangling) {
2273-
appendFunctionSignature(fn, forDecl);
2274+
if (functionMangling != NoFunctionMangling) {
2275+
appendFunctionSignature(fn, forDecl, functionMangling);
22742276
} else {
22752277
appendFunctionType(fn, /*autoclosure*/ false, forDecl);
22762278
}
@@ -2281,7 +2283,7 @@ void ASTMangler::appendFunctionType(AnyFunctionType *fn, bool isAutoClosure,
22812283
assert((DWARFMangling || fn->isCanonical()) &&
22822284
"expecting canonical types when not mangling for the debugger");
22832285

2284-
appendFunctionSignature(fn, forDecl);
2286+
appendFunctionSignature(fn, forDecl, NoFunctionMangling);
22852287

22862288
bool mangleClangType = fn->getASTContext().LangOpts.UseClangFunctionTypes &&
22872289
fn->hasNonDerivableClangType();
@@ -2359,10 +2361,11 @@ void ASTMangler::appendClangType(AnyFunctionType *fn) {
23592361
}
23602362

23612363
void ASTMangler::appendFunctionSignature(AnyFunctionType *fn,
2362-
const ValueDecl *forDecl) {
2364+
const ValueDecl *forDecl,
2365+
FunctionManglingKind functionMangling) {
23632366
appendFunctionResultType(fn->getResult(), forDecl);
23642367
appendFunctionInputType(fn->getParams(), forDecl);
2365-
if (fn->isAsync())
2368+
if (fn->isAsync() || functionMangling == AsyncHandlerBodyMangling)
23662369
appendOperator("Y");
23672370
if (fn->isThrowing())
23682371
appendOperator("K");
@@ -2780,22 +2783,23 @@ CanType ASTMangler::getDeclTypeForMangling(
27802783
return canTy;
27812784
}
27822785

2783-
void ASTMangler::appendDeclType(const ValueDecl *decl, bool isFunctionMangling) {
2786+
void ASTMangler::appendDeclType(const ValueDecl *decl,
2787+
FunctionManglingKind functionMangling) {
27842788
Mod = decl->getModuleContext();
27852789
GenericSignature genericSig;
27862790
GenericSignature parentGenericSig;
27872791
auto type = getDeclTypeForMangling(decl, genericSig, parentGenericSig);
27882792

27892793
if (AnyFunctionType *FuncTy = type->getAs<AnyFunctionType>()) {
2790-
appendFunction(FuncTy, isFunctionMangling, decl);
2794+
appendFunction(FuncTy, functionMangling, decl);
27912795
} else {
27922796
appendType(type, decl);
27932797
}
27942798

27952799
// Mangle the generic signature, if any.
27962800
if (genericSig && appendGenericSignature(genericSig, parentGenericSig)) {
27972801
// The 'F' function mangling doesn't need a 'u' for its generic signature.
2798-
if (!isFunctionMangling)
2802+
if (functionMangling == NoFunctionMangling)
27992803
appendOperator("u");
28002804
}
28012805
}
@@ -2870,7 +2874,7 @@ void ASTMangler::appendEntity(const ValueDecl *decl, StringRef EntityOp,
28702874
appendOperator("Z");
28712875
}
28722876

2873-
void ASTMangler::appendEntity(const ValueDecl *decl) {
2877+
void ASTMangler::appendEntity(const ValueDecl *decl, bool isAsyncHandlerBody) {
28742878
assert(!isa<ConstructorDecl>(decl));
28752879
assert(!isa<DestructorDecl>(decl));
28762880

@@ -2891,7 +2895,8 @@ void ASTMangler::appendEntity(const ValueDecl *decl) {
28912895

28922896
appendContextOf(decl);
28932897
appendDeclName(decl);
2894-
appendDeclType(decl, /*isFunctionMangling*/ true);
2898+
appendDeclType(decl, isAsyncHandlerBody ? AsyncHandlerBodyMangling
2899+
: FunctionMangling);
28952900
appendOperator("F");
28962901
if (decl->isStatic())
28972902
appendOperator("Z");

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,9 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
764764
case SILDeclRef::ManglingKind::DynamicThunk:
765765
SKind = ASTMangler::SymbolKind::DynamicThunk;
766766
break;
767+
case SILDeclRef::ManglingKind::AsyncHandlerBody:
768+
SKind = ASTMangler::SymbolKind::AsyncHandlerBody;
769+
break;
767770
}
768771

769772
switch (kind) {

lib/SILGen/SILGen.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,11 @@ SILGenModule::getResumeUnsafeThrowingContinuationWithError() {
393393
ResumeUnsafeThrowingContinuationWithError,
394394
"_resumeUnsafeThrowingContinuationWithError");
395395
}
396+
FuncDecl *
397+
SILGenModule::getRunAsyncHandler() {
398+
return lookupConcurrencyIntrinsic(getASTContext(), RunAsyncHandler,
399+
"_runAsyncHandler");
400+
}
396401

397402
ProtocolConformance *SILGenModule::getNSErrorConformanceToError() {
398403
if (NSErrorConformanceToError)

lib/SILGen/SILGen.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
126126
Optional<FuncDecl*> ResumeUnsafeContinuation;
127127
Optional<FuncDecl*> ResumeUnsafeThrowingContinuation;
128128
Optional<FuncDecl*> ResumeUnsafeThrowingContinuationWithError;
129+
Optional<FuncDecl*> RunAsyncHandler;
129130

130131
public:
131132
SILGenModule(SILModule &M, ModuleDecl *SM);
@@ -492,6 +493,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
492493
FuncDecl *getResumeUnsafeThrowingContinuation();
493494
/// Retrieve the _Concurrency._resumeUnsafeThrowingContinuationWithError intrinsic.
494495
FuncDecl *getResumeUnsafeThrowingContinuationWithError();
496+
/// Retrieve the _Concurrency._runAsyncHandler intrinsic.
497+
FuncDecl *getRunAsyncHandler();
495498

496499
SILFunction *getKeyPathProjectionCoroutine(bool isReadAccess,
497500
KeyPathTypeKind typeKind);

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1439,7 +1439,7 @@ static ManagedValue emitBuiltinCreateAsyncTaskFuture(
14391439
// Form the metatype of the result type.
14401440
CanType futureResultType =
14411441
Type(
1442-
MetatypeType::get(GenericTypeParamType::get(0, 0, SGF.getASTContext())))
1442+
MetatypeType::get(GenericTypeParamType::get(0, 0, SGF.getASTContext()), MetatypeRepresentation::Thick))
14431443
.subst(subs)->getCanonicalType();
14441444
CanType anyTypeType = ExistentialMetatypeType::get(
14451445
ProtocolCompositionType::get(ctx, { }, false))->getCanonicalType();

lib/SILGen/SILGenFunction.cpp

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -517,11 +517,11 @@ void SILGenFunction::emitFunction(FuncDecl *fd) {
517517
fd->getResultInterfaceType(), fd->hasThrows(), fd->getThrowsLoc());
518518
prepareEpilog(true, fd->hasThrows(), CleanupLocation(fd));
519519

520-
if (fd->isAsyncHandler()) {
521-
// Async handlers are need to have their bodies emitted into a
522-
// detached task.
523-
// FIXME: Actually implement these properly.
524-
B.createBuiltinTrap(fd->getTypecheckedBody());
520+
if (fd->isAsyncHandler() &&
521+
// If F.isAsync() we are emitting the asyncHandler body and not the
522+
// original asyncHandler.
523+
!F.isAsync()) {
524+
emitAsyncHandler(fd);
525525
} else {
526526
emitStmt(fd->getTypecheckedBody());
527527
}
@@ -531,6 +531,58 @@ void SILGenFunction::emitFunction(FuncDecl *fd) {
531531
mergeCleanupBlocks();
532532
}
533533

534+
/// An asyncHandler function is split into two functions:
535+
/// 1. The asyncHandler body function: it contains the body of the function, but
536+
/// is emitted as an async function.
537+
/// 2. The original function: it just contains
538+
/// _runAsyncHandler(operation: asyncHandlerBodyFunction)
539+
void SILGenFunction::emitAsyncHandler(FuncDecl *fd) {
540+
541+
// 1. step: create the asyncHandler body function
542+
//
543+
auto origFnTy = F.getLoweredFunctionType();
544+
assert(!F.isAsync() && "an asyncHandler function cannot be async");
545+
546+
// The body function type is the same as the original type, just with "async".
547+
auto bodyFnTy = origFnTy->getWithExtInfo(origFnTy->getExtInfo().withAsync());
548+
549+
SILDeclRef constant(fd, SILDeclRef::Kind::Func);
550+
std::string name = constant.mangle(SILDeclRef::ManglingKind::AsyncHandlerBody);
551+
SILLocation loc = F.getLocation();
552+
SILGenFunctionBuilder builder(*this);
553+
554+
SILFunction *bodyFn = builder.createFunction(
555+
SILLinkage::Hidden, name, bodyFnTy, F.getGenericEnvironment(),
556+
loc, F.isBare(), F.isTransparent(),
557+
F.isSerialized(), IsNotDynamic, ProfileCounter(), IsNotThunk,
558+
F.getClassSubclassScope(), F.getInlineStrategy(), F.getEffectsKind());
559+
bodyFn->setDebugScope(new (getModule()) SILDebugScope(loc, bodyFn));
560+
561+
SILGenFunction(SGM, *bodyFn, fd).emitFunction(fd);
562+
563+
// 2. step: emit the original asyncHandler function
564+
//
565+
Scope scope(*this, loc);
566+
567+
// %bodyFnRef = partial_apply %bodyFn(%originalArg0, %originalArg1, ...)
568+
//
569+
SmallVector<ManagedValue, 4> managedArgs;
570+
for (SILValue arg : F.getArguments()) {
571+
ManagedValue argVal = ManagedValue(arg, CleanupHandle::invalid());
572+
managedArgs.push_back(argVal.copy(*this, loc));
573+
}
574+
auto *bodyFnRef = B.createFunctionRef(loc, bodyFn);
575+
ManagedValue bodyFnValue =
576+
B.createPartialApply(loc, bodyFnRef, F.getForwardingSubstitutionMap(),
577+
managedArgs, ParameterConvention::Direct_Guaranteed);
578+
579+
// apply %_runAsyncHandler(%bodyFnValue)
580+
//
581+
FuncDecl *asyncHandlerDecl = SGM.getRunAsyncHandler();
582+
emitApplyOfLibraryIntrinsic(loc, asyncHandlerDecl, SubstitutionMap(),
583+
{ bodyFnValue }, SGFContext());
584+
}
585+
534586
void SILGenFunction::emitClosure(AbstractClosureExpr *ace) {
535587
MagicFunctionName = SILGenModule::getMagicFunctionName(ace);
536588

lib/SILGen/SILGenFunction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
623623

624624
/// Generates code for a FuncDecl.
625625
void emitFunction(FuncDecl *fd);
626+
/// Generate code for @asyncHandler functions.
627+
void emitAsyncHandler(FuncDecl *fd);
626628
/// Emits code for a ClosureExpr.
627629
void emitClosure(AbstractClosureExpr *ce);
628630
/// Generates code for a class destroying destructor. This

stdlib/public/Concurrency/Task.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,11 @@ extension Task {
310310

311311
return Handle<T>(task: task)
312312
}
313+
314+
}
315+
316+
public func _runAsyncHandler(operation: @escaping () async -> ()) {
317+
_ = Task.runDetached(operation: operation)
313318
}
314319

315320
// ==== Voluntary Suspension -----------------------------------------------------

test/SILGen/async_handler.swift

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s -module-name test -swift-version 5 -enable-experimental-concurrency | %FileCheck %s
2+
// REQUIRES: concurrency
3+
4+
func take<T>(_ t: T) async {
5+
print(t)
6+
}
7+
8+
// CHECK-LABEL: sil [ossa] @$s4test13simpleHandleryySiF : $@convention(thin) (Int) -> () {
9+
// CHECK: [[BODYFN:%[0-9]+]] = function_ref @$s4test13simpleHandleryySiYF : $@convention(thin) @async (Int) -> ()
10+
// CHECK: [[FN:%[0-9]+]] = partial_apply [callee_guaranteed] [[BODYFN]](%0) : $@convention(thin) @async (Int) -> ()
11+
// CHECK: [[INTRINSIC:%[0-9]+]] = function_ref @$s12_Concurrency16_runAsyncHandler9operationyyyYc_tF : $@convention(thin) (@guaranteed @async @callee_guaranteed () -> ()) -> ()
12+
// CHECK: {{.*}} = apply [[INTRINSIC]]([[FN]]) : $@convention(thin) (@guaranteed @async @callee_guaranteed () -> ()) -> ()
13+
// CHECK: destroy_value [[FN]] : $@async @callee_guaranteed () -> ()
14+
// CHECK: } // end sil function '$s4test13simpleHandleryySiF'
15+
@asyncHandler
16+
public func simpleHandler(_ i: Int) {
17+
await take(i)
18+
}
19+
20+
// CHECK-LABEL: sil [ossa] @$s4test20nonTrivialArgHandleryySSF : $@convention(thin) (@guaranteed String) -> () {
21+
// CHECK: [[COPY:%[0-9]+]] = copy_value %0 : $String
22+
// CHECK: [[BODYFN:%[0-9]+]] = function_ref @$s4test20nonTrivialArgHandleryySSYF : $@convention(thin) @async (@guaranteed String) -> ()
23+
// CHECK: [[FN:%[0-9]+]] = partial_apply [callee_guaranteed] [[BODYFN]]([[COPY]]) : $@convention(thin) @async (@guaranteed String) -> ()
24+
// CHECK: [[INTRINSIC:%[0-9]+]] = function_ref @$s12_Concurrency16_runAsyncHandler9operationyyyYc_tF : $@convention(thin) (@guaranteed @async @callee_guaranteed () -> ()) -> ()
25+
// CHECK: {{.*}} = apply [[INTRINSIC]]([[FN]]) : $@convention(thin) (@guaranteed @async @callee_guaranteed () -> ()) -> ()
26+
// CHECK: destroy_value [[FN]] : $@async @callee_guaranteed () -> ()
27+
// CHECK: } // end sil function '$s4test20nonTrivialArgHandleryySSF'
28+
@asyncHandler
29+
public func nonTrivialArgHandler(_ s: String) {
30+
await take(s)
31+
}
32+
33+
// CHECK-LABEL: sil [ossa] @$s4test14genericHandleryyxlF : $@convention(thin) <T> (@in_guaranteed T) -> () {
34+
// CHECK: [[TMP:%[0-9]+]] = alloc_stack $T
35+
// CHECK: copy_addr %0 to [initialization] [[TMP]] : $*T
36+
// CHECK: [[BODYFN:%[0-9]+]] = function_ref @$s4test14genericHandleryyxYlF : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> ()
37+
// CHECK: [[FN:%[0-9]+]] = partial_apply [callee_guaranteed] [[BODYFN]]<T>([[TMP]]) : $@convention(thin) @async <τ_0_0> (@in_guaranteed τ_0_0) -> ()
38+
// CHECK: [[INTRINSIC:%[0-9]+]] = function_ref @$s12_Concurrency16_runAsyncHandler9operationyyyYc_tF : $@convention(thin) (@guaranteed @async @callee_guaranteed () -> ()) -> ()
39+
// CHECK: {{.*}} = apply [[INTRINSIC]]([[FN]]) : $@convention(thin) (@guaranteed @async @callee_guaranteed () -> ()) -> ()
40+
// CHECK: destroy_value [[FN]] : $@async @callee_guaranteed () -> ()
41+
// CHECK: } // end sil function '$s4test14genericHandleryyxlF'
42+
@asyncHandler
43+
public func genericHandler<T>(_ t: T) {
44+
await take(t)
45+
}
46+
47+
public struct Mystruct {
48+
// CHECK-LABEL: sil [ossa] @$s4test8MystructV13memberHandleryySiF : $@convention(method) (Int, Mystruct) -> () {
49+
// CHECK: [[BODYFN:%[0-9]+]] = function_ref @$s4test8MystructV13memberHandleryySiYF : $@convention(method) @async (Int, Mystruct) -> ()
50+
// CHECK: [[FN:%[0-9]+]] = partial_apply [callee_guaranteed] [[BODYFN]](%0, %1) : $@convention(method) @async (Int, Mystruct) -> ()
51+
// CHECK: [[INTRINSIC:%[0-9]+]] = function_ref @$s12_Concurrency16_runAsyncHandler9operationyyyYc_tF : $@convention(thin) (@guaranteed @async @callee_guaranteed () -> ()) -> ()
52+
// CHECK: {{.*}} = apply [[INTRINSIC]]([[FN]]) : $@convention(thin) (@guaranteed @async @callee_guaranteed () -> ()) -> ()
53+
// CHECK: destroy_value [[FN]] : $@async @callee_guaranteed () -> ()
54+
// CHECK: } // end sil function '$s4test8MystructV13memberHandleryySiF'
55+
@asyncHandler
56+
public func memberHandler(_ i: Int) {
57+
await take(i)
58+
}
59+
}

0 commit comments

Comments
 (0)