39 : TheModule(M), Context(M.getContext()),
57 "makeSubFnCall: Index value out of range");
65 "llvm.coro.async.context.alloc",
66 "llvm.coro.async.context.dealloc",
67 "llvm.coro.async.resume",
68 "llvm.coro.async.size.replace",
69 "llvm.coro.async.store_resume",
70 "llvm.coro.await.suspend.bool",
71 "llvm.coro.await.suspend.handle",
72 "llvm.coro.await.suspend.void",
77 "llvm.coro.end.async",
82 "llvm.coro.id.retcon",
83 "llvm.coro.id.retcon.once",
85 "llvm.coro.prepare.async",
86 "llvm.coro.prepare.retcon",
91 "llvm.coro.subfn.addr",
93 "llvm.coro.suspend.async",
94 "llvm.coro.suspend.retcon",
106 if (M.getNamedValue(
Name))
116 const std::initializer_list<StringRef>
List) {
119 if (M.getNamedValue(
Name))
131 if (
auto CF = dyn_cast<CoroFreeInst>(U))
134 if (CoroFrees.
empty())
140 : CoroFrees.
front()->getFrame();
143 CF->replaceAllUsesWith(Replacement);
144 CF->eraseFromParent();
163 auto *SaveInst = cast<CoroSaveInst>(
172 bool HasFinalSuspend =
false;
173 bool HasUnwindCoroEnd =
false;
174 size_t FinalSuspendIndex = 0;
182 if (
auto AWS = dyn_cast<CoroAwaitSuspendInst>(&
I)) {
184 }
else if (
auto II = dyn_cast<IntrinsicInst>(&
I)) {
185 switch (
II->getIntrinsicID()) {
188 case Intrinsic::coro_size:
189 CoroSizes.push_back(cast<CoroSizeInst>(
II));
191 case Intrinsic::coro_align:
192 CoroAligns.push_back(cast<CoroAlignInst>(
II));
194 case Intrinsic::coro_frame:
197 case Intrinsic::coro_save:
203 case Intrinsic::coro_suspend_async: {
204 auto *Suspend = cast<CoroSuspendAsyncInst>(
II);
205 Suspend->checkWellFormed();
206 CoroSuspends.push_back(Suspend);
209 case Intrinsic::coro_suspend_retcon: {
210 auto Suspend = cast<CoroSuspendRetconInst>(
II);
211 CoroSuspends.push_back(Suspend);
214 case Intrinsic::coro_suspend: {
215 auto Suspend = cast<CoroSuspendInst>(
II);
216 CoroSuspends.push_back(Suspend);
217 if (Suspend->isFinal()) {
220 "Only one suspend point can be marked as final");
221 HasFinalSuspend =
true;
222 FinalSuspendIndex = CoroSuspends.size() - 1;
226 case Intrinsic::coro_begin: {
227 auto CB = cast<CoroBeginInst>(
II);
230 auto Id = dyn_cast<CoroIdInst>(CB->getId());
231 if (Id && !Id->getInfo().isPreSplit())
236 "coroutine should have exactly one defining @llvm.coro.begin");
237 CB->addRetAttr(Attribute::NonNull);
238 CB->addRetAttr(Attribute::NoAlias);
239 CB->removeFnAttr(Attribute::NoDuplicate);
243 case Intrinsic::coro_end_async:
244 case Intrinsic::coro_end:
245 CoroEnds.push_back(cast<AnyCoroEndInst>(
II));
246 if (
auto *AsyncEnd = dyn_cast<CoroAsyncEndInst>(
II)) {
247 AsyncEnd->checkWellFormed();
250 if (CoroEnds.back()->isUnwind())
251 HasUnwindCoroEnd =
true;
253 if (CoroEnds.back()->isFallthrough() && isa<CoroEndInst>(
II)) {
257 if (CoroEnds.size() > 1) {
258 if (CoroEnds.front()->isFallthrough())
260 "Only one coro.end can be marked as fallthrough");
261 std::swap(CoroEnds.front(), CoroEnds.back());
275 CF->replaceAllUsesWith(Undef);
276 CF->eraseFromParent();
283 CS->eraseFromParent();
284 if (
auto *CoroSave = CS->getCoroSave())
285 CoroSave->eraseFromParent();
295 auto Id = CoroBegin->getId();
296 switch (
auto IdIntrinsic = Id->getIntrinsicID()) {
297 case Intrinsic::coro_id: {
298 auto SwitchId = cast<CoroIdInst>(Id);
300 this->SwitchLowering.HasFinalSuspend = HasFinalSuspend;
301 this->SwitchLowering.HasUnwindCoroEnd = HasUnwindCoroEnd;
302 this->SwitchLowering.ResumeSwitch =
nullptr;
303 this->SwitchLowering.PromiseAlloca = SwitchId->getPromise();
304 this->SwitchLowering.ResumeEntryBlock =
nullptr;
306 for (
auto *AnySuspend : CoroSuspends) {
307 auto Suspend = dyn_cast<CoroSuspendInst>(AnySuspend);
315 if (!Suspend->getCoroSave())
320 case Intrinsic::coro_id_async: {
321 auto *AsyncId = cast<CoroIdAsyncInst>(Id);
322 AsyncId->checkWellFormed();
324 this->AsyncLowering.Context = AsyncId->getStorage();
325 this->AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex();
326 this->AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize();
327 this->AsyncLowering.ContextAlignment =
328 AsyncId->getStorageAlignment().value();
329 this->AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer();
330 this->AsyncLowering.AsyncCC =
F.getCallingConv();
333 case Intrinsic::coro_id_retcon:
334 case Intrinsic::coro_id_retcon_once: {
335 auto ContinuationId = cast<AnyCoroIdRetconInst>(Id);
336 ContinuationId->checkWellFormed();
337 this->
ABI = (IdIntrinsic == Intrinsic::coro_id_retcon
340 auto Prototype = ContinuationId->getPrototype();
341 this->RetconLowering.ResumePrototype = Prototype;
342 this->RetconLowering.Alloc = ContinuationId->getAllocFunction();
343 this->RetconLowering.Dealloc = ContinuationId->getDeallocFunction();
344 this->RetconLowering.ReturnBlock =
nullptr;
345 this->RetconLowering.IsFrameInlineInStorage =
false;
349 auto ResultTys = getRetconResultTypes();
350 auto ResumeTys = getRetconResumeTypes();
352 for (
auto *AnySuspend : CoroSuspends) {
353 auto Suspend = dyn_cast<CoroSuspendRetconInst>(AnySuspend);
359 "coro.suspend.retcon");
363 auto SI = Suspend->value_begin(), SE = Suspend->value_end();
364 auto RI = ResultTys.begin(), RE = ResultTys.end();
365 for (; SI != SE && RI != RE; ++SI, ++RI) {
366 auto SrcTy = (*SI)->getType();
372 auto BCI =
new BitCastInst(*SI, *RI,
"", Suspend->getIterator());
379 Prototype->getFunctionType()->dump();
382 "match corresponding prototype function result");
385 if (SI != SE || RI != RE) {
388 Prototype->getFunctionType()->dump();
394 Type *SResultTy = Suspend->getType();
398 }
else if (
auto SResultStructTy = dyn_cast<StructType>(SResultTy)) {
399 SuspendResultTys = SResultStructTy->elements();
402 SuspendResultTys = SResultTy;
404 if (SuspendResultTys.
size() != ResumeTys.size()) {
407 Prototype->getFunctionType()->dump();
411 for (
size_t I = 0, E = ResumeTys.size();
I != E; ++
I) {
412 if (SuspendResultTys[
I] != ResumeTys[
I]) {
415 Prototype->getFunctionType()->dump();
418 "match corresponding prototype function param");
431 CF->replaceAllUsesWith(CoroBegin);
432 CF->eraseFromParent();
437 SwitchLowering.HasFinalSuspend &&
438 FinalSuspendIndex != CoroSuspends.size() - 1)
439 std::swap(CoroSuspends[FinalSuspendIndex], CoroSuspends.back());
443 CoroSave->eraseFromParent();
447 Call->setCallingConv(Callee->getCallingConv());
453 (*CG)[Call->getFunction()]->addCalledFunction(Call, (*CG)[Callee]);
464 auto Alloc = RetconLowering.Alloc;
466 Alloc->getFunctionType()->getParamType(0),
487 auto Dealloc = RetconLowering.Dealloc;
489 Dealloc->getFunctionType()->getParamType(0));
506 errs() <<
" Value: ";
517 auto F = dyn_cast<Function>(V->stripPointerCasts());
519 fail(
I,
"llvm.coro.id.retcon.* prototype not a Function", V);
521 auto FT =
F->getFunctionType();
523 if (isa<CoroIdRetconInst>(
I)) {
525 if (FT->getReturnType()->isPointerTy()) {
527 }
else if (
auto SRetTy = dyn_cast<StructType>(FT->getReturnType())) {
528 ResultOkay = (!SRetTy->isOpaque() &&
529 SRetTy->getNumElements() > 0 &&
530 SRetTy->getElementType(0)->isPointerTy());
535 fail(
I,
"llvm.coro.id.retcon prototype must return pointer as first "
538 if (FT->getReturnType() !=
539 I->getFunction()->getFunctionType()->getReturnType())
540 fail(
I,
"llvm.coro.id.retcon prototype return type must be same as"
541 "current function return type",
F);
546 if (FT->getNumParams() == 0 || !FT->getParamType(0)->isPointerTy())
547 fail(
I,
"llvm.coro.id.retcon.* prototype must take pointer as "
548 "its first parameter",
F);
553 auto F = dyn_cast<Function>(V->stripPointerCasts());
555 fail(
I,
"llvm.coro.* allocator not a Function", V);
557 auto FT =
F->getFunctionType();
558 if (!FT->getReturnType()->isPointerTy())
559 fail(
I,
"llvm.coro.* allocator must return a pointer",
F);
561 if (FT->getNumParams() != 1 ||
562 !FT->getParamType(0)->isIntegerTy())
563 fail(
I,
"llvm.coro.* allocator must take integer as only param",
F);
568 auto F = dyn_cast<Function>(V->stripPointerCasts());
570 fail(
I,
"llvm.coro.* deallocator not a Function", V);
572 auto FT =
F->getFunctionType();
573 if (!FT->getReturnType()->isVoidTy())
574 fail(
I,
"llvm.coro.* deallocator must return void",
F);
576 if (FT->getNumParams() != 1 ||
577 !FT->getParamType(0)->isPointerTy())
578 fail(
I,
"llvm.coro.* deallocator must take pointer as only param",
F);
582 const char *Reason) {
583 if (!isa<ConstantInt>(V)) {
590 "size argument to coro.id.retcon.* must be constant");
592 "alignment argument to coro.id.retcon.* must be constant");
599 auto *AsyncFuncPtrAddr = dyn_cast<GlobalVariable>(V->stripPointerCasts());
600 if (!AsyncFuncPtrAddr)
601 fail(
I,
"llvm.coro.id.async async function pointer not a global", V);
606 "size argument to coro.id.async must be constant");
608 "alignment argument to coro.id.async must be constant");
610 "storage argument offset to coro.id.async must be constant");
616 auto *FunTy = cast<FunctionType>(
F->getValueType());
617 if (!FunTy->getReturnType()->isPointerTy())
619 "llvm.coro.suspend.async resume function projection function must "
622 if (FunTy->getNumParams() != 1 || !FunTy->getParamType(0)->isPointerTy())
624 "llvm.coro.suspend.async resume function projection function must "
625 "take one ptr type as parameter",
634 auto *MustTailCallFunc = getMustTailCallFunction();
635 if (!MustTailCallFunc)
637 auto *FnTy = MustTailCallFunc->getFunctionType();
638 if (FnTy->getNumParams() != (arg_size() - 3))
640 "llvm.coro.end.async must tail call function argument type must "
641 "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 void clear(coro::Shape &Shape)
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.
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.
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 instruction.
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.
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
Value * CreateIntCast(Value *V, Type *DestTy, bool isSigned, const Twine &Name="")
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args=std::nullopt, const Twine &Name="", MDNode *FPMathTag=nullptr)
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...
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.
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'.
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
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.
int lookupLLVMIntrinsicByName(ArrayRef< const char * > NameTable, StringRef Name)
Looks up Name in NameTable via binary search.
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
@ 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 declaresIntrinsics(const Module &M, const std::initializer_list< StringRef >)
void replaceCoroFree(CoroIdInst *CoroId, bool Elide)
This is an optimization pass for GlobalISel generic memory operations.
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)
SmallVector< CoroSizeInst *, 2 > CoroSizes
SmallVector< AnyCoroSuspendInst *, 4 > CoroSuspends
Value * emitAlloc(IRBuilder<> &Builder, Value *Size, CallGraph *CG) const
Allocate memory according to the rules of the active lowering.
void buildFrom(Function &F)
CoroBeginInst * CoroBegin
void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const
Deallocate memory according to the rules of the active lowering.
SmallVector< AnyCoroEndInst *, 4 > CoroEnds
BasicBlock * AllocaSpillBlock