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