1 //===- Coroutines.cpp -----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the common infrastructure for Coroutine Passes.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "CoroInstr.h"
14 #include "CoroInternal.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Analysis/CallGraph.h"
18 #include "llvm/IR/Attributes.h"
19 #include "llvm/IR/Constants.h"
20 #include "llvm/IR/DerivedTypes.h"
21 #include "llvm/IR/Function.h"
22 #include "llvm/IR/InstIterator.h"
23 #include "llvm/IR/Instructions.h"
24 #include "llvm/IR/IntrinsicInst.h"
25 #include "llvm/IR/Intrinsics.h"
26 #include "llvm/IR/Module.h"
27 #include "llvm/IR/Type.h"
28 #include "llvm/Support/Casting.h"
29 #include "llvm/Support/ErrorHandling.h"
30 #include "llvm/Transforms/Utils/Local.h"
31 #include <cassert>
32 #include <cstddef>
33 #include <utility>
34 
35 using namespace llvm;
36 
37 // Construct the lowerer base class and initialize its members.
38 coro::LowererBase::LowererBase(Module &M)
39     : TheModule(M), Context(M.getContext()),
40       Int8Ptr(Type::getInt8PtrTy(Context)),
41       ResumeFnType(FunctionType::get(Type::getVoidTy(Context), Int8Ptr,
42                                      /*isVarArg=*/false)),
43       NullPtr(ConstantPointerNull::get(Int8Ptr)) {}
44 
45 // Creates a sequence of instructions to obtain a resume function address using
46 // llvm.coro.subfn.addr. It generates the following sequence:
47 //
48 //    call i8* @llvm.coro.subfn.addr(i8* %Arg, i8 %index)
49 //    bitcast i8* %2 to void(i8*)*
50 
51 Value *coro::LowererBase::makeSubFnCall(Value *Arg, int Index,
52                                         Instruction *InsertPt) {
53   auto *IndexVal = ConstantInt::get(Type::getInt8Ty(Context), Index);
54   auto *Fn = Intrinsic::getDeclaration(&TheModule, Intrinsic::coro_subfn_addr);
55 
56   assert(Index >= CoroSubFnInst::IndexFirst &&
57          Index < CoroSubFnInst::IndexLast &&
58          "makeSubFnCall: Index value out of range");
59   auto *Call = CallInst::Create(Fn, {Arg, IndexVal}, "", InsertPt);
60 
61   auto *Bitcast =
62       new BitCastInst(Call, ResumeFnType->getPointerTo(), "", InsertPt);
63   return Bitcast;
64 }
65 
66 // NOTE: Must be sorted!
67 static const char *const CoroIntrinsics[] = {
68     "llvm.coro.align",
69     "llvm.coro.alloc",
70     "llvm.coro.async.context.alloc",
71     "llvm.coro.async.context.dealloc",
72     "llvm.coro.async.resume",
73     "llvm.coro.async.size.replace",
74     "llvm.coro.async.store_resume",
75     "llvm.coro.begin",
76     "llvm.coro.destroy",
77     "llvm.coro.done",
78     "llvm.coro.end",
79     "llvm.coro.end.async",
80     "llvm.coro.frame",
81     "llvm.coro.free",
82     "llvm.coro.id",
83     "llvm.coro.id.async",
84     "llvm.coro.id.retcon",
85     "llvm.coro.id.retcon.once",
86     "llvm.coro.noop",
87     "llvm.coro.prepare.async",
88     "llvm.coro.prepare.retcon",
89     "llvm.coro.promise",
90     "llvm.coro.resume",
91     "llvm.coro.save",
92     "llvm.coro.size",
93     "llvm.coro.subfn.addr",
94     "llvm.coro.suspend",
95     "llvm.coro.suspend.async",
96     "llvm.coro.suspend.retcon",
97 };
98 
99 #ifndef NDEBUG
100 static bool isCoroutineIntrinsicName(StringRef Name) {
101   return Intrinsic::lookupLLVMIntrinsicByName(CoroIntrinsics, Name) != -1;
102 }
103 #endif
104 
105 bool coro::declaresAnyIntrinsic(const Module &M) {
106   for (StringRef Name : CoroIntrinsics) {
107     assert(isCoroutineIntrinsicName(Name) && "not a coroutine intrinsic");
108     if (M.getNamedValue(Name))
109       return true;
110   }
111 
112   return false;
113 }
114 
115 // Verifies if a module has named values listed. Also, in debug mode verifies
116 // that names are intrinsic names.
117 bool coro::declaresIntrinsics(const Module &M,
118                               const std::initializer_list<StringRef> List) {
119   for (StringRef Name : List) {
120     assert(isCoroutineIntrinsicName(Name) && "not a coroutine intrinsic");
121     if (M.getNamedValue(Name))
122       return true;
123   }
124 
125   return false;
126 }
127 
128 // Replace all coro.frees associated with the provided CoroId either with 'null'
129 // if Elide is true and with its frame parameter otherwise.
130 void coro::replaceCoroFree(CoroIdInst *CoroId, bool Elide) {
131   SmallVector<CoroFreeInst *, 4> CoroFrees;
132   for (User *U : CoroId->users())
133     if (auto CF = dyn_cast<CoroFreeInst>(U))
134       CoroFrees.push_back(CF);
135 
136   if (CoroFrees.empty())
137     return;
138 
139   Value *Replacement =
140       Elide ? ConstantPointerNull::get(Type::getInt8PtrTy(CoroId->getContext()))
141             : CoroFrees.front()->getFrame();
142 
143   for (CoroFreeInst *CF : CoroFrees) {
144     CF->replaceAllUsesWith(Replacement);
145     CF->eraseFromParent();
146   }
147 }
148 
149 static void clear(coro::Shape &Shape) {
150   Shape.CoroBegin = nullptr;
151   Shape.CoroEnds.clear();
152   Shape.CoroSizes.clear();
153   Shape.CoroSuspends.clear();
154 
155   Shape.FrameTy = nullptr;
156   Shape.FramePtr = nullptr;
157   Shape.AllocaSpillBlock = nullptr;
158 }
159 
160 static CoroSaveInst *createCoroSave(CoroBeginInst *CoroBegin,
161                                     CoroSuspendInst *SuspendInst) {
162   Module *M = SuspendInst->getModule();
163   auto *Fn = Intrinsic::getDeclaration(M, Intrinsic::coro_save);
164   auto *SaveInst =
165       cast<CoroSaveInst>(CallInst::Create(Fn, CoroBegin, "", SuspendInst));
166   assert(!SuspendInst->getCoroSave());
167   SuspendInst->setArgOperand(0, SaveInst);
168   return SaveInst;
169 }
170 
171 // Collect "interesting" coroutine intrinsics.
172 void coro::Shape::buildFrom(Function &F) {
173   bool HasFinalSuspend = false;
174   size_t FinalSuspendIndex = 0;
175   clear(*this);
176   SmallVector<CoroFrameInst *, 8> CoroFrames;
177   SmallVector<CoroSaveInst *, 2> UnusedCoroSaves;
178 
179   for (Instruction &I : instructions(F)) {
180     if (auto II = dyn_cast<IntrinsicInst>(&I)) {
181       switch (II->getIntrinsicID()) {
182       default:
183         continue;
184       case Intrinsic::coro_size:
185         CoroSizes.push_back(cast<CoroSizeInst>(II));
186         break;
187       case Intrinsic::coro_align:
188         CoroAligns.push_back(cast<CoroAlignInst>(II));
189         break;
190       case Intrinsic::coro_frame:
191         CoroFrames.push_back(cast<CoroFrameInst>(II));
192         break;
193       case Intrinsic::coro_save:
194         // After optimizations, coro_suspends using this coro_save might have
195         // been removed, remember orphaned coro_saves to remove them later.
196         if (II->use_empty())
197           UnusedCoroSaves.push_back(cast<CoroSaveInst>(II));
198         break;
199       case Intrinsic::coro_suspend_async: {
200         auto *Suspend = cast<CoroSuspendAsyncInst>(II);
201         Suspend->checkWellFormed();
202         CoroSuspends.push_back(Suspend);
203         break;
204       }
205       case Intrinsic::coro_suspend_retcon: {
206         auto Suspend = cast<CoroSuspendRetconInst>(II);
207         CoroSuspends.push_back(Suspend);
208         break;
209       }
210       case Intrinsic::coro_suspend: {
211         auto Suspend = cast<CoroSuspendInst>(II);
212         CoroSuspends.push_back(Suspend);
213         if (Suspend->isFinal()) {
214           if (HasFinalSuspend)
215             report_fatal_error(
216               "Only one suspend point can be marked as final");
217           HasFinalSuspend = true;
218           FinalSuspendIndex = CoroSuspends.size() - 1;
219         }
220         break;
221       }
222       case Intrinsic::coro_begin: {
223         auto CB = cast<CoroBeginInst>(II);
224 
225         // Ignore coro id's that aren't pre-split.
226         auto Id = dyn_cast<CoroIdInst>(CB->getId());
227         if (Id && !Id->getInfo().isPreSplit())
228           break;
229 
230         if (CoroBegin)
231           report_fatal_error(
232                 "coroutine should have exactly one defining @llvm.coro.begin");
233         CB->addRetAttr(Attribute::NonNull);
234         CB->addRetAttr(Attribute::NoAlias);
235         CB->removeFnAttr(Attribute::NoDuplicate);
236         CoroBegin = CB;
237         break;
238       }
239       case Intrinsic::coro_end_async:
240       case Intrinsic::coro_end:
241         CoroEnds.push_back(cast<AnyCoroEndInst>(II));
242         if (auto *AsyncEnd = dyn_cast<CoroAsyncEndInst>(II)) {
243           AsyncEnd->checkWellFormed();
244         }
245         if (CoroEnds.back()->isFallthrough() && isa<CoroEndInst>(II)) {
246           // Make sure that the fallthrough coro.end is the first element in the
247           // CoroEnds vector.
248           // Note: I don't think this is neccessary anymore.
249           if (CoroEnds.size() > 1) {
250             if (CoroEnds.front()->isFallthrough())
251               report_fatal_error(
252                   "Only one coro.end can be marked as fallthrough");
253             std::swap(CoroEnds.front(), CoroEnds.back());
254           }
255         }
256         break;
257       }
258     }
259   }
260 
261   // If for some reason, we were not able to find coro.begin, bailout.
262   if (!CoroBegin) {
263     // Replace coro.frame which are supposed to be lowered to the result of
264     // coro.begin with undef.
265     auto *Undef = UndefValue::get(Type::getInt8PtrTy(F.getContext()));
266     for (CoroFrameInst *CF : CoroFrames) {
267       CF->replaceAllUsesWith(Undef);
268       CF->eraseFromParent();
269     }
270 
271     // Replace all coro.suspend with undef and remove related coro.saves if
272     // present.
273     for (AnyCoroSuspendInst *CS : CoroSuspends) {
274       CS->replaceAllUsesWith(UndefValue::get(CS->getType()));
275       CS->eraseFromParent();
276       if (auto *CoroSave = CS->getCoroSave())
277         CoroSave->eraseFromParent();
278     }
279 
280     // Replace all coro.ends with unreachable instruction.
281     for (AnyCoroEndInst *CE : CoroEnds)
282       changeToUnreachable(CE);
283 
284     return;
285   }
286 
287   auto Id = CoroBegin->getId();
288   switch (auto IdIntrinsic = Id->getIntrinsicID()) {
289   case Intrinsic::coro_id: {
290     auto SwitchId = cast<CoroIdInst>(Id);
291     this->ABI = coro::ABI::Switch;
292     this->SwitchLowering.HasFinalSuspend = HasFinalSuspend;
293     this->SwitchLowering.ResumeSwitch = nullptr;
294     this->SwitchLowering.PromiseAlloca = SwitchId->getPromise();
295     this->SwitchLowering.ResumeEntryBlock = nullptr;
296 
297     for (auto AnySuspend : CoroSuspends) {
298       auto Suspend = dyn_cast<CoroSuspendInst>(AnySuspend);
299       if (!Suspend) {
300 #ifndef NDEBUG
301         AnySuspend->dump();
302 #endif
303         report_fatal_error("coro.id must be paired with coro.suspend");
304       }
305 
306       if (!Suspend->getCoroSave())
307         createCoroSave(CoroBegin, Suspend);
308     }
309     break;
310   }
311   case Intrinsic::coro_id_async: {
312     auto *AsyncId = cast<CoroIdAsyncInst>(Id);
313     AsyncId->checkWellFormed();
314     this->ABI = coro::ABI::Async;
315     this->AsyncLowering.Context = AsyncId->getStorage();
316     this->AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex();
317     this->AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize();
318     this->AsyncLowering.ContextAlignment =
319         AsyncId->getStorageAlignment().value();
320     this->AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer();
321     this->AsyncLowering.AsyncCC = F.getCallingConv();
322     break;
323   };
324   case Intrinsic::coro_id_retcon:
325   case Intrinsic::coro_id_retcon_once: {
326     auto ContinuationId = cast<AnyCoroIdRetconInst>(Id);
327     ContinuationId->checkWellFormed();
328     this->ABI = (IdIntrinsic == Intrinsic::coro_id_retcon
329                   ? coro::ABI::Retcon
330                   : coro::ABI::RetconOnce);
331     auto Prototype = ContinuationId->getPrototype();
332     this->RetconLowering.ResumePrototype = Prototype;
333     this->RetconLowering.Alloc = ContinuationId->getAllocFunction();
334     this->RetconLowering.Dealloc = ContinuationId->getDeallocFunction();
335     this->RetconLowering.ReturnBlock = nullptr;
336     this->RetconLowering.IsFrameInlineInStorage = false;
337 
338     // Determine the result value types, and make sure they match up with
339     // the values passed to the suspends.
340     auto ResultTys = getRetconResultTypes();
341     auto ResumeTys = getRetconResumeTypes();
342 
343     for (auto AnySuspend : CoroSuspends) {
344       auto Suspend = dyn_cast<CoroSuspendRetconInst>(AnySuspend);
345       if (!Suspend) {
346 #ifndef NDEBUG
347         AnySuspend->dump();
348 #endif
349         report_fatal_error("coro.id.retcon.* must be paired with "
350                            "coro.suspend.retcon");
351       }
352 
353       // Check that the argument types of the suspend match the results.
354       auto SI = Suspend->value_begin(), SE = Suspend->value_end();
355       auto RI = ResultTys.begin(), RE = ResultTys.end();
356       for (; SI != SE && RI != RE; ++SI, ++RI) {
357         auto SrcTy = (*SI)->getType();
358         if (SrcTy != *RI) {
359           // The optimizer likes to eliminate bitcasts leading into variadic
360           // calls, but that messes with our invariants.  Re-insert the
361           // bitcast and ignore this type mismatch.
362           if (CastInst::isBitCastable(SrcTy, *RI)) {
363             auto BCI = new BitCastInst(*SI, *RI, "", Suspend);
364             SI->set(BCI);
365             continue;
366           }
367 
368 #ifndef NDEBUG
369           Suspend->dump();
370           Prototype->getFunctionType()->dump();
371 #endif
372           report_fatal_error("argument to coro.suspend.retcon does not "
373                              "match corresponding prototype function result");
374         }
375       }
376       if (SI != SE || RI != RE) {
377 #ifndef NDEBUG
378         Suspend->dump();
379         Prototype->getFunctionType()->dump();
380 #endif
381         report_fatal_error("wrong number of arguments to coro.suspend.retcon");
382       }
383 
384       // Check that the result type of the suspend matches the resume types.
385       Type *SResultTy = Suspend->getType();
386       ArrayRef<Type*> SuspendResultTys;
387       if (SResultTy->isVoidTy()) {
388         // leave as empty array
389       } else if (auto SResultStructTy = dyn_cast<StructType>(SResultTy)) {
390         SuspendResultTys = SResultStructTy->elements();
391       } else {
392         // forms an ArrayRef using SResultTy, be careful
393         SuspendResultTys = SResultTy;
394       }
395       if (SuspendResultTys.size() != ResumeTys.size()) {
396 #ifndef NDEBUG
397         Suspend->dump();
398         Prototype->getFunctionType()->dump();
399 #endif
400         report_fatal_error("wrong number of results from coro.suspend.retcon");
401       }
402       for (size_t I = 0, E = ResumeTys.size(); I != E; ++I) {
403         if (SuspendResultTys[I] != ResumeTys[I]) {
404 #ifndef NDEBUG
405           Suspend->dump();
406           Prototype->getFunctionType()->dump();
407 #endif
408           report_fatal_error("result from coro.suspend.retcon does not "
409                              "match corresponding prototype function param");
410         }
411       }
412     }
413     break;
414   }
415 
416   default:
417     llvm_unreachable("coro.begin is not dependent on a coro.id call");
418   }
419 
420   // The coro.free intrinsic is always lowered to the result of coro.begin.
421   for (CoroFrameInst *CF : CoroFrames) {
422     CF->replaceAllUsesWith(CoroBegin);
423     CF->eraseFromParent();
424   }
425 
426   // Move final suspend to be the last element in the CoroSuspends vector.
427   if (ABI == coro::ABI::Switch &&
428       SwitchLowering.HasFinalSuspend &&
429       FinalSuspendIndex != CoroSuspends.size() - 1)
430     std::swap(CoroSuspends[FinalSuspendIndex], CoroSuspends.back());
431 
432   // Remove orphaned coro.saves.
433   for (CoroSaveInst *CoroSave : UnusedCoroSaves)
434     CoroSave->eraseFromParent();
435 }
436 
437 static void propagateCallAttrsFromCallee(CallInst *Call, Function *Callee) {
438   Call->setCallingConv(Callee->getCallingConv());
439   // TODO: attributes?
440 }
441 
442 static void addCallToCallGraph(CallGraph *CG, CallInst *Call, Function *Callee){
443   if (CG)
444     (*CG)[Call->getFunction()]->addCalledFunction(Call, (*CG)[Callee]);
445 }
446 
447 Value *coro::Shape::emitAlloc(IRBuilder<> &Builder, Value *Size,
448                               CallGraph *CG) const {
449   switch (ABI) {
450   case coro::ABI::Switch:
451     llvm_unreachable("can't allocate memory in coro switch-lowering");
452 
453   case coro::ABI::Retcon:
454   case coro::ABI::RetconOnce: {
455     auto Alloc = RetconLowering.Alloc;
456     Size = Builder.CreateIntCast(Size,
457                                  Alloc->getFunctionType()->getParamType(0),
458                                  /*is signed*/ false);
459     auto *Call = Builder.CreateCall(Alloc, Size);
460     propagateCallAttrsFromCallee(Call, Alloc);
461     addCallToCallGraph(CG, Call, Alloc);
462     return Call;
463   }
464   case coro::ABI::Async:
465     llvm_unreachable("can't allocate memory in coro async-lowering");
466   }
467   llvm_unreachable("Unknown coro::ABI enum");
468 }
469 
470 void coro::Shape::emitDealloc(IRBuilder<> &Builder, Value *Ptr,
471                               CallGraph *CG) const {
472   switch (ABI) {
473   case coro::ABI::Switch:
474     llvm_unreachable("can't allocate memory in coro switch-lowering");
475 
476   case coro::ABI::Retcon:
477   case coro::ABI::RetconOnce: {
478     auto Dealloc = RetconLowering.Dealloc;
479     Ptr = Builder.CreateBitCast(Ptr,
480                                 Dealloc->getFunctionType()->getParamType(0));
481     auto *Call = Builder.CreateCall(Dealloc, Ptr);
482     propagateCallAttrsFromCallee(Call, Dealloc);
483     addCallToCallGraph(CG, Call, Dealloc);
484     return;
485   }
486   case coro::ABI::Async:
487     llvm_unreachable("can't allocate memory in coro async-lowering");
488   }
489   llvm_unreachable("Unknown coro::ABI enum");
490 }
491 
492 [[noreturn]] static void fail(const Instruction *I, const char *Reason,
493                               Value *V) {
494 #ifndef NDEBUG
495   I->dump();
496   if (V) {
497     errs() << "  Value: ";
498     V->printAsOperand(llvm::errs());
499     errs() << '\n';
500   }
501 #endif
502   report_fatal_error(Reason);
503 }
504 
505 /// Check that the given value is a well-formed prototype for the
506 /// llvm.coro.id.retcon.* intrinsics.
507 static void checkWFRetconPrototype(const AnyCoroIdRetconInst *I, Value *V) {
508   auto F = dyn_cast<Function>(V->stripPointerCasts());
509   if (!F)
510     fail(I, "llvm.coro.id.retcon.* prototype not a Function", V);
511 
512   auto FT = F->getFunctionType();
513 
514   if (isa<CoroIdRetconInst>(I)) {
515     bool ResultOkay;
516     if (FT->getReturnType()->isPointerTy()) {
517       ResultOkay = true;
518     } else if (auto SRetTy = dyn_cast<StructType>(FT->getReturnType())) {
519       ResultOkay = (!SRetTy->isOpaque() &&
520                     SRetTy->getNumElements() > 0 &&
521                     SRetTy->getElementType(0)->isPointerTy());
522     } else {
523       ResultOkay = false;
524     }
525     if (!ResultOkay)
526       fail(I, "llvm.coro.id.retcon prototype must return pointer as first "
527               "result", F);
528 
529     if (FT->getReturnType() !=
530           I->getFunction()->getFunctionType()->getReturnType())
531       fail(I, "llvm.coro.id.retcon prototype return type must be same as"
532               "current function return type", F);
533   } else {
534     // No meaningful validation to do here for llvm.coro.id.unique.once.
535   }
536 
537   if (FT->getNumParams() == 0 || !FT->getParamType(0)->isPointerTy())
538     fail(I, "llvm.coro.id.retcon.* prototype must take pointer as "
539             "its first parameter", F);
540 }
541 
542 /// Check that the given value is a well-formed allocator.
543 static void checkWFAlloc(const Instruction *I, Value *V) {
544   auto F = dyn_cast<Function>(V->stripPointerCasts());
545   if (!F)
546     fail(I, "llvm.coro.* allocator not a Function", V);
547 
548   auto FT = F->getFunctionType();
549   if (!FT->getReturnType()->isPointerTy())
550     fail(I, "llvm.coro.* allocator must return a pointer", F);
551 
552   if (FT->getNumParams() != 1 ||
553       !FT->getParamType(0)->isIntegerTy())
554     fail(I, "llvm.coro.* allocator must take integer as only param", F);
555 }
556 
557 /// Check that the given value is a well-formed deallocator.
558 static void checkWFDealloc(const Instruction *I, Value *V) {
559   auto F = dyn_cast<Function>(V->stripPointerCasts());
560   if (!F)
561     fail(I, "llvm.coro.* deallocator not a Function", V);
562 
563   auto FT = F->getFunctionType();
564   if (!FT->getReturnType()->isVoidTy())
565     fail(I, "llvm.coro.* deallocator must return void", F);
566 
567   if (FT->getNumParams() != 1 ||
568       !FT->getParamType(0)->isPointerTy())
569     fail(I, "llvm.coro.* deallocator must take pointer as only param", F);
570 }
571 
572 static void checkConstantInt(const Instruction *I, Value *V,
573                              const char *Reason) {
574   if (!isa<ConstantInt>(V)) {
575     fail(I, Reason, V);
576   }
577 }
578 
579 void AnyCoroIdRetconInst::checkWellFormed() const {
580   checkConstantInt(this, getArgOperand(SizeArg),
581                    "size argument to coro.id.retcon.* must be constant");
582   checkConstantInt(this, getArgOperand(AlignArg),
583                    "alignment argument to coro.id.retcon.* must be constant");
584   checkWFRetconPrototype(this, getArgOperand(PrototypeArg));
585   checkWFAlloc(this, getArgOperand(AllocArg));
586   checkWFDealloc(this, getArgOperand(DeallocArg));
587 }
588 
589 static void checkAsyncFuncPointer(const Instruction *I, Value *V) {
590   auto *AsyncFuncPtrAddr = dyn_cast<GlobalVariable>(V->stripPointerCasts());
591   if (!AsyncFuncPtrAddr)
592     fail(I, "llvm.coro.id.async async function pointer not a global", V);
593 
594   if (AsyncFuncPtrAddr->getType()->isOpaquePointerTy())
595     return;
596 
597   auto *StructTy = cast<StructType>(
598       AsyncFuncPtrAddr->getType()->getNonOpaquePointerElementType());
599   if (StructTy->isOpaque() || !StructTy->isPacked() ||
600       StructTy->getNumElements() != 2 ||
601       !StructTy->getElementType(0)->isIntegerTy(32) ||
602       !StructTy->getElementType(1)->isIntegerTy(32))
603     fail(I,
604          "llvm.coro.id.async async function pointer argument's type is not "
605          "<{i32, i32}>",
606          V);
607 }
608 
609 void CoroIdAsyncInst::checkWellFormed() const {
610   checkConstantInt(this, getArgOperand(SizeArg),
611                    "size argument to coro.id.async must be constant");
612   checkConstantInt(this, getArgOperand(AlignArg),
613                    "alignment argument to coro.id.async must be constant");
614   checkConstantInt(this, getArgOperand(StorageArg),
615                    "storage argument offset to coro.id.async must be constant");
616   checkAsyncFuncPointer(this, getArgOperand(AsyncFuncPtrArg));
617 }
618 
619 static void checkAsyncContextProjectFunction(const Instruction *I,
620                                              Function *F) {
621   auto *FunTy = cast<FunctionType>(F->getValueType());
622   Type *Int8Ty = Type::getInt8Ty(F->getContext());
623   auto *RetPtrTy = dyn_cast<PointerType>(FunTy->getReturnType());
624   if (!RetPtrTy || !RetPtrTy->isOpaqueOrPointeeTypeMatches(Int8Ty))
625     fail(I,
626          "llvm.coro.suspend.async resume function projection function must "
627          "return an i8* type",
628          F);
629   if (FunTy->getNumParams() != 1 || !FunTy->getParamType(0)->isPointerTy() ||
630       !cast<PointerType>(FunTy->getParamType(0))
631            ->isOpaqueOrPointeeTypeMatches(Int8Ty))
632     fail(I,
633          "llvm.coro.suspend.async resume function projection function must "
634          "take one i8* type as parameter",
635          F);
636 }
637 
638 void CoroSuspendAsyncInst::checkWellFormed() const {
639   checkAsyncContextProjectFunction(this, getAsyncContextProjectionFunction());
640 }
641 
642 void CoroAsyncEndInst::checkWellFormed() const {
643   auto *MustTailCallFunc = getMustTailCallFunction();
644   if (!MustTailCallFunc)
645     return;
646   auto *FnTy = MustTailCallFunc->getFunctionType();
647   if (FnTy->getNumParams() != (arg_size() - 3))
648     fail(this,
649          "llvm.coro.end.async must tail call function argument type must "
650          "match the tail arguments",
651          MustTailCallFunc);
652 }
653