197e3b6d8SGor Nishanov //===----- CGCoroutine.cpp - Emit LLVM Code for C++ coroutines ------------===//
297e3b6d8SGor Nishanov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
697e3b6d8SGor Nishanov //
797e3b6d8SGor Nishanov //===----------------------------------------------------------------------===//
897e3b6d8SGor Nishanov //
997e3b6d8SGor Nishanov // This contains code dealing with C++ code generation of coroutines.
1097e3b6d8SGor Nishanov //
1197e3b6d8SGor Nishanov //===----------------------------------------------------------------------===//
1297e3b6d8SGor Nishanov
134c2f68fdSGor Nishanov #include "CGCleanup.h"
1497e3b6d8SGor Nishanov #include "CodeGenFunction.h"
155eb58583SGor Nishanov #include "llvm/ADT/ScopeExit.h"
168df64e94SGor Nishanov #include "clang/AST/StmtCXX.h"
1733d5fd24SGor Nishanov #include "clang/AST/StmtVisitor.h"
1897e3b6d8SGor Nishanov
1997e3b6d8SGor Nishanov using namespace clang;
2097e3b6d8SGor Nishanov using namespace CodeGen;
2197e3b6d8SGor Nishanov
225eb58583SGor Nishanov using llvm::Value;
235eb58583SGor Nishanov using llvm::BasicBlock;
2497e3b6d8SGor Nishanov
255eb58583SGor Nishanov namespace {
265eb58583SGor Nishanov enum class AwaitKind { Init, Normal, Yield, Final };
275eb58583SGor Nishanov static constexpr llvm::StringLiteral AwaitKindStr[] = {"init", "await", "yield",
285eb58583SGor Nishanov "final"};
295eb58583SGor Nishanov }
3090be1213SGor Nishanov
315eb58583SGor Nishanov struct clang::CodeGen::CGCoroData {
325eb58583SGor Nishanov // What is the current await expression kind and how many
335eb58583SGor Nishanov // await/yield expressions were encountered so far.
345eb58583SGor Nishanov // These are used to generate pretty labels for await expressions in LLVM IR.
355eb58583SGor Nishanov AwaitKind CurrentAwaitKind = AwaitKind::Init;
365eb58583SGor Nishanov unsigned AwaitNum = 0;
375eb58583SGor Nishanov unsigned YieldNum = 0;
385eb58583SGor Nishanov
395eb58583SGor Nishanov // How many co_return statements are in the coroutine. Used to decide whether
405eb58583SGor Nishanov // we need to add co_return; equivalent at the end of the user authored body.
415eb58583SGor Nishanov unsigned CoreturnCount = 0;
425eb58583SGor Nishanov
435eb58583SGor Nishanov // A branch to this block is emitted when coroutine needs to suspend.
445eb58583SGor Nishanov llvm::BasicBlock *SuspendBB = nullptr;
455eb58583SGor Nishanov
46ea9144e8SBrian Gesiak // The promise type's 'unhandled_exception' handler, if it defines one.
47ea9144e8SBrian Gesiak Stmt *ExceptionHandler = nullptr;
48ea9144e8SBrian Gesiak
49ea9144e8SBrian Gesiak // A temporary i1 alloca that stores whether 'await_resume' threw an
50ea9144e8SBrian Gesiak // exception. If it did, 'true' is stored in this variable, and the coroutine
51ea9144e8SBrian Gesiak // body must be skipped. If the promise type does not define an exception
52ea9144e8SBrian Gesiak // handler, this is null.
53ea9144e8SBrian Gesiak llvm::Value *ResumeEHVar = nullptr;
54ea9144e8SBrian Gesiak
555eb58583SGor Nishanov // Stores the jump destination just before the coroutine memory is freed.
565eb58583SGor Nishanov // This is the destination that every suspend point jumps to for the cleanup
575eb58583SGor Nishanov // branch.
585eb58583SGor Nishanov CodeGenFunction::JumpDest CleanupJD;
595eb58583SGor Nishanov
605eb58583SGor Nishanov // Stores the jump destination just before the final suspend. The co_return
6190be1213SGor Nishanov // statements jumps to this point after calling return_xxx promise member.
6290be1213SGor Nishanov CodeGenFunction::JumpDest FinalJD;
6390be1213SGor Nishanov
6497e3b6d8SGor Nishanov // Stores the llvm.coro.id emitted in the function so that we can supply it
6597e3b6d8SGor Nishanov // as the first argument to coro.begin, coro.alloc and coro.free intrinsics.
6697e3b6d8SGor Nishanov // Note: llvm.coro.id returns a token that cannot be directly expressed in a
6797e3b6d8SGor Nishanov // builtin.
6897e3b6d8SGor Nishanov llvm::CallInst *CoroId = nullptr;
695eb58583SGor Nishanov
7068fe6ee7SGor Nishanov // Stores the llvm.coro.begin emitted in the function so that we can replace
7168fe6ee7SGor Nishanov // all coro.frame intrinsics with direct SSA value of coro.begin that returns
7268fe6ee7SGor Nishanov // the address of the coroutine frame of the current coroutine.
7368fe6ee7SGor Nishanov llvm::CallInst *CoroBegin = nullptr;
7468fe6ee7SGor Nishanov
756c4530c6SGor Nishanov // Stores the last emitted coro.free for the deallocate expressions, we use it
766c4530c6SGor Nishanov // to wrap dealloc code with if(auto mem = coro.free) dealloc(mem).
776c4530c6SGor Nishanov llvm::CallInst *LastCoroFree = nullptr;
786c4530c6SGor Nishanov
7997e3b6d8SGor Nishanov // If coro.id came from the builtin, remember the expression to give better
8097e3b6d8SGor Nishanov // diagnostic. If CoroIdExpr is nullptr, the coro.id was created by
8197e3b6d8SGor Nishanov // EmitCoroutineBody.
8297e3b6d8SGor Nishanov CallExpr const *CoroIdExpr = nullptr;
8397e3b6d8SGor Nishanov };
8497e3b6d8SGor Nishanov
855eb58583SGor Nishanov // Defining these here allows to keep CGCoroData private to this file.
CGCoroInfo()8697e3b6d8SGor Nishanov clang::CodeGen::CodeGenFunction::CGCoroInfo::CGCoroInfo() {}
~CGCoroInfo()8797e3b6d8SGor Nishanov CodeGenFunction::CGCoroInfo::~CGCoroInfo() {}
8897e3b6d8SGor Nishanov
createCoroData(CodeGenFunction & CGF,CodeGenFunction::CGCoroInfo & CurCoro,llvm::CallInst * CoroId,CallExpr const * CoroIdExpr=nullptr)898df64e94SGor Nishanov static void createCoroData(CodeGenFunction &CGF,
9097e3b6d8SGor Nishanov CodeGenFunction::CGCoroInfo &CurCoro,
918df64e94SGor Nishanov llvm::CallInst *CoroId,
928df64e94SGor Nishanov CallExpr const *CoroIdExpr = nullptr) {
9397e3b6d8SGor Nishanov if (CurCoro.Data) {
9497e3b6d8SGor Nishanov if (CurCoro.Data->CoroIdExpr)
95f2ceec48SStephen Kelly CGF.CGM.Error(CoroIdExpr->getBeginLoc(),
9697e3b6d8SGor Nishanov "only one __builtin_coro_id can be used in a function");
9797e3b6d8SGor Nishanov else if (CoroIdExpr)
98f2ceec48SStephen Kelly CGF.CGM.Error(CoroIdExpr->getBeginLoc(),
9997e3b6d8SGor Nishanov "__builtin_coro_id shall not be used in a C++ coroutine");
10097e3b6d8SGor Nishanov else
10197e3b6d8SGor Nishanov llvm_unreachable("EmitCoroutineBodyStatement called twice?");
10297e3b6d8SGor Nishanov
1038df64e94SGor Nishanov return;
10497e3b6d8SGor Nishanov }
10597e3b6d8SGor Nishanov
10697e3b6d8SGor Nishanov CurCoro.Data = std::unique_ptr<CGCoroData>(new CGCoroData);
10797e3b6d8SGor Nishanov CurCoro.Data->CoroId = CoroId;
10897e3b6d8SGor Nishanov CurCoro.Data->CoroIdExpr = CoroIdExpr;
1098df64e94SGor Nishanov }
1108df64e94SGor Nishanov
1115eb58583SGor Nishanov // Synthesize a pretty name for a suspend point.
buildSuspendPrefixStr(CGCoroData & Coro,AwaitKind Kind)1125eb58583SGor Nishanov static SmallString<32> buildSuspendPrefixStr(CGCoroData &Coro, AwaitKind Kind) {
1135eb58583SGor Nishanov unsigned No = 0;
1145eb58583SGor Nishanov switch (Kind) {
1155eb58583SGor Nishanov case AwaitKind::Init:
1165eb58583SGor Nishanov case AwaitKind::Final:
1175eb58583SGor Nishanov break;
1185eb58583SGor Nishanov case AwaitKind::Normal:
1195eb58583SGor Nishanov No = ++Coro.AwaitNum;
1205eb58583SGor Nishanov break;
1215eb58583SGor Nishanov case AwaitKind::Yield:
1225eb58583SGor Nishanov No = ++Coro.YieldNum;
1235eb58583SGor Nishanov break;
1245eb58583SGor Nishanov }
1255eb58583SGor Nishanov SmallString<32> Prefix(AwaitKindStr[static_cast<unsigned>(Kind)]);
1265eb58583SGor Nishanov if (No > 1) {
1275eb58583SGor Nishanov Twine(No).toVector(Prefix);
1285eb58583SGor Nishanov }
1295eb58583SGor Nishanov return Prefix;
1305eb58583SGor Nishanov }
1315eb58583SGor Nishanov
memberCallExpressionCanThrow(const Expr * E)13212728474SBrian Gesiak static bool memberCallExpressionCanThrow(const Expr *E) {
13312728474SBrian Gesiak if (const auto *CE = dyn_cast<CXXMemberCallExpr>(E))
13412728474SBrian Gesiak if (const auto *Proto =
13512728474SBrian Gesiak CE->getMethodDecl()->getType()->getAs<FunctionProtoType>())
13612728474SBrian Gesiak if (isNoexceptExceptionSpec(Proto->getExceptionSpecType()) &&
13712728474SBrian Gesiak Proto->canThrow() == CT_Cannot)
13812728474SBrian Gesiak return false;
13912728474SBrian Gesiak return true;
14012728474SBrian Gesiak }
14112728474SBrian Gesiak
1425eb58583SGor Nishanov // Emit suspend expression which roughly looks like:
1435eb58583SGor Nishanov //
1445eb58583SGor Nishanov // auto && x = CommonExpr();
1455eb58583SGor Nishanov // if (!x.await_ready()) {
1465eb58583SGor Nishanov // llvm_coro_save();
1475eb58583SGor Nishanov // x.await_suspend(...); (*)
1485eb58583SGor Nishanov // llvm_coro_suspend(); (**)
1495eb58583SGor Nishanov // }
1505eb58583SGor Nishanov // x.await_resume();
1515eb58583SGor Nishanov //
1525eb58583SGor Nishanov // where the result of the entire expression is the result of x.await_resume()
1535eb58583SGor Nishanov //
1545eb58583SGor Nishanov // (*) If x.await_suspend return type is bool, it allows to veto a suspend:
1555eb58583SGor Nishanov // if (x.await_suspend(...))
1565eb58583SGor Nishanov // llvm_coro_suspend();
1575eb58583SGor Nishanov //
1585eb58583SGor Nishanov // (**) llvm_coro_suspend() encodes three possible continuations as
1595eb58583SGor Nishanov // a switch instruction:
1605eb58583SGor Nishanov //
1615eb58583SGor Nishanov // %where-to = call i8 @llvm.coro.suspend(...)
1625eb58583SGor Nishanov // switch i8 %where-to, label %coro.ret [ ; jump to epilogue to suspend
1635eb58583SGor Nishanov // i8 0, label %yield.ready ; go here when resumed
1645eb58583SGor Nishanov // i8 1, label %yield.cleanup ; go here when destroyed
1655eb58583SGor Nishanov // ]
1665eb58583SGor Nishanov //
1675eb58583SGor Nishanov // See llvm's docs/Coroutines.rst for more details.
1685eb58583SGor Nishanov //
169cddaf872SEric Fiselier namespace {
170cddaf872SEric Fiselier struct LValueOrRValue {
171cddaf872SEric Fiselier LValue LV;
172cddaf872SEric Fiselier RValue RV;
173cddaf872SEric Fiselier };
174cddaf872SEric Fiselier }
emitSuspendExpression(CodeGenFunction & CGF,CGCoroData & Coro,CoroutineSuspendExpr const & S,AwaitKind Kind,AggValueSlot aggSlot,bool ignoreResult,bool forLValue)175cddaf872SEric Fiselier static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro,
1765eb58583SGor Nishanov CoroutineSuspendExpr const &S,
1775eb58583SGor Nishanov AwaitKind Kind, AggValueSlot aggSlot,
178cddaf872SEric Fiselier bool ignoreResult, bool forLValue) {
1795eb58583SGor Nishanov auto *E = S.getCommonExpr();
180e4f15a2bSGor Nishanov
1815eb58583SGor Nishanov auto Binder =
1825eb58583SGor Nishanov CodeGenFunction::OpaqueValueMappingData::bind(CGF, S.getOpaqueValue(), E);
1835eb58583SGor Nishanov auto UnbindOnExit = llvm::make_scope_exit([&] { Binder.unbind(CGF); });
1845eb58583SGor Nishanov
1855eb58583SGor Nishanov auto Prefix = buildSuspendPrefixStr(Coro, Kind);
1865eb58583SGor Nishanov BasicBlock *ReadyBlock = CGF.createBasicBlock(Prefix + Twine(".ready"));
1875eb58583SGor Nishanov BasicBlock *SuspendBlock = CGF.createBasicBlock(Prefix + Twine(".suspend"));
1885eb58583SGor Nishanov BasicBlock *CleanupBlock = CGF.createBasicBlock(Prefix + Twine(".cleanup"));
1895eb58583SGor Nishanov
1905eb58583SGor Nishanov // If expression is ready, no need to suspend.
1915eb58583SGor Nishanov CGF.EmitBranchOnBoolExpr(S.getReadyExpr(), ReadyBlock, SuspendBlock, 0);
1925eb58583SGor Nishanov
1935eb58583SGor Nishanov // Otherwise, emit suspend logic.
1945eb58583SGor Nishanov CGF.EmitBlock(SuspendBlock);
1955eb58583SGor Nishanov
1965eb58583SGor Nishanov auto &Builder = CGF.Builder;
1975eb58583SGor Nishanov llvm::Function *CoroSave = CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_save);
1985eb58583SGor Nishanov auto *NullPtr = llvm::ConstantPointerNull::get(CGF.CGM.Int8PtrTy);
1995eb58583SGor Nishanov auto *SaveCall = Builder.CreateCall(CoroSave, {NullPtr});
2005eb58583SGor Nishanov
2015eb58583SGor Nishanov auto *SuspendRet = CGF.EmitScalarExpr(S.getSuspendExpr());
2020f333006SGor Nishanov if (SuspendRet != nullptr && SuspendRet->getType()->isIntegerTy(1)) {
2035eb58583SGor Nishanov // Veto suspension if requested by bool returning await_suspend.
2045eb58583SGor Nishanov BasicBlock *RealSuspendBlock =
2055eb58583SGor Nishanov CGF.createBasicBlock(Prefix + Twine(".suspend.bool"));
2065eb58583SGor Nishanov CGF.Builder.CreateCondBr(SuspendRet, RealSuspendBlock, ReadyBlock);
2075eb58583SGor Nishanov CGF.EmitBlock(RealSuspendBlock);
2085eb58583SGor Nishanov }
2095eb58583SGor Nishanov
2105eb58583SGor Nishanov // Emit the suspend point.
2115eb58583SGor Nishanov const bool IsFinalSuspend = (Kind == AwaitKind::Final);
2125eb58583SGor Nishanov llvm::Function *CoroSuspend =
2135eb58583SGor Nishanov CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_suspend);
2145eb58583SGor Nishanov auto *SuspendResult = Builder.CreateCall(
2155eb58583SGor Nishanov CoroSuspend, {SaveCall, Builder.getInt1(IsFinalSuspend)});
2165eb58583SGor Nishanov
2175eb58583SGor Nishanov // Create a switch capturing three possible continuations.
2185eb58583SGor Nishanov auto *Switch = Builder.CreateSwitch(SuspendResult, Coro.SuspendBB, 2);
2195eb58583SGor Nishanov Switch->addCase(Builder.getInt8(0), ReadyBlock);
2205eb58583SGor Nishanov Switch->addCase(Builder.getInt8(1), CleanupBlock);
2215eb58583SGor Nishanov
2225eb58583SGor Nishanov // Emit cleanup for this suspend point.
2235eb58583SGor Nishanov CGF.EmitBlock(CleanupBlock);
2245eb58583SGor Nishanov CGF.EmitBranchThroughCleanup(Coro.CleanupJD);
2255eb58583SGor Nishanov
2265eb58583SGor Nishanov // Emit await_resume expression.
2275eb58583SGor Nishanov CGF.EmitBlock(ReadyBlock);
22812728474SBrian Gesiak
22912728474SBrian Gesiak // Exception handling requires additional IR. If the 'await_resume' function
23012728474SBrian Gesiak // is marked as 'noexcept', we avoid generating this additional IR.
231ea9144e8SBrian Gesiak CXXTryStmt *TryStmt = nullptr;
23212728474SBrian Gesiak if (Coro.ExceptionHandler && Kind == AwaitKind::Init &&
23312728474SBrian Gesiak memberCallExpressionCanThrow(S.getResumeExpr())) {
234ea9144e8SBrian Gesiak Coro.ResumeEHVar =
235ea9144e8SBrian Gesiak CGF.CreateTempAlloca(Builder.getInt1Ty(), Prefix + Twine("resume.eh"));
236ea9144e8SBrian Gesiak Builder.CreateFlagStore(true, Coro.ResumeEHVar);
237ea9144e8SBrian Gesiak
238ea9144e8SBrian Gesiak auto Loc = S.getResumeExpr()->getExprLoc();
239ea9144e8SBrian Gesiak auto *Catch = new (CGF.getContext())
240ea9144e8SBrian Gesiak CXXCatchStmt(Loc, /*exDecl=*/nullptr, Coro.ExceptionHandler);
241*f7819ce1SSerge Pavlov auto *TryBody = CompoundStmt::Create(CGF.getContext(), S.getResumeExpr(),
242*f7819ce1SSerge Pavlov FPOptionsOverride(), Loc, Loc);
243ea9144e8SBrian Gesiak TryStmt = CXXTryStmt::Create(CGF.getContext(), Loc, TryBody, Catch);
244ea9144e8SBrian Gesiak CGF.EnterCXXTryStmt(*TryStmt);
245ea9144e8SBrian Gesiak }
246ea9144e8SBrian Gesiak
247cddaf872SEric Fiselier LValueOrRValue Res;
248cddaf872SEric Fiselier if (forLValue)
249cddaf872SEric Fiselier Res.LV = CGF.EmitLValue(S.getResumeExpr());
250cddaf872SEric Fiselier else
251cddaf872SEric Fiselier Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult);
252ea9144e8SBrian Gesiak
253ea9144e8SBrian Gesiak if (TryStmt) {
254ea9144e8SBrian Gesiak Builder.CreateFlagStore(false, Coro.ResumeEHVar);
255ea9144e8SBrian Gesiak CGF.ExitCXXTryStmt(*TryStmt);
256ea9144e8SBrian Gesiak }
257ea9144e8SBrian Gesiak
258cddaf872SEric Fiselier return Res;
2595eb58583SGor Nishanov }
2605eb58583SGor Nishanov
EmitCoawaitExpr(const CoawaitExpr & E,AggValueSlot aggSlot,bool ignoreResult)2615eb58583SGor Nishanov RValue CodeGenFunction::EmitCoawaitExpr(const CoawaitExpr &E,
2625eb58583SGor Nishanov AggValueSlot aggSlot,
2635eb58583SGor Nishanov bool ignoreResult) {
2645eb58583SGor Nishanov return emitSuspendExpression(*this, *CurCoro.Data, E,
2655eb58583SGor Nishanov CurCoro.Data->CurrentAwaitKind, aggSlot,
266cddaf872SEric Fiselier ignoreResult, /*forLValue*/false).RV;
2675eb58583SGor Nishanov }
EmitCoyieldExpr(const CoyieldExpr & E,AggValueSlot aggSlot,bool ignoreResult)2685eb58583SGor Nishanov RValue CodeGenFunction::EmitCoyieldExpr(const CoyieldExpr &E,
2695eb58583SGor Nishanov AggValueSlot aggSlot,
2705eb58583SGor Nishanov bool ignoreResult) {
2715eb58583SGor Nishanov return emitSuspendExpression(*this, *CurCoro.Data, E, AwaitKind::Yield,
272cddaf872SEric Fiselier aggSlot, ignoreResult, /*forLValue*/false).RV;
2735eb58583SGor Nishanov }
2745eb58583SGor Nishanov
EmitCoreturnStmt(CoreturnStmt const & S)27590be1213SGor Nishanov void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) {
27690be1213SGor Nishanov ++CurCoro.Data->CoreturnCount;
277e9a5e7e4SEric Fiselier const Expr *RV = S.getOperand();
27853c2e10fSJun Ma if (RV && RV->getType()->isVoidType() && !isa<InitListExpr>(RV)) {
27953c2e10fSJun Ma // Make sure to evaluate the non initlist expression of a co_return
28053c2e10fSJun Ma // with a void expression for side effects.
281e9a5e7e4SEric Fiselier RunCleanupsScope cleanupScope(*this);
282e9a5e7e4SEric Fiselier EmitIgnoredExpr(RV);
283e9a5e7e4SEric Fiselier }
28490be1213SGor Nishanov EmitStmt(S.getPromiseCall());
28590be1213SGor Nishanov EmitBranchThroughCleanup(CurCoro.Data->FinalJD);
28690be1213SGor Nishanov }
28790be1213SGor Nishanov
288cddaf872SEric Fiselier
289cddaf872SEric Fiselier #ifndef NDEBUG
getCoroutineSuspendExprReturnType(const ASTContext & Ctx,const CoroutineSuspendExpr * E)290cddaf872SEric Fiselier static QualType getCoroutineSuspendExprReturnType(const ASTContext &Ctx,
291cddaf872SEric Fiselier const CoroutineSuspendExpr *E) {
292cddaf872SEric Fiselier const auto *RE = E->getResumeExpr();
293cddaf872SEric Fiselier // Is it possible for RE to be a CXXBindTemporaryExpr wrapping
294cddaf872SEric Fiselier // a MemberCallExpr?
295cddaf872SEric Fiselier assert(isa<CallExpr>(RE) && "unexpected suspend expression type");
296cddaf872SEric Fiselier return cast<CallExpr>(RE)->getCallReturnType(Ctx);
297cddaf872SEric Fiselier }
298cddaf872SEric Fiselier #endif
299cddaf872SEric Fiselier
300cddaf872SEric Fiselier LValue
EmitCoawaitLValue(const CoawaitExpr * E)301cddaf872SEric Fiselier CodeGenFunction::EmitCoawaitLValue(const CoawaitExpr *E) {
302cddaf872SEric Fiselier assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() &&
303cddaf872SEric Fiselier "Can't have a scalar return unless the return type is a "
304cddaf872SEric Fiselier "reference type!");
305cddaf872SEric Fiselier return emitSuspendExpression(*this, *CurCoro.Data, *E,
306cddaf872SEric Fiselier CurCoro.Data->CurrentAwaitKind, AggValueSlot::ignored(),
307cddaf872SEric Fiselier /*ignoreResult*/false, /*forLValue*/true).LV;
308cddaf872SEric Fiselier }
309cddaf872SEric Fiselier
310cddaf872SEric Fiselier LValue
EmitCoyieldLValue(const CoyieldExpr * E)311cddaf872SEric Fiselier CodeGenFunction::EmitCoyieldLValue(const CoyieldExpr *E) {
312cddaf872SEric Fiselier assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() &&
313cddaf872SEric Fiselier "Can't have a scalar return unless the return type is a "
314cddaf872SEric Fiselier "reference type!");
315cddaf872SEric Fiselier return emitSuspendExpression(*this, *CurCoro.Data, *E,
316cddaf872SEric Fiselier AwaitKind::Yield, AggValueSlot::ignored(),
317cddaf872SEric Fiselier /*ignoreResult*/false, /*forLValue*/true).LV;
318cddaf872SEric Fiselier }
319cddaf872SEric Fiselier
32033d5fd24SGor Nishanov // Hunts for the parameter reference in the parameter copy/move declaration.
32133d5fd24SGor Nishanov namespace {
32233d5fd24SGor Nishanov struct GetParamRef : public StmtVisitor<GetParamRef> {
32333d5fd24SGor Nishanov public:
32433d5fd24SGor Nishanov DeclRefExpr *Expr = nullptr;
GetParamRef__anon268cdc500411::GetParamRef32533d5fd24SGor Nishanov GetParamRef() {}
VisitDeclRefExpr__anon268cdc500411::GetParamRef32633d5fd24SGor Nishanov void VisitDeclRefExpr(DeclRefExpr *E) {
32733d5fd24SGor Nishanov assert(Expr == nullptr && "multilple declref in param move");
32833d5fd24SGor Nishanov Expr = E;
32933d5fd24SGor Nishanov }
VisitStmt__anon268cdc500411::GetParamRef33033d5fd24SGor Nishanov void VisitStmt(Stmt *S) {
33133d5fd24SGor Nishanov for (auto *C : S->children()) {
33233d5fd24SGor Nishanov if (C)
33333d5fd24SGor Nishanov Visit(C);
33433d5fd24SGor Nishanov }
33533d5fd24SGor Nishanov }
33633d5fd24SGor Nishanov };
33733d5fd24SGor Nishanov }
33833d5fd24SGor Nishanov
33933d5fd24SGor Nishanov // This class replaces references to parameters to their copies by changing
34033d5fd24SGor Nishanov // the addresses in CGF.LocalDeclMap and restoring back the original values in
34133d5fd24SGor Nishanov // its destructor.
34233d5fd24SGor Nishanov
34333d5fd24SGor Nishanov namespace {
34433d5fd24SGor Nishanov struct ParamReferenceReplacerRAII {
34533d5fd24SGor Nishanov CodeGenFunction::DeclMapTy SavedLocals;
34633d5fd24SGor Nishanov CodeGenFunction::DeclMapTy& LocalDeclMap;
34733d5fd24SGor Nishanov
ParamReferenceReplacerRAII__anon268cdc500511::ParamReferenceReplacerRAII34833d5fd24SGor Nishanov ParamReferenceReplacerRAII(CodeGenFunction::DeclMapTy &LocalDeclMap)
34933d5fd24SGor Nishanov : LocalDeclMap(LocalDeclMap) {}
35033d5fd24SGor Nishanov
addCopy__anon268cdc500511::ParamReferenceReplacerRAII35133d5fd24SGor Nishanov void addCopy(DeclStmt const *PM) {
35233d5fd24SGor Nishanov // Figure out what param it refers to.
35333d5fd24SGor Nishanov
35433d5fd24SGor Nishanov assert(PM->isSingleDecl());
35533d5fd24SGor Nishanov VarDecl const*VD = static_cast<VarDecl const*>(PM->getSingleDecl());
35633d5fd24SGor Nishanov Expr const *InitExpr = VD->getInit();
35733d5fd24SGor Nishanov GetParamRef Visitor;
35833d5fd24SGor Nishanov Visitor.Visit(const_cast<Expr*>(InitExpr));
35933d5fd24SGor Nishanov assert(Visitor.Expr);
36000f70bd9SGeorge Burgess IV DeclRefExpr *DREOrig = Visitor.Expr;
36133d5fd24SGor Nishanov auto *PD = DREOrig->getDecl();
36233d5fd24SGor Nishanov
36333d5fd24SGor Nishanov auto it = LocalDeclMap.find(PD);
36433d5fd24SGor Nishanov assert(it != LocalDeclMap.end() && "parameter is not found");
36533d5fd24SGor Nishanov SavedLocals.insert({ PD, it->second });
36633d5fd24SGor Nishanov
36733d5fd24SGor Nishanov auto copyIt = LocalDeclMap.find(VD);
36833d5fd24SGor Nishanov assert(copyIt != LocalDeclMap.end() && "parameter copy is not found");
36933d5fd24SGor Nishanov it->second = copyIt->getSecond();
37033d5fd24SGor Nishanov }
37133d5fd24SGor Nishanov
~ParamReferenceReplacerRAII__anon268cdc500511::ParamReferenceReplacerRAII37233d5fd24SGor Nishanov ~ParamReferenceReplacerRAII() {
37333d5fd24SGor Nishanov for (auto&& SavedLocal : SavedLocals) {
37433d5fd24SGor Nishanov LocalDeclMap.insert({SavedLocal.first, SavedLocal.second});
37533d5fd24SGor Nishanov }
37633d5fd24SGor Nishanov }
37733d5fd24SGor Nishanov };
37833d5fd24SGor Nishanov }
37933d5fd24SGor Nishanov
38033d5fd24SGor Nishanov // For WinEH exception representation backend needs to know what funclet coro.end
381818a7761SGor Nishanov // belongs to. That information is passed in a funclet bundle.
382818a7761SGor Nishanov static SmallVector<llvm::OperandBundleDef, 1>
getBundlesForCoroEnd(CodeGenFunction & CGF)383818a7761SGor Nishanov getBundlesForCoroEnd(CodeGenFunction &CGF) {
384818a7761SGor Nishanov SmallVector<llvm::OperandBundleDef, 1> BundleList;
385818a7761SGor Nishanov
386818a7761SGor Nishanov if (llvm::Instruction *EHPad = CGF.CurrentFuncletPad)
387818a7761SGor Nishanov BundleList.emplace_back("funclet", EHPad);
388818a7761SGor Nishanov
389818a7761SGor Nishanov return BundleList;
390818a7761SGor Nishanov }
391818a7761SGor Nishanov
392818a7761SGor Nishanov namespace {
393818a7761SGor Nishanov // We will insert coro.end to cut any of the destructors for objects that
394818a7761SGor Nishanov // do not need to be destroyed once the coroutine is resumed.
395818a7761SGor Nishanov // See llvm/docs/Coroutines.rst for more details about coro.end.
396818a7761SGor Nishanov struct CallCoroEnd final : public EHScopeStack::Cleanup {
Emit__anon268cdc500611::CallCoroEnd397818a7761SGor Nishanov void Emit(CodeGenFunction &CGF, Flags flags) override {
398818a7761SGor Nishanov auto &CGM = CGF.CGM;
399818a7761SGor Nishanov auto *NullPtr = llvm::ConstantPointerNull::get(CGF.Int8PtrTy);
400818a7761SGor Nishanov llvm::Function *CoroEndFn = CGM.getIntrinsic(llvm::Intrinsic::coro_end);
401818a7761SGor Nishanov // See if we have a funclet bundle to associate coro.end with. (WinEH)
402818a7761SGor Nishanov auto Bundles = getBundlesForCoroEnd(CGF);
403818a7761SGor Nishanov auto *CoroEnd = CGF.Builder.CreateCall(
404818a7761SGor Nishanov CoroEndFn, {NullPtr, CGF.Builder.getTrue()}, Bundles);
405818a7761SGor Nishanov if (Bundles.empty()) {
406818a7761SGor Nishanov // Otherwise, (landingpad model), create a conditional branch that leads
407818a7761SGor Nishanov // either to a cleanup block or a block with EH resume instruction.
40849a3ad21SRui Ueyama auto *ResumeBB = CGF.getEHResumeBlock(/*isCleanup=*/true);
409818a7761SGor Nishanov auto *CleanupContBB = CGF.createBasicBlock("cleanup.cont");
410818a7761SGor Nishanov CGF.Builder.CreateCondBr(CoroEnd, ResumeBB, CleanupContBB);
411818a7761SGor Nishanov CGF.EmitBlock(CleanupContBB);
412818a7761SGor Nishanov }
413818a7761SGor Nishanov }
414818a7761SGor Nishanov };
415818a7761SGor Nishanov }
416818a7761SGor Nishanov
41763b6df4fSGor Nishanov namespace {
41863b6df4fSGor Nishanov // Make sure to call coro.delete on scope exit.
41963b6df4fSGor Nishanov struct CallCoroDelete final : public EHScopeStack::Cleanup {
42063b6df4fSGor Nishanov Stmt *Deallocate;
42163b6df4fSGor Nishanov
4226c4530c6SGor Nishanov // Emit "if (coro.free(CoroId, CoroBegin)) Deallocate;"
4236c4530c6SGor Nishanov
42463b6df4fSGor Nishanov // Note: That deallocation will be emitted twice: once for a normal exit and
42563b6df4fSGor Nishanov // once for exceptional exit. This usage is safe because Deallocate does not
42663b6df4fSGor Nishanov // contain any declarations. The SubStmtBuilder::makeNewAndDeleteExpr()
42763b6df4fSGor Nishanov // builds a single call to a deallocation function which is safe to emit
42863b6df4fSGor Nishanov // multiple times.
Emit__anon268cdc500711::CallCoroDelete4296c4530c6SGor Nishanov void Emit(CodeGenFunction &CGF, Flags) override {
4306c4530c6SGor Nishanov // Remember the current point, as we are going to emit deallocation code
4316c4530c6SGor Nishanov // first to get to coro.free instruction that is an argument to a delete
4326c4530c6SGor Nishanov // call.
4336c4530c6SGor Nishanov BasicBlock *SaveInsertBlock = CGF.Builder.GetInsertBlock();
4346c4530c6SGor Nishanov
4356c4530c6SGor Nishanov auto *FreeBB = CGF.createBasicBlock("coro.free");
4366c4530c6SGor Nishanov CGF.EmitBlock(FreeBB);
43763b6df4fSGor Nishanov CGF.EmitStmt(Deallocate);
4386c4530c6SGor Nishanov
4396c4530c6SGor Nishanov auto *AfterFreeBB = CGF.createBasicBlock("after.coro.free");
4406c4530c6SGor Nishanov CGF.EmitBlock(AfterFreeBB);
4416c4530c6SGor Nishanov
4426c4530c6SGor Nishanov // We should have captured coro.free from the emission of deallocate.
4436c4530c6SGor Nishanov auto *CoroFree = CGF.CurCoro.Data->LastCoroFree;
4446c4530c6SGor Nishanov if (!CoroFree) {
445f2ceec48SStephen Kelly CGF.CGM.Error(Deallocate->getBeginLoc(),
4466c4530c6SGor Nishanov "Deallocation expressoin does not refer to coro.free");
4476c4530c6SGor Nishanov return;
4486c4530c6SGor Nishanov }
4496c4530c6SGor Nishanov
4506c4530c6SGor Nishanov // Get back to the block we were originally and move coro.free there.
4516c4530c6SGor Nishanov auto *InsertPt = SaveInsertBlock->getTerminator();
4526c4530c6SGor Nishanov CoroFree->moveBefore(InsertPt);
4536c4530c6SGor Nishanov CGF.Builder.SetInsertPoint(InsertPt);
4546c4530c6SGor Nishanov
4556c4530c6SGor Nishanov // Add if (auto *mem = coro.free) Deallocate;
4566c4530c6SGor Nishanov auto *NullPtr = llvm::ConstantPointerNull::get(CGF.Int8PtrTy);
4576c4530c6SGor Nishanov auto *Cond = CGF.Builder.CreateICmpNE(CoroFree, NullPtr);
4586c4530c6SGor Nishanov CGF.Builder.CreateCondBr(Cond, FreeBB, AfterFreeBB);
4596c4530c6SGor Nishanov
4606c4530c6SGor Nishanov // No longer need old terminator.
4616c4530c6SGor Nishanov InsertPt->eraseFromParent();
4626c4530c6SGor Nishanov CGF.Builder.SetInsertPoint(AfterFreeBB);
46363b6df4fSGor Nishanov }
CallCoroDelete__anon268cdc500711::CallCoroDelete46463b6df4fSGor Nishanov explicit CallCoroDelete(Stmt *DeallocStmt) : Deallocate(DeallocStmt) {}
46563b6df4fSGor Nishanov };
46663b6df4fSGor Nishanov }
46763b6df4fSGor Nishanov
emitBodyAndFallthrough(CodeGenFunction & CGF,const CoroutineBodyStmt & S,Stmt * Body)4685b050e4aSGor Nishanov static void emitBodyAndFallthrough(CodeGenFunction &CGF,
4695b050e4aSGor Nishanov const CoroutineBodyStmt &S, Stmt *Body) {
4705b050e4aSGor Nishanov CGF.EmitStmt(Body);
4715b050e4aSGor Nishanov const bool CanFallthrough = CGF.Builder.GetInsertBlock();
4725b050e4aSGor Nishanov if (CanFallthrough)
4735b050e4aSGor Nishanov if (Stmt *OnFallthrough = S.getFallthroughHandler())
4745b050e4aSGor Nishanov CGF.EmitStmt(OnFallthrough);
4755b050e4aSGor Nishanov }
4765b050e4aSGor Nishanov
EmitCoroutineBody(const CoroutineBodyStmt & S)4778df64e94SGor Nishanov void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
4788df64e94SGor Nishanov auto *NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy());
4798df64e94SGor Nishanov auto &TI = CGM.getContext().getTargetInfo();
4808df64e94SGor Nishanov unsigned NewAlign = TI.getNewAlign() / TI.getCharWidth();
4818df64e94SGor Nishanov
482aa6e9a99SGor Nishanov auto *EntryBB = Builder.GetInsertBlock();
483aa6e9a99SGor Nishanov auto *AllocBB = createBasicBlock("coro.alloc");
484aa6e9a99SGor Nishanov auto *InitBB = createBasicBlock("coro.init");
48590be1213SGor Nishanov auto *FinalBB = createBasicBlock("coro.final");
4865eb58583SGor Nishanov auto *RetBB = createBasicBlock("coro.ret");
48790be1213SGor Nishanov
4888df64e94SGor Nishanov auto *CoroId = Builder.CreateCall(
4898df64e94SGor Nishanov CGM.getIntrinsic(llvm::Intrinsic::coro_id),
4908df64e94SGor Nishanov {Builder.getInt32(NewAlign), NullPtr, NullPtr, NullPtr});
4918df64e94SGor Nishanov createCoroData(*this, CurCoro, CoroId);
4925eb58583SGor Nishanov CurCoro.Data->SuspendBB = RetBB;
493c7a39c83SXun Li assert(ShouldEmitLifetimeMarkers &&
494c7a39c83SXun Li "Must emit lifetime intrinsics for coroutines");
4958df64e94SGor Nishanov
496aa6e9a99SGor Nishanov // Backend is allowed to elide memory allocations, to help it, emit
497aa6e9a99SGor Nishanov // auto mem = coro.alloc() ? 0 : ... allocation code ...;
498aa6e9a99SGor Nishanov auto *CoroAlloc = Builder.CreateCall(
499aa6e9a99SGor Nishanov CGM.getIntrinsic(llvm::Intrinsic::coro_alloc), {CoroId});
500aa6e9a99SGor Nishanov
501aa6e9a99SGor Nishanov Builder.CreateCondBr(CoroAlloc, AllocBB, InitBB);
502aa6e9a99SGor Nishanov
503aa6e9a99SGor Nishanov EmitBlock(AllocBB);
5043aa9eb38SGor Nishanov auto *AllocateCall = EmitScalarExpr(S.getAllocate());
505aa6e9a99SGor Nishanov auto *AllocOrInvokeContBB = Builder.GetInsertBlock();
5063aa9eb38SGor Nishanov
5073aa9eb38SGor Nishanov // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
5083aa9eb38SGor Nishanov if (auto *RetOnAllocFailure = S.getReturnStmtOnAllocFailure()) {
5093aa9eb38SGor Nishanov auto *RetOnFailureBB = createBasicBlock("coro.ret.on.failure");
5103aa9eb38SGor Nishanov
5113aa9eb38SGor Nishanov // See if allocation was successful.
5123aa9eb38SGor Nishanov auto *NullPtr = llvm::ConstantPointerNull::get(Int8PtrTy);
5133aa9eb38SGor Nishanov auto *Cond = Builder.CreateICmpNE(AllocateCall, NullPtr);
5143aa9eb38SGor Nishanov Builder.CreateCondBr(Cond, InitBB, RetOnFailureBB);
5153aa9eb38SGor Nishanov
5163aa9eb38SGor Nishanov // If not, return OnAllocFailure object.
5173aa9eb38SGor Nishanov EmitBlock(RetOnFailureBB);
5183aa9eb38SGor Nishanov EmitStmt(RetOnAllocFailure);
519aa6e9a99SGor Nishanov }
520aa6e9a99SGor Nishanov else {
521aa6e9a99SGor Nishanov Builder.CreateBr(InitBB);
522aa6e9a99SGor Nishanov }
5233aa9eb38SGor Nishanov
5243aa9eb38SGor Nishanov EmitBlock(InitBB);
525aa6e9a99SGor Nishanov
526aa6e9a99SGor Nishanov // Pass the result of the allocation to coro.begin.
527aa6e9a99SGor Nishanov auto *Phi = Builder.CreatePHI(VoidPtrTy, 2);
528aa6e9a99SGor Nishanov Phi->addIncoming(NullPtr, EntryBB);
529aa6e9a99SGor Nishanov Phi->addIncoming(AllocateCall, AllocOrInvokeContBB);
53068fe6ee7SGor Nishanov auto *CoroBegin = Builder.CreateCall(
531aa6e9a99SGor Nishanov CGM.getIntrinsic(llvm::Intrinsic::coro_begin), {CoroId, Phi});
53268fe6ee7SGor Nishanov CurCoro.Data->CoroBegin = CoroBegin;
53390be1213SGor Nishanov
53463b6df4fSGor Nishanov CurCoro.Data->CleanupJD = getJumpDestInCurrentScope(RetBB);
53563b6df4fSGor Nishanov {
5363a6a80b6Syifeng.dongyifeng CGDebugInfo *DI = getDebugInfo();
53733d5fd24SGor Nishanov ParamReferenceReplacerRAII ParamReplacer(LocalDeclMap);
53863b6df4fSGor Nishanov CodeGenFunction::RunCleanupsScope ResumeScope(*this);
53963b6df4fSGor Nishanov EHStack.pushCleanup<CallCoroDelete>(NormalAndEHCleanup, S.getDeallocate());
54090be1213SGor Nishanov
5413a6a80b6Syifeng.dongyifeng // Create mapping between parameters and copy-params for coroutine function.
5423a6a80b6Syifeng.dongyifeng auto ParamMoves = S.getParamMoves();
5433a6a80b6Syifeng.dongyifeng assert(
5443a6a80b6Syifeng.dongyifeng (ParamMoves.size() == 0 || (ParamMoves.size() == FnArgs.size())) &&
5453a6a80b6Syifeng.dongyifeng "ParamMoves and FnArgs should be the same size for coroutine function");
5463a6a80b6Syifeng.dongyifeng if (ParamMoves.size() == FnArgs.size() && DI)
5473a6a80b6Syifeng.dongyifeng for (const auto Pair : llvm::zip(FnArgs, ParamMoves))
5483a6a80b6Syifeng.dongyifeng DI->getCoroutineParameterMappings().insert(
5493a6a80b6Syifeng.dongyifeng {std::get<0>(Pair), std::get<1>(Pair)});
5503a6a80b6Syifeng.dongyifeng
55133d5fd24SGor Nishanov // Create parameter copies. We do it before creating a promise, since an
55233d5fd24SGor Nishanov // evolution of coroutine TS may allow promise constructor to observe
55333d5fd24SGor Nishanov // parameter copies.
55433d5fd24SGor Nishanov for (auto *PM : S.getParamMoves()) {
55533d5fd24SGor Nishanov EmitStmt(PM);
55633d5fd24SGor Nishanov ParamReplacer.addCopy(cast<DeclStmt>(PM));
55733d5fd24SGor Nishanov // TODO: if(CoroParam(...)) need to surround ctor and dtor
55833d5fd24SGor Nishanov // for the copy, so that llvm can elide it if the copy is
55933d5fd24SGor Nishanov // not needed.
56033d5fd24SGor Nishanov }
56133d5fd24SGor Nishanov
56290be1213SGor Nishanov EmitStmt(S.getPromiseDeclStmt());
56390be1213SGor Nishanov
56433d5fd24SGor Nishanov Address PromiseAddr = GetAddrOfLocalVar(S.getPromiseDecl());
56533d5fd24SGor Nishanov auto *PromiseAddrVoidPtr =
56633d5fd24SGor Nishanov new llvm::BitCastInst(PromiseAddr.getPointer(), VoidPtrTy, "", CoroId);
56733d5fd24SGor Nishanov // Update CoroId to refer to the promise. We could not do it earlier because
56833d5fd24SGor Nishanov // promise local variable was not emitted yet.
56933d5fd24SGor Nishanov CoroId->setArgOperand(1, PromiseAddrVoidPtr);
57033d5fd24SGor Nishanov
571d30ca5e2SChuanqi Xu // ReturnValue should be valid as long as the coroutine's return type
572d30ca5e2SChuanqi Xu // is not void. The assertion could help us to reduce the check later.
573d30ca5e2SChuanqi Xu assert(ReturnValue.isValid() == (bool)S.getReturnStmt());
574d30ca5e2SChuanqi Xu // Now we have the promise, initialize the GRO.
575d30ca5e2SChuanqi Xu // We need to emit `get_return_object` first. According to:
576d30ca5e2SChuanqi Xu // [dcl.fct.def.coroutine]p7
577d30ca5e2SChuanqi Xu // The call to get_return_object is sequenced before the call to
578d30ca5e2SChuanqi Xu // initial_suspend and is invoked at most once.
579d30ca5e2SChuanqi Xu //
580d30ca5e2SChuanqi Xu // So we couldn't emit return value when we emit return statment,
581d30ca5e2SChuanqi Xu // otherwise the call to get_return_object wouldn't be in front
582d30ca5e2SChuanqi Xu // of initial_suspend.
583d30ca5e2SChuanqi Xu if (ReturnValue.isValid()) {
584d30ca5e2SChuanqi Xu EmitAnyExprToMem(S.getReturnValue(), ReturnValue,
585d30ca5e2SChuanqi Xu S.getReturnValue()->getType().getQualifiers(),
586d30ca5e2SChuanqi Xu /*IsInit*/ true);
587d30ca5e2SChuanqi Xu }
58833d5fd24SGor Nishanov
589818a7761SGor Nishanov EHStack.pushCleanup<CallCoroEnd>(EHCleanup);
590818a7761SGor Nishanov
5915efc6186SGor Nishanov CurCoro.Data->CurrentAwaitKind = AwaitKind::Init;
592ea9144e8SBrian Gesiak CurCoro.Data->ExceptionHandler = S.getExceptionHandler();
5935efc6186SGor Nishanov EmitStmt(S.getInitSuspendStmt());
59433d5fd24SGor Nishanov CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB);
59590be1213SGor Nishanov
5965eb58583SGor Nishanov CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal;
5975b050e4aSGor Nishanov
598ea9144e8SBrian Gesiak if (CurCoro.Data->ExceptionHandler) {
59912728474SBrian Gesiak // If we generated IR to record whether an exception was thrown from
60012728474SBrian Gesiak // 'await_resume', then use that IR to determine whether the coroutine
60112728474SBrian Gesiak // body should be skipped.
60212728474SBrian Gesiak // If we didn't generate the IR (perhaps because 'await_resume' was marked
60312728474SBrian Gesiak // as 'noexcept'), then we skip this check.
60412728474SBrian Gesiak BasicBlock *ContBB = nullptr;
60512728474SBrian Gesiak if (CurCoro.Data->ResumeEHVar) {
606ea9144e8SBrian Gesiak BasicBlock *BodyBB = createBasicBlock("coro.resumed.body");
60712728474SBrian Gesiak ContBB = createBasicBlock("coro.resumed.cont");
60812728474SBrian Gesiak Value *SkipBody = Builder.CreateFlagLoad(CurCoro.Data->ResumeEHVar,
60912728474SBrian Gesiak "coro.resumed.eh");
610ea9144e8SBrian Gesiak Builder.CreateCondBr(SkipBody, ContBB, BodyBB);
611ea9144e8SBrian Gesiak EmitBlock(BodyBB);
61212728474SBrian Gesiak }
613ea9144e8SBrian Gesiak
614f2ceec48SStephen Kelly auto Loc = S.getBeginLoc();
615ea9144e8SBrian Gesiak CXXCatchStmt Catch(Loc, /*exDecl=*/nullptr,
616ea9144e8SBrian Gesiak CurCoro.Data->ExceptionHandler);
617ea9144e8SBrian Gesiak auto *TryStmt =
618ea9144e8SBrian Gesiak CXXTryStmt::Create(getContext(), Loc, S.getBody(), &Catch);
6195b050e4aSGor Nishanov
6205b050e4aSGor Nishanov EnterCXXTryStmt(*TryStmt);
6215b050e4aSGor Nishanov emitBodyAndFallthrough(*this, S, TryStmt->getTryBlock());
6225b050e4aSGor Nishanov ExitCXXTryStmt(*TryStmt);
623ea9144e8SBrian Gesiak
62412728474SBrian Gesiak if (ContBB)
625ea9144e8SBrian Gesiak EmitBlock(ContBB);
6265b050e4aSGor Nishanov }
6275b050e4aSGor Nishanov else {
6285b050e4aSGor Nishanov emitBodyAndFallthrough(*this, S, S.getBody());
6295b050e4aSGor Nishanov }
63090be1213SGor Nishanov
63190be1213SGor Nishanov // See if we need to generate final suspend.
63290be1213SGor Nishanov const bool CanFallthrough = Builder.GetInsertBlock();
63390be1213SGor Nishanov const bool HasCoreturns = CurCoro.Data->CoreturnCount > 0;
63490be1213SGor Nishanov if (CanFallthrough || HasCoreturns) {
63590be1213SGor Nishanov EmitBlock(FinalBB);
6365efc6186SGor Nishanov CurCoro.Data->CurrentAwaitKind = AwaitKind::Final;
6375efc6186SGor Nishanov EmitStmt(S.getFinalSuspendStmt());
63875a8ea5eSGor Nishanov } else {
639db615dd6SGor Nishanov // We don't need FinalBB. Emit it to make sure the block is deleted.
640db615dd6SGor Nishanov EmitBlock(FinalBB, /*IsFinished=*/true);
641db615dd6SGor Nishanov }
64263b6df4fSGor Nishanov }
64390be1213SGor Nishanov
6445eb58583SGor Nishanov EmitBlock(RetBB);
6456a470689SGor Nishanov // Emit coro.end before getReturnStmt (and parameter destructors), since
6466a470689SGor Nishanov // resume and destroy parts of the coroutine should not include them.
647818a7761SGor Nishanov llvm::Function *CoroEnd = CGM.getIntrinsic(llvm::Intrinsic::coro_end);
648818a7761SGor Nishanov Builder.CreateCall(CoroEnd, {NullPtr, Builder.getFalse()});
6495eb58583SGor Nishanov
650d30ca5e2SChuanqi Xu if (Stmt *Ret = S.getReturnStmt()) {
651d30ca5e2SChuanqi Xu // Since we already emitted the return value above, so we shouldn't
652d30ca5e2SChuanqi Xu // emit it again here.
653d30ca5e2SChuanqi Xu cast<ReturnStmt>(Ret)->setRetValue(nullptr);
6546a470689SGor Nishanov EmitStmt(Ret);
655d30ca5e2SChuanqi Xu }
656c75cedc2SChuanqi Xu
657735e6c40SChuanqi Xu // LLVM require the frontend to mark the coroutine.
658735e6c40SChuanqi Xu CurFn->setPresplitCoroutine();
65997e3b6d8SGor Nishanov }
66097e3b6d8SGor Nishanov
66197e3b6d8SGor Nishanov // Emit coroutine intrinsic and patch up arguments of the token type.
EmitCoroutineIntrinsic(const CallExpr * E,unsigned int IID)66297e3b6d8SGor Nishanov RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
66397e3b6d8SGor Nishanov unsigned int IID) {
66497e3b6d8SGor Nishanov SmallVector<llvm::Value *, 8> Args;
66597e3b6d8SGor Nishanov switch (IID) {
66697e3b6d8SGor Nishanov default:
66797e3b6d8SGor Nishanov break;
66868fe6ee7SGor Nishanov // The coro.frame builtin is replaced with an SSA value of the coro.begin
66968fe6ee7SGor Nishanov // intrinsic.
67068fe6ee7SGor Nishanov case llvm::Intrinsic::coro_frame: {
67168fe6ee7SGor Nishanov if (CurCoro.Data && CurCoro.Data->CoroBegin) {
67268fe6ee7SGor Nishanov return RValue::get(CurCoro.Data->CoroBegin);
67368fe6ee7SGor Nishanov }
674f2ceec48SStephen Kelly CGM.Error(E->getBeginLoc(), "this builtin expect that __builtin_coro_begin "
67568fe6ee7SGor Nishanov "has been used earlier in this function");
67668fe6ee7SGor Nishanov auto NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy());
67768fe6ee7SGor Nishanov return RValue::get(NullPtr);
67868fe6ee7SGor Nishanov }
67997e3b6d8SGor Nishanov // The following three intrinsics take a token parameter referring to a token
68097e3b6d8SGor Nishanov // returned by earlier call to @llvm.coro.id. Since we cannot represent it in
68197e3b6d8SGor Nishanov // builtins, we patch it up here.
68297e3b6d8SGor Nishanov case llvm::Intrinsic::coro_alloc:
68397e3b6d8SGor Nishanov case llvm::Intrinsic::coro_begin:
68497e3b6d8SGor Nishanov case llvm::Intrinsic::coro_free: {
68597e3b6d8SGor Nishanov if (CurCoro.Data && CurCoro.Data->CoroId) {
68697e3b6d8SGor Nishanov Args.push_back(CurCoro.Data->CoroId);
68797e3b6d8SGor Nishanov break;
68897e3b6d8SGor Nishanov }
689f2ceec48SStephen Kelly CGM.Error(E->getBeginLoc(), "this builtin expect that __builtin_coro_id has"
69097e3b6d8SGor Nishanov " been used earlier in this function");
69197e3b6d8SGor Nishanov // Fallthrough to the next case to add TokenNone as the first argument.
6920872d6c2SGalina Kistanova LLVM_FALLTHROUGH;
69397e3b6d8SGor Nishanov }
69497e3b6d8SGor Nishanov // @llvm.coro.suspend takes a token parameter. Add token 'none' as the first
69597e3b6d8SGor Nishanov // argument.
69697e3b6d8SGor Nishanov case llvm::Intrinsic::coro_suspend:
69797e3b6d8SGor Nishanov Args.push_back(llvm::ConstantTokenNone::get(getLLVMContext()));
69897e3b6d8SGor Nishanov break;
69997e3b6d8SGor Nishanov }
700259e1bdfSRichard Smith for (const Expr *Arg : E->arguments())
70197e3b6d8SGor Nishanov Args.push_back(EmitScalarExpr(Arg));
70297e3b6d8SGor Nishanov
7038799caeeSJames Y Knight llvm::Function *F = CGM.getIntrinsic(IID);
70497e3b6d8SGor Nishanov llvm::CallInst *Call = Builder.CreateCall(F, Args);
70597e3b6d8SGor Nishanov
7066c4530c6SGor Nishanov // Note: The following code is to enable to emit coro.id and coro.begin by
70768fe6ee7SGor Nishanov // hand to experiment with coroutines in C.
70897e3b6d8SGor Nishanov // If we see @llvm.coro.id remember it in the CoroData. We will update
70997e3b6d8SGor Nishanov // coro.alloc, coro.begin and coro.free intrinsics to refer to it.
71097e3b6d8SGor Nishanov if (IID == llvm::Intrinsic::coro_id) {
71197e3b6d8SGor Nishanov createCoroData(*this, CurCoro, Call, E);
71297e3b6d8SGor Nishanov }
71368fe6ee7SGor Nishanov else if (IID == llvm::Intrinsic::coro_begin) {
71468fe6ee7SGor Nishanov if (CurCoro.Data)
71568fe6ee7SGor Nishanov CurCoro.Data->CoroBegin = Call;
71668fe6ee7SGor Nishanov }
7176c4530c6SGor Nishanov else if (IID == llvm::Intrinsic::coro_free) {
7186c4530c6SGor Nishanov // Remember the last coro_free as we need it to build the conditional
7196c4530c6SGor Nishanov // deletion of the coroutine frame.
7206c4530c6SGor Nishanov if (CurCoro.Data)
7216c4530c6SGor Nishanov CurCoro.Data->LastCoroFree = Call;
72233d5fd24SGor Nishanov }
72333d5fd24SGor Nishanov return RValue::get(Call);
72497e3b6d8SGor Nishanov }
725