@@ -330,10 +330,6 @@ AsyncContextLayout::AsyncContextLayout(
330
330
#endif
331
331
}
332
332
333
- static Size getAsyncContextSize (AsyncContextLayout layout) {
334
- return layout.getSize ();
335
- }
336
-
337
333
static Alignment getAsyncContextAlignment (IRGenModule &IGM) {
338
334
return IGM.getPointerAlignment ();
339
335
}
@@ -2043,6 +2039,12 @@ class SyncCallEmission final : public CallEmission {
2043
2039
return origConv.getSILArgumentType (
2044
2040
index, IGF.IGM .getMaximalTypeExpansionContext ());
2045
2041
}
2042
+
2043
+ llvm::CallInst *createCall (const FunctionPointer &fn,
2044
+ ArrayRef<llvm::Value *> args) override {
2045
+ return IGF.Builder .CreateCall (fn, Args);
2046
+ }
2047
+
2046
2048
void begin () override { super::begin (); }
2047
2049
void end () override { super::end (); }
2048
2050
void setFromCallee () override {
@@ -2234,9 +2236,9 @@ class AsyncCallEmission final : public CallEmission {
2234
2236
using super = CallEmission;
2235
2237
2236
2238
Address contextBuffer;
2237
- Size contextSize;
2238
2239
Address context;
2239
2240
llvm::Value *calleeFunction = nullptr ;
2241
+ llvm::Value *currentResumeFn = nullptr ;
2240
2242
llvm::Value *thickContext = nullptr ;
2241
2243
Optional<AsyncContextLayout> asyncContextLayout;
2242
2244
@@ -2278,8 +2280,7 @@ class AsyncCallEmission final : public CallEmission {
2278
2280
CurCallee.getFunctionPointer (), thickContext);
2279
2281
auto *dynamicContextSize =
2280
2282
IGF.Builder .CreateZExt (dynamicContextSize32, IGF.IGM .SizeTy );
2281
- std::tie (contextBuffer, contextSize) = emitAllocAsyncContext (
2282
- IGF, layout, dynamicContextSize, getAsyncContextSize (layout));
2283
+ contextBuffer = emitAllocAsyncContext (IGF, dynamicContextSize);
2283
2284
context = layout.emitCastTo (IGF, contextBuffer.getAddress ());
2284
2285
if (layout.canHaveError ()) {
2285
2286
auto fieldLayout = layout.getErrorLayout ();
@@ -2292,7 +2293,7 @@ class AsyncCallEmission final : public CallEmission {
2292
2293
void end () override {
2293
2294
assert (contextBuffer.isValid ());
2294
2295
assert (context.isValid ());
2295
- emitDeallocAsyncContext (IGF, contextBuffer, contextSize );
2296
+ emitDeallocAsyncContext (IGF, contextBuffer);
2296
2297
super::end ();
2297
2298
}
2298
2299
void setFromCallee () override {
@@ -2337,6 +2338,26 @@ class AsyncCallEmission final : public CallEmission {
2337
2338
explosion.add (context);
2338
2339
saveValue (fieldLayout, explosion, isOutlined);
2339
2340
}
2341
+ { // Return to caller function.
2342
+ auto fieldLayout = layout.getResumeParentLayout ();
2343
+ currentResumeFn = IGF.Builder .CreateIntrinsicCall (
2344
+ llvm::Intrinsic::coro_async_resume, {});
2345
+ auto fnVal = currentResumeFn;
2346
+ // Sign the pointer.
2347
+ // TODO: use a distinct schema.
2348
+ if (auto schema = IGF.IGM .getOptions ().PointerAuth .AsyncContextParent ) {
2349
+ Address fieldAddr =
2350
+ fieldLayout.project (IGF, this ->context , /* offsets*/ llvm::None);
2351
+ auto authInfo = PointerAuthInfo::emit (
2352
+ IGF, schema, fieldAddr.getAddress (), PointerAuthEntity ());
2353
+ fnVal = emitPointerAuthSign (IGF, fnVal, authInfo);
2354
+ }
2355
+ fnVal = IGF.Builder .CreateBitCast (fnVal,
2356
+ IGF.IGM .TaskContinuationFunctionPtrTy );
2357
+ Explosion explosion;
2358
+ explosion.add (fnVal);
2359
+ saveValue (fieldLayout, explosion, isOutlined);
2360
+ }
2340
2361
{ // caller executor
2341
2362
Explosion explosion;
2342
2363
explosion.add (IGF.getAsyncExecutor ());
@@ -2396,6 +2417,28 @@ class AsyncCallEmission final : public CallEmission {
2396
2417
auto address = errorLayout.project (IGF, context, /* offsets*/ llvm::None);
2397
2418
return address;
2398
2419
};
2420
+
2421
+ llvm::CallInst *createCall (const FunctionPointer &fn,
2422
+ ArrayRef<llvm::Value *> args) override {
2423
+ auto &IGM = IGF.IGM ;
2424
+ auto &Builder = IGF.Builder ;
2425
+ // Setup the suspend point.
2426
+ SmallVector<llvm::Value *, 8 > arguments;
2427
+ arguments.push_back (currentResumeFn);
2428
+ auto resumeProjFn = IGF.getOrCreateResumePrjFn ();
2429
+ arguments.push_back (
2430
+ Builder.CreateBitOrPointerCast (resumeProjFn, IGM.Int8PtrTy ));
2431
+ auto dispatchFn = IGF.createAsyncDispatchFn (fn, args);
2432
+ arguments.push_back (
2433
+ Builder.CreateBitOrPointerCast (dispatchFn, IGM.Int8PtrTy ));
2434
+ arguments.push_back (
2435
+ Builder.CreateBitOrPointerCast (fn.getRawPointer (), IGM.Int8PtrTy ));
2436
+ for (auto arg: args)
2437
+ arguments.push_back (arg);
2438
+ auto *id = Builder.CreateIntrinsicCall (llvm::Intrinsic::coro_suspend_async,
2439
+ arguments);
2440
+ return id;
2441
+ }
2399
2442
};
2400
2443
2401
2444
} // end anonymous namespace
@@ -2464,7 +2507,7 @@ llvm::CallInst *CallEmission::emitCallSite() {
2464
2507
}
2465
2508
2466
2509
// TODO: exceptions!
2467
- auto call = IGF. Builder . CreateCall (fn, Args);
2510
+ auto call = createCall (fn, Args);
2468
2511
2469
2512
// Make coroutines calls opaque to LLVM analysis.
2470
2513
if (IsCoroutine) {
@@ -3469,6 +3512,28 @@ emitRetconCoroutineEntry(IRGenFunction &IGF, CanSILFunctionType fnType,
3469
3512
IGF.setCoroutineHandle (hdl);
3470
3513
}
3471
3514
3515
+ void irgen::emitAsyncFunctionEntry (IRGenFunction &IGF,
3516
+ SILFunction *asyncFunction) {
3517
+ auto &IGM = IGF.IGM ;
3518
+ auto size = getAsyncContextLayout (IGM, asyncFunction).getSize ();
3519
+ auto asyncFuncPointer = IGF.Builder .CreateBitOrPointerCast (
3520
+ IGM.getAddrOfAsyncFunctionPointer (asyncFunction), IGM.Int8PtrTy );
3521
+ auto *id = IGF.Builder .CreateIntrinsicCall (
3522
+ llvm::Intrinsic::coro_id_async,
3523
+ {llvm::ConstantInt::get (IGM.Int32Ty , size.getValue ()),
3524
+ llvm::ConstantInt::get (IGM.Int32Ty , 16 ),
3525
+ llvm::ConstantInt::get (IGM.Int32Ty , 2 ), asyncFuncPointer});
3526
+ // Call 'llvm.coro.begin', just for consistency with the normal pattern.
3527
+ // This serves as a handle that we can pass around to other intrinsics.
3528
+ auto hdl = IGF.Builder .CreateIntrinsicCall (
3529
+ llvm::Intrinsic::coro_begin,
3530
+ {id, llvm::ConstantPointerNull::get (IGM.Int8PtrTy )});
3531
+
3532
+ // Set the coroutine handle; this also flags that is a coroutine so that
3533
+ // e.g. dynamic allocas use the right code generation.
3534
+ IGF.setCoroutineHandle (hdl);
3535
+ }
3536
+
3472
3537
void irgen::emitYieldOnceCoroutineEntry (
3473
3538
IRGenFunction &IGF, CanSILFunctionType fnType,
3474
3539
NativeCCEntryPointArgumentEmission &emission) {
@@ -3518,28 +3583,6 @@ void irgen::emitDeallocYieldManyCoroutineBuffer(IRGenFunction &IGF,
3518
3583
IGF.Builder .CreateLifetimeEnd (buffer, bufferSize);
3519
3584
}
3520
3585
3521
- Address irgen::emitTaskAlloc (IRGenFunction &IGF, llvm::Value *size,
3522
- Alignment alignment) {
3523
- auto *call = IGF.Builder .CreateCall (IGF.IGM .getTaskAllocFn (),
3524
- {IGF.getAsyncTask (), size});
3525
- call->setDoesNotThrow ();
3526
- call->setCallingConv (IGF.IGM .SwiftCC );
3527
- call->addAttribute (llvm::AttributeList::FunctionIndex,
3528
- llvm::Attribute::ReadNone);
3529
- auto address = Address (call, alignment);
3530
- return address;
3531
- }
3532
-
3533
- void irgen::emitTaskDealloc (IRGenFunction &IGF, Address address,
3534
- llvm::Value *size) {
3535
- auto *call = IGF.Builder .CreateCall (
3536
- IGF.IGM .getTaskDeallocFn (), {IGF.getAsyncTask (), address.getAddress ()});
3537
- call->setDoesNotThrow ();
3538
- call->setCallingConv (IGF.IGM .SwiftCC );
3539
- call->addAttribute (llvm::AttributeList::FunctionIndex,
3540
- llvm::Attribute::ReadNone);
3541
- }
3542
-
3543
3586
void irgen::emitTaskCancel (IRGenFunction &IGF, llvm::Value *task) {
3544
3587
if (task->getType () != IGF.IGM .SwiftTaskPtrTy ) {
3545
3588
task = IGF.Builder .CreateBitCast (task, IGF.IGM .SwiftTaskPtrTy );
@@ -3591,28 +3634,17 @@ llvm::Value *irgen::emitTaskCreate(
3591
3634
return result;
3592
3635
}
3593
3636
3594
- std::pair<Address, Size> irgen::emitAllocAsyncContext (IRGenFunction &IGF,
3595
- AsyncContextLayout layout,
3596
- llvm::Value *sizeValue,
3597
- Size sizeLowerBound) {
3637
+ Address irgen::emitAllocAsyncContext (IRGenFunction &IGF,
3638
+ llvm::Value *sizeValue) {
3598
3639
auto alignment = getAsyncContextAlignment (IGF.IGM );
3599
- auto address = emitTaskAlloc (IGF, sizeValue, alignment);
3600
- IGF.Builder .CreateLifetimeStart (address, sizeLowerBound);
3601
- return {address, sizeLowerBound};
3602
- }
3603
-
3604
- std::pair<Address, Size>
3605
- irgen::emitAllocAsyncContext (IRGenFunction &IGF, AsyncContextLayout layout) {
3606
- auto size = getAsyncContextSize (layout);
3607
- auto *sizeValue = llvm::ConstantInt::get (IGF.IGM .SizeTy , size.getValue ());
3608
- return emitAllocAsyncContext (IGF, layout, sizeValue, size);
3640
+ auto address = IGF.emitTaskAlloc (sizeValue, alignment);
3641
+ IGF.Builder .CreateLifetimeStart (address, Size (-1 ) /* dynamic size*/ );
3642
+ return address;
3609
3643
}
3610
3644
3611
- void irgen::emitDeallocAsyncContext (IRGenFunction &IGF, Address context,
3612
- Size size) {
3613
- auto *sizeValue = llvm::ConstantInt::get (IGF.IGM .SizeTy , size.getValue ());
3614
- emitTaskDealloc (IGF, context, sizeValue);
3615
- IGF.Builder .CreateLifetimeEnd (context, size);
3645
+ void irgen::emitDeallocAsyncContext (IRGenFunction &IGF, Address context) {
3646
+ IGF.emitTaskDealloc (context);
3647
+ IGF.Builder .CreateLifetimeEnd (context, Size (-1 ) /* dynamic size*/ );
3616
3648
}
3617
3649
3618
3650
llvm::Value *irgen::emitYield (IRGenFunction &IGF,
@@ -4484,3 +4516,36 @@ FunctionPointer::getExplosionValue(IRGenFunction &IGF,
4484
4516
FunctionPointer FunctionPointer::getAsFunction (IRGenFunction &IGF) const {
4485
4517
return FunctionPointer (KindTy::Function, getPointer (IGF), AuthInfo, Sig);
4486
4518
}
4519
+
4520
+ void irgen::emitAsyncReturn (IRGenFunction &IGF, AsyncContextLayout &asyncLayout,
4521
+ CanSILFunctionType fnType) {
4522
+ auto contextAddr = asyncLayout.emitCastTo (IGF, IGF.getAsyncContext ());
4523
+ auto returnToCallerLayout = asyncLayout.getResumeParentLayout ();
4524
+ auto returnToCallerAddr =
4525
+ returnToCallerLayout.project (IGF, contextAddr, llvm::None);
4526
+ Explosion fn;
4527
+ cast<LoadableTypeInfo>(returnToCallerLayout.getType ())
4528
+ .loadAsCopy (IGF, returnToCallerAddr, fn);
4529
+ llvm::Value *fnVal = fn.claimNext ();
4530
+
4531
+ // TODO: use distinct schema
4532
+ if (auto schema = IGF.IGM .getOptions ().PointerAuth .AsyncContextParent ) {
4533
+ Address fieldAddr =
4534
+ returnToCallerLayout.project (IGF, contextAddr, /* offsets*/ llvm::None);
4535
+ auto authInfo = PointerAuthInfo::emit (IGF, schema, fieldAddr.getAddress (),
4536
+ PointerAuthEntity ());
4537
+ fnVal = emitPointerAuthAuth (IGF, fnVal, authInfo);
4538
+ }
4539
+
4540
+ auto sig = emitCastOfFunctionPointer (IGF, fnVal, fnType);
4541
+ FunctionPointer fnPtr (FunctionPointer::KindTy::Function, fnVal,
4542
+ PointerAuthInfo (), sig);
4543
+
4544
+ SmallVector<llvm::Value*, 4 > Args;
4545
+ // Get the current task, executor, and async context.
4546
+ Args.push_back (IGF.getAsyncTask ());
4547
+ Args.push_back (IGF.getAsyncExecutor ());
4548
+ Args.push_back (IGF.getAsyncContext ());
4549
+ auto call = IGF.Builder .CreateCall (fnPtr, Args);
4550
+ call->setTailCall ();
4551
+ }
0 commit comments