41 : TheModule(M), Context(M.getContext()),
60 "makeSubFnCall: Index value out of range");
68 "llvm.coro.async.context.alloc",
69 "llvm.coro.async.context.dealloc",
70 "llvm.coro.async.resume",
71 "llvm.coro.async.size.replace",
72 "llvm.coro.async.store_resume",
73 "llvm.coro.await.suspend.bool",
74 "llvm.coro.await.suspend.handle",
75 "llvm.coro.await.suspend.void",
77 "llvm.coro.begin.custom.abi",
81 "llvm.coro.end.async",
86 "llvm.coro.id.retcon",
87 "llvm.coro.id.retcon.once",
89 "llvm.coro.prepare.async",
90 "llvm.coro.prepare.retcon",
95 "llvm.coro.subfn.addr",
97 "llvm.coro.suspend.async",
98 "llvm.coro.suspend.retcon",
108 return isa<AnyCoroSuspendInst>(BB->
front());
113 if (M.getNamedValue(
Name))
123 const std::initializer_list<StringRef>
List) {
126 if (M.getNamedValue(
Name))
138 if (
auto CF = dyn_cast<CoroFreeInst>(U))
141 if (CoroFrees.
empty())
147 : CoroFrees.
front()->getFrame();
150 CF->replaceAllUsesWith(Replacement);
151 CF->eraseFromParent();
158 if (
auto *CA = dyn_cast<CoroAllocInst>(U))
161 if (CoroAllocs.
empty())
176 for (
auto *CA : CoroAllocs) {
177 CA->replaceAllUsesWith(False);
178 CA->eraseFromParent();
186 auto *SaveInst = cast<CoroSaveInst>(
199 bool HasFinalSuspend =
false;
200 bool HasUnwindCoroEnd =
false;
201 size_t FinalSuspendIndex = 0;
206 if (
auto AWS = dyn_cast<CoroAwaitSuspendInst>(&
I)) {
207 CoroAwaitSuspends.push_back(AWS);
208 }
else if (
auto II = dyn_cast<IntrinsicInst>(&
I)) {
209 switch (
II->getIntrinsicID()) {
212 case Intrinsic::coro_size:
213 CoroSizes.push_back(cast<CoroSizeInst>(
II));
215 case Intrinsic::coro_align:
216 CoroAligns.push_back(cast<CoroAlignInst>(
II));
218 case Intrinsic::coro_frame:
221 case Intrinsic::coro_save:
227 case Intrinsic::coro_suspend_async: {
228 auto *Suspend = cast<CoroSuspendAsyncInst>(
II);
229 Suspend->checkWellFormed();
230 CoroSuspends.push_back(Suspend);
233 case Intrinsic::coro_suspend_retcon: {
234 auto Suspend = cast<CoroSuspendRetconInst>(
II);
235 CoroSuspends.push_back(Suspend);
238 case Intrinsic::coro_suspend: {
239 auto Suspend = cast<CoroSuspendInst>(
II);
240 CoroSuspends.push_back(Suspend);
241 if (Suspend->isFinal()) {
244 "Only one suspend point can be marked as final");
245 HasFinalSuspend =
true;
246 FinalSuspendIndex = CoroSuspends.size() - 1;
250 case Intrinsic::coro_begin:
251 case Intrinsic::coro_begin_custom_abi: {
252 auto CB = cast<CoroBeginInst>(
II);
255 auto Id = dyn_cast<CoroIdInst>(CB->getId());
256 if (Id && !Id->getInfo().isPreSplit())
261 "coroutine should have exactly one defining @llvm.coro.begin");
262 CB->addRetAttr(Attribute::NonNull);
263 CB->addRetAttr(Attribute::NoAlias);
264 CB->removeFnAttr(Attribute::NoDuplicate);
268 case Intrinsic::coro_end_async:
269 case Intrinsic::coro_end:
270 CoroEnds.push_back(cast<AnyCoroEndInst>(
II));
271 if (
auto *AsyncEnd = dyn_cast<CoroAsyncEndInst>(
II)) {
272 AsyncEnd->checkWellFormed();
275 if (CoroEnds.back()->isUnwind())
276 HasUnwindCoroEnd =
true;
278 if (CoroEnds.back()->isFallthrough() && isa<CoroEndInst>(
II)) {
282 if (CoroEnds.size() > 1) {
283 if (CoroEnds.front()->isFallthrough())
285 "Only one coro.end can be marked as fallthrough");
286 std::swap(CoroEnds.front(), CoroEnds.back());
299 auto Id = CoroBegin->getId();
300 switch (
auto IntrID = Id->getIntrinsicID()) {
301 case Intrinsic::coro_id: {
303 SwitchLowering.HasFinalSuspend = HasFinalSuspend;
304 SwitchLowering.HasUnwindCoroEnd = HasUnwindCoroEnd;
306 auto SwitchId = getSwitchCoroId();
307 SwitchLowering.ResumeSwitch =
nullptr;
308 SwitchLowering.PromiseAlloca = SwitchId->getPromise();
309 SwitchLowering.ResumeEntryBlock =
nullptr;
312 if (SwitchLowering.HasFinalSuspend &&
313 FinalSuspendIndex != CoroSuspends.size() - 1)
314 std::swap(CoroSuspends[FinalSuspendIndex], CoroSuspends.back());
317 case Intrinsic::coro_id_async: {
319 auto *AsyncId = getAsyncCoroId();
320 AsyncId->checkWellFormed();
321 AsyncLowering.Context = AsyncId->getStorage();
322 AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex();
323 AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize();
324 AsyncLowering.ContextAlignment = AsyncId->getStorageAlignment().value();
325 AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer();
326 AsyncLowering.AsyncCC =
F.getCallingConv();
329 case Intrinsic::coro_id_retcon:
330 case Intrinsic::coro_id_retcon_once: {
333 auto ContinuationId = getRetconCoroId();
334 ContinuationId->checkWellFormed();
335 auto Prototype = ContinuationId->getPrototype();
336 RetconLowering.ResumePrototype = Prototype;
337 RetconLowering.Alloc = ContinuationId->getAllocFunction();
338 RetconLowering.Dealloc = ContinuationId->getDeallocFunction();
339 RetconLowering.ReturnBlock =
nullptr;
340 RetconLowering.IsFrameInlineInStorage =
false;
357 CF->replaceAllUsesWith(
Poison);
358 CF->eraseFromParent();
366 CS->eraseFromParent();
367 if (
auto *CoroSave = CS->getCoroSave())
368 CoroSave->eraseFromParent();
370 CoroSuspends.clear();
382 auto Suspend = dyn_cast<CoroSuspendInst>(AnySuspend);
390 if (!Suspend->getCoroSave())
407 auto Suspend = dyn_cast<CoroSuspendRetconInst>(AnySuspend);
413 "coro.suspend.retcon");
417 auto SI = Suspend->value_begin(), SE = Suspend->value_end();
418 auto RI = ResultTys.begin(), RE = ResultTys.end();
419 for (; SI != SE && RI != RE; ++SI, ++RI) {
420 auto SrcTy = (*SI)->getType();
426 auto BCI =
new BitCastInst(*SI, *RI,
"", Suspend->getIterator());
436 "match corresponding prototype function result");
439 if (SI != SE || RI != RE) {
448 Type *SResultTy = Suspend->getType();
452 }
else if (
auto SResultStructTy = dyn_cast<StructType>(SResultTy)) {
453 SuspendResultTys = SResultStructTy->elements();
456 SuspendResultTys = SResultTy;
458 if (SuspendResultTys.
size() != ResumeTys.size()) {
465 for (
size_t I = 0, E = ResumeTys.size();
I != E; ++
I) {
466 if (SuspendResultTys[
I] != ResumeTys[
I]) {
472 "match corresponding prototype function param");
484 CF->replaceAllUsesWith(CoroBegin);
485 CF->eraseFromParent();
491 CoroSave->eraseFromParent();
492 UnusedCoroSaves.
clear();
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",
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 void checkWFDealloc(const Instruction *I, Value *V)
Check that the given value is a well-formed deallocator.
static bool isCoroutineIntrinsicName(StringRef Name)
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 const char *const CoroIntrinsics[]
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
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallVector class.
This represents either the llvm.coro.id.retcon or llvm.coro.id.retcon.once instruction.
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 bool isBitCastable(Type *SrcTy, Type *DestTy)
Check whether a bitcast between these types is valid.
static ConstantInt * getFalse(LLVMContext &Context)
A constant pointer value that points to null.
static ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
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.
void checkWellFormed() const
This represents the llvm.coro.id instruction.
This represents the llvm.coro.save instruction.
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...
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
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 PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static 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.
StringRef - Represent a constant reference to a string, i.e.
The instances of the Type class are immutable: once they are created, they are never changed.
static IntegerType * getInt8Ty(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
LLVM Value Representation.
iterator_range< user_iterator > users()
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.
Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
@ 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)
bool declaresIntrinsics(const Module &M, const std::initializer_list< StringRef >)
void suppressCoroAllocs(CoroIdInst *CoroId)
Replaces all @llvm.coro.alloc intrinsics calls associated with a given call @llvm....
void replaceCoroFree(CoroIdInst *CoroId, bool Elide)
This is an optimization pass for GlobalISel generic memory operations.
auto binary_search(R &&Range, T &&Value)
Provide wrappers to std::binary_search which take ranges instead of having to pass begin/end explicit...
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
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...
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
ArrayRef< Type * > getRetconResumeTypes() const
SmallVector< AnyCoroSuspendInst *, 4 > CoroSuspends
Value * emitAlloc(IRBuilder<> &Builder, Value *Size, CallGraph *CG) const
Allocate memory according to the rules of the active lowering.
void cleanCoroutine(SmallVectorImpl< CoroFrameInst * > &CoroFrames, SmallVectorImpl< CoroSaveInst * > &UnusedCoroSaves)
CoroBeginInst * CoroBegin
ArrayRef< Type * > getRetconResultTypes() const
void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const
Deallocate memory according to the rules of the active lowering.
RetconLoweringStorage RetconLowering
void invalidateCoroutine(Function &F, SmallVectorImpl< CoroFrameInst * > &CoroFrames)
void analyze(Function &F, SmallVectorImpl< CoroFrameInst * > &CoroFrames, SmallVectorImpl< CoroSaveInst * > &UnusedCoroSaves)