[llvm] 42f1916 - Revert "Start of an llvm.coro.async implementation"
Arnold Schwaighofer via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 4 08:28:41 PST 2020
Author: Arnold Schwaighofer
Date: 2020-11-04T08:26:20-08:00
New Revision: 42f19166405878459e27bf682ad38b8f1ac43d0a
URL: https://github.com/llvm/llvm-project/commit/42f19166405878459e27bf682ad38b8f1ac43d0a
DIFF: https://github.com/llvm/llvm-project/commit/42f19166405878459e27bf682ad38b8f1ac43d0a.diff
LOG: Revert "Start of an llvm.coro.async implementation"
This reverts commit ea606cced0583d1dbd4c44680601d1d4e9a56e58.
This patch causes memory sanitizer failures sanitizer-x86_64-linux-fast.
Added:
Modified:
llvm/docs/Coroutines.rst
llvm/include/llvm/IR/Intrinsics.td
llvm/lib/Transforms/Coroutines/CoroCleanup.cpp
llvm/lib/Transforms/Coroutines/CoroEarly.cpp
llvm/lib/Transforms/Coroutines/CoroFrame.cpp
llvm/lib/Transforms/Coroutines/CoroInstr.h
llvm/lib/Transforms/Coroutines/CoroInternal.h
llvm/lib/Transforms/Coroutines/CoroSplit.cpp
llvm/lib/Transforms/Coroutines/Coroutines.cpp
Removed:
llvm/test/Transforms/Coroutines/coro-async.ll
################################################################################
diff --git a/llvm/docs/Coroutines.rst b/llvm/docs/Coroutines.rst
index 6d2538e45568..8c8d13a45aa6 100644
--- a/llvm/docs/Coroutines.rst
+++ b/llvm/docs/Coroutines.rst
@@ -174,61 +174,6 @@ This may be acceptable if LLVM's coroutine support is primarily being
used for low-level lowering and inlining is expected to be applied
earlier in the pipeline.
-Async Lowering
---------------
-
-In async-continuation lowering, signaled by the use of `llvm.coro.id.async`,
-handling of control-flow must be handled explicitly by the frontend.
-
-In this lowering, a coroutine is assumed to take the current `async context` as
-its first argument. It is used to marshal arguments and return values of the
-coroutine. Therefore a async coroutine returns `void`.
-
-.. code-block:: llvm
- define swiftcc void @async_coroutine(i8* %async.ctxt, i8*, i8*) {
- }
-
-
-Every suspend point takes an `async context` argument which provides the context
-and the coroutine frame of the callee function. Every
-suspend point has an associated `resume function` denoted by the
-`llvm.coro.async.resume` intrinsic. The coroutine is resumed by
-calling this `resume function` passing the `async context` as the first
-argument. It is assumed that the `resume function` can restore its (the
-caller's) `async context` by loading the first field in the `async context`.
-
-.. code-block:: c
-
- struct async_context {
- struct async_context *caller_context;
- ...
- }
-
-The frontend should provide a `async function pointer` struct associated with
-each async coroutine by `llvm.coro.id.async`'s argument. The initial size and
-alignment of the `async context` must be provided as arguments to the
-`llvm.coro.id.async` intrinsic. Lowering will update the size entry with the
-coroutine frame requirements. The frontend is responsible for allocating the
-memory for the `async context` but can use the `async function pointer` struct
-to obtain the required size.
-
-.. code-block:: c
- struct async_function_pointer {
- uint32_t context_size;
- uint32_t relative_function_pointer_to_async_impl;
- }
-
-Lowering will split an async coroutine into a ramp function and one resume
-function per suspend point.
-
-How control-flow is passed between caller, suspension point, and back to
-resume function is left up to the frontend.
-
-The suspend point takes a function and its arguments. The function is intended
-to model the transfer to the callee function. It will be tail called by
-lowering and therefore must have the same signature and calling convention as
-the async coroutine.
-
Coroutines by Example
=====================
@@ -1148,45 +1093,6 @@ duplicated.
A frontend should emit exactly one `coro.id` intrinsic per coroutine.
-.. _coro.id.async:
-
-'llvm.coro.id.async' Intrinsic
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-::
-
- declare token @llvm.coro.id.async(i32 <context size>, i32 <align>,
- i8* <context arg>,
- i8* <async function pointer>)
-
-Overview:
-"""""""""
-
-The '``llvm.coro.id.async``' intrinsic returns a token identifying an async coroutine.
-
-Arguments:
-""""""""""
-
-The first argument provides the initial size of the `async context` as required
-from the frontend. Lowering will add to this size the size required by the frame
-storage and store that value to the `async function pointer`.
-
-The second argument, is the alignment guarantee of the memory of the
-`async context`. The frontend guarantees that the memory will be aligned by this
-value.
-
-The third argument is the `async context` argument in the current coroutine.
-
-The fourth argument is the address of the `async function pointer` struct.
-Lowering will update the context size requirement in this struct by adding the
-coroutine frame size requirement to the initial size requirement as specified by
-the first argument of this intrinisc.
-
-
-Semantics:
-""""""""""
-
-A frontend should emit exactly one `coro.id.async` intrinsic per coroutine.
-
.. _coro.id.retcon:
'llvm.coro.id.retcon' Intrinsic
@@ -1474,46 +1380,6 @@ to the coroutine:
switch i8 %suspend1, label %suspend [i8 0, label %resume1
i8 1, label %cleanup]
-.. _coro.suspend.async:
-
-'llvm.coro.suspend.async' Intrinsic
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-::
-
- declare {i8*, i8*, i8*} @llvm.coro.suspend.async(i8* <resume function>,
- i8* <callee context>,
- ... <function to call>
- ... <arguments to function>)
-
-Overview:
-"""""""""
-
-The '``llvm.coro.suspend.async``' intrinsic marks the point where
-execution of a async coroutine is suspended and control is passed to a callee.
-
-Arguments:
-""""""""""
-
-The first argument should be the result of the `llvm.coro.async.resume` intrinsic.
-Lowering will replace this intrinsic with the resume function for this suspend
-point.
-
-The second argument is the `async context` allocation for the callee. It should
-provide storage the `async context` header and the coroutine frame.
-
-The third argument is the function that models tranfer to the callee at the
-suspend point. It should take 3 arguments. Lowering will `musttail` call this
-function.
-
-The fourth to six argument are the arguments for the third argument.
-
-Semantics:
-""""""""""
-
-The result of the intrinsic are mapped to the arguments of the resume function.
-Execution is suspended at this intrinsic and resumed when the resume function is
-called.
-
.. _coro.suspend.retcon:
'llvm.coro.suspend.retcon' Intrinsic
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 85afbfe9ab3b..8a379f86829a 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -1187,21 +1187,6 @@ def int_coro_id_retcon_once : Intrinsic<[llvm_token_ty],
llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty],
[]>;
def int_coro_alloc : Intrinsic<[llvm_i1_ty], [llvm_token_ty], []>;
-def int_coro_id_async : Intrinsic<[llvm_token_ty],
- [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty, llvm_ptr_ty],
- []>;
-def int_coro_async_context_alloc : Intrinsic<[llvm_ptr_ty],
- [llvm_ptr_ty, llvm_ptr_ty],
- []>;
-def int_coro_async_context_dealloc : Intrinsic<[],
- [llvm_ptr_ty],
- []>;
-def int_coro_async_resume : Intrinsic<[llvm_ptr_ty],
- [],
- []>;
-def int_coro_suspend_async : Intrinsic<[llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty],
- [llvm_ptr_ty, llvm_ptr_ty, llvm_vararg_ty],
- []>;
def int_coro_begin : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty],
[WriteOnly<ArgIndex<1>>]>;
diff --git a/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp b/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp
index 298149f8b546..233eae37c497 100644
--- a/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp
@@ -74,7 +74,6 @@ bool Lowerer::lowerRemainingCoroIntrinsics(Function &F) {
case Intrinsic::coro_id:
case Intrinsic::coro_id_retcon:
case Intrinsic::coro_id_retcon_once:
- case Intrinsic::coro_id_async:
II->replaceAllUsesWith(ConstantTokenNone::get(Context));
break;
case Intrinsic::coro_subfn_addr:
diff --git a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
index 07c571a962b0..242e6c3f6b23 100644
--- a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
@@ -187,7 +187,6 @@ bool Lowerer::lowerEarlyIntrinsics(Function &F) {
break;
case Intrinsic::coro_id_retcon:
case Intrinsic::coro_id_retcon_once:
- case Intrinsic::coro_id_async:
F.addFnAttr(CORO_PRESPLIT_ATTR, PREPARED_FOR_SPLIT);
break;
case Intrinsic::coro_resume:
diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
index af07d28fc7c5..5fb713541812 100644
--- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
@@ -135,10 +135,10 @@ struct SuspendCrossingInfo {
BasicBlock *UseBB = I->getParent();
- // As a special case, treat uses by an llvm.coro.suspend.retcon or an
- // llvm.coro.suspend.async as if they were uses in the suspend's single
- // predecessor: the uses conceptually occur before the suspend.
- if (isa<CoroSuspendRetconInst>(I) || isa<CoroSuspendAsyncInst>(I)) {
+ // As a special case, treat uses by an llvm.coro.suspend.retcon
+ // as if they were uses in the suspend's single predecessor: the
+ // uses conceptually occur before the suspend.
+ if (isa<CoroSuspendRetconInst>(I)) {
UseBB = UseBB->getSinglePredecessor();
assert(UseBB && "should have split coro.suspend into its own block");
}
@@ -788,18 +788,6 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape,
B.getStructAlign() <= Id->getStorageAlignment());
break;
}
- case coro::ABI::Async: {
- Shape.AsyncLowering.FrameOffset =
- alignTo(Shape.AsyncLowering.ContextHeaderSize, Shape.FrameAlign);
- Shape.AsyncLowering.ContextSize =
- Shape.AsyncLowering.FrameOffset + Shape.FrameSize;
- if (Shape.AsyncLowering.getContextAlignment() < Shape.FrameAlign) {
- report_fatal_error(
- "The alignment requirment of frame variables cannot be higher than "
- "the alignment of the async function context");
- }
- break;
- }
}
return FrameTy;
@@ -1155,8 +1143,7 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData,
Shape.AllocaSpillBlock = SpillBlock;
// retcon and retcon.once lowering assumes all uses have been sunk.
- if (Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce ||
- Shape.ABI == coro::ABI::Async) {
+ if (Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce) {
// If we found any allocas, replace all of their remaining uses with Geps.
Builder.SetInsertPoint(&SpillBlock->front());
for (const auto &P : FrameData.Allocas) {
@@ -1879,8 +1866,7 @@ static void sinkSpillUsesAfterCoroBegin(Function &F,
for (User *U : Def->users()) {
auto Inst = cast<Instruction>(U);
if (Inst->getParent() != CoroBegin->getParent() ||
- Dom.dominates(CoroBegin, Inst) ||
- isa<CoroIdAsyncInst>(Inst) /*'fake' use of async context argument*/)
+ Dom.dominates(CoroBegin, Inst))
continue;
if (ToMove.insert(Inst))
Worklist.push_back(Inst);
@@ -2176,8 +2162,7 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) {
}
}
LLVM_DEBUG(dumpSpills("Spills", FrameData.Spills));
- if (Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce ||
- Shape.ABI == coro::ABI::Async)
+ if (Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce)
sinkSpillUsesAfterCoroBegin(F, FrameData, Shape.CoroBegin);
Shape.FrameTy = buildFrameType(F, Shape, FrameData);
// Add PromiseAlloca to Allocas list so that it is processed in insertSpills.
diff --git a/llvm/lib/Transforms/Coroutines/CoroInstr.h b/llvm/lib/Transforms/Coroutines/CoroInstr.h
index 5dbb94d10985..320137526db8 100644
--- a/llvm/lib/Transforms/Coroutines/CoroInstr.h
+++ b/llvm/lib/Transforms/Coroutines/CoroInstr.h
@@ -99,9 +99,9 @@ class LLVM_LIBRARY_VISIBILITY AnyCoroIdInst : public IntrinsicInst {
// Methods to support type inquiry through isa, cast, and dyn_cast:
static bool classof(const IntrinsicInst *I) {
auto ID = I->getIntrinsicID();
- return ID == Intrinsic::coro_id || ID == Intrinsic::coro_id_retcon ||
- ID == Intrinsic::coro_id_retcon_once ||
- ID == Intrinsic::coro_id_async;
+ return ID == Intrinsic::coro_id ||
+ ID == Intrinsic::coro_id_retcon ||
+ ID == Intrinsic::coro_id_retcon_once;
}
static bool classof(const Value *V) {
@@ -273,102 +273,6 @@ class LLVM_LIBRARY_VISIBILITY CoroIdRetconOnceInst
}
};
-/// This represents the llvm.coro.id.async instruction.
-class LLVM_LIBRARY_VISIBILITY CoroIdAsyncInst : public AnyCoroIdInst {
- enum { SizeArg, AlignArg, StorageArg, AsyncFuncPtrArg };
-
-public:
- void checkWellFormed() const;
-
- /// The initial async function context size. The fields of which are reserved
- /// for use by the frontend. The frame will be allocated as a tail of this
- /// context.
- uint64_t getStorageSize() const {
- return cast<ConstantInt>(getArgOperand(SizeArg))->getZExtValue();
- }
-
- /// The alignment of the initial async function context.
- Align getStorageAlignment() const {
- return cast<ConstantInt>(getArgOperand(AlignArg))->getAlignValue();
- }
-
- /// The async context parameter.
- Value *getStorage() const { return getArgOperand(StorageArg); }
-
- /// Return the async function pointer address. This should be the address of
- /// a async function pointer struct for the current async function.
- /// struct async_function_pointer {
- /// uint32_t context_size;
- /// uint32_t relative_async_function_pointer;
- /// };
- GlobalVariable *getAsyncFunctionPointer() const {
- return cast<GlobalVariable>(
- getArgOperand(AsyncFuncPtrArg)->stripPointerCasts());
- }
-
- // Methods to support type inquiry through isa, cast, and dyn_cast:
- static bool classof(const IntrinsicInst *I) {
- auto ID = I->getIntrinsicID();
- return ID == Intrinsic::coro_id_async;
- }
-
- static bool classof(const Value *V) {
- return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
- }
-};
-
-/// This represents the llvm.coro.context.alloc instruction.
-class LLVM_LIBRARY_VISIBILITY CoroAsyncContextAllocInst : public IntrinsicInst {
- enum { AsyncFuncPtrArg };
-
-public:
- GlobalVariable *getAsyncFunctionPointer() const {
- return cast<GlobalVariable>(
- getArgOperand(AsyncFuncPtrArg)->stripPointerCasts());
- }
-
- // Methods to support type inquiry through isa, cast, and dyn_cast:
- static bool classof(const IntrinsicInst *I) {
- return I->getIntrinsicID() == Intrinsic::coro_async_context_alloc;
- }
- static bool classof(const Value *V) {
- return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
- }
-};
-
-/// This represents the llvm.coro.context.dealloc instruction.
-class LLVM_LIBRARY_VISIBILITY CoroAsyncContextDeallocInst
- : public IntrinsicInst {
- enum { AsyncContextArg };
-
-public:
- Value *getAsyncContext() const {
- return getArgOperand(AsyncContextArg)->stripPointerCasts();
- }
-
- // Methods to support type inquiry through isa, cast, and dyn_cast:
- static bool classof(const IntrinsicInst *I) {
- return I->getIntrinsicID() == Intrinsic::coro_async_context_dealloc;
- }
- static bool classof(const Value *V) {
- return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
- }
-};
-
-/// This represents the llvm.coro.async.resume instruction.
-/// During lowering this is replaced by the resume function of a suspend point
-/// (the continuation function).
-class LLVM_LIBRARY_VISIBILITY CoroAsyncResumeInst : public IntrinsicInst {
-public:
- // Methods to support type inquiry through isa, cast, and dyn_cast:
- static bool classof(const IntrinsicInst *I) {
- return I->getIntrinsicID() == Intrinsic::coro_async_resume;
- }
- static bool classof(const Value *V) {
- return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
- }
-};
-
/// This represents the llvm.coro.frame instruction.
class LLVM_LIBRARY_VISIBILITY CoroFrameInst : public IntrinsicInst {
public:
@@ -462,7 +366,6 @@ class LLVM_LIBRARY_VISIBILITY AnyCoroSuspendInst : public IntrinsicInst {
// Methods to support type inquiry through isa, cast, and dyn_cast:
static bool classof(const IntrinsicInst *I) {
return I->getIntrinsicID() == Intrinsic::coro_suspend ||
- I->getIntrinsicID() == Intrinsic::coro_suspend_async ||
I->getIntrinsicID() == Intrinsic::coro_suspend_retcon;
}
static bool classof(const Value *V) {
@@ -502,34 +405,6 @@ inline CoroSaveInst *AnyCoroSuspendInst::getCoroSave() const {
return nullptr;
}
-/// This represents the llvm.coro.suspend.async instruction.
-class LLVM_LIBRARY_VISIBILITY CoroSuspendAsyncInst : public AnyCoroSuspendInst {
- enum { ResumeFunctionArg, AsyncContextArg, MustTailCallFuncArg };
-
-public:
- Value *getAsyncContext() const {
- return getArgOperand(AsyncContextArg)->stripPointerCasts();
- }
-
- CoroAsyncResumeInst *getResumeFunction() const {
- return cast<CoroAsyncResumeInst>(
- getArgOperand(ResumeFunctionArg)->stripPointerCasts());
- }
-
- Function *getMustTailCallFunction() const {
- return cast<Function>(
- getArgOperand(MustTailCallFuncArg)->stripPointerCasts());
- }
-
- // Methods to support type inquiry through isa, cast, and dyn_cast:
- static bool classof(const IntrinsicInst *I) {
- return I->getIntrinsicID() == Intrinsic::coro_suspend_async;
- }
- static bool classof(const Value *V) {
- return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
- }
-};
-
/// This represents the llvm.coro.suspend.retcon instruction.
class LLVM_LIBRARY_VISIBILITY CoroSuspendRetconInst : public AnyCoroSuspendInst {
public:
diff --git a/llvm/lib/Transforms/Coroutines/CoroInternal.h b/llvm/lib/Transforms/Coroutines/CoroInternal.h
index 855c5c4b582d..bf178454e1d0 100644
--- a/llvm/lib/Transforms/Coroutines/CoroInternal.h
+++ b/llvm/lib/Transforms/Coroutines/CoroInternal.h
@@ -81,11 +81,6 @@ enum class ABI {
/// suspend at most once during its execution, and the return value of
/// the continuation is void.
RetconOnce,
-
- /// The "async continuation" lowering, where each suspend point creates a
- /// single continuation function. The continuation function is available as an
- /// intrinsic.
- Async,
};
// Holds structural Coroutine Intrinsics for a particular function and other
@@ -138,22 +133,9 @@ struct LLVM_LIBRARY_VISIBILITY Shape {
bool IsFrameInlineInStorage;
};
- struct AsyncLoweringStorage {
- FunctionType *AsyncFuncTy;
- Value *Context;
- uint64_t ContextHeaderSize;
- uint64_t ContextAlignment;
- uint64_t FrameOffset; // Start of the frame.
- uint64_t ContextSize; // Includes frame size.
- GlobalVariable *AsyncFuncPointer;
-
- Align getContextAlignment() const { return Align(ContextAlignment); }
- };
-
union {
SwitchLoweringStorage SwitchLowering;
RetconLoweringStorage RetconLowering;
- AsyncLoweringStorage AsyncLowering;
};
CoroIdInst *getSwitchCoroId() const {
@@ -167,11 +149,6 @@ struct LLVM_LIBRARY_VISIBILITY Shape {
return cast<AnyCoroIdRetconInst>(CoroBegin->getId());
}
- CoroIdAsyncInst *getAsyncCoroId() const {
- assert(ABI == coro::ABI::Async);
- return cast<CoroIdAsyncInst>(CoroBegin->getId());
- }
-
unsigned getSwitchIndexField() const {
assert(ABI == coro::ABI::Switch);
assert(FrameTy && "frame type not assigned");
@@ -201,10 +178,7 @@ struct LLVM_LIBRARY_VISIBILITY Shape {
case coro::ABI::Retcon:
case coro::ABI::RetconOnce:
return RetconLowering.ResumePrototype->getFunctionType();
- case coro::ABI::Async:
- return AsyncLowering.AsyncFuncTy;
}
-
llvm_unreachable("Unknown coro::ABI enum");
}
@@ -238,8 +212,6 @@ struct LLVM_LIBRARY_VISIBILITY Shape {
case coro::ABI::Retcon:
case coro::ABI::RetconOnce:
return RetconLowering.ResumePrototype->getCallingConv();
- case coro::ABI::Async:
- return CallingConv::Swift;
}
llvm_unreachable("Unknown coro::ABI enum");
}
diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
index ef77f4365c9a..0b77f08caf14 100644
--- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -90,11 +90,7 @@ class CoroCloner {
/// An individual continuation function.
Continuation,
-
- /// An async resume function.
- Async,
};
-
private:
Function &OrigF;
Function *NewF;
@@ -106,9 +102,8 @@ class CoroCloner {
Value *NewFramePtr = nullptr;
Value *SwiftErrorSlot = nullptr;
- /// The active suspend instruction; meaningful only for continuation and async
- /// ABIs.
- AnyCoroSuspendInst *ActiveSuspend;
+ /// The active suspend instruction; meaningful only for continuation ABIs.
+ AnyCoroSuspendInst *ActiveSuspend = nullptr;
public:
/// Create a cloner for a switch lowering.
@@ -122,11 +117,11 @@ class CoroCloner {
/// Create a cloner for a continuation lowering.
CoroCloner(Function &OrigF, const Twine &Suffix, coro::Shape &Shape,
Function *NewF, AnyCoroSuspendInst *ActiveSuspend)
- : OrigF(OrigF), NewF(NewF), Suffix(Suffix), Shape(Shape),
- FKind(Shape.ABI == coro::ABI::Async ? Kind::Async : Kind::Continuation),
- Builder(OrigF.getContext()), ActiveSuspend(ActiveSuspend) {
+ : OrigF(OrigF), NewF(NewF), Suffix(Suffix), Shape(Shape),
+ FKind(Kind::Continuation), Builder(OrigF.getContext()),
+ ActiveSuspend(ActiveSuspend) {
assert(Shape.ABI == coro::ABI::Retcon ||
- Shape.ABI == coro::ABI::RetconOnce || Shape.ABI == coro::ABI::Async);
+ Shape.ABI == coro::ABI::RetconOnce);
assert(NewF && "need existing function for continuation");
assert(ActiveSuspend && "need active suspend point for continuation");
}
@@ -141,7 +136,6 @@ class CoroCloner {
private:
bool isSwitchDestroyFunction() {
switch (FKind) {
- case Kind::Async:
case Kind::Continuation:
case Kind::SwitchResume:
return false;
@@ -155,7 +149,7 @@ class CoroCloner {
void createDeclaration();
void replaceEntryBlock();
Value *deriveNewFramePointer();
- void replaceRetconOrAsyncSuspendUses();
+ void replaceRetconSuspendUses();
void replaceCoroSuspends();
void replaceCoroEnds();
void replaceSwiftErrorOps();
@@ -194,11 +188,6 @@ static void replaceFallthroughCoroEnd(CoroEndInst *End,
Builder.CreateRetVoid();
break;
- // In async lowering this returns.
- case coro::ABI::Async:
- Builder.CreateRetVoid();
- break;
-
// In unique continuation lowering, the continuations always return void.
// But we may have implicitly allocated storage.
case coro::ABI::RetconOnce:
@@ -242,9 +231,7 @@ static void replaceUnwindCoroEnd(CoroEndInst *End, const coro::Shape &Shape,
if (!InResume)
return;
break;
- // In async lowering this does nothing.
- case coro::ABI::Async:
- break;
+
// In continuation-lowering, this frees the continuation storage.
case coro::ABI::Retcon:
case coro::ABI::RetconOnce:
@@ -416,24 +403,20 @@ static Function *createCloneDeclaration(Function &OrigF, coro::Shape &Shape,
Function::Create(FnTy, GlobalValue::LinkageTypes::InternalLinkage,
OrigF.getName() + Suffix);
NewF->addParamAttr(0, Attribute::NonNull);
-
- // For the async lowering ABI we can't guarantee that the context argument is
- // not access via a
diff erent pointer not based on the argument.
- if (Shape.ABI != coro::ABI::Async)
- NewF->addParamAttr(0, Attribute::NoAlias);
+ NewF->addParamAttr(0, Attribute::NoAlias);
M->getFunctionList().insert(InsertBefore, NewF);
return NewF;
}
-/// Replace uses of the active llvm.coro.suspend.retcon/async call with the
+/// Replace uses of the active llvm.coro.suspend.retcon call with the
/// arguments to the continuation function.
///
/// This assumes that the builder has a meaningful insertion point.
-void CoroCloner::replaceRetconOrAsyncSuspendUses() {
- assert(Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce ||
- Shape.ABI == coro::ABI::Async);
+void CoroCloner::replaceRetconSuspendUses() {
+ assert(Shape.ABI == coro::ABI::Retcon ||
+ Shape.ABI == coro::ABI::RetconOnce);
auto NewS = VMap[ActiveSuspend];
if (NewS->use_empty()) return;
@@ -441,11 +424,7 @@ void CoroCloner::replaceRetconOrAsyncSuspendUses() {
// Copy out all the continuation arguments after the buffer pointer into
// an easily-indexed data structure for convenience.
SmallVector<Value*, 8> Args;
- // The async ABI includes all arguments -- including the first argument.
- bool IsAsyncABI = Shape.ABI == coro::ABI::Async;
- for (auto I = IsAsyncABI ? NewF->arg_begin() : std::next(NewF->arg_begin()),
- E = NewF->arg_end();
- I != E; ++I)
+ for (auto I = std::next(NewF->arg_begin()), E = NewF->arg_end(); I != E; ++I)
Args.push_back(&*I);
// If the suspend returns a single scalar value, we can just do a simple
@@ -491,10 +470,6 @@ void CoroCloner::replaceCoroSuspends() {
SuspendResult = Builder.getInt8(isSwitchDestroyFunction() ? 1 : 0);
break;
- // In async lowering there are no uses of the result.
- case coro::ABI::Async:
- return;
-
// In returned-continuation lowering, the arguments from earlier
// continuations are theoretically arbitrary, and they should have been
// spilled.
@@ -626,18 +601,13 @@ void CoroCloner::replaceEntryBlock() {
Builder.CreateBr(SwitchBB);
break;
}
- case coro::ABI::Async:
+
case coro::ABI::Retcon:
case coro::ABI::RetconOnce: {
// In continuation ABIs, we want to branch to immediately after the
// active suspend point. Earlier phases will have put the suspend in its
// own basic block, so just thread our jump directly to its successor.
- assert((Shape.ABI == coro::ABI::Async &&
- isa<CoroSuspendAsyncInst>(ActiveSuspend)) ||
- ((Shape.ABI == coro::ABI::Retcon ||
- Shape.ABI == coro::ABI::RetconOnce) &&
- isa<CoroSuspendRetconInst>(ActiveSuspend)));
- auto *MappedCS = cast<AnyCoroSuspendInst>(VMap[ActiveSuspend]);
+ auto MappedCS = cast<CoroSuspendRetconInst>(VMap[ActiveSuspend]);
auto Branch = cast<BranchInst>(MappedCS->getNextNode());
assert(Branch->isUnconditional());
Builder.CreateBr(Branch->getSuccessor(0));
@@ -654,25 +624,7 @@ Value *CoroCloner::deriveNewFramePointer() {
// In switch-lowering, the argument is the frame pointer.
case coro::ABI::Switch:
return &*NewF->arg_begin();
- case coro::ABI::Async: {
- auto *CalleeContext = &*NewF->arg_begin();
- auto *FramePtrTy = Shape.FrameTy->getPointerTo();
- // The caller context is assumed to be stored at the begining of the callee
- // context.
- // struct async_context {
- // struct async_context *caller;
- // ...
- auto &Context = Builder.getContext();
- auto *Int8PtrPtrTy = Type::getInt8PtrTy(Context)->getPointerTo();
- auto *CallerContextAddr =
- Builder.CreateBitOrPointerCast(CalleeContext, Int8PtrPtrTy);
- auto *CallerContext = Builder.CreateLoad(CallerContextAddr);
- // The frame is located after the async_context header.
- auto *FramePtrAddr = Builder.CreateConstInBoundsGEP1_32(
- Type::getInt8Ty(Context), CallerContext,
- Shape.AsyncLowering.FrameOffset, "async.ctx.frameptr");
- return Builder.CreateBitCast(FramePtrAddr, FramePtrTy);
- }
+
// In continuation-lowering, the argument is the opaque storage.
case coro::ABI::Retcon:
case coro::ABI::RetconOnce: {
@@ -755,8 +707,7 @@ void CoroCloner::create() {
addFramePointerAttrs(NewAttrs, Context, 0,
Shape.FrameSize, Shape.FrameAlign);
break;
- case coro::ABI::Async:
- break;
+
case coro::ABI::Retcon:
case coro::ABI::RetconOnce:
// If we have a continuation prototype, just use its attributes,
@@ -786,12 +737,6 @@ void CoroCloner::create() {
// so we want to leave any returns in place.
case coro::ABI::Retcon:
break;
- // Async lowering will insert musttail call functions at all suspend points
- // followed by a return.
- // Don't change returns to unreachable because that will trip up the verifier.
- // These returns should be unreachable from the clone.
- case coro::ABI::Async:
- break;
}
NewF->setAttributes(NewAttrs);
@@ -822,14 +767,14 @@ void CoroCloner::create() {
if (Shape.SwitchLowering.HasFinalSuspend)
handleFinalSuspend();
break;
- case coro::ABI::Async:
+
case coro::ABI::Retcon:
case coro::ABI::RetconOnce:
// Replace uses of the active suspend with the corresponding
// continuation-function arguments.
assert(ActiveSuspend != nullptr &&
"no active suspend when lowering a continuation-style coroutine");
- replaceRetconOrAsyncSuspendUses();
+ replaceRetconSuspendUses();
break;
}
@@ -866,25 +811,7 @@ static void removeCoroEnds(const coro::Shape &Shape, CallGraph *CG) {
}
}
-static void updateAsyncFuncPointerContextSize(coro::Shape &Shape) {
- assert(Shape.ABI == coro::ABI::Async);
-
- auto *FuncPtrStruct = cast<ConstantStruct>(
- Shape.AsyncLowering.AsyncFuncPointer->getInitializer());
- auto *OrigContextSize = FuncPtrStruct->getOperand(0);
- auto *OrigRelativeFunOffset = FuncPtrStruct->getOperand(1);
- auto *NewContextSize = ConstantInt::get(OrigContextSize->getType(),
- Shape.AsyncLowering.ContextSize);
- auto *NewFuncPtrStruct = ConstantStruct::get(
- FuncPtrStruct->getType(), NewContextSize, OrigRelativeFunOffset);
-
- Shape.AsyncLowering.AsyncFuncPointer->setInitializer(NewFuncPtrStruct);
-}
-
static void replaceFrameSize(coro::Shape &Shape) {
- if (Shape.ABI == coro::ABI::Async)
- updateAsyncFuncPointerContextSize(Shape);
-
if (Shape.CoroSizes.empty())
return;
@@ -1148,7 +1075,7 @@ static void handleNoSuspendCoroutine(coro::Shape &Shape) {
}
break;
}
- case coro::ABI::Async:
+
case coro::ABI::Retcon:
case coro::ABI::RetconOnce:
CoroBegin->replaceAllUsesWith(UndefValue::get(CoroBegin->getType()));
@@ -1344,98 +1271,6 @@ static void splitSwitchCoroutine(Function &F, coro::Shape &Shape,
setCoroInfo(F, Shape, Clones);
}
-static void replaceAsyncResumeFunction(CoroSuspendAsyncInst *Suspend,
- Value *Continuation) {
- auto *ResumeIntrinsic = Suspend->getResumeFunction();
- auto &Context = Suspend->getParent()->getParent()->getContext();
- auto *Int8PtrTy = Type::getInt8PtrTy(Context);
-
- IRBuilder<> Builder(ResumeIntrinsic);
- auto *Val = Builder.CreateBitOrPointerCast(Continuation, Int8PtrTy);
- ResumeIntrinsic->replaceAllUsesWith(Val);
- ResumeIntrinsic->eraseFromParent();
- Suspend->setOperand(0, UndefValue::get(Int8PtrTy));
-}
-
-static void splitAsyncCoroutine(Function &F, coro::Shape &Shape,
- SmallVectorImpl<Function *> &Clones) {
- assert(Shape.ABI == coro::ABI::Async);
- assert(Clones.empty());
- // Reset various things that the optimizer might have decided it
- // "knows" about the coroutine function due to not seeing a return.
- F.removeFnAttr(Attribute::NoReturn);
- F.removeAttribute(AttributeList::ReturnIndex, Attribute::NoAlias);
- F.removeAttribute(AttributeList::ReturnIndex, Attribute::NonNull);
-
- auto &Context = F.getContext();
- auto *Int8PtrTy = Type::getInt8PtrTy(Context);
-
- auto *Id = cast<CoroIdAsyncInst>(Shape.CoroBegin->getId());
- IRBuilder<> Builder(Id);
-
- auto *FramePtr = Id->getStorage();
- FramePtr = Builder.CreateBitOrPointerCast(FramePtr, Int8PtrTy);
- FramePtr = Builder.CreateConstInBoundsGEP1_32(
- Type::getInt8Ty(Context), FramePtr, Shape.AsyncLowering.FrameOffset,
- "async.ctx.frameptr");
-
- // Map all uses of llvm.coro.begin to the allocated frame pointer.
- {
- // Make sure we don't invalidate Shape.FramePtr.
- TrackingVH<Instruction> Handle(Shape.FramePtr);
- Shape.CoroBegin->replaceAllUsesWith(FramePtr);
- Shape.FramePtr = Handle.getValPtr();
- }
-
- // Create all the functions in order after the main function.
- auto NextF = std::next(F.getIterator());
-
- // Create a continuation function for each of the suspend points.
- Clones.reserve(Shape.CoroSuspends.size());
- for (size_t Idx = 0, End = Shape.CoroSuspends.size(); Idx != End; ++Idx) {
- auto *Suspend = cast<CoroSuspendAsyncInst>(Shape.CoroSuspends[Idx]);
-
- // Create the clone declaration.
- auto *Continuation =
- createCloneDeclaration(F, Shape, ".resume." + Twine(Idx), NextF);
- Clones.push_back(Continuation);
-
- // Insert a branch to a new return block immediately before the suspend
- // point.
- auto *SuspendBB = Suspend->getParent();
- auto *NewSuspendBB = SuspendBB->splitBasicBlock(Suspend);
- auto *Branch = cast<BranchInst>(SuspendBB->getTerminator());
-
- // Place it before the first suspend.
- auto *ReturnBB =
- BasicBlock::Create(F.getContext(), "coro.return", &F, NewSuspendBB);
- Branch->setSuccessor(0, ReturnBB);
-
- IRBuilder<> Builder(ReturnBB);
-
- // Insert the call to the tail call function.
- auto *Fun = Suspend->getMustTailCallFunction();
- SmallVector<Value *, 8> Args(Suspend->operand_values());
- auto *TailCall = Builder.CreateCall(
- cast<FunctionType>(Fun->getType()->getPointerElementType()), Fun,
- ArrayRef<Value *>(Args).drop_front(3).drop_back(1));
- TailCall->setTailCallKind(CallInst::TCK_MustTail);
- TailCall->setCallingConv(Fun->getCallingConv());
- Builder.CreateRetVoid();
-
- // Replace the lvm.coro.async.resume intrisic call.
- replaceAsyncResumeFunction(Suspend, Continuation);
- }
-
- assert(Clones.size() == Shape.CoroSuspends.size());
- for (size_t Idx = 0, End = Shape.CoroSuspends.size(); Idx != End; ++Idx) {
- auto *Suspend = Shape.CoroSuspends[Idx];
- auto *Clone = Clones[Idx];
-
- CoroCloner(F, "resume." + Twine(Idx), Shape, Clone, Suspend).create();
- }
-}
-
static void splitRetconCoroutine(Function &F, coro::Shape &Shape,
SmallVectorImpl<Function *> &Clones) {
assert(Shape.ABI == coro::ABI::Retcon ||
@@ -1606,9 +1441,6 @@ static coro::Shape splitCoroutine(Function &F,
case coro::ABI::Switch:
splitSwitchCoroutine(F, Shape, Clones);
break;
- case coro::ABI::Async:
- splitAsyncCoroutine(F, Shape, Clones);
- break;
case coro::ABI::Retcon:
case coro::ABI::RetconOnce:
splitRetconCoroutine(F, Shape, Clones);
diff --git a/llvm/lib/Transforms/Coroutines/Coroutines.cpp b/llvm/lib/Transforms/Coroutines/Coroutines.cpp
index 932bd4015993..18d46247deab 100644
--- a/llvm/lib/Transforms/Coroutines/Coroutines.cpp
+++ b/llvm/lib/Transforms/Coroutines/Coroutines.cpp
@@ -124,9 +124,6 @@ static bool isCoroutineIntrinsicName(StringRef Name) {
// NOTE: Must be sorted!
static const char *const CoroIntrinsics[] = {
"llvm.coro.alloc",
- "llvm.coro.async.context.alloc",
- "llvm.coro.async.context.dealloc",
- "llvm.coro.async.store_resume",
"llvm.coro.begin",
"llvm.coro.destroy",
"llvm.coro.done",
@@ -134,7 +131,6 @@ static bool isCoroutineIntrinsicName(StringRef Name) {
"llvm.coro.frame",
"llvm.coro.free",
"llvm.coro.id",
- "llvm.coro.id.async",
"llvm.coro.id.retcon",
"llvm.coro.id.retcon.once",
"llvm.coro.noop",
@@ -146,7 +142,6 @@ static bool isCoroutineIntrinsicName(StringRef Name) {
"llvm.coro.size",
"llvm.coro.subfn.addr",
"llvm.coro.suspend",
- "llvm.coro.suspend.async",
"llvm.coro.suspend.retcon",
};
return Intrinsic::lookupLLVMIntrinsicByName(CoroIntrinsics, Name) != -1;
@@ -274,11 +269,6 @@ void coro::Shape::buildFrom(Function &F) {
if (II->use_empty())
UnusedCoroSaves.push_back(cast<CoroSaveInst>(II));
break;
- case Intrinsic::coro_suspend_async: {
- auto *Suspend = cast<CoroSuspendAsyncInst>(II);
- CoroSuspends.push_back(Suspend);
- break;
- }
case Intrinsic::coro_suspend_retcon: {
auto Suspend = cast<CoroSuspendRetconInst>(II);
CoroSuspends.push_back(Suspend);
@@ -381,22 +371,7 @@ void coro::Shape::buildFrom(Function &F) {
}
break;
}
- case Intrinsic::coro_id_async: {
- auto *AsyncId = cast<CoroIdAsyncInst>(Id);
- AsyncId->checkWellFormed();
- this->ABI = coro::ABI::Async;
- this->AsyncLowering.Context = AsyncId->getStorage();
- this->AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize();
- this->AsyncLowering.ContextAlignment =
- AsyncId->getStorageAlignment().value();
- this->AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer();
- auto &Context = F.getContext();
- auto *Int8PtrTy = Type::getInt8PtrTy(Context);
- auto *VoidTy = Type::getVoidTy(Context);
- this->AsyncLowering.AsyncFuncTy =
- FunctionType::get(VoidTy, {Int8PtrTy, Int8PtrTy, Int8PtrTy}, false);
- break;
- };
+
case Intrinsic::coro_id_retcon:
case Intrinsic::coro_id_retcon_once: {
auto ContinuationId = cast<AnyCoroIdRetconInst>(Id);
@@ -537,8 +512,6 @@ Value *coro::Shape::emitAlloc(IRBuilder<> &Builder, Value *Size,
addCallToCallGraph(CG, Call, Alloc);
return Call;
}
- case coro::ABI::Async:
- llvm_unreachable("can't allocate memory in coro async-lowering");
}
llvm_unreachable("Unknown coro::ABI enum");
}
@@ -559,8 +532,6 @@ void coro::Shape::emitDealloc(IRBuilder<> &Builder, Value *Ptr,
addCallToCallGraph(CG, Call, Dealloc);
return;
}
- case coro::ABI::Async:
- llvm_unreachable("can't allocate memory in coro async-lowering");
}
llvm_unreachable("Unknown coro::ABI enum");
}
@@ -662,32 +633,6 @@ void AnyCoroIdRetconInst::checkWellFormed() const {
checkWFDealloc(this, getArgOperand(DeallocArg));
}
-static void checkAsyncFuncPointer(const Instruction *I, Value *V) {
- auto *AsyncFuncPtrAddr = dyn_cast<GlobalVariable>(V->stripPointerCasts());
- if (!AsyncFuncPtrAddr)
- fail(I, "llvm.coro.id.async async function pointer not a global", V);
-
- auto *StructTy = dyn_cast<StructType>(
- AsyncFuncPtrAddr->getType()->getPointerElementType());
- if (StructTy->isOpaque() || !StructTy->isPacked() ||
- StructTy->getNumElements() != 2 ||
- !StructTy->getElementType(0)->isIntegerTy(32) ||
- !StructTy->getElementType(1)->isIntegerTy(32))
- fail(I,
- "llvm.coro.id.async async function pointer argument's type is not "
- "<{i32, i32}>",
- V);
-}
-
-void CoroIdAsyncInst::checkWellFormed() const {
- // TODO: check that the StorageArg is a parameter of this function.
- checkConstantInt(this, getArgOperand(SizeArg),
- "size argument to coro.id.async must be constant");
- checkConstantInt(this, getArgOperand(AlignArg),
- "alignment argument to coro.id.async must be constant");
- checkAsyncFuncPointer(this, getArgOperand(AsyncFuncPtrArg));
-}
-
void LLVMAddCoroEarlyPass(LLVMPassManagerRef PM) {
unwrap(PM)->add(createCoroEarlyLegacyPass());
}
diff --git a/llvm/test/Transforms/Coroutines/coro-async.ll b/llvm/test/Transforms/Coroutines/coro-async.ll
deleted file mode 100644
index 79e5b66dd9cf..000000000000
--- a/llvm/test/Transforms/Coroutines/coro-async.ll
+++ /dev/null
@@ -1,241 +0,0 @@
-; RUN: opt < %s -enable-coroutines -O2 -S | FileCheck --check-prefixes=CHECK %s
-
-target datalayout = "p:64:64:64"
-
-%async.task = type { i64 }
-%async.actor = type { i64 }
-%async.fp = type <{ i32, i32 }>
-
-%async.ctxt = type { i8*, void (i8*, %async.task*, %async.actor*)* }
-
-; The async callee.
- at my_other_async_function_fp = external global <{ i32, i32 }>
-declare void @my_other_async_function(i8* %async.ctxt)
-
-; The current async function (the caller).
-; This struct describes an async function. The first field is the size needed
-; for the async context of the current async function, the second field is the
-; relative offset to the async function implementation.
- at my_async_function_fp = constant <{ i32, i32 }>
- <{ i32 128, ; Initial async context size without space for frame
- i32 trunc ( ; Relative pointer to async function
- i64 sub (
- i64 ptrtoint (void (i8*, %async.task*, %async.actor*)* @my_async_function to i64),
- i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @my_async_function_fp, i32 0, i32 1) to i64)
- )
- to i32)
- }>
-
-; Function that implements the dispatch to the callee function.
-define swiftcc void @my_async_function.my_other_async_function_fp.apply(i8* %async.ctxt, %async.task* %task, %async.actor* %actor) {
- musttail call swiftcc void @asyncSuspend(i8* %async.ctxt, %async.task* %task, %async.actor* %actor)
- ret void
-}
-
-declare void @some_user(i64)
-declare void @some_may_write(i64*)
-
-define swiftcc void @my_async_function(i8* %async.ctxt, %async.task* %task, %async.actor* %actor) {
-entry:
- %tmp = alloca { i64, i64 }, align 8
- %proj.1 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %tmp, i64 0, i32 0
- %proj.2 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %tmp, i64 0, i32 1
-
- %id = call token @llvm.coro.id.async(i32 128, i32 16, i8* %async.ctxt, i8* bitcast (<{i32, i32}>* @my_async_function_fp to i8*))
- %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
- store i64 0, i64* %proj.1, align 8
- store i64 1, i64* %proj.2, align 8
- call void @some_may_write(i64* %proj.1)
-
- ; Begin lowering: apply %my_other_async_function(%args...)
-
- ; setup callee context
- %arg0 = bitcast %async.task* %task to i8*
- %arg1 = bitcast <{ i32, i32}>* @my_other_async_function_fp to i8*
- %callee_context = call i8* @llvm.coro.async.context.alloc(i8* %arg0, i8* %arg1)
- %callee_context.0 = bitcast i8* %callee_context to %async.ctxt*
- ; store arguments ...
- ; ... (omitted)
-
- ; store the return continuation
- %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 1
- %return_to_caller.addr = bitcast void(i8*, %async.task*, %async.actor*)** %callee_context.return_to_caller.addr to i8**
- %resume.func_ptr = call i8* @llvm.coro.async.resume()
- store i8* %resume.func_ptr, i8** %return_to_caller.addr
-
- ; store caller context into callee context
- %callee_context.caller_context.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 0
- store i8* %async.ctxt, i8** %callee_context.caller_context.addr
-
- %res = call {i8*, i8*, i8*} (i8*, i8*, ...) @llvm.coro.suspend.async(
- i8* %resume.func_ptr,
- i8* %callee_context,
- void (i8*, %async.task*, %async.actor*)* @my_async_function.my_other_async_function_fp.apply,
- i8* %callee_context, %async.task* %task, %async.actor *%actor)
-
- call void @llvm.coro.async.context.dealloc(i8* %callee_context)
- %continuation_task_arg = extractvalue {i8*, i8*, i8*} %res, 1
- %task.2 = bitcast i8* %continuation_task_arg to %async.task*
- %val = load i64, i64* %proj.1
- call void @some_user(i64 %val)
- %val.2 = load i64, i64* %proj.2
- call void @some_user(i64 %val.2)
-
- tail call swiftcc void @asyncReturn(i8* %async.ctxt, %async.task* %task.2, %async.actor* %actor)
- call i1 @llvm.coro.end(i8* %hdl, i1 0)
- unreachable
-}
-
-; Make sure we update the async function pointer
-; CHECK: @my_async_function_fp = constant <{ i32, i32 }> <{ i32 168,
-; CHECK: @my_async_function2_fp = constant <{ i32, i32 }> <{ i32 168,
-
-; CHECK-LABEL: define swiftcc void @my_async_function(i8* %async.ctxt, %async.task* %task, %async.actor* %actor) {
-; CHECK: entry:
-; CHECK: [[FRAMEPTR:%.*]] = getelementptr inbounds i8, i8* %async.ctxt, i64 128
-; CHECK: [[ACTOR_SPILL_ADDR:%.*]] = getelementptr inbounds i8, i8* %async.ctxt, i64 152
-; CHECK: [[CAST1:%.*]] = bitcast i8* [[ACTOR_SPILL_ADDR]] to %async.actor**
-; CHECK: store %async.actor* %actor, %async.actor** [[CAST1]]
-; CHECK: [[ADDR1:%.*]] = getelementptr inbounds i8, i8* %async.ctxt, i64 144
-; CHECK: [[ASYNC_CTXT_SPILL_ADDR:%.*]] = bitcast i8* [[ADDR1]] to i8**
-; CHECK: store i8* %async.ctxt, i8** [[ASYNC_CTXT_SPILL_ADDR]]
-; CHECK: [[ALLOCA_PRJ1:%.*]] = bitcast i8* [[FRAMEPTR]] to i64*
-; CHECK: [[ALLOCA_PRJ2:%.*]] = getelementptr inbounds i8, i8* %async.ctxt, i64 136
-; CHECK: [[ADDR2:%.*]] = bitcast i8* [[ALLOCA_PRJ2]] to i64*
-; CHECK: store i64 0, i64* [[ALLOCA_PRJ1]]
-; CHECK: store i64 1, i64* [[ADDR2]]
-; CHECK: tail call void @some_may_write(i64* nonnull %proj.1)
-; CHECK: [[TASK:%.*]] = bitcast %async.task* %task to i8*
-; CHECK: [[CALLEE_CTXT:%.*]] = tail call i8* @llvm.coro.async.context.alloc(i8* [[TASK]], i8* bitcast (<{ i32, i32 }>* @my_other_async_function_fp to i8*))
-; CHECK: [[CALLEE_CTXT_SPILL:%.*]] = getelementptr inbounds i8, i8* %async.ctxt, i64 160
-; CHECK: [[CAST2:%.*]] = bitcast i8* [[CALLEE_CTXT_SPILL]] to i8**
-; CHECK: store i8* [[CALLEE_CTXT]], i8** [[CAST2]]
-; CHECK: [[TYPED_RETURN_TO_CALLER_ADDR:%.*]] = getelementptr inbounds i8, i8* [[CALLEE_CTXT]], i64 8
-; CHECK: [[RETURN_TO_CALLER_ADDR:%.*]] = bitcast i8* [[TYPED_RETURN_TO_CALLER_ADDR]] to i8**
-; CHECK: store i8* bitcast (void (i8*, i8*, i8*)* @my_async_function.resume.0 to i8*), i8** [[RETURN_TO_CALLER_ADDR]]
-; CHECK: [[CALLER_CONTEXT_ADDR:%.*]] = bitcast i8* [[CALLEE_CTXT]] to i8**
-; CHECK: store i8* %async.ctxt, i8** [[CALLER_CONTEXT_ADDR]]
-; CHECK: musttail call swiftcc void @my_async_function.my_other_async_function_fp.apply(i8* [[CALLEE_CTXT]], %async.task* %task, %async.actor* %actor)
-; CHECK: ret void
-; CHECK: }
-
-; CHECK-LABEL: define internal swiftcc void @my_async_function.resume.0(i8* %0, i8* %1, i8* %2) {
-; CHECK: entryresume.0:
-; CHECK: [[CALLER_CONTEXT_ADDR:%.*]] = bitcast i8* %0 to i8**
-; CHECK: [[CALLER_CONTEXT:%.*]] = load i8*, i8** [[CALLER_CONTEXT_ADDR]]
-; CHECK: [[FRAME_PTR:%.*]] = getelementptr inbounds i8, i8* [[CALLER_CONTEXT]], i64 128
-; CHECK: [[CALLEE_CTXT_SPILL_ADDR:%.*]] = getelementptr inbounds i8, i8* [[CALLER_CONTEXT]], i64 160
-; CHECK: [[CAST1:%.*]] = bitcast i8* [[CALLEE_CTXT_SPILL_ADDR]] to i8**
-; CHECK: [[CALLEE_CTXT_RELOAD:%.*]] = load i8*, i8** [[CAST1]]
-; CHECK: [[ACTOR_RELOAD_ADDR:%.*]] = getelementptr inbounds i8, i8* [[CALLER_CONTEXT]], i64 152
-; CHECK: [[CAST2:%.*]] = bitcast i8* [[ACTOR_RELOAD_ADDR]] to %async.actor**
-; CHECK: [[ACTOR_RELOAD:%.*]] = load %async.actor*, %async.actor** [[CAST2]]
-; CHECK: [[ADDR1:%.*]] = getelementptr inbounds i8, i8* %4, i64 144
-; CHECK: [[ASYNC_CTXT_RELOAD_ADDR:%.*]] = bitcast i8* [[ADDR1]] to i8**
-; CHECK: [[ASYNC_CTXT_RELOAD:%.*]] = load i8*, i8** [[ASYNC_CTXT_RELOAD_ADDR]]
-; CHECK: [[ALLOCA_PRJ2:%.*]] = getelementptr inbounds i8, i8* [[CALLER_CONTEXT]], i64 136
-; CHECK: [[ADDR2:%.*]] = bitcast i8* [[ALLOCA_PRJ2]] to i64*
-; CHECK: [[ALLOCA_PRJ1:%.*]] = bitcast i8* [[FRAME_PTR]] to i64*
-; CHECK: tail call void @llvm.coro.async.context.dealloc(i8* [[CALLEE_CTXT_RELOAD]])
-; CHECK: [[TASK_ARG:%.*]] = bitcast i8* %1 to %async.task*
-; CHECK: [[VAL1:%.*]] = load i64, i64* [[ALLOCA_PRJ1]]
-; CHECK: tail call void @some_user(i64 [[VAL1]])
-; CHECK: [[VAL2:%.*]] = load i64, i64* [[ADDR2]]
-; CHECK: tail call void @some_user(i64 [[VAL2]])
-; CHECK: tail call swiftcc void @asyncReturn(i8* [[ASYNC_CTXT_RELOAD]], %async.task* [[TASK_ARG]], %async.actor* [[ACTOR_RELOAD]])
-; CHECK: ret void
-; CHECK: }
-
- at my_async_function2_fp = constant <{ i32, i32 }>
- <{ i32 128, ; Initial async context size without space for frame
- i32 trunc ( ; Relative pointer to async function
- i64 sub (
- i64 ptrtoint (void (i8*, %async.task*, %async.actor*)* @my_async_function2 to i64),
- i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @my_async_function2_fp, i32 0, i32 1) to i64)
- )
- to i32)
- }>
-
-define swiftcc void @my_async_function2(i8* %async.ctxt, %async.task* %task, %async.actor* %actor) {
-entry:
-
- %id = call token @llvm.coro.id.async(i32 128, i32 16, i8* %async.ctxt, i8* bitcast (<{i32, i32}>* @my_async_function2_fp to i8*))
- %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
- ; setup callee context
- %arg0 = bitcast %async.task* %task to i8*
- %arg1 = bitcast <{ i32, i32}>* @my_other_async_function_fp to i8*
- %callee_context = call i8* @llvm.coro.async.context.alloc(i8* %arg0, i8* %arg1)
-
- %callee_context.0 = bitcast i8* %callee_context to %async.ctxt*
- %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 1
- %return_to_caller.addr = bitcast void(i8*, %async.task*, %async.actor*)** %callee_context.return_to_caller.addr to i8**
- %resume.func_ptr = call i8* @llvm.coro.async.resume()
- store i8* %resume.func_ptr, i8** %return_to_caller.addr
- %callee_context.caller_context.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 0
- store i8* %async.ctxt, i8** %callee_context.caller_context.addr
- %res = call {i8*, i8*, i8*} (i8*, i8*, ...) @llvm.coro.suspend.async(
- i8* %resume.func_ptr,
- i8* %callee_context,
- void (i8*, %async.task*, %async.actor*)* @my_async_function.my_other_async_function_fp.apply,
- i8* %callee_context, %async.task* %task, %async.actor *%actor)
-
- %continuation_task_arg = extractvalue {i8*, i8*, i8*} %res, 1
- %task.2 = bitcast i8* %continuation_task_arg to %async.task*
-
- %callee_context.0.1 = bitcast i8* %callee_context to %async.ctxt*
- %callee_context.return_to_caller.addr.1 = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0.1, i32 0, i32 1
- %return_to_caller.addr.1 = bitcast void(i8*, %async.task*, %async.actor*)** %callee_context.return_to_caller.addr.1 to i8**
- %resume.func_ptr.1 = call i8* @llvm.coro.async.resume()
- store i8* %resume.func_ptr.1, i8** %return_to_caller.addr.1
- %callee_context.caller_context.addr.1 = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0.1, i32 0, i32 0
- store i8* %async.ctxt, i8** %callee_context.caller_context.addr.1
- %res.2 = call {i8*, i8*, i8*} (i8*, i8*, ...) @llvm.coro.suspend.async(
- i8* %resume.func_ptr.1,
- i8* %callee_context,
- void (i8*, %async.task*, %async.actor*)* @my_async_function.my_other_async_function_fp.apply,
- i8* %callee_context, %async.task* %task, %async.actor *%actor)
-
- call void @llvm.coro.async.context.dealloc(i8* %callee_context)
- %continuation_actor_arg = extractvalue {i8*, i8*, i8*} %res.2, 2
- %actor.2 = bitcast i8* %continuation_actor_arg to %async.actor*
-
- tail call swiftcc void @asyncReturn(i8* %async.ctxt, %async.task* %task.2, %async.actor* %actor.2)
- call i1 @llvm.coro.end(i8* %hdl, i1 0)
- unreachable
-}
-
-; CHECK-LABEL: define swiftcc void @my_async_function2(i8* %async.ctxt, %async.task* %task, %async.actor* %actor) {
-; CHECK: store %async.actor* %actor,
-; CHECK: store %async.task* %task,
-; CHECK: store i8* %async.ctxt,
-; CHECK: [[CALLEE_CTXT:%.*]] = tail call i8* @llvm.coro.async.context.alloc(
-; CHECK: store i8* [[CALLEE_CTXT]],
-; CHECK: store i8* bitcast (void (i8*, i8*, i8*)* @my_async_function2.resume.0 to i8*),
-; CHECK: store i8* %async.ctxt,
-; CHECK: musttail call swiftcc void @my_async_function.my_other_async_function_fp.apply(i8* [[CALLEE_CTXT]], %async.task* %task, %async.actor* %actor)
-; CHECK: ret void
-
-; CHECK-LABEL: define internal swiftcc void @my_async_function2.resume.0(i8* %0, i8* %1, i8* %2) {
-; CHECK: [[CALLEE_CTXT_ADDR:%.*]] = bitcast i8* %0 to i8**
-; CHECK: [[CALLEE_CTXT:%.*]] = load i8*, i8** [[CALLEE_CTXT_ADDR]]
-; CHECK: [[CALLEE_CTXT_SPILL_ADDR:%.*]] = getelementptr inbounds i8, i8* [[CALLEE_CTXT]], i64 152
-; CHECK: [[CALLEE_CTXT_SPILL_ADDR2:%.*]] = bitcast i8* [[CALLEE_CTXT_SPILL_ADDR]] to i8**
-; CHECK: store i8* bitcast (void (i8*, i8*, i8*)* @my_async_function2.resume.1 to i8*),
-; CHECK: [[CALLLE_CTXT_RELOAD:%.*]] = load i8*, i8** [[CALLEE_CTXT_SPILL_ADDR2]]
-; CHECK: musttail call swiftcc void @my_async_function.my_other_async_function_fp.apply(i8* [[CALLEE_CTXT_RELOAD]]
-; CHECK: ret void
-
-; CHECK-LABEL: define internal swiftcc void @my_async_function2.resume.1(i8* %0, i8* %1, i8* %2) {
-; CHECK: [[ACTOR_ARG:%.*]] = bitcast i8* %2
-; CHECK: tail call swiftcc void @asyncReturn({{.*}}[[ACTOR_ARG]])
-; CHECK: ret void
-
-declare token @llvm.coro.id.async(i32, i32, i8*, i8*)
-declare i8* @llvm.coro.begin(token, i8*)
-declare i1 @llvm.coro.end(i8*, i1)
-declare {i8*, i8*, i8*} @llvm.coro.suspend.async(i8*, i8*, ...)
-declare i8* @llvm.coro.async.context.alloc(i8*, i8*)
-declare void @llvm.coro.async.context.dealloc(i8*)
-declare swiftcc void @asyncReturn(i8*, %async.task*, %async.actor*)
-declare swiftcc void @asyncSuspend(i8*, %async.task*, %async.actor*)
-declare i8* @llvm.coro.async.resume()
More information about the llvm-commits
mailing list