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