@@ -658,6 +658,17 @@ void IRGenFunction::emitGetAsyncContinuation(SILType resumeTy,
658
658
out.add (unsafeContinuation);
659
659
}
660
660
661
+ static bool shouldUseContinuationAwait (IRGenModule &IGM) {
662
+ auto &ctx = IGM.Context ;
663
+ auto module = ctx.getLoadedModule (ctx.Id_Concurrency );
664
+ assert (module && " building async code without concurrency library" );
665
+ SmallVector<ValueDecl *, 1 > results;
666
+ module ->lookupValue (ctx.getIdentifier (" _abiEnableAwaitContinuation" ),
667
+ NLKind::UnqualifiedLookup, results);
668
+ assert (results.size () <= 1 );
669
+ return !results.empty ();
670
+ }
671
+
661
672
void IRGenFunction::emitAwaitAsyncContinuation (
662
673
SILType resumeTy, bool isIndirectResult,
663
674
Explosion &outDirectResult, llvm::BasicBlock *&normalBB,
@@ -667,6 +678,43 @@ void IRGenFunction::emitAwaitAsyncContinuation(
667
678
668
679
// Call swift_continuation_await to check whether the continuation
669
680
// has already been resumed.
681
+ bool useContinuationAwait = shouldUseContinuationAwait (IGM);
682
+
683
+ // As a temporary hack for compatibility with SDKs that don't provide
684
+ // swift_continuation_await, emit the old inline sequence. This can
685
+ // be removed as soon as we're sure that such SDKs don't exist.
686
+ if (!useContinuationAwait) {
687
+ auto contAwaitSyncAddr =
688
+ Builder.CreateStructGEP (AsyncCoroutineCurrentContinuationContext, 1 );
689
+
690
+ auto pendingV = llvm::ConstantInt::get (
691
+ contAwaitSyncAddr->getType ()->getPointerElementType (),
692
+ unsigned (ContinuationStatus::Pending));
693
+ auto awaitedV = llvm::ConstantInt::get (
694
+ contAwaitSyncAddr->getType ()->getPointerElementType (),
695
+ unsigned (ContinuationStatus::Awaited));
696
+ auto results = Builder.CreateAtomicCmpXchg (
697
+ contAwaitSyncAddr, pendingV, awaitedV,
698
+ llvm::AtomicOrdering::Release /* success ordering*/ ,
699
+ llvm::AtomicOrdering::Acquire /* failure ordering */ ,
700
+ llvm::SyncScope::System);
701
+ auto firstAtAwait = Builder.CreateExtractValue (results, 1 );
702
+ auto contBB = createBasicBlock (" await.async.resume" );
703
+ auto abortBB = createBasicBlock (" await.async.abort" );
704
+ Builder.CreateCondBr (firstAtAwait, abortBB, contBB);
705
+ Builder.emitBlock (abortBB);
706
+ {
707
+ // We were the first to the sync point. "Abort" (return from the
708
+ // coroutine partial function, without making a tail call to anything)
709
+ // because the continuation result is not available yet. When the
710
+ // continuation is later resumed, the task will get scheduled
711
+ // starting from the suspension point.
712
+ emitCoroutineOrAsyncExit ();
713
+ }
714
+
715
+ Builder.emitBlock (contBB);
716
+ }
717
+
670
718
{
671
719
// Set up the suspend point.
672
720
SmallVector<llvm::Value *, 8 > arguments;
@@ -676,10 +724,26 @@ void IRGenFunction::emitAwaitAsyncContinuation(
676
724
auto resumeProjFn = getOrCreateResumePrjFn ();
677
725
arguments.push_back (
678
726
Builder.CreateBitOrPointerCast (resumeProjFn, IGM.Int8PtrTy ));
679
- arguments.push_back (Builder.CreateBitOrPointerCast (
680
- IGM.getAwaitAsyncContinuationFn (),
681
- IGM.Int8PtrTy ));
682
- arguments.push_back (AsyncCoroutineCurrentContinuationContext);
727
+
728
+ llvm::Constant *awaitFnPtr;
729
+ if (useContinuationAwait) {
730
+ awaitFnPtr = IGM.getAwaitAsyncContinuationFn ();
731
+ } else {
732
+ auto resumeFnPtr =
733
+ getFunctionPointerForResumeIntrinsic (AsyncCoroutineCurrentResume);
734
+ awaitFnPtr = createAsyncDispatchFn (resumeFnPtr, {IGM.Int8PtrTy });
735
+ }
736
+ arguments.push_back (
737
+ Builder.CreateBitOrPointerCast (awaitFnPtr, IGM.Int8PtrTy ));
738
+
739
+ if (useContinuationAwait) {
740
+ arguments.push_back (AsyncCoroutineCurrentContinuationContext);
741
+ } else {
742
+ arguments.push_back (AsyncCoroutineCurrentResume);
743
+ arguments.push_back (Builder.CreateBitOrPointerCast (
744
+ AsyncCoroutineCurrentContinuationContext, IGM.Int8PtrTy ));
745
+ }
746
+
683
747
auto resultTy =
684
748
llvm::StructType::get (IGM.getLLVMContext (), {IGM.Int8PtrTy }, false /* packed*/ );
685
749
emitSuspendAsyncCall (swiftAsyncContextIndex, resultTy, arguments);
0 commit comments