@@ -25,8 +25,10 @@ class Lowerer : public coro::LowererBase {
25
25
IRBuilder<> Builder;
26
26
PointerType *const AnyResumeFnPtrTy;
27
27
Constant *NoopCoro = nullptr ;
28
+ SmallVector<CoroFrameInst *, 8 > CoroFrames;
28
29
29
30
void lowerResumeOrDestroy (CallBase &CB, CoroSubFnInst::ResumeKind);
31
+ void lowerCoroFrames (Function &F, Value *CoroBegin);
30
32
void lowerCoroPromise (CoroPromiseInst *Intrin);
31
33
void lowerCoroDone (IntrinsicInst *II);
32
34
void lowerCoroNoop (IntrinsicInst *II);
@@ -50,6 +52,18 @@ void Lowerer::lowerResumeOrDestroy(CallBase &CB,
50
52
CB.setCallingConv (CallingConv::Fast);
51
53
}
52
54
55
+ void Lowerer::lowerCoroFrames (Function &F, Value *CoroBegin) {
56
+ // Lower with poison if we cannot func coro.begin
57
+ if (CoroBegin == nullptr )
58
+ CoroBegin = PoisonValue::get (PointerType::get (F.getContext (), 0 ));
59
+
60
+ for (CoroFrameInst *CF : CoroFrames) {
61
+ CF->replaceAllUsesWith (CoroBegin);
62
+ CF->eraseFromParent ();
63
+ }
64
+ CoroFrames.clear ();
65
+ }
66
+
53
67
// Coroutine promise field is always at the fixed offset from the beginning of
54
68
// the coroutine frame. i8* coro.promise(i8*, i1 from) intrinsic adds an offset
55
69
// to a passed pointer to move from coroutine frame to coroutine promise and
@@ -165,6 +179,7 @@ static void setCannotDuplicate(CoroIdInst *CoroId) {
165
179
166
180
void Lowerer::lowerEarlyIntrinsics (Function &F) {
167
181
CoroIdInst *CoroId = nullptr ;
182
+ CoroBeginInst *CoroBegin = nullptr ;
168
183
SmallVector<CoroFreeInst *, 4 > CoroFrees;
169
184
bool HasCoroSuspend = false ;
170
185
for (Instruction &I : llvm::make_early_inc_range (instructions (F))) {
@@ -175,6 +190,26 @@ void Lowerer::lowerEarlyIntrinsics(Function &F) {
175
190
switch (CB->getIntrinsicID ()) {
176
191
default :
177
192
continue ;
193
+ case Intrinsic::coro_begin:
194
+ case Intrinsic::coro_begin_custom_abi: {
195
+ auto CBI = cast<CoroBeginInst>(&I);
196
+
197
+ // Ignore coro id's that aren't pre-split.
198
+ auto Id = dyn_cast<CoroIdInst>(CBI->getId ());
199
+ if (Id && !Id->getInfo ().isPreSplit ())
200
+ break ;
201
+
202
+ if (CoroBegin)
203
+ report_fatal_error (
204
+ " coroutine should have exactly one defining @llvm.coro.begin" );
205
+ CBI->addRetAttr (Attribute::NonNull);
206
+ CBI->addRetAttr (Attribute::NoAlias);
207
+ CoroBegin = CBI;
208
+ break ;
209
+ }
210
+ case Intrinsic::coro_frame:
211
+ CoroFrames.push_back (cast<CoroFrameInst>(&I));
212
+ break ;
178
213
case Intrinsic::coro_free:
179
214
CoroFrees.push_back (cast<CoroFreeInst>(&I));
180
215
break ;
@@ -226,6 +261,8 @@ void Lowerer::lowerEarlyIntrinsics(Function &F) {
226
261
break ;
227
262
}
228
263
}
264
+ // The coro.frame intrinsic is always lowered to the result of coro.begin.
265
+ lowerCoroFrames (F, CoroBegin);
229
266
230
267
// Make sure that all CoroFree reference the coro.id intrinsic.
231
268
// Token type is not exposed through coroutine C/C++ builtins to plain C, so
@@ -246,10 +283,10 @@ void Lowerer::lowerEarlyIntrinsics(Function &F) {
246
283
static bool declaresCoroEarlyIntrinsics (const Module &M) {
247
284
return coro::declaresIntrinsics (
248
285
M, {" llvm.coro.id" , " llvm.coro.id.retcon" , " llvm.coro.id.retcon.once" ,
249
- " llvm.coro.id.async" , " llvm.coro.destroy " , " llvm.coro.done " ,
250
- " llvm.coro.end " , " llvm.coro.end.async " , " llvm.coro.noop " ,
251
- " llvm.coro.free " , " llvm.coro.promise " , " llvm.coro.resume " ,
252
- " llvm.coro.suspend" });
286
+ " llvm.coro.id.async" , " llvm.coro.begin " , " llvm.coro.destroy " ,
287
+ " llvm.coro.done " , " llvm.coro.end" , " llvm.coro.end.async " ,
288
+ " llvm.coro.noop " , " llvm.coro.frame " , " llvm.coro.free " ,
289
+ " llvm.coro.promise " , " llvm.coro.resume " , " llvm.coro. suspend" });
253
290
}
254
291
255
292
PreservedAnalyses CoroEarlyPass::run (Module &M, ModuleAnalysisManager &) {
0 commit comments