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 | |
32 | namespace llvm { |
33 | |
34 | /// This class represents the llvm.coro.subfn.addr instruction. |
35 | class LLVM_LIBRARY_VISIBILITY CoroSubFnInst : public IntrinsicInst { |
36 | enum { FrameArg, IndexArg }; |
37 | |
38 | public: |
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(i: 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>(Val: getArgOperand(i: 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>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
66 | } |
67 | }; |
68 | |
69 | /// This represents the llvm.coro.alloc instruction. |
70 | class LLVM_LIBRARY_VISIBILITY CoroAllocInst : public IntrinsicInst { |
71 | public: |
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>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
78 | } |
79 | }; |
80 | |
81 | /// This represents the llvm.coro.await.suspend.{void,bool,handle} instructions. |
82 | // FIXME: add callback metadata |
83 | // FIXME: make a proper IntrinisicInst. Currently this is not possible, |
84 | // because llvm.coro.await.suspend.* can be invoked. |
85 | class LLVM_LIBRARY_VISIBILITY CoroAwaitSuspendInst : public CallBase { |
86 | enum { AwaiterArg, FrameArg, WrapperArg }; |
87 | |
88 | public: |
89 | Value *getAwaiter() const { return getArgOperand(i: AwaiterArg); } |
90 | |
91 | Value *getFrame() const { return getArgOperand(i: FrameArg); } |
92 | |
93 | Function *getWrapperFunction() const { |
94 | return cast<Function>(Val: getArgOperand(i: WrapperArg)); |
95 | } |
96 | |
97 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
98 | static bool classof(const CallBase *CB) { |
99 | if (const Function *CF = CB->getCalledFunction()) { |
100 | auto IID = CF->getIntrinsicID(); |
101 | return IID == Intrinsic::coro_await_suspend_void || |
102 | IID == Intrinsic::coro_await_suspend_bool || |
103 | IID == Intrinsic::coro_await_suspend_handle; |
104 | } |
105 | |
106 | return false; |
107 | } |
108 | |
109 | static bool classof(const Value *V) { |
110 | return isa<CallBase>(Val: V) && classof(CB: cast<CallBase>(Val: V)); |
111 | } |
112 | }; |
113 | |
114 | /// This represents a common base class for llvm.coro.id instructions. |
115 | class LLVM_LIBRARY_VISIBILITY AnyCoroIdInst : public IntrinsicInst { |
116 | public: |
117 | CoroAllocInst *getCoroAlloc() { |
118 | for (User *U : users()) |
119 | if (auto *CA = dyn_cast<CoroAllocInst>(Val: U)) |
120 | return CA; |
121 | return nullptr; |
122 | } |
123 | |
124 | IntrinsicInst *getCoroBegin() { |
125 | for (User *U : users()) |
126 | if (auto *II = dyn_cast<IntrinsicInst>(Val: U)) |
127 | if (II->getIntrinsicID() == Intrinsic::coro_begin) |
128 | return II; |
129 | llvm_unreachable("no coro.begin associated with coro.id" ); |
130 | } |
131 | |
132 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
133 | static bool classof(const IntrinsicInst *I) { |
134 | auto ID = I->getIntrinsicID(); |
135 | return ID == Intrinsic::coro_id || ID == Intrinsic::coro_id_retcon || |
136 | ID == Intrinsic::coro_id_retcon_once || |
137 | ID == Intrinsic::coro_id_async; |
138 | } |
139 | |
140 | static bool classof(const Value *V) { |
141 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
142 | } |
143 | }; |
144 | |
145 | /// This represents the llvm.coro.id instruction. |
146 | class LLVM_LIBRARY_VISIBILITY CoroIdInst : public AnyCoroIdInst { |
147 | enum { AlignArg, PromiseArg, CoroutineArg, InfoArg }; |
148 | |
149 | public: |
150 | AllocaInst *getPromise() const { |
151 | Value *Arg = getArgOperand(i: PromiseArg); |
152 | return isa<ConstantPointerNull>(Val: Arg) |
153 | ? nullptr |
154 | : cast<AllocaInst>(Val: Arg->stripPointerCasts()); |
155 | } |
156 | |
157 | void clearPromise() { |
158 | Value *Arg = getArgOperand(i: PromiseArg); |
159 | setArgOperand(i: PromiseArg, v: ConstantPointerNull::get( |
160 | T: PointerType::getUnqual(C&: getContext()))); |
161 | if (isa<AllocaInst>(Val: Arg)) |
162 | return; |
163 | assert((isa<BitCastInst>(Arg) || isa<GetElementPtrInst>(Arg)) && |
164 | "unexpected instruction designating the promise" ); |
165 | // TODO: Add a check that any remaining users of Inst are after coro.begin |
166 | // or add code to move the users after coro.begin. |
167 | auto *Inst = cast<Instruction>(Val: Arg); |
168 | if (Inst->use_empty()) { |
169 | Inst->eraseFromParent(); |
170 | return; |
171 | } |
172 | Inst->moveBefore(MovePos: getCoroBegin()->getNextNode()); |
173 | } |
174 | |
175 | // Info argument of coro.id is |
176 | // fresh out of the frontend: null ; |
177 | // outlined : {Init, Return, Susp1, Susp2, ...} ; |
178 | // postsplit : [resume, destroy, cleanup] ; |
179 | // |
180 | // If parts of the coroutine were outlined to protect against undesirable |
181 | // code motion, these functions will be stored in a struct literal referred to |
182 | // by the Info parameter. Note: this is only needed before coroutine is split. |
183 | // |
184 | // After coroutine is split, resume functions are stored in an array |
185 | // referred to by this parameter. |
186 | |
187 | struct Info { |
188 | ConstantStruct *OutlinedParts = nullptr; |
189 | ConstantArray *Resumers = nullptr; |
190 | |
191 | bool hasOutlinedParts() const { return OutlinedParts != nullptr; } |
192 | bool isPostSplit() const { return Resumers != nullptr; } |
193 | bool isPreSplit() const { return !isPostSplit(); } |
194 | }; |
195 | Info getInfo() const { |
196 | Info Result; |
197 | auto *GV = dyn_cast<GlobalVariable>(Val: getRawInfo()); |
198 | if (!GV) |
199 | return Result; |
200 | |
201 | assert(GV->isConstant() && GV->hasDefinitiveInitializer()); |
202 | Constant *Initializer = GV->getInitializer(); |
203 | if ((Result.OutlinedParts = dyn_cast<ConstantStruct>(Val: Initializer))) |
204 | return Result; |
205 | |
206 | Result.Resumers = cast<ConstantArray>(Val: Initializer); |
207 | return Result; |
208 | } |
209 | Constant *getRawInfo() const { |
210 | return cast<Constant>(Val: getArgOperand(i: InfoArg)->stripPointerCasts()); |
211 | } |
212 | |
213 | void setInfo(Constant *C) { setArgOperand(i: InfoArg, v: C); } |
214 | |
215 | Function *getCoroutine() const { |
216 | return cast<Function>(Val: getArgOperand(i: CoroutineArg)->stripPointerCasts()); |
217 | } |
218 | void setCoroutineSelf() { |
219 | assert(isa<ConstantPointerNull>(getArgOperand(CoroutineArg)) && |
220 | "Coroutine argument is already assigned" ); |
221 | setArgOperand(i: CoroutineArg, v: getFunction()); |
222 | } |
223 | |
224 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
225 | static bool classof(const IntrinsicInst *I) { |
226 | return I->getIntrinsicID() == Intrinsic::coro_id; |
227 | } |
228 | static bool classof(const Value *V) { |
229 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
230 | } |
231 | }; |
232 | |
233 | /// This represents either the llvm.coro.id.retcon or |
234 | /// llvm.coro.id.retcon.once instruction. |
235 | class LLVM_LIBRARY_VISIBILITY AnyCoroIdRetconInst : public AnyCoroIdInst { |
236 | enum { SizeArg, AlignArg, StorageArg, PrototypeArg, AllocArg, DeallocArg }; |
237 | |
238 | public: |
239 | void checkWellFormed() const; |
240 | |
241 | uint64_t getStorageSize() const { |
242 | return cast<ConstantInt>(Val: getArgOperand(i: SizeArg))->getZExtValue(); |
243 | } |
244 | |
245 | Align getStorageAlignment() const { |
246 | return cast<ConstantInt>(Val: getArgOperand(i: AlignArg))->getAlignValue(); |
247 | } |
248 | |
249 | Value *getStorage() const { |
250 | return getArgOperand(i: StorageArg); |
251 | } |
252 | |
253 | /// Return the prototype for the continuation function. The type, |
254 | /// attributes, and calling convention of the continuation function(s) |
255 | /// are taken from this declaration. |
256 | Function *getPrototype() const { |
257 | return cast<Function>(Val: getArgOperand(i: PrototypeArg)->stripPointerCasts()); |
258 | } |
259 | |
260 | /// Return the function to use for allocating memory. |
261 | Function *getAllocFunction() const { |
262 | return cast<Function>(Val: getArgOperand(i: AllocArg)->stripPointerCasts()); |
263 | } |
264 | |
265 | /// Return the function to use for deallocating memory. |
266 | Function *getDeallocFunction() const { |
267 | return cast<Function>(Val: getArgOperand(i: DeallocArg)->stripPointerCasts()); |
268 | } |
269 | |
270 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
271 | static bool classof(const IntrinsicInst *I) { |
272 | auto ID = I->getIntrinsicID(); |
273 | return ID == Intrinsic::coro_id_retcon |
274 | || ID == Intrinsic::coro_id_retcon_once; |
275 | } |
276 | static bool classof(const Value *V) { |
277 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
278 | } |
279 | }; |
280 | |
281 | /// This represents the llvm.coro.id.retcon instruction. |
282 | class LLVM_LIBRARY_VISIBILITY CoroIdRetconInst |
283 | : public AnyCoroIdRetconInst { |
284 | public: |
285 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
286 | static bool classof(const IntrinsicInst *I) { |
287 | return I->getIntrinsicID() == Intrinsic::coro_id_retcon; |
288 | } |
289 | static bool classof(const Value *V) { |
290 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
291 | } |
292 | }; |
293 | |
294 | /// This represents the llvm.coro.id.retcon.once instruction. |
295 | class LLVM_LIBRARY_VISIBILITY CoroIdRetconOnceInst |
296 | : public AnyCoroIdRetconInst { |
297 | public: |
298 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
299 | static bool classof(const IntrinsicInst *I) { |
300 | return I->getIntrinsicID() == Intrinsic::coro_id_retcon_once; |
301 | } |
302 | static bool classof(const Value *V) { |
303 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
304 | } |
305 | }; |
306 | |
307 | /// This represents the llvm.coro.id.async instruction. |
308 | class LLVM_LIBRARY_VISIBILITY CoroIdAsyncInst : public AnyCoroIdInst { |
309 | enum { SizeArg, AlignArg, StorageArg, AsyncFuncPtrArg }; |
310 | |
311 | public: |
312 | void checkWellFormed() const; |
313 | |
314 | /// The initial async function context size. The fields of which are reserved |
315 | /// for use by the frontend. The frame will be allocated as a tail of this |
316 | /// context. |
317 | uint64_t getStorageSize() const { |
318 | return cast<ConstantInt>(Val: getArgOperand(i: SizeArg))->getZExtValue(); |
319 | } |
320 | |
321 | /// The alignment of the initial async function context. |
322 | Align getStorageAlignment() const { |
323 | return cast<ConstantInt>(Val: getArgOperand(i: AlignArg))->getAlignValue(); |
324 | } |
325 | |
326 | /// The async context parameter. |
327 | Value *getStorage() const { |
328 | return getParent()->getParent()->getArg(i: getStorageArgumentIndex()); |
329 | } |
330 | |
331 | unsigned getStorageArgumentIndex() const { |
332 | auto *Arg = cast<ConstantInt>(Val: getArgOperand(i: StorageArg)); |
333 | return Arg->getZExtValue(); |
334 | } |
335 | |
336 | /// Return the async function pointer address. This should be the address of |
337 | /// a async function pointer struct for the current async function. |
338 | /// struct async_function_pointer { |
339 | /// uint32_t context_size; |
340 | /// uint32_t relative_async_function_pointer; |
341 | /// }; |
342 | GlobalVariable *getAsyncFunctionPointer() const { |
343 | return cast<GlobalVariable>( |
344 | Val: getArgOperand(i: AsyncFuncPtrArg)->stripPointerCasts()); |
345 | } |
346 | |
347 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
348 | static bool classof(const IntrinsicInst *I) { |
349 | auto ID = I->getIntrinsicID(); |
350 | return ID == Intrinsic::coro_id_async; |
351 | } |
352 | |
353 | static bool classof(const Value *V) { |
354 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
355 | } |
356 | }; |
357 | |
358 | /// This represents the llvm.coro.context.alloc instruction. |
359 | class LLVM_LIBRARY_VISIBILITY CoroAsyncContextAllocInst : public IntrinsicInst { |
360 | enum { AsyncFuncPtrArg }; |
361 | |
362 | public: |
363 | GlobalVariable *getAsyncFunctionPointer() const { |
364 | return cast<GlobalVariable>( |
365 | Val: getArgOperand(i: AsyncFuncPtrArg)->stripPointerCasts()); |
366 | } |
367 | |
368 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
369 | static bool classof(const IntrinsicInst *I) { |
370 | return I->getIntrinsicID() == Intrinsic::coro_async_context_alloc; |
371 | } |
372 | static bool classof(const Value *V) { |
373 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
374 | } |
375 | }; |
376 | |
377 | /// This represents the llvm.coro.context.dealloc instruction. |
378 | class LLVM_LIBRARY_VISIBILITY CoroAsyncContextDeallocInst |
379 | : public IntrinsicInst { |
380 | enum { AsyncContextArg }; |
381 | |
382 | public: |
383 | Value *getAsyncContext() const { |
384 | return getArgOperand(i: AsyncContextArg)->stripPointerCasts(); |
385 | } |
386 | |
387 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
388 | static bool classof(const IntrinsicInst *I) { |
389 | return I->getIntrinsicID() == Intrinsic::coro_async_context_dealloc; |
390 | } |
391 | static bool classof(const Value *V) { |
392 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
393 | } |
394 | }; |
395 | |
396 | /// This represents the llvm.coro.async.resume instruction. |
397 | /// During lowering this is replaced by the resume function of a suspend point |
398 | /// (the continuation function). |
399 | class LLVM_LIBRARY_VISIBILITY CoroAsyncResumeInst : public IntrinsicInst { |
400 | public: |
401 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
402 | static bool classof(const IntrinsicInst *I) { |
403 | return I->getIntrinsicID() == Intrinsic::coro_async_resume; |
404 | } |
405 | static bool classof(const Value *V) { |
406 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
407 | } |
408 | }; |
409 | |
410 | /// This represents the llvm.coro.async.size.replace instruction. |
411 | class LLVM_LIBRARY_VISIBILITY CoroAsyncSizeReplace : public IntrinsicInst { |
412 | public: |
413 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
414 | static bool classof(const IntrinsicInst *I) { |
415 | return I->getIntrinsicID() == Intrinsic::coro_async_size_replace; |
416 | } |
417 | static bool classof(const Value *V) { |
418 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
419 | } |
420 | }; |
421 | |
422 | /// This represents the llvm.coro.frame instruction. |
423 | class LLVM_LIBRARY_VISIBILITY CoroFrameInst : public IntrinsicInst { |
424 | public: |
425 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
426 | static bool classof(const IntrinsicInst *I) { |
427 | return I->getIntrinsicID() == Intrinsic::coro_frame; |
428 | } |
429 | static bool classof(const Value *V) { |
430 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
431 | } |
432 | }; |
433 | |
434 | /// This represents the llvm.coro.free instruction. |
435 | class LLVM_LIBRARY_VISIBILITY CoroFreeInst : public IntrinsicInst { |
436 | enum { IdArg, FrameArg }; |
437 | |
438 | public: |
439 | Value *getFrame() const { return getArgOperand(i: FrameArg); } |
440 | |
441 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
442 | static bool classof(const IntrinsicInst *I) { |
443 | return I->getIntrinsicID() == Intrinsic::coro_free; |
444 | } |
445 | static bool classof(const Value *V) { |
446 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
447 | } |
448 | }; |
449 | |
450 | /// This class represents the llvm.coro.begin instruction. |
451 | class LLVM_LIBRARY_VISIBILITY CoroBeginInst : public IntrinsicInst { |
452 | enum { IdArg, MemArg }; |
453 | |
454 | public: |
455 | AnyCoroIdInst *getId() const { |
456 | return cast<AnyCoroIdInst>(Val: getArgOperand(i: IdArg)); |
457 | } |
458 | |
459 | Value *getMem() const { return getArgOperand(i: MemArg); } |
460 | |
461 | // Methods for support type inquiry through isa, cast, and dyn_cast: |
462 | static bool classof(const IntrinsicInst *I) { |
463 | return I->getIntrinsicID() == Intrinsic::coro_begin; |
464 | } |
465 | static bool classof(const Value *V) { |
466 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
467 | } |
468 | }; |
469 | |
470 | /// This represents the llvm.coro.save instruction. |
471 | class LLVM_LIBRARY_VISIBILITY CoroSaveInst : public IntrinsicInst { |
472 | public: |
473 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
474 | static bool classof(const IntrinsicInst *I) { |
475 | return I->getIntrinsicID() == Intrinsic::coro_save; |
476 | } |
477 | static bool classof(const Value *V) { |
478 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
479 | } |
480 | }; |
481 | |
482 | /// This represents the llvm.coro.promise instruction. |
483 | class LLVM_LIBRARY_VISIBILITY CoroPromiseInst : public IntrinsicInst { |
484 | enum { FrameArg, AlignArg, FromArg }; |
485 | |
486 | public: |
487 | /// Are we translating from the frame to the promise (false) or from |
488 | /// the promise to the frame (true)? |
489 | bool isFromPromise() const { |
490 | return cast<Constant>(Val: getArgOperand(i: FromArg))->isOneValue(); |
491 | } |
492 | |
493 | /// The required alignment of the promise. This must match the |
494 | /// alignment of the promise alloca in the coroutine. |
495 | Align getAlignment() const { |
496 | return cast<ConstantInt>(Val: getArgOperand(i: AlignArg))->getAlignValue(); |
497 | } |
498 | |
499 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
500 | static bool classof(const IntrinsicInst *I) { |
501 | return I->getIntrinsicID() == Intrinsic::coro_promise; |
502 | } |
503 | static bool classof(const Value *V) { |
504 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
505 | } |
506 | }; |
507 | |
508 | class LLVM_LIBRARY_VISIBILITY AnyCoroSuspendInst : public IntrinsicInst { |
509 | public: |
510 | CoroSaveInst *getCoroSave() const; |
511 | |
512 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
513 | static bool classof(const IntrinsicInst *I) { |
514 | return I->getIntrinsicID() == Intrinsic::coro_suspend || |
515 | I->getIntrinsicID() == Intrinsic::coro_suspend_async || |
516 | I->getIntrinsicID() == Intrinsic::coro_suspend_retcon; |
517 | } |
518 | static bool classof(const Value *V) { |
519 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
520 | } |
521 | }; |
522 | |
523 | /// This represents the llvm.coro.suspend instruction. |
524 | class LLVM_LIBRARY_VISIBILITY CoroSuspendInst : public AnyCoroSuspendInst { |
525 | enum { SaveArg, FinalArg }; |
526 | |
527 | public: |
528 | CoroSaveInst *getCoroSave() const { |
529 | Value *Arg = getArgOperand(i: SaveArg); |
530 | if (auto *SI = dyn_cast<CoroSaveInst>(Val: Arg)) |
531 | return SI; |
532 | assert(isa<ConstantTokenNone>(Arg)); |
533 | return nullptr; |
534 | } |
535 | |
536 | bool isFinal() const { |
537 | return cast<Constant>(Val: getArgOperand(i: FinalArg))->isOneValue(); |
538 | } |
539 | |
540 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
541 | static bool classof(const IntrinsicInst *I) { |
542 | return I->getIntrinsicID() == Intrinsic::coro_suspend; |
543 | } |
544 | static bool classof(const Value *V) { |
545 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
546 | } |
547 | }; |
548 | |
549 | inline CoroSaveInst *AnyCoroSuspendInst::getCoroSave() const { |
550 | if (auto Suspend = dyn_cast<CoroSuspendInst>(Val: this)) |
551 | return Suspend->getCoroSave(); |
552 | return nullptr; |
553 | } |
554 | |
555 | /// This represents the llvm.coro.suspend.async instruction. |
556 | class LLVM_LIBRARY_VISIBILITY CoroSuspendAsyncInst : public AnyCoroSuspendInst { |
557 | public: |
558 | enum { |
559 | StorageArgNoArg, |
560 | ResumeFunctionArg, |
561 | AsyncContextProjectionArg, |
562 | MustTailCallFuncArg |
563 | }; |
564 | |
565 | void checkWellFormed() const; |
566 | |
567 | unsigned getStorageArgumentIndex() const { |
568 | auto *Arg = cast<ConstantInt>(Val: getArgOperand(i: StorageArgNoArg)); |
569 | return Arg->getZExtValue(); |
570 | } |
571 | |
572 | Function *getAsyncContextProjectionFunction() const { |
573 | return cast<Function>( |
574 | Val: getArgOperand(i: AsyncContextProjectionArg)->stripPointerCasts()); |
575 | } |
576 | |
577 | CoroAsyncResumeInst *getResumeFunction() const { |
578 | return cast<CoroAsyncResumeInst>( |
579 | Val: getArgOperand(i: ResumeFunctionArg)->stripPointerCasts()); |
580 | } |
581 | |
582 | Function *getMustTailCallFunction() const { |
583 | return cast<Function>( |
584 | Val: getArgOperand(i: MustTailCallFuncArg)->stripPointerCasts()); |
585 | } |
586 | |
587 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
588 | static bool classof(const IntrinsicInst *I) { |
589 | return I->getIntrinsicID() == Intrinsic::coro_suspend_async; |
590 | } |
591 | static bool classof(const Value *V) { |
592 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
593 | } |
594 | }; |
595 | |
596 | /// This represents the llvm.coro.suspend.retcon instruction. |
597 | class LLVM_LIBRARY_VISIBILITY CoroSuspendRetconInst : public AnyCoroSuspendInst { |
598 | public: |
599 | op_iterator value_begin() { return arg_begin(); } |
600 | const_op_iterator value_begin() const { return arg_begin(); } |
601 | |
602 | op_iterator value_end() { return arg_end(); } |
603 | const_op_iterator value_end() const { return arg_end(); } |
604 | |
605 | iterator_range<op_iterator> value_operands() { |
606 | return make_range(x: value_begin(), y: value_end()); |
607 | } |
608 | iterator_range<const_op_iterator> value_operands() const { |
609 | return make_range(x: value_begin(), y: value_end()); |
610 | } |
611 | |
612 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
613 | static bool classof(const IntrinsicInst *I) { |
614 | return I->getIntrinsicID() == Intrinsic::coro_suspend_retcon; |
615 | } |
616 | static bool classof(const Value *V) { |
617 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
618 | } |
619 | }; |
620 | |
621 | /// This represents the llvm.coro.size instruction. |
622 | class LLVM_LIBRARY_VISIBILITY CoroSizeInst : public IntrinsicInst { |
623 | public: |
624 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
625 | static bool classof(const IntrinsicInst *I) { |
626 | return I->getIntrinsicID() == Intrinsic::coro_size; |
627 | } |
628 | static bool classof(const Value *V) { |
629 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
630 | } |
631 | }; |
632 | |
633 | /// This represents the llvm.coro.align instruction. |
634 | class LLVM_LIBRARY_VISIBILITY CoroAlignInst : public IntrinsicInst { |
635 | public: |
636 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
637 | static bool classof(const IntrinsicInst *I) { |
638 | return I->getIntrinsicID() == Intrinsic::coro_align; |
639 | } |
640 | static bool classof(const Value *V) { |
641 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
642 | } |
643 | }; |
644 | |
645 | /// This represents the llvm.end.results instruction. |
646 | class LLVM_LIBRARY_VISIBILITY CoroEndResults : public IntrinsicInst { |
647 | public: |
648 | op_iterator retval_begin() { return arg_begin(); } |
649 | const_op_iterator retval_begin() const { return arg_begin(); } |
650 | |
651 | op_iterator retval_end() { return arg_end(); } |
652 | const_op_iterator retval_end() const { return arg_end(); } |
653 | |
654 | iterator_range<op_iterator> return_values() { |
655 | return make_range(x: retval_begin(), y: retval_end()); |
656 | } |
657 | iterator_range<const_op_iterator> return_values() const { |
658 | return make_range(x: retval_begin(), y: retval_end()); |
659 | } |
660 | |
661 | unsigned numReturns() const { |
662 | return std::distance(first: retval_begin(), last: retval_end()); |
663 | } |
664 | |
665 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
666 | static bool classof(const IntrinsicInst *I) { |
667 | return I->getIntrinsicID() == Intrinsic::coro_end_results; |
668 | } |
669 | static bool classof(const Value *V) { |
670 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
671 | } |
672 | }; |
673 | |
674 | class LLVM_LIBRARY_VISIBILITY AnyCoroEndInst : public IntrinsicInst { |
675 | enum { FrameArg, UnwindArg, TokenArg }; |
676 | |
677 | public: |
678 | bool isFallthrough() const { return !isUnwind(); } |
679 | bool isUnwind() const { |
680 | return cast<Constant>(Val: getArgOperand(i: UnwindArg))->isOneValue(); |
681 | } |
682 | |
683 | bool hasResults() const { |
684 | return !isa<ConstantTokenNone>(Val: getArgOperand(i: TokenArg)); |
685 | } |
686 | |
687 | CoroEndResults *getResults() const { |
688 | assert(hasResults()); |
689 | return cast<CoroEndResults>(Val: getArgOperand(i: TokenArg)); |
690 | } |
691 | |
692 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
693 | static bool classof(const IntrinsicInst *I) { |
694 | auto ID = I->getIntrinsicID(); |
695 | return ID == Intrinsic::coro_end || ID == Intrinsic::coro_end_async; |
696 | } |
697 | static bool classof(const Value *V) { |
698 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
699 | } |
700 | }; |
701 | |
702 | /// This represents the llvm.coro.end instruction. |
703 | class LLVM_LIBRARY_VISIBILITY CoroEndInst : public AnyCoroEndInst { |
704 | public: |
705 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
706 | static bool classof(const IntrinsicInst *I) { |
707 | return I->getIntrinsicID() == Intrinsic::coro_end; |
708 | } |
709 | static bool classof(const Value *V) { |
710 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
711 | } |
712 | }; |
713 | |
714 | /// This represents the llvm.coro.end instruction. |
715 | class LLVM_LIBRARY_VISIBILITY CoroAsyncEndInst : public AnyCoroEndInst { |
716 | enum { FrameArg, UnwindArg, MustTailCallFuncArg }; |
717 | |
718 | public: |
719 | void checkWellFormed() const; |
720 | |
721 | Function *getMustTailCallFunction() const { |
722 | if (arg_size() < 3) |
723 | return nullptr; |
724 | |
725 | return cast<Function>( |
726 | Val: getArgOperand(i: MustTailCallFuncArg)->stripPointerCasts()); |
727 | } |
728 | |
729 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
730 | static bool classof(const IntrinsicInst *I) { |
731 | return I->getIntrinsicID() == Intrinsic::coro_end_async; |
732 | } |
733 | static bool classof(const Value *V) { |
734 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
735 | } |
736 | }; |
737 | |
738 | /// This represents the llvm.coro.alloca.alloc instruction. |
739 | class LLVM_LIBRARY_VISIBILITY CoroAllocaAllocInst : public IntrinsicInst { |
740 | enum { SizeArg, AlignArg }; |
741 | public: |
742 | Value *getSize() const { |
743 | return getArgOperand(i: SizeArg); |
744 | } |
745 | Align getAlignment() const { |
746 | return cast<ConstantInt>(Val: getArgOperand(i: AlignArg))->getAlignValue(); |
747 | } |
748 | |
749 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
750 | static bool classof(const IntrinsicInst *I) { |
751 | return I->getIntrinsicID() == Intrinsic::coro_alloca_alloc; |
752 | } |
753 | static bool classof(const Value *V) { |
754 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
755 | } |
756 | }; |
757 | |
758 | /// This represents the llvm.coro.alloca.get instruction. |
759 | class LLVM_LIBRARY_VISIBILITY CoroAllocaGetInst : public IntrinsicInst { |
760 | enum { AllocArg }; |
761 | public: |
762 | CoroAllocaAllocInst *getAlloc() const { |
763 | return cast<CoroAllocaAllocInst>(Val: getArgOperand(i: AllocArg)); |
764 | } |
765 | |
766 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
767 | static bool classof(const IntrinsicInst *I) { |
768 | return I->getIntrinsicID() == Intrinsic::coro_alloca_get; |
769 | } |
770 | static bool classof(const Value *V) { |
771 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
772 | } |
773 | }; |
774 | |
775 | /// This represents the llvm.coro.alloca.free instruction. |
776 | class LLVM_LIBRARY_VISIBILITY CoroAllocaFreeInst : public IntrinsicInst { |
777 | enum { AllocArg }; |
778 | public: |
779 | CoroAllocaAllocInst *getAlloc() const { |
780 | return cast<CoroAllocaAllocInst>(Val: getArgOperand(i: AllocArg)); |
781 | } |
782 | |
783 | // Methods to support type inquiry through isa, cast, and dyn_cast: |
784 | static bool classof(const IntrinsicInst *I) { |
785 | return I->getIntrinsicID() == Intrinsic::coro_alloca_free; |
786 | } |
787 | static bool classof(const Value *V) { |
788 | return isa<IntrinsicInst>(Val: V) && classof(I: cast<IntrinsicInst>(Val: V)); |
789 | } |
790 | }; |
791 | |
792 | } // End namespace llvm. |
793 | |
794 | #endif |
795 | |