aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen/CGCoroutine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen/CGCoroutine.cpp')
-rw-r--r--clang/lib/CodeGen/CGCoroutine.cpp107
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.