@@ -43,6 +43,8 @@ struct clang::CodeGen::CGCoroData {
4343
4444 // A branch to this block is emitted when coroutine needs to suspend.
4545 llvm::BasicBlock *SuspendBB = nullptr ;
46+ // A branch to this block after final.cleanup or final.ready
47+ llvm::BasicBlock *FinalExit = nullptr ;
4648
4749 // The promise type's 'unhandled_exception' handler, if it defines one.
4850 Stmt *ExceptionHandler = nullptr ;
@@ -332,6 +334,8 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Co
332334 // Emit cleanup for this suspend point.
333335 CGF.EmitBlock (CleanupBlock);
334336 CGF.EmitBranchThroughCleanup (Coro.CleanupJD );
337+ if (IsFinalSuspend)
338+ Coro.FinalExit = CleanupBlock->getSingleSuccessor ();
335339
336340 // Emit await_resume expression.
337341 CGF.EmitBlock (ReadyBlock);
@@ -687,11 +691,11 @@ struct GetReturnObjectManager {
687691 }
688692
689693 // The gro variable has to outlive coroutine frame and coroutine promise, but,
690- // it can only be initialized after coroutine promise was created, thus, we
691- // split its emission in two parts. EmitGroAlloca emits an alloca and sets up
692- // cleanups. Later when coroutine promise is available we initialize the gro
693- // and sets the flag that the cleanup is now active.
694- void EmitGroAlloca () {
694+ // it can only be initialized after coroutine promise was created. Thus,
695+ // EmitGroActive emits a flag and sets it to false. Later when coroutine
696+ // promise is available we initialize the gro and set the flag indicating that
697+ // the cleanup is now active.
698+ void EmitGroActive () {
695699 if (DirectEmit)
696700 return ;
697701
@@ -701,12 +705,23 @@ struct GetReturnObjectManager {
701705 return ;
702706 }
703707
704- auto *GroVarDecl = cast<VarDecl>(GroDeclStmt->getSingleDecl ());
705-
706708 // Set GRO flag that it is not initialized yet
707709 GroActiveFlag = CGF.CreateTempAlloca (Builder.getInt1Ty (), CharUnits::One (),
708710 " gro.active" );
709711 Builder.CreateStore (Builder.getFalse (), GroActiveFlag);
712+ }
713+
714+ void EmitGroAlloca () {
715+ if (DirectEmit)
716+ return ;
717+
718+ auto *GroDeclStmt = dyn_cast_or_null<DeclStmt>(S.getResultDecl ());
719+ if (!GroDeclStmt) {
720+ // If get_return_object returns void, no need to do an alloca.
721+ return ;
722+ }
723+
724+ auto *GroVarDecl = cast<VarDecl>(GroDeclStmt->getSingleDecl ());
710725
711726 GroEmission = CGF.EmitAutoVarAlloca (*GroVarDecl);
712727
@@ -768,6 +783,78 @@ struct GetReturnObjectManager {
768783 CGF.EmitAutoVarInit (GroEmission);
769784 Builder.CreateStore (Builder.getTrue (), GroActiveFlag);
770785 }
786+ // The GRO returns either when it is first suspended or when it completes
787+ // without ever being suspended. The EmitGroConv function evaluates these
788+ // conditions and perform the conversion if needed.
789+ //
790+ // Before EmitGroConv():
791+ // final.exit:
792+ // switch i32 %cleanup.dest, label %destroy [
793+ // i32 0, label %after.ready
794+ // ]
795+ //
796+ // after.ready:
797+ // ; (empty)
798+ //
799+ // After EmitGroConv():
800+ // final.exit:
801+ // switch i32 %cleanup.dest, label %destroy [
802+ // i32 0, label %pre.gro.conv
803+ // ]
804+ //
805+ // pre.gro.conv:
806+ // %IsFinalExit = phi i1 [ false, %any.suspend ], [ true, %final.exit ]
807+ // %InRamp = call i1 @llvm.coro.is_in_ramp()
808+ // br i1 %InRamp, label %gro.conv, label %after.gro.conv
809+ //
810+ // gro.conv:
811+ // ; GRO conversion
812+ // br label %after.gro.conv
813+ //
814+ // after.gro.conv:
815+ // br i1 %IsFinalExit, label %after.ready, label %coro.ret
816+ void EmitGroConv (BasicBlock *RetBB) {
817+ auto *AfterReadyBB = Builder.GetInsertBlock ();
818+ Builder.ClearInsertionPoint ();
819+
820+ auto *PreConvBB = CGF.CurCoro .Data ->SuspendBB ;
821+ CGF.EmitBlock (PreConvBB);
822+ // If final.exit exists, redirect it to PreConvBB
823+ llvm::PHINode *IsFinalExit = nullptr ;
824+ if (BasicBlock *FinalExit = CGF.CurCoro .Data ->FinalExit ) {
825+ assert (AfterReadyBB &&
826+ AfterReadyBB->getSinglePredecessor () == FinalExit &&
827+ " Expect fallthrough from final.exit block" );
828+ AfterReadyBB->replaceAllUsesWith (PreConvBB);
829+ PreConvBB->moveBefore (AfterReadyBB);
830+
831+ // If true, coroutine completes and should be destroyed after conversion
832+ IsFinalExit =
833+ Builder.CreatePHI (Builder.getInt1Ty (), llvm::pred_size (PreConvBB));
834+ for (auto *Pred : llvm::predecessors (PreConvBB)) {
835+ auto *V = (Pred == FinalExit) ? Builder.getTrue () : Builder.getFalse ();
836+ IsFinalExit->addIncoming (V, Pred);
837+ }
838+ }
839+ auto *InRampFn = CGF.CGM .getIntrinsic (llvm::Intrinsic::coro_is_in_ramp);
840+ auto *InRamp = Builder.CreateCall (InRampFn, {}, " InRamp" );
841+ auto *ConvBB = CGF.createBasicBlock (" gro.conv" );
842+ auto *AfterConvBB = CGF.createBasicBlock (" after.gro.conv" );
843+ Builder.CreateCondBr (InRamp, ConvBB, AfterConvBB);
844+
845+ CGF.EmitBlock (ConvBB);
846+ CGF.EmitAnyExprToMem (S.getReturnValue (), CGF.ReturnValue ,
847+ S.getReturnValue ()->getType ().getQualifiers (),
848+ /* IsInit*/ true );
849+ Builder.CreateBr (AfterConvBB);
850+
851+ CGF.EmitBlock (AfterConvBB);
852+ if (IsFinalExit)
853+ Builder.CreateCondBr (IsFinalExit, AfterReadyBB, RetBB);
854+ else
855+ Builder.CreateBr (RetBB);
856+ Builder.SetInsertPoint (AfterReadyBB);
857+ }
771858};
772859} // namespace
773860
@@ -795,7 +882,10 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
795882 CGM.getIntrinsic (llvm::Intrinsic::coro_id),
796883 {Builder.getInt32 (NewAlign), NullPtr, NullPtr, NullPtr});
797884 createCoroData (*this , CurCoro, CoroId);
798- CurCoro.Data ->SuspendBB = RetBB;
885+
886+ GetReturnObjectManager GroManager (*this , S);
887+ CurCoro.Data ->SuspendBB =
888+ GroManager.DirectEmit ? RetBB : createBasicBlock (" pre.gvo.conv" );
799889 assert (ShouldEmitLifetimeMarkers &&
800890 " Must emit lifetime intrinsics for coroutines" );
801891
@@ -839,9 +929,6 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
839929 CGM.getIntrinsic (llvm::Intrinsic::coro_begin), {CoroId, Phi});
840930 CurCoro.Data ->CoroBegin = CoroBegin;
841931
842- GetReturnObjectManager GroManager (*this , S);
843- GroManager.EmitGroAlloca ();
844-
845932 CurCoro.Data ->CleanupJD = getJumpDestInCurrentScope (RetBB);
846933 {
847934 CGDebugInfo *DI = getDebugInfo ();
@@ -884,6 +971,7 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
884971 // not needed.
885972 }
886973
974+ GroManager.EmitGroActive ();
887975 EmitStmt (S.getPromiseDeclStmt ());
888976
889977 Address PromiseAddr = GetAddrOfLocalVar (S.getPromiseDecl ());
@@ -895,6 +983,7 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
895983 CoroId->setArgOperand (1 , PromiseAddrVoidPtr);
896984
897985 // Now we have the promise, initialize the GRO
986+ GroManager.EmitGroAlloca ();
898987 GroManager.EmitGroInit ();
899988
900989 EHStack.pushCleanup <CallCoroEnd>(EHCleanup);
@@ -950,31 +1039,31 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
9501039 // We don't need FinalBB. Emit it to make sure the block is deleted.
9511040 EmitBlock (FinalBB, /* IsFinished=*/ true );
9521041 }
1042+
1043+ // We need conversion if get_return_object's type doesn't matches the
1044+ // coroutine return type.
1045+ if (!GroManager.DirectEmit )
1046+ GroManager.EmitGroConv (RetBB);
9531047 }
9541048
9551049 EmitBlock (RetBB);
956- // Emit coro.end before getReturnStmt ( and parameter destructors), since
957- // resume and destroy parts of the coroutine should not include them .
1050+ // Emit coro.end before ret instruction, since resume and destroy parts of the
1051+ // coroutine should return void .
9581052 llvm::Function *CoroEnd = CGM.getIntrinsic (llvm::Intrinsic::coro_end);
9591053 Builder.CreateCall (CoroEnd,
9601054 {NullPtr, Builder.getFalse (),
9611055 llvm::ConstantTokenNone::get (CoroEnd->getContext ())});
9621056
963- if (Stmt *Ret = S.getReturnStmt ()) {
1057+ if (auto *Ret = cast_or_null<ReturnStmt>( S.getReturnStmt () )) {
9641058 // Since we already emitted the return value above, so we shouldn't
9651059 // emit it again here.
966- Expr *PreviousRetValue = nullptr ;
967- if (GroManager.DirectEmit ) {
968- PreviousRetValue = cast<ReturnStmt>(Ret)->getRetValue ();
969- cast<ReturnStmt>(Ret)->setRetValue (nullptr );
970- }
1060+ Expr *PreviousRetValue = Ret->getRetValue ();
1061+ Ret->setRetValue (nullptr );
9711062 EmitStmt (Ret);
9721063 // Set the return value back. The code generator, as the AST **Consumer**,
9731064 // shouldn't change the AST.
974- if (PreviousRetValue)
975- cast<ReturnStmt>(Ret)->setRetValue (PreviousRetValue);
1065+ Ret->setRetValue (PreviousRetValue);
9761066 }
977-
9781067 // LLVM require the frontend to mark the coroutine.
9791068 CurFn->setPresplitCoroutine ();
9801069
0 commit comments