• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 a common base class for llvm.coro.id instructions.
82 class LLVM_LIBRARY_VISIBILITY AnyCoroIdInst : public IntrinsicInst {
83 public:
getCoroAlloc()84   CoroAllocInst *getCoroAlloc() {
85     for (User *U : users())
86       if (auto *CA = dyn_cast<CoroAllocInst>(U))
87         return CA;
88     return nullptr;
89   }
90 
getCoroBegin()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:
classof(const IntrinsicInst * I)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 
classof(const Value * V)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:
getPromise()117   AllocaInst *getPromise() const {
118     Value *Arg = getArgOperand(PromiseArg);
119     return isa<ConstantPointerNull>(Arg)
120                ? nullptr
121                : cast<AllocaInst>(Arg->stripPointerCasts());
122   }
123 
clearPromise()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 
hasOutlinedPartsInfo158     bool hasOutlinedParts() const { return OutlinedParts != nullptr; }
isPostSplitInfo159     bool isPostSplit() const { return Resumers != nullptr; }
isPreSplitInfo160     bool isPreSplit() const { return !isPostSplit(); }
161   };
getInfo()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   }
getRawInfo()176   Constant *getRawInfo() const {
177     return cast<Constant>(getArgOperand(InfoArg)->stripPointerCasts());
178   }
179 
setInfo(Constant * C)180   void setInfo(Constant *C) { setArgOperand(InfoArg, C); }
181 
getCoroutine()182   Function *getCoroutine() const {
183     return cast<Function>(getArgOperand(CoroutineArg)->stripPointerCasts());
184   }
setCoroutineSelf()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:
classof(const IntrinsicInst * I)194   static bool classof(const IntrinsicInst *I) {
195     return I->getIntrinsicID() == Intrinsic::coro_id;
196   }
classof(const Value * V)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 
getStorageSize()210   uint64_t getStorageSize() const {
211     return cast<ConstantInt>(getArgOperand(SizeArg))->getZExtValue();
212   }
213 
getStorageAlignment()214   uint64_t getStorageAlignment() const {
215     return cast<ConstantInt>(getArgOperand(AlignArg))->getZExtValue();
216   }
217 
getStorage()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.
getPrototype()225   Function *getPrototype() const {
226     return cast<Function>(getArgOperand(PrototypeArg)->stripPointerCasts());
227   }
228 
229   /// Return the function to use for allocating memory.
getAllocFunction()230   Function *getAllocFunction() const {
231     return cast<Function>(getArgOperand(AllocArg)->stripPointerCasts());
232   }
233 
234   /// Return the function to use for deallocating memory.
getDeallocFunction()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:
classof(const IntrinsicInst * I)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   }
classof(const Value * V)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:
classof(const IntrinsicInst * I)255   static bool classof(const IntrinsicInst *I) {
256     return I->getIntrinsicID() == Intrinsic::coro_id_retcon;
257   }
classof(const Value * V)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:
classof(const IntrinsicInst * I)268   static bool classof(const IntrinsicInst *I) {
269     return I->getIntrinsicID() == Intrinsic::coro_id_retcon_once;
270   }
classof(const Value * V)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:
classof(const IntrinsicInst * I)280   static bool classof(const IntrinsicInst *I) {
281     return I->getIntrinsicID() == Intrinsic::coro_frame;
282   }
classof(const Value * V)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:
getFrame()293   Value *getFrame() const { return getArgOperand(FrameArg); }
294 
295   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)296   static bool classof(const IntrinsicInst *I) {
297     return I->getIntrinsicID() == Intrinsic::coro_free;
298   }
classof(const Value * V)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:
getId()309   AnyCoroIdInst *getId() const {
310     return cast<AnyCoroIdInst>(getArgOperand(IdArg));
311   }
312 
getMem()313   Value *getMem() const { return getArgOperand(MemArg); }
314 
315   // Methods for support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)316   static bool classof(const IntrinsicInst *I) {
317     return I->getIntrinsicID() == Intrinsic::coro_begin;
318   }
classof(const Value * V)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:
classof(const IntrinsicInst * I)328   static bool classof(const IntrinsicInst *I) {
329     return I->getIntrinsicID() == Intrinsic::coro_save;
330   }
classof(const Value * V)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:
isFromPromise()341   bool isFromPromise() const {
342     return cast<Constant>(getArgOperand(FromArg))->isOneValue();
343   }
getAlignment()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:
classof(const IntrinsicInst * I)349   static bool classof(const IntrinsicInst *I) {
350     return I->getIntrinsicID() == Intrinsic::coro_promise;
351   }
classof(const Value * V)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:
classof(const IntrinsicInst * I)362   static bool classof(const IntrinsicInst *I) {
363     return I->getIntrinsicID() == Intrinsic::coro_suspend ||
364            I->getIntrinsicID() == Intrinsic::coro_suspend_retcon;
365   }
classof(const Value * V)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:
getCoroSave()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 
isFinal()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:
classof(const IntrinsicInst * I)389   static bool classof(const IntrinsicInst *I) {
390     return I->getIntrinsicID() == Intrinsic::coro_suspend;
391   }
classof(const Value * V)392   static bool classof(const Value *V) {
393     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
394   }
395 };
396 
getCoroSave()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:
value_begin()406   op_iterator value_begin() { return arg_begin(); }
value_begin()407   const_op_iterator value_begin() const { return arg_begin(); }
408 
value_end()409   op_iterator value_end() { return arg_end(); }
value_end()410   const_op_iterator value_end() const { return arg_end(); }
411 
value_operands()412   iterator_range<op_iterator> value_operands() {
413     return make_range(value_begin(), value_end());
414   }
value_operands()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:
classof(const IntrinsicInst * I)420   static bool classof(const IntrinsicInst *I) {
421     return I->getIntrinsicID() == Intrinsic::coro_suspend_retcon;
422   }
classof(const Value * V)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:
classof(const IntrinsicInst * I)432   static bool classof(const IntrinsicInst *I) {
433     return I->getIntrinsicID() == Intrinsic::coro_size;
434   }
classof(const Value * V)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:
isFallthrough()445   bool isFallthrough() const { return !isUnwind(); }
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:
classof(const IntrinsicInst * I)451   static bool classof(const IntrinsicInst *I) {
452     return I->getIntrinsicID() == Intrinsic::coro_end;
453   }
classof(const Value * V)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:
getSize()463   Value *getSize() const {
464     return getArgOperand(SizeArg);
465   }
getAlignment()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:
classof(const IntrinsicInst * I)471   static bool classof(const IntrinsicInst *I) {
472     return I->getIntrinsicID() == Intrinsic::coro_alloca_alloc;
473   }
classof(const Value * V)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:
getAlloc()483   CoroAllocaAllocInst *getAlloc() const {
484     return cast<CoroAllocaAllocInst>(getArgOperand(AllocArg));
485   }
486 
487   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)488   static bool classof(const IntrinsicInst *I) {
489     return I->getIntrinsicID() == Intrinsic::coro_alloca_get;
490   }
classof(const Value * V)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:
getAlloc()500   CoroAllocaAllocInst *getAlloc() const {
501     return cast<CoroAllocaAllocInst>(getArgOperand(AllocArg));
502   }
503 
504   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)505   static bool classof(const IntrinsicInst *I) {
506     return I->getIntrinsicID() == Intrinsic::coro_alloca_free;
507   }
classof(const Value * V)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