1 //===-- CoroInstr.h - Coroutine Intrinsics Instruction Wrappers -*- C++ -*-===//
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
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:
12 // if (auto *SF = dyn_cast<CoroSubFnInst>(Inst))
13 // ... SF->getFrame() ...
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
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 //===----------------------------------------------------------------------===//
25 #ifndef LLVM_LIB_TRANSFORMS_COROUTINES_COROINSTR_H
26 #define LLVM_LIB_TRANSFORMS_COROUTINES_COROINSTR_H
28 #include "llvm/IR/GlobalVariable.h"
29 #include "llvm/IR/IntrinsicInst.h"
30 #include "llvm/Support/raw_ostream.h"
34 /// This class represents the llvm.coro.subfn.addr instruction.
35 class LLVM_LIBRARY_VISIBILITY CoroSubFnInst
: public IntrinsicInst
{
36 enum { FrameArg
, IndexArg
};
45 IndexFirst
= RestartTrigger
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
);
56 ConstantInt
*getRawIndex() const {
57 return cast
<ConstantInt
>(getArgOperand(IndexArg
));
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
;
64 static bool classof(const Value
*V
) {
65 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
69 /// This represents the llvm.coro.alloc instruction.
70 class LLVM_LIBRARY_VISIBILITY CoroAllocInst
: public IntrinsicInst
{
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
;
76 static bool classof(const Value
*V
) {
77 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
81 /// This represents a common base class for llvm.coro.id instructions.
82 class LLVM_LIBRARY_VISIBILITY AnyCoroIdInst
: public IntrinsicInst
{
84 CoroAllocInst
*getCoroAlloc() {
85 for (User
*U
: users())
86 if (auto *CA
= dyn_cast
<CoroAllocInst
>(U
))
91 IntrinsicInst
*getCoroBegin() {
92 for (User
*U
: users())
93 if (auto *II
= dyn_cast
<IntrinsicInst
>(U
))
94 if (II
->getIntrinsicID() == Intrinsic::coro_begin
)
96 llvm_unreachable("no coro.begin associated with coro.id");
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
;
107 static bool classof(const Value
*V
) {
108 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
112 /// This represents the llvm.coro.id instruction.
113 class LLVM_LIBRARY_VISIBILITY CoroIdInst
: public AnyCoroIdInst
{
114 enum { AlignArg
, PromiseArg
, CoroutineArg
, InfoArg
};
117 AllocaInst
*getPromise() const {
118 Value
*Arg
= getArgOperand(PromiseArg
);
119 return isa
<ConstantPointerNull
>(Arg
)
121 : cast
<AllocaInst
>(Arg
->stripPointerCasts());
124 void clearPromise() {
125 Value
*Arg
= getArgOperand(PromiseArg
);
126 setArgOperand(PromiseArg
,
127 ConstantPointerNull::get(Type::getInt8PtrTy(getContext())));
128 if (isa
<AllocaInst
>(Arg
))
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();
139 Inst
->moveBefore(getCoroBegin()->getNextNode());
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] ;
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.
151 // After coroutine is split, resume functions are stored in an array
152 // referred to by this parameter.
155 ConstantStruct
*OutlinedParts
= nullptr;
156 ConstantArray
*Resumers
= nullptr;
158 bool hasOutlinedParts() const { return OutlinedParts
!= nullptr; }
159 bool isPostSplit() const { return Resumers
!= nullptr; }
160 bool isPreSplit() const { return !isPostSplit(); }
162 Info
getInfo() const {
164 auto *GV
= dyn_cast
<GlobalVariable
>(getRawInfo());
168 assert(GV
->isConstant() && GV
->hasDefinitiveInitializer());
169 Constant
*Initializer
= GV
->getInitializer();
170 if ((Result
.OutlinedParts
= dyn_cast
<ConstantStruct
>(Initializer
)))
173 Result
.Resumers
= cast
<ConstantArray
>(Initializer
);
176 Constant
*getRawInfo() const {
177 return cast
<Constant
>(getArgOperand(InfoArg
)->stripPointerCasts());
180 void setInfo(Constant
*C
) { setArgOperand(InfoArg
, C
); }
182 Function
*getCoroutine() const {
183 return cast
<Function
>(getArgOperand(CoroutineArg
)->stripPointerCasts());
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
));
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
;
197 static bool classof(const Value
*V
) {
198 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
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
};
208 void checkWellFormed() const;
210 uint64_t getStorageSize() const {
211 return cast
<ConstantInt
>(getArgOperand(SizeArg
))->getZExtValue();
214 uint64_t getStorageAlignment() const {
215 return cast
<ConstantInt
>(getArgOperand(AlignArg
))->getZExtValue();
218 Value
*getStorage() const {
219 return getArgOperand(StorageArg
);
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());
229 /// Return the function to use for allocating memory.
230 Function
*getAllocFunction() const {
231 return cast
<Function
>(getArgOperand(AllocArg
)->stripPointerCasts());
234 /// Return the function to use for deallocating memory.
235 Function
*getDeallocFunction() const {
236 return cast
<Function
>(getArgOperand(DeallocArg
)->stripPointerCasts());
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
;
245 static bool classof(const Value
*V
) {
246 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
250 /// This represents the llvm.coro.id.retcon instruction.
251 class LLVM_LIBRARY_VISIBILITY CoroIdRetconInst
252 : public AnyCoroIdRetconInst
{
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
;
258 static bool classof(const Value
*V
) {
259 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
263 /// This represents the llvm.coro.id.retcon.once instruction.
264 class LLVM_LIBRARY_VISIBILITY CoroIdRetconOnceInst
265 : public AnyCoroIdRetconInst
{
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
;
271 static bool classof(const Value
*V
) {
272 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
276 /// This represents the llvm.coro.frame instruction.
277 class LLVM_LIBRARY_VISIBILITY CoroFrameInst
: public IntrinsicInst
{
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
;
283 static bool classof(const Value
*V
) {
284 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
288 /// This represents the llvm.coro.free instruction.
289 class LLVM_LIBRARY_VISIBILITY CoroFreeInst
: public IntrinsicInst
{
290 enum { IdArg
, FrameArg
};
293 Value
*getFrame() const { return getArgOperand(FrameArg
); }
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
;
299 static bool classof(const Value
*V
) {
300 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
304 /// This class represents the llvm.coro.begin instruction.
305 class LLVM_LIBRARY_VISIBILITY CoroBeginInst
: public IntrinsicInst
{
306 enum { IdArg
, MemArg
};
309 AnyCoroIdInst
*getId() const {
310 return cast
<AnyCoroIdInst
>(getArgOperand(IdArg
));
313 Value
*getMem() const { return getArgOperand(MemArg
); }
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
;
319 static bool classof(const Value
*V
) {
320 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
324 /// This represents the llvm.coro.save instruction.
325 class LLVM_LIBRARY_VISIBILITY CoroSaveInst
: public IntrinsicInst
{
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
;
331 static bool classof(const Value
*V
) {
332 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
336 /// This represents the llvm.coro.promise instruction.
337 class LLVM_LIBRARY_VISIBILITY CoroPromiseInst
: public IntrinsicInst
{
338 enum { FrameArg
, AlignArg
, FromArg
};
341 bool isFromPromise() const {
342 return cast
<Constant
>(getArgOperand(FromArg
))->isOneValue();
344 unsigned getAlignment() const {
345 return cast
<ConstantInt
>(getArgOperand(AlignArg
))->getZExtValue();
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
;
352 static bool classof(const Value
*V
) {
353 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
357 class LLVM_LIBRARY_VISIBILITY AnyCoroSuspendInst
: public IntrinsicInst
{
359 CoroSaveInst
*getCoroSave() const;
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
;
366 static bool classof(const Value
*V
) {
367 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
371 /// This represents the llvm.coro.suspend instruction.
372 class LLVM_LIBRARY_VISIBILITY CoroSuspendInst
: public AnyCoroSuspendInst
{
373 enum { SaveArg
, FinalArg
};
376 CoroSaveInst
*getCoroSave() const {
377 Value
*Arg
= getArgOperand(SaveArg
);
378 if (auto *SI
= dyn_cast
<CoroSaveInst
>(Arg
))
380 assert(isa
<ConstantTokenNone
>(Arg
));
384 bool isFinal() const {
385 return cast
<Constant
>(getArgOperand(FinalArg
))->isOneValue();
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
;
392 static bool classof(const Value
*V
) {
393 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
397 inline CoroSaveInst
*AnyCoroSuspendInst::getCoroSave() const {
398 if (auto Suspend
= dyn_cast
<CoroSuspendInst
>(this))
399 return Suspend
->getCoroSave();
403 /// This represents the llvm.coro.suspend.retcon instruction.
404 class LLVM_LIBRARY_VISIBILITY CoroSuspendRetconInst
: public AnyCoroSuspendInst
{
406 op_iterator
value_begin() { return arg_begin(); }
407 const_op_iterator
value_begin() const { return arg_begin(); }
409 op_iterator
value_end() { return arg_end(); }
410 const_op_iterator
value_end() const { return arg_end(); }
412 iterator_range
<op_iterator
> value_operands() {
413 return make_range(value_begin(), value_end());
415 iterator_range
<const_op_iterator
> value_operands() const {
416 return make_range(value_begin(), value_end());
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
;
423 static bool classof(const Value
*V
) {
424 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
428 /// This represents the llvm.coro.size instruction.
429 class LLVM_LIBRARY_VISIBILITY CoroSizeInst
: public IntrinsicInst
{
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
;
435 static bool classof(const Value
*V
) {
436 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
440 /// This represents the llvm.coro.end instruction.
441 class LLVM_LIBRARY_VISIBILITY CoroEndInst
: public IntrinsicInst
{
442 enum { FrameArg
, UnwindArg
};
445 bool isFallthrough() const { return !isUnwind(); }
446 bool isUnwind() const {
447 return cast
<Constant
>(getArgOperand(UnwindArg
))->isOneValue();
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
;
454 static bool classof(const Value
*V
) {
455 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
459 /// This represents the llvm.coro.alloca.alloc instruction.
460 class LLVM_LIBRARY_VISIBILITY CoroAllocaAllocInst
: public IntrinsicInst
{
461 enum { SizeArg
, AlignArg
};
463 Value
*getSize() const {
464 return getArgOperand(SizeArg
);
466 unsigned getAlignment() const {
467 return cast
<ConstantInt
>(getArgOperand(AlignArg
))->getZExtValue();
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
;
474 static bool classof(const Value
*V
) {
475 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
479 /// This represents the llvm.coro.alloca.get instruction.
480 class LLVM_LIBRARY_VISIBILITY CoroAllocaGetInst
: public IntrinsicInst
{
483 CoroAllocaAllocInst
*getAlloc() const {
484 return cast
<CoroAllocaAllocInst
>(getArgOperand(AllocArg
));
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
;
491 static bool classof(const Value
*V
) {
492 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
496 /// This represents the llvm.coro.alloca.free instruction.
497 class LLVM_LIBRARY_VISIBILITY CoroAllocaFreeInst
: public IntrinsicInst
{
500 CoroAllocaAllocInst
*getAlloc() const {
501 return cast
<CoroAllocaAllocInst
>(getArgOperand(AllocArg
));
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
;
508 static bool classof(const Value
*V
) {
509 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
513 } // End namespace llvm.