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