23#define DEBUG_TYPE "coro-cleanup"
31 Lowerer(
Module &M) : LowererBase(M), Builder(Context) {}
49 void visitLoadInst(
LoadInst &
I) { enqueueUsers(
I); }
60 Builder.SetInsertPoint(SubFn);
65 {Builder.getPtrTy(), Builder.getPtrTy()});
67 Builder.SetInsertPoint(SubFn);
68 auto *Gep = Builder.CreateConstInBoundsGEP2_32(FrameTy,
FramePtr, 0, Index);
69 auto *Load = Builder.CreateLoad(FrameTy->getElementType(Index), Gep);
76 if (M.debug_compile_units().empty())
81 std::array<Metadata *, 2> Params{
nullptr,
nullptr};
82 auto *SubroutineType =
83 DB.createSubroutineType(DB.getOrCreateTypeArray(Params));
85 auto *SP = DB.createFunction(
86 CU, Name, Name,
CU->getFile(),
87 0, SubroutineType, 0, DINode::FlagArtificial,
88 DISubprogram::SPFlagDefinition);
94 bool IsPrivateAndUnprocessed =
F.isPresplitCoroutine() &&
F.hasLocalLinkage();
97 NoopCoroElider NCE(
F.getDataLayout(),
F.getContext());
98 SmallPtrSet<Instruction *, 8> DeadInsts{};
101 switch (
II->getIntrinsicID()) {
104 case Intrinsic::coro_begin:
105 case Intrinsic::coro_begin_custom_abi:
106 II->replaceAllUsesWith(
II->getArgOperand(1));
108 case Intrinsic::coro_free:
109 II->replaceAllUsesWith(
II->getArgOperand(1));
111 case Intrinsic::coro_alloc:
114 case Intrinsic::coro_async_resume:
115 II->replaceAllUsesWith(
118 case Intrinsic::coro_id:
119 case Intrinsic::coro_id_retcon:
120 case Intrinsic::coro_id_retcon_once:
121 case Intrinsic::coro_id_async:
124 case Intrinsic::coro_noop:
126 if (!
II->user_empty())
129 case Intrinsic::coro_subfn_addr:
132 case Intrinsic::coro_suspend_retcon:
133 case Intrinsic::coro_is_in_ramp:
134 if (IsPrivateAndUnprocessed) {
139 case Intrinsic::coro_async_size_replace:
146 auto *TargetSize =
Target->getOperand(1);
147 auto *SourceSize =
Source->getOperand(1);
148 if (TargetSize->isElementWiseEqual(SourceSize)) {
151 auto *TargetRelativeFunOffset =
Target->getOperand(0);
153 Target->getType(), TargetRelativeFunOffset, SourceSize);
154 Target->replaceAllUsesWith(NewFuncPtrStruct);
162 for (
auto *
I : DeadInsts)
163 I->eraseFromParent();
167void Lowerer::lowerCoroNoop(IntrinsicInst *
II) {
173 auto *FnTy = FunctionType::get(Type::getVoidTy(
C), Builder.
getPtrTy(0),
175 auto *FnPtrTy = Builder.
getPtrTy(0);
176 StructType *FrameTy =
181 FnTy, GlobalValue::LinkageTypes::InternalLinkage,
182 M.getDataLayout().getProgramAddressSpace(),
"__NoopCoro_ResumeDestroy",
184 NoopFn->setCallingConv(CallingConv::Fast);
190 Constant *Values[] = {NoopFn, NoopFn};
192 NoopCoro =
new GlobalVariable(
193 M, NoopCoroConst->
getType(),
true,
194 GlobalVariable::PrivateLinkage, NoopCoroConst,
"NoopCoro.Frame.Const");
199 auto *NoopCoroVoidPtr = Builder.
CreateBitCast(NoopCoro, Int8Ptr);
200 II->replaceAllUsesWith(NoopCoroVoidPtr);
203void NoopCoroElider::run(IntrinsicInst *
II) {
210void NoopCoroElider::visitCallBase(CallBase &CB) {
213 if (ResumeOrDestroy) {
214 [[maybe_unused]]
bool Success = tryEraseCallInvoke(&CB);
217 auto AboutToDeleteCallback = [
this](
Value *
V) {
221 AboutToDeleteCallback);
225void NoopCoroElider::visitIntrinsicInst(IntrinsicInst &
II) {
227 auto *
User = SubFn->getUniqueUndroppableUser();
230 SubFn->eraseFromParent();
234bool NoopCoroElider::tryEraseCallInvoke(Instruction *
I) {
236 eraseFromWorklist(
Call);
244 eraseFromWorklist(
II);
245 II->eraseFromParent();
251void NoopCoroElider::eraseFromWorklist(Instruction *
I) {
253 return I ==
U.UseAndIsOffsetKnown.getPointer()->getUser();
260 {Intrinsic::coro_alloc, Intrinsic::coro_begin, Intrinsic::coro_subfn_addr,
261 Intrinsic::coro_free, Intrinsic::coro_id, Intrinsic::coro_id_retcon,
262 Intrinsic::coro_id_async, Intrinsic::coro_id_retcon_once,
263 Intrinsic::coro_noop, Intrinsic::coro_async_size_replace,
264 Intrinsic::coro_async_resume, Intrinsic::coro_begin_custom_abi});
284 FAM.invalidate(
F, FuncPA);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static bool declaresCoroCleanupIntrinsics(const Module &M)
static void lowerSubFn(IRBuilder<> &Builder, CoroSubFnInst *SubFn)
static void buildDebugInfoForNoopResumeDestroyFunc(Function *NoopFn)
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
Machine Check Debug Module
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
This file provides a collection of visitors which walk the (instruction) uses of a pointer.
This file provides the interface for the pass responsible for both simplifying and canonicalizing the...
static const unsigned FramePtr
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...
Value * getCalledOperand() const
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
static LLVM_ABI Constant * get(StructType *T, ArrayRef< Constant * > V)
static LLVM_ABI ConstantTokenNone * get(LLVMContext &Context)
Return the ConstantTokenNone.
This is an important base class in LLVM.
This class represents the llvm.coro.subfn.addr instruction.
ResumeKind getIndex() const
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 * createWithDefaultAttr(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Creates a function with some attributes recorded in llvm.module.flags and the LLVMContext applied.
Module * getParent()
Get the module that this global value is contained inside of...
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
LLVMContext & getContext() const
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
BranchInst * CreateBr(BasicBlock *Dest)
Create an unconditional 'br label X' instruction.
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI 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.
An instruction for reading from memory.
A Module instance is used to store all the information related to an LLVM module.
LLVM_ATTRIBUTE_MINSIZE std::enable_if_t<!std::is_same_v< PassT, PassManager > > addPass(PassT &&Pass)
PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs... ExtraArgs)
Run all of the passes in this manager over the given unit of IR.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
A base class for visitors over the uses of a pointer value.
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)
A pass to simplify and canonicalize the CFG of a function.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
StringRef - Represent a constant reference to a string, i.e.
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
@ C
The default llvm calling convention, compatible with C.
bool declaresIntrinsics(const Module &M, ArrayRef< Intrinsic::ID > List)
@ User
could "use" a pointer
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
LLVM_ABI bool RecursivelyDeleteTriviallyDeadInstructions(Value *V, const TargetLibraryInfo *TLI=nullptr, MemorySSAUpdater *MSSAU=nullptr, std::function< void(Value *)> AboutToDeleteCallback=std::function< void(Value *)>())
If the specified value is a trivially dead instruction, delete it.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
PassManager< Function > FunctionPassManager
Convenience typedef for a pass manager over functions.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)