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
32namespace llvm {
33
34/// This class represents the llvm.coro.subfn.addr instruction.
35class LLVM_LIBRARY_VISIBILITY CoroSubFnInst : public IntrinsicInst {
36  enum { FrameArg, IndexArg };
37
38public:
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.
70class LLVM_LIBRARY_VISIBILITY CoroAllocInst : public IntrinsicInst {
71public:
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 a common base class for llvm.coro.id instructions.
82class LLVM_LIBRARY_VISIBILITY AnyCoroIdInst : public IntrinsicInst {
83public:
84  CoroAllocInst *getCoroAlloc() {
85    for (User *U : users())
86      if (auto *CA = dyn_cast<CoroAllocInst>(U))
87        return CA;
88    return nullptr;
89  }
90
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:
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
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.
113class LLVM_LIBRARY_VISIBILITY CoroIdInst : public AnyCoroIdInst {
114  enum { AlignArg, PromiseArg, CoroutineArg, InfoArg };
115
116public:
117  AllocaInst *getPromise() const {
118    Value *Arg = getArgOperand(PromiseArg);
119    return isa<ConstantPointerNull>(Arg)
120               ? nullptr
121               : cast<AllocaInst>(Arg->stripPointerCasts());
122  }
123
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
158    bool hasOutlinedParts() const { return OutlinedParts != nullptr; }
159    bool isPostSplit() const { return Resumers != nullptr; }
160    bool isPreSplit() const { return !isPostSplit(); }
161  };
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  }
176  Constant *getRawInfo() const {
177    return cast<Constant>(getArgOperand(InfoArg)->stripPointerCasts());
178  }
179
180  void setInfo(Constant *C) { setArgOperand(InfoArg, C); }
181
182  Function *getCoroutine() const {
183    return cast<Function>(getArgOperand(CoroutineArg)->stripPointerCasts());
184  }
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:
194  static bool classof(const IntrinsicInst *I) {
195    return I->getIntrinsicID() == Intrinsic::coro_id;
196  }
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.
204class LLVM_LIBRARY_VISIBILITY AnyCoroIdRetconInst : public AnyCoroIdInst {
205  enum { SizeArg, AlignArg, StorageArg, PrototypeArg, AllocArg, DeallocArg };
206
207public:
208  void checkWellFormed() const;
209
210  uint64_t getStorageSize() const {
211    return cast<ConstantInt>(getArgOperand(SizeArg))->getZExtValue();
212  }
213
214  uint64_t getStorageAlignment() const {
215    return cast<ConstantInt>(getArgOperand(AlignArg))->getZExtValue();
216  }
217
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.
225  Function *getPrototype() const {
226    return cast<Function>(getArgOperand(PrototypeArg)->stripPointerCasts());
227  }
228
229  /// Return the function to use for allocating memory.
230  Function *getAllocFunction() const {
231    return cast<Function>(getArgOperand(AllocArg)->stripPointerCasts());
232  }
233
234  /// Return the function to use for deallocating memory.
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:
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  }
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.
251class LLVM_LIBRARY_VISIBILITY CoroIdRetconInst
252    : public AnyCoroIdRetconInst {
253public:
254  // Methods to support type inquiry through isa, cast, and dyn_cast:
255  static bool classof(const IntrinsicInst *I) {
256    return I->getIntrinsicID() == Intrinsic::coro_id_retcon;
257  }
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.
264class LLVM_LIBRARY_VISIBILITY CoroIdRetconOnceInst
265    : public AnyCoroIdRetconInst {
266public:
267  // Methods to support type inquiry through isa, cast, and dyn_cast:
268  static bool classof(const IntrinsicInst *I) {
269    return I->getIntrinsicID() == Intrinsic::coro_id_retcon_once;
270  }
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.
277class LLVM_LIBRARY_VISIBILITY CoroFrameInst : public IntrinsicInst {
278public:
279  // Methods to support type inquiry through isa, cast, and dyn_cast:
280  static bool classof(const IntrinsicInst *I) {
281    return I->getIntrinsicID() == Intrinsic::coro_frame;
282  }
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.
289class LLVM_LIBRARY_VISIBILITY CoroFreeInst : public IntrinsicInst {
290  enum { IdArg, FrameArg };
291
292public:
293  Value *getFrame() const { return getArgOperand(FrameArg); }
294
295  // Methods to support type inquiry through isa, cast, and dyn_cast:
296  static bool classof(const IntrinsicInst *I) {
297    return I->getIntrinsicID() == Intrinsic::coro_free;
298  }
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.
305class LLVM_LIBRARY_VISIBILITY CoroBeginInst : public IntrinsicInst {
306  enum { IdArg, MemArg };
307
308public:
309  AnyCoroIdInst *getId() const {
310    return cast<AnyCoroIdInst>(getArgOperand(IdArg));
311  }
312
313  Value *getMem() const { return getArgOperand(MemArg); }
314
315  // Methods for support type inquiry through isa, cast, and dyn_cast:
316  static bool classof(const IntrinsicInst *I) {
317    return I->getIntrinsicID() == Intrinsic::coro_begin;
318  }
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.
325class LLVM_LIBRARY_VISIBILITY CoroSaveInst : public IntrinsicInst {
326public:
327  // Methods to support type inquiry through isa, cast, and dyn_cast:
328  static bool classof(const IntrinsicInst *I) {
329    return I->getIntrinsicID() == Intrinsic::coro_save;
330  }
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.
337class LLVM_LIBRARY_VISIBILITY CoroPromiseInst : public IntrinsicInst {
338  enum { FrameArg, AlignArg, FromArg };
339
340public:
341  bool isFromPromise() const {
342    return cast<Constant>(getArgOperand(FromArg))->isOneValue();
343  }
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:
349  static bool classof(const IntrinsicInst *I) {
350    return I->getIntrinsicID() == Intrinsic::coro_promise;
351  }
352  static bool classof(const Value *V) {
353    return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
354  }
355};
356
357class LLVM_LIBRARY_VISIBILITY AnyCoroSuspendInst : public IntrinsicInst {
358public:
359  CoroSaveInst *getCoroSave() const;
360
361  // Methods to support type inquiry through isa, cast, and dyn_cast:
362  static bool classof(const IntrinsicInst *I) {
363    return I->getIntrinsicID() == Intrinsic::coro_suspend ||
364           I->getIntrinsicID() == Intrinsic::coro_suspend_retcon;
365  }
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.
372class LLVM_LIBRARY_VISIBILITY CoroSuspendInst : public AnyCoroSuspendInst {
373  enum { SaveArg, FinalArg };
374
375public:
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
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:
389  static bool classof(const IntrinsicInst *I) {
390    return I->getIntrinsicID() == Intrinsic::coro_suspend;
391  }
392  static bool classof(const Value *V) {
393    return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
394  }
395};
396
397inline 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.
404class LLVM_LIBRARY_VISIBILITY CoroSuspendRetconInst : public AnyCoroSuspendInst {
405public:
406  op_iterator value_begin() { return arg_begin(); }
407  const_op_iterator value_begin() const { return arg_begin(); }
408
409  op_iterator value_end() { return arg_end(); }
410  const_op_iterator value_end() const { return arg_end(); }
411
412  iterator_range<op_iterator> value_operands() {
413    return make_range(value_begin(), value_end());
414  }
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:
420  static bool classof(const IntrinsicInst *I) {
421    return I->getIntrinsicID() == Intrinsic::coro_suspend_retcon;
422  }
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.
429class LLVM_LIBRARY_VISIBILITY CoroSizeInst : public IntrinsicInst {
430public:
431  // Methods to support type inquiry through isa, cast, and dyn_cast:
432  static bool classof(const IntrinsicInst *I) {
433    return I->getIntrinsicID() == Intrinsic::coro_size;
434  }
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.
441class LLVM_LIBRARY_VISIBILITY CoroEndInst : public IntrinsicInst {
442  enum { FrameArg, UnwindArg };
443
444public:
445  bool isFallthrough() const { return !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:
451  static bool classof(const IntrinsicInst *I) {
452    return I->getIntrinsicID() == Intrinsic::coro_end;
453  }
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.
460class LLVM_LIBRARY_VISIBILITY CoroAllocaAllocInst : public IntrinsicInst {
461  enum { SizeArg, AlignArg };
462public:
463  Value *getSize() const {
464    return getArgOperand(SizeArg);
465  }
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:
471  static bool classof(const IntrinsicInst *I) {
472    return I->getIntrinsicID() == Intrinsic::coro_alloca_alloc;
473  }
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.
480class LLVM_LIBRARY_VISIBILITY CoroAllocaGetInst : public IntrinsicInst {
481  enum { AllocArg };
482public:
483  CoroAllocaAllocInst *getAlloc() const {
484    return cast<CoroAllocaAllocInst>(getArgOperand(AllocArg));
485  }
486
487  // Methods to support type inquiry through isa, cast, and dyn_cast:
488  static bool classof(const IntrinsicInst *I) {
489    return I->getIntrinsicID() == Intrinsic::coro_alloca_get;
490  }
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.
497class LLVM_LIBRARY_VISIBILITY CoroAllocaFreeInst : public IntrinsicInst {
498  enum { AllocArg };
499public:
500  CoroAllocaAllocInst *getAlloc() const {
501    return cast<CoroAllocaAllocInst>(getArgOperand(AllocArg));
502  }
503
504  // Methods to support type inquiry through isa, cast, and dyn_cast:
505  static bool classof(const IntrinsicInst *I) {
506    return I->getIntrinsicID() == Intrinsic::coro_alloca_free;
507  }
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