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 "CoroInstr.h" 14 #include "CoroInternal.h" 15 #include "llvm/ADT/SmallVector.h" 16 #include "llvm/ADT/StringRef.h" 17 #include "llvm/Analysis/CallGraph.h" 18 #include "llvm/Analysis/CallGraphSCCPass.h" 19 #include "llvm/IR/Attributes.h" 20 #include "llvm/IR/Constants.h" 21 #include "llvm/IR/DerivedTypes.h" 22 #include "llvm/IR/Function.h" 23 #include "llvm/IR/InstIterator.h" 24 #include "llvm/IR/Instructions.h" 25 #include "llvm/IR/IntrinsicInst.h" 26 #include "llvm/IR/Intrinsics.h" 27 #include "llvm/IR/LegacyPassManager.h" 28 #include "llvm/IR/Module.h" 29 #include "llvm/IR/Type.h" 30 #include "llvm/InitializePasses.h" 31 #include "llvm/Support/Casting.h" 32 #include "llvm/Support/ErrorHandling.h" 33 #include "llvm/Transforms/IPO.h" 34 #include "llvm/Transforms/IPO/PassManagerBuilder.h" 35 #include "llvm/Transforms/Utils/Local.h" 36 #include <cassert> 37 #include <cstddef> 38 #include <utility> 39 40 using namespace llvm; 41 42 // Construct the lowerer base class and initialize its members. 43 coro::LowererBase::LowererBase(Module &M) 44 : TheModule(M), Context(M.getContext()), 45 Int8Ptr(Type::getInt8PtrTy(Context)), 46 ResumeFnType(FunctionType::get(Type::getVoidTy(Context), Int8Ptr, 47 /*isVarArg=*/false)), 48 NullPtr(ConstantPointerNull::get(Int8Ptr)) {} 49 50 // Creates a sequence of instructions to obtain a resume function address using 51 // llvm.coro.subfn.addr. It generates the following sequence: 52 // 53 // call i8* @llvm.coro.subfn.addr(i8* %Arg, i8 %index) 54 // bitcast i8* %2 to void(i8*)* 55 56 Value *coro::LowererBase::makeSubFnCall(Value *Arg, int Index, 57 Instruction *InsertPt) { 58 auto *IndexVal = ConstantInt::get(Type::getInt8Ty(Context), Index); 59 auto *Fn = Intrinsic::getDeclaration(&TheModule, Intrinsic::coro_subfn_addr); 60 61 assert(Index >= CoroSubFnInst::IndexFirst && 62 Index < CoroSubFnInst::IndexLast && 63 "makeSubFnCall: Index value out of range"); 64 auto *Call = CallInst::Create(Fn, {Arg, IndexVal}, "", InsertPt); 65 66 auto *Bitcast = 67 new BitCastInst(Call, ResumeFnType->getPointerTo(), "", InsertPt); 68 return Bitcast; 69 } 70 71 // NOTE: Must be sorted! 72 static const char *const CoroIntrinsics[] = { 73 "llvm.coro.align", 74 "llvm.coro.alloc", 75 "llvm.coro.async.context.alloc", 76 "llvm.coro.async.context.dealloc", 77 "llvm.coro.async.resume", 78 "llvm.coro.async.size.replace", 79 "llvm.coro.async.store_resume", 80 "llvm.coro.begin", 81 "llvm.coro.destroy", 82 "llvm.coro.done", 83 "llvm.coro.end", 84 "llvm.coro.end.async", 85 "llvm.coro.frame", 86 "llvm.coro.free", 87 "llvm.coro.id", 88 "llvm.coro.id.async", 89 "llvm.coro.id.retcon", 90 "llvm.coro.id.retcon.once", 91 "llvm.coro.noop", 92 "llvm.coro.prepare.async", 93 "llvm.coro.prepare.retcon", 94 "llvm.coro.promise", 95 "llvm.coro.resume", 96 "llvm.coro.save", 97 "llvm.coro.size", 98 "llvm.coro.subfn.addr", 99 "llvm.coro.suspend", 100 "llvm.coro.suspend.async", 101 "llvm.coro.suspend.retcon", 102 }; 103 104 #ifndef NDEBUG 105 static bool isCoroutineIntrinsicName(StringRef Name) { 106 return Intrinsic::lookupLLVMIntrinsicByName(CoroIntrinsics, Name) != -1; 107 } 108 #endif 109 110 bool coro::declaresAnyIntrinsic(const Module &M) { 111 for (StringRef Name : CoroIntrinsics) { 112 assert(isCoroutineIntrinsicName(Name) && "not a coroutine intrinsic"); 113 if (M.getNamedValue(Name)) 114 return true; 115 } 116 117 return false; 118 } 119 120 // Verifies if a module has named values listed. Also, in debug mode verifies 121 // that names are intrinsic names. 122 bool coro::declaresIntrinsics(const Module &M, 123 const std::initializer_list<StringRef> List) { 124 for (StringRef Name : List) { 125 assert(isCoroutineIntrinsicName(Name) && "not a coroutine intrinsic"); 126 if (M.getNamedValue(Name)) 127 return true; 128 } 129 130 return false; 131 } 132 133 // Replace all coro.frees associated with the provided CoroId either with 'null' 134 // if Elide is true and with its frame parameter otherwise. 135 void coro::replaceCoroFree(CoroIdInst *CoroId, bool Elide) { 136 SmallVector<CoroFreeInst *, 4> CoroFrees; 137 for (User *U : CoroId->users()) 138 if (auto CF = dyn_cast<CoroFreeInst>(U)) 139 CoroFrees.push_back(CF); 140 141 if (CoroFrees.empty()) 142 return; 143 144 Value *Replacement = 145 Elide ? ConstantPointerNull::get(Type::getInt8PtrTy(CoroId->getContext())) 146 : CoroFrees.front()->getFrame(); 147 148 for (CoroFreeInst *CF : CoroFrees) { 149 CF->replaceAllUsesWith(Replacement); 150 CF->eraseFromParent(); 151 } 152 } 153 154 static void clear(coro::Shape &Shape) { 155 Shape.CoroBegin = nullptr; 156 Shape.CoroEnds.clear(); 157 Shape.CoroSizes.clear(); 158 Shape.CoroSuspends.clear(); 159 160 Shape.FrameTy = nullptr; 161 Shape.FramePtr = nullptr; 162 Shape.AllocaSpillBlock = nullptr; 163 } 164 165 static CoroSaveInst *createCoroSave(CoroBeginInst *CoroBegin, 166 CoroSuspendInst *SuspendInst) { 167 Module *M = SuspendInst->getModule(); 168 auto *Fn = Intrinsic::getDeclaration(M, Intrinsic::coro_save); 169 auto *SaveInst = 170 cast<CoroSaveInst>(CallInst::Create(Fn, CoroBegin, "", SuspendInst)); 171 assert(!SuspendInst->getCoroSave()); 172 SuspendInst->setArgOperand(0, SaveInst); 173 return SaveInst; 174 } 175 176 // Collect "interesting" coroutine intrinsics. 177 void coro::Shape::buildFrom(Function &F) { 178 bool HasFinalSuspend = false; 179 size_t FinalSuspendIndex = 0; 180 clear(*this); 181 SmallVector<CoroFrameInst *, 8> CoroFrames; 182 SmallVector<CoroSaveInst *, 2> UnusedCoroSaves; 183 184 for (Instruction &I : instructions(F)) { 185 if (auto II = dyn_cast<IntrinsicInst>(&I)) { 186 switch (II->getIntrinsicID()) { 187 default: 188 continue; 189 case Intrinsic::coro_size: 190 CoroSizes.push_back(cast<CoroSizeInst>(II)); 191 break; 192 case Intrinsic::coro_align: 193 CoroAligns.push_back(cast<CoroAlignInst>(II)); 194 break; 195 case Intrinsic::coro_frame: 196 CoroFrames.push_back(cast<CoroFrameInst>(II)); 197 break; 198 case Intrinsic::coro_save: 199 // After optimizations, coro_suspends using this coro_save might have 200 // been removed, remember orphaned coro_saves to remove them later. 201 if (II->use_empty()) 202 UnusedCoroSaves.push_back(cast<CoroSaveInst>(II)); 203 break; 204 case Intrinsic::coro_suspend_async: { 205 auto *Suspend = cast<CoroSuspendAsyncInst>(II); 206 Suspend->checkWellFormed(); 207 CoroSuspends.push_back(Suspend); 208 break; 209 } 210 case Intrinsic::coro_suspend_retcon: { 211 auto Suspend = cast<CoroSuspendRetconInst>(II); 212 CoroSuspends.push_back(Suspend); 213 break; 214 } 215 case Intrinsic::coro_suspend: { 216 auto Suspend = cast<CoroSuspendInst>(II); 217 CoroSuspends.push_back(Suspend); 218 if (Suspend->isFinal()) { 219 if (HasFinalSuspend) 220 report_fatal_error( 221 "Only one suspend point can be marked as final"); 222 HasFinalSuspend = true; 223 FinalSuspendIndex = CoroSuspends.size() - 1; 224 } 225 break; 226 } 227 case Intrinsic::coro_begin: { 228 auto CB = cast<CoroBeginInst>(II); 229 230 // Ignore coro id's that aren't pre-split. 231 auto Id = dyn_cast<CoroIdInst>(CB->getId()); 232 if (Id && !Id->getInfo().isPreSplit()) 233 break; 234 235 if (CoroBegin) 236 report_fatal_error( 237 "coroutine should have exactly one defining @llvm.coro.begin"); 238 CB->addRetAttr(Attribute::NonNull); 239 CB->addRetAttr(Attribute::NoAlias); 240 CB->removeFnAttr(Attribute::NoDuplicate); 241 CoroBegin = CB; 242 break; 243 } 244 case Intrinsic::coro_end_async: 245 case Intrinsic::coro_end: 246 CoroEnds.push_back(cast<AnyCoroEndInst>(II)); 247 if (auto *AsyncEnd = dyn_cast<CoroAsyncEndInst>(II)) { 248 AsyncEnd->checkWellFormed(); 249 } 250 if (CoroEnds.back()->isFallthrough() && isa<CoroEndInst>(II)) { 251 // Make sure that the fallthrough coro.end is the first element in the 252 // CoroEnds vector. 253 // Note: I don't think this is neccessary anymore. 254 if (CoroEnds.size() > 1) { 255 if (CoroEnds.front()->isFallthrough()) 256 report_fatal_error( 257 "Only one coro.end can be marked as fallthrough"); 258 std::swap(CoroEnds.front(), CoroEnds.back()); 259 } 260 } 261 break; 262 } 263 } 264 } 265 266 // If for some reason, we were not able to find coro.begin, bailout. 267 if (!CoroBegin) { 268 // Replace coro.frame which are supposed to be lowered to the result of 269 // coro.begin with undef. 270 auto *Undef = UndefValue::get(Type::getInt8PtrTy(F.getContext())); 271 for (CoroFrameInst *CF : CoroFrames) { 272 CF->replaceAllUsesWith(Undef); 273 CF->eraseFromParent(); 274 } 275 276 // Replace all coro.suspend with undef and remove related coro.saves if 277 // present. 278 for (AnyCoroSuspendInst *CS : CoroSuspends) { 279 CS->replaceAllUsesWith(UndefValue::get(CS->getType())); 280 CS->eraseFromParent(); 281 if (auto *CoroSave = CS->getCoroSave()) 282 CoroSave->eraseFromParent(); 283 } 284 285 // Replace all coro.ends with unreachable instruction. 286 for (AnyCoroEndInst *CE : CoroEnds) 287 changeToUnreachable(CE); 288 289 return; 290 } 291 292 auto Id = CoroBegin->getId(); 293 switch (auto IdIntrinsic = Id->getIntrinsicID()) { 294 case Intrinsic::coro_id: { 295 auto SwitchId = cast<CoroIdInst>(Id); 296 this->ABI = coro::ABI::Switch; 297 this->SwitchLowering.HasFinalSuspend = HasFinalSuspend; 298 this->SwitchLowering.ResumeSwitch = nullptr; 299 this->SwitchLowering.PromiseAlloca = SwitchId->getPromise(); 300 this->SwitchLowering.ResumeEntryBlock = nullptr; 301 302 for (auto AnySuspend : CoroSuspends) { 303 auto Suspend = dyn_cast<CoroSuspendInst>(AnySuspend); 304 if (!Suspend) { 305 #ifndef NDEBUG 306 AnySuspend->dump(); 307 #endif 308 report_fatal_error("coro.id must be paired with coro.suspend"); 309 } 310 311 if (!Suspend->getCoroSave()) 312 createCoroSave(CoroBegin, Suspend); 313 } 314 break; 315 } 316 case Intrinsic::coro_id_async: { 317 auto *AsyncId = cast<CoroIdAsyncInst>(Id); 318 AsyncId->checkWellFormed(); 319 this->ABI = coro::ABI::Async; 320 this->AsyncLowering.Context = AsyncId->getStorage(); 321 this->AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex(); 322 this->AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize(); 323 this->AsyncLowering.ContextAlignment = 324 AsyncId->getStorageAlignment().value(); 325 this->AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer(); 326 this->AsyncLowering.AsyncCC = F.getCallingConv(); 327 break; 328 }; 329 case Intrinsic::coro_id_retcon: 330 case Intrinsic::coro_id_retcon_once: { 331 auto ContinuationId = cast<AnyCoroIdRetconInst>(Id); 332 ContinuationId->checkWellFormed(); 333 this->ABI = (IdIntrinsic == Intrinsic::coro_id_retcon 334 ? coro::ABI::Retcon 335 : coro::ABI::RetconOnce); 336 auto Prototype = ContinuationId->getPrototype(); 337 this->RetconLowering.ResumePrototype = Prototype; 338 this->RetconLowering.Alloc = ContinuationId->getAllocFunction(); 339 this->RetconLowering.Dealloc = ContinuationId->getDeallocFunction(); 340 this->RetconLowering.ReturnBlock = nullptr; 341 this->RetconLowering.IsFrameInlineInStorage = false; 342 343 // Determine the result value types, and make sure they match up with 344 // the values passed to the suspends. 345 auto ResultTys = getRetconResultTypes(); 346 auto ResumeTys = getRetconResumeTypes(); 347 348 for (auto AnySuspend : CoroSuspends) { 349 auto Suspend = dyn_cast<CoroSuspendRetconInst>(AnySuspend); 350 if (!Suspend) { 351 #ifndef NDEBUG 352 AnySuspend->dump(); 353 #endif 354 report_fatal_error("coro.id.retcon.* must be paired with " 355 "coro.suspend.retcon"); 356 } 357 358 // Check that the argument types of the suspend match the results. 359 auto SI = Suspend->value_begin(), SE = Suspend->value_end(); 360 auto RI = ResultTys.begin(), RE = ResultTys.end(); 361 for (; SI != SE && RI != RE; ++SI, ++RI) { 362 auto SrcTy = (*SI)->getType(); 363 if (SrcTy != *RI) { 364 // The optimizer likes to eliminate bitcasts leading into variadic 365 // calls, but that messes with our invariants. Re-insert the 366 // bitcast and ignore this type mismatch. 367 if (CastInst::isBitCastable(SrcTy, *RI)) { 368 auto BCI = new BitCastInst(*SI, *RI, "", Suspend); 369 SI->set(BCI); 370 continue; 371 } 372 373 #ifndef NDEBUG 374 Suspend->dump(); 375 Prototype->getFunctionType()->dump(); 376 #endif 377 report_fatal_error("argument to coro.suspend.retcon does not " 378 "match corresponding prototype function result"); 379 } 380 } 381 if (SI != SE || RI != RE) { 382 #ifndef NDEBUG 383 Suspend->dump(); 384 Prototype->getFunctionType()->dump(); 385 #endif 386 report_fatal_error("wrong number of arguments to coro.suspend.retcon"); 387 } 388 389 // Check that the result type of the suspend matches the resume types. 390 Type *SResultTy = Suspend->getType(); 391 ArrayRef<Type*> SuspendResultTys; 392 if (SResultTy->isVoidTy()) { 393 // leave as empty array 394 } else if (auto SResultStructTy = dyn_cast<StructType>(SResultTy)) { 395 SuspendResultTys = SResultStructTy->elements(); 396 } else { 397 // forms an ArrayRef using SResultTy, be careful 398 SuspendResultTys = SResultTy; 399 } 400 if (SuspendResultTys.size() != ResumeTys.size()) { 401 #ifndef NDEBUG 402 Suspend->dump(); 403 Prototype->getFunctionType()->dump(); 404 #endif 405 report_fatal_error("wrong number of results from coro.suspend.retcon"); 406 } 407 for (size_t I = 0, E = ResumeTys.size(); I != E; ++I) { 408 if (SuspendResultTys[I] != ResumeTys[I]) { 409 #ifndef NDEBUG 410 Suspend->dump(); 411 Prototype->getFunctionType()->dump(); 412 #endif 413 report_fatal_error("result from coro.suspend.retcon does not " 414 "match corresponding prototype function param"); 415 } 416 } 417 } 418 break; 419 } 420 421 default: 422 llvm_unreachable("coro.begin is not dependent on a coro.id call"); 423 } 424 425 // The coro.free intrinsic is always lowered to the result of coro.begin. 426 for (CoroFrameInst *CF : CoroFrames) { 427 CF->replaceAllUsesWith(CoroBegin); 428 CF->eraseFromParent(); 429 } 430 431 // Move final suspend to be the last element in the CoroSuspends vector. 432 if (ABI == coro::ABI::Switch && 433 SwitchLowering.HasFinalSuspend && 434 FinalSuspendIndex != CoroSuspends.size() - 1) 435 std::swap(CoroSuspends[FinalSuspendIndex], CoroSuspends.back()); 436 437 // Remove orphaned coro.saves. 438 for (CoroSaveInst *CoroSave : UnusedCoroSaves) 439 CoroSave->eraseFromParent(); 440 } 441 442 static void propagateCallAttrsFromCallee(CallInst *Call, Function *Callee) { 443 Call->setCallingConv(Callee->getCallingConv()); 444 // TODO: attributes? 445 } 446 447 static void addCallToCallGraph(CallGraph *CG, CallInst *Call, Function *Callee){ 448 if (CG) 449 (*CG)[Call->getFunction()]->addCalledFunction(Call, (*CG)[Callee]); 450 } 451 452 Value *coro::Shape::emitAlloc(IRBuilder<> &Builder, Value *Size, 453 CallGraph *CG) const { 454 switch (ABI) { 455 case coro::ABI::Switch: 456 llvm_unreachable("can't allocate memory in coro switch-lowering"); 457 458 case coro::ABI::Retcon: 459 case coro::ABI::RetconOnce: { 460 auto Alloc = RetconLowering.Alloc; 461 Size = Builder.CreateIntCast(Size, 462 Alloc->getFunctionType()->getParamType(0), 463 /*is signed*/ false); 464 auto *Call = Builder.CreateCall(Alloc, Size); 465 propagateCallAttrsFromCallee(Call, Alloc); 466 addCallToCallGraph(CG, Call, Alloc); 467 return Call; 468 } 469 case coro::ABI::Async: 470 llvm_unreachable("can't allocate memory in coro async-lowering"); 471 } 472 llvm_unreachable("Unknown coro::ABI enum"); 473 } 474 475 void coro::Shape::emitDealloc(IRBuilder<> &Builder, Value *Ptr, 476 CallGraph *CG) const { 477 switch (ABI) { 478 case coro::ABI::Switch: 479 llvm_unreachable("can't allocate memory in coro switch-lowering"); 480 481 case coro::ABI::Retcon: 482 case coro::ABI::RetconOnce: { 483 auto Dealloc = RetconLowering.Dealloc; 484 Ptr = Builder.CreateBitCast(Ptr, 485 Dealloc->getFunctionType()->getParamType(0)); 486 auto *Call = Builder.CreateCall(Dealloc, Ptr); 487 propagateCallAttrsFromCallee(Call, Dealloc); 488 addCallToCallGraph(CG, Call, Dealloc); 489 return; 490 } 491 case coro::ABI::Async: 492 llvm_unreachable("can't allocate memory in coro async-lowering"); 493 } 494 llvm_unreachable("Unknown coro::ABI enum"); 495 } 496 497 [[noreturn]] static void fail(const Instruction *I, const char *Reason, 498 Value *V) { 499 #ifndef NDEBUG 500 I->dump(); 501 if (V) { 502 errs() << " Value: "; 503 V->printAsOperand(llvm::errs()); 504 errs() << '\n'; 505 } 506 #endif 507 report_fatal_error(Reason); 508 } 509 510 /// Check that the given value is a well-formed prototype for the 511 /// llvm.coro.id.retcon.* intrinsics. 512 static void checkWFRetconPrototype(const AnyCoroIdRetconInst *I, Value *V) { 513 auto F = dyn_cast<Function>(V->stripPointerCasts()); 514 if (!F) 515 fail(I, "llvm.coro.id.retcon.* prototype not a Function", V); 516 517 auto FT = F->getFunctionType(); 518 519 if (isa<CoroIdRetconInst>(I)) { 520 bool ResultOkay; 521 if (FT->getReturnType()->isPointerTy()) { 522 ResultOkay = true; 523 } else if (auto SRetTy = dyn_cast<StructType>(FT->getReturnType())) { 524 ResultOkay = (!SRetTy->isOpaque() && 525 SRetTy->getNumElements() > 0 && 526 SRetTy->getElementType(0)->isPointerTy()); 527 } else { 528 ResultOkay = false; 529 } 530 if (!ResultOkay) 531 fail(I, "llvm.coro.id.retcon prototype must return pointer as first " 532 "result", F); 533 534 if (FT->getReturnType() != 535 I->getFunction()->getFunctionType()->getReturnType()) 536 fail(I, "llvm.coro.id.retcon prototype return type must be same as" 537 "current function return type", F); 538 } else { 539 // No meaningful validation to do here for llvm.coro.id.unique.once. 540 } 541 542 if (FT->getNumParams() == 0 || !FT->getParamType(0)->isPointerTy()) 543 fail(I, "llvm.coro.id.retcon.* prototype must take pointer as " 544 "its first parameter", F); 545 } 546 547 /// Check that the given value is a well-formed allocator. 548 static void checkWFAlloc(const Instruction *I, Value *V) { 549 auto F = dyn_cast<Function>(V->stripPointerCasts()); 550 if (!F) 551 fail(I, "llvm.coro.* allocator not a Function", V); 552 553 auto FT = F->getFunctionType(); 554 if (!FT->getReturnType()->isPointerTy()) 555 fail(I, "llvm.coro.* allocator must return a pointer", F); 556 557 if (FT->getNumParams() != 1 || 558 !FT->getParamType(0)->isIntegerTy()) 559 fail(I, "llvm.coro.* allocator must take integer as only param", F); 560 } 561 562 /// Check that the given value is a well-formed deallocator. 563 static void checkWFDealloc(const Instruction *I, Value *V) { 564 auto F = dyn_cast<Function>(V->stripPointerCasts()); 565 if (!F) 566 fail(I, "llvm.coro.* deallocator not a Function", V); 567 568 auto FT = F->getFunctionType(); 569 if (!FT->getReturnType()->isVoidTy()) 570 fail(I, "llvm.coro.* deallocator must return void", F); 571 572 if (FT->getNumParams() != 1 || 573 !FT->getParamType(0)->isPointerTy()) 574 fail(I, "llvm.coro.* deallocator must take pointer as only param", F); 575 } 576 577 static void checkConstantInt(const Instruction *I, Value *V, 578 const char *Reason) { 579 if (!isa<ConstantInt>(V)) { 580 fail(I, Reason, V); 581 } 582 } 583 584 void AnyCoroIdRetconInst::checkWellFormed() const { 585 checkConstantInt(this, getArgOperand(SizeArg), 586 "size argument to coro.id.retcon.* must be constant"); 587 checkConstantInt(this, getArgOperand(AlignArg), 588 "alignment argument to coro.id.retcon.* must be constant"); 589 checkWFRetconPrototype(this, getArgOperand(PrototypeArg)); 590 checkWFAlloc(this, getArgOperand(AllocArg)); 591 checkWFDealloc(this, getArgOperand(DeallocArg)); 592 } 593 594 static void checkAsyncFuncPointer(const Instruction *I, Value *V) { 595 auto *AsyncFuncPtrAddr = dyn_cast<GlobalVariable>(V->stripPointerCasts()); 596 if (!AsyncFuncPtrAddr) 597 fail(I, "llvm.coro.id.async async function pointer not a global", V); 598 599 if (AsyncFuncPtrAddr->getType()->isOpaquePointerTy()) 600 return; 601 602 auto *StructTy = cast<StructType>( 603 AsyncFuncPtrAddr->getType()->getNonOpaquePointerElementType()); 604 if (StructTy->isOpaque() || !StructTy->isPacked() || 605 StructTy->getNumElements() != 2 || 606 !StructTy->getElementType(0)->isIntegerTy(32) || 607 !StructTy->getElementType(1)->isIntegerTy(32)) 608 fail(I, 609 "llvm.coro.id.async async function pointer argument's type is not " 610 "<{i32, i32}>", 611 V); 612 } 613 614 void CoroIdAsyncInst::checkWellFormed() const { 615 checkConstantInt(this, getArgOperand(SizeArg), 616 "size argument to coro.id.async must be constant"); 617 checkConstantInt(this, getArgOperand(AlignArg), 618 "alignment argument to coro.id.async must be constant"); 619 checkConstantInt(this, getArgOperand(StorageArg), 620 "storage argument offset to coro.id.async must be constant"); 621 checkAsyncFuncPointer(this, getArgOperand(AsyncFuncPtrArg)); 622 } 623 624 static void checkAsyncContextProjectFunction(const Instruction *I, 625 Function *F) { 626 auto *FunTy = cast<FunctionType>(F->getValueType()); 627 Type *Int8Ty = Type::getInt8Ty(F->getContext()); 628 auto *RetPtrTy = dyn_cast<PointerType>(FunTy->getReturnType()); 629 if (!RetPtrTy || !RetPtrTy->isOpaqueOrPointeeTypeMatches(Int8Ty)) 630 fail(I, 631 "llvm.coro.suspend.async resume function projection function must " 632 "return an i8* type", 633 F); 634 if (FunTy->getNumParams() != 1 || !FunTy->getParamType(0)->isPointerTy() || 635 !cast<PointerType>(FunTy->getParamType(0)) 636 ->isOpaqueOrPointeeTypeMatches(Int8Ty)) 637 fail(I, 638 "llvm.coro.suspend.async resume function projection function must " 639 "take one i8* type as parameter", 640 F); 641 } 642 643 void CoroSuspendAsyncInst::checkWellFormed() const { 644 checkAsyncContextProjectFunction(this, getAsyncContextProjectionFunction()); 645 } 646 647 void CoroAsyncEndInst::checkWellFormed() const { 648 auto *MustTailCallFunc = getMustTailCallFunction(); 649 if (!MustTailCallFunc) 650 return; 651 auto *FnTy = MustTailCallFunc->getFunctionType(); 652 if (FnTy->getNumParams() != (arg_size() - 3)) 653 fail(this, 654 "llvm.coro.end.async must tail call function argument type must " 655 "match the tail arguments", 656 MustTailCallFunc); 657 } 658