brintos

brintos / llvm-project-archived public Read only

0
0
Text · 24.0 KiB · 47c2d0d Raw
697 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the common infrastructure for Coroutine Passes.10//11//===----------------------------------------------------------------------===//12 13#include "CoroInternal.h"14#include "llvm/ADT/SmallVector.h"15#include "llvm/ADT/StringRef.h"16#include "llvm/Analysis/CallGraph.h"17#include "llvm/IR/Attributes.h"18#include "llvm/IR/Constants.h"19#include "llvm/IR/DerivedTypes.h"20#include "llvm/IR/Function.h"21#include "llvm/IR/InstIterator.h"22#include "llvm/IR/Instructions.h"23#include "llvm/IR/IntrinsicInst.h"24#include "llvm/IR/Intrinsics.h"25#include "llvm/IR/Module.h"26#include "llvm/IR/Type.h"27#include "llvm/Support/Casting.h"28#include "llvm/Support/ErrorHandling.h"29#include "llvm/Transforms/Coroutines/ABI.h"30#include "llvm/Transforms/Coroutines/CoroInstr.h"31#include "llvm/Transforms/Coroutines/CoroShape.h"32#include "llvm/Transforms/Utils/Local.h"33#include <cassert>34#include <cstddef>35#include <utility>36 37using namespace llvm;38 39// Construct the lowerer base class and initialize its members.40coro::LowererBase::LowererBase(Module &M)41    : TheModule(M), Context(M.getContext()),42      Int8Ptr(PointerType::get(Context, 0)),43      ResumeFnType(FunctionType::get(Type::getVoidTy(Context), Int8Ptr,44                                     /*isVarArg=*/false)),45      NullPtr(ConstantPointerNull::get(Int8Ptr)) {}46 47// Creates a call to llvm.coro.subfn.addr to obtain a resume function address.48// It generates the following:49//50//    call ptr @llvm.coro.subfn.addr(ptr %Arg, i8 %index)51 52CallInst *coro::LowererBase::makeSubFnCall(Value *Arg, int Index,53                                           Instruction *InsertPt) {54  auto *IndexVal = ConstantInt::get(Type::getInt8Ty(Context), Index);55  auto *Fn =56      Intrinsic::getOrInsertDeclaration(&TheModule, Intrinsic::coro_subfn_addr);57 58  assert(Index >= CoroSubFnInst::IndexFirst &&59         Index < CoroSubFnInst::IndexLast &&60         "makeSubFnCall: Index value out of range");61  return CallInst::Create(Fn, {Arg, IndexVal}, "", InsertPt->getIterator());62}63 64// We can only efficiently check for non-overloaded intrinsics.65// The following intrinsics are absent for that reason:66// coro_align, coro_size, coro_suspend_async, coro_suspend_retcon67static Intrinsic::ID NonOverloadedCoroIntrinsics[] = {68    Intrinsic::coro_alloc,69    Intrinsic::coro_async_context_alloc,70    Intrinsic::coro_async_context_dealloc,71    Intrinsic::coro_async_resume,72    Intrinsic::coro_async_size_replace,73    Intrinsic::coro_await_suspend_bool,74    Intrinsic::coro_await_suspend_handle,75    Intrinsic::coro_await_suspend_void,76    Intrinsic::coro_begin,77    Intrinsic::coro_begin_custom_abi,78    Intrinsic::coro_destroy,79    Intrinsic::coro_done,80    Intrinsic::coro_end,81    Intrinsic::coro_end_async,82    Intrinsic::coro_frame,83    Intrinsic::coro_free,84    Intrinsic::coro_id,85    Intrinsic::coro_id_async,86    Intrinsic::coro_id_retcon,87    Intrinsic::coro_id_retcon_once,88    Intrinsic::coro_noop,89    Intrinsic::coro_prepare_async,90    Intrinsic::coro_prepare_retcon,91    Intrinsic::coro_promise,92    Intrinsic::coro_resume,93    Intrinsic::coro_save,94    Intrinsic::coro_subfn_addr,95    Intrinsic::coro_suspend,96    Intrinsic::coro_is_in_ramp,97};98 99bool coro::isSuspendBlock(BasicBlock *BB) {100  return isa<AnyCoroSuspendInst>(BB->front());101}102 103bool coro::declaresAnyIntrinsic(const Module &M) {104  return declaresIntrinsics(M, NonOverloadedCoroIntrinsics);105}106 107// Checks whether the module declares any of the listed intrinsics.108bool coro::declaresIntrinsics(const Module &M, ArrayRef<Intrinsic::ID> List) {109#ifndef NDEBUG110  for (Intrinsic::ID ID : List)111    assert(!Intrinsic::isOverloaded(ID) &&112           "Only non-overloaded intrinsics supported");113#endif114 115  for (Intrinsic::ID ID : List)116    if (Intrinsic::getDeclarationIfExists(&M, ID))117      return true;118  return false;119}120 121// Replace all coro.frees associated with the provided CoroId either with 'null'122// if Elide is true and with its frame parameter otherwise.123void coro::replaceCoroFree(CoroIdInst *CoroId, bool Elide) {124  SmallVector<CoroFreeInst *, 4> CoroFrees;125  for (User *U : CoroId->users())126    if (auto CF = dyn_cast<CoroFreeInst>(U))127      CoroFrees.push_back(CF);128 129  if (CoroFrees.empty())130    return;131 132  Value *Replacement =133      Elide134          ? ConstantPointerNull::get(PointerType::get(CoroId->getContext(), 0))135          : CoroFrees.front()->getFrame();136 137  for (CoroFreeInst *CF : CoroFrees) {138    CF->replaceAllUsesWith(Replacement);139    CF->eraseFromParent();140  }141}142 143void coro::suppressCoroAllocs(CoroIdInst *CoroId) {144  SmallVector<CoroAllocInst *, 4> CoroAllocs;145  for (User *U : CoroId->users())146    if (auto *CA = dyn_cast<CoroAllocInst>(U))147      CoroAllocs.push_back(CA);148 149  if (CoroAllocs.empty())150    return;151 152  coro::suppressCoroAllocs(CoroId->getContext(), CoroAllocs);153}154 155// Replacing llvm.coro.alloc with false will suppress dynamic156// allocation as it is expected for the frontend to generate the code that157// looks like:158//   id = coro.id(...)159//   mem = coro.alloc(id) ? malloc(coro.size()) : 0;160//   coro.begin(id, mem)161void coro::suppressCoroAllocs(LLVMContext &Context,162                              ArrayRef<CoroAllocInst *> CoroAllocs) {163  auto *False = ConstantInt::getFalse(Context);164  for (auto *CA : CoroAllocs) {165    CA->replaceAllUsesWith(False);166    CA->eraseFromParent();167  }168}169 170static CoroSaveInst *createCoroSave(CoroBeginInst *CoroBegin,171                                    CoroSuspendInst *SuspendInst) {172  Module *M = SuspendInst->getModule();173  auto *Fn = Intrinsic::getOrInsertDeclaration(M, Intrinsic::coro_save);174  auto *SaveInst = cast<CoroSaveInst>(175      CallInst::Create(Fn, CoroBegin, "", SuspendInst->getIterator()));176  assert(!SuspendInst->getCoroSave());177  SuspendInst->setArgOperand(0, SaveInst);178  return SaveInst;179}180 181// Collect "interesting" coroutine intrinsics.182void coro::Shape::analyze(Function &F,183                          SmallVectorImpl<CoroFrameInst *> &CoroFrames,184                          SmallVectorImpl<CoroSaveInst *> &UnusedCoroSaves,185                          CoroPromiseInst *&CoroPromise) {186  clear();187 188  bool HasFinalSuspend = false;189  bool HasUnwindCoroEnd = false;190  size_t FinalSuspendIndex = 0;191 192  for (Instruction &I : instructions(F)) {193    // FIXME: coro_await_suspend_* are not proper `IntrinisicInst`s194    // because they might be invoked195    if (auto AWS = dyn_cast<CoroAwaitSuspendInst>(&I)) {196      CoroAwaitSuspends.push_back(AWS);197    } else if (auto II = dyn_cast<IntrinsicInst>(&I)) {198      switch (II->getIntrinsicID()) {199      default:200        continue;201      case Intrinsic::coro_size:202        CoroSizes.push_back(cast<CoroSizeInst>(II));203        break;204      case Intrinsic::coro_align:205        CoroAligns.push_back(cast<CoroAlignInst>(II));206        break;207      case Intrinsic::coro_frame:208        CoroFrames.push_back(cast<CoroFrameInst>(II));209        break;210      case Intrinsic::coro_save:211        // After optimizations, coro_suspends using this coro_save might have212        // been removed, remember orphaned coro_saves to remove them later.213        if (II->use_empty())214          UnusedCoroSaves.push_back(cast<CoroSaveInst>(II));215        break;216      case Intrinsic::coro_suspend_async: {217        auto *Suspend = cast<CoroSuspendAsyncInst>(II);218        Suspend->checkWellFormed();219        CoroSuspends.push_back(Suspend);220        break;221      }222      case Intrinsic::coro_suspend_retcon: {223        auto Suspend = cast<CoroSuspendRetconInst>(II);224        CoroSuspends.push_back(Suspend);225        break;226      }227      case Intrinsic::coro_suspend: {228        auto Suspend = cast<CoroSuspendInst>(II);229        CoroSuspends.push_back(Suspend);230        if (Suspend->isFinal()) {231          if (HasFinalSuspend)232            report_fatal_error(233              "Only one suspend point can be marked as final");234          HasFinalSuspend = true;235          FinalSuspendIndex = CoroSuspends.size() - 1;236        }237        break;238      }239      case Intrinsic::coro_begin:240      case Intrinsic::coro_begin_custom_abi: {241        auto CB = cast<CoroBeginInst>(II);242 243        // Ignore coro id's that aren't pre-split.244        auto Id = dyn_cast<CoroIdInst>(CB->getId());245        if (Id && !Id->getInfo().isPreSplit())246          break;247 248        if (CoroBegin)249          report_fatal_error(250                "coroutine should have exactly one defining @llvm.coro.begin");251        CB->addRetAttr(Attribute::NonNull);252        CB->addRetAttr(Attribute::NoAlias);253        CB->removeFnAttr(Attribute::NoDuplicate);254        CoroBegin = CB;255        break;256      }257      case Intrinsic::coro_end_async:258      case Intrinsic::coro_end:259        CoroEnds.push_back(cast<AnyCoroEndInst>(II));260        if (auto *AsyncEnd = dyn_cast<CoroAsyncEndInst>(II)) {261          AsyncEnd->checkWellFormed();262        }263 264        if (CoroEnds.back()->isUnwind())265          HasUnwindCoroEnd = true;266 267        if (CoroEnds.back()->isFallthrough() && isa<CoroEndInst>(II)) {268          // Make sure that the fallthrough coro.end is the first element in the269          // CoroEnds vector.270          // Note: I don't think this is neccessary anymore.271          if (CoroEnds.size() > 1) {272            if (CoroEnds.front()->isFallthrough())273              report_fatal_error(274                  "Only one coro.end can be marked as fallthrough");275            std::swap(CoroEnds.front(), CoroEnds.back());276          }277        }278        break;279      case Intrinsic::coro_is_in_ramp:280        CoroIsInRampInsts.push_back(cast<CoroIsInRampInst>(II));281        break;282      case Intrinsic::coro_promise:283        assert(CoroPromise == nullptr &&284               "CoroEarly must ensure coro.promise unique");285        CoroPromise = cast<CoroPromiseInst>(II);286        break;287      }288    }289  }290 291  // If there is no CoroBegin then this is not a coroutine.292  if (!CoroBegin)293    return;294 295  // Determination of ABI and initializing lowering info296  auto Id = CoroBegin->getId();297  switch (auto IntrID = Id->getIntrinsicID()) {298  case Intrinsic::coro_id: {299    ABI = coro::ABI::Switch;300    SwitchLowering.HasFinalSuspend = HasFinalSuspend;301    SwitchLowering.HasUnwindCoroEnd = HasUnwindCoroEnd;302 303    auto SwitchId = getSwitchCoroId();304    SwitchLowering.ResumeSwitch = nullptr;305    SwitchLowering.PromiseAlloca = SwitchId->getPromise();306    SwitchLowering.ResumeEntryBlock = nullptr;307 308    // Move final suspend to the last element in the CoroSuspends vector.309    if (SwitchLowering.HasFinalSuspend &&310        FinalSuspendIndex != CoroSuspends.size() - 1)311      std::swap(CoroSuspends[FinalSuspendIndex], CoroSuspends.back());312    break;313  }314  case Intrinsic::coro_id_async: {315    ABI = coro::ABI::Async;316    auto *AsyncId = getAsyncCoroId();317    AsyncId->checkWellFormed();318    AsyncLowering.Context = AsyncId->getStorage();319    AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex();320    AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize();321    AsyncLowering.ContextAlignment = AsyncId->getStorageAlignment().value();322    AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer();323    AsyncLowering.AsyncCC = F.getCallingConv();324    break;325  }326  case Intrinsic::coro_id_retcon:327  case Intrinsic::coro_id_retcon_once: {328    ABI = IntrID == Intrinsic::coro_id_retcon ? coro::ABI::Retcon329                                              : coro::ABI::RetconOnce;330    auto ContinuationId = getRetconCoroId();331    ContinuationId->checkWellFormed();332    auto Prototype = ContinuationId->getPrototype();333    RetconLowering.ResumePrototype = Prototype;334    RetconLowering.Alloc = ContinuationId->getAllocFunction();335    RetconLowering.Dealloc = ContinuationId->getDeallocFunction();336    RetconLowering.ReturnBlock = nullptr;337    RetconLowering.IsFrameInlineInStorage = false;338    break;339  }340  default:341    llvm_unreachable("coro.begin is not dependent on a coro.id call");342  }343}344 345// If for some reason, we were not able to find coro.begin, bailout.346void coro::Shape::invalidateCoroutine(347    Function &F, SmallVectorImpl<CoroFrameInst *> &CoroFrames) {348  assert(!CoroBegin);349  {350    // Replace coro.frame which are supposed to be lowered to the result of351    // coro.begin with poison.352    auto *Poison = PoisonValue::get(PointerType::get(F.getContext(), 0));353    for (CoroFrameInst *CF : CoroFrames) {354      CF->replaceAllUsesWith(Poison);355      CF->eraseFromParent();356    }357    CoroFrames.clear();358 359    // Replace all coro.suspend with poison and remove related coro.saves if360    // present.361    for (AnyCoroSuspendInst *CS : CoroSuspends) {362      CS->replaceAllUsesWith(PoisonValue::get(CS->getType()));363      if (auto *CoroSave = CS->getCoroSave())364        CoroSave->eraseFromParent();365      CS->eraseFromParent();366    }367    CoroSuspends.clear();368 369    // Replace all coro.ends with unreachable instruction.370    for (AnyCoroEndInst *CE : CoroEnds)371      changeToUnreachable(CE);372  }373}374 375void coro::SwitchABI::init() {376  assert(Shape.ABI == coro::ABI::Switch);377  {378    for (auto *AnySuspend : Shape.CoroSuspends) {379      auto Suspend = dyn_cast<CoroSuspendInst>(AnySuspend);380      if (!Suspend) {381#ifndef NDEBUG382        AnySuspend->dump();383#endif384        report_fatal_error("coro.id must be paired with coro.suspend");385      }386 387      if (!Suspend->getCoroSave())388        createCoroSave(Shape.CoroBegin, Suspend);389    }390  }391}392 393void coro::AsyncABI::init() { assert(Shape.ABI == coro::ABI::Async); }394 395void coro::AnyRetconABI::init() {396  assert(Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce);397  {398    // Determine the result value types, and make sure they match up with399    // the values passed to the suspends.400    auto ResultTys = Shape.getRetconResultTypes();401    auto ResumeTys = Shape.getRetconResumeTypes();402 403    for (auto *AnySuspend : Shape.CoroSuspends) {404      auto Suspend = dyn_cast<CoroSuspendRetconInst>(AnySuspend);405      if (!Suspend) {406#ifndef NDEBUG407        AnySuspend->dump();408#endif409        report_fatal_error("coro.id.retcon.* must be paired with "410                           "coro.suspend.retcon");411      }412 413      // Check that the argument types of the suspend match the results.414      auto SI = Suspend->value_begin(), SE = Suspend->value_end();415      auto RI = ResultTys.begin(), RE = ResultTys.end();416      for (; SI != SE && RI != RE; ++SI, ++RI) {417        auto SrcTy = (*SI)->getType();418        if (SrcTy != *RI) {419          // The optimizer likes to eliminate bitcasts leading into variadic420          // calls, but that messes with our invariants.  Re-insert the421          // bitcast and ignore this type mismatch.422          if (CastInst::isBitCastable(SrcTy, *RI)) {423            auto BCI = new BitCastInst(*SI, *RI, "", Suspend->getIterator());424            SI->set(BCI);425            continue;426          }427 428#ifndef NDEBUG429          Suspend->dump();430          Shape.RetconLowering.ResumePrototype->getFunctionType()->dump();431#endif432          report_fatal_error("argument to coro.suspend.retcon does not "433                             "match corresponding prototype function result");434        }435      }436      if (SI != SE || RI != RE) {437#ifndef NDEBUG438        Suspend->dump();439        Shape.RetconLowering.ResumePrototype->getFunctionType()->dump();440#endif441        report_fatal_error("wrong number of arguments to coro.suspend.retcon");442      }443 444      // Check that the result type of the suspend matches the resume types.445      Type *SResultTy = Suspend->getType();446      ArrayRef<Type *> SuspendResultTys;447      if (SResultTy->isVoidTy()) {448        // leave as empty array449      } else if (auto SResultStructTy = dyn_cast<StructType>(SResultTy)) {450        SuspendResultTys = SResultStructTy->elements();451      } else {452        // forms an ArrayRef using SResultTy, be careful453        SuspendResultTys = SResultTy;454      }455      if (SuspendResultTys.size() != ResumeTys.size()) {456#ifndef NDEBUG457        Suspend->dump();458        Shape.RetconLowering.ResumePrototype->getFunctionType()->dump();459#endif460        report_fatal_error("wrong number of results from coro.suspend.retcon");461      }462      for (size_t I = 0, E = ResumeTys.size(); I != E; ++I) {463        if (SuspendResultTys[I] != ResumeTys[I]) {464#ifndef NDEBUG465          Suspend->dump();466          Shape.RetconLowering.ResumePrototype->getFunctionType()->dump();467#endif468          report_fatal_error("result from coro.suspend.retcon does not "469                             "match corresponding prototype function param");470        }471      }472    }473  }474}475 476void coro::Shape::cleanCoroutine(477    SmallVectorImpl<CoroFrameInst *> &CoroFrames,478    SmallVectorImpl<CoroSaveInst *> &UnusedCoroSaves, CoroPromiseInst *PI) {479  // The coro.frame intrinsic is always lowered to the result of coro.begin.480  for (CoroFrameInst *CF : CoroFrames) {481    CF->replaceAllUsesWith(CoroBegin);482    CF->eraseFromParent();483  }484  CoroFrames.clear();485 486  // Remove orphaned coro.saves.487  for (CoroSaveInst *CoroSave : UnusedCoroSaves)488    CoroSave->eraseFromParent();489  UnusedCoroSaves.clear();490 491  if (PI) {492    PI->replaceAllUsesWith(PI->isFromPromise()493                               ? cast<Value>(CoroBegin)494                               : cast<Value>(getPromiseAlloca()));495    PI->eraseFromParent();496  }497}498 499static void propagateCallAttrsFromCallee(CallInst *Call, Function *Callee) {500  Call->setCallingConv(Callee->getCallingConv());501  // TODO: attributes?502}503 504static void addCallToCallGraph(CallGraph *CG, CallInst *Call, Function *Callee){505  if (CG)506    (*CG)[Call->getFunction()]->addCalledFunction(Call, (*CG)[Callee]);507}508 509Value *coro::Shape::emitAlloc(IRBuilder<> &Builder, Value *Size,510                              CallGraph *CG) const {511  switch (ABI) {512  case coro::ABI::Switch:513    llvm_unreachable("can't allocate memory in coro switch-lowering");514 515  case coro::ABI::Retcon:516  case coro::ABI::RetconOnce: {517    auto Alloc = RetconLowering.Alloc;518    Size = Builder.CreateIntCast(Size,519                                 Alloc->getFunctionType()->getParamType(0),520                                 /*is signed*/ false);521    auto *Call = Builder.CreateCall(Alloc, Size);522    propagateCallAttrsFromCallee(Call, Alloc);523    addCallToCallGraph(CG, Call, Alloc);524    return Call;525  }526  case coro::ABI::Async:527    llvm_unreachable("can't allocate memory in coro async-lowering");528  }529  llvm_unreachable("Unknown coro::ABI enum");530}531 532void coro::Shape::emitDealloc(IRBuilder<> &Builder, Value *Ptr,533                              CallGraph *CG) const {534  switch (ABI) {535  case coro::ABI::Switch:536    llvm_unreachable("can't allocate memory in coro switch-lowering");537 538  case coro::ABI::Retcon:539  case coro::ABI::RetconOnce: {540    auto Dealloc = RetconLowering.Dealloc;541    Ptr = Builder.CreateBitCast(Ptr,542                                Dealloc->getFunctionType()->getParamType(0));543    auto *Call = Builder.CreateCall(Dealloc, Ptr);544    propagateCallAttrsFromCallee(Call, Dealloc);545    addCallToCallGraph(CG, Call, Dealloc);546    return;547  }548  case coro::ABI::Async:549    llvm_unreachable("can't allocate memory in coro async-lowering");550  }551  llvm_unreachable("Unknown coro::ABI enum");552}553 554[[noreturn]] static void fail(const Instruction *I, const char *Reason,555                              Value *V) {556#ifndef NDEBUG557  I->dump();558  if (V) {559    errs() << "  Value: ";560    V->printAsOperand(llvm::errs());561    errs() << '\n';562  }563#endif564  report_fatal_error(Reason);565}566 567/// Check that the given value is a well-formed prototype for the568/// llvm.coro.id.retcon.* intrinsics.569static void checkWFRetconPrototype(const AnyCoroIdRetconInst *I, Value *V) {570  auto F = dyn_cast<Function>(V->stripPointerCasts());571  if (!F)572    fail(I, "llvm.coro.id.retcon.* prototype not a Function", V);573 574  auto FT = F->getFunctionType();575 576  if (isa<CoroIdRetconInst>(I)) {577    bool ResultOkay;578    if (FT->getReturnType()->isPointerTy()) {579      ResultOkay = true;580    } else if (auto SRetTy = dyn_cast<StructType>(FT->getReturnType())) {581      ResultOkay = (!SRetTy->isOpaque() &&582                    SRetTy->getNumElements() > 0 &&583                    SRetTy->getElementType(0)->isPointerTy());584    } else {585      ResultOkay = false;586    }587    if (!ResultOkay)588      fail(I, "llvm.coro.id.retcon prototype must return pointer as first "589              "result", F);590 591    if (FT->getReturnType() !=592          I->getFunction()->getFunctionType()->getReturnType())593      fail(I, "llvm.coro.id.retcon prototype return type must be same as"594              "current function return type", F);595  } else {596    // No meaningful validation to do here for llvm.coro.id.unique.once.597  }598 599  if (FT->getNumParams() == 0 || !FT->getParamType(0)->isPointerTy())600    fail(I, "llvm.coro.id.retcon.* prototype must take pointer as "601            "its first parameter", F);602}603 604/// Check that the given value is a well-formed allocator.605static void checkWFAlloc(const Instruction *I, Value *V) {606  auto F = dyn_cast<Function>(V->stripPointerCasts());607  if (!F)608    fail(I, "llvm.coro.* allocator not a Function", V);609 610  auto FT = F->getFunctionType();611  if (!FT->getReturnType()->isPointerTy())612    fail(I, "llvm.coro.* allocator must return a pointer", F);613 614  if (FT->getNumParams() != 1 ||615      !FT->getParamType(0)->isIntegerTy())616    fail(I, "llvm.coro.* allocator must take integer as only param", F);617}618 619/// Check that the given value is a well-formed deallocator.620static void checkWFDealloc(const Instruction *I, Value *V) {621  auto F = dyn_cast<Function>(V->stripPointerCasts());622  if (!F)623    fail(I, "llvm.coro.* deallocator not a Function", V);624 625  auto FT = F->getFunctionType();626  if (!FT->getReturnType()->isVoidTy())627    fail(I, "llvm.coro.* deallocator must return void", F);628 629  if (FT->getNumParams() != 1 ||630      !FT->getParamType(0)->isPointerTy())631    fail(I, "llvm.coro.* deallocator must take pointer as only param", F);632}633 634static void checkConstantInt(const Instruction *I, Value *V,635                             const char *Reason) {636  if (!isa<ConstantInt>(V)) {637    fail(I, Reason, V);638  }639}640 641void AnyCoroIdRetconInst::checkWellFormed() const {642  checkConstantInt(this, getArgOperand(SizeArg),643                   "size argument to coro.id.retcon.* must be constant");644  checkConstantInt(this, getArgOperand(AlignArg),645                   "alignment argument to coro.id.retcon.* must be constant");646  checkWFRetconPrototype(this, getArgOperand(PrototypeArg));647  checkWFAlloc(this, getArgOperand(AllocArg));648  checkWFDealloc(this, getArgOperand(DeallocArg));649}650 651static void checkAsyncFuncPointer(const Instruction *I, Value *V) {652  auto *AsyncFuncPtrAddr = dyn_cast<GlobalVariable>(V->stripPointerCasts());653  if (!AsyncFuncPtrAddr)654    fail(I, "llvm.coro.id.async async function pointer not a global", V);655}656 657void CoroIdAsyncInst::checkWellFormed() const {658  checkConstantInt(this, getArgOperand(SizeArg),659                   "size argument to coro.id.async must be constant");660  checkConstantInt(this, getArgOperand(AlignArg),661                   "alignment argument to coro.id.async must be constant");662  checkConstantInt(this, getArgOperand(StorageArg),663                   "storage argument offset to coro.id.async must be constant");664  checkAsyncFuncPointer(this, getArgOperand(AsyncFuncPtrArg));665}666 667static void checkAsyncContextProjectFunction(const Instruction *I,668                                             Function *F) {669  auto *FunTy = cast<FunctionType>(F->getValueType());670  if (!FunTy->getReturnType()->isPointerTy())671    fail(I,672         "llvm.coro.suspend.async resume function projection function must "673         "return a ptr type",674         F);675  if (FunTy->getNumParams() != 1 || !FunTy->getParamType(0)->isPointerTy())676    fail(I,677         "llvm.coro.suspend.async resume function projection function must "678         "take one ptr type as parameter",679         F);680}681 682void CoroSuspendAsyncInst::checkWellFormed() const {683  checkAsyncContextProjectFunction(this, getAsyncContextProjectionFunction());684}685 686void CoroAsyncEndInst::checkWellFormed() const {687  auto *MustTailCallFunc = getMustTailCallFunction();688  if (!MustTailCallFunc)689    return;690  auto *FnTy = MustTailCallFunc->getFunctionType();691  if (FnTy->getNumParams() != (arg_size() - 3))692    fail(this,693         "llvm.coro.end.async must tail call function argument type must "694         "match the tail arguments",695         MustTailCallFunc);696}697