1 //===-- CoroInstr.h - Coroutine Intrinsics Instruction Wrappers -*- C++ -*-===// 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 // This file defines classes that make it really easy to deal with intrinsic 9 // functions with the isa/dyncast family of functions. In particular, this 10 // allows you to do things like: 11 // 12 // if (auto *SF = dyn_cast<CoroSubFnInst>(Inst)) 13 // ... SF->getFrame() ... 14 // 15 // All intrinsic function calls are instances of the call instruction, so these 16 // are all subclasses of the CallInst class. Note that none of these classes 17 // has state or virtual methods, which is an important part of this gross/neat 18 // hack working. 19 // 20 // The helpful comment above is borrowed from llvm/IntrinsicInst.h, we keep 21 // coroutine intrinsic wrappers here since they are only used by the passes in 22 // the Coroutine library. 23 //===----------------------------------------------------------------------===// 24 25 #ifndef LLVM_LIB_TRANSFORMS_COROUTINES_COROINSTR_H 26 #define LLVM_LIB_TRANSFORMS_COROUTINES_COROINSTR_H 27 28 #include "llvm/IR/GlobalVariable.h" 29 #include "llvm/IR/IntrinsicInst.h" 30 #include "llvm/Support/raw_ostream.h" 31 32 namespace llvm { 33 34 /// This class represents the llvm.coro.subfn.addr instruction. 35 class LLVM_LIBRARY_VISIBILITY CoroSubFnInst : public IntrinsicInst { 36 enum { FrameArg, IndexArg }; 37 38 public: 39 enum ResumeKind { 40 RestartTrigger = -1, 41 ResumeIndex, 42 DestroyIndex, 43 CleanupIndex, 44 IndexLast, 45 IndexFirst = RestartTrigger 46 }; 47 48 Value *getFrame() const { return getArgOperand(FrameArg); } 49 ResumeKind getIndex() const { 50 int64_t Index = getRawIndex()->getValue().getSExtValue(); 51 assert(Index >= IndexFirst && Index < IndexLast && 52 "unexpected CoroSubFnInst index argument"); 53 return static_cast<ResumeKind>(Index); 54 } 55 56 ConstantInt *getRawIndex() const { 57 return cast<ConstantInt>(getArgOperand(IndexArg)); 58 } 59 60 // Methods to support type inquiry through isa, cast, and dyn_cast: 61 static bool classof(const IntrinsicInst *I) { 62 return I->getIntrinsicID() == Intrinsic::coro_subfn_addr; 63 } 64 static bool classof(const Value *V) { 65 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 66 } 67 }; 68 69 /// This represents the llvm.coro.alloc instruction. 70 class LLVM_LIBRARY_VISIBILITY CoroAllocInst : public IntrinsicInst { 71 public: 72 // Methods to support type inquiry through isa, cast, and dyn_cast: 73 static bool classof(const IntrinsicInst *I) { 74 return I->getIntrinsicID() == Intrinsic::coro_alloc; 75 } 76 static bool classof(const Value *V) { 77 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 78 } 79 }; 80 81 /// This represents a common base class for llvm.coro.id instructions. 82 class LLVM_LIBRARY_VISIBILITY AnyCoroIdInst : public IntrinsicInst { 83 public: 84 CoroAllocInst *getCoroAlloc() { 85 for (User *U : users()) 86 if (auto *CA = dyn_cast<CoroAllocInst>(U)) 87 return CA; 88 return nullptr; 89 } 90 91 IntrinsicInst *getCoroBegin() { 92 for (User *U : users()) 93 if (auto *II = dyn_cast<IntrinsicInst>(U)) 94 if (II->getIntrinsicID() == Intrinsic::coro_begin) 95 return II; 96 llvm_unreachable("no coro.begin associated with coro.id"); 97 } 98 99 // Methods to support type inquiry through isa, cast, and dyn_cast: 100 static bool classof(const IntrinsicInst *I) { 101 auto ID = I->getIntrinsicID(); 102 return ID == Intrinsic::coro_id || 103 ID == Intrinsic::coro_id_retcon || 104 ID == Intrinsic::coro_id_retcon_once; 105 } 106 107 static bool classof(const Value *V) { 108 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 109 } 110 }; 111 112 /// This represents the llvm.coro.id instruction. 113 class LLVM_LIBRARY_VISIBILITY CoroIdInst : public AnyCoroIdInst { 114 enum { AlignArg, PromiseArg, CoroutineArg, InfoArg }; 115 116 public: 117 AllocaInst *getPromise() const { 118 Value *Arg = getArgOperand(PromiseArg); 119 return isa<ConstantPointerNull>(Arg) 120 ? nullptr 121 : cast<AllocaInst>(Arg->stripPointerCasts()); 122 } 123 124 void clearPromise() { 125 Value *Arg = getArgOperand(PromiseArg); 126 setArgOperand(PromiseArg, 127 ConstantPointerNull::get(Type::getInt8PtrTy(getContext()))); 128 if (isa<AllocaInst>(Arg)) 129 return; 130 assert((isa<BitCastInst>(Arg) || isa<GetElementPtrInst>(Arg)) && 131 "unexpected instruction designating the promise"); 132 // TODO: Add a check that any remaining users of Inst are after coro.begin 133 // or add code to move the users after coro.begin. 134 auto *Inst = cast<Instruction>(Arg); 135 if (Inst->use_empty()) { 136 Inst->eraseFromParent(); 137 return; 138 } 139 Inst->moveBefore(getCoroBegin()->getNextNode()); 140 } 141 142 // Info argument of coro.id is 143 // fresh out of the frontend: null ; 144 // outlined : {Init, Return, Susp1, Susp2, ...} ; 145 // postsplit : [resume, destroy, cleanup] ; 146 // 147 // If parts of the coroutine were outlined to protect against undesirable 148 // code motion, these functions will be stored in a struct literal referred to 149 // by the Info parameter. Note: this is only needed before coroutine is split. 150 // 151 // After coroutine is split, resume functions are stored in an array 152 // referred to by this parameter. 153 154 struct Info { 155 ConstantStruct *OutlinedParts = nullptr; 156 ConstantArray *Resumers = nullptr; 157 158 bool hasOutlinedParts() const { return OutlinedParts != nullptr; } 159 bool isPostSplit() const { return Resumers != nullptr; } 160 bool isPreSplit() const { return !isPostSplit(); } 161 }; 162 Info getInfo() const { 163 Info Result; 164 auto *GV = dyn_cast<GlobalVariable>(getRawInfo()); 165 if (!GV) 166 return Result; 167 168 assert(GV->isConstant() && GV->hasDefinitiveInitializer()); 169 Constant *Initializer = GV->getInitializer(); 170 if ((Result.OutlinedParts = dyn_cast<ConstantStruct>(Initializer))) 171 return Result; 172 173 Result.Resumers = cast<ConstantArray>(Initializer); 174 return Result; 175 } 176 Constant *getRawInfo() const { 177 return cast<Constant>(getArgOperand(InfoArg)->stripPointerCasts()); 178 } 179 180 void setInfo(Constant *C) { setArgOperand(InfoArg, C); } 181 182 Function *getCoroutine() const { 183 return cast<Function>(getArgOperand(CoroutineArg)->stripPointerCasts()); 184 } 185 void setCoroutineSelf() { 186 assert(isa<ConstantPointerNull>(getArgOperand(CoroutineArg)) && 187 "Coroutine argument is already assigned"); 188 auto *const Int8PtrTy = Type::getInt8PtrTy(getContext()); 189 setArgOperand(CoroutineArg, 190 ConstantExpr::getBitCast(getFunction(), Int8PtrTy)); 191 } 192 193 // Methods to support type inquiry through isa, cast, and dyn_cast: 194 static bool classof(const IntrinsicInst *I) { 195 return I->getIntrinsicID() == Intrinsic::coro_id; 196 } 197 static bool classof(const Value *V) { 198 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 199 } 200 }; 201 202 /// This represents either the llvm.coro.id.retcon or 203 /// llvm.coro.id.retcon.once instruction. 204 class LLVM_LIBRARY_VISIBILITY AnyCoroIdRetconInst : public AnyCoroIdInst { 205 enum { SizeArg, AlignArg, StorageArg, PrototypeArg, AllocArg, DeallocArg }; 206 207 public: 208 void checkWellFormed() const; 209 210 uint64_t getStorageSize() const { 211 return cast<ConstantInt>(getArgOperand(SizeArg))->getZExtValue(); 212 } 213 214 uint64_t getStorageAlignment() const { 215 return cast<ConstantInt>(getArgOperand(AlignArg))->getZExtValue(); 216 } 217 218 Value *getStorage() const { 219 return getArgOperand(StorageArg); 220 } 221 222 /// Return the prototype for the continuation function. The type, 223 /// attributes, and calling convention of the continuation function(s) 224 /// are taken from this declaration. 225 Function *getPrototype() const { 226 return cast<Function>(getArgOperand(PrototypeArg)->stripPointerCasts()); 227 } 228 229 /// Return the function to use for allocating memory. 230 Function *getAllocFunction() const { 231 return cast<Function>(getArgOperand(AllocArg)->stripPointerCasts()); 232 } 233 234 /// Return the function to use for deallocating memory. 235 Function *getDeallocFunction() const { 236 return cast<Function>(getArgOperand(DeallocArg)->stripPointerCasts()); 237 } 238 239 // Methods to support type inquiry through isa, cast, and dyn_cast: 240 static bool classof(const IntrinsicInst *I) { 241 auto ID = I->getIntrinsicID(); 242 return ID == Intrinsic::coro_id_retcon 243 || ID == Intrinsic::coro_id_retcon_once; 244 } 245 static bool classof(const Value *V) { 246 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 247 } 248 }; 249 250 /// This represents the llvm.coro.id.retcon instruction. 251 class LLVM_LIBRARY_VISIBILITY CoroIdRetconInst 252 : public AnyCoroIdRetconInst { 253 public: 254 // Methods to support type inquiry through isa, cast, and dyn_cast: 255 static bool classof(const IntrinsicInst *I) { 256 return I->getIntrinsicID() == Intrinsic::coro_id_retcon; 257 } 258 static bool classof(const Value *V) { 259 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 260 } 261 }; 262 263 /// This represents the llvm.coro.id.retcon.once instruction. 264 class LLVM_LIBRARY_VISIBILITY CoroIdRetconOnceInst 265 : public AnyCoroIdRetconInst { 266 public: 267 // Methods to support type inquiry through isa, cast, and dyn_cast: 268 static bool classof(const IntrinsicInst *I) { 269 return I->getIntrinsicID() == Intrinsic::coro_id_retcon_once; 270 } 271 static bool classof(const Value *V) { 272 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 273 } 274 }; 275 276 /// This represents the llvm.coro.frame instruction. 277 class LLVM_LIBRARY_VISIBILITY CoroFrameInst : public IntrinsicInst { 278 public: 279 // Methods to support type inquiry through isa, cast, and dyn_cast: 280 static bool classof(const IntrinsicInst *I) { 281 return I->getIntrinsicID() == Intrinsic::coro_frame; 282 } 283 static bool classof(const Value *V) { 284 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 285 } 286 }; 287 288 /// This represents the llvm.coro.free instruction. 289 class LLVM_LIBRARY_VISIBILITY CoroFreeInst : public IntrinsicInst { 290 enum { IdArg, FrameArg }; 291 292 public: 293 Value *getFrame() const { return getArgOperand(FrameArg); } 294 295 // Methods to support type inquiry through isa, cast, and dyn_cast: 296 static bool classof(const IntrinsicInst *I) { 297 return I->getIntrinsicID() == Intrinsic::coro_free; 298 } 299 static bool classof(const Value *V) { 300 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 301 } 302 }; 303 304 /// This class represents the llvm.coro.begin instruction. 305 class LLVM_LIBRARY_VISIBILITY CoroBeginInst : public IntrinsicInst { 306 enum { IdArg, MemArg }; 307 308 public: 309 AnyCoroIdInst *getId() const { 310 return cast<AnyCoroIdInst>(getArgOperand(IdArg)); 311 } 312 313 Value *getMem() const { return getArgOperand(MemArg); } 314 315 // Methods for support type inquiry through isa, cast, and dyn_cast: 316 static bool classof(const IntrinsicInst *I) { 317 return I->getIntrinsicID() == Intrinsic::coro_begin; 318 } 319 static bool classof(const Value *V) { 320 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 321 } 322 }; 323 324 /// This represents the llvm.coro.save instruction. 325 class LLVM_LIBRARY_VISIBILITY CoroSaveInst : public IntrinsicInst { 326 public: 327 // Methods to support type inquiry through isa, cast, and dyn_cast: 328 static bool classof(const IntrinsicInst *I) { 329 return I->getIntrinsicID() == Intrinsic::coro_save; 330 } 331 static bool classof(const Value *V) { 332 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 333 } 334 }; 335 336 /// This represents the llvm.coro.promise instruction. 337 class LLVM_LIBRARY_VISIBILITY CoroPromiseInst : public IntrinsicInst { 338 enum { FrameArg, AlignArg, FromArg }; 339 340 public: 341 bool isFromPromise() const { 342 return cast<Constant>(getArgOperand(FromArg))->isOneValue(); 343 } 344 unsigned getAlignment() const { 345 return cast<ConstantInt>(getArgOperand(AlignArg))->getZExtValue(); 346 } 347 348 // Methods to support type inquiry through isa, cast, and dyn_cast: 349 static bool classof(const IntrinsicInst *I) { 350 return I->getIntrinsicID() == Intrinsic::coro_promise; 351 } 352 static bool classof(const Value *V) { 353 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 354 } 355 }; 356 357 class LLVM_LIBRARY_VISIBILITY AnyCoroSuspendInst : public IntrinsicInst { 358 public: 359 CoroSaveInst *getCoroSave() const; 360 361 // Methods to support type inquiry through isa, cast, and dyn_cast: 362 static bool classof(const IntrinsicInst *I) { 363 return I->getIntrinsicID() == Intrinsic::coro_suspend || 364 I->getIntrinsicID() == Intrinsic::coro_suspend_retcon; 365 } 366 static bool classof(const Value *V) { 367 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 368 } 369 }; 370 371 /// This represents the llvm.coro.suspend instruction. 372 class LLVM_LIBRARY_VISIBILITY CoroSuspendInst : public AnyCoroSuspendInst { 373 enum { SaveArg, FinalArg }; 374 375 public: 376 CoroSaveInst *getCoroSave() const { 377 Value *Arg = getArgOperand(SaveArg); 378 if (auto *SI = dyn_cast<CoroSaveInst>(Arg)) 379 return SI; 380 assert(isa<ConstantTokenNone>(Arg)); 381 return nullptr; 382 } 383 384 bool isFinal() const { 385 return cast<Constant>(getArgOperand(FinalArg))->isOneValue(); 386 } 387 388 // Methods to support type inquiry through isa, cast, and dyn_cast: 389 static bool classof(const IntrinsicInst *I) { 390 return I->getIntrinsicID() == Intrinsic::coro_suspend; 391 } 392 static bool classof(const Value *V) { 393 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 394 } 395 }; 396 397 inline CoroSaveInst *AnyCoroSuspendInst::getCoroSave() const { 398 if (auto Suspend = dyn_cast<CoroSuspendInst>(this)) 399 return Suspend->getCoroSave(); 400 return nullptr; 401 } 402 403 /// This represents the llvm.coro.suspend.retcon instruction. 404 class LLVM_LIBRARY_VISIBILITY CoroSuspendRetconInst : public AnyCoroSuspendInst { 405 public: 406 op_iterator value_begin() { return arg_begin(); } 407 const_op_iterator value_begin() const { return arg_begin(); } 408 409 op_iterator value_end() { return arg_end(); } 410 const_op_iterator value_end() const { return arg_end(); } 411 412 iterator_range<op_iterator> value_operands() { 413 return make_range(value_begin(), value_end()); 414 } 415 iterator_range<const_op_iterator> value_operands() const { 416 return make_range(value_begin(), value_end()); 417 } 418 419 // Methods to support type inquiry through isa, cast, and dyn_cast: 420 static bool classof(const IntrinsicInst *I) { 421 return I->getIntrinsicID() == Intrinsic::coro_suspend_retcon; 422 } 423 static bool classof(const Value *V) { 424 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 425 } 426 }; 427 428 /// This represents the llvm.coro.size instruction. 429 class LLVM_LIBRARY_VISIBILITY CoroSizeInst : public IntrinsicInst { 430 public: 431 // Methods to support type inquiry through isa, cast, and dyn_cast: 432 static bool classof(const IntrinsicInst *I) { 433 return I->getIntrinsicID() == Intrinsic::coro_size; 434 } 435 static bool classof(const Value *V) { 436 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 437 } 438 }; 439 440 /// This represents the llvm.coro.end instruction. 441 class LLVM_LIBRARY_VISIBILITY CoroEndInst : public IntrinsicInst { 442 enum { FrameArg, UnwindArg }; 443 444 public: 445 bool isFallthrough() const { return !isUnwind(); } 446 bool isUnwind() const { 447 return cast<Constant>(getArgOperand(UnwindArg))->isOneValue(); 448 } 449 450 // Methods to support type inquiry through isa, cast, and dyn_cast: 451 static bool classof(const IntrinsicInst *I) { 452 return I->getIntrinsicID() == Intrinsic::coro_end; 453 } 454 static bool classof(const Value *V) { 455 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 456 } 457 }; 458 459 /// This represents the llvm.coro.alloca.alloc instruction. 460 class LLVM_LIBRARY_VISIBILITY CoroAllocaAllocInst : public IntrinsicInst { 461 enum { SizeArg, AlignArg }; 462 public: 463 Value *getSize() const { 464 return getArgOperand(SizeArg); 465 } 466 unsigned getAlignment() const { 467 return cast<ConstantInt>(getArgOperand(AlignArg))->getZExtValue(); 468 } 469 470 // Methods to support type inquiry through isa, cast, and dyn_cast: 471 static bool classof(const IntrinsicInst *I) { 472 return I->getIntrinsicID() == Intrinsic::coro_alloca_alloc; 473 } 474 static bool classof(const Value *V) { 475 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 476 } 477 }; 478 479 /// This represents the llvm.coro.alloca.get instruction. 480 class LLVM_LIBRARY_VISIBILITY CoroAllocaGetInst : public IntrinsicInst { 481 enum { AllocArg }; 482 public: 483 CoroAllocaAllocInst *getAlloc() const { 484 return cast<CoroAllocaAllocInst>(getArgOperand(AllocArg)); 485 } 486 487 // Methods to support type inquiry through isa, cast, and dyn_cast: 488 static bool classof(const IntrinsicInst *I) { 489 return I->getIntrinsicID() == Intrinsic::coro_alloca_get; 490 } 491 static bool classof(const Value *V) { 492 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 493 } 494 }; 495 496 /// This represents the llvm.coro.alloca.free instruction. 497 class LLVM_LIBRARY_VISIBILITY CoroAllocaFreeInst : public IntrinsicInst { 498 enum { AllocArg }; 499 public: 500 CoroAllocaAllocInst *getAlloc() const { 501 return cast<CoroAllocaAllocInst>(getArgOperand(AllocArg)); 502 } 503 504 // Methods to support type inquiry through isa, cast, and dyn_cast: 505 static bool classof(const IntrinsicInst *I) { 506 return I->getIntrinsicID() == Intrinsic::coro_alloca_free; 507 } 508 static bool classof(const Value *V) { 509 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 510 } 511 }; 512 513 } // End namespace llvm. 514 515 #endif 516