41 : TheModule(M),
Context(M.getContext()),
60 "makeSubFnCall: Index value out of range");
68 Intrinsic::coro_alloc,
69 Intrinsic::coro_async_context_alloc,
70 Intrinsic::coro_async_context_dealloc,
71 Intrinsic::coro_async_resume,
72 Intrinsic::coro_async_size_replace,
73 Intrinsic::coro_await_suspend_bool,
74 Intrinsic::coro_await_suspend_handle,
75 Intrinsic::coro_await_suspend_void,
76 Intrinsic::coro_begin,
77 Intrinsic::coro_begin_custom_abi,
78 Intrinsic::coro_destroy,
81 Intrinsic::coro_end_async,
82 Intrinsic::coro_frame,
85 Intrinsic::coro_id_async,
86 Intrinsic::coro_id_retcon,
87 Intrinsic::coro_id_retcon_once,
89 Intrinsic::coro_prepare_async,
90 Intrinsic::coro_prepare_retcon,
91 Intrinsic::coro_promise,
92 Intrinsic::coro_resume,
94 Intrinsic::coro_subfn_addr,
95 Intrinsic::coro_suspend,
99 return isa<AnyCoroSuspendInst>(BB->
front());
111 "Only non-overloaded intrinsics supported");
125 if (
auto CF = dyn_cast<CoroFreeInst>(U))
128 if (CoroFrees.
empty())
134 : CoroFrees.
front()->getFrame();
137 CF->replaceAllUsesWith(Replacement);
138 CF->eraseFromParent();
145 if (
auto *CA = dyn_cast<CoroAllocInst>(U))
148 if (CoroAllocs.
empty())
163 for (
auto *CA : CoroAllocs) {
164 CA->replaceAllUsesWith(False);
165 CA->eraseFromParent();
173 auto *SaveInst = cast<CoroSaveInst>(
187 bool HasFinalSuspend =
false;
188 bool HasUnwindCoroEnd =
false;
189 size_t FinalSuspendIndex = 0;
194 if (
auto AWS = dyn_cast<CoroAwaitSuspendInst>(&
I)) {
195 CoroAwaitSuspends.push_back(AWS);
196 }
else if (
auto II = dyn_cast<IntrinsicInst>(&
I)) {
197 switch (
II->getIntrinsicID()) {
200 case Intrinsic::coro_size:
201 CoroSizes.push_back(cast<CoroSizeInst>(
II));
203 case Intrinsic::coro_align:
204 CoroAligns.push_back(cast<CoroAlignInst>(
II));
206 case Intrinsic::coro_frame:
209 case Intrinsic::coro_save:
215 case Intrinsic::coro_suspend_async: {
216 auto *Suspend = cast<CoroSuspendAsyncInst>(
II);
217 Suspend->checkWellFormed();
218 CoroSuspends.push_back(Suspend);
221 case Intrinsic::coro_suspend_retcon: {
222 auto Suspend = cast<CoroSuspendRetconInst>(
II);
223 CoroSuspends.push_back(Suspend);
226 case Intrinsic::coro_suspend: {
227 auto Suspend = cast<CoroSuspendInst>(
II);
228 CoroSuspends.push_back(Suspend);
229 if (Suspend->isFinal()) {
232 "Only one suspend point can be marked as final");
233 HasFinalSuspend =
true;
234 FinalSuspendIndex = CoroSuspends.size() - 1;
238 case Intrinsic::coro_begin:
239 case Intrinsic::coro_begin_custom_abi: {
240 auto CB = cast<CoroBeginInst>(
II);
243 auto Id = dyn_cast<CoroIdInst>(CB->getId());
244 if (Id && !Id->getInfo().isPreSplit())
249 "coroutine should have exactly one defining @llvm.coro.begin");
250 CB->addRetAttr(Attribute::NonNull);
251 CB->addRetAttr(Attribute::NoAlias);
252 CB->removeFnAttr(Attribute::NoDuplicate);
256 case Intrinsic::coro_end_async:
257 case Intrinsic::coro_end:
258 CoroEnds.push_back(cast<AnyCoroEndInst>(
II));
259 if (
auto *AsyncEnd = dyn_cast<CoroAsyncEndInst>(
II)) {
260 AsyncEnd->checkWellFormed();
263 if (CoroEnds.back()->isUnwind())
264 HasUnwindCoroEnd =
true;
266 if (CoroEnds.back()->isFallthrough() && isa<CoroEndInst>(
II)) {
270 if (CoroEnds.size() > 1) {
271 if (CoroEnds.front()->isFallthrough())
273 "Only one coro.end can be marked as fallthrough");
274 std::swap(CoroEnds.front(), CoroEnds.back());
278 case Intrinsic::coro_promise:
279 assert(CoroPromise ==
nullptr &&
280 "CoroEarly must ensure coro.promise unique");
281 CoroPromise = cast<CoroPromiseInst>(
II);
292 auto Id = CoroBegin->getId();
293 switch (
auto IntrID = Id->getIntrinsicID()) {
294 case Intrinsic::coro_id: {
296 SwitchLowering.HasFinalSuspend = HasFinalSuspend;
297 SwitchLowering.HasUnwindCoroEnd = HasUnwindCoroEnd;
299 auto SwitchId = getSwitchCoroId();
300 SwitchLowering.ResumeSwitch =
nullptr;
301 SwitchLowering.PromiseAlloca = SwitchId->getPromise();
302 SwitchLowering.ResumeEntryBlock =
nullptr;
305 if (SwitchLowering.HasFinalSuspend &&
306 FinalSuspendIndex != CoroSuspends.size() - 1)
307 std::swap(CoroSuspends[FinalSuspendIndex], CoroSuspends.back());
310 case Intrinsic::coro_id_async: {
312 auto *AsyncId = getAsyncCoroId();
313 AsyncId->checkWellFormed();
314 AsyncLowering.Context = AsyncId->getStorage();
315 AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex();
316 AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize();
317 AsyncLowering.ContextAlignment = AsyncId->getStorageAlignment().value();
318 AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer();
319 AsyncLowering.AsyncCC =
F.getCallingConv();
322 case Intrinsic::coro_id_retcon:
323 case Intrinsic::coro_id_retcon_once: {
326 auto ContinuationId = getRetconCoroId();
327 ContinuationId->checkWellFormed();
328 auto Prototype = ContinuationId->getPrototype();
329 RetconLowering.ResumePrototype = Prototype;
330 RetconLowering.Alloc = ContinuationId->getAllocFunction();
331 RetconLowering.Dealloc = ContinuationId->getDeallocFunction();
332 RetconLowering.ReturnBlock =
nullptr;
333 RetconLowering.IsFrameInlineInStorage =
false;
350 CF->replaceAllUsesWith(
Poison);
351 CF->eraseFromParent();
359 CS->eraseFromParent();
360 if (
auto *CoroSave = CS->getCoroSave())
361 CoroSave->eraseFromParent();
363 CoroSuspends.clear();
375 auto Suspend = dyn_cast<CoroSuspendInst>(AnySuspend);
383 if (!Suspend->getCoroSave())
400 auto Suspend = dyn_cast<CoroSuspendRetconInst>(AnySuspend);
406 "coro.suspend.retcon");
410 auto SI = Suspend->value_begin(), SE = Suspend->value_end();
411 auto RI = ResultTys.begin(), RE = ResultTys.end();
412 for (; SI != SE && RI != RE; ++SI, ++RI) {
413 auto SrcTy = (*SI)->getType();
419 auto BCI =
new BitCastInst(*SI, *RI,
"", Suspend->getIterator());
429 "match corresponding prototype function result");
432 if (SI != SE || RI != RE) {
441 Type *SResultTy = Suspend->getType();
445 }
else if (
auto SResultStructTy = dyn_cast<StructType>(SResultTy)) {
446 SuspendResultTys = SResultStructTy->elements();
449 SuspendResultTys = SResultTy;
451 if (SuspendResultTys.
size() != ResumeTys.size()) {
458 for (
size_t I = 0, E = ResumeTys.size();
I != E; ++
I) {
459 if (SuspendResultTys[
I] != ResumeTys[
I]) {
465 "match corresponding prototype function param");
477 CF->replaceAllUsesWith(CoroBegin);
478 CF->eraseFromParent();
484 CoroSave->eraseFromParent();
485 UnusedCoroSaves.
clear();
489 ? cast<Value>(CoroBegin)
490 : cast<Value>(getPromiseAlloca()));
496 Call->setCallingConv(Callee->getCallingConv());
502 (*CG)[Call->getFunction()]->addCalledFunction(Call, (*CG)[Callee]);
513 auto Alloc = RetconLowering.Alloc;
515 Alloc->getFunctionType()->getParamType(0),
536 auto Dealloc = RetconLowering.Dealloc;
538 Dealloc->getFunctionType()->getParamType(0));
555 errs() <<
" Value: ";
566 auto F = dyn_cast<Function>(V->stripPointerCasts());
568 fail(
I,
"llvm.coro.id.retcon.* prototype not a Function", V);
570 auto FT =
F->getFunctionType();
572 if (isa<CoroIdRetconInst>(
I)) {
574 if (FT->getReturnType()->isPointerTy()) {
576 }
else if (
auto SRetTy = dyn_cast<StructType>(FT->getReturnType())) {
577 ResultOkay = (!SRetTy->isOpaque() &&
578 SRetTy->getNumElements() > 0 &&
579 SRetTy->getElementType(0)->isPointerTy());
584 fail(
I,
"llvm.coro.id.retcon prototype must return pointer as first "
587 if (FT->getReturnType() !=
588 I->getFunction()->getFunctionType()->getReturnType())
589 fail(
I,
"llvm.coro.id.retcon prototype return type must be same as"
590 "current function return type",
F);
595 if (FT->getNumParams() == 0 || !FT->getParamType(0)->isPointerTy())
596 fail(
I,
"llvm.coro.id.retcon.* prototype must take pointer as "
597 "its first parameter",
F);
602 auto F = dyn_cast<Function>(V->stripPointerCasts());
604 fail(
I,
"llvm.coro.* allocator not a Function", V);
606 auto FT =
F->getFunctionType();
607 if (!FT->getReturnType()->isPointerTy())
608 fail(
I,
"llvm.coro.* allocator must return a pointer",
F);
610 if (FT->getNumParams() != 1 ||
611 !FT->getParamType(0)->isIntegerTy())
612 fail(
I,
"llvm.coro.* allocator must take integer as only param",
F);
617 auto F = dyn_cast<Function>(V->stripPointerCasts());
619 fail(
I,
"llvm.coro.* deallocator not a Function", V);
621 auto FT =
F->getFunctionType();
622 if (!FT->getReturnType()->isVoidTy())
623 fail(
I,
"llvm.coro.* deallocator must return void",
F);
625 if (FT->getNumParams() != 1 ||
626 !FT->getParamType(0)->isPointerTy())
627 fail(
I,
"llvm.coro.* deallocator must take pointer as only param",
F);
631 const char *Reason) {
632 if (!isa<ConstantInt>(V)) {
639 "size argument to coro.id.retcon.* must be constant");
641 "alignment argument to coro.id.retcon.* must be constant");
648 auto *AsyncFuncPtrAddr = dyn_cast<GlobalVariable>(V->stripPointerCasts());
649 if (!AsyncFuncPtrAddr)
650 fail(
I,
"llvm.coro.id.async async function pointer not a global", V);
655 "size argument to coro.id.async must be constant");
657 "alignment argument to coro.id.async must be constant");
659 "storage argument offset to coro.id.async must be constant");
665 auto *FunTy = cast<FunctionType>(
F->getValueType());
666 if (!FunTy->getReturnType()->isPointerTy())
668 "llvm.coro.suspend.async resume function projection function must "
671 if (FunTy->getNumParams() != 1 || !FunTy->getParamType(0)->isPointerTy())
673 "llvm.coro.suspend.async resume function projection function must "
674 "take one ptr type as parameter",
683 auto *MustTailCallFunc = getMustTailCallFunction();
684 if (!MustTailCallFunc)
686 auto *FnTy = MustTailCallFunc->getFunctionType();
687 if (FnTy->getNumParams() != (arg_size() - 3))
689 "llvm.coro.end.async must tail call function argument type must "
690 "match the tail arguments",
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Expand Atomic instructions
This file contains the simple types necessary to represent the attributes associated with functions a...
static void fail(const SDLoc &DL, SelectionDAG &DAG, const Twine &Msg, SDValue Val={})
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static Intrinsic::ID NonOverloadedCoroIntrinsics[]
static void checkWFDealloc(const Instruction *I, Value *V)
Check that the given value is a well-formed deallocator.
static void checkConstantInt(const Instruction *I, Value *V, const char *Reason)
static void checkWFRetconPrototype(const AnyCoroIdRetconInst *I, Value *V)
Check that the given value is a well-formed prototype for the llvm.coro.id.retcon.
static void propagateCallAttrsFromCallee(CallInst *Call, Function *Callee)
static void checkAsyncContextProjectFunction(const Instruction *I, Function *F)
static CoroSaveInst * createCoroSave(CoroBeginInst *CoroBegin, CoroSuspendInst *SuspendInst)
static void checkWFAlloc(const Instruction *I, Value *V)
Check that the given value is a well-formed allocator.
static void addCallToCallGraph(CallGraph *CG, CallInst *Call, Function *Callee)
static void checkAsyncFuncPointer(const Instruction *I, Value *V)
Module.h This file contains the declarations for the Module class.
uint64_t IntrinsicInst * II
This file defines the SmallVector class.
This represents either the llvm.coro.id.retcon or llvm.coro.id.retcon.once instruction.
LLVM_ABI void checkWellFormed() const
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
LLVM Basic Block Representation.
const Instruction & front() const
This class represents a no-op cast from one type to another.
void setArgOperand(unsigned i, Value *v)
The basic data container for the call graph of a Module of IR.
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static LLVM_ABI bool isBitCastable(Type *SrcTy, Type *DestTy)
Check whether a bitcast between these types is valid.
static LLVM_ABI ConstantInt * getFalse(LLVMContext &Context)
A constant pointer value that points to null.
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
LLVM_ABI void checkWellFormed() const
This class represents the llvm.coro.begin or llvm.coro.begin.custom.abi instructions.
This represents the llvm.coro.frame instruction.
This represents the llvm.coro.free instruction.
LLVM_ABI void checkWellFormed() const
This represents the llvm.coro.id instruction.
This represents the llvm.coro.promise instruction.
bool isFromPromise() const
Are we translating from the frame to the promise (false) or from the promise to the frame (true)?
This represents the llvm.coro.save instruction.
LLVM_ABI void checkWellFormed() const
This represents the llvm.coro.suspend instruction.
CoroSaveInst * getCoroSave() const
Class to represent function types.
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateIntCast(Value *V, Type *DestTy, bool isSigned, const Twine &Name="")
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
This is an important class for using LLVM in a threaded context.
A Module instance is used to store all the information related to an LLVM module.
Class to represent pointers.
static LLVM_ABI PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI void dump() const
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
LLVM Value Representation.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
LLVM_ABI LLVMContext & getContext() const
All values hold a context through their type.
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
LLVM_ABI Function * getDeclarationIfExists(const Module *M, ID id)
Look up the Function declaration of the intrinsic id in the Module M and return it if it exists.
LLVM_ABI bool isOverloaded(ID id)
Returns true if the intrinsic can be overloaded.
@ Async
The "async continuation" lowering, where each suspend point creates a single continuation function.
@ RetconOnce
The "unique returned-continuation" lowering, where each suspend point creates a single continuation f...
@ Retcon
The "returned-continuation" lowering, where each suspend point creates a single continuation function...
@ Switch
The "resume-switch" lowering, where there are separate resume and destroy functions that are shared b...
bool declaresAnyIntrinsic(const Module &M)
bool isSuspendBlock(BasicBlock *BB)
void suppressCoroAllocs(CoroIdInst *CoroId)
Replaces all @llvm.coro.alloc intrinsics calls associated with a given call @llvm....
void replaceCoroFree(CoroIdInst *CoroId, bool Elide)
bool declaresIntrinsics(const Module &M, ArrayRef< Intrinsic::ID > List)
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI unsigned changeToUnreachable(Instruction *I, bool PreserveLCSSA=false, DomTreeUpdater *DTU=nullptr, MemorySSAUpdater *MSSAU=nullptr)
Insert an unreachable instruction before the specified instruction, making it and the rest of the cod...
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
CallInst * makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt)
Function * ResumePrototype
LLVM_ABI void cleanCoroutine(SmallVectorImpl< CoroFrameInst * > &CoroFrames, SmallVectorImpl< CoroSaveInst * > &UnusedCoroSaves, CoroPromiseInst *CoroPromise)
LLVM_ABI void analyze(Function &F, SmallVectorImpl< CoroFrameInst * > &CoroFrames, SmallVectorImpl< CoroSaveInst * > &UnusedCoroSaves, CoroPromiseInst *&CoroPromise)
ArrayRef< Type * > getRetconResumeTypes() const
SmallVector< AnyCoroSuspendInst *, 4 > CoroSuspends
LLVM_ABI Value * emitAlloc(IRBuilder<> &Builder, Value *Size, CallGraph *CG) const
Allocate memory according to the rules of the active lowering.
CoroBeginInst * CoroBegin
ArrayRef< Type * > getRetconResultTypes() const
LLVM_ABI void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const
Deallocate memory according to the rules of the active lowering.
RetconLoweringStorage RetconLowering
LLVM_ABI void invalidateCoroutine(Function &F, SmallVectorImpl< CoroFrameInst * > &CoroFrames)