/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Transforms/Coroutines/CoroInstr.h
Line | Count | Source (jump to first uncovered line) |
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 | | |
31 | | namespace llvm { |
32 | | |
33 | | /// This class represents the llvm.coro.subfn.addr instruction. |
34 | | class LLVM_LIBRARY_VISIBILITY CoroSubFnInst : public IntrinsicInst { |
35 | | enum { FrameArg, IndexArg }; |
36 | | |
37 | | public: |
38 | | enum ResumeKind { |
39 | | RestartTrigger = -1, |
40 | | ResumeIndex, |
41 | | DestroyIndex, |
42 | | CleanupIndex, |
43 | | IndexLast, |
44 | | IndexFirst = RestartTrigger |
45 | | }; |
46 | | |
47 | 12 | Value *getFrame() const { return getArgOperand(FrameArg); } |
48 | 43 | ResumeKind getIndex() const { |
49 | 43 | int64_t Index = getRawIndex()->getValue().getSExtValue(); |
50 | 43 | assert(Index >= IndexFirst && Index < IndexLast && |
51 | 43 | "unexpected CoroSubFnInst index argument"); |
52 | 43 | return static_cast<ResumeKind>(Index); |
53 | 43 | } |
54 | | |
55 | 46 | ConstantInt *getRawIndex() const { |
56 | 46 | return cast<ConstantInt>(getArgOperand(IndexArg)); |
57 | 46 | } |
58 | | |
59 | | // Methods to support type inquiry through isa, cast, and dyn_cast: |
60 | 125 | static bool classof(const IntrinsicInst *I) { |
61 | 125 | return I->getIntrinsicID() == Intrinsic::coro_subfn_addr; |
62 | 125 | } |
63 | 548 | static bool classof(const Value *V) { |
64 | 548 | return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V))125 ; |
65 | 548 | } |
66 | | }; |
67 | | |
68 | | /// This represents the llvm.coro.alloc instruction. |
69 | | class LLVM_LIBRARY_VISIBILITY CoroAllocInst : public IntrinsicInst { |
70 | | public: |
71 | | // Methods to support type inquiry through isa, cast, and dyn_cast: |
72 | 64 | static bool classof(const IntrinsicInst *I) { |
73 | 64 | return I->getIntrinsicID() == Intrinsic::coro_alloc; |
74 | 64 | } |
75 | 64 | static bool classof(const Value *V) { |
76 | 64 | return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); |
77 | 64 | } |
78 | | }; |
79 | | |
80 | | /// This represents the llvm.coro.alloc instruction. |
81 | | class LLVM_LIBRARY_VISIBILITY CoroIdInst : public IntrinsicInst { |
82 | | enum { AlignArg, PromiseArg, CoroutineArg, InfoArg }; |
83 | | |
84 | | public: |
85 | 37 | CoroAllocInst *getCoroAlloc() { |
86 | 37 | for (User *U : users()) |
87 | 56 | if (auto *CA = dyn_cast<CoroAllocInst>(U)) |
88 | 14 | return CA; |
89 | 37 | return nullptr23 ; |
90 | 37 | } |
91 | | |
92 | 0 | IntrinsicInst *getCoroBegin() { |
93 | 0 | for (User *U : users()) |
94 | 0 | if (auto *II = dyn_cast<IntrinsicInst>(U)) |
95 | 0 | if (II->getIntrinsicID() == Intrinsic::coro_begin) |
96 | 0 | return II; |
97 | 0 | llvm_unreachable("no coro.begin associated with coro.id"); |
98 | 0 | } |
99 | | |
100 | 37 | AllocaInst *getPromise() const { |
101 | 37 | Value *Arg = getArgOperand(PromiseArg); |
102 | 37 | return isa<ConstantPointerNull>(Arg) |
103 | 37 | ? nullptr35 |
104 | 37 | : cast<AllocaInst>(Arg->stripPointerCasts())2 ; |
105 | 37 | } |
106 | | |
107 | 2 | void clearPromise() { |
108 | 2 | Value *Arg = getArgOperand(PromiseArg); |
109 | 2 | setArgOperand(PromiseArg, |
110 | 2 | ConstantPointerNull::get(Type::getInt8PtrTy(getContext()))); |
111 | 2 | if (isa<AllocaInst>(Arg)) |
112 | 0 | return; |
113 | 2 | assert((isa<BitCastInst>(Arg) || isa<GetElementPtrInst>(Arg)) && |
114 | 2 | "unexpected instruction designating the promise"); |
115 | 2 | // TODO: Add a check that any remaining users of Inst are after coro.begin |
116 | 2 | // or add code to move the users after coro.begin. |
117 | 2 | auto *Inst = cast<Instruction>(Arg); |
118 | 2 | if (Inst->use_empty()) { |
119 | 2 | Inst->eraseFromParent(); |
120 | 2 | return; |
121 | 2 | } |
122 | 0 | Inst->moveBefore(getCoroBegin()->getNextNode()); |
123 | 0 | } |
124 | | |
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] ; |
129 | | // |
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. |
133 | | // |
134 | | // After coroutine is split, resume functions are stored in an array |
135 | | // referred to by this parameter. |
136 | | |
137 | | struct Info { |
138 | | ConstantStruct *OutlinedParts = nullptr; |
139 | | ConstantArray *Resumers = nullptr; |
140 | | |
141 | 0 | bool hasOutlinedParts() const { return OutlinedParts != nullptr; } |
142 | 95 | bool isPostSplit() const { return Resumers != nullptr; } |
143 | 48 | bool isPreSplit() const { return !isPostSplit(); } |
144 | | }; |
145 | 118 | Info getInfo() const { |
146 | 118 | Info Result; |
147 | 118 | auto *GV = dyn_cast<GlobalVariable>(getRawInfo()); |
148 | 118 | if (!GV) |
149 | 58 | return Result; |
150 | 60 | |
151 | 60 | assert(GV->isConstant() && GV->hasDefinitiveInitializer()); |
152 | 60 | Constant *Initializer = GV->getInitializer(); |
153 | 60 | if ((Result.OutlinedParts = dyn_cast<ConstantStruct>(Initializer))) |
154 | 0 | return Result; |
155 | 60 | |
156 | 60 | Result.Resumers = cast<ConstantArray>(Initializer); |
157 | 60 | return Result; |
158 | 60 | } |
159 | 118 | Constant *getRawInfo() const { |
160 | 118 | return cast<Constant>(getArgOperand(InfoArg)->stripPointerCasts()); |
161 | 118 | } |
162 | | |
163 | 33 | void setInfo(Constant *C) { setArgOperand(InfoArg, C); } |
164 | | |
165 | 36 | Function *getCoroutine() const { |
166 | 36 | return cast<Function>(getArgOperand(CoroutineArg)->stripPointerCasts()); |
167 | 36 | } |
168 | 10 | void setCoroutineSelf() { |
169 | 10 | assert(isa<ConstantPointerNull>(getArgOperand(CoroutineArg)) && |
170 | 10 | "Coroutine argument is already assigned"); |
171 | 10 | auto *const Int8PtrTy = Type::getInt8PtrTy(getContext()); |
172 | 10 | setArgOperand(CoroutineArg, |
173 | 10 | ConstantExpr::getBitCast(getFunction(), Int8PtrTy)); |
174 | 10 | } |
175 | | |
176 | | // Methods to support type inquiry through isa, cast, and dyn_cast: |
177 | 496 | static bool classof(const IntrinsicInst *I) { |
178 | 496 | return I->getIntrinsicID() == Intrinsic::coro_id; |
179 | 496 | } |
180 | 2.80k | static bool classof(const Value *V) { |
181 | 2.80k | return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V))496 ; |
182 | 2.80k | } |
183 | | }; |
184 | | |
185 | | /// This represents the llvm.coro.frame instruction. |
186 | | class LLVM_LIBRARY_VISIBILITY CoroFrameInst : public IntrinsicInst { |
187 | | public: |
188 | | // Methods to support type inquiry through isa, cast, and dyn_cast: |
189 | 0 | static bool classof(const IntrinsicInst *I) { |
190 | 0 | return I->getIntrinsicID() == Intrinsic::coro_frame; |
191 | 0 | } |
192 | 0 | static bool classof(const Value *V) { |
193 | 0 | return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); |
194 | 0 | } |
195 | | }; |
196 | | |
197 | | /// This represents the llvm.coro.free instruction. |
198 | | class LLVM_LIBRARY_VISIBILITY CoroFreeInst : public IntrinsicInst { |
199 | | enum { IdArg, FrameArg }; |
200 | | |
201 | | public: |
202 | 56 | Value *getFrame() const { return getArgOperand(FrameArg); } |
203 | | |
204 | | // Methods to support type inquiry through isa, cast, and dyn_cast: |
205 | 228 | static bool classof(const IntrinsicInst *I) { |
206 | 228 | return I->getIntrinsicID() == Intrinsic::coro_free; |
207 | 228 | } |
208 | 228 | static bool classof(const Value *V) { |
209 | 228 | return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); |
210 | 228 | } |
211 | | }; |
212 | | |
213 | | /// This class represents the llvm.coro.begin instruction. |
214 | | class LLVM_LIBRARY_VISIBILITY CoroBeginInst : public IntrinsicInst { |
215 | | enum { IdArg, MemArg }; |
216 | | |
217 | | public: |
218 | 246 | CoroIdInst *getId() const { return cast<CoroIdInst>(getArgOperand(IdArg)); } |
219 | | |
220 | 0 | Value *getMem() const { return getArgOperand(MemArg); } |
221 | | |
222 | | // Methods for support type inquiry through isa, cast, and dyn_cast: |
223 | 58 | static bool classof(const IntrinsicInst *I) { |
224 | 58 | return I->getIntrinsicID() == Intrinsic::coro_begin; |
225 | 58 | } |
226 | 58 | static bool classof(const Value *V) { |
227 | 58 | return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); |
228 | 58 | } |
229 | | }; |
230 | | |
231 | | /// This represents the llvm.coro.save instruction. |
232 | | class LLVM_LIBRARY_VISIBILITY CoroSaveInst : public IntrinsicInst { |
233 | | public: |
234 | | // Methods to support type inquiry through isa, cast, and dyn_cast: |
235 | 390 | static bool classof(const IntrinsicInst *I) { |
236 | 390 | return I->getIntrinsicID() == Intrinsic::coro_save; |
237 | 390 | } |
238 | 1.29k | static bool classof(const Value *V) { |
239 | 1.29k | return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V))390 ; |
240 | 1.29k | } |
241 | | }; |
242 | | |
243 | | /// This represents the llvm.coro.promise instruction. |
244 | | class LLVM_LIBRARY_VISIBILITY CoroPromiseInst : public IntrinsicInst { |
245 | | enum { FrameArg, AlignArg, FromArg }; |
246 | | |
247 | | public: |
248 | 1 | bool isFromPromise() const { |
249 | 1 | return cast<Constant>(getArgOperand(FromArg))->isOneValue(); |
250 | 1 | } |
251 | 1 | unsigned getAlignment() const { |
252 | 1 | return cast<ConstantInt>(getArgOperand(AlignArg))->getZExtValue(); |
253 | 1 | } |
254 | | |
255 | | // Methods to support type inquiry through isa, cast, and dyn_cast: |
256 | 0 | static bool classof(const IntrinsicInst *I) { |
257 | 0 | return I->getIntrinsicID() == Intrinsic::coro_promise; |
258 | 0 | } |
259 | 0 | static bool classof(const Value *V) { |
260 | 0 | return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); |
261 | 0 | } |
262 | | }; |
263 | | |
264 | | /// This represents the llvm.coro.suspend instruction. |
265 | | class LLVM_LIBRARY_VISIBILITY CoroSuspendInst : public IntrinsicInst { |
266 | | enum { SaveArg, FinalArg }; |
267 | | |
268 | | public: |
269 | 164 | CoroSaveInst *getCoroSave() const { |
270 | 164 | Value *Arg = getArgOperand(SaveArg); |
271 | 164 | if (auto *SI = dyn_cast<CoroSaveInst>(Arg)) |
272 | 135 | return SI; |
273 | 29 | assert(isa<ConstantTokenNone>(Arg)); |
274 | 29 | return nullptr; |
275 | 29 | } |
276 | 95 | bool isFinal() const { |
277 | 95 | return cast<Constant>(getArgOperand(FinalArg))->isOneValue(); |
278 | 95 | } |
279 | | |
280 | | // Methods to support type inquiry through isa, cast, and dyn_cast: |
281 | 216 | static bool classof(const IntrinsicInst *I) { |
282 | 216 | return I->getIntrinsicID() == Intrinsic::coro_suspend; |
283 | 216 | } |
284 | 1.09k | static bool classof(const Value *V) { |
285 | 1.09k | return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V))216 ; |
286 | 1.09k | } |
287 | | }; |
288 | | |
289 | | /// This represents the llvm.coro.size instruction. |
290 | | class LLVM_LIBRARY_VISIBILITY CoroSizeInst : public IntrinsicInst { |
291 | | public: |
292 | | // Methods to support type inquiry through isa, cast, and dyn_cast: |
293 | 0 | static bool classof(const IntrinsicInst *I) { |
294 | 0 | return I->getIntrinsicID() == Intrinsic::coro_size; |
295 | 0 | } |
296 | 0 | static bool classof(const Value *V) { |
297 | 0 | return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); |
298 | 0 | } |
299 | | }; |
300 | | |
301 | | /// This represents the llvm.coro.end instruction. |
302 | | class LLVM_LIBRARY_VISIBILITY CoroEndInst : public IntrinsicInst { |
303 | | enum { FrameArg, UnwindArg }; |
304 | | |
305 | | public: |
306 | 49 | bool isFallthrough() const { return !isUnwind(); } |
307 | 154 | bool isUnwind() const { |
308 | 154 | return cast<Constant>(getArgOperand(UnwindArg))->isOneValue(); |
309 | 154 | } |
310 | | |
311 | | // Methods to support type inquiry through isa, cast, and dyn_cast: |
312 | 0 | static bool classof(const IntrinsicInst *I) { |
313 | 0 | return I->getIntrinsicID() == Intrinsic::coro_end; |
314 | 0 | } |
315 | 0 | static bool classof(const Value *V) { |
316 | 0 | return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); |
317 | 0 | } |
318 | | }; |
319 | | |
320 | | } // End namespace llvm. |
321 | | |
322 | | #endif |