1616#include " clang/AST/StmtCXX.h"
1717#include " clang/AST/StmtVisitor.h"
1818#include " llvm/ADT/ScopeExit.h"
19+ #include " llvm/Transforms/Utils/Cloning.h"
1920
2021using namespace clang ;
2122using namespace CodeGen ;
@@ -73,6 +74,13 @@ struct clang::CodeGen::CGCoroData {
7374 // the address of the coroutine frame of the current coroutine.
7475 llvm::CallInst *CoroBegin = nullptr ;
7576
77+ // Stores the cloned cleanup block.
78+ BasicBlock *RampCleanupBB = nullptr ;
79+
80+ // Stores the llvm.coro.end that identifies if the coroutine exit without
81+ // suspend.
82+ llvm::CallInst *InRamp = nullptr ;
83+
7684 // Stores the last emitted coro.free for the deallocate expressions, we use it
7785 // to wrap dealloc code with if(auto mem = coro.free) dealloc(mem).
7886 llvm::CallInst *LastCoroFree = nullptr ;
@@ -597,7 +605,7 @@ struct CallCoroEnd final : public EHScopeStack::Cleanup {
597605namespace {
598606// Make sure to call coro.delete on scope exit.
599607struct CallCoroDelete final : public EHScopeStack::Cleanup {
600- Stmt *Deallocate ;
608+ const CoroutineBodyStmt *S ;
601609
602610 // Emit "if (coro.free(CoroId, CoroBegin)) Deallocate;"
603611
@@ -607,16 +615,54 @@ struct CallCoroDelete final : public EHScopeStack::Cleanup {
607615 // builds a single call to a deallocation function which is safe to emit
608616 // multiple times.
609617 void Emit (CodeGenFunction &CGF, Flags) override {
618+ bool Splited = CGF.CurCoro .Data ->InRamp != nullptr ;
619+ if (!Splited)
620+ splitCleanupBB (CGF);
621+ EmitCoroFree (CGF);
622+ }
623+
624+ // Clone the cleanup block for ramp function if the coroutine completes
625+ // without suspending
626+ void splitCleanupBB (CodeGenFunction &CGF) {
627+ auto &Builder = CGF.Builder ;
628+ auto &CoroData = *CGF.CurCoro .Data ;
629+ auto *SaveInsertPt = Builder.GetInsertBlock ();
630+ auto *PreCleanupBB = SaveInsertPt->getSinglePredecessor ();
631+
632+ auto *CleanupBB =
633+ PreCleanupBB->splitBasicBlock (PreCleanupBB->begin (), " coro.cleanup" );
634+
635+ PreCleanupBB->getTerminator ()->eraseFromParent ();
636+ Builder.SetInsertPoint (PreCleanupBB);
637+
638+ llvm::Function *CoroInRamp =
639+ CGF.CGM .getIntrinsic (llvm::Intrinsic::coro_is_in_ramp);
640+ CoroData.InRamp = Builder.CreateCall (CoroInRamp, {}, " InRamp" );
641+
642+ BasicBlock *EndBB = CoroData.CleanupJD .getBlock ();
643+ Builder.CreateCondBr (CoroData.InRamp , EndBB, CleanupBB);
644+ Builder.SetInsertPoint (SaveInsertPt);
645+
646+ if (S->getReturnStmt ()) {
647+ // Clone cleanup block before EmitCoroFree()
648+ llvm::ValueToValueMapTy VMap{};
649+ CoroData.RampCleanupBB =
650+ llvm::CloneBasicBlock (CleanupBB, VMap, " .ramp" );
651+ }
652+ }
653+
654+ void EmitCoroFree (CodeGenFunction &CGF, const Twine &NameSuffix = " " ) {
610655 // Remember the current point, as we are going to emit deallocation code
611656 // first to get to coro.free instruction that is an argument to a delete
612657 // call.
613658 BasicBlock *SaveInsertBlock = CGF.Builder .GetInsertBlock ();
614659
615- auto *FreeBB = CGF.createBasicBlock (" coro.free" );
660+ Stmt *Deallocate = S->getDeallocate ();
661+ auto *FreeBB = CGF.createBasicBlock (" coro.free" + NameSuffix);
616662 CGF.EmitBlock (FreeBB);
617663 CGF.EmitStmt (Deallocate);
618664
619- auto *AfterFreeBB = CGF.createBasicBlock (" after.coro.free" );
665+ auto *AfterFreeBB = CGF.createBasicBlock (" after.coro.free" + NameSuffix );
620666 CGF.EmitBlock (AfterFreeBB);
621667
622668 // We should have captured coro.free from the emission of deallocate.
@@ -641,7 +687,7 @@ struct CallCoroDelete final : public EHScopeStack::Cleanup {
641687 InsertPt->eraseFromParent ();
642688 CGF.Builder .SetInsertPoint (AfterFreeBB);
643689 }
644- explicit CallCoroDelete (Stmt *DeallocStmt ) : Deallocate(DeallocStmt ) {}
690+ explicit CallCoroDelete (const CoroutineBodyStmt *S ) : S(S ) {}
645691};
646692}
647693
@@ -789,13 +835,13 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
789835 auto *AllocBB = createBasicBlock (" coro.alloc" );
790836 auto *InitBB = createBasicBlock (" coro.init" );
791837 auto *FinalBB = createBasicBlock (" coro.final" );
792- auto *RetBB = createBasicBlock (" coro.ret " );
838+ auto *EndBB = createBasicBlock (" coro.end " );
793839
794840 auto *CoroId = Builder.CreateCall (
795841 CGM.getIntrinsic (llvm::Intrinsic::coro_id),
796842 {Builder.getInt32 (NewAlign), NullPtr, NullPtr, NullPtr});
797843 createCoroData (*this , CurCoro, CoroId);
798- CurCoro.Data ->SuspendBB = RetBB ;
844+ CurCoro.Data ->SuspendBB = EndBB ;
799845 assert (ShouldEmitLifetimeMarkers &&
800846 " Must emit lifetime intrinsics for coroutines" );
801847
@@ -831,23 +877,25 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
831877
832878 EmitBlock (InitBB);
833879
834- // Pass the result of the allocation to coro.begin.
835- auto *Phi = Builder.CreatePHI (VoidPtrTy, 2 );
836- Phi->addIncoming (NullPtr, EntryBB);
837- Phi->addIncoming (AllocateCall, AllocOrInvokeContBB);
838- auto *CoroBegin = Builder.CreateCall (
839- CGM.getIntrinsic (llvm::Intrinsic::coro_begin), {CoroId, Phi});
840- CurCoro.Data ->CoroBegin = CoroBegin;
880+ {
881+ // Pass the result of the allocation to coro.begin.
882+ auto *Phi = Builder.CreatePHI (VoidPtrTy, 2 );
883+ Phi->addIncoming (NullPtr, EntryBB);
884+ Phi->addIncoming (AllocateCall, AllocOrInvokeContBB);
885+ auto *CoroBegin = Builder.CreateCall (
886+ CGM.getIntrinsic (llvm::Intrinsic::coro_begin), {CoroId, Phi});
887+ CurCoro.Data ->CoroBegin = CoroBegin;
888+ }
841889
842890 GetReturnObjectManager GroManager (*this , S);
843891 GroManager.EmitGroAlloca ();
844892
845- CurCoro.Data ->CleanupJD = getJumpDestInCurrentScope (RetBB );
893+ CurCoro.Data ->CleanupJD = getJumpDestInCurrentScope (EndBB );
846894 {
847895 CGDebugInfo *DI = getDebugInfo ();
848896 ParamReferenceReplacerRAII ParamReplacer (LocalDeclMap);
849897 CodeGenFunction::RunCleanupsScope ResumeScope (*this );
850- EHStack.pushCleanup <CallCoroDelete>(NormalAndEHCleanup, S. getDeallocate () );
898+ EHStack.pushCleanup <CallCoroDelete>(NormalAndEHCleanup, &S );
851899
852900 // Create mapping between parameters and copy-params for coroutine function.
853901 llvm::ArrayRef<const Stmt *> ParamMoves = S.getParamMoves ();
@@ -952,7 +1000,14 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
9521000 }
9531001 }
9541002
955- EmitBlock (RetBB);
1003+ EmitBlock (EndBB);
1004+ auto *Phi = Builder.CreatePHI (Builder.getInt1Ty (), llvm::pred_size (EndBB),
1005+ " never.suspend" );
1006+ BasicBlock *CleanupBB = CurCoro.Data ->InRamp ->getParent ();
1007+ for (auto *Pred : llvm::predecessors (EndBB)) {
1008+ auto *V = (Pred == CleanupBB) ? Builder.getTrue () : Builder.getFalse ();
1009+ Phi->addIncoming (V, Pred);
1010+ }
9561011 // Emit coro.end before getReturnStmt (and parameter destructors), since
9571012 // resume and destroy parts of the coroutine should not include them.
9581013 llvm::Function *CoroEnd = CGM.getIntrinsic (llvm::Intrinsic::coro_end);
@@ -973,7 +1028,21 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
9731028 // shouldn't change the AST.
9741029 if (PreviousRetValue)
9751030 cast<ReturnStmt>(Ret)->setRetValue (PreviousRetValue);
976- }
1031+
1032+ // Emit cleanup for ramp function
1033+ auto *RampCleanupBB = CurCoro.Data ->RampCleanupBB ;
1034+ auto *RetBB = EndBB->splitBasicBlock (EndBB->getTerminator (), " coro.ret" );
1035+ EndBB->getTerminator ()->eraseFromParent ();
1036+
1037+ Builder.SetInsertPoint (EndBB);
1038+ Builder.CreateCondBr (Phi, RampCleanupBB, RetBB);
1039+
1040+ EmitBlock (RampCleanupBB);
1041+ CallCoroDelete (&S).EmitCoroFree (*this , " .ramp" );
1042+ Builder.CreateBr (RetBB);
1043+ Builder.ClearInsertionPoint ();
1044+ } else
1045+ EndBB->setName (" coro.ret" );
9771046
9781047 // LLVM require the frontend to mark the coroutine.
9791048 CurFn->setPresplitCoroutine ();
0 commit comments