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 42 using namespace llvm; 43 44 void llvm::initializeCoroutines(PassRegistry &Registry) { 45 initializeCoroEarlyLegacyPass(Registry); 46 initializeCoroSplitLegacyPass(Registry); 47 initializeCoroElideLegacyPass(Registry); 48 initializeCoroCleanupLegacyPass(Registry); 49 } 50 51 static 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 60 static void addCoroutineEarlyPasses(const PassManagerBuilder &Builder, 61 legacy::PassManagerBase &PM) { 62 PM.add(createCoroEarlyLegacyPass()); 63 } 64 65 static void addCoroutineScalarOptimizerPasses(const PassManagerBuilder &Builder, 66 legacy::PassManagerBase &PM) { 67 PM.add(createCoroElideLegacyPass()); 68 } 69 70 static void addCoroutineSCCPasses(const PassManagerBuilder &Builder, 71 legacy::PassManagerBase &PM) { 72 PM.add(createCoroSplitLegacyPass(Builder.OptLevel != 0)); 73 } 74 75 static void addCoroutineOptimizerLastPasses(const PassManagerBuilder &Builder, 76 legacy::PassManagerBase &PM) { 77 PM.add(createCoroCleanupLegacyPass()); 78 } 79 80 void 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. 94 coro::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 107 Value *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 123 static bool isCoroutineIntrinsicName(StringRef Name) { 124 // NOTE: Must be sorted! 125 static const char *const CoroIntrinsics[] = { 126 "llvm.coro.align", 127 "llvm.coro.alloc", 128 "llvm.coro.async.context.alloc", 129 "llvm.coro.async.context.dealloc", 130 "llvm.coro.async.resume", 131 "llvm.coro.async.size.replace", 132 "llvm.coro.async.store_resume", 133 "llvm.coro.begin", 134 "llvm.coro.destroy", 135 "llvm.coro.done", 136 "llvm.coro.end", 137 "llvm.coro.end.async", 138 "llvm.coro.frame", 139 "llvm.coro.free", 140 "llvm.coro.id", 141 "llvm.coro.id.async", 142 "llvm.coro.id.retcon", 143 "llvm.coro.id.retcon.once", 144 "llvm.coro.noop", 145 "llvm.coro.prepare.async", 146 "llvm.coro.prepare.retcon", 147 "llvm.coro.promise", 148 "llvm.coro.resume", 149 "llvm.coro.save", 150 "llvm.coro.size", 151 "llvm.coro.subfn.addr", 152 "llvm.coro.suspend", 153 "llvm.coro.suspend.async", 154 "llvm.coro.suspend.retcon", 155 }; 156 return Intrinsic::lookupLLVMIntrinsicByName(CoroIntrinsics, Name) != -1; 157 } 158 #endif 159 160 // Verifies if a module has named values listed. Also, in debug mode verifies 161 // that names are intrinsic names. 162 bool coro::declaresIntrinsics(const Module &M, 163 const std::initializer_list<StringRef> List) { 164 for (StringRef Name : List) { 165 assert(isCoroutineIntrinsicName(Name) && "not a coroutine intrinsic"); 166 if (M.getNamedValue(Name)) 167 return true; 168 } 169 170 return false; 171 } 172 173 // Replace all coro.frees associated with the provided CoroId either with 'null' 174 // if Elide is true and with its frame parameter otherwise. 175 void coro::replaceCoroFree(CoroIdInst *CoroId, bool Elide) { 176 SmallVector<CoroFreeInst *, 4> CoroFrees; 177 for (User *U : CoroId->users()) 178 if (auto CF = dyn_cast<CoroFreeInst>(U)) 179 CoroFrees.push_back(CF); 180 181 if (CoroFrees.empty()) 182 return; 183 184 Value *Replacement = 185 Elide ? ConstantPointerNull::get(Type::getInt8PtrTy(CoroId->getContext())) 186 : CoroFrees.front()->getFrame(); 187 188 for (CoroFreeInst *CF : CoroFrees) { 189 CF->replaceAllUsesWith(Replacement); 190 CF->eraseFromParent(); 191 } 192 } 193 194 // FIXME: This code is stolen from CallGraph::addToCallGraph(Function *F), which 195 // happens to be private. It is better for this functionality exposed by the 196 // CallGraph. 197 static void buildCGN(CallGraph &CG, CallGraphNode *Node) { 198 Function *F = Node->getFunction(); 199 200 // Look for calls by this function. 201 for (Instruction &I : instructions(F)) 202 if (auto *Call = dyn_cast<CallBase>(&I)) { 203 const Function *Callee = Call->getCalledFunction(); 204 if (!Callee || !Intrinsic::isLeaf(Callee->getIntrinsicID())) 205 // Indirect calls of intrinsics are not allowed so no need to check. 206 // We can be more precise here by using TargetArg returned by 207 // Intrinsic::isLeaf. 208 Node->addCalledFunction(Call, CG.getCallsExternalNode()); 209 else if (!Callee->isIntrinsic()) 210 Node->addCalledFunction(Call, CG.getOrInsertFunction(Callee)); 211 } 212 } 213 214 // Rebuild CGN after we extracted parts of the code from ParentFunc into 215 // NewFuncs. Builds CGNs for the NewFuncs and adds them to the current SCC. 216 void coro::updateCallGraph(Function &ParentFunc, ArrayRef<Function *> NewFuncs, 217 CallGraph &CG, CallGraphSCC &SCC) { 218 // Rebuild CGN from scratch for the ParentFunc 219 auto *ParentNode = CG[&ParentFunc]; 220 ParentNode->removeAllCalledFunctions(); 221 buildCGN(CG, ParentNode); 222 223 SmallVector<CallGraphNode *, 8> Nodes(SCC.begin(), SCC.end()); 224 225 for (Function *F : NewFuncs) { 226 CallGraphNode *Callee = CG.getOrInsertFunction(F); 227 Nodes.push_back(Callee); 228 buildCGN(CG, Callee); 229 } 230 231 SCC.initialize(Nodes); 232 } 233 234 static void clear(coro::Shape &Shape) { 235 Shape.CoroBegin = nullptr; 236 Shape.CoroEnds.clear(); 237 Shape.CoroSizes.clear(); 238 Shape.CoroSuspends.clear(); 239 240 Shape.FrameTy = nullptr; 241 Shape.FramePtr = nullptr; 242 Shape.AllocaSpillBlock = nullptr; 243 } 244 245 static CoroSaveInst *createCoroSave(CoroBeginInst *CoroBegin, 246 CoroSuspendInst *SuspendInst) { 247 Module *M = SuspendInst->getModule(); 248 auto *Fn = Intrinsic::getDeclaration(M, Intrinsic::coro_save); 249 auto *SaveInst = 250 cast<CoroSaveInst>(CallInst::Create(Fn, CoroBegin, "", SuspendInst)); 251 assert(!SuspendInst->getCoroSave()); 252 SuspendInst->setArgOperand(0, SaveInst); 253 return SaveInst; 254 } 255 256 // Collect "interesting" coroutine intrinsics. 257 void coro::Shape::buildFrom(Function &F) { 258 bool HasFinalSuspend = false; 259 size_t FinalSuspendIndex = 0; 260 clear(*this); 261 SmallVector<CoroFrameInst *, 8> CoroFrames; 262 SmallVector<CoroSaveInst *, 2> UnusedCoroSaves; 263 264 for (Instruction &I : instructions(F)) { 265 if (auto II = dyn_cast<IntrinsicInst>(&I)) { 266 switch (II->getIntrinsicID()) { 267 default: 268 continue; 269 case Intrinsic::coro_size: 270 CoroSizes.push_back(cast<CoroSizeInst>(II)); 271 break; 272 case Intrinsic::coro_align: 273 CoroAligns.push_back(cast<CoroAlignInst>(II)); 274 break; 275 case Intrinsic::coro_frame: 276 CoroFrames.push_back(cast<CoroFrameInst>(II)); 277 break; 278 case Intrinsic::coro_save: 279 // After optimizations, coro_suspends using this coro_save might have 280 // been removed, remember orphaned coro_saves to remove them later. 281 if (II->use_empty()) 282 UnusedCoroSaves.push_back(cast<CoroSaveInst>(II)); 283 break; 284 case Intrinsic::coro_suspend_async: { 285 auto *Suspend = cast<CoroSuspendAsyncInst>(II); 286 Suspend->checkWellFormed(); 287 CoroSuspends.push_back(Suspend); 288 break; 289 } 290 case Intrinsic::coro_suspend_retcon: { 291 auto Suspend = cast<CoroSuspendRetconInst>(II); 292 CoroSuspends.push_back(Suspend); 293 break; 294 } 295 case Intrinsic::coro_suspend: { 296 auto Suspend = cast<CoroSuspendInst>(II); 297 CoroSuspends.push_back(Suspend); 298 if (Suspend->isFinal()) { 299 if (HasFinalSuspend) 300 report_fatal_error( 301 "Only one suspend point can be marked as final"); 302 HasFinalSuspend = true; 303 FinalSuspendIndex = CoroSuspends.size() - 1; 304 } 305 break; 306 } 307 case Intrinsic::coro_begin: { 308 auto CB = cast<CoroBeginInst>(II); 309 310 // Ignore coro id's that aren't pre-split. 311 auto Id = dyn_cast<CoroIdInst>(CB->getId()); 312 if (Id && !Id->getInfo().isPreSplit()) 313 break; 314 315 if (CoroBegin) 316 report_fatal_error( 317 "coroutine should have exactly one defining @llvm.coro.begin"); 318 CB->addRetAttr(Attribute::NonNull); 319 CB->addRetAttr(Attribute::NoAlias); 320 CB->removeFnAttr(Attribute::NoDuplicate); 321 CoroBegin = CB; 322 break; 323 } 324 case Intrinsic::coro_end_async: 325 case Intrinsic::coro_end: 326 CoroEnds.push_back(cast<AnyCoroEndInst>(II)); 327 if (auto *AsyncEnd = dyn_cast<CoroAsyncEndInst>(II)) { 328 AsyncEnd->checkWellFormed(); 329 } 330 if (CoroEnds.back()->isFallthrough() && isa<CoroEndInst>(II)) { 331 // Make sure that the fallthrough coro.end is the first element in the 332 // CoroEnds vector. 333 // Note: I don't think this is neccessary anymore. 334 if (CoroEnds.size() > 1) { 335 if (CoroEnds.front()->isFallthrough()) 336 report_fatal_error( 337 "Only one coro.end can be marked as fallthrough"); 338 std::swap(CoroEnds.front(), CoroEnds.back()); 339 } 340 } 341 break; 342 } 343 } 344 } 345 346 // If for some reason, we were not able to find coro.begin, bailout. 347 if (!CoroBegin) { 348 // Replace coro.frame which are supposed to be lowered to the result of 349 // coro.begin with undef. 350 auto *Undef = UndefValue::get(Type::getInt8PtrTy(F.getContext())); 351 for (CoroFrameInst *CF : CoroFrames) { 352 CF->replaceAllUsesWith(Undef); 353 CF->eraseFromParent(); 354 } 355 356 // Replace all coro.suspend with undef and remove related coro.saves if 357 // present. 358 for (AnyCoroSuspendInst *CS : CoroSuspends) { 359 CS->replaceAllUsesWith(UndefValue::get(CS->getType())); 360 CS->eraseFromParent(); 361 if (auto *CoroSave = CS->getCoroSave()) 362 CoroSave->eraseFromParent(); 363 } 364 365 // Replace all coro.ends with unreachable instruction. 366 for (AnyCoroEndInst *CE : CoroEnds) 367 changeToUnreachable(CE); 368 369 return; 370 } 371 372 auto Id = CoroBegin->getId(); 373 switch (auto IdIntrinsic = Id->getIntrinsicID()) { 374 case Intrinsic::coro_id: { 375 auto SwitchId = cast<CoroIdInst>(Id); 376 this->ABI = coro::ABI::Switch; 377 this->SwitchLowering.HasFinalSuspend = HasFinalSuspend; 378 this->SwitchLowering.ResumeSwitch = nullptr; 379 this->SwitchLowering.PromiseAlloca = SwitchId->getPromise(); 380 this->SwitchLowering.ResumeEntryBlock = nullptr; 381 382 for (auto AnySuspend : CoroSuspends) { 383 auto Suspend = dyn_cast<CoroSuspendInst>(AnySuspend); 384 if (!Suspend) { 385 #ifndef NDEBUG 386 AnySuspend->dump(); 387 #endif 388 report_fatal_error("coro.id must be paired with coro.suspend"); 389 } 390 391 if (!Suspend->getCoroSave()) 392 createCoroSave(CoroBegin, Suspend); 393 } 394 break; 395 } 396 case Intrinsic::coro_id_async: { 397 auto *AsyncId = cast<CoroIdAsyncInst>(Id); 398 AsyncId->checkWellFormed(); 399 this->ABI = coro::ABI::Async; 400 this->AsyncLowering.Context = AsyncId->getStorage(); 401 this->AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex(); 402 this->AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize(); 403 this->AsyncLowering.ContextAlignment = 404 AsyncId->getStorageAlignment().value(); 405 this->AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer(); 406 this->AsyncLowering.AsyncCC = F.getCallingConv(); 407 break; 408 }; 409 case Intrinsic::coro_id_retcon: 410 case Intrinsic::coro_id_retcon_once: { 411 auto ContinuationId = cast<AnyCoroIdRetconInst>(Id); 412 ContinuationId->checkWellFormed(); 413 this->ABI = (IdIntrinsic == Intrinsic::coro_id_retcon 414 ? coro::ABI::Retcon 415 : coro::ABI::RetconOnce); 416 auto Prototype = ContinuationId->getPrototype(); 417 this->RetconLowering.ResumePrototype = Prototype; 418 this->RetconLowering.Alloc = ContinuationId->getAllocFunction(); 419 this->RetconLowering.Dealloc = ContinuationId->getDeallocFunction(); 420 this->RetconLowering.ReturnBlock = nullptr; 421 this->RetconLowering.IsFrameInlineInStorage = false; 422 423 // Determine the result value types, and make sure they match up with 424 // the values passed to the suspends. 425 auto ResultTys = getRetconResultTypes(); 426 auto ResumeTys = getRetconResumeTypes(); 427 428 for (auto AnySuspend : CoroSuspends) { 429 auto Suspend = dyn_cast<CoroSuspendRetconInst>(AnySuspend); 430 if (!Suspend) { 431 #ifndef NDEBUG 432 AnySuspend->dump(); 433 #endif 434 report_fatal_error("coro.id.retcon.* must be paired with " 435 "coro.suspend.retcon"); 436 } 437 438 // Check that the argument types of the suspend match the results. 439 auto SI = Suspend->value_begin(), SE = Suspend->value_end(); 440 auto RI = ResultTys.begin(), RE = ResultTys.end(); 441 for (; SI != SE && RI != RE; ++SI, ++RI) { 442 auto SrcTy = (*SI)->getType(); 443 if (SrcTy != *RI) { 444 // The optimizer likes to eliminate bitcasts leading into variadic 445 // calls, but that messes with our invariants. Re-insert the 446 // bitcast and ignore this type mismatch. 447 if (CastInst::isBitCastable(SrcTy, *RI)) { 448 auto BCI = new BitCastInst(*SI, *RI, "", Suspend); 449 SI->set(BCI); 450 continue; 451 } 452 453 #ifndef NDEBUG 454 Suspend->dump(); 455 Prototype->getFunctionType()->dump(); 456 #endif 457 report_fatal_error("argument to coro.suspend.retcon does not " 458 "match corresponding prototype function result"); 459 } 460 } 461 if (SI != SE || RI != RE) { 462 #ifndef NDEBUG 463 Suspend->dump(); 464 Prototype->getFunctionType()->dump(); 465 #endif 466 report_fatal_error("wrong number of arguments to coro.suspend.retcon"); 467 } 468 469 // Check that the result type of the suspend matches the resume types. 470 Type *SResultTy = Suspend->getType(); 471 ArrayRef<Type*> SuspendResultTys; 472 if (SResultTy->isVoidTy()) { 473 // leave as empty array 474 } else if (auto SResultStructTy = dyn_cast<StructType>(SResultTy)) { 475 SuspendResultTys = SResultStructTy->elements(); 476 } else { 477 // forms an ArrayRef using SResultTy, be careful 478 SuspendResultTys = SResultTy; 479 } 480 if (SuspendResultTys.size() != ResumeTys.size()) { 481 #ifndef NDEBUG 482 Suspend->dump(); 483 Prototype->getFunctionType()->dump(); 484 #endif 485 report_fatal_error("wrong number of results from coro.suspend.retcon"); 486 } 487 for (size_t I = 0, E = ResumeTys.size(); I != E; ++I) { 488 if (SuspendResultTys[I] != ResumeTys[I]) { 489 #ifndef NDEBUG 490 Suspend->dump(); 491 Prototype->getFunctionType()->dump(); 492 #endif 493 report_fatal_error("result from coro.suspend.retcon does not " 494 "match corresponding prototype function param"); 495 } 496 } 497 } 498 break; 499 } 500 501 default: 502 llvm_unreachable("coro.begin is not dependent on a coro.id call"); 503 } 504 505 // The coro.free intrinsic is always lowered to the result of coro.begin. 506 for (CoroFrameInst *CF : CoroFrames) { 507 CF->replaceAllUsesWith(CoroBegin); 508 CF->eraseFromParent(); 509 } 510 511 // Move final suspend to be the last element in the CoroSuspends vector. 512 if (ABI == coro::ABI::Switch && 513 SwitchLowering.HasFinalSuspend && 514 FinalSuspendIndex != CoroSuspends.size() - 1) 515 std::swap(CoroSuspends[FinalSuspendIndex], CoroSuspends.back()); 516 517 // Remove orphaned coro.saves. 518 for (CoroSaveInst *CoroSave : UnusedCoroSaves) 519 CoroSave->eraseFromParent(); 520 } 521 522 static void propagateCallAttrsFromCallee(CallInst *Call, Function *Callee) { 523 Call->setCallingConv(Callee->getCallingConv()); 524 // TODO: attributes? 525 } 526 527 static void addCallToCallGraph(CallGraph *CG, CallInst *Call, Function *Callee){ 528 if (CG) 529 (*CG)[Call->getFunction()]->addCalledFunction(Call, (*CG)[Callee]); 530 } 531 532 Value *coro::Shape::emitAlloc(IRBuilder<> &Builder, Value *Size, 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 Alloc = RetconLowering.Alloc; 541 Size = Builder.CreateIntCast(Size, 542 Alloc->getFunctionType()->getParamType(0), 543 /*is signed*/ false); 544 auto *Call = Builder.CreateCall(Alloc, Size); 545 propagateCallAttrsFromCallee(Call, Alloc); 546 addCallToCallGraph(CG, Call, Alloc); 547 return Call; 548 } 549 case coro::ABI::Async: 550 llvm_unreachable("can't allocate memory in coro async-lowering"); 551 } 552 llvm_unreachable("Unknown coro::ABI enum"); 553 } 554 555 void coro::Shape::emitDealloc(IRBuilder<> &Builder, Value *Ptr, 556 CallGraph *CG) const { 557 switch (ABI) { 558 case coro::ABI::Switch: 559 llvm_unreachable("can't allocate memory in coro switch-lowering"); 560 561 case coro::ABI::Retcon: 562 case coro::ABI::RetconOnce: { 563 auto Dealloc = RetconLowering.Dealloc; 564 Ptr = Builder.CreateBitCast(Ptr, 565 Dealloc->getFunctionType()->getParamType(0)); 566 auto *Call = Builder.CreateCall(Dealloc, Ptr); 567 propagateCallAttrsFromCallee(Call, Dealloc); 568 addCallToCallGraph(CG, Call, Dealloc); 569 return; 570 } 571 case coro::ABI::Async: 572 llvm_unreachable("can't allocate memory in coro async-lowering"); 573 } 574 llvm_unreachable("Unknown coro::ABI enum"); 575 } 576 577 [[noreturn]] static void fail(const Instruction *I, const char *Reason, 578 Value *V) { 579 #ifndef NDEBUG 580 I->dump(); 581 if (V) { 582 errs() << " Value: "; 583 V->printAsOperand(llvm::errs()); 584 errs() << '\n'; 585 } 586 #endif 587 report_fatal_error(Reason); 588 } 589 590 /// Check that the given value is a well-formed prototype for the 591 /// llvm.coro.id.retcon.* intrinsics. 592 static void checkWFRetconPrototype(const AnyCoroIdRetconInst *I, Value *V) { 593 auto F = dyn_cast<Function>(V->stripPointerCasts()); 594 if (!F) 595 fail(I, "llvm.coro.id.retcon.* prototype not a Function", V); 596 597 auto FT = F->getFunctionType(); 598 599 if (isa<CoroIdRetconInst>(I)) { 600 bool ResultOkay; 601 if (FT->getReturnType()->isPointerTy()) { 602 ResultOkay = true; 603 } else if (auto SRetTy = dyn_cast<StructType>(FT->getReturnType())) { 604 ResultOkay = (!SRetTy->isOpaque() && 605 SRetTy->getNumElements() > 0 && 606 SRetTy->getElementType(0)->isPointerTy()); 607 } else { 608 ResultOkay = false; 609 } 610 if (!ResultOkay) 611 fail(I, "llvm.coro.id.retcon prototype must return pointer as first " 612 "result", F); 613 614 if (FT->getReturnType() != 615 I->getFunction()->getFunctionType()->getReturnType()) 616 fail(I, "llvm.coro.id.retcon prototype return type must be same as" 617 "current function return type", F); 618 } else { 619 // No meaningful validation to do here for llvm.coro.id.unique.once. 620 } 621 622 if (FT->getNumParams() == 0 || !FT->getParamType(0)->isPointerTy()) 623 fail(I, "llvm.coro.id.retcon.* prototype must take pointer as " 624 "its first parameter", F); 625 } 626 627 /// Check that the given value is a well-formed allocator. 628 static void checkWFAlloc(const Instruction *I, Value *V) { 629 auto F = dyn_cast<Function>(V->stripPointerCasts()); 630 if (!F) 631 fail(I, "llvm.coro.* allocator not a Function", V); 632 633 auto FT = F->getFunctionType(); 634 if (!FT->getReturnType()->isPointerTy()) 635 fail(I, "llvm.coro.* allocator must return a pointer", F); 636 637 if (FT->getNumParams() != 1 || 638 !FT->getParamType(0)->isIntegerTy()) 639 fail(I, "llvm.coro.* allocator must take integer as only param", F); 640 } 641 642 /// Check that the given value is a well-formed deallocator. 643 static void checkWFDealloc(const Instruction *I, Value *V) { 644 auto F = dyn_cast<Function>(V->stripPointerCasts()); 645 if (!F) 646 fail(I, "llvm.coro.* deallocator not a Function", V); 647 648 auto FT = F->getFunctionType(); 649 if (!FT->getReturnType()->isVoidTy()) 650 fail(I, "llvm.coro.* deallocator must return void", F); 651 652 if (FT->getNumParams() != 1 || 653 !FT->getParamType(0)->isPointerTy()) 654 fail(I, "llvm.coro.* deallocator must take pointer as only param", F); 655 } 656 657 static void checkConstantInt(const Instruction *I, Value *V, 658 const char *Reason) { 659 if (!isa<ConstantInt>(V)) { 660 fail(I, Reason, V); 661 } 662 } 663 664 void AnyCoroIdRetconInst::checkWellFormed() const { 665 checkConstantInt(this, getArgOperand(SizeArg), 666 "size argument to coro.id.retcon.* must be constant"); 667 checkConstantInt(this, getArgOperand(AlignArg), 668 "alignment argument to coro.id.retcon.* must be constant"); 669 checkWFRetconPrototype(this, getArgOperand(PrototypeArg)); 670 checkWFAlloc(this, getArgOperand(AllocArg)); 671 checkWFDealloc(this, getArgOperand(DeallocArg)); 672 } 673 674 static void checkAsyncFuncPointer(const Instruction *I, Value *V) { 675 auto *AsyncFuncPtrAddr = dyn_cast<GlobalVariable>(V->stripPointerCasts()); 676 if (!AsyncFuncPtrAddr) 677 fail(I, "llvm.coro.id.async async function pointer not a global", V); 678 679 if (AsyncFuncPtrAddr->getType()->isOpaquePointerTy()) 680 return; 681 682 auto *StructTy = cast<StructType>( 683 AsyncFuncPtrAddr->getType()->getNonOpaquePointerElementType()); 684 if (StructTy->isOpaque() || !StructTy->isPacked() || 685 StructTy->getNumElements() != 2 || 686 !StructTy->getElementType(0)->isIntegerTy(32) || 687 !StructTy->getElementType(1)->isIntegerTy(32)) 688 fail(I, 689 "llvm.coro.id.async async function pointer argument's type is not " 690 "<{i32, i32}>", 691 V); 692 } 693 694 void CoroIdAsyncInst::checkWellFormed() const { 695 checkConstantInt(this, getArgOperand(SizeArg), 696 "size argument to coro.id.async must be constant"); 697 checkConstantInt(this, getArgOperand(AlignArg), 698 "alignment argument to coro.id.async must be constant"); 699 checkConstantInt(this, getArgOperand(StorageArg), 700 "storage argument offset to coro.id.async must be constant"); 701 checkAsyncFuncPointer(this, getArgOperand(AsyncFuncPtrArg)); 702 } 703 704 static void checkAsyncContextProjectFunction(const Instruction *I, 705 Function *F) { 706 auto *FunTy = cast<FunctionType>(F->getValueType()); 707 Type *Int8Ty = Type::getInt8Ty(F->getContext()); 708 auto *RetPtrTy = dyn_cast<PointerType>(FunTy->getReturnType()); 709 if (!RetPtrTy || !RetPtrTy->isOpaqueOrPointeeTypeMatches(Int8Ty)) 710 fail(I, 711 "llvm.coro.suspend.async resume function projection function must " 712 "return an i8* type", 713 F); 714 if (FunTy->getNumParams() != 1 || !FunTy->getParamType(0)->isPointerTy() || 715 !cast<PointerType>(FunTy->getParamType(0)) 716 ->isOpaqueOrPointeeTypeMatches(Int8Ty)) 717 fail(I, 718 "llvm.coro.suspend.async resume function projection function must " 719 "take one i8* type as parameter", 720 F); 721 } 722 723 void CoroSuspendAsyncInst::checkWellFormed() const { 724 checkAsyncContextProjectFunction(this, getAsyncContextProjectionFunction()); 725 } 726 727 void CoroAsyncEndInst::checkWellFormed() const { 728 auto *MustTailCallFunc = getMustTailCallFunction(); 729 if (!MustTailCallFunc) 730 return; 731 auto *FnTy = MustTailCallFunc->getFunctionType(); 732 if (FnTy->getNumParams() != (arg_size() - 3)) 733 fail(this, 734 "llvm.coro.end.async must tail call function argument type must " 735 "match the tail arguments", 736 MustTailCallFunc); 737 } 738 739 void LLVMAddCoroEarlyPass(LLVMPassManagerRef PM) { 740 unwrap(PM)->add(createCoroEarlyLegacyPass()); 741 } 742 743 void LLVMAddCoroSplitPass(LLVMPassManagerRef PM) { 744 unwrap(PM)->add(createCoroSplitLegacyPass()); 745 } 746 747 void LLVMAddCoroElidePass(LLVMPassManagerRef PM) { 748 unwrap(PM)->add(createCoroElideLegacyPass()); 749 } 750 751 void LLVMAddCoroCleanupPass(LLVMPassManagerRef PM) { 752 unwrap(PM)->add(createCoroCleanupLegacyPass()); 753 } 754 755 void 756 LLVMPassManagerBuilderAddCoroutinePassesToExtensionPoints(LLVMPassManagerBuilderRef PMB) { 757 PassManagerBuilder *Builder = unwrap(PMB); 758 addCoroutinePassesToExtensionPoints(*Builder); 759 } 760