1 //===-- CoroInstr.h - Coroutine Intrinsics Instruction Wrappers -*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // This file defines classes that make it really easy to deal with intrinsic 10 // functions with the isa/dyncast family of functions. In particular, this 11 // allows you to do things like: 12 // 13 // if (auto *SF = dyn_cast<CoroSubFnInst>(Inst)) 14 // ... SF->getFrame() ... 15 // 16 // All intrinsic function calls are instances of the call instruction, so these 17 // are all subclasses of the CallInst class. Note that none of these classes 18 // has state or virtual methods, which is an important part of this gross/neat 19 // hack working. 20 // 21 // The helpful comment above is borrowed from llvm/IntrinsicInst.h, we keep 22 // coroutine intrinsic wrappers here since they are only used by the passes in 23 // the Coroutine library. 24 //===----------------------------------------------------------------------===// 25 26 #ifndef LLVM_LIB_TRANSFORMS_COROUTINES_COROINSTR_H 27 #define LLVM_LIB_TRANSFORMS_COROUTINES_COROINSTR_H 28 29 #include "llvm/IR/GlobalVariable.h" 30 #include "llvm/IR/IntrinsicInst.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 getFrame()48 Value *getFrame() const { return getArgOperand(FrameArg); } getIndex()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 getRawIndex()56 ConstantInt *getRawIndex() const { 57 return cast<ConstantInt>(getArgOperand(IndexArg)); 58 } 59 60 // Methods to support type inquiry through isa, cast, and dyn_cast: classof(const IntrinsicInst * I)61 static bool classof(const IntrinsicInst *I) { 62 return I->getIntrinsicID() == Intrinsic::coro_subfn_addr; 63 } classof(const Value * V)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: classof(const IntrinsicInst * I)73 static bool classof(const IntrinsicInst *I) { 74 return I->getIntrinsicID() == Intrinsic::coro_alloc; 75 } classof(const Value * V)76 static bool classof(const Value *V) { 77 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 78 } 79 }; 80 81 /// This represents the llvm.coro.alloc instruction. 82 class LLVM_LIBRARY_VISIBILITY CoroIdInst : public IntrinsicInst { 83 enum { AlignArg, PromiseArg, CoroutineArg, InfoArg }; 84 85 public: getCoroAlloc()86 CoroAllocInst *getCoroAlloc() { 87 for (User *U : users()) 88 if (auto *CA = dyn_cast<CoroAllocInst>(U)) 89 return CA; 90 return nullptr; 91 } 92 getCoroBegin()93 IntrinsicInst *getCoroBegin() { 94 for (User *U : users()) 95 if (auto *II = dyn_cast<IntrinsicInst>(U)) 96 if (II->getIntrinsicID() == Intrinsic::coro_begin) 97 return II; 98 llvm_unreachable("no coro.begin associated with coro.id"); 99 } 100 getPromise()101 AllocaInst *getPromise() const { 102 Value *Arg = getArgOperand(PromiseArg); 103 return isa<ConstantPointerNull>(Arg) 104 ? nullptr 105 : cast<AllocaInst>(Arg->stripPointerCasts()); 106 } 107 clearPromise()108 void clearPromise() { 109 Value *Arg = getArgOperand(PromiseArg); 110 setArgOperand(PromiseArg, 111 ConstantPointerNull::get(Type::getInt8PtrTy(getContext()))); 112 if (isa<AllocaInst>(Arg)) 113 return; 114 assert((isa<BitCastInst>(Arg) || isa<GetElementPtrInst>(Arg)) && 115 "unexpected instruction designating the promise"); 116 // TODO: Add a check that any remaining users of Inst are after coro.begin 117 // or add code to move the users after coro.begin. 118 auto *Inst = cast<Instruction>(Arg); 119 if (Inst->use_empty()) { 120 Inst->eraseFromParent(); 121 return; 122 } 123 Inst->moveBefore(getCoroBegin()->getNextNode()); 124 } 125 126 // Info argument of coro.id is 127 // fresh out of the frontend: null ; 128 // outlined : {Init, Return, Susp1, Susp2, ...} ; 129 // postsplit : [resume, destroy, cleanup] ; 130 // 131 // If parts of the coroutine were outlined to protect against undesirable 132 // code motion, these functions will be stored in a struct literal referred to 133 // by the Info parameter. Note: this is only needed before coroutine is split. 134 // 135 // After coroutine is split, resume functions are stored in an array 136 // referred to by this parameter. 137 138 struct Info { 139 ConstantStruct *OutlinedParts = nullptr; 140 ConstantArray *Resumers = nullptr; 141 hasOutlinedPartsInfo142 bool hasOutlinedParts() const { return OutlinedParts != nullptr; } isPostSplitInfo143 bool isPostSplit() const { return Resumers != nullptr; } isPreSplitInfo144 bool isPreSplit() const { return !isPostSplit(); } 145 }; getInfo()146 Info getInfo() const { 147 Info Result; 148 auto *GV = dyn_cast<GlobalVariable>(getRawInfo()); 149 if (!GV) 150 return Result; 151 152 assert(GV->isConstant() && GV->hasDefinitiveInitializer()); 153 Constant *Initializer = GV->getInitializer(); 154 if ((Result.OutlinedParts = dyn_cast<ConstantStruct>(Initializer))) 155 return Result; 156 157 Result.Resumers = cast<ConstantArray>(Initializer); 158 return Result; 159 } getRawInfo()160 Constant *getRawInfo() const { 161 return cast<Constant>(getArgOperand(InfoArg)->stripPointerCasts()); 162 } 163 setInfo(Constant * C)164 void setInfo(Constant *C) { setArgOperand(InfoArg, C); } 165 getCoroutine()166 Function *getCoroutine() const { 167 return cast<Function>(getArgOperand(CoroutineArg)->stripPointerCasts()); 168 } setCoroutineSelf()169 void setCoroutineSelf() { 170 assert(isa<ConstantPointerNull>(getArgOperand(CoroutineArg)) && 171 "Coroutine argument is already assigned"); 172 auto *const Int8PtrTy = Type::getInt8PtrTy(getContext()); 173 setArgOperand(CoroutineArg, 174 ConstantExpr::getBitCast(getFunction(), Int8PtrTy)); 175 } 176 177 // Methods to support type inquiry through isa, cast, and dyn_cast: classof(const IntrinsicInst * I)178 static bool classof(const IntrinsicInst *I) { 179 return I->getIntrinsicID() == Intrinsic::coro_id; 180 } classof(const Value * V)181 static bool classof(const Value *V) { 182 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 183 } 184 }; 185 186 /// This represents the llvm.coro.frame instruction. 187 class LLVM_LIBRARY_VISIBILITY CoroFrameInst : public IntrinsicInst { 188 public: 189 // Methods to support type inquiry through isa, cast, and dyn_cast: classof(const IntrinsicInst * I)190 static bool classof(const IntrinsicInst *I) { 191 return I->getIntrinsicID() == Intrinsic::coro_frame; 192 } classof(const Value * V)193 static bool classof(const Value *V) { 194 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 195 } 196 }; 197 198 /// This represents the llvm.coro.free instruction. 199 class LLVM_LIBRARY_VISIBILITY CoroFreeInst : public IntrinsicInst { 200 enum { IdArg, FrameArg }; 201 202 public: getFrame()203 Value *getFrame() const { return getArgOperand(FrameArg); } 204 205 // Methods to support type inquiry through isa, cast, and dyn_cast: classof(const IntrinsicInst * I)206 static bool classof(const IntrinsicInst *I) { 207 return I->getIntrinsicID() == Intrinsic::coro_free; 208 } classof(const Value * V)209 static bool classof(const Value *V) { 210 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 211 } 212 }; 213 214 /// This class represents the llvm.coro.begin instruction. 215 class LLVM_LIBRARY_VISIBILITY CoroBeginInst : public IntrinsicInst { 216 enum { IdArg, MemArg }; 217 218 public: getId()219 CoroIdInst *getId() const { return cast<CoroIdInst>(getArgOperand(IdArg)); } 220 getMem()221 Value *getMem() const { return getArgOperand(MemArg); } 222 223 // Methods for support type inquiry through isa, cast, and dyn_cast: classof(const IntrinsicInst * I)224 static bool classof(const IntrinsicInst *I) { 225 return I->getIntrinsicID() == Intrinsic::coro_begin; 226 } classof(const Value * V)227 static bool classof(const Value *V) { 228 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 229 } 230 }; 231 232 /// This represents the llvm.coro.save instruction. 233 class LLVM_LIBRARY_VISIBILITY CoroSaveInst : public IntrinsicInst { 234 public: 235 // Methods to support type inquiry through isa, cast, and dyn_cast: classof(const IntrinsicInst * I)236 static bool classof(const IntrinsicInst *I) { 237 return I->getIntrinsicID() == Intrinsic::coro_save; 238 } classof(const Value * V)239 static bool classof(const Value *V) { 240 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 241 } 242 }; 243 244 /// This represents the llvm.coro.promise instruction. 245 class LLVM_LIBRARY_VISIBILITY CoroPromiseInst : public IntrinsicInst { 246 enum { FrameArg, AlignArg, FromArg }; 247 248 public: isFromPromise()249 bool isFromPromise() const { 250 return cast<Constant>(getArgOperand(FromArg))->isOneValue(); 251 } getAlignment()252 unsigned getAlignment() const { 253 return cast<ConstantInt>(getArgOperand(AlignArg))->getZExtValue(); 254 } 255 256 // Methods to support type inquiry through isa, cast, and dyn_cast: classof(const IntrinsicInst * I)257 static bool classof(const IntrinsicInst *I) { 258 return I->getIntrinsicID() == Intrinsic::coro_promise; 259 } classof(const Value * V)260 static bool classof(const Value *V) { 261 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 262 } 263 }; 264 265 /// This represents the llvm.coro.suspend instruction. 266 class LLVM_LIBRARY_VISIBILITY CoroSuspendInst : public IntrinsicInst { 267 enum { SaveArg, FinalArg }; 268 269 public: getCoroSave()270 CoroSaveInst *getCoroSave() const { 271 Value *Arg = getArgOperand(SaveArg); 272 if (auto *SI = dyn_cast<CoroSaveInst>(Arg)) 273 return SI; 274 assert(isa<ConstantTokenNone>(Arg)); 275 return nullptr; 276 } isFinal()277 bool isFinal() const { 278 return cast<Constant>(getArgOperand(FinalArg))->isOneValue(); 279 } 280 281 // Methods to support type inquiry through isa, cast, and dyn_cast: classof(const IntrinsicInst * I)282 static bool classof(const IntrinsicInst *I) { 283 return I->getIntrinsicID() == Intrinsic::coro_suspend; 284 } classof(const Value * V)285 static bool classof(const Value *V) { 286 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 287 } 288 }; 289 290 /// This represents the llvm.coro.size instruction. 291 class LLVM_LIBRARY_VISIBILITY CoroSizeInst : public IntrinsicInst { 292 public: 293 // Methods to support type inquiry through isa, cast, and dyn_cast: classof(const IntrinsicInst * I)294 static bool classof(const IntrinsicInst *I) { 295 return I->getIntrinsicID() == Intrinsic::coro_size; 296 } classof(const Value * V)297 static bool classof(const Value *V) { 298 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 299 } 300 }; 301 302 /// This represents the llvm.coro.end instruction. 303 class LLVM_LIBRARY_VISIBILITY CoroEndInst : public IntrinsicInst { 304 enum { FrameArg, UnwindArg }; 305 306 public: isFallthrough()307 bool isFallthrough() const { return !isUnwind(); } isUnwind()308 bool isUnwind() const { 309 return cast<Constant>(getArgOperand(UnwindArg))->isOneValue(); 310 } 311 312 // Methods to support type inquiry through isa, cast, and dyn_cast: classof(const IntrinsicInst * I)313 static bool classof(const IntrinsicInst *I) { 314 return I->getIntrinsicID() == Intrinsic::coro_end; 315 } classof(const Value * V)316 static bool classof(const Value *V) { 317 return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); 318 } 319 }; 320 321 } // End namespace llvm. 322 323 #endif 324