xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Transforms/Coroutines/CoroInstr.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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_TRANSFORMS_COROUTINES_COROINSTR_H
26 #define LLVM_TRANSFORMS_COROUTINES_COROINSTR_H
27 
28 #include "llvm/IR/GlobalVariable.h"
29 #include "llvm/IR/IntrinsicInst.h"
30 #include "llvm/Support/Compiler.h"
31 #include "llvm/Support/raw_ostream.h"
32 
33 namespace llvm {
34 
35 /// This class represents the llvm.coro.subfn.addr instruction.
36 class CoroSubFnInst : public IntrinsicInst {
37   enum { FrameArg, IndexArg };
38 
39 public:
40   enum ResumeKind {
41     RestartTrigger = -1,
42     ResumeIndex,
43     DestroyIndex,
44     CleanupIndex,
45     IndexLast,
46     IndexFirst = RestartTrigger
47   };
48 
getFrame()49   Value *getFrame() const { return getArgOperand(FrameArg); }
getIndex()50   ResumeKind getIndex() const {
51     int64_t Index = getRawIndex()->getValue().getSExtValue();
52     assert(Index >= IndexFirst && Index < IndexLast &&
53            "unexpected CoroSubFnInst index argument");
54     return static_cast<ResumeKind>(Index);
55   }
56 
getRawIndex()57   ConstantInt *getRawIndex() const {
58     return cast<ConstantInt>(getArgOperand(IndexArg));
59   }
60 
61   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)62   static bool classof(const IntrinsicInst *I) {
63     return I->getIntrinsicID() == Intrinsic::coro_subfn_addr;
64   }
classof(const Value * V)65   static bool classof(const Value *V) {
66     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
67   }
68 };
69 
70 /// This represents the llvm.coro.alloc instruction.
71 class CoroAllocInst : public IntrinsicInst {
72 public:
73   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)74   static bool classof(const IntrinsicInst *I) {
75     return I->getIntrinsicID() == Intrinsic::coro_alloc;
76   }
classof(const Value * V)77   static bool classof(const Value *V) {
78     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
79   }
80 };
81 
82 /// This represents the llvm.coro.await.suspend.{void,bool,handle} instructions.
83 // FIXME: add callback metadata
84 // FIXME: make a proper IntrinisicInst. Currently this is not possible,
85 // because llvm.coro.await.suspend.* can be invoked.
86 class CoroAwaitSuspendInst : public CallBase {
87   enum { AwaiterArg, FrameArg, WrapperArg };
88 
89 public:
getAwaiter()90   Value *getAwaiter() const { return getArgOperand(AwaiterArg); }
91 
getFrame()92   Value *getFrame() const { return getArgOperand(FrameArg); }
93 
getWrapperFunction()94   Function *getWrapperFunction() const {
95     return cast<Function>(getArgOperand(WrapperArg));
96   }
97 
98   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const CallBase * CB)99   static bool classof(const CallBase *CB) {
100     if (const Function *CF = CB->getCalledFunction()) {
101       auto IID = CF->getIntrinsicID();
102       return IID == Intrinsic::coro_await_suspend_void ||
103              IID == Intrinsic::coro_await_suspend_bool ||
104              IID == Intrinsic::coro_await_suspend_handle;
105     }
106 
107     return false;
108   }
109 
classof(const Value * V)110   static bool classof(const Value *V) {
111     return isa<CallBase>(V) && classof(cast<CallBase>(V));
112   }
113 };
114 
115 /// This represents a common base class for llvm.coro.id instructions.
116 class AnyCoroIdInst : public IntrinsicInst {
117 public:
getCoroAlloc()118   CoroAllocInst *getCoroAlloc() {
119     for (User *U : users())
120       if (auto *CA = dyn_cast<CoroAllocInst>(U))
121         return CA;
122     return nullptr;
123   }
124 
getCoroBegin()125   IntrinsicInst *getCoroBegin() {
126     for (User *U : users())
127       if (auto *II = dyn_cast<IntrinsicInst>(U))
128         if (II->getIntrinsicID() == Intrinsic::coro_begin ||
129             II->getIntrinsicID() == Intrinsic::coro_begin_custom_abi)
130           return II;
131     llvm_unreachable("no coro.begin associated with coro.id");
132   }
133 
134   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)135   static bool classof(const IntrinsicInst *I) {
136     auto ID = I->getIntrinsicID();
137     return ID == Intrinsic::coro_id || ID == Intrinsic::coro_id_retcon ||
138            ID == Intrinsic::coro_id_retcon_once ||
139            ID == Intrinsic::coro_id_async;
140   }
141 
classof(const Value * V)142   static bool classof(const Value *V) {
143     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
144   }
145 };
146 
147 /// This represents the llvm.coro.id instruction.
148 class CoroIdInst : public AnyCoroIdInst {
149   enum { AlignArg, PromiseArg, CoroutineArg, InfoArg };
150 
151 public:
getPromise()152   AllocaInst *getPromise() const {
153     Value *Arg = getArgOperand(PromiseArg);
154     return isa<ConstantPointerNull>(Arg)
155                ? nullptr
156                : cast<AllocaInst>(Arg->stripPointerCasts());
157   }
158 
clearPromise()159   void clearPromise() {
160     Value *Arg = getArgOperand(PromiseArg);
161     setArgOperand(PromiseArg, ConstantPointerNull::get(
162                                   PointerType::getUnqual(getContext())));
163     if (isa<AllocaInst>(Arg))
164       return;
165     assert((isa<BitCastInst>(Arg) || isa<GetElementPtrInst>(Arg)) &&
166            "unexpected instruction designating the promise");
167     // TODO: Add a check that any remaining users of Inst are after coro.begin
168     // or add code to move the users after coro.begin.
169     auto *Inst = cast<Instruction>(Arg);
170     if (Inst->use_empty()) {
171       Inst->eraseFromParent();
172       return;
173     }
174     Inst->moveBefore(std::next(getCoroBegin()->getIterator()));
175   }
176 
177   // Info argument of coro.id is
178   //   fresh out of the frontend: null ;
179   //   outlined                 : {Init, Return, Susp1, Susp2, ...} ;
180   //   postsplit                : [resume, destroy, cleanup] ;
181   //
182   // If parts of the coroutine were outlined to protect against undesirable
183   // code motion, these functions will be stored in a struct literal referred to
184   // by the Info parameter. Note: this is only needed before coroutine is split.
185   //
186   // After coroutine is split, resume functions are stored in an array
187   // referred to by this parameter.
188 
189   struct Info {
190     ConstantStruct *OutlinedParts = nullptr;
191     ConstantArray *Resumers = nullptr;
192 
hasOutlinedPartsInfo193     bool hasOutlinedParts() const { return OutlinedParts != nullptr; }
isPostSplitInfo194     bool isPostSplit() const { return Resumers != nullptr; }
isPreSplitInfo195     bool isPreSplit() const { return !isPostSplit(); }
196   };
getInfo()197   Info getInfo() const {
198     Info Result;
199     auto *GV = dyn_cast<GlobalVariable>(getRawInfo());
200     if (!GV)
201       return Result;
202 
203     assert(GV->isConstant() && GV->hasDefinitiveInitializer());
204     Constant *Initializer = GV->getInitializer();
205     if ((Result.OutlinedParts = dyn_cast<ConstantStruct>(Initializer)))
206       return Result;
207 
208     Result.Resumers = cast<ConstantArray>(Initializer);
209     return Result;
210   }
getRawInfo()211   Constant *getRawInfo() const {
212     return cast<Constant>(getArgOperand(InfoArg)->stripPointerCasts());
213   }
214 
setInfo(Constant * C)215   void setInfo(Constant *C) { setArgOperand(InfoArg, C); }
216 
getCoroutine()217   Function *getCoroutine() const {
218     return cast<Function>(getArgOperand(CoroutineArg)->stripPointerCasts());
219   }
setCoroutineSelf()220   void setCoroutineSelf() {
221     if (!isa<ConstantPointerNull>(getArgOperand(CoroutineArg)))
222       assert(getCoroutine() == getFunction() && "Don't change coroutine.");
223     setArgOperand(CoroutineArg, getFunction());
224   }
225 
226   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)227   static bool classof(const IntrinsicInst *I) {
228     return I->getIntrinsicID() == Intrinsic::coro_id;
229   }
classof(const Value * V)230   static bool classof(const Value *V) {
231     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
232   }
233 };
234 
235 /// This represents either the llvm.coro.id.retcon or
236 /// llvm.coro.id.retcon.once instruction.
237 class AnyCoroIdRetconInst : public AnyCoroIdInst {
238   enum { SizeArg, AlignArg, StorageArg, PrototypeArg, AllocArg, DeallocArg };
239 
240 public:
241   LLVM_ABI void checkWellFormed() const;
242 
getStorageSize()243   uint64_t getStorageSize() const {
244     return cast<ConstantInt>(getArgOperand(SizeArg))->getZExtValue();
245   }
246 
getStorageAlignment()247   Align getStorageAlignment() const {
248     return cast<ConstantInt>(getArgOperand(AlignArg))->getAlignValue();
249   }
250 
getStorage()251   Value *getStorage() const { return getArgOperand(StorageArg); }
252 
253   /// Return the prototype for the continuation function.  The type,
254   /// attributes, and calling convention of the continuation function(s)
255   /// are taken from this declaration.
getPrototype()256   Function *getPrototype() const {
257     return cast<Function>(getArgOperand(PrototypeArg)->stripPointerCasts());
258   }
259 
260   /// Return the function to use for allocating memory.
getAllocFunction()261   Function *getAllocFunction() const {
262     return cast<Function>(getArgOperand(AllocArg)->stripPointerCasts());
263   }
264 
265   /// Return the function to use for deallocating memory.
getDeallocFunction()266   Function *getDeallocFunction() const {
267     return cast<Function>(getArgOperand(DeallocArg)->stripPointerCasts());
268   }
269 
270   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)271   static bool classof(const IntrinsicInst *I) {
272     auto ID = I->getIntrinsicID();
273     return ID == Intrinsic::coro_id_retcon ||
274            ID == Intrinsic::coro_id_retcon_once;
275   }
classof(const Value * V)276   static bool classof(const Value *V) {
277     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
278   }
279 };
280 
281 /// This represents the llvm.coro.id.retcon instruction.
282 class CoroIdRetconInst : public AnyCoroIdRetconInst {
283 public:
284   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)285   static bool classof(const IntrinsicInst *I) {
286     return I->getIntrinsicID() == Intrinsic::coro_id_retcon;
287   }
classof(const Value * V)288   static bool classof(const Value *V) {
289     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
290   }
291 };
292 
293 /// This represents the llvm.coro.id.retcon.once instruction.
294 class CoroIdRetconOnceInst : public AnyCoroIdRetconInst {
295 public:
296   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)297   static bool classof(const IntrinsicInst *I) {
298     return I->getIntrinsicID() == Intrinsic::coro_id_retcon_once;
299   }
classof(const Value * V)300   static bool classof(const Value *V) {
301     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
302   }
303 };
304 
305 /// This represents the llvm.coro.id.async instruction.
306 class CoroIdAsyncInst : public AnyCoroIdInst {
307   enum { SizeArg, AlignArg, StorageArg, AsyncFuncPtrArg };
308 
309 public:
310   LLVM_ABI void checkWellFormed() const;
311 
312   /// The initial async function context size. The fields of which are reserved
313   /// for use by the frontend. The frame will be allocated as a tail of this
314   /// context.
getStorageSize()315   uint64_t getStorageSize() const {
316     return cast<ConstantInt>(getArgOperand(SizeArg))->getZExtValue();
317   }
318 
319   /// The alignment of the initial async function context.
getStorageAlignment()320   Align getStorageAlignment() const {
321     return cast<ConstantInt>(getArgOperand(AlignArg))->getAlignValue();
322   }
323 
324   /// The async context parameter.
getStorage()325   Value *getStorage() const {
326     return getParent()->getParent()->getArg(getStorageArgumentIndex());
327   }
328 
getStorageArgumentIndex()329   unsigned getStorageArgumentIndex() const {
330     auto *Arg = cast<ConstantInt>(getArgOperand(StorageArg));
331     return Arg->getZExtValue();
332   }
333 
334   /// Return the async function pointer address. This should be the address of
335   /// a async function pointer struct for the current async function.
336   /// struct async_function_pointer {
337   ///   uint32_t context_size;
338   ///   uint32_t relative_async_function_pointer;
339   ///  };
getAsyncFunctionPointer()340   GlobalVariable *getAsyncFunctionPointer() const {
341     return cast<GlobalVariable>(
342         getArgOperand(AsyncFuncPtrArg)->stripPointerCasts());
343   }
344 
345   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)346   static bool classof(const IntrinsicInst *I) {
347     auto ID = I->getIntrinsicID();
348     return ID == Intrinsic::coro_id_async;
349   }
350 
classof(const Value * V)351   static bool classof(const Value *V) {
352     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
353   }
354 };
355 
356 /// This represents the llvm.coro.context.alloc instruction.
357 class CoroAsyncContextAllocInst : public IntrinsicInst {
358   enum { AsyncFuncPtrArg };
359 
360 public:
getAsyncFunctionPointer()361   GlobalVariable *getAsyncFunctionPointer() const {
362     return cast<GlobalVariable>(
363         getArgOperand(AsyncFuncPtrArg)->stripPointerCasts());
364   }
365 
366   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)367   static bool classof(const IntrinsicInst *I) {
368     return I->getIntrinsicID() == Intrinsic::coro_async_context_alloc;
369   }
classof(const Value * V)370   static bool classof(const Value *V) {
371     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
372   }
373 };
374 
375 /// This represents the llvm.coro.context.dealloc instruction.
376 class CoroAsyncContextDeallocInst : public IntrinsicInst {
377   enum { AsyncContextArg };
378 
379 public:
getAsyncContext()380   Value *getAsyncContext() const {
381     return getArgOperand(AsyncContextArg)->stripPointerCasts();
382   }
383 
384   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)385   static bool classof(const IntrinsicInst *I) {
386     return I->getIntrinsicID() == Intrinsic::coro_async_context_dealloc;
387   }
classof(const Value * V)388   static bool classof(const Value *V) {
389     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
390   }
391 };
392 
393 /// This represents the llvm.coro.async.resume instruction.
394 /// During lowering this is replaced by the resume function of a suspend point
395 /// (the continuation function).
396 class CoroAsyncResumeInst : public IntrinsicInst {
397 public:
398   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)399   static bool classof(const IntrinsicInst *I) {
400     return I->getIntrinsicID() == Intrinsic::coro_async_resume;
401   }
classof(const Value * V)402   static bool classof(const Value *V) {
403     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
404   }
405 };
406 
407 /// This represents the llvm.coro.async.size.replace instruction.
408 class CoroAsyncSizeReplace : public IntrinsicInst {
409 public:
410   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)411   static bool classof(const IntrinsicInst *I) {
412     return I->getIntrinsicID() == Intrinsic::coro_async_size_replace;
413   }
classof(const Value * V)414   static bool classof(const Value *V) {
415     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
416   }
417 };
418 
419 /// This represents the llvm.coro.frame instruction.
420 class CoroFrameInst : public IntrinsicInst {
421 public:
422   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)423   static bool classof(const IntrinsicInst *I) {
424     return I->getIntrinsicID() == Intrinsic::coro_frame;
425   }
classof(const Value * V)426   static bool classof(const Value *V) {
427     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
428   }
429 };
430 
431 /// This represents the llvm.coro.free instruction.
432 class CoroFreeInst : public IntrinsicInst {
433   enum { IdArg, FrameArg };
434 
435 public:
getFrame()436   Value *getFrame() const { return getArgOperand(FrameArg); }
437 
438   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)439   static bool classof(const IntrinsicInst *I) {
440     return I->getIntrinsicID() == Intrinsic::coro_free;
441   }
classof(const Value * V)442   static bool classof(const Value *V) {
443     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
444   }
445 };
446 
447 /// This class represents the llvm.coro.begin or llvm.coro.begin.custom.abi
448 /// instructions.
449 class CoroBeginInst : public IntrinsicInst {
450   enum { IdArg, MemArg, CustomABIArg };
451 
452 public:
getId()453   AnyCoroIdInst *getId() const {
454     return cast<AnyCoroIdInst>(getArgOperand(IdArg));
455   }
456 
hasCustomABI()457   bool hasCustomABI() const {
458     return getIntrinsicID() == Intrinsic::coro_begin_custom_abi;
459   }
460 
getCustomABI()461   int getCustomABI() const {
462     return cast<ConstantInt>(getArgOperand(CustomABIArg))->getZExtValue();
463   }
464 
getMem()465   Value *getMem() const { return getArgOperand(MemArg); }
466 
467   // Methods for support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)468   static bool classof(const IntrinsicInst *I) {
469     return I->getIntrinsicID() == Intrinsic::coro_begin ||
470            I->getIntrinsicID() == Intrinsic::coro_begin_custom_abi;
471   }
classof(const Value * V)472   static bool classof(const Value *V) {
473     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
474   }
475 };
476 
477 /// This represents the llvm.coro.save instruction.
478 class CoroSaveInst : public IntrinsicInst {
479 public:
480   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)481   static bool classof(const IntrinsicInst *I) {
482     return I->getIntrinsicID() == Intrinsic::coro_save;
483   }
classof(const Value * V)484   static bool classof(const Value *V) {
485     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
486   }
487 };
488 
489 /// This represents the llvm.coro.promise instruction.
490 class CoroPromiseInst : public IntrinsicInst {
491   enum { FrameArg, AlignArg, FromArg };
492 
493 public:
494   /// Are we translating from the frame to the promise (false) or from
495   /// the promise to the frame (true)?
isFromPromise()496   bool isFromPromise() const {
497     return cast<Constant>(getArgOperand(FromArg))->isOneValue();
498   }
499 
500   /// The required alignment of the promise.  This must match the
501   /// alignment of the promise alloca in the coroutine.
getAlignment()502   Align getAlignment() const {
503     return cast<ConstantInt>(getArgOperand(AlignArg))->getAlignValue();
504   }
505 
506   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)507   static bool classof(const IntrinsicInst *I) {
508     return I->getIntrinsicID() == Intrinsic::coro_promise;
509   }
classof(const Value * V)510   static bool classof(const Value *V) {
511     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
512   }
513 };
514 
515 class AnyCoroSuspendInst : public IntrinsicInst {
516 public:
517   CoroSaveInst *getCoroSave() const;
518 
519   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)520   static bool classof(const IntrinsicInst *I) {
521     return I->getIntrinsicID() == Intrinsic::coro_suspend ||
522            I->getIntrinsicID() == Intrinsic::coro_suspend_async ||
523            I->getIntrinsicID() == Intrinsic::coro_suspend_retcon;
524   }
classof(const Value * V)525   static bool classof(const Value *V) {
526     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
527   }
528 };
529 
530 /// This represents the llvm.coro.suspend instruction.
531 class CoroSuspendInst : public AnyCoroSuspendInst {
532   enum { SaveArg, FinalArg };
533 
534 public:
getCoroSave()535   CoroSaveInst *getCoroSave() const {
536     Value *Arg = getArgOperand(SaveArg);
537     if (auto *SI = dyn_cast<CoroSaveInst>(Arg))
538       return SI;
539     assert(isa<ConstantTokenNone>(Arg));
540     return nullptr;
541   }
542 
isFinal()543   bool isFinal() const {
544     return cast<Constant>(getArgOperand(FinalArg))->isOneValue();
545   }
546 
547   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)548   static bool classof(const IntrinsicInst *I) {
549     return I->getIntrinsicID() == Intrinsic::coro_suspend;
550   }
classof(const Value * V)551   static bool classof(const Value *V) {
552     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
553   }
554 };
555 
getCoroSave()556 inline CoroSaveInst *AnyCoroSuspendInst::getCoroSave() const {
557   if (auto Suspend = dyn_cast<CoroSuspendInst>(this))
558     return Suspend->getCoroSave();
559   return nullptr;
560 }
561 
562 /// This represents the llvm.coro.suspend.async instruction.
563 class CoroSuspendAsyncInst : public AnyCoroSuspendInst {
564 public:
565   enum {
566     StorageArgNoArg,
567     ResumeFunctionArg,
568     AsyncContextProjectionArg,
569     MustTailCallFuncArg
570   };
571 
572   LLVM_ABI void checkWellFormed() const;
573 
getStorageArgumentIndex()574   unsigned getStorageArgumentIndex() const {
575     auto *Arg = cast<ConstantInt>(getArgOperand(StorageArgNoArg));
576     return Arg->getZExtValue();
577   }
578 
getAsyncContextProjectionFunction()579   Function *getAsyncContextProjectionFunction() const {
580     return cast<Function>(
581         getArgOperand(AsyncContextProjectionArg)->stripPointerCasts());
582   }
583 
getResumeFunction()584   CoroAsyncResumeInst *getResumeFunction() const {
585     return cast<CoroAsyncResumeInst>(
586         getArgOperand(ResumeFunctionArg)->stripPointerCasts());
587   }
588 
getMustTailCallFunction()589   Function *getMustTailCallFunction() const {
590     return cast<Function>(
591         getArgOperand(MustTailCallFuncArg)->stripPointerCasts());
592   }
593 
594   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)595   static bool classof(const IntrinsicInst *I) {
596     return I->getIntrinsicID() == Intrinsic::coro_suspend_async;
597   }
classof(const Value * V)598   static bool classof(const Value *V) {
599     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
600   }
601 };
602 
603 /// This represents the llvm.coro.suspend.retcon instruction.
604 class CoroSuspendRetconInst : public AnyCoroSuspendInst {
605 public:
value_begin()606   op_iterator value_begin() { return arg_begin(); }
value_begin()607   const_op_iterator value_begin() const { return arg_begin(); }
608 
value_end()609   op_iterator value_end() { return arg_end(); }
value_end()610   const_op_iterator value_end() const { return arg_end(); }
611 
value_operands()612   iterator_range<op_iterator> value_operands() {
613     return make_range(value_begin(), value_end());
614   }
value_operands()615   iterator_range<const_op_iterator> value_operands() const {
616     return make_range(value_begin(), value_end());
617   }
618 
619   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)620   static bool classof(const IntrinsicInst *I) {
621     return I->getIntrinsicID() == Intrinsic::coro_suspend_retcon;
622   }
classof(const Value * V)623   static bool classof(const Value *V) {
624     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
625   }
626 };
627 
628 /// This represents the llvm.coro.size instruction.
629 class CoroSizeInst : public IntrinsicInst {
630 public:
631   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)632   static bool classof(const IntrinsicInst *I) {
633     return I->getIntrinsicID() == Intrinsic::coro_size;
634   }
classof(const Value * V)635   static bool classof(const Value *V) {
636     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
637   }
638 };
639 
640 /// This represents the llvm.coro.align instruction.
641 class CoroAlignInst : public IntrinsicInst {
642 public:
643   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)644   static bool classof(const IntrinsicInst *I) {
645     return I->getIntrinsicID() == Intrinsic::coro_align;
646   }
classof(const Value * V)647   static bool classof(const Value *V) {
648     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
649   }
650 };
651 
652 /// This represents the llvm.end.results instruction.
653 class CoroEndResults : public IntrinsicInst {
654 public:
retval_begin()655   op_iterator retval_begin() { return arg_begin(); }
retval_begin()656   const_op_iterator retval_begin() const { return arg_begin(); }
657 
retval_end()658   op_iterator retval_end() { return arg_end(); }
retval_end()659   const_op_iterator retval_end() const { return arg_end(); }
660 
return_values()661   iterator_range<op_iterator> return_values() {
662     return make_range(retval_begin(), retval_end());
663   }
return_values()664   iterator_range<const_op_iterator> return_values() const {
665     return make_range(retval_begin(), retval_end());
666   }
667 
numReturns()668   unsigned numReturns() const {
669     return std::distance(retval_begin(), retval_end());
670   }
671 
672   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)673   static bool classof(const IntrinsicInst *I) {
674     return I->getIntrinsicID() == Intrinsic::coro_end_results;
675   }
classof(const Value * V)676   static bool classof(const Value *V) {
677     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
678   }
679 };
680 
681 class AnyCoroEndInst : public IntrinsicInst {
682   enum { FrameArg, UnwindArg, TokenArg };
683 
684 public:
isFallthrough()685   bool isFallthrough() const { return !isUnwind(); }
isUnwind()686   bool isUnwind() const {
687     return cast<Constant>(getArgOperand(UnwindArg))->isOneValue();
688   }
689 
hasResults()690   bool hasResults() const {
691     return !isa<ConstantTokenNone>(getArgOperand(TokenArg));
692   }
693 
getResults()694   CoroEndResults *getResults() const {
695     assert(hasResults());
696     return cast<CoroEndResults>(getArgOperand(TokenArg));
697   }
698 
699   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)700   static bool classof(const IntrinsicInst *I) {
701     auto ID = I->getIntrinsicID();
702     return ID == Intrinsic::coro_end || ID == Intrinsic::coro_end_async;
703   }
classof(const Value * V)704   static bool classof(const Value *V) {
705     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
706   }
707 };
708 
709 /// This represents the llvm.coro.end instruction.
710 class CoroEndInst : public AnyCoroEndInst {
711 public:
712   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)713   static bool classof(const IntrinsicInst *I) {
714     return I->getIntrinsicID() == Intrinsic::coro_end;
715   }
classof(const Value * V)716   static bool classof(const Value *V) {
717     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
718   }
719 };
720 
721 /// This represents the llvm.coro.end instruction.
722 class CoroAsyncEndInst : public AnyCoroEndInst {
723   enum { FrameArg, UnwindArg, MustTailCallFuncArg };
724 
725 public:
726   LLVM_ABI void checkWellFormed() const;
727 
getMustTailCallFunction()728   Function *getMustTailCallFunction() const {
729     if (arg_size() < 3)
730       return nullptr;
731 
732     return cast<Function>(
733         getArgOperand(MustTailCallFuncArg)->stripPointerCasts());
734   }
735 
736   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)737   static bool classof(const IntrinsicInst *I) {
738     return I->getIntrinsicID() == Intrinsic::coro_end_async;
739   }
classof(const Value * V)740   static bool classof(const Value *V) {
741     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
742   }
743 };
744 
745 /// This represents the llvm.coro.alloca.alloc instruction.
746 class CoroAllocaAllocInst : public IntrinsicInst {
747   enum { SizeArg, AlignArg };
748 
749 public:
getSize()750   Value *getSize() const { return getArgOperand(SizeArg); }
getAlignment()751   Align getAlignment() const {
752     return cast<ConstantInt>(getArgOperand(AlignArg))->getAlignValue();
753   }
754 
755   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)756   static bool classof(const IntrinsicInst *I) {
757     return I->getIntrinsicID() == Intrinsic::coro_alloca_alloc;
758   }
classof(const Value * V)759   static bool classof(const Value *V) {
760     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
761   }
762 };
763 
764 /// This represents the llvm.coro.alloca.get instruction.
765 class CoroAllocaGetInst : public IntrinsicInst {
766   enum { AllocArg };
767 
768 public:
getAlloc()769   CoroAllocaAllocInst *getAlloc() const {
770     return cast<CoroAllocaAllocInst>(getArgOperand(AllocArg));
771   }
772 
773   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)774   static bool classof(const IntrinsicInst *I) {
775     return I->getIntrinsicID() == Intrinsic::coro_alloca_get;
776   }
classof(const Value * V)777   static bool classof(const Value *V) {
778     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
779   }
780 };
781 
782 /// This represents the llvm.coro.alloca.free instruction.
783 class CoroAllocaFreeInst : public IntrinsicInst {
784   enum { AllocArg };
785 
786 public:
getAlloc()787   CoroAllocaAllocInst *getAlloc() const {
788     return cast<CoroAllocaAllocInst>(getArgOperand(AllocArg));
789   }
790 
791   // Methods to support type inquiry through isa, cast, and dyn_cast:
classof(const IntrinsicInst * I)792   static bool classof(const IntrinsicInst *I) {
793     return I->getIntrinsicID() == Intrinsic::coro_alloca_free;
794   }
classof(const Value * V)795   static bool classof(const Value *V) {
796     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
797   }
798 };
799 
800 } // End namespace llvm.
801 
802 #endif // LLVM_TRANSFORMS_COROUTINES_COROINSTR_H
803