@@ -177,17 +177,6 @@ void coro::suppressCoroAllocs(LLVMContext &Context,
177
177
}
178
178
}
179
179
180
- static void clear (coro::Shape &Shape) {
181
- Shape.CoroBegin = nullptr ;
182
- Shape.CoroEnds .clear ();
183
- Shape.CoroSizes .clear ();
184
- Shape.CoroSuspends .clear ();
185
-
186
- Shape.FrameTy = nullptr ;
187
- Shape.FramePtr = nullptr ;
188
- Shape.AllocaSpillBlock = nullptr ;
189
- }
190
-
191
180
static CoroSaveInst *createCoroSave (CoroBeginInst *CoroBegin,
192
181
CoroSuspendInst *SuspendInst) {
193
182
Module *M = SuspendInst->getModule ();
@@ -200,13 +189,12 @@ static CoroSaveInst *createCoroSave(CoroBeginInst *CoroBegin,
200
189
}
201
190
202
191
// Collect "interesting" coroutine intrinsics.
203
- void coro::Shape::buildFrom (Function &F) {
192
+ void coro::Shape::analyze (Function &F) {
193
+ clear ();
194
+
204
195
bool HasFinalSuspend = false ;
205
196
bool HasUnwindCoroEnd = false ;
206
197
size_t FinalSuspendIndex = 0 ;
207
- clear (*this );
208
- SmallVector<CoroFrameInst *, 8 > CoroFrames;
209
- SmallVector<CoroSaveInst *, 2 > UnusedCoroSaves;
210
198
211
199
for (Instruction &I : instructions (F)) {
212
200
// FIXME: coro_await_suspend_* are not proper `IntrinisicInst`s
@@ -298,8 +286,58 @@ void coro::Shape::buildFrom(Function &F) {
298
286
}
299
287
}
300
288
301
- // If for some reason, we were not able to find coro.begin, bailout.
302
- if (!CoroBegin) {
289
+ // If there is no CoroBegin then this is not a coroutine.
290
+ if (!CoroBegin)
291
+ return ;
292
+
293
+ // Determination of ABI and initializing lowering info
294
+ auto Id = CoroBegin->getId ();
295
+ auto IntrID = Id->getIntrinsicID ();
296
+ if (IntrID == Intrinsic::coro_id) {
297
+ ABI = coro::ABI::Switch;
298
+ SwitchLowering.HasFinalSuspend = HasFinalSuspend;
299
+ SwitchLowering.HasUnwindCoroEnd = HasUnwindCoroEnd;
300
+
301
+ auto SwitchId = getSwitchCoroId ();
302
+ SwitchLowering.ResumeSwitch = nullptr ;
303
+ SwitchLowering.PromiseAlloca = SwitchId->getPromise ();
304
+ SwitchLowering.ResumeEntryBlock = nullptr ;
305
+
306
+ // Move final suspend to the last element in the CoroSuspends vector.
307
+ if (SwitchLowering.HasFinalSuspend &&
308
+ FinalSuspendIndex != CoroSuspends.size () - 1 )
309
+ std::swap (CoroSuspends[FinalSuspendIndex], CoroSuspends.back ());
310
+ } else if (IntrID == Intrinsic::coro_id_async) {
311
+ ABI = coro::ABI::Async;
312
+ auto *AsyncId = getAsyncCoroId ();
313
+ AsyncId->checkWellFormed ();
314
+ AsyncLowering.Context = AsyncId->getStorage ();
315
+ AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex ();
316
+ AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize ();
317
+ AsyncLowering.ContextAlignment = AsyncId->getStorageAlignment ().value ();
318
+ AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer ();
319
+ AsyncLowering.AsyncCC = F.getCallingConv ();
320
+ } else if (IntrID == Intrinsic::coro_id_retcon ||
321
+ IntrID == Intrinsic::coro_id_retcon_once) {
322
+ ABI = IntrID == Intrinsic::coro_id_retcon ? coro::ABI::Retcon
323
+ : coro::ABI::RetconOnce;
324
+ auto ContinuationId = getRetconCoroId ();
325
+ ContinuationId->checkWellFormed ();
326
+ auto Prototype = ContinuationId->getPrototype ();
327
+ RetconLowering.ResumePrototype = Prototype;
328
+ RetconLowering.Alloc = ContinuationId->getAllocFunction ();
329
+ RetconLowering.Dealloc = ContinuationId->getDeallocFunction ();
330
+ RetconLowering.ReturnBlock = nullptr ;
331
+ RetconLowering.IsFrameInlineInStorage = false ;
332
+ } else {
333
+ llvm_unreachable (" coro.begin is not dependent on a coro.id call" );
334
+ }
335
+ }
336
+
337
+ // If for some reason, we were not able to find coro.begin, bailout.
338
+ void coro::Shape::invalidateCoroutine (Function &F) {
339
+ assert (!CoroBegin);
340
+ {
303
341
// Replace coro.frame which are supposed to be lowered to the result of
304
342
// coro.begin with undef.
305
343
auto *Undef = UndefValue::get (PointerType::get (F.getContext (), 0 ));
@@ -320,21 +358,13 @@ void coro::Shape::buildFrom(Function &F) {
320
358
// Replace all coro.ends with unreachable instruction.
321
359
for (AnyCoroEndInst *CE : CoroEnds)
322
360
changeToUnreachable (CE);
323
-
324
- return ;
325
361
}
362
+ }
326
363
327
- auto Id = CoroBegin->getId ();
328
- switch (auto IdIntrinsic = Id->getIntrinsicID ()) {
329
- case Intrinsic::coro_id: {
330
- auto SwitchId = cast<CoroIdInst>(Id);
331
- this ->ABI = coro::ABI::Switch;
332
- this ->SwitchLowering .HasFinalSuspend = HasFinalSuspend;
333
- this ->SwitchLowering .HasUnwindCoroEnd = HasUnwindCoroEnd;
334
- this ->SwitchLowering .ResumeSwitch = nullptr ;
335
- this ->SwitchLowering .PromiseAlloca = SwitchId->getPromise ();
336
- this ->SwitchLowering .ResumeEntryBlock = nullptr ;
337
-
364
+ // Perform semantic checking and initialization of the ABI
365
+ void coro::Shape::initABI () {
366
+ switch (ABI) {
367
+ case coro::ABI::Switch: {
338
368
for (auto *AnySuspend : CoroSuspends) {
339
369
auto Suspend = dyn_cast<CoroSuspendInst>(AnySuspend);
340
370
if (!Suspend) {
@@ -349,33 +379,11 @@ void coro::Shape::buildFrom(Function &F) {
349
379
}
350
380
break ;
351
381
}
352
- case Intrinsic::coro_id_async: {
353
- auto *AsyncId = cast<CoroIdAsyncInst>(Id);
354
- AsyncId->checkWellFormed ();
355
- this ->ABI = coro::ABI::Async;
356
- this ->AsyncLowering .Context = AsyncId->getStorage ();
357
- this ->AsyncLowering .ContextArgNo = AsyncId->getStorageArgumentIndex ();
358
- this ->AsyncLowering .ContextHeaderSize = AsyncId->getStorageSize ();
359
- this ->AsyncLowering .ContextAlignment =
360
- AsyncId->getStorageAlignment ().value ();
361
- this ->AsyncLowering .AsyncFuncPointer = AsyncId->getAsyncFunctionPointer ();
362
- this ->AsyncLowering .AsyncCC = F.getCallingConv ();
382
+ case coro::ABI::Async: {
363
383
break ;
364
384
};
365
- case Intrinsic::coro_id_retcon:
366
- case Intrinsic::coro_id_retcon_once: {
367
- auto ContinuationId = cast<AnyCoroIdRetconInst>(Id);
368
- ContinuationId->checkWellFormed ();
369
- this ->ABI = (IdIntrinsic == Intrinsic::coro_id_retcon
370
- ? coro::ABI::Retcon
371
- : coro::ABI::RetconOnce);
372
- auto Prototype = ContinuationId->getPrototype ();
373
- this ->RetconLowering .ResumePrototype = Prototype;
374
- this ->RetconLowering .Alloc = ContinuationId->getAllocFunction ();
375
- this ->RetconLowering .Dealloc = ContinuationId->getDeallocFunction ();
376
- this ->RetconLowering .ReturnBlock = nullptr ;
377
- this ->RetconLowering .IsFrameInlineInStorage = false ;
378
-
385
+ case coro::ABI::Retcon:
386
+ case coro::ABI::RetconOnce: {
379
387
// Determine the result value types, and make sure they match up with
380
388
// the values passed to the suspends.
381
389
auto ResultTys = getRetconResultTypes ();
@@ -408,7 +416,7 @@ void coro::Shape::buildFrom(Function &F) {
408
416
409
417
#ifndef NDEBUG
410
418
Suspend->dump ();
411
- Prototype ->getFunctionType ()->dump ();
419
+ RetconLowering. ResumePrototype ->getFunctionType ()->dump ();
412
420
#endif
413
421
report_fatal_error (" argument to coro.suspend.retcon does not "
414
422
" match corresponding prototype function result" );
@@ -417,14 +425,14 @@ void coro::Shape::buildFrom(Function &F) {
417
425
if (SI != SE || RI != RE) {
418
426
#ifndef NDEBUG
419
427
Suspend->dump ();
420
- Prototype ->getFunctionType ()->dump ();
428
+ RetconLowering. ResumePrototype ->getFunctionType ()->dump ();
421
429
#endif
422
430
report_fatal_error (" wrong number of arguments to coro.suspend.retcon" );
423
431
}
424
432
425
433
// Check that the result type of the suspend matches the resume types.
426
434
Type *SResultTy = Suspend->getType ();
427
- ArrayRef<Type*> SuspendResultTys;
435
+ ArrayRef<Type *> SuspendResultTys;
428
436
if (SResultTy->isVoidTy ()) {
429
437
// leave as empty array
430
438
} else if (auto SResultStructTy = dyn_cast<StructType>(SResultTy)) {
@@ -436,15 +444,15 @@ void coro::Shape::buildFrom(Function &F) {
436
444
if (SuspendResultTys.size () != ResumeTys.size ()) {
437
445
#ifndef NDEBUG
438
446
Suspend->dump ();
439
- Prototype ->getFunctionType ()->dump ();
447
+ RetconLowering. ResumePrototype ->getFunctionType ()->dump ();
440
448
#endif
441
449
report_fatal_error (" wrong number of results from coro.suspend.retcon" );
442
450
}
443
451
for (size_t I = 0 , E = ResumeTys.size (); I != E; ++I) {
444
452
if (SuspendResultTys[I] != ResumeTys[I]) {
445
453
#ifndef NDEBUG
446
454
Suspend->dump ();
447
- Prototype ->getFunctionType ()->dump ();
455
+ RetconLowering. ResumePrototype ->getFunctionType ()->dump ();
448
456
#endif
449
457
report_fatal_error (" result from coro.suspend.retcon does not "
450
458
" match corresponding prototype function param" );
@@ -453,23 +461,18 @@ void coro::Shape::buildFrom(Function &F) {
453
461
}
454
462
break ;
455
463
}
456
-
457
464
default :
458
465
llvm_unreachable (" coro.begin is not dependent on a coro.id call" );
459
466
}
467
+ }
460
468
469
+ void coro::Shape::tidyCoroutine () {
461
470
// The coro.free intrinsic is always lowered to the result of coro.begin.
462
471
for (CoroFrameInst *CF : CoroFrames) {
463
472
CF->replaceAllUsesWith (CoroBegin);
464
473
CF->eraseFromParent ();
465
474
}
466
475
467
- // Move final suspend to be the last element in the CoroSuspends vector.
468
- if (ABI == coro::ABI::Switch &&
469
- SwitchLowering.HasFinalSuspend &&
470
- FinalSuspendIndex != CoroSuspends.size () - 1 )
471
- std::swap (CoroSuspends[FinalSuspendIndex], CoroSuspends.back ());
472
-
473
476
// Remove orphaned coro.saves.
474
477
for (CoroSaveInst *CoroSave : UnusedCoroSaves)
475
478
CoroSave->eraseFromParent ();
0 commit comments