Skip to content

Commit cd35636

Browse files
authored
Merge pull request #38529 from rjmccall/stage-continuation-await-5.5
[5.5] Stage the swift_continuation_await ABI change
2 parents 13da0b6 + 0b6fcb2 commit cd35636

File tree

2 files changed

+75
-4
lines changed

2 files changed

+75
-4
lines changed

lib/IRGen/IRGenFunction.cpp

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,17 @@ void IRGenFunction::emitGetAsyncContinuation(SILType resumeTy,
658658
out.add(unsafeContinuation);
659659
}
660660

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+
661672
void IRGenFunction::emitAwaitAsyncContinuation(
662673
SILType resumeTy, bool isIndirectResult,
663674
Explosion &outDirectResult, llvm::BasicBlock *&normalBB,
@@ -667,6 +678,43 @@ void IRGenFunction::emitAwaitAsyncContinuation(
667678

668679
// Call swift_continuation_await to check whether the continuation
669680
// 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+
670718
{
671719
// Set up the suspend point.
672720
SmallVector<llvm::Value *, 8> arguments;
@@ -676,10 +724,26 @@ void IRGenFunction::emitAwaitAsyncContinuation(
676724
auto resumeProjFn = getOrCreateResumePrjFn();
677725
arguments.push_back(
678726
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+
683747
auto resultTy =
684748
llvm::StructType::get(IGM.getLLVMContext(), {IGM.Int8PtrTy}, false /*packed*/);
685749
emitSuspendAsyncCall(swiftAsyncContextIndex, resultTy, arguments);

stdlib/public/Concurrency/PartialAsyncTask.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,10 @@ public func withUnsafeThrowingContinuation<T>(
271271
fn(UnsafeContinuation<T, Error>($0))
272272
}
273273
}
274+
275+
/// A hack to mark an SDK that supports swift_continuation_await.
276+
@available(SwiftStdlib 5.5, *)
277+
@_alwaysEmitIntoClient
278+
public func _abiEnableAwaitContinuation() {
279+
fatalError("never use this function")
280+
}

0 commit comments

Comments
 (0)