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