15 #include "llvm/ADT/ScopeExit.h"
19 using namespace clang;
20 using namespace CodeGen;
23 using llvm::BasicBlock;
26 enum class AwaitKind { Init,
Normal, Yield, Final };
27 static constexpr llvm::StringLiteral AwaitKindStr[] = {
"init",
"await",
"yield",
91 llvm::CallInst *CoroId,
92 CallExpr const *CoroIdExpr =
nullptr) {
95 CGF.
CGM.
Error(CoroIdExpr->getBeginLoc(),
96 "only one __builtin_coro_id can be used in a function");
98 CGF.
CGM.
Error(CoroIdExpr->getBeginLoc(),
99 "__builtin_coro_id shall not be used in a C++ coroutine");
101 llvm_unreachable(
"EmitCoroutineBodyStatement called twice?");
115 case AwaitKind::Init:
116 case AwaitKind::Final:
118 case AwaitKind::Normal:
121 case AwaitKind::Yield:
127 Twine(
No).toVector(Prefix);
133 if (
const auto *CE = dyn_cast<CXXMemberCallExpr>(E))
134 if (
const auto *Proto =
170 struct LValueOrRValue {
178 bool ignoreResult,
bool forLValue) {
179 auto *E = S.getCommonExpr();
183 auto UnbindOnExit = llvm::make_scope_exit([&] { Binder.unbind(CGF); });
187 BasicBlock *SuspendBlock = CGF.
createBasicBlock(Prefix + Twine(
".suspend"));
188 BasicBlock *CleanupBlock = CGF.
createBasicBlock(Prefix + Twine(
".cleanup"));
197 llvm::Function *CoroSave = CGF.
CGM.
getIntrinsic(llvm::Intrinsic::coro_save);
198 auto *NullPtr = llvm::ConstantPointerNull::get(CGF.
CGM.
Int8PtrTy);
199 auto *SaveCall =
Builder.CreateCall(CoroSave, {NullPtr});
202 if (SuspendRet !=
nullptr && SuspendRet->getType()->isIntegerTy(1)) {
204 BasicBlock *RealSuspendBlock =
206 CGF.
Builder.CreateCondBr(SuspendRet, RealSuspendBlock, ReadyBlock);
211 const bool IsFinalSuspend = (
Kind == AwaitKind::Final);
212 llvm::Function *CoroSuspend =
214 auto *SuspendResult =
Builder.CreateCall(
215 CoroSuspend, {SaveCall,
Builder.getInt1(IsFinalSuspend)});
238 auto Loc = S.getResumeExpr()->getExprLoc();
251 Res.RV = CGF.
EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult);
266 ignoreResult,
false).RV;
272 aggSlot, ignoreResult,
false).RV;
277 const Expr *RV = S.getOperand();
295 assert(isa<CallExpr>(RE) &&
"unexpected suspend expression type");
296 return cast<CallExpr>(RE)->getCallReturnType(Ctx);
303 "Can't have a scalar return unless the return type is a "
313 "Can't have a scalar return unless the return type is a "
322 struct GetParamRef :
public StmtVisitor<GetParamRef> {
327 assert(
Expr ==
nullptr &&
"multilple declref in param move");
330 void VisitStmt(
Stmt *S) {
331 for (
auto *C : S->children()) {
344 struct ParamReferenceReplacerRAII {
349 : LocalDeclMap(LocalDeclMap) {}
358 Visitor.Visit(
const_cast<Expr*
>(InitExpr));
359 assert(Visitor.Expr);
363 auto it = LocalDeclMap.find(PD);
364 assert(it != LocalDeclMap.end() &&
"parameter is not found");
365 SavedLocals.insert({ PD, it->second });
367 auto copyIt = LocalDeclMap.find(VD);
368 assert(copyIt != LocalDeclMap.end() &&
"parameter copy is not found");
369 it->second = copyIt->getSecond();
372 ~ParamReferenceReplacerRAII() {
373 for (
auto&& SavedLocal : SavedLocals) {
374 LocalDeclMap.insert({SavedLocal.first, SavedLocal.second});
387 BundleList.emplace_back(
"funclet", EHPad);
399 auto *NullPtr = llvm::ConstantPointerNull::get(CGF.
Int8PtrTy);
400 llvm::Function *CoroEndFn =
CGM.
getIntrinsic(llvm::Intrinsic::coro_end);
403 auto *CoroEnd = CGF.
Builder.CreateCall(
404 CoroEndFn, {NullPtr, CGF.
Builder.getTrue()}, Bundles);
405 if (Bundles.empty()) {
410 CGF.
Builder.CreateCondBr(CoroEnd, ResumeBB, CleanupContBB);
433 BasicBlock *SaveInsertBlock = CGF.
Builder.GetInsertBlock();
445 CGF.
CGM.
Error(Deallocate->getBeginLoc(),
446 "Deallocation expressoin does not refer to coro.free");
451 auto *InsertPt = SaveInsertBlock->getTerminator();
452 CoroFree->moveBefore(InsertPt);
453 CGF.
Builder.SetInsertPoint(InsertPt);
456 auto *NullPtr = llvm::ConstantPointerNull::get(CGF.
Int8PtrTy);
457 auto *Cond = CGF.
Builder.CreateICmpNE(CoroFree, NullPtr);
458 CGF.
Builder.CreateCondBr(Cond, FreeBB, AfterFreeBB);
461 InsertPt->eraseFromParent();
462 CGF.
Builder.SetInsertPoint(AfterFreeBB);
464 explicit CallCoroDelete(
Stmt *DeallocStmt) : Deallocate(DeallocStmt) {}
469 struct GetReturnObjectManager {
487 void EmitGroAlloca() {
488 auto *GroDeclStmt = dyn_cast<DeclStmt>(S.getResultDecl());
494 auto *GroVarDecl = cast<VarDecl>(GroDeclStmt->getSingleDecl());
511 if (
auto *Cleanup = dyn_cast<EHCleanupScope>(&*
b)) {
512 assert(!Cleanup->hasActiveFlag() &&
"cleanup already has active flag?");
513 Cleanup->setActiveFlag(GroActiveFlag);
514 Cleanup->setTestFlagInEHCleanup();
515 Cleanup->setTestFlagInNormalCleanup();
521 if (!GroActiveFlag.
isValid()) {
537 const bool CanFallthrough = CGF.
Builder.GetInsertBlock();
539 if (
Stmt *OnFallthrough = S.getFallthroughHandler())
544 auto *NullPtr = llvm::ConstantPointerNull::get(
Builder.getInt8PtrTy());
546 unsigned NewAlign = TI.
getNewAlign() / TI.getCharWidth();
548 auto *EntryBB =
Builder.GetInsertBlock();
554 auto *CoroId =
Builder.CreateCall(
556 {Builder.getInt32(NewAlign), NullPtr, NullPtr, NullPtr});
562 auto *CoroAlloc =
Builder.CreateCall(
565 Builder.CreateCondBr(CoroAlloc, AllocBB, InitBB);
569 auto *AllocOrInvokeContBB =
Builder.GetInsertBlock();
572 if (
auto *RetOnAllocFailure = S.getReturnStmtOnAllocFailure()) {
576 auto *NullPtr = llvm::ConstantPointerNull::get(
Int8PtrTy);
577 auto *Cond =
Builder.CreateICmpNE(AllocateCall, NullPtr);
578 Builder.CreateCondBr(Cond, InitBB, RetOnFailureBB);
592 Phi->addIncoming(NullPtr, EntryBB);
593 Phi->addIncoming(AllocateCall, AllocOrInvokeContBB);
594 auto *CoroBegin =
Builder.CreateCall(
598 GetReturnObjectManager GroManager(*
this, S);
599 GroManager.EmitGroAlloca();
603 ParamReferenceReplacerRAII ParamReplacer(LocalDeclMap);
610 for (
auto *PM : S.getParamMoves()) {
612 ParamReplacer.addCopy(cast<DeclStmt>(PM));
621 auto *PromiseAddrVoidPtr =
625 CoroId->setArgOperand(1, PromiseAddrVoidPtr);
628 GroManager.EmitGroInit();
633 CurCoro.
Data->ExceptionHandler = S.getExceptionHandler();
637 CurCoro.
Data->CurrentAwaitKind = AwaitKind::Normal;
645 BasicBlock *ContBB =
nullptr;
651 Builder.CreateCondBr(SkipBody, ContBB, BodyBB);
655 auto Loc = S.getBeginLoc();
673 const bool CanFallthrough =
Builder.GetInsertBlock();
674 const bool HasCoreturns =
CurCoro.
Data->CoreturnCount > 0;
675 if (CanFallthrough || HasCoreturns) {
691 if (
Stmt *
Ret = S.getReturnStmt())
704 case llvm::Intrinsic::coro_frame: {
709 "has been used earlier in this function");
710 auto NullPtr = llvm::ConstantPointerNull::get(
Builder.getInt8PtrTy());
716 case llvm::Intrinsic::coro_alloc:
717 case llvm::Intrinsic::coro_begin:
718 case llvm::Intrinsic::coro_free: {
724 " been used earlier in this function");
730 case llvm::Intrinsic::coro_suspend:
738 llvm::CallInst *Call =
Builder.CreateCall(F, Args);
744 if (IID == llvm::Intrinsic::coro_id) {
747 else if (IID == llvm::Intrinsic::coro_begin) {
751 else if (IID == llvm::Intrinsic::coro_free) {