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