1 //===----- CGCoroutine.cpp - Emit LLVM Code for C++ coroutines ------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This contains code dealing with C++ code generation of coroutines. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "CodeGenFunction.h" 15 #include "clang/AST/StmtCXX.h" 16 17 using namespace clang; 18 using namespace CodeGen; 19 20 namespace clang { 21 namespace CodeGen { 22 23 struct CGCoroData { 24 25 // Stores the jump destination just before the final suspend. Coreturn 26 // statements jumps to this point after calling return_xxx promise member. 27 CodeGenFunction::JumpDest FinalJD; 28 29 unsigned CoreturnCount = 0; 30 31 // Stores the llvm.coro.id emitted in the function so that we can supply it 32 // as the first argument to coro.begin, coro.alloc and coro.free intrinsics. 33 // Note: llvm.coro.id returns a token that cannot be directly expressed in a 34 // builtin. 35 llvm::CallInst *CoroId = nullptr; 36 // If coro.id came from the builtin, remember the expression to give better 37 // diagnostic. If CoroIdExpr is nullptr, the coro.id was created by 38 // EmitCoroutineBody. 39 CallExpr const *CoroIdExpr = nullptr; 40 }; 41 } 42 } 43 44 clang::CodeGen::CodeGenFunction::CGCoroInfo::CGCoroInfo() {} 45 CodeGenFunction::CGCoroInfo::~CGCoroInfo() {} 46 47 static void createCoroData(CodeGenFunction &CGF, 48 CodeGenFunction::CGCoroInfo &CurCoro, 49 llvm::CallInst *CoroId, 50 CallExpr const *CoroIdExpr = nullptr) { 51 if (CurCoro.Data) { 52 if (CurCoro.Data->CoroIdExpr) 53 CGF.CGM.Error(CoroIdExpr->getLocStart(), 54 "only one __builtin_coro_id can be used in a function"); 55 else if (CoroIdExpr) 56 CGF.CGM.Error(CoroIdExpr->getLocStart(), 57 "__builtin_coro_id shall not be used in a C++ coroutine"); 58 else 59 llvm_unreachable("EmitCoroutineBodyStatement called twice?"); 60 61 return; 62 } 63 64 CurCoro.Data = std::unique_ptr<CGCoroData>(new CGCoroData); 65 CurCoro.Data->CoroId = CoroId; 66 CurCoro.Data->CoroIdExpr = CoroIdExpr; 67 } 68 69 void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) { 70 ++CurCoro.Data->CoreturnCount; 71 EmitStmt(S.getPromiseCall()); 72 EmitBranchThroughCleanup(CurCoro.Data->FinalJD); 73 } 74 75 void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) { 76 auto *NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy()); 77 auto &TI = CGM.getContext().getTargetInfo(); 78 unsigned NewAlign = TI.getNewAlign() / TI.getCharWidth(); 79 80 auto *FinalBB = createBasicBlock("coro.final"); 81 82 auto *CoroId = Builder.CreateCall( 83 CGM.getIntrinsic(llvm::Intrinsic::coro_id), 84 {Builder.getInt32(NewAlign), NullPtr, NullPtr, NullPtr}); 85 createCoroData(*this, CurCoro, CoroId); 86 87 EmitScalarExpr(S.getAllocate()); 88 89 // FIXME: Setup cleanup scopes. 90 91 EmitStmt(S.getPromiseDeclStmt()); 92 93 CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB); 94 95 // FIXME: Emit initial suspend and more before the body. 96 97 EmitStmt(S.getBody()); 98 99 // See if we need to generate final suspend. 100 const bool CanFallthrough = Builder.GetInsertBlock(); 101 const bool HasCoreturns = CurCoro.Data->CoreturnCount > 0; 102 if (CanFallthrough || HasCoreturns) { 103 EmitBlock(FinalBB); 104 // FIXME: Emit final suspend. 105 } 106 EmitStmt(S.getDeallocate()); 107 108 // FIXME: Emit return for the coroutine return object. 109 } 110 111 // Emit coroutine intrinsic and patch up arguments of the token type. 112 RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E, 113 unsigned int IID) { 114 SmallVector<llvm::Value *, 8> Args; 115 switch (IID) { 116 default: 117 break; 118 // The following three intrinsics take a token parameter referring to a token 119 // returned by earlier call to @llvm.coro.id. Since we cannot represent it in 120 // builtins, we patch it up here. 121 case llvm::Intrinsic::coro_alloc: 122 case llvm::Intrinsic::coro_begin: 123 case llvm::Intrinsic::coro_free: { 124 if (CurCoro.Data && CurCoro.Data->CoroId) { 125 Args.push_back(CurCoro.Data->CoroId); 126 break; 127 } 128 CGM.Error(E->getLocStart(), "this builtin expect that __builtin_coro_id has" 129 " been used earlier in this function"); 130 // Fallthrough to the next case to add TokenNone as the first argument. 131 } 132 // @llvm.coro.suspend takes a token parameter. Add token 'none' as the first 133 // argument. 134 case llvm::Intrinsic::coro_suspend: 135 Args.push_back(llvm::ConstantTokenNone::get(getLLVMContext())); 136 break; 137 } 138 for (auto &Arg : E->arguments()) 139 Args.push_back(EmitScalarExpr(Arg)); 140 141 llvm::Value *F = CGM.getIntrinsic(IID); 142 llvm::CallInst *Call = Builder.CreateCall(F, Args); 143 144 // If we see @llvm.coro.id remember it in the CoroData. We will update 145 // coro.alloc, coro.begin and coro.free intrinsics to refer to it. 146 if (IID == llvm::Intrinsic::coro_id) { 147 createCoroData(*this, CurCoro, Call, E); 148 } 149 return RValue::get(Call); 150 } 151