diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp --- a/clang/lib/CodeGen/CGCoroutine.cpp +++ b/clang/lib/CodeGen/CGCoroutine.cpp @@ -245,10 +245,39 @@ } LValueOrRValue Res; - if (forLValue) + if (forLValue) { Res.LV = CGF.EmitLValue(S.getResumeExpr()); - else + } else { + // If the result of co_await is stored into a memory address, we want to + // make sure the lifetime of that memory address does not start too early, + // causing more space to be allocated in the frame rather than on stack. + // The lifetime of the return value of co_await should start here right + // before we attempt to assign it. + auto adjustLifetimeStart = [&]() { + // aggSlot points to the instruction that allocated the object. Latter + // instructions use it in this pattern: + // %tmpX = alloca %.., align 4 + // %0 = bitcast %...* %tmpX to i8* + // call void @llvm.lifetime.start.p0i8(i64 ..., i8* nonnull %0) #2 + // Hence we trace back through uses to eventually locate the lifetime + // start intrinsics marker, and move it down to the current insertion + // point. + auto *AllocaInst = + dyn_cast_or_null(aggSlot.getPointer()); + if (!AllocaInst || AllocaInst->getNumUses() != 1) + return; + auto *CastInst = dyn_cast(*AllocaInst->users().begin()); + if (!CastInst || CastInst->getNumUses() != 1) + return; + if (auto *LifetimeInst = + dyn_cast(*CastInst->users().begin())) { + LifetimeInst->removeFromParent(); + CGF.Builder.Insert(LifetimeInst); + } + }; + adjustLifetimeStart(); Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult); + } if (TryStmt) { Builder.CreateFlagStore(false, Coro.ResumeEHVar);