Coroutines.cpp revision 360784
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
43using namespace llvm;
44
45void llvm::initializeCoroutines(PassRegistry &Registry) {
46  initializeCoroEarlyLegacyPass(Registry);
47  initializeCoroSplitLegacyPass(Registry);
48  initializeCoroElideLegacyPass(Registry);
49  initializeCoroCleanupLegacyPass(Registry);
50}
51
52static 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
61static void addCoroutineEarlyPasses(const PassManagerBuilder &Builder,
62                                    legacy::PassManagerBase &PM) {
63  PM.add(createCoroEarlyLegacyPass());
64}
65
66static void addCoroutineScalarOptimizerPasses(const PassManagerBuilder &Builder,
67                                              legacy::PassManagerBase &PM) {
68  PM.add(createCoroElideLegacyPass());
69}
70
71static void addCoroutineSCCPasses(const PassManagerBuilder &Builder,
72                                  legacy::PassManagerBase &PM) {
73  PM.add(createCoroSplitLegacyPass());
74}
75
76static void addCoroutineOptimizerLastPasses(const PassManagerBuilder &Builder,
77                                            legacy::PassManagerBase &PM) {
78  PM.add(createCoroCleanupLegacyPass());
79}
80
81void 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.
95coro::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
108Value *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
124static 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.
154bool 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.
167void 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.
189static 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.
208void 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
226static 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
237static 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.
249void 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
489static void propagateCallAttrsFromCallee(CallInst *Call, Function *Callee) {
490  Call->setCallingConv(Callee->getCallingConv());
491  // TODO: attributes?
492}
493
494static void addCallToCallGraph(CallGraph *CG, CallInst *Call, Function *Callee){
495  if (CG)
496    (*CG)[Call->getFunction()]->addCalledFunction(Call, (*CG)[Callee]);
497}
498
499Value *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
520void 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
540LLVM_ATTRIBUTE_NORETURN
541static 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.
555static 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.
591static 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.
606static 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
620static void checkConstantInt(const Instruction *I, Value *V,
621                             const char *Reason) {
622  if (!isa<ConstantInt>(V)) {
623    fail(I, Reason, V);
624  }
625}
626
627void 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
637void LLVMAddCoroEarlyPass(LLVMPassManagerRef PM) {
638  unwrap(PM)->add(createCoroEarlyLegacyPass());
639}
640
641void LLVMAddCoroSplitPass(LLVMPassManagerRef PM) {
642  unwrap(PM)->add(createCoroSplitLegacyPass());
643}
644
645void LLVMAddCoroElidePass(LLVMPassManagerRef PM) {
646  unwrap(PM)->add(createCoroElideLegacyPass());
647}
648
649void LLVMAddCoroCleanupPass(LLVMPassManagerRef PM) {
650  unwrap(PM)->add(createCoroCleanupLegacyPass());
651}
652