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(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.
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>(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.
85class LLVM_LIBRARY_VISIBILITY CoroAwaitSuspendInst : public CallBase {
86 enum { AwaiterArg, FrameArg, WrapperArg };
87
88public:
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.
115class LLVM_LIBRARY_VISIBILITY AnyCoroIdInst : public IntrinsicInst {
116public:
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.
146class LLVM_LIBRARY_VISIBILITY CoroIdInst : public AnyCoroIdInst {
147 enum { AlignArg, PromiseArg, CoroutineArg, InfoArg };
148
149public:
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.
235class LLVM_LIBRARY_VISIBILITY AnyCoroIdRetconInst : public AnyCoroIdInst {
236 enum { SizeArg, AlignArg, StorageArg, PrototypeArg, AllocArg, DeallocArg };
237
238public:
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.
282class LLVM_LIBRARY_VISIBILITY CoroIdRetconInst
283 : public AnyCoroIdRetconInst {
284public:
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.
295class LLVM_LIBRARY_VISIBILITY CoroIdRetconOnceInst
296 : public AnyCoroIdRetconInst {
297public:
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.
308class LLVM_LIBRARY_VISIBILITY CoroIdAsyncInst : public AnyCoroIdInst {
309 enum { SizeArg, AlignArg, StorageArg, AsyncFuncPtrArg };
310
311public:
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.
359class LLVM_LIBRARY_VISIBILITY CoroAsyncContextAllocInst : public IntrinsicInst {
360 enum { AsyncFuncPtrArg };
361
362public:
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.
378class LLVM_LIBRARY_VISIBILITY CoroAsyncContextDeallocInst
379 : public IntrinsicInst {
380 enum { AsyncContextArg };
381
382public:
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).
399class LLVM_LIBRARY_VISIBILITY CoroAsyncResumeInst : public IntrinsicInst {
400public:
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.
411class LLVM_LIBRARY_VISIBILITY CoroAsyncSizeReplace : public IntrinsicInst {
412public:
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.
423class LLVM_LIBRARY_VISIBILITY CoroFrameInst : public IntrinsicInst {
424public:
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.
435class LLVM_LIBRARY_VISIBILITY CoroFreeInst : public IntrinsicInst {
436 enum { IdArg, FrameArg };
437
438public:
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.
451class LLVM_LIBRARY_VISIBILITY CoroBeginInst : public IntrinsicInst {
452 enum { IdArg, MemArg };
453
454public:
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.
471class LLVM_LIBRARY_VISIBILITY CoroSaveInst : public IntrinsicInst {
472public:
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.
483class LLVM_LIBRARY_VISIBILITY CoroPromiseInst : public IntrinsicInst {
484 enum { FrameArg, AlignArg, FromArg };
485
486public:
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
508class LLVM_LIBRARY_VISIBILITY AnyCoroSuspendInst : public IntrinsicInst {
509public:
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.
524class LLVM_LIBRARY_VISIBILITY CoroSuspendInst : public AnyCoroSuspendInst {
525 enum { SaveArg, FinalArg };
526
527public:
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
549inline 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.
556class LLVM_LIBRARY_VISIBILITY CoroSuspendAsyncInst : public AnyCoroSuspendInst {
557public:
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.
597class LLVM_LIBRARY_VISIBILITY CoroSuspendRetconInst : public AnyCoroSuspendInst {
598public:
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.
622class LLVM_LIBRARY_VISIBILITY CoroSizeInst : public IntrinsicInst {
623public:
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.
634class LLVM_LIBRARY_VISIBILITY CoroAlignInst : public IntrinsicInst {
635public:
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.
646class LLVM_LIBRARY_VISIBILITY CoroEndResults : public IntrinsicInst {
647public:
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
674class LLVM_LIBRARY_VISIBILITY AnyCoroEndInst : public IntrinsicInst {
675 enum { FrameArg, UnwindArg, TokenArg };
676
677public:
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.
703class LLVM_LIBRARY_VISIBILITY CoroEndInst : public AnyCoroEndInst {
704public:
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.
715class LLVM_LIBRARY_VISIBILITY CoroAsyncEndInst : public AnyCoroEndInst {
716 enum { FrameArg, UnwindArg, MustTailCallFuncArg };
717
718public:
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.
739class LLVM_LIBRARY_VISIBILITY CoroAllocaAllocInst : public IntrinsicInst {
740 enum { SizeArg, AlignArg };
741public:
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.
759class LLVM_LIBRARY_VISIBILITY CoroAllocaGetInst : public IntrinsicInst {
760 enum { AllocArg };
761public:
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.
776class LLVM_LIBRARY_VISIBILITY CoroAllocaFreeInst : public IntrinsicInst {
777 enum { AllocArg };
778public:
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

source code of llvm/lib/Transforms/Coroutines/CoroInstr.h