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"
33 /// This class represents the llvm.coro.subfn.addr instruction.
34 class LLVM_LIBRARY_VISIBILITY CoroSubFnInst
: public IntrinsicInst
{
35 enum { FrameArg
, IndexArg
};
44 IndexFirst
= RestartTrigger
47 Value
*getFrame() const { return getArgOperand(FrameArg
); }
48 ResumeKind
getIndex() const {
49 int64_t Index
= getRawIndex()->getValue().getSExtValue();
50 assert(Index
>= IndexFirst
&& Index
< IndexLast
&&
51 "unexpected CoroSubFnInst index argument");
52 return static_cast<ResumeKind
>(Index
);
55 ConstantInt
*getRawIndex() const {
56 return cast
<ConstantInt
>(getArgOperand(IndexArg
));
59 // Methods to support type inquiry through isa, cast, and dyn_cast:
60 static bool classof(const IntrinsicInst
*I
) {
61 return I
->getIntrinsicID() == Intrinsic::coro_subfn_addr
;
63 static bool classof(const Value
*V
) {
64 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
68 /// This represents the llvm.coro.alloc instruction.
69 class LLVM_LIBRARY_VISIBILITY CoroAllocInst
: public IntrinsicInst
{
71 // Methods to support type inquiry through isa, cast, and dyn_cast:
72 static bool classof(const IntrinsicInst
*I
) {
73 return I
->getIntrinsicID() == Intrinsic::coro_alloc
;
75 static bool classof(const Value
*V
) {
76 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
80 /// This represents the llvm.coro.alloc instruction.
81 class LLVM_LIBRARY_VISIBILITY CoroIdInst
: public IntrinsicInst
{
82 enum { AlignArg
, PromiseArg
, CoroutineArg
, InfoArg
};
85 CoroAllocInst
*getCoroAlloc() {
86 for (User
*U
: users())
87 if (auto *CA
= dyn_cast
<CoroAllocInst
>(U
))
92 IntrinsicInst
*getCoroBegin() {
93 for (User
*U
: users())
94 if (auto *II
= dyn_cast
<IntrinsicInst
>(U
))
95 if (II
->getIntrinsicID() == Intrinsic::coro_begin
)
97 llvm_unreachable("no coro.begin associated with coro.id");
100 AllocaInst
*getPromise() const {
101 Value
*Arg
= getArgOperand(PromiseArg
);
102 return isa
<ConstantPointerNull
>(Arg
)
104 : cast
<AllocaInst
>(Arg
->stripPointerCasts());
107 void clearPromise() {
108 Value
*Arg
= getArgOperand(PromiseArg
);
109 setArgOperand(PromiseArg
,
110 ConstantPointerNull::get(Type::getInt8PtrTy(getContext())));
111 if (isa
<AllocaInst
>(Arg
))
113 assert((isa
<BitCastInst
>(Arg
) || isa
<GetElementPtrInst
>(Arg
)) &&
114 "unexpected instruction designating the promise");
115 // TODO: Add a check that any remaining users of Inst are after coro.begin
116 // or add code to move the users after coro.begin.
117 auto *Inst
= cast
<Instruction
>(Arg
);
118 if (Inst
->use_empty()) {
119 Inst
->eraseFromParent();
122 Inst
->moveBefore(getCoroBegin()->getNextNode());
125 // Info argument of coro.id is
126 // fresh out of the frontend: null ;
127 // outlined : {Init, Return, Susp1, Susp2, ...} ;
128 // postsplit : [resume, destroy, cleanup] ;
130 // If parts of the coroutine were outlined to protect against undesirable
131 // code motion, these functions will be stored in a struct literal referred to
132 // by the Info parameter. Note: this is only needed before coroutine is split.
134 // After coroutine is split, resume functions are stored in an array
135 // referred to by this parameter.
138 ConstantStruct
*OutlinedParts
= nullptr;
139 ConstantArray
*Resumers
= nullptr;
141 bool hasOutlinedParts() const { return OutlinedParts
!= nullptr; }
142 bool isPostSplit() const { return Resumers
!= nullptr; }
143 bool isPreSplit() const { return !isPostSplit(); }
145 Info
getInfo() const {
147 auto *GV
= dyn_cast
<GlobalVariable
>(getRawInfo());
151 assert(GV
->isConstant() && GV
->hasDefinitiveInitializer());
152 Constant
*Initializer
= GV
->getInitializer();
153 if ((Result
.OutlinedParts
= dyn_cast
<ConstantStruct
>(Initializer
)))
156 Result
.Resumers
= cast
<ConstantArray
>(Initializer
);
159 Constant
*getRawInfo() const {
160 return cast
<Constant
>(getArgOperand(InfoArg
)->stripPointerCasts());
163 void setInfo(Constant
*C
) { setArgOperand(InfoArg
, C
); }
165 Function
*getCoroutine() const {
166 return cast
<Function
>(getArgOperand(CoroutineArg
)->stripPointerCasts());
168 void setCoroutineSelf() {
169 assert(isa
<ConstantPointerNull
>(getArgOperand(CoroutineArg
)) &&
170 "Coroutine argument is already assigned");
171 auto *const Int8PtrTy
= Type::getInt8PtrTy(getContext());
172 setArgOperand(CoroutineArg
,
173 ConstantExpr::getBitCast(getFunction(), Int8PtrTy
));
176 // Methods to support type inquiry through isa, cast, and dyn_cast:
177 static bool classof(const IntrinsicInst
*I
) {
178 return I
->getIntrinsicID() == Intrinsic::coro_id
;
180 static bool classof(const Value
*V
) {
181 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
185 /// This represents the llvm.coro.frame instruction.
186 class LLVM_LIBRARY_VISIBILITY CoroFrameInst
: public IntrinsicInst
{
188 // Methods to support type inquiry through isa, cast, and dyn_cast:
189 static bool classof(const IntrinsicInst
*I
) {
190 return I
->getIntrinsicID() == Intrinsic::coro_frame
;
192 static bool classof(const Value
*V
) {
193 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
197 /// This represents the llvm.coro.free instruction.
198 class LLVM_LIBRARY_VISIBILITY CoroFreeInst
: public IntrinsicInst
{
199 enum { IdArg
, FrameArg
};
202 Value
*getFrame() const { return getArgOperand(FrameArg
); }
204 // Methods to support type inquiry through isa, cast, and dyn_cast:
205 static bool classof(const IntrinsicInst
*I
) {
206 return I
->getIntrinsicID() == Intrinsic::coro_free
;
208 static bool classof(const Value
*V
) {
209 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
213 /// This class represents the llvm.coro.begin instruction.
214 class LLVM_LIBRARY_VISIBILITY CoroBeginInst
: public IntrinsicInst
{
215 enum { IdArg
, MemArg
};
218 CoroIdInst
*getId() const { return cast
<CoroIdInst
>(getArgOperand(IdArg
)); }
220 Value
*getMem() const { return getArgOperand(MemArg
); }
222 // Methods for support type inquiry through isa, cast, and dyn_cast:
223 static bool classof(const IntrinsicInst
*I
) {
224 return I
->getIntrinsicID() == Intrinsic::coro_begin
;
226 static bool classof(const Value
*V
) {
227 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
231 /// This represents the llvm.coro.save instruction.
232 class LLVM_LIBRARY_VISIBILITY CoroSaveInst
: public IntrinsicInst
{
234 // Methods to support type inquiry through isa, cast, and dyn_cast:
235 static bool classof(const IntrinsicInst
*I
) {
236 return I
->getIntrinsicID() == Intrinsic::coro_save
;
238 static bool classof(const Value
*V
) {
239 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
243 /// This represents the llvm.coro.promise instruction.
244 class LLVM_LIBRARY_VISIBILITY CoroPromiseInst
: public IntrinsicInst
{
245 enum { FrameArg
, AlignArg
, FromArg
};
248 bool isFromPromise() const {
249 return cast
<Constant
>(getArgOperand(FromArg
))->isOneValue();
251 unsigned getAlignment() const {
252 return cast
<ConstantInt
>(getArgOperand(AlignArg
))->getZExtValue();
255 // Methods to support type inquiry through isa, cast, and dyn_cast:
256 static bool classof(const IntrinsicInst
*I
) {
257 return I
->getIntrinsicID() == Intrinsic::coro_promise
;
259 static bool classof(const Value
*V
) {
260 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
264 /// This represents the llvm.coro.suspend instruction.
265 class LLVM_LIBRARY_VISIBILITY CoroSuspendInst
: public IntrinsicInst
{
266 enum { SaveArg
, FinalArg
};
269 CoroSaveInst
*getCoroSave() const {
270 Value
*Arg
= getArgOperand(SaveArg
);
271 if (auto *SI
= dyn_cast
<CoroSaveInst
>(Arg
))
273 assert(isa
<ConstantTokenNone
>(Arg
));
276 bool isFinal() const {
277 return cast
<Constant
>(getArgOperand(FinalArg
))->isOneValue();
280 // Methods to support type inquiry through isa, cast, and dyn_cast:
281 static bool classof(const IntrinsicInst
*I
) {
282 return I
->getIntrinsicID() == Intrinsic::coro_suspend
;
284 static bool classof(const Value
*V
) {
285 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
289 /// This represents the llvm.coro.size instruction.
290 class LLVM_LIBRARY_VISIBILITY CoroSizeInst
: public IntrinsicInst
{
292 // Methods to support type inquiry through isa, cast, and dyn_cast:
293 static bool classof(const IntrinsicInst
*I
) {
294 return I
->getIntrinsicID() == Intrinsic::coro_size
;
296 static bool classof(const Value
*V
) {
297 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
301 /// This represents the llvm.coro.end instruction.
302 class LLVM_LIBRARY_VISIBILITY CoroEndInst
: public IntrinsicInst
{
303 enum { FrameArg
, UnwindArg
};
306 bool isFallthrough() const { return !isUnwind(); }
307 bool isUnwind() const {
308 return cast
<Constant
>(getArgOperand(UnwindArg
))->isOneValue();
311 // Methods to support type inquiry through isa, cast, and dyn_cast:
312 static bool classof(const IntrinsicInst
*I
) {
313 return I
->getIntrinsicID() == Intrinsic::coro_end
;
315 static bool classof(const Value
*V
) {
316 return isa
<IntrinsicInst
>(V
) && classof(cast
<IntrinsicInst
>(V
));
320 } // End namespace llvm.