diff options
Diffstat (limited to 'clang/lib/CodeGen/CGCoroutine.cpp')
| -rw-r--r-- | clang/lib/CodeGen/CGCoroutine.cpp | 107 |
1 files changed, 26 insertions, 81 deletions
diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp index c1763cbbc5a0..594c7d49df3c 100644 --- a/clang/lib/CodeGen/CGCoroutine.cpp +++ b/clang/lib/CodeGen/CGCoroutine.cpp @@ -238,8 +238,8 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Co auto Loc = S.getResumeExpr()->getExprLoc(); auto *Catch = new (CGF.getContext()) CXXCatchStmt(Loc, /*exDecl=*/nullptr, Coro.ExceptionHandler); - auto *TryBody = - CompoundStmt::Create(CGF.getContext(), S.getResumeExpr(), Loc, Loc); + auto *TryBody = CompoundStmt::Create(CGF.getContext(), S.getResumeExpr(), + FPOptionsOverride(), Loc, Loc); TryStmt = CXXTryStmt::Create(CGF.getContext(), Loc, TryBody, Catch); CGF.EnterCXXTryStmt(*TryStmt); } @@ -465,72 +465,6 @@ struct CallCoroDelete final : public EHScopeStack::Cleanup { }; } -namespace { -struct GetReturnObjectManager { - CodeGenFunction &CGF; - CGBuilderTy &Builder; - const CoroutineBodyStmt &S; - - Address GroActiveFlag; - CodeGenFunction::AutoVarEmission GroEmission; - - GetReturnObjectManager(CodeGenFunction &CGF, const CoroutineBodyStmt &S) - : CGF(CGF), Builder(CGF.Builder), S(S), GroActiveFlag(Address::invalid()), - GroEmission(CodeGenFunction::AutoVarEmission::invalid()) {} - - // The gro variable has to outlive coroutine frame and coroutine promise, but, - // it can only be initialized after coroutine promise was created, thus, we - // split its emission in two parts. EmitGroAlloca emits an alloca and sets up - // cleanups. Later when coroutine promise is available we initialize the gro - // and sets the flag that the cleanup is now active. - - void EmitGroAlloca() { - auto *GroDeclStmt = dyn_cast<DeclStmt>(S.getResultDecl()); - if (!GroDeclStmt) { - // If get_return_object returns void, no need to do an alloca. - return; - } - - auto *GroVarDecl = cast<VarDecl>(GroDeclStmt->getSingleDecl()); - - // Set GRO flag that it is not initialized yet - GroActiveFlag = - CGF.CreateTempAlloca(Builder.getInt1Ty(), CharUnits::One(), "gro.active"); - Builder.CreateStore(Builder.getFalse(), GroActiveFlag); - - GroEmission = CGF.EmitAutoVarAlloca(*GroVarDecl); - - // Remember the top of EHStack before emitting the cleanup. - auto old_top = CGF.EHStack.stable_begin(); - CGF.EmitAutoVarCleanups(GroEmission); - auto top = CGF.EHStack.stable_begin(); - - // Make the cleanup conditional on gro.active - for (auto b = CGF.EHStack.find(top), e = CGF.EHStack.find(old_top); - b != e; b++) { - if (auto *Cleanup = dyn_cast<EHCleanupScope>(&*b)) { - assert(!Cleanup->hasActiveFlag() && "cleanup already has active flag?"); - Cleanup->setActiveFlag(GroActiveFlag); - Cleanup->setTestFlagInEHCleanup(); - Cleanup->setTestFlagInNormalCleanup(); - } - } - } - - void EmitGroInit() { - if (!GroActiveFlag.isValid()) { - // No Gro variable was allocated. Simply emit the call to - // get_return_object. - CGF.EmitStmt(S.getResultDecl()); - return; - } - - CGF.EmitAutoVarInit(GroEmission); - Builder.CreateStore(Builder.getTrue(), GroActiveFlag); - } -}; -} - static void emitBodyAndFallthrough(CodeGenFunction &CGF, const CoroutineBodyStmt &S, Stmt *Body) { CGF.EmitStmt(Body); @@ -597,13 +531,6 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) { CGM.getIntrinsic(llvm::Intrinsic::coro_begin), {CoroId, Phi}); CurCoro.Data->CoroBegin = CoroBegin; - // We need to emit `get_return_object` first. According to: - // [dcl.fct.def.coroutine]p7 - // The call to get_return_object is sequenced before the call to - // initial_suspend and is invoked at most once. - GetReturnObjectManager GroManager(*this, S); - GroManager.EmitGroAlloca(); - CurCoro.Data->CleanupJD = getJumpDestInCurrentScope(RetBB); { CGDebugInfo *DI = getDebugInfo(); @@ -641,8 +568,23 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) { // promise local variable was not emitted yet. CoroId->setArgOperand(1, PromiseAddrVoidPtr); - // Now we have the promise, initialize the GRO - GroManager.EmitGroInit(); + // ReturnValue should be valid as long as the coroutine's return type + // is not void. The assertion could help us to reduce the check later. + assert(ReturnValue.isValid() == (bool)S.getReturnStmt()); + // Now we have the promise, initialize the GRO. + // We need to emit `get_return_object` first. According to: + // [dcl.fct.def.coroutine]p7 + // The call to get_return_object is sequenced before the call to + // initial_suspend and is invoked at most once. + // + // So we couldn't emit return value when we emit return statment, + // otherwise the call to get_return_object wouldn't be in front + // of initial_suspend. + if (ReturnValue.isValid()) { + EmitAnyExprToMem(S.getReturnValue(), ReturnValue, + S.getReturnValue()->getType().getQualifiers(), + /*IsInit*/ true); + } EHStack.pushCleanup<CallCoroEnd>(EHCleanup); @@ -705,12 +647,15 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) { llvm::Function *CoroEnd = CGM.getIntrinsic(llvm::Intrinsic::coro_end); Builder.CreateCall(CoroEnd, {NullPtr, Builder.getFalse()}); - if (Stmt *Ret = S.getReturnStmt()) + if (Stmt *Ret = S.getReturnStmt()) { + // Since we already emitted the return value above, so we shouldn't + // emit it again here. + cast<ReturnStmt>(Ret)->setRetValue(nullptr); EmitStmt(Ret); + } - // LLVM require the frontend to add the function attribute. See - // Coroutines.rst. - CurFn->addFnAttr("coroutine.presplit", "0"); + // LLVM require the frontend to mark the coroutine. + CurFn->setPresplitCoroutine(); } // Emit coroutine intrinsic and patch up arguments of the token type. |
