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