Home | History | Annotate | Download | only in Coroutines
      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 
     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 the llvm.coro.alloc instruction.
     82 class LLVM_LIBRARY_VISIBILITY CoroIdInst : public IntrinsicInst {
     83   enum { AlignArg, PromiseArg, CoroutineArg, InfoArg };
     84 
     85 public:
     86   CoroAllocInst *getCoroAlloc() {
     87     for (User *U : users())
     88       if (auto *CA = dyn_cast<CoroAllocInst>(U))
     89         return CA;
     90     return nullptr;
     91   }
     92 
     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 
    101   AllocaInst *getPromise() const {
    102     Value *Arg = getArgOperand(PromiseArg);
    103     return isa<ConstantPointerNull>(Arg)
    104                ? nullptr
    105                : cast<AllocaInst>(Arg->stripPointerCasts());
    106   }
    107 
    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 
    142     bool hasOutlinedParts() const { return OutlinedParts != nullptr; }
    143     bool isPostSplit() const { return Resumers != nullptr; }
    144     bool isPreSplit() const { return !isPostSplit(); }
    145   };
    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   }
    160   Constant *getRawInfo() const {
    161     return cast<Constant>(getArgOperand(InfoArg)->stripPointerCasts());
    162   }
    163 
    164   void setInfo(Constant *C) { setArgOperand(InfoArg, C); }
    165 
    166   Function *getCoroutine() const {
    167     return cast<Function>(getArgOperand(CoroutineArg)->stripPointerCasts());
    168   }
    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:
    178   static bool classof(const IntrinsicInst *I) {
    179     return I->getIntrinsicID() == Intrinsic::coro_id;
    180   }
    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:
    190   static bool classof(const IntrinsicInst *I) {
    191     return I->getIntrinsicID() == Intrinsic::coro_frame;
    192   }
    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:
    203   Value *getFrame() const { return getArgOperand(FrameArg); }
    204 
    205   // Methods to support type inquiry through isa, cast, and dyn_cast:
    206   static bool classof(const IntrinsicInst *I) {
    207     return I->getIntrinsicID() == Intrinsic::coro_free;
    208   }
    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:
    219   CoroIdInst *getId() const { return cast<CoroIdInst>(getArgOperand(IdArg)); }
    220 
    221   Value *getMem() const { return getArgOperand(MemArg); }
    222 
    223   // Methods for support type inquiry through isa, cast, and dyn_cast:
    224   static bool classof(const IntrinsicInst *I) {
    225     return I->getIntrinsicID() == Intrinsic::coro_begin;
    226   }
    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:
    236   static bool classof(const IntrinsicInst *I) {
    237     return I->getIntrinsicID() == Intrinsic::coro_save;
    238   }
    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:
    249   bool isFromPromise() const {
    250     return cast<Constant>(getArgOperand(FromArg))->isOneValue();
    251   }
    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:
    257   static bool classof(const IntrinsicInst *I) {
    258     return I->getIntrinsicID() == Intrinsic::coro_promise;
    259   }
    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:
    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   }
    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:
    282   static bool classof(const IntrinsicInst *I) {
    283     return I->getIntrinsicID() == Intrinsic::coro_suspend;
    284   }
    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:
    294   static bool classof(const IntrinsicInst *I) {
    295     return I->getIntrinsicID() == Intrinsic::coro_size;
    296   }
    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:
    307   bool isFallthrough() const { return !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:
    313   static bool classof(const IntrinsicInst *I) {
    314     return I->getIntrinsicID() == Intrinsic::coro_end;
    315   }
    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