LLVM 23.0.0git
CoroCleanup.cpp
Go to the documentation of this file.
1//===- CoroCleanup.cpp - Coroutine Cleanup Pass ---------------------------===//
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
10#include "CoroInternal.h"
11#include "llvm/IR/DIBuilder.h"
12#include "llvm/IR/Function.h"
13#include "llvm/IR/IRBuilder.h"
15#include "llvm/IR/Module.h"
16#include "llvm/IR/PassManager.h"
18
19using namespace llvm;
20
21#define DEBUG_TYPE "coro-cleanup"
22
23namespace {
24// Created on demand if CoroCleanup pass has work to do.
25struct Lowerer : coro::LowererBase {
26 IRBuilder<> Builder;
27 Constant *NoopCoro = nullptr;
28
29 Lowerer(Module &M) : LowererBase(M), Builder(Context) {}
30 bool lower(Function &F);
31
32private:
33 void elideCoroNoop(IntrinsicInst *II);
34 void lowerCoroNoop(IntrinsicInst *II);
35};
36}
37
38static void lowerSubFn(IRBuilder<> &Builder, CoroSubFnInst *SubFn) {
39 Builder.SetInsertPoint(SubFn);
40 Value *FramePtr = SubFn->getFrame();
41 int Index = SubFn->getIndex();
42
43 auto *FrameTy = StructType::get(SubFn->getContext(),
44 {Builder.getPtrTy(), Builder.getPtrTy()});
45
46 Builder.SetInsertPoint(SubFn);
47 auto *Gep = Builder.CreateConstInBoundsGEP2_32(FrameTy, FramePtr, 0, Index);
48 auto *Load = Builder.CreateLoad(FrameTy->getElementType(Index), Gep);
49
50 SubFn->replaceAllUsesWith(Load);
51}
52
54 Module &M = *NoopFn->getParent();
55 if (M.debug_compile_units().empty())
56 return;
57
58 DICompileUnit *CU = *M.debug_compile_units_begin();
59 DIBuilder DB(M, /*AllowUnresolved*/ false, CU);
60 std::array<Metadata *, 2> Params{nullptr, nullptr};
61 auto *SubroutineType =
62 DB.createSubroutineType(DB.getOrCreateTypeArray(Params));
63 StringRef Name = NoopFn->getName();
64 auto *SP = DB.createFunction(
65 CU, /*Name=*/Name, /*LinkageName=*/Name, /*File=*/CU->getFile(),
66 /*LineNo=*/0, SubroutineType, /*ScopeLine=*/0, DINode::FlagArtificial,
67 DISubprogram::SPFlagDefinition);
68 NoopFn->setSubprogram(SP);
69 DB.finalize();
70}
71
72bool Lowerer::lower(Function &F) {
73 bool IsPrivateAndUnprocessed = F.isPresplitCoroutine() && F.hasLocalLinkage();
74 bool Changed = false;
75
76 SmallPtrSet<Instruction *, 8> DeadInsts{};
77 for (Instruction &I : instructions(F)) {
78 if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
79 switch (II->getIntrinsicID()) {
80 default:
81 continue;
82 case Intrinsic::coro_begin:
83 case Intrinsic::coro_begin_custom_abi:
84 II->replaceAllUsesWith(II->getArgOperand(1));
85 break;
86 case Intrinsic::coro_free:
87 II->replaceAllUsesWith(II->getArgOperand(1));
88 break;
89 case Intrinsic::coro_alloc:
90 II->replaceAllUsesWith(ConstantInt::getTrue(Context));
91 break;
92 case Intrinsic::coro_async_resume:
93 II->replaceAllUsesWith(
95 break;
96 case Intrinsic::coro_id:
97 case Intrinsic::coro_id_retcon:
98 case Intrinsic::coro_id_retcon_once:
99 case Intrinsic::coro_id_async:
100 II->replaceAllUsesWith(ConstantTokenNone::get(Context));
101 break;
102 case Intrinsic::coro_noop:
103 elideCoroNoop(II);
104 if (!II->user_empty())
105 lowerCoroNoop(II);
106 break;
107 case Intrinsic::coro_subfn_addr:
109 break;
110 case Intrinsic::coro_suspend_retcon:
111 case Intrinsic::coro_is_in_ramp:
112 if (IsPrivateAndUnprocessed) {
113 II->replaceAllUsesWith(PoisonValue::get(II->getType()));
114 } else
115 continue;
116 break;
117 case Intrinsic::coro_async_size_replace:
119 cast<GlobalVariable>(II->getArgOperand(0)->stripPointerCasts())
120 ->getInitializer());
122 cast<GlobalVariable>(II->getArgOperand(1)->stripPointerCasts())
123 ->getInitializer());
124 auto *TargetSize = Target->getOperand(1);
125 auto *SourceSize = Source->getOperand(1);
126 if (TargetSize->isElementWiseEqual(SourceSize)) {
127 break;
128 }
129 auto *TargetRelativeFunOffset = Target->getOperand(0);
130 auto *NewFuncPtrStruct = ConstantStruct::get(
131 Target->getType(), TargetRelativeFunOffset, SourceSize);
132 Target->replaceAllUsesWith(NewFuncPtrStruct);
133 break;
134 }
135 DeadInsts.insert(II);
136 Changed = true;
137 }
138 }
139
140 for (auto *I : DeadInsts)
141 I->eraseFromParent();
142 return Changed;
143}
144
145void Lowerer::elideCoroNoop(IntrinsicInst *II) {
146 for (User *U : make_early_inc_range(II->users())) {
147 auto *Fn = dyn_cast<CoroSubFnInst>(U);
148 if (Fn == nullptr)
149 continue;
150
151 auto *User = Fn->getUniqueUndroppableUser();
152 if (auto *Call = dyn_cast<CallInst>(User)) {
154 Fn->eraseFromParent();
155 continue;
156 }
157
158 if (auto *I = dyn_cast<InvokeInst>(User)) {
159 Builder.SetInsertPoint(I);
160 Builder.CreateBr(I->getNormalDest());
162 Fn->eraseFromParent();
163 }
164 }
165}
166
167void Lowerer::lowerCoroNoop(IntrinsicInst *II) {
168 if (!NoopCoro) {
169 LLVMContext &C = Builder.getContext();
170 Module &M = *II->getModule();
171
172 // Create a noop.frame struct type.
173 auto *FnTy = FunctionType::get(Type::getVoidTy(C), Builder.getPtrTy(0),
174 /*isVarArg=*/false);
175 auto *FnPtrTy = Builder.getPtrTy(0);
176 StructType *FrameTy =
177 StructType::create({FnPtrTy, FnPtrTy}, "NoopCoro.Frame");
178
179 // Create a Noop function that does nothing.
181 FnTy, GlobalValue::LinkageTypes::InternalLinkage,
182 M.getDataLayout().getProgramAddressSpace(), "__NoopCoro_ResumeDestroy",
183 &M);
184 NoopFn->setCallingConv(CallingConv::Fast);
186 auto *Entry = BasicBlock::Create(C, "entry", NoopFn);
187 ReturnInst::Create(C, Entry);
188
189 // Create a constant struct for the frame.
190 Constant *Values[] = {NoopFn, NoopFn};
191 Constant *NoopCoroConst = ConstantStruct::get(FrameTy, Values);
192 NoopCoro = new GlobalVariable(
193 M, NoopCoroConst->getType(), /*isConstant=*/true,
194 GlobalVariable::PrivateLinkage, NoopCoroConst, "NoopCoro.Frame.Const");
195 cast<GlobalVariable>(NoopCoro)->setNoSanitizeMetadata();
196 }
197
198 Builder.SetInsertPoint(II);
199 auto *NoopCoroVoidPtr = Builder.CreateBitCast(NoopCoro, Int8Ptr);
200 II->replaceAllUsesWith(NoopCoroVoidPtr);
201}
202
205 M,
206 {Intrinsic::coro_alloc, Intrinsic::coro_begin, Intrinsic::coro_subfn_addr,
207 Intrinsic::coro_free, Intrinsic::coro_id, Intrinsic::coro_id_retcon,
208 Intrinsic::coro_id_async, Intrinsic::coro_id_retcon_once,
209 Intrinsic::coro_noop, Intrinsic::coro_async_size_replace,
210 Intrinsic::coro_async_resume, Intrinsic::coro_begin_custom_abi});
211}
212
216 return PreservedAnalyses::all();
217
219 MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
220
223
224 PreservedAnalyses FuncPA;
225 FuncPA.preserveSet<CFGAnalyses>();
226
227 Lowerer L(M);
228 for (auto &F : M) {
229 if (L.lower(F)) {
230 FAM.invalidate(F, FuncPA);
231 FPM.run(F, FAM);
232 }
233 }
234
236}
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.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
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.
Definition BasicBlock.h:206
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
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.
Definition Constant.h:43
This class represents the llvm.coro.subfn.addr instruction.
Definition CoroInstr.h:36
Value * getFrame() const
Definition CoroInstr.h:49
ResumeKind getIndex() const
Definition CoroInstr.h:50
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.
Definition Function.cpp:380
Module * getParent()
Get the module that this global value is contained inside of...
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2175
LLVMContext & getContext() const
Definition IRBuilder.h:203
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
Definition IRBuilder.h:605
BranchInst * CreateBr(BasicBlock *Dest)
Create an unconditional 'br label X' instruction.
Definition IRBuilder.h:1191
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition IRBuilder.h:207
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2762
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.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
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.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)
A pass to simplify and canonicalize the CFG of a function.
Definition SimplifyCFG.h:30
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.
Definition StringRef.h:55
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.
Definition Type.cpp:413
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Definition Type.cpp:619
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
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
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:322
CallInst * Call
Changed
@ Entry
Definition COFF.h:862
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
bool declaresIntrinsics(const Module &M, ArrayRef< Intrinsic::ID > List)
@ User
could "use" a pointer
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
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...
Definition STLExtras.h:632
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.
Definition Casting.h:559
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)