LLVM 23.0.0git
Coroutines.cpp
Go to the documentation of this file.
1//===- Coroutines.cpp -----------------------------------------------------===//
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//
9// This file implements the common infrastructure for Coroutine Passes.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CoroInternal.h"
15#include "llvm/ADT/StringRef.h"
17#include "llvm/IR/Attributes.h"
18#include "llvm/IR/Constants.h"
20#include "llvm/IR/Function.h"
24#include "llvm/IR/Intrinsics.h"
25#include "llvm/IR/Module.h"
26#include "llvm/IR/Type.h"
33#include <cassert>
34#include <cstddef>
35#include <utility>
36
37using namespace llvm;
38
39// Construct the lowerer base class and initialize its members.
46
47// Creates a call to llvm.coro.subfn.addr to obtain a resume function address.
48// It generates the following:
49//
50// call ptr @llvm.coro.subfn.addr(ptr %Arg, i8 %index)
51
53 Instruction *InsertPt) {
54 auto *IndexVal = ConstantInt::get(Type::getInt8Ty(Context), Index);
55 auto *Fn =
56 Intrinsic::getOrInsertDeclaration(&TheModule, Intrinsic::coro_subfn_addr);
57
60 "makeSubFnCall: Index value out of range");
61 return CallInst::Create(Fn, {Arg, IndexVal}, "", InsertPt->getIterator());
62}
63
64// We can only efficiently check for non-overloaded intrinsics.
65// The following intrinsics are absent for that reason:
66// coro_align, coro_size, coro_suspend_async, coro_suspend_retcon
68 Intrinsic::coro_alloc,
69 Intrinsic::coro_async_context_alloc,
70 Intrinsic::coro_async_context_dealloc,
71 Intrinsic::coro_async_resume,
72 Intrinsic::coro_async_size_replace,
73 Intrinsic::coro_await_suspend_bool,
74 Intrinsic::coro_await_suspend_handle,
75 Intrinsic::coro_await_suspend_void,
76 Intrinsic::coro_begin,
77 Intrinsic::coro_begin_custom_abi,
78 Intrinsic::coro_destroy,
79 Intrinsic::coro_done,
80 Intrinsic::coro_end,
81 Intrinsic::coro_end_async,
82 Intrinsic::coro_frame,
83 Intrinsic::coro_free,
84 Intrinsic::coro_id,
85 Intrinsic::coro_id_async,
86 Intrinsic::coro_id_retcon,
87 Intrinsic::coro_id_retcon_once,
88 Intrinsic::coro_noop,
89 Intrinsic::coro_prepare_async,
90 Intrinsic::coro_prepare_retcon,
91 Intrinsic::coro_promise,
92 Intrinsic::coro_resume,
93 Intrinsic::coro_save,
94 Intrinsic::coro_subfn_addr,
95 Intrinsic::coro_suspend,
96 Intrinsic::coro_is_in_ramp,
97};
98
102
106
107// Checks whether the module declares any of the listed intrinsics.
109#ifndef NDEBUG
110 for (Intrinsic::ID ID : List)
112 "Only non-overloaded intrinsics supported");
113#endif
114
115 for (Intrinsic::ID ID : List)
117 return true;
118 return false;
119}
120
121// Replace all coro.frees associated with the provided frame with 'null' and
122// erase all associated coro.deads
126 for (User *U : FramePtr->users()) {
127 if (auto *CF = dyn_cast<CoroFreeInst>(U))
128 CoroFrees.push_back(CF);
129 else if (auto *CD = dyn_cast<CoroDeadInst>(U))
130 CoroDeads.push_back(CD);
131 }
132
133 Value *Replacement =
135 for (CoroFreeInst *CF : CoroFrees) {
136 CF->replaceAllUsesWith(Replacement);
137 CF->eraseFromParent();
138 }
139
140 for (auto *CD : CoroDeads)
141 CD->eraseFromParent();
142}
143
146 for (User *U : CoroId->users())
147 if (auto *CA = dyn_cast<CoroAllocInst>(U))
148 CoroAllocs.push_back(CA);
149
150 if (CoroAllocs.empty())
151 return;
152
153 coro::suppressCoroAllocs(CoroId->getContext(), CoroAllocs);
154}
155
156// Replacing llvm.coro.alloc with false will suppress dynamic
157// allocation as it is expected for the frontend to generate the code that
158// looks like:
159// id = coro.id(...)
160// mem = coro.alloc(id) ? malloc(coro.size()) : 0;
161// coro.begin(id, mem)
163 ArrayRef<CoroAllocInst *> CoroAllocs) {
164 auto *False = ConstantInt::getFalse(Context);
165 for (auto *CA : CoroAllocs) {
166 CA->replaceAllUsesWith(False);
167 CA->eraseFromParent();
168 }
169}
170
172 CoroSuspendInst *SuspendInst) {
173 Module *M = SuspendInst->getModule();
174 auto *Fn = Intrinsic::getOrInsertDeclaration(M, Intrinsic::coro_save);
175 auto *SaveInst = cast<CoroSaveInst>(
176 CallInst::Create(Fn, CoroBegin, "", SuspendInst->getIterator()));
177 assert(!SuspendInst->getCoroSave());
178 SuspendInst->setArgOperand(0, SaveInst);
179 return SaveInst;
180}
181
182// Collect "interesting" coroutine intrinsics.
185 SmallVectorImpl<CoroSaveInst *> &UnusedCoroSaves,
186 CoroPromiseInst *&CoroPromise) {
187 clear();
188
189 bool HasFinalSuspend = false;
190 bool HasUnwindCoroEnd = false;
191 size_t FinalSuspendIndex = 0;
192
193 for (Instruction &I : instructions(F)) {
194 // FIXME: coro_await_suspend_* are not proper `IntrinisicInst`s
195 // because they might be invoked
196 if (auto AWS = dyn_cast<CoroAwaitSuspendInst>(&I)) {
197 CoroAwaitSuspends.push_back(AWS);
198 } else if (auto II = dyn_cast<IntrinsicInst>(&I)) {
199 switch (II->getIntrinsicID()) {
200 default:
201 continue;
202 case Intrinsic::coro_size:
203 CoroSizes.push_back(cast<CoroSizeInst>(II));
204 break;
205 case Intrinsic::coro_align:
207 break;
208 case Intrinsic::coro_frame:
209 CoroFrames.push_back(cast<CoroFrameInst>(II));
210 break;
211 case Intrinsic::coro_save:
212 // After optimizations, coro_suspends using this coro_save might have
213 // been removed, remember orphaned coro_saves to remove them later.
214 if (II->use_empty())
215 UnusedCoroSaves.push_back(cast<CoroSaveInst>(II));
216 break;
217 case Intrinsic::coro_suspend_async: {
218 auto *Suspend = cast<CoroSuspendAsyncInst>(II);
219 Suspend->checkWellFormed();
220 CoroSuspends.push_back(Suspend);
221 break;
222 }
223 case Intrinsic::coro_suspend_retcon: {
224 auto Suspend = cast<CoroSuspendRetconInst>(II);
225 CoroSuspends.push_back(Suspend);
226 break;
227 }
228 case Intrinsic::coro_suspend: {
229 auto Suspend = cast<CoroSuspendInst>(II);
230 CoroSuspends.push_back(Suspend);
231 if (Suspend->isFinal()) {
232 if (HasFinalSuspend)
234 "Only one suspend point can be marked as final");
235 HasFinalSuspend = true;
236 FinalSuspendIndex = CoroSuspends.size() - 1;
237 }
238 break;
239 }
240 case Intrinsic::coro_begin:
241 case Intrinsic::coro_begin_custom_abi: {
242 auto CB = cast<CoroBeginInst>(II);
243
244 // Ignore coro id's that aren't pre-split.
245 auto Id = dyn_cast<CoroIdInst>(CB->getId());
246 if (Id && !Id->getInfo().isPreSplit())
247 break;
248
249 if (CoroBegin)
251 "coroutine should have exactly one defining @llvm.coro.begin");
252 CB->addRetAttr(Attribute::NonNull);
253 CB->addRetAttr(Attribute::NoAlias);
254 CB->removeFnAttr(Attribute::NoDuplicate);
255 CoroBegin = CB;
256 break;
257 }
258 case Intrinsic::coro_end_async:
259 case Intrinsic::coro_end:
260 CoroEnds.push_back(cast<AnyCoroEndInst>(II));
261 if (auto *AsyncEnd = dyn_cast<CoroAsyncEndInst>(II)) {
262 AsyncEnd->checkWellFormed();
263 }
264
265 if (CoroEnds.back()->isUnwind())
266 HasUnwindCoroEnd = true;
267
268 if (CoroEnds.back()->isFallthrough() && isa<CoroEndInst>(II)) {
269 // Make sure that the fallthrough coro.end is the first element in the
270 // CoroEnds vector.
271 // Note: I don't think this is neccessary anymore.
272 if (CoroEnds.size() > 1) {
273 if (CoroEnds.front()->isFallthrough())
275 "Only one coro.end can be marked as fallthrough");
276 std::swap(CoroEnds.front(), CoroEnds.back());
277 }
278 }
279 break;
280 case Intrinsic::coro_is_in_ramp:
282 break;
283 case Intrinsic::coro_promise:
284 assert(CoroPromise == nullptr &&
285 "CoroEarly must ensure coro.promise unique");
286 CoroPromise = cast<CoroPromiseInst>(II);
287 break;
288 }
289 }
290 }
291
292 // If there is no CoroBegin then this is not a coroutine.
293 if (!CoroBegin)
294 return;
295
296 // Determination of ABI and initializing lowering info
297 auto Id = CoroBegin->getId();
298 switch (auto IntrID = Id->getIntrinsicID()) {
299 case Intrinsic::coro_id: {
301 SwitchLowering.HasFinalSuspend = HasFinalSuspend;
302 SwitchLowering.HasUnwindCoroEnd = HasUnwindCoroEnd;
303
304 auto SwitchId = getSwitchCoroId();
305 SwitchLowering.ResumeSwitch = nullptr;
306 SwitchLowering.PromiseAlloca = SwitchId->getPromise();
307 SwitchLowering.ResumeEntryBlock = nullptr;
308
309 // Move final suspend to the last element in the CoroSuspends vector.
310 if (SwitchLowering.HasFinalSuspend &&
311 FinalSuspendIndex != CoroSuspends.size() - 1)
312 std::swap(CoroSuspends[FinalSuspendIndex], CoroSuspends.back());
313 break;
314 }
315 case Intrinsic::coro_id_async: {
317 auto *AsyncId = getAsyncCoroId();
318 AsyncId->checkWellFormed();
319 AsyncLowering.Context = AsyncId->getStorage();
320 AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex();
321 AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize();
322 AsyncLowering.ContextAlignment = AsyncId->getStorageAlignment().value();
323 AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer();
324 AsyncLowering.AsyncCC = F.getCallingConv();
325 break;
326 }
327 case Intrinsic::coro_id_retcon:
328 case Intrinsic::coro_id_retcon_once: {
329 ABI = IntrID == Intrinsic::coro_id_retcon ? coro::ABI::Retcon
331 auto ContinuationId = getRetconCoroId();
332 ContinuationId->checkWellFormed();
333 auto Prototype = ContinuationId->getPrototype();
334 RetconLowering.ResumePrototype = Prototype;
335 RetconLowering.Alloc = ContinuationId->getAllocFunction();
336 RetconLowering.Dealloc = ContinuationId->getDeallocFunction();
337 RetconLowering.ReturnBlock = nullptr;
338 RetconLowering.IsFrameInlineInStorage = false;
339 break;
340 }
341 default:
342 llvm_unreachable("coro.begin is not dependent on a coro.id call");
343 }
344}
345
346// If for some reason, we were not able to find coro.begin, bailout.
350 {
351 // Replace coro.frame which are supposed to be lowered to the result of
352 // coro.begin with poison.
353 auto *Poison = PoisonValue::get(PointerType::get(F.getContext(), 0));
354 for (CoroFrameInst *CF : CoroFrames) {
355 CF->replaceAllUsesWith(Poison);
356 CF->eraseFromParent();
357 }
358 CoroFrames.clear();
359
360 // Replace all coro.suspend with poison and remove related coro.saves if
361 // present.
362 for (AnyCoroSuspendInst *CS : CoroSuspends) {
363 CS->replaceAllUsesWith(PoisonValue::get(CS->getType()));
364 if (auto *CoroSave = CS->getCoroSave())
365 CoroSave->eraseFromParent();
366 CS->eraseFromParent();
367 }
368 CoroSuspends.clear();
369
370 // Replace all coro.ends with unreachable instruction.
371 for (AnyCoroEndInst *CE : CoroEnds)
373 }
374}
375
378 {
379 for (auto *AnySuspend : Shape.CoroSuspends) {
380 auto Suspend = dyn_cast<CoroSuspendInst>(AnySuspend);
381 if (!Suspend) {
382#ifndef NDEBUG
383 AnySuspend->dump();
384#endif
385 report_fatal_error("coro.id must be paired with coro.suspend");
386 }
387
388 if (!Suspend->getCoroSave())
389 createCoroSave(Shape.CoroBegin, Suspend);
390 }
391 }
392}
393
395
398 {
399 // Determine the result value types, and make sure they match up with
400 // the values passed to the suspends.
401 auto ResultTys = Shape.getRetconResultTypes();
402 auto ResumeTys = Shape.getRetconResumeTypes();
403
404 for (auto *AnySuspend : Shape.CoroSuspends) {
405 auto Suspend = dyn_cast<CoroSuspendRetconInst>(AnySuspend);
406 if (!Suspend) {
407#ifndef NDEBUG
408 AnySuspend->dump();
409#endif
410 report_fatal_error("coro.id.retcon.* must be paired with "
411 "coro.suspend.retcon");
412 }
413
414 // Check that the argument types of the suspend match the results.
415 auto SI = Suspend->value_begin(), SE = Suspend->value_end();
416 auto RI = ResultTys.begin(), RE = ResultTys.end();
417 for (; SI != SE && RI != RE; ++SI, ++RI) {
418 auto SrcTy = (*SI)->getType();
419 if (SrcTy != *RI) {
420 // The optimizer likes to eliminate bitcasts leading into variadic
421 // calls, but that messes with our invariants. Re-insert the
422 // bitcast and ignore this type mismatch.
423 if (CastInst::isBitCastable(SrcTy, *RI)) {
424 auto BCI = new BitCastInst(*SI, *RI, "", Suspend->getIterator());
425 SI->set(BCI);
426 continue;
427 }
428
429#ifndef NDEBUG
430 Suspend->dump();
431 Shape.RetconLowering.ResumePrototype->getFunctionType()->dump();
432#endif
433 report_fatal_error("argument to coro.suspend.retcon does not "
434 "match corresponding prototype function result");
435 }
436 }
437 if (SI != SE || RI != RE) {
438#ifndef NDEBUG
439 Suspend->dump();
440 Shape.RetconLowering.ResumePrototype->getFunctionType()->dump();
441#endif
442 report_fatal_error("wrong number of arguments to coro.suspend.retcon");
443 }
444
445 // Check that the result type of the suspend matches the resume types.
446 Type *SResultTy = Suspend->getType();
447 ArrayRef<Type *> SuspendResultTys;
448 if (SResultTy->isVoidTy()) {
449 // leave as empty array
450 } else if (auto SResultStructTy = dyn_cast<StructType>(SResultTy)) {
451 SuspendResultTys = SResultStructTy->elements();
452 } else {
453 // forms an ArrayRef using SResultTy, be careful
454 SuspendResultTys = SResultTy;
455 }
456 if (SuspendResultTys.size() != ResumeTys.size()) {
457#ifndef NDEBUG
458 Suspend->dump();
459 Shape.RetconLowering.ResumePrototype->getFunctionType()->dump();
460#endif
461 report_fatal_error("wrong number of results from coro.suspend.retcon");
462 }
463 for (size_t I = 0, E = ResumeTys.size(); I != E; ++I) {
464 if (SuspendResultTys[I] != ResumeTys[I]) {
465#ifndef NDEBUG
466 Suspend->dump();
467 Shape.RetconLowering.ResumePrototype->getFunctionType()->dump();
468#endif
469 report_fatal_error("result from coro.suspend.retcon does not "
470 "match corresponding prototype function param");
471 }
472 }
473 }
474 }
475}
476
479 SmallVectorImpl<CoroSaveInst *> &UnusedCoroSaves, CoroPromiseInst *PI) {
480 // The coro.frame intrinsic is always lowered to the result of coro.begin.
481 for (CoroFrameInst *CF : CoroFrames) {
482 CF->replaceAllUsesWith(CoroBegin);
483 CF->eraseFromParent();
484 }
485 CoroFrames.clear();
486
487 // Remove orphaned coro.saves.
488 for (CoroSaveInst *CoroSave : UnusedCoroSaves)
489 CoroSave->eraseFromParent();
490 UnusedCoroSaves.clear();
491
492 if (PI) {
496 PI->eraseFromParent();
497 }
498}
499
501 Call->setCallingConv(Callee->getCallingConv());
502 // TODO: attributes?
503}
504
506 if (CG)
507 (*CG)[Call->getFunction()]->addCalledFunction(Call, (*CG)[Callee]);
508}
509
511 CallGraph *CG) const {
512 switch (ABI) {
514 llvm_unreachable("can't allocate memory in coro switch-lowering");
515
518 auto Alloc = RetconLowering.Alloc;
519 Size = Builder.CreateIntCast(Size,
520 Alloc->getFunctionType()->getParamType(0),
521 /*is signed*/ false);
522 auto *Call = Builder.CreateCall(Alloc, Size);
525 return Call;
526 }
527 case coro::ABI::Async:
528 llvm_unreachable("can't allocate memory in coro async-lowering");
529 }
530 llvm_unreachable("Unknown coro::ABI enum");
531}
532
534 CallGraph *CG) const {
535 switch (ABI) {
537 llvm_unreachable("can't allocate memory in coro switch-lowering");
538
541 auto Dealloc = RetconLowering.Dealloc;
542 Ptr = Builder.CreateBitCast(Ptr,
543 Dealloc->getFunctionType()->getParamType(0));
544 auto *Call = Builder.CreateCall(Dealloc, Ptr);
546 addCallToCallGraph(CG, Call, Dealloc);
547 return;
548 }
549 case coro::ABI::Async:
550 llvm_unreachable("can't allocate memory in coro async-lowering");
551 }
552 llvm_unreachable("Unknown coro::ABI enum");
553}
554
555[[noreturn]] static void fail(const Instruction *I, const char *Reason,
556 Value *V) {
557#ifndef NDEBUG
558 I->dump();
559 if (V) {
560 errs() << " Value: ";
561 V->printAsOperand(llvm::errs());
562 errs() << '\n';
563 }
564#endif
565 report_fatal_error(Reason);
566}
567
568/// Check that the given value is a well-formed prototype for the
569/// llvm.coro.id.retcon.* intrinsics.
571 auto F = dyn_cast<Function>(V->stripPointerCasts());
572 if (!F)
573 fail(I, "llvm.coro.id.retcon.* prototype not a Function", V);
574
575 auto FT = F->getFunctionType();
576
578 bool ResultOkay;
579 if (FT->getReturnType()->isPointerTy()) {
580 ResultOkay = true;
581 } else if (auto SRetTy = dyn_cast<StructType>(FT->getReturnType())) {
582 ResultOkay = (!SRetTy->isOpaque() &&
583 SRetTy->getNumElements() > 0 &&
584 SRetTy->getElementType(0)->isPointerTy());
585 } else {
586 ResultOkay = false;
587 }
588 if (!ResultOkay)
589 fail(I, "llvm.coro.id.retcon prototype must return pointer as first "
590 "result", F);
591
592 if (FT->getReturnType() !=
593 I->getFunction()->getFunctionType()->getReturnType())
594 fail(I, "llvm.coro.id.retcon prototype return type must be same as"
595 "current function return type", F);
596 } else {
597 // No meaningful validation to do here for llvm.coro.id.unique.once.
598 }
599
600 if (FT->getNumParams() == 0 || !FT->getParamType(0)->isPointerTy())
601 fail(I, "llvm.coro.id.retcon.* prototype must take pointer as "
602 "its first parameter", F);
603}
604
605/// Check that the given value is a well-formed allocator.
606static void checkWFAlloc(const Instruction *I, Value *V) {
607 auto F = dyn_cast<Function>(V->stripPointerCasts());
608 if (!F)
609 fail(I, "llvm.coro.* allocator not a Function", V);
610
611 auto FT = F->getFunctionType();
612 if (!FT->getReturnType()->isPointerTy())
613 fail(I, "llvm.coro.* allocator must return a pointer", F);
614
615 if (FT->getNumParams() != 1 ||
616 !FT->getParamType(0)->isIntegerTy())
617 fail(I, "llvm.coro.* allocator must take integer as only param", F);
618}
619
620/// Check that the given value is a well-formed deallocator.
621static void checkWFDealloc(const Instruction *I, Value *V) {
622 auto F = dyn_cast<Function>(V->stripPointerCasts());
623 if (!F)
624 fail(I, "llvm.coro.* deallocator not a Function", V);
625
626 auto FT = F->getFunctionType();
627 if (!FT->getReturnType()->isVoidTy())
628 fail(I, "llvm.coro.* deallocator must return void", F);
629
630 if (FT->getNumParams() != 1 ||
631 !FT->getParamType(0)->isPointerTy())
632 fail(I, "llvm.coro.* deallocator must take pointer as only param", F);
633}
634
635static void checkConstantInt(const Instruction *I, Value *V,
636 const char *Reason) {
637 if (!isa<ConstantInt>(V)) {
638 fail(I, Reason, V);
639 }
640}
641
643 checkConstantInt(this, getArgOperand(SizeArg),
644 "size argument to coro.id.retcon.* must be constant");
645 checkConstantInt(this, getArgOperand(AlignArg),
646 "alignment argument to coro.id.retcon.* must be constant");
647 checkWFRetconPrototype(this, getArgOperand(PrototypeArg));
648 checkWFAlloc(this, getArgOperand(AllocArg));
649 checkWFDealloc(this, getArgOperand(DeallocArg));
650}
651
652static void checkAsyncFuncPointer(const Instruction *I, Value *V) {
653 auto *AsyncFuncPtrAddr = dyn_cast<GlobalVariable>(V->stripPointerCasts());
654 if (!AsyncFuncPtrAddr)
655 fail(I, "llvm.coro.id.async async function pointer not a global", V);
656}
657
659 checkConstantInt(this, getArgOperand(SizeArg),
660 "size argument to coro.id.async must be constant");
661 checkConstantInt(this, getArgOperand(AlignArg),
662 "alignment argument to coro.id.async must be constant");
663 checkConstantInt(this, getArgOperand(StorageArg),
664 "storage argument offset to coro.id.async must be constant");
665 checkAsyncFuncPointer(this, getArgOperand(AsyncFuncPtrArg));
666}
667
669 Function *F) {
670 auto *FunTy = F->getFunctionType();
671 if (!FunTy->getReturnType()->isPointerTy())
672 fail(I,
673 "llvm.coro.suspend.async resume function projection function must "
674 "return a ptr type",
675 F);
676 if (FunTy->getNumParams() != 1 || !FunTy->getParamType(0)->isPointerTy())
677 fail(I,
678 "llvm.coro.suspend.async resume function projection function must "
679 "take one ptr type as parameter",
680 F);
681}
682
686
688 auto *MustTailCallFunc = getMustTailCallFunction();
689 if (!MustTailCallFunc)
690 return;
691 auto *FnTy = MustTailCallFunc->getFunctionType();
692 if (FnTy->getNumParams() != (arg_size() - 3))
693 fail(this,
694 "llvm.coro.end.async must tail call function argument type must "
695 "match the tail arguments",
696 MustTailCallFunc);
697}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Expand Atomic instructions
This file contains the simple types necessary to represent the attributes associated with functions a...
static void fail(const SDLoc &DL, SelectionDAG &DAG, const Twine &Msg, SDValue Val={})
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static Intrinsic::ID NonOverloadedCoroIntrinsics[]
static void checkWFDealloc(const Instruction *I, Value *V)
Check that the given value is a well-formed deallocator.
static void checkConstantInt(const Instruction *I, Value *V, const char *Reason)
static void checkWFRetconPrototype(const AnyCoroIdRetconInst *I, Value *V)
Check that the given value is a well-formed prototype for the llvm.coro.id.retcon.
static void propagateCallAttrsFromCallee(CallInst *Call, Function *Callee)
static void checkAsyncContextProjectFunction(const Instruction *I, Function *F)
static CoroSaveInst * createCoroSave(CoroBeginInst *CoroBegin, CoroSuspendInst *SuspendInst)
static void checkWFAlloc(const Instruction *I, Value *V)
Check that the given value is a well-formed allocator.
static void addCallToCallGraph(CallGraph *CG, CallInst *Call, Function *Callee)
static void checkAsyncFuncPointer(const Instruction *I, Value *V)
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
uint64_t IntrinsicInst * II
This file defines the SmallVector class.
static const unsigned FramePtr
This represents either the llvm.coro.id.retcon or llvm.coro.id.retcon.once instruction.
Definition CoroInstr.h:237
LLVM_ABI void checkWellFormed() const
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
size - Get the array size.
Definition ArrayRef.h:142
LLVM Basic Block Representation.
Definition BasicBlock.h:62
const Instruction & front() const
Definition BasicBlock.h:484
This class represents a no-op cast from one type to another.
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
unsigned arg_size() const
The basic data container for the call graph of a Module of IR.
Definition CallGraph.h:72
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static LLVM_ABI bool isBitCastable(Type *SrcTy, Type *DestTy)
Check whether a bitcast between these types is valid.
static LLVM_ABI ConstantInt * getFalse(LLVMContext &Context)
A constant pointer value that points to null.
Definition Constants.h:701
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
Function * getMustTailCallFunction() const
Definition CoroInstr.h:754
LLVM_ABI void checkWellFormed() const
This class represents the llvm.coro.begin or llvm.coro.begin.custom.abi instructions.
Definition CoroInstr.h:475
This represents the llvm.coro.frame instruction.
Definition CoroInstr.h:420
This represents the llvm.coro.free instruction.
Definition CoroInstr.h:444
LLVM_ABI void checkWellFormed() const
This represents the llvm.coro.id instruction.
Definition CoroInstr.h:148
This represents the llvm.coro.promise instruction.
Definition CoroInstr.h:516
bool isFromPromise() const
Are we translating from the frame to the promise (false) or from the promise to the frame (true)?
Definition CoroInstr.h:522
This represents the llvm.coro.save instruction.
Definition CoroInstr.h:504
Function * getAsyncContextProjectionFunction() const
Definition CoroInstr.h:605
LLVM_ABI void checkWellFormed() const
This represents the llvm.coro.suspend instruction.
Definition CoroInstr.h:557
CoroSaveInst * getCoroSave() const
Definition CoroInstr.h:561
Class to represent function types.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2811
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
Class to represent pointers.
static LLVM_ABI PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:311
bool isVoidTy() const
Return true if this is 'void'.
Definition Type.h:141
LLVM Value Representation.
Definition Value.h:75
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
LLVMContext & getContext() const
All values hold a context through their type.
Definition Value.h:259
iterator_range< user_iterator > users()
Definition Value.h:427
void init() override
coro::Shape & Shape
Definition ABI.h:60
void init() override
self_iterator getIterator()
Definition ilist_node.h:123
CallInst * Call
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
LLVM_ABI Function * getDeclarationIfExists(const Module *M, ID id)
Look up the Function declaration of the intrinsic id in the Module M and return it if it exists.
LLVM_ABI bool isOverloaded(ID id)
Returns true if the intrinsic can be overloaded.
@ Async
The "async continuation" lowering, where each suspend point creates a single continuation function.
Definition CoroShape.h:48
@ RetconOnce
The "unique returned-continuation" lowering, where each suspend point creates a single continuation f...
Definition CoroShape.h:43
@ Retcon
The "returned-continuation" lowering, where each suspend point creates a single continuation function...
Definition CoroShape.h:36
@ Switch
The "resume-switch" lowering, where there are separate resume and destroy functions that are shared b...
Definition CoroShape.h:31
bool declaresAnyIntrinsic(const Module &M)
bool isSuspendBlock(BasicBlock *BB)
void suppressCoroAllocs(CoroIdInst *CoroId)
Replaces all @llvm.coro.alloc intrinsics calls associated with a given call @llvm....
void elideCoroFree(Value *FramePtr)
bool declaresIntrinsics(const Module &M, ArrayRef< Intrinsic::ID > List)
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ABI unsigned changeToUnreachable(Instruction *I, bool PreserveLCSSA=false, DomTreeUpdater *DTU=nullptr, MemorySSAUpdater *MSSAU=nullptr)
Insert an unreachable instruction before the specified instruction, making it and the rest of the cod...
Definition Local.cpp:2528
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:872
PointerType *const Int8Ptr
ConstantPointerNull *const NullPtr
CallInst * makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt)
FunctionType *const ResumeFnType
SmallVector< CoroAwaitSuspendInst *, 4 > CoroAwaitSuspends
Definition CoroShape.h:60
AsyncLoweringStorage AsyncLowering
Definition CoroShape.h:142
LLVM_ABI void cleanCoroutine(SmallVectorImpl< CoroFrameInst * > &CoroFrames, SmallVectorImpl< CoroSaveInst * > &UnusedCoroSaves, CoroPromiseInst *CoroPromise)
AnyCoroIdRetconInst * getRetconCoroId() const
Definition CoroShape.h:150
CoroIdInst * getSwitchCoroId() const
Definition CoroShape.h:145
SmallVector< CoroSizeInst *, 2 > CoroSizes
Definition CoroShape.h:57
LLVM_ABI void analyze(Function &F, SmallVectorImpl< CoroFrameInst * > &CoroFrames, SmallVectorImpl< CoroSaveInst * > &UnusedCoroSaves, CoroPromiseInst *&CoroPromise)
coro::ABI ABI
Definition CoroShape.h:98
SmallVector< AnyCoroSuspendInst *, 4 > CoroSuspends
Definition CoroShape.h:59
LLVM_ABI Value * emitAlloc(IRBuilder<> &Builder, Value *Size, CallGraph *CG) const
Allocate memory according to the rules of the active lowering.
AllocaInst * getPromiseAlloca() const
Definition CoroShape.h:226
SwitchLoweringStorage SwitchLowering
Definition CoroShape.h:140
CoroBeginInst * CoroBegin
Definition CoroShape.h:54
SmallVector< CoroIsInRampInst *, 2 > CoroIsInRampInsts
Definition CoroShape.h:56
LLVM_ABI void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const
Deallocate memory according to the rules of the active lowering.
RetconLoweringStorage RetconLowering
Definition CoroShape.h:141
SmallVector< CoroAlignInst *, 2 > CoroAligns
Definition CoroShape.h:58
CoroIdAsyncInst * getAsyncCoroId() const
Definition CoroShape.h:155
SmallVector< AnyCoroEndInst *, 4 > CoroEnds
Definition CoroShape.h:55
LLVM_ABI void invalidateCoroutine(Function &F, SmallVectorImpl< CoroFrameInst * > &CoroFrames)