• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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