LLVM: lib/Transforms/Coroutines/CoroEarly.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
17
18using namespace llvm;
19
20#define DEBUG_TYPE "coro-early"
21
22namespace {
23
28
34
35public:
37 : LowererBase(M), Builder(Context),
39 void lowerEarlyIntrinsics(Function &F);
40};
41}
42
43
44
45
46
47void Lowerer::lowerResumeOrDestroy(CallBase &CB,
52}
53
54
55
56
57
58
59
60
61void Lowerer::lowerCoroPromise(CoroPromiseInst *Intrin) {
65
66 auto *SampleStruct =
68 const DataLayout &DL = TheModule.getDataLayout();
70 DL.getStructLayout(SampleStruct)->getElementOffset(2), Alignment);
73
75 Value *Replacement =
77
80}
81
82
83
84
85
86void Lowerer::lowerCoroDone(IntrinsicInst *II) {
87 Value *Operand = II->getArgOperand(0);
88
89
91 "resume function not at offset zero");
92 auto *FrameTy = Int8Ptr;
93
97
98 II->replaceAllUsesWith(Cond);
99 II->eraseFromParent();
100}
101
104 if (M.debug_compile_units().empty())
105 return;
106
108 DIBuilder DB(M, false, CU);
109 std::array<Metadata *, 2> Params{nullptr, nullptr};
110 auto *SubroutineType =
111 DB.createSubroutineType(DB.getOrCreateTypeArray(Params));
113 auto *SP = DB.createFunction(
114 CU, Name, Name, CU->getFile(),
115 0, SubroutineType, 0, DINode::FlagArtificial,
116 DISubprogram::SPFlagDefinition);
118 DB.finalize();
119}
120
121void Lowerer::lowerCoroNoop(IntrinsicInst *II) {
122 if (!NoopCoro) {
125
126
127 auto *FnTy = FunctionType::get(Type::getVoidTy(C), Builder.getPtrTy(0),
128 false);
129 auto *FnPtrTy = Builder.getPtrTy(0);
130 StructType *FrameTy =
132
133
135 FnTy, GlobalValue::LinkageTypes::InternalLinkage,
136 M.getDataLayout().getProgramAddressSpace(), "__NoopCoro_ResumeDestroy",
137 &M);
138 NoopFn->setCallingConv(CallingConv::Fast);
142
143
144 Constant* Values[] = {NoopFn, NoopFn};
146 NoopCoro = new GlobalVariable(M, NoopCoroConst->getType(), true,
147 GlobalVariable::PrivateLinkage, NoopCoroConst,
148 "NoopCoro.Frame.Const");
150 }
151
153 auto *NoopCoroVoidPtr = Builder.CreateBitCast(NoopCoro, Int8Ptr);
154 II->replaceAllUsesWith(NoopCoroVoidPtr);
155 II->eraseFromParent();
156}
157
158
159
160
161void Lowerer::hidePromiseAlloca(CoroIdInst *CoroId, CoroBeginInst *CoroBegin) {
163 if (!PA || !CoroBegin)
164 return;
166
167 auto *Alignment = Builder.getInt32(PA->getAlign().value());
168 auto *FromPromise = Builder.getInt1(false);
171 Builder.getPtrTy(), Intrinsic::coro_promise, Arg, {}, "promise.addr");
173
176 if (I->isLifetimeStartOrEnd())
177 I->eraseFromParent();
178 }
179 PA->replaceUsesWithIf(PI, [CoroId](Use &U) {
180 bool IsBitcast = U == U.getUser()->stripPointerCasts();
181 bool IsCoroId = U.getUser() == CoroId;
182 return !IsBitcast && !IsCoroId;
183 });
184}
185
186
187
188
189
195
196void Lowerer::lowerEarlyIntrinsics(Function &F) {
197 CoroIdInst *CoroId = nullptr;
198 CoroBeginInst *CoroBegin = nullptr;
200 bool HasCoroSuspend = false;
203 if (!CB)
204 continue;
205
207 default:
208 continue;
209 case Intrinsic::coro_begin:
210 case Intrinsic::coro_begin_custom_abi:
211 if (CoroBegin)
213 "coroutine should have exactly one defining @llvm.coro.begin");
215 break;
216 case Intrinsic::coro_free:
218 break;
219 case Intrinsic::coro_suspend:
220
221
224 HasCoroSuspend = true;
225 break;
226 case Intrinsic::coro_end_async:
227 case Intrinsic::coro_end:
228
229
232 break;
233 case Intrinsic::coro_noop:
235 break;
236 case Intrinsic::coro_id:
238 if (CII->getInfo().isPreSplit()) {
239 assert(F.isPresplitCoroutine() &&
240 "The frontend uses Switch-Resumed ABI should emit "
241 "\"presplitcoroutine\" attribute for the coroutine.");
243 CII->setCoroutineSelf();
245 }
246 }
247 break;
248 case Intrinsic::coro_id_retcon:
249 case Intrinsic::coro_id_retcon_once:
250 case Intrinsic::coro_id_async:
251 F.setPresplitCoroutine();
252 break;
253 case Intrinsic::coro_resume:
255 break;
256 case Intrinsic::coro_destroy:
258 break;
259 case Intrinsic::coro_promise:
261 break;
262 case Intrinsic::coro_done:
264 break;
265 }
266 }
267
268 if (CoroId) {
269
270
271
272 for (CoroFreeInst *CF : CoroFrees)
273 CF->setArgOperand(0, CoroId);
274
275 hidePromiseAlloca(CoroId, CoroBegin);
276 }
277
278
279
280
281 if (HasCoroSuspend)
282 for (Argument &A : F.args())
283 if (A.hasNoAliasAttr())
284 A.removeAttr(Attribute::NoAlias);
285}
286
288
290 M, {Intrinsic::coro_id, Intrinsic::coro_id_retcon,
291 Intrinsic::coro_id_retcon_once, Intrinsic::coro_id_async,
292 Intrinsic::coro_destroy, Intrinsic::coro_done, Intrinsic::coro_end,
293 Intrinsic::coro_end_async, Intrinsic::coro_noop, Intrinsic::coro_free,
294 Intrinsic::coro_promise, Intrinsic::coro_resume});
295}
296
300
301 Lowerer L(M);
302 for (auto &F : M)
303 L.lowerEarlyIntrinsics(F);
304
307 return PA;
308}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static void setCannotDuplicate(CoroIdInst *CoroId)
Definition CoroEarly.cpp:190
static bool declaresCoroEarlyIntrinsics(const Module &M)
Definition CoroEarly.cpp:287
static void buildDebugInfoForNoopResumeDestroyFunc(Function *NoopFn)
Definition CoroEarly.cpp:102
Module.h This file contains the declarations for the Module class.
Machine Check Debug Module
uint64_t IntrinsicInst * II
const SmallVectorImpl< MachineOperand > & Cond
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()
LLVM_ABI 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 LLVM_ABI Constant * get(StructType *T, ArrayRef< Constant * > V)
This is an important base class in LLVM.
This class represents the llvm.coro.begin or llvm.coro.begin.custom.abi instructions.
This represents the llvm.coro.id instruction.
AllocaInst * getPromise() const
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)?
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...
ConstantInt * getInt1(bool V)
Get a constant value representing either true or false.
Value * CreateConstInBoundsGEP1_32(Type *Ty, Value *Ptr, unsigned Idx0, const Twine &Name="")
LLVM_ABI CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="")
Create a call to intrinsic ID with Args, mangled using Types.
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Value * CreateICmpEQ(Value *LHS, Value *RHS, const Twine &Name="")
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
LLVMContext & getContext() const
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
IntegerType * getInt8Ty()
Fetch the type representing an 8-bit integer.
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.
LLVM_ABI std::optional< InstListType::iterator > getInsertionPointAfterDef()
Get the first insertion point at which the result of this instruction is defined.
A wrapper class for inspecting calls to intrinsic functions.
A Module instance is used to store all the information related to an LLVM module.
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
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.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)
void push_back(const T &Elt)
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.
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.
iterator_range< user_iterator > users()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
@ C
The default llvm calling convention, compatible with C.
bool declaresIntrinsics(const Module &M, ArrayRef< Intrinsic::ID > List)
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
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...
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
decltype(auto) cast(const From &Val)
cast - Return the argument parameter cast to the specified type.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
Definition CoroEarly.cpp:297