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,
96 Intrinsic::coro_is_in_ramp,
112 "Only non-overloaded intrinsics supported");
136 CF->replaceAllUsesWith(Replacement);
137 CF->eraseFromParent();
140 for (
auto *CD : CoroDeads)
141 CD->eraseFromParent();
150 if (CoroAllocs.
empty())
165 for (
auto *CA : CoroAllocs) {
166 CA->replaceAllUsesWith(False);
167 CA->eraseFromParent();
188 bool HasFinalSuspend =
false;
189 bool HasUnwindCoroEnd =
false;
190 size_t FinalSuspendIndex = 0;
198 switch (
II->getIntrinsicID()) {
201 case Intrinsic::coro_size:
204 case Intrinsic::coro_align:
207 case Intrinsic::coro_frame:
210 case Intrinsic::coro_save:
216 case Intrinsic::coro_suspend_async: {
218 Suspend->checkWellFormed();
222 case Intrinsic::coro_suspend_retcon: {
227 case Intrinsic::coro_suspend: {
230 if (Suspend->isFinal()) {
233 "Only one suspend point can be marked as final");
234 HasFinalSuspend =
true;
239 case Intrinsic::coro_begin:
240 case Intrinsic::coro_begin_custom_abi: {
245 if (Id && !Id->getInfo().isPreSplit())
250 "coroutine should have exactly one defining @llvm.coro.begin");
251 CB->addRetAttr(Attribute::NonNull);
252 CB->addRetAttr(Attribute::NoAlias);
253 CB->removeFnAttr(Attribute::NoDuplicate);
257 case Intrinsic::coro_end_async:
258 case Intrinsic::coro_end:
261 AsyncEnd->checkWellFormed();
265 HasUnwindCoroEnd =
true;
272 if (
CoroEnds.front()->isFallthrough())
274 "Only one coro.end can be marked as fallthrough");
279 case Intrinsic::coro_is_in_ramp:
292 switch (
auto IntrID = Id->getIntrinsicID()) {
293 case Intrinsic::coro_id: {
309 case Intrinsic::coro_id_async: {
312 AsyncId->checkWellFormed();
314 AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex();
316 AsyncLowering.ContextAlignment = AsyncId->getStorageAlignment().value();
317 AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer();
321 case Intrinsic::coro_id_retcon:
322 case Intrinsic::coro_id_retcon_once: {
326 ContinuationId->checkWellFormed();
327 auto Prototype = ContinuationId->getPrototype();
349 CF->replaceAllUsesWith(
Poison);
350 CF->eraseFromParent();
358 if (
auto *CoroSave = CS->getCoroSave())
359 CoroSave->eraseFromParent();
360 CS->eraseFromParent();
373 for (
auto *AnySuspend :
Shape.CoroSuspends) {
382 if (!Suspend->getCoroSave())
395 auto ResultTys =
Shape.getRetconResultTypes();
396 auto ResumeTys =
Shape.getRetconResumeTypes();
398 for (
auto *AnySuspend :
Shape.CoroSuspends) {
405 "coro.suspend.retcon");
409 auto SI = Suspend->value_begin(), SE = Suspend->value_end();
410 auto RI = ResultTys.begin(), RE = ResultTys.end();
411 for (;
SI != SE && RI != RE; ++
SI, ++RI) {
412 auto SrcTy = (*SI)->getType();
418 auto BCI =
new BitCastInst(*
SI, *RI,
"", Suspend->getIterator());
425 Shape.RetconLowering.ResumePrototype->getFunctionType()->dump();
428 "match corresponding prototype function result");
431 if (
SI != SE || RI != RE) {
434 Shape.RetconLowering.ResumePrototype->getFunctionType()->dump();
440 Type *SResultTy = Suspend->getType();
445 SuspendResultTys = SResultStructTy->elements();
448 SuspendResultTys = SResultTy;
450 if (SuspendResultTys.
size() != ResumeTys.size()) {
453 Shape.RetconLowering.ResumePrototype->getFunctionType()->dump();
457 for (
size_t I = 0, E = ResumeTys.size();
I != E; ++
I) {
458 if (SuspendResultTys[
I] != ResumeTys[
I]) {
461 Shape.RetconLowering.ResumePrototype->getFunctionType()->dump();
464 "match corresponding prototype function param");
477 CF->eraseFromParent();
483 CoroSave->eraseFromParent();
484 UnusedCoroSaves.
clear();
488 Call->setCallingConv(Callee->getCallingConv());
494 (*CG)[
Call->getFunction()]->addCalledFunction(
Call, (*CG)[Callee]);
507 Alloc->getFunctionType()->getParamType(0),
529 Ptr = Builder.CreateBitCast(Ptr,
530 Dealloc->getFunctionType()->getParamType(0));
531 auto *
Call = Builder.CreateCall(Dealloc, Ptr);
547 errs() <<
" Value: ";
560 fail(
I,
"llvm.coro.id.retcon.* prototype not a Function", V);
562 auto FT =
F->getFunctionType();
566 if (FT->getReturnType()->isPointerTy()) {
569 ResultOkay = (!SRetTy->isOpaque() &&
570 SRetTy->getNumElements() > 0 &&
571 SRetTy->getElementType(0)->isPointerTy());
576 fail(
I,
"llvm.coro.id.retcon prototype must return pointer as first "
579 if (FT->getReturnType() !=
580 I->getFunction()->getFunctionType()->getReturnType())
581 fail(
I,
"llvm.coro.id.retcon prototype return type must be same as"
582 "current function return type",
F);
587 if (FT->getNumParams() == 0 || !FT->getParamType(0)->isPointerTy())
588 fail(
I,
"llvm.coro.id.retcon.* prototype must take pointer as "
589 "its first parameter",
F);
596 fail(
I,
"llvm.coro.* allocator not a Function", V);
598 auto FT =
F->getFunctionType();
599 if (!FT->getReturnType()->isPointerTy())
600 fail(
I,
"llvm.coro.* allocator must return a pointer",
F);
602 if (FT->getNumParams() != 1 ||
603 !FT->getParamType(0)->isIntegerTy())
604 fail(
I,
"llvm.coro.* allocator must take integer as only param",
F);
611 fail(
I,
"llvm.coro.* deallocator not a Function", V);
613 auto FT =
F->getFunctionType();
614 if (!FT->getReturnType()->isVoidTy())
615 fail(
I,
"llvm.coro.* deallocator must return void",
F);
617 if (FT->getNumParams() != 1 ||
618 !FT->getParamType(0)->isPointerTy())
619 fail(
I,
"llvm.coro.* deallocator must take pointer as only param",
F);
623 const char *Reason) {
631 "size argument to coro.id.retcon.* must be constant");
633 "alignment argument to coro.id.retcon.* must be constant");
641 if (!AsyncFuncPtrAddr)
642 fail(
I,
"llvm.coro.id.async async function pointer not a global", V);
647 "size argument to coro.id.async must be constant");
649 "alignment argument to coro.id.async must be constant");
651 "storage argument offset to coro.id.async must be constant");
657 auto *FunTy =
F->getFunctionType();
658 if (!FunTy->getReturnType()->isPointerTy())
660 "llvm.coro.suspend.async resume function projection function must "
663 if (FunTy->getNumParams() != 1 || !FunTy->getParamType(0)->isPointerTy())
665 "llvm.coro.suspend.async resume function projection function must "
666 "take one ptr type as parameter",
676 if (!MustTailCallFunc)
678 auto *FnTy = MustTailCallFunc->getFunctionType();
679 if (FnTy->getNumParams() != (
arg_size() - 3))
681 "llvm.coro.end.async must tail call function argument type must "
682 "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.
static const unsigned FramePtr
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.
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
unsigned arg_size() const
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.
Function * getMustTailCallFunction() const
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.save instruction.
Function * getAsyncContextProjectionFunction() const
LLVM_ABI void checkWellFormed() const
This represents the llvm.coro.suspend instruction.
CoroSaveInst * getCoroSave() const
Class to represent function types.
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...
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.
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
LLVM Value Representation.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< user_iterator > users()
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
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 Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
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 elideCoroFree(Value *FramePtr)
bool declaresIntrinsics(const Module &M, ArrayRef< Intrinsic::ID > List)
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
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.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
PointerType *const Int8Ptr
ConstantPointerNull *const NullPtr
CallInst * makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt)
FunctionType *const ResumeFnType
SmallVector< CoroAwaitSuspendInst *, 4 > CoroAwaitSuspends
AsyncLoweringStorage AsyncLowering
AnyCoroIdRetconInst * getRetconCoroId() const
CoroIdInst * getSwitchCoroId() const
SmallVector< CoroSizeInst *, 2 > CoroSizes
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.
LLVM_ABI void cleanCoroutine(SmallVectorImpl< CoroFrameInst * > &CoroFrames, SmallVectorImpl< CoroSaveInst * > &UnusedCoroSaves)
SwitchLoweringStorage SwitchLowering
CoroBeginInst * CoroBegin
SmallVector< CoroIsInRampInst *, 2 > CoroIsInRampInsts
LLVM_ABI void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const
Deallocate memory according to the rules of the active lowering.
RetconLoweringStorage RetconLowering
SmallVector< CoroAlignInst *, 2 > CoroAligns
CoroIdAsyncInst * getAsyncCoroId() const
SmallVector< AnyCoroEndInst *, 4 > CoroEnds
LLVM_ABI void invalidateCoroutine(Function &F, SmallVectorImpl< CoroFrameInst * > &CoroFrames)
LLVM_ABI void analyze(Function &F, SmallVectorImpl< CoroFrameInst * > &CoroFrames, SmallVectorImpl< CoroSaveInst * > &UnusedCoroSaves)