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