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