19#define DEBUG_TYPE "coro-early"
35 : LowererBase(M), Builder(Context),
47void Lowerer::lowerResumeOrDestroy(
CallBase &CB,
70 DL.getStructLayout(SampleStruct)->getElementOffset(2), Alignment);
74 Builder.SetInsertPoint(Intrin);
76 Builder.CreateConstInBoundsGEP1_32(Int8Ty, Operand,
Offset);
87 Value *Operand =
II->getArgOperand(0);
91 "resume function not at offset zero");
92 auto *FrameTy = Int8Ptr;
95 Builder.SetInsertPoint(
II);
96 auto *BCI = Builder.CreateBitCast(Operand, FramePtrTy);
97 auto *
Load = Builder.CreateLoad(FrameTy, BCI);
98 auto *
Cond = Builder.CreateICmpEQ(Load, NullPtr);
100 II->replaceAllUsesWith(
Cond);
101 II->eraseFromParent();
106 if (M.debug_compile_units().empty())
111 std::array<Metadata *, 2> Params{
nullptr,
nullptr};
112 auto *SubroutineType =
113 DB.createSubroutineType(DB.getOrCreateTypeArray(Params));
115 auto *SP = DB.createFunction(
117 0, SubroutineType, 0, DINode::FlagArtificial,
118 DISubprogram::SPFlagDefinition);
133 auto *FnPtrTy = FnTy->getPointerTo();
134 FrameTy->
setBody({FnPtrTy, FnPtrTy});
139 "__NoopCoro_ResumeDestroy", &M);
146 Constant* Values[] = {NoopFn, NoopFn};
149 GlobalVariable::PrivateLinkage, NoopCoroConst,
150 "NoopCoro.Frame.Const");
151 cast<GlobalVariable>(NoopCoro)->setNoSanitizeMetadata();
154 Builder.SetInsertPoint(
II);
155 auto *NoopCoroVoidPtr = Builder.CreateBitCast(NoopCoro, Int8Ptr);
156 II->replaceAllUsesWith(NoopCoroVoidPtr);
157 II->eraseFromParent();
166 if (
auto *CB = dyn_cast<CoroBeginInst>(U))
170void Lowerer::lowerEarlyIntrinsics(
Function &
F) {
173 bool HasCoroSuspend =
false;
175 auto *CB = dyn_cast<CallBase>(&
I);
182 case Intrinsic::coro_free:
185 case Intrinsic::coro_suspend:
188 if (cast<CoroSuspendInst>(&
I)->isFinal())
190 HasCoroSuspend =
true;
192 case Intrinsic::coro_end_async:
193 case Intrinsic::coro_end:
196 if (cast<AnyCoroEndInst>(&
I)->isFallthrough())
199 case Intrinsic::coro_noop:
200 lowerCoroNoop(cast<IntrinsicInst>(&
I));
202 case Intrinsic::coro_id:
203 if (
auto *CII = cast<CoroIdInst>(&
I)) {
204 if (CII->getInfo().isPreSplit()) {
205 assert(
F.isPresplitCoroutine() &&
206 "The frontend uses Swtich-Resumed ABI should emit "
207 "\"presplitcoroutine\" attribute for the coroutine.");
209 CII->setCoroutineSelf();
210 CoroId = cast<CoroIdInst>(&
I);
214 case Intrinsic::coro_id_retcon:
215 case Intrinsic::coro_id_retcon_once:
216 case Intrinsic::coro_id_async:
217 F.setPresplitCoroutine();
219 case Intrinsic::coro_resume:
222 case Intrinsic::coro_destroy:
225 case Intrinsic::coro_promise:
226 lowerCoroPromise(cast<CoroPromiseInst>(&
I));
228 case Intrinsic::coro_done:
229 lowerCoroDone(cast<IntrinsicInst>(&
I));
239 CF->setArgOperand(0, CoroId);
246 if (
A.hasNoAliasAttr())
247 A.removeAttr(Attribute::NoAlias);
252 M, {
"llvm.coro.id",
"llvm.coro.id.retcon",
"llvm.coro.id.retcon.once",
253 "llvm.coro.id.async",
"llvm.coro.destroy",
"llvm.coro.done",
254 "llvm.coro.end",
"llvm.coro.end.async",
"llvm.coro.noop",
255 "llvm.coro.free",
"llvm.coro.promise",
"llvm.coro.resume",
256 "llvm.coro.suspend"});
265 L.lowerEarlyIntrinsics(
F);
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static void setCannotDuplicate(CoroIdInst *CoroId)
static bool declaresCoroEarlyIntrinsics(const Module &M)
static void buildDebugInfoForNoopResumeDestroyFunc(Function *NoopFn)
Module.h This file contains the declarations for the Module class.
uint64_t IntrinsicInst * II
const SmallVectorImpl< MachineOperand > & Cond
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A container for analyses that lazily runs them and caches their results.
This class represents an incoming formal argument to a Function.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Represents analyses that only rely on functions' control flow.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void setCallingConv(CallingConv::ID CC)
Value * getArgOperand(unsigned i) const
void setCannotDuplicate()
Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
void setCalledOperand(Value *V)
static Constant * get(StructType *T, ArrayRef< Constant * > V)
This is an important base class in LLVM.
This represents the llvm.coro.free instruction.
This represents the llvm.coro.id instruction.
This represents the llvm.coro.promise instruction.
Align getAlignment() const
The required alignment of the promise.
bool isFromPromise() const
Are we translating from the frame to the promise (false) or from the promise to the frame (true)?
A parsed version of the target data layout string in and methods for querying it.
void setSubprogram(DISubprogram *SP)
Set the attached subprogram.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
void setCallingConv(CallingConv::ID CC)
Module * getParent()
Get the module that this global value is contained inside of...
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
A Module instance is used to store all the information related to an LLVM module.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void preserveSet()
Mark an analysis set as preserved.
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Class to represent struct types.
static StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
void setBody(ArrayRef< Type * > Elements, bool isPacked=false)
Specify a body for an opaque identified type.
static StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
The instances of the Type class are immutable: once they are created, they are never changed.
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
static Type * getVoidTy(LLVMContext &C)
static IntegerType * getInt8Ty(LLVMContext &C)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
StringRef getName() const
Return a constant reference to the value's name.
@ Fast
Attempts to make calls as fast as possible (e.g.
@ C
The default llvm calling convention, compatible with C.
bool declaresIntrinsics(const Module &M, const std::initializer_list< StringRef >)
This is an optimization pass for GlobalISel generic memory operations.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
This struct is a compact representation of a valid (non-zero power of two) alignment.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)