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  Align getStorageAlignment() const {
215    return cast<ConstantInt>(getArgOperand(AlignArg))->getAlignValue();
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  /// Are we translating from the frame to the promise (false) or from
342  /// the promise to the frame (true)?
343  bool isFromPromise() const {
344    return cast<Constant>(getArgOperand(FromArg))->isOneValue();
345  }
346
347  /// The required alignment of the promise.  This must match the
348  /// alignment of the promise alloca in the coroutine.
349  Align getAlignment() const {
350    return cast<ConstantInt>(getArgOperand(AlignArg))->getAlignValue();
351  }
352
353  // Methods to support type inquiry through isa, cast, and dyn_cast:
354  static bool classof(const IntrinsicInst *I) {
355    return I->getIntrinsicID() == Intrinsic::coro_promise;
356  }
357  static bool classof(const Value *V) {
358    return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
359  }
360};
361
362class LLVM_LIBRARY_VISIBILITY AnyCoroSuspendInst : public IntrinsicInst {
363public:
364  CoroSaveInst *getCoroSave() const;
365
366  // Methods to support type inquiry through isa, cast, and dyn_cast:
367  static bool classof(const IntrinsicInst *I) {
368    return I->getIntrinsicID() == Intrinsic::coro_suspend ||
369           I->getIntrinsicID() == Intrinsic::coro_suspend_retcon;
370  }
371  static bool classof(const Value *V) {
372    return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
373  }
374};
375
376/// This represents the llvm.coro.suspend instruction.
377class LLVM_LIBRARY_VISIBILITY CoroSuspendInst : public AnyCoroSuspendInst {
378  enum { SaveArg, FinalArg };
379
380public:
381  CoroSaveInst *getCoroSave() const {
382    Value *Arg = getArgOperand(SaveArg);
383    if (auto *SI = dyn_cast<CoroSaveInst>(Arg))
384      return SI;
385    assert(isa<ConstantTokenNone>(Arg));
386    return nullptr;
387  }
388
389  bool isFinal() const {
390    return cast<Constant>(getArgOperand(FinalArg))->isOneValue();
391  }
392
393  // Methods to support type inquiry through isa, cast, and dyn_cast:
394  static bool classof(const IntrinsicInst *I) {
395    return I->getIntrinsicID() == Intrinsic::coro_suspend;
396  }
397  static bool classof(const Value *V) {
398    return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
399  }
400};
401
402inline CoroSaveInst *AnyCoroSuspendInst::getCoroSave() const {
403  if (auto Suspend = dyn_cast<CoroSuspendInst>(this))
404    return Suspend->getCoroSave();
405  return nullptr;
406}
407
408/// This represents the llvm.coro.suspend.retcon instruction.
409class LLVM_LIBRARY_VISIBILITY CoroSuspendRetconInst : public AnyCoroSuspendInst {
410public:
411  op_iterator value_begin() { return arg_begin(); }
412  const_op_iterator value_begin() const { return arg_begin(); }
413
414  op_iterator value_end() { return arg_end(); }
415  const_op_iterator value_end() const { return arg_end(); }
416
417  iterator_range<op_iterator> value_operands() {
418    return make_range(value_begin(), value_end());
419  }
420  iterator_range<const_op_iterator> value_operands() const {
421    return make_range(value_begin(), value_end());
422  }
423
424  // Methods to support type inquiry through isa, cast, and dyn_cast:
425  static bool classof(const IntrinsicInst *I) {
426    return I->getIntrinsicID() == Intrinsic::coro_suspend_retcon;
427  }
428  static bool classof(const Value *V) {
429    return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
430  }
431};
432
433/// This represents the llvm.coro.size instruction.
434class LLVM_LIBRARY_VISIBILITY CoroSizeInst : public IntrinsicInst {
435public:
436  // Methods to support type inquiry through isa, cast, and dyn_cast:
437  static bool classof(const IntrinsicInst *I) {
438    return I->getIntrinsicID() == Intrinsic::coro_size;
439  }
440  static bool classof(const Value *V) {
441    return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
442  }
443};
444
445/// This represents the llvm.coro.end instruction.
446class LLVM_LIBRARY_VISIBILITY CoroEndInst : public IntrinsicInst {
447  enum { FrameArg, UnwindArg };
448
449public:
450  bool isFallthrough() const { return !isUnwind(); }
451  bool isUnwind() const {
452    return cast<Constant>(getArgOperand(UnwindArg))->isOneValue();
453  }
454
455  // Methods to support type inquiry through isa, cast, and dyn_cast:
456  static bool classof(const IntrinsicInst *I) {
457    return I->getIntrinsicID() == Intrinsic::coro_end;
458  }
459  static bool classof(const Value *V) {
460    return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
461  }
462};
463
464/// This represents the llvm.coro.alloca.alloc instruction.
465class LLVM_LIBRARY_VISIBILITY CoroAllocaAllocInst : public IntrinsicInst {
466  enum { SizeArg, AlignArg };
467public:
468  Value *getSize() const {
469    return getArgOperand(SizeArg);
470  }
471  Align getAlignment() const {
472    return cast<ConstantInt>(getArgOperand(AlignArg))->getAlignValue();
473  }
474
475  // Methods to support type inquiry through isa, cast, and dyn_cast:
476  static bool classof(const IntrinsicInst *I) {
477    return I->getIntrinsicID() == Intrinsic::coro_alloca_alloc;
478  }
479  static bool classof(const Value *V) {
480    return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
481  }
482};
483
484/// This represents the llvm.coro.alloca.get instruction.
485class LLVM_LIBRARY_VISIBILITY CoroAllocaGetInst : public IntrinsicInst {
486  enum { AllocArg };
487public:
488  CoroAllocaAllocInst *getAlloc() const {
489    return cast<CoroAllocaAllocInst>(getArgOperand(AllocArg));
490  }
491
492  // Methods to support type inquiry through isa, cast, and dyn_cast:
493  static bool classof(const IntrinsicInst *I) {
494    return I->getIntrinsicID() == Intrinsic::coro_alloca_get;
495  }
496  static bool classof(const Value *V) {
497    return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
498  }
499};
500
501/// This represents the llvm.coro.alloca.free instruction.
502class LLVM_LIBRARY_VISIBILITY CoroAllocaFreeInst : public IntrinsicInst {
503  enum { AllocArg };
504public:
505  CoroAllocaAllocInst *getAlloc() const {
506    return cast<CoroAllocaAllocInst>(getArgOperand(AllocArg));
507  }
508
509  // Methods to support type inquiry through isa, cast, and dyn_cast:
510  static bool classof(const IntrinsicInst *I) {
511    return I->getIntrinsicID() == Intrinsic::coro_alloca_free;
512  }
513  static bool classof(const Value *V) {
514    return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
515  }
516};
517
518} // End namespace llvm.
519
520#endif
521