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) {}
471 const bool CanFallthrough = CGF.
Builder.GetInsertBlock();
473 if (
Stmt *OnFallthrough = S.getFallthroughHandler())
478 auto *NullPtr = llvm::ConstantPointerNull::get(
Builder.getInt8PtrTy());
480 unsigned NewAlign = TI.
getNewAlign() / TI.getCharWidth();
482 auto *EntryBB =
Builder.GetInsertBlock();
488 auto *CoroId =
Builder.CreateCall(
490 {Builder.getInt32(NewAlign), NullPtr, NullPtr, NullPtr});
493 assert(ShouldEmitLifetimeMarkers &&
494 "Must emit lifetime intrinsics for coroutines");
498 auto *CoroAlloc =
Builder.CreateCall(
501 Builder.CreateCondBr(CoroAlloc, AllocBB, InitBB);
505 auto *AllocOrInvokeContBB =
Builder.GetInsertBlock();
508 if (
auto *RetOnAllocFailure = S.getReturnStmtOnAllocFailure()) {
512 auto *NullPtr = llvm::ConstantPointerNull::get(
Int8PtrTy);
513 auto *Cond =
Builder.CreateICmpNE(AllocateCall, NullPtr);
514 Builder.CreateCondBr(Cond, InitBB, RetOnFailureBB);
528 Phi->addIncoming(NullPtr, EntryBB);
529 Phi->addIncoming(AllocateCall, AllocOrInvokeContBB);
530 auto *CoroBegin =
Builder.CreateCall(
537 ParamReferenceReplacerRAII ParamReplacer(LocalDeclMap);
544 (ParamMoves.size() == 0 || (ParamMoves.size() ==
FnArgs.size())) &&
545 "ParamMoves and FnArgs should be the same size for coroutine function");
546 if (ParamMoves.size() ==
FnArgs.size() && DI)
547 for (
const auto Pair : llvm::zip(
FnArgs, ParamMoves))
549 {std::get<0>(Pair), std::get<1>(Pair)});
554 for (
auto *PM : S.getParamMoves()) {
556 ParamReplacer.addCopy(cast<DeclStmt>(PM));
565 auto *PromiseAddrVoidPtr =
569 CoroId->setArgOperand(1, PromiseAddrVoidPtr);
585 S.getReturnValue()->getType().getQualifiers(),
592 CurCoro.
Data->ExceptionHandler = S.getExceptionHandler();
596 CurCoro.
Data->CurrentAwaitKind = AwaitKind::Normal;
604 BasicBlock *ContBB =
nullptr;
610 Builder.CreateCondBr(SkipBody, ContBB, BodyBB);
614 auto Loc = S.getBeginLoc();
632 const bool CanFallthrough =
Builder.GetInsertBlock();
633 const bool HasCoreturns =
CurCoro.
Data->CoreturnCount > 0;
634 if (CanFallthrough || HasCoreturns) {
650 if (
Stmt *
Ret = S.getReturnStmt()) {
653 cast<ReturnStmt>(
Ret)->setRetValue(
nullptr);
658 CurFn->setPresplitCoroutine();
670 case llvm::Intrinsic::coro_frame: {
675 "has been used earlier in this function");
676 auto *NullPtr = llvm::ConstantPointerNull::get(
Builder.getInt8PtrTy());
679 case llvm::Intrinsic::coro_size: {
686 case llvm::Intrinsic::coro_align: {
696 case llvm::Intrinsic::coro_alloc:
697 case llvm::Intrinsic::coro_begin:
698 case llvm::Intrinsic::coro_free: {
704 " been used earlier in this function");
710 case llvm::Intrinsic::coro_suspend:
718 llvm::CallInst *Call =
Builder.CreateCall(F, Args);
724 if (IID == llvm::Intrinsic::coro_id) {
727 else if (IID == llvm::Intrinsic::coro_begin) {
731 else if (IID == llvm::Intrinsic::coro_free) {