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.await.suspend.bool",
73 "llvm.coro.await.suspend.handle",
74 "llvm.coro.await.suspend.void",
76 "llvm.coro.begin.custom.abi",
80 "llvm.coro.end.async",
85 "llvm.coro.id.retcon",
86 "llvm.coro.id.retcon.once",
88 "llvm.coro.prepare.async",
89 "llvm.coro.prepare.retcon",
94 "llvm.coro.subfn.addr",
96 "llvm.coro.suspend.async",
97 "llvm.coro.suspend.retcon",
107 return isa<AnyCoroSuspendInst>(BB->
front());
112 if (M.getNamedValue(
Name))
122 const std::initializer_list<StringRef>
List) {
125 if (M.getNamedValue(
Name))
137 if (
auto CF = dyn_cast<CoroFreeInst>(U))
140 if (CoroFrees.
empty())
146 : CoroFrees.
front()->getFrame();
149 CF->replaceAllUsesWith(Replacement);
150 CF->eraseFromParent();
157 if (
auto *CA = dyn_cast<CoroAllocInst>(U))
160 if (CoroAllocs.
empty())
175 for (
auto *CA : CoroAllocs) {
176 CA->replaceAllUsesWith(False);
177 CA->eraseFromParent();
185 auto *SaveInst = cast<CoroSaveInst>(
198 bool HasFinalSuspend =
false;
199 bool HasUnwindCoroEnd =
false;
200 size_t FinalSuspendIndex = 0;
205 if (
auto AWS = dyn_cast<CoroAwaitSuspendInst>(&
I)) {
206 CoroAwaitSuspends.push_back(AWS);
207 }
else if (
auto II = dyn_cast<IntrinsicInst>(&
I)) {
208 switch (
II->getIntrinsicID()) {
211 case Intrinsic::coro_size:
212 CoroSizes.push_back(cast<CoroSizeInst>(
II));
214 case Intrinsic::coro_align:
215 CoroAligns.push_back(cast<CoroAlignInst>(
II));
217 case Intrinsic::coro_frame:
220 case Intrinsic::coro_save:
226 case Intrinsic::coro_suspend_async: {
227 auto *Suspend = cast<CoroSuspendAsyncInst>(
II);
228 Suspend->checkWellFormed();
229 CoroSuspends.push_back(Suspend);
232 case Intrinsic::coro_suspend_retcon: {
233 auto Suspend = cast<CoroSuspendRetconInst>(
II);
234 CoroSuspends.push_back(Suspend);
237 case Intrinsic::coro_suspend: {
238 auto Suspend = cast<CoroSuspendInst>(
II);
239 CoroSuspends.push_back(Suspend);
240 if (Suspend->isFinal()) {
243 "Only one suspend point can be marked as final");
244 HasFinalSuspend =
true;
245 FinalSuspendIndex = CoroSuspends.size() - 1;
249 case Intrinsic::coro_begin:
250 case Intrinsic::coro_begin_custom_abi: {
251 auto CB = cast<CoroBeginInst>(
II);
254 auto Id = dyn_cast<CoroIdInst>(CB->getId());
255 if (Id && !Id->getInfo().isPreSplit())
260 "coroutine should have exactly one defining @llvm.coro.begin");
261 CB->addRetAttr(Attribute::NonNull);
262 CB->addRetAttr(Attribute::NoAlias);
263 CB->removeFnAttr(Attribute::NoDuplicate);
267 case Intrinsic::coro_end_async:
268 case Intrinsic::coro_end:
269 CoroEnds.push_back(cast<AnyCoroEndInst>(
II));
270 if (
auto *AsyncEnd = dyn_cast<CoroAsyncEndInst>(
II)) {
271 AsyncEnd->checkWellFormed();
274 if (CoroEnds.back()->isUnwind())
275 HasUnwindCoroEnd =
true;
277 if (CoroEnds.back()->isFallthrough() && isa<CoroEndInst>(
II)) {
281 if (CoroEnds.size() > 1) {
282 if (CoroEnds.front()->isFallthrough())
284 "Only one coro.end can be marked as fallthrough");
285 std::swap(CoroEnds.front(), CoroEnds.back());
298 auto Id = CoroBegin->getId();
299 switch (
auto IntrID = Id->getIntrinsicID()) {
300 case Intrinsic::coro_id: {
302 SwitchLowering.HasFinalSuspend = HasFinalSuspend;
303 SwitchLowering.HasUnwindCoroEnd = HasUnwindCoroEnd;
305 auto SwitchId = getSwitchCoroId();
306 SwitchLowering.ResumeSwitch =
nullptr;
307 SwitchLowering.PromiseAlloca = SwitchId->getPromise();
308 SwitchLowering.ResumeEntryBlock =
nullptr;
311 if (SwitchLowering.HasFinalSuspend &&
312 FinalSuspendIndex != CoroSuspends.size() - 1)
313 std::swap(CoroSuspends[FinalSuspendIndex], CoroSuspends.back());
316 case Intrinsic::coro_id_async: {
318 auto *AsyncId = getAsyncCoroId();
319 AsyncId->checkWellFormed();
320 AsyncLowering.Context = AsyncId->getStorage();
321 AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex();
322 AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize();
323 AsyncLowering.ContextAlignment = AsyncId->getStorageAlignment().value();
324 AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer();
325 AsyncLowering.AsyncCC =
F.getCallingConv();
328 case Intrinsic::coro_id_retcon:
329 case Intrinsic::coro_id_retcon_once: {
332 auto ContinuationId = getRetconCoroId();
333 ContinuationId->checkWellFormed();
334 auto Prototype = ContinuationId->getPrototype();
335 RetconLowering.ResumePrototype = Prototype;
336 RetconLowering.Alloc = ContinuationId->getAllocFunction();
337 RetconLowering.Dealloc = ContinuationId->getDeallocFunction();
338 RetconLowering.ReturnBlock =
nullptr;
339 RetconLowering.IsFrameInlineInStorage =
false;
356 CF->replaceAllUsesWith(
Poison);
357 CF->eraseFromParent();
365 CS->eraseFromParent();
366 if (
auto *CoroSave = CS->getCoroSave())
367 CoroSave->eraseFromParent();
369 CoroSuspends.clear();
381 auto Suspend = dyn_cast<CoroSuspendInst>(AnySuspend);
389 if (!Suspend->getCoroSave())
406 auto Suspend = dyn_cast<CoroSuspendRetconInst>(AnySuspend);
412 "coro.suspend.retcon");
416 auto SI = Suspend->value_begin(), SE = Suspend->value_end();
417 auto RI = ResultTys.begin(), RE = ResultTys.end();
418 for (; SI != SE && RI != RE; ++SI, ++RI) {
419 auto SrcTy = (*SI)->getType();
425 auto BCI =
new BitCastInst(*SI, *RI,
"", Suspend->getIterator());
435 "match corresponding prototype function result");
438 if (SI != SE || RI != RE) {
447 Type *SResultTy = Suspend->getType();
451 }
else if (
auto SResultStructTy = dyn_cast<StructType>(SResultTy)) {
452 SuspendResultTys = SResultStructTy->elements();
455 SuspendResultTys = SResultTy;
457 if (SuspendResultTys.
size() != ResumeTys.size()) {
464 for (
size_t I = 0, E = ResumeTys.size();
I != E; ++
I) {
465 if (SuspendResultTys[
I] != ResumeTys[
I]) {
471 "match corresponding prototype function param");
483 CF->replaceAllUsesWith(CoroBegin);
484 CF->eraseFromParent();
490 CoroSave->eraseFromParent();
491 UnusedCoroSaves.
clear();
495 Call->setCallingConv(Callee->getCallingConv());
501 (*CG)[Call->getFunction()]->addCalledFunction(Call, (*CG)[Callee]);
512 auto Alloc = RetconLowering.Alloc;
514 Alloc->getFunctionType()->getParamType(0),
535 auto Dealloc = RetconLowering.Dealloc;
537 Dealloc->getFunctionType()->getParamType(0));
554 errs() <<
" Value: ";
565 auto F = dyn_cast<Function>(V->stripPointerCasts());
567 fail(
I,
"llvm.coro.id.retcon.* prototype not a Function", V);
569 auto FT =
F->getFunctionType();
571 if (isa<CoroIdRetconInst>(
I)) {
573 if (FT->getReturnType()->isPointerTy()) {
575 }
else if (
auto SRetTy = dyn_cast<StructType>(FT->getReturnType())) {
576 ResultOkay = (!SRetTy->isOpaque() &&
577 SRetTy->getNumElements() > 0 &&
578 SRetTy->getElementType(0)->isPointerTy());
583 fail(
I,
"llvm.coro.id.retcon prototype must return pointer as first "
586 if (FT->getReturnType() !=
587 I->getFunction()->getFunctionType()->getReturnType())
588 fail(
I,
"llvm.coro.id.retcon prototype return type must be same as"
589 "current function return type",
F);
594 if (FT->getNumParams() == 0 || !FT->getParamType(0)->isPointerTy())
595 fail(
I,
"llvm.coro.id.retcon.* prototype must take pointer as "
596 "its first parameter",
F);
601 auto F = dyn_cast<Function>(V->stripPointerCasts());
603 fail(
I,
"llvm.coro.* allocator not a Function", V);
605 auto FT =
F->getFunctionType();
606 if (!FT->getReturnType()->isPointerTy())
607 fail(
I,
"llvm.coro.* allocator must return a pointer",
F);
609 if (FT->getNumParams() != 1 ||
610 !FT->getParamType(0)->isIntegerTy())
611 fail(
I,
"llvm.coro.* allocator must take integer as only param",
F);
616 auto F = dyn_cast<Function>(V->stripPointerCasts());
618 fail(
I,
"llvm.coro.* deallocator not a Function", V);
620 auto FT =
F->getFunctionType();
621 if (!FT->getReturnType()->isVoidTy())
622 fail(
I,
"llvm.coro.* deallocator must return void",
F);
624 if (FT->getNumParams() != 1 ||
625 !FT->getParamType(0)->isPointerTy())
626 fail(
I,
"llvm.coro.* deallocator must take pointer as only param",
F);
630 const char *Reason) {
631 if (!isa<ConstantInt>(V)) {
638 "size argument to coro.id.retcon.* must be constant");
640 "alignment argument to coro.id.retcon.* must be constant");
647 auto *AsyncFuncPtrAddr = dyn_cast<GlobalVariable>(V->stripPointerCasts());
648 if (!AsyncFuncPtrAddr)
649 fail(
I,
"llvm.coro.id.async async function pointer not a global", V);
654 "size argument to coro.id.async must be constant");
656 "alignment argument to coro.id.async must be constant");
658 "storage argument offset to coro.id.async must be constant");
664 auto *FunTy = cast<FunctionType>(
F->getValueType());
665 if (!FunTy->getReturnType()->isPointerTy())
667 "llvm.coro.suspend.async resume function projection function must "
670 if (FunTy->getNumParams() != 1 || !FunTy->getParamType(0)->isPointerTy())
672 "llvm.coro.suspend.async resume function projection function must "
673 "take one ptr type as parameter",
682 auto *MustTailCallFunc = getMustTailCallFunction();
683 if (!MustTailCallFunc)
685 auto *FnTy = MustTailCallFunc->getFunctionType();
686 if (FnTy->getNumParams() != (arg_size() - 3))
688 "llvm.coro.end.async must tail call function argument type must "
689 "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)