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.alloc", 127 "llvm.coro.async.context.alloc", 128 "llvm.coro.async.context.dealloc", 129 "llvm.coro.async.resume", 130 "llvm.coro.async.size.replace", 131 "llvm.coro.async.store_resume", 132 "llvm.coro.begin", 133 "llvm.coro.destroy", 134 "llvm.coro.done", 135 "llvm.coro.end", 136 "llvm.coro.end.async", 137 "llvm.coro.frame", 138 "llvm.coro.free", 139 "llvm.coro.id", 140 "llvm.coro.id.async", 141 "llvm.coro.id.retcon", 142 "llvm.coro.id.retcon.once", 143 "llvm.coro.noop", 144 "llvm.coro.param", 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_frame: 273 CoroFrames.push_back(cast<CoroFrameInst>(II)); 274 break; 275 case Intrinsic::coro_save: 276 // After optimizations, coro_suspends using this coro_save might have 277 // been removed, remember orphaned coro_saves to remove them later. 278 if (II->use_empty()) 279 UnusedCoroSaves.push_back(cast<CoroSaveInst>(II)); 280 break; 281 case Intrinsic::coro_suspend_async: { 282 auto *Suspend = cast<CoroSuspendAsyncInst>(II); 283 Suspend->checkWellFormed(); 284 CoroSuspends.push_back(Suspend); 285 break; 286 } 287 case Intrinsic::coro_suspend_retcon: { 288 auto Suspend = cast<CoroSuspendRetconInst>(II); 289 CoroSuspends.push_back(Suspend); 290 break; 291 } 292 case Intrinsic::coro_suspend: { 293 auto Suspend = cast<CoroSuspendInst>(II); 294 CoroSuspends.push_back(Suspend); 295 if (Suspend->isFinal()) { 296 if (HasFinalSuspend) 297 report_fatal_error( 298 "Only one suspend point can be marked as final"); 299 HasFinalSuspend = true; 300 FinalSuspendIndex = CoroSuspends.size() - 1; 301 } 302 break; 303 } 304 case Intrinsic::coro_begin: { 305 auto CB = cast<CoroBeginInst>(II); 306 307 // Ignore coro id's that aren't pre-split. 308 auto Id = dyn_cast<CoroIdInst>(CB->getId()); 309 if (Id && !Id->getInfo().isPreSplit()) 310 break; 311 312 if (CoroBegin) 313 report_fatal_error( 314 "coroutine should have exactly one defining @llvm.coro.begin"); 315 CB->addRetAttr(Attribute::NonNull); 316 CB->addRetAttr(Attribute::NoAlias); 317 CB->removeFnAttr(Attribute::NoDuplicate); 318 CoroBegin = CB; 319 break; 320 } 321 case Intrinsic::coro_end_async: 322 case Intrinsic::coro_end: 323 CoroEnds.push_back(cast<AnyCoroEndInst>(II)); 324 if (auto *AsyncEnd = dyn_cast<CoroAsyncEndInst>(II)) { 325 AsyncEnd->checkWellFormed(); 326 } 327 if (CoroEnds.back()->isFallthrough() && isa<CoroEndInst>(II)) { 328 // Make sure that the fallthrough coro.end is the first element in the 329 // CoroEnds vector. 330 // Note: I don't think this is neccessary anymore. 331 if (CoroEnds.size() > 1) { 332 if (CoroEnds.front()->isFallthrough()) 333 report_fatal_error( 334 "Only one coro.end can be marked as fallthrough"); 335 std::swap(CoroEnds.front(), CoroEnds.back()); 336 } 337 } 338 break; 339 } 340 } 341 } 342 343 // If for some reason, we were not able to find coro.begin, bailout. 344 if (!CoroBegin) { 345 // Replace coro.frame which are supposed to be lowered to the result of 346 // coro.begin with undef. 347 auto *Undef = UndefValue::get(Type::getInt8PtrTy(F.getContext())); 348 for (CoroFrameInst *CF : CoroFrames) { 349 CF->replaceAllUsesWith(Undef); 350 CF->eraseFromParent(); 351 } 352 353 // Replace all coro.suspend with undef and remove related coro.saves if 354 // present. 355 for (AnyCoroSuspendInst *CS : CoroSuspends) { 356 CS->replaceAllUsesWith(UndefValue::get(CS->getType())); 357 CS->eraseFromParent(); 358 if (auto *CoroSave = CS->getCoroSave()) 359 CoroSave->eraseFromParent(); 360 } 361 362 // Replace all coro.ends with unreachable instruction. 363 for (AnyCoroEndInst *CE : CoroEnds) 364 changeToUnreachable(CE); 365 366 return; 367 } 368 369 auto Id = CoroBegin->getId(); 370 switch (auto IdIntrinsic = Id->getIntrinsicID()) { 371 case Intrinsic::coro_id: { 372 auto SwitchId = cast<CoroIdInst>(Id); 373 this->ABI = coro::ABI::Switch; 374 this->SwitchLowering.HasFinalSuspend = HasFinalSuspend; 375 this->SwitchLowering.ResumeSwitch = nullptr; 376 this->SwitchLowering.PromiseAlloca = SwitchId->getPromise(); 377 this->SwitchLowering.ResumeEntryBlock = nullptr; 378 379 for (auto AnySuspend : CoroSuspends) { 380 auto Suspend = dyn_cast<CoroSuspendInst>(AnySuspend); 381 if (!Suspend) { 382 #ifndef NDEBUG 383 AnySuspend->dump(); 384 #endif 385 report_fatal_error("coro.id must be paired with coro.suspend"); 386 } 387 388 if (!Suspend->getCoroSave()) 389 createCoroSave(CoroBegin, Suspend); 390 } 391 break; 392 } 393 case Intrinsic::coro_id_async: { 394 auto *AsyncId = cast<CoroIdAsyncInst>(Id); 395 AsyncId->checkWellFormed(); 396 this->ABI = coro::ABI::Async; 397 this->AsyncLowering.Context = AsyncId->getStorage(); 398 this->AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex(); 399 this->AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize(); 400 this->AsyncLowering.ContextAlignment = 401 AsyncId->getStorageAlignment().value(); 402 this->AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer(); 403 this->AsyncLowering.AsyncCC = F.getCallingConv(); 404 break; 405 }; 406 case Intrinsic::coro_id_retcon: 407 case Intrinsic::coro_id_retcon_once: { 408 auto ContinuationId = cast<AnyCoroIdRetconInst>(Id); 409 ContinuationId->checkWellFormed(); 410 this->ABI = (IdIntrinsic == Intrinsic::coro_id_retcon 411 ? coro::ABI::Retcon 412 : coro::ABI::RetconOnce); 413 auto Prototype = ContinuationId->getPrototype(); 414 this->RetconLowering.ResumePrototype = Prototype; 415 this->RetconLowering.Alloc = ContinuationId->getAllocFunction(); 416 this->RetconLowering.Dealloc = ContinuationId->getDeallocFunction(); 417 this->RetconLowering.ReturnBlock = nullptr; 418 this->RetconLowering.IsFrameInlineInStorage = false; 419 420 // Determine the result value types, and make sure they match up with 421 // the values passed to the suspends. 422 auto ResultTys = getRetconResultTypes(); 423 auto ResumeTys = getRetconResumeTypes(); 424 425 for (auto AnySuspend : CoroSuspends) { 426 auto Suspend = dyn_cast<CoroSuspendRetconInst>(AnySuspend); 427 if (!Suspend) { 428 #ifndef NDEBUG 429 AnySuspend->dump(); 430 #endif 431 report_fatal_error("coro.id.retcon.* must be paired with " 432 "coro.suspend.retcon"); 433 } 434 435 // Check that the argument types of the suspend match the results. 436 auto SI = Suspend->value_begin(), SE = Suspend->value_end(); 437 auto RI = ResultTys.begin(), RE = ResultTys.end(); 438 for (; SI != SE && RI != RE; ++SI, ++RI) { 439 auto SrcTy = (*SI)->getType(); 440 if (SrcTy != *RI) { 441 // The optimizer likes to eliminate bitcasts leading into variadic 442 // calls, but that messes with our invariants. Re-insert the 443 // bitcast and ignore this type mismatch. 444 if (CastInst::isBitCastable(SrcTy, *RI)) { 445 auto BCI = new BitCastInst(*SI, *RI, "", Suspend); 446 SI->set(BCI); 447 continue; 448 } 449 450 #ifndef NDEBUG 451 Suspend->dump(); 452 Prototype->getFunctionType()->dump(); 453 #endif 454 report_fatal_error("argument to coro.suspend.retcon does not " 455 "match corresponding prototype function result"); 456 } 457 } 458 if (SI != SE || RI != RE) { 459 #ifndef NDEBUG 460 Suspend->dump(); 461 Prototype->getFunctionType()->dump(); 462 #endif 463 report_fatal_error("wrong number of arguments to coro.suspend.retcon"); 464 } 465 466 // Check that the result type of the suspend matches the resume types. 467 Type *SResultTy = Suspend->getType(); 468 ArrayRef<Type*> SuspendResultTys; 469 if (SResultTy->isVoidTy()) { 470 // leave as empty array 471 } else if (auto SResultStructTy = dyn_cast<StructType>(SResultTy)) { 472 SuspendResultTys = SResultStructTy->elements(); 473 } else { 474 // forms an ArrayRef using SResultTy, be careful 475 SuspendResultTys = SResultTy; 476 } 477 if (SuspendResultTys.size() != ResumeTys.size()) { 478 #ifndef NDEBUG 479 Suspend->dump(); 480 Prototype->getFunctionType()->dump(); 481 #endif 482 report_fatal_error("wrong number of results from coro.suspend.retcon"); 483 } 484 for (size_t I = 0, E = ResumeTys.size(); I != E; ++I) { 485 if (SuspendResultTys[I] != ResumeTys[I]) { 486 #ifndef NDEBUG 487 Suspend->dump(); 488 Prototype->getFunctionType()->dump(); 489 #endif 490 report_fatal_error("result from coro.suspend.retcon does not " 491 "match corresponding prototype function param"); 492 } 493 } 494 } 495 break; 496 } 497 498 default: 499 llvm_unreachable("coro.begin is not dependent on a coro.id call"); 500 } 501 502 // The coro.free intrinsic is always lowered to the result of coro.begin. 503 for (CoroFrameInst *CF : CoroFrames) { 504 CF->replaceAllUsesWith(CoroBegin); 505 CF->eraseFromParent(); 506 } 507 508 // Move final suspend to be the last element in the CoroSuspends vector. 509 if (ABI == coro::ABI::Switch && 510 SwitchLowering.HasFinalSuspend && 511 FinalSuspendIndex != CoroSuspends.size() - 1) 512 std::swap(CoroSuspends[FinalSuspendIndex], CoroSuspends.back()); 513 514 // Remove orphaned coro.saves. 515 for (CoroSaveInst *CoroSave : UnusedCoroSaves) 516 CoroSave->eraseFromParent(); 517 } 518 519 static void propagateCallAttrsFromCallee(CallInst *Call, Function *Callee) { 520 Call->setCallingConv(Callee->getCallingConv()); 521 // TODO: attributes? 522 } 523 524 static void addCallToCallGraph(CallGraph *CG, CallInst *Call, Function *Callee){ 525 if (CG) 526 (*CG)[Call->getFunction()]->addCalledFunction(Call, (*CG)[Callee]); 527 } 528 529 Value *coro::Shape::emitAlloc(IRBuilder<> &Builder, Value *Size, 530 CallGraph *CG) const { 531 switch (ABI) { 532 case coro::ABI::Switch: 533 llvm_unreachable("can't allocate memory in coro switch-lowering"); 534 535 case coro::ABI::Retcon: 536 case coro::ABI::RetconOnce: { 537 auto Alloc = RetconLowering.Alloc; 538 Size = Builder.CreateIntCast(Size, 539 Alloc->getFunctionType()->getParamType(0), 540 /*is signed*/ false); 541 auto *Call = Builder.CreateCall(Alloc, Size); 542 propagateCallAttrsFromCallee(Call, Alloc); 543 addCallToCallGraph(CG, Call, Alloc); 544 return Call; 545 } 546 case coro::ABI::Async: 547 llvm_unreachable("can't allocate memory in coro async-lowering"); 548 } 549 llvm_unreachable("Unknown coro::ABI enum"); 550 } 551 552 void coro::Shape::emitDealloc(IRBuilder<> &Builder, Value *Ptr, 553 CallGraph *CG) const { 554 switch (ABI) { 555 case coro::ABI::Switch: 556 llvm_unreachable("can't allocate memory in coro switch-lowering"); 557 558 case coro::ABI::Retcon: 559 case coro::ABI::RetconOnce: { 560 auto Dealloc = RetconLowering.Dealloc; 561 Ptr = Builder.CreateBitCast(Ptr, 562 Dealloc->getFunctionType()->getParamType(0)); 563 auto *Call = Builder.CreateCall(Dealloc, Ptr); 564 propagateCallAttrsFromCallee(Call, Dealloc); 565 addCallToCallGraph(CG, Call, Dealloc); 566 return; 567 } 568 case coro::ABI::Async: 569 llvm_unreachable("can't allocate memory in coro async-lowering"); 570 } 571 llvm_unreachable("Unknown coro::ABI enum"); 572 } 573 574 [[noreturn]] static void fail(const Instruction *I, const char *Reason, 575 Value *V) { 576 #ifndef NDEBUG 577 I->dump(); 578 if (V) { 579 errs() << " Value: "; 580 V->printAsOperand(llvm::errs()); 581 errs() << '\n'; 582 } 583 #endif 584 report_fatal_error(Reason); 585 } 586 587 /// Check that the given value is a well-formed prototype for the 588 /// llvm.coro.id.retcon.* intrinsics. 589 static void checkWFRetconPrototype(const AnyCoroIdRetconInst *I, Value *V) { 590 auto F = dyn_cast<Function>(V->stripPointerCasts()); 591 if (!F) 592 fail(I, "llvm.coro.id.retcon.* prototype not a Function", V); 593 594 auto FT = F->getFunctionType(); 595 596 if (isa<CoroIdRetconInst>(I)) { 597 bool ResultOkay; 598 if (FT->getReturnType()->isPointerTy()) { 599 ResultOkay = true; 600 } else if (auto SRetTy = dyn_cast<StructType>(FT->getReturnType())) { 601 ResultOkay = (!SRetTy->isOpaque() && 602 SRetTy->getNumElements() > 0 && 603 SRetTy->getElementType(0)->isPointerTy()); 604 } else { 605 ResultOkay = false; 606 } 607 if (!ResultOkay) 608 fail(I, "llvm.coro.id.retcon prototype must return pointer as first " 609 "result", F); 610 611 if (FT->getReturnType() != 612 I->getFunction()->getFunctionType()->getReturnType()) 613 fail(I, "llvm.coro.id.retcon prototype return type must be same as" 614 "current function return type", F); 615 } else { 616 // No meaningful validation to do here for llvm.coro.id.unique.once. 617 } 618 619 if (FT->getNumParams() == 0 || !FT->getParamType(0)->isPointerTy()) 620 fail(I, "llvm.coro.id.retcon.* prototype must take pointer as " 621 "its first parameter", F); 622 } 623 624 /// Check that the given value is a well-formed allocator. 625 static void checkWFAlloc(const Instruction *I, Value *V) { 626 auto F = dyn_cast<Function>(V->stripPointerCasts()); 627 if (!F) 628 fail(I, "llvm.coro.* allocator not a Function", V); 629 630 auto FT = F->getFunctionType(); 631 if (!FT->getReturnType()->isPointerTy()) 632 fail(I, "llvm.coro.* allocator must return a pointer", F); 633 634 if (FT->getNumParams() != 1 || 635 !FT->getParamType(0)->isIntegerTy()) 636 fail(I, "llvm.coro.* allocator must take integer as only param", F); 637 } 638 639 /// Check that the given value is a well-formed deallocator. 640 static void checkWFDealloc(const Instruction *I, Value *V) { 641 auto F = dyn_cast<Function>(V->stripPointerCasts()); 642 if (!F) 643 fail(I, "llvm.coro.* deallocator not a Function", V); 644 645 auto FT = F->getFunctionType(); 646 if (!FT->getReturnType()->isVoidTy()) 647 fail(I, "llvm.coro.* deallocator must return void", F); 648 649 if (FT->getNumParams() != 1 || 650 !FT->getParamType(0)->isPointerTy()) 651 fail(I, "llvm.coro.* deallocator must take pointer as only param", F); 652 } 653 654 static void checkConstantInt(const Instruction *I, Value *V, 655 const char *Reason) { 656 if (!isa<ConstantInt>(V)) { 657 fail(I, Reason, V); 658 } 659 } 660 661 void AnyCoroIdRetconInst::checkWellFormed() const { 662 checkConstantInt(this, getArgOperand(SizeArg), 663 "size argument to coro.id.retcon.* must be constant"); 664 checkConstantInt(this, getArgOperand(AlignArg), 665 "alignment argument to coro.id.retcon.* must be constant"); 666 checkWFRetconPrototype(this, getArgOperand(PrototypeArg)); 667 checkWFAlloc(this, getArgOperand(AllocArg)); 668 checkWFDealloc(this, getArgOperand(DeallocArg)); 669 } 670 671 static void checkAsyncFuncPointer(const Instruction *I, Value *V) { 672 auto *AsyncFuncPtrAddr = dyn_cast<GlobalVariable>(V->stripPointerCasts()); 673 if (!AsyncFuncPtrAddr) 674 fail(I, "llvm.coro.id.async async function pointer not a global", V); 675 676 auto *StructTy = 677 cast<StructType>(AsyncFuncPtrAddr->getType()->getPointerElementType()); 678 if (StructTy->isOpaque() || !StructTy->isPacked() || 679 StructTy->getNumElements() != 2 || 680 !StructTy->getElementType(0)->isIntegerTy(32) || 681 !StructTy->getElementType(1)->isIntegerTy(32)) 682 fail(I, 683 "llvm.coro.id.async async function pointer argument's type is not " 684 "<{i32, i32}>", 685 V); 686 } 687 688 void CoroIdAsyncInst::checkWellFormed() const { 689 checkConstantInt(this, getArgOperand(SizeArg), 690 "size argument to coro.id.async must be constant"); 691 checkConstantInt(this, getArgOperand(AlignArg), 692 "alignment argument to coro.id.async must be constant"); 693 checkConstantInt(this, getArgOperand(StorageArg), 694 "storage argument offset to coro.id.async must be constant"); 695 checkAsyncFuncPointer(this, getArgOperand(AsyncFuncPtrArg)); 696 } 697 698 static void checkAsyncContextProjectFunction(const Instruction *I, 699 Function *F) { 700 auto *FunTy = cast<FunctionType>(F->getValueType()); 701 if (!FunTy->getReturnType()->isPointerTy() || 702 !FunTy->getReturnType()->getPointerElementType()->isIntegerTy(8)) 703 fail(I, 704 "llvm.coro.suspend.async resume function projection function must " 705 "return an i8* type", 706 F); 707 if (FunTy->getNumParams() != 1 || !FunTy->getParamType(0)->isPointerTy() || 708 !FunTy->getParamType(0)->getPointerElementType()->isIntegerTy(8)) 709 fail(I, 710 "llvm.coro.suspend.async resume function projection function must " 711 "take one i8* type as parameter", 712 F); 713 } 714 715 void CoroSuspendAsyncInst::checkWellFormed() const { 716 checkAsyncContextProjectFunction(this, getAsyncContextProjectionFunction()); 717 } 718 719 void CoroAsyncEndInst::checkWellFormed() const { 720 auto *MustTailCallFunc = getMustTailCallFunction(); 721 if (!MustTailCallFunc) 722 return; 723 auto *FnTy = 724 cast<FunctionType>(MustTailCallFunc->getType()->getPointerElementType()); 725 if (FnTy->getNumParams() != (arg_size() - 3)) 726 fail(this, 727 "llvm.coro.end.async must tail call function argument type must " 728 "match the tail arguments", 729 MustTailCallFunc); 730 } 731 732 void LLVMAddCoroEarlyPass(LLVMPassManagerRef PM) { 733 unwrap(PM)->add(createCoroEarlyLegacyPass()); 734 } 735 736 void LLVMAddCoroSplitPass(LLVMPassManagerRef PM) { 737 unwrap(PM)->add(createCoroSplitLegacyPass()); 738 } 739 740 void LLVMAddCoroElidePass(LLVMPassManagerRef PM) { 741 unwrap(PM)->add(createCoroElideLegacyPass()); 742 } 743 744 void LLVMAddCoroCleanupPass(LLVMPassManagerRef PM) { 745 unwrap(PM)->add(createCoroCleanupLegacyPass()); 746 } 747 748 void 749 LLVMPassManagerBuilderAddCoroutinePassesToExtensionPoints(LLVMPassManagerBuilderRef PMB) { 750 PassManagerBuilder *Builder = unwrap(PMB); 751 addCoroutinePassesToExtensionPoints(*Builder); 752 } 753