blob: 2f5e8ab2f0f75380f31df11d6bd51abe03e27b23 [file] [log] [blame]
Gor Nishanov97e3b6d2016-10-03 22:44:48 +00001//===----- 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
16using namespace clang;
17using namespace CodeGen;
18
19namespace clang {
20namespace CodeGen {
21
22struct CGCoroData {
23 // Stores the llvm.coro.id emitted in the function so that we can supply it
24 // as the first argument to coro.begin, coro.alloc and coro.free intrinsics.
25 // Note: llvm.coro.id returns a token that cannot be directly expressed in a
26 // builtin.
27 llvm::CallInst *CoroId = nullptr;
28 // If coro.id came from the builtin, remember the expression to give better
29 // diagnostic. If CoroIdExpr is nullptr, the coro.id was created by
30 // EmitCoroutineBody.
31 CallExpr const *CoroIdExpr = nullptr;
32};
33}
34}
35
36clang::CodeGen::CodeGenFunction::CGCoroInfo::CGCoroInfo() {}
37CodeGenFunction::CGCoroInfo::~CGCoroInfo() {}
38
39static bool createCoroData(CodeGenFunction &CGF,
40 CodeGenFunction::CGCoroInfo &CurCoro,
41 llvm::CallInst *CoroId, CallExpr const *CoroIdExpr) {
42 if (CurCoro.Data) {
43 if (CurCoro.Data->CoroIdExpr)
44 CGF.CGM.Error(CoroIdExpr->getLocStart(),
45 "only one __builtin_coro_id can be used in a function");
46 else if (CoroIdExpr)
47 CGF.CGM.Error(CoroIdExpr->getLocStart(),
48 "__builtin_coro_id shall not be used in a C++ coroutine");
49 else
50 llvm_unreachable("EmitCoroutineBodyStatement called twice?");
51
52 return false;
53 }
54
55 CurCoro.Data = std::unique_ptr<CGCoroData>(new CGCoroData);
56 CurCoro.Data->CoroId = CoroId;
57 CurCoro.Data->CoroIdExpr = CoroIdExpr;
58 return true;
59}
60
61// Emit coroutine intrinsic and patch up arguments of the token type.
62RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
63 unsigned int IID) {
64 SmallVector<llvm::Value *, 8> Args;
65 switch (IID) {
66 default:
67 break;
68 // The following three intrinsics take a token parameter referring to a token
69 // returned by earlier call to @llvm.coro.id. Since we cannot represent it in
70 // builtins, we patch it up here.
71 case llvm::Intrinsic::coro_alloc:
72 case llvm::Intrinsic::coro_begin:
73 case llvm::Intrinsic::coro_free: {
74 if (CurCoro.Data && CurCoro.Data->CoroId) {
75 Args.push_back(CurCoro.Data->CoroId);
76 break;
77 }
78 CGM.Error(E->getLocStart(), "this builtin expect that __builtin_coro_id has"
79 " been used earlier in this function");
80 // Fallthrough to the next case to add TokenNone as the first argument.
81 }
82 // @llvm.coro.suspend takes a token parameter. Add token 'none' as the first
83 // argument.
84 case llvm::Intrinsic::coro_suspend:
85 Args.push_back(llvm::ConstantTokenNone::get(getLLVMContext()));
86 break;
87 }
88 for (auto &Arg : E->arguments())
89 Args.push_back(EmitScalarExpr(Arg));
90
91 llvm::Value *F = CGM.getIntrinsic(IID);
92 llvm::CallInst *Call = Builder.CreateCall(F, Args);
93
94 // If we see @llvm.coro.id remember it in the CoroData. We will update
95 // coro.alloc, coro.begin and coro.free intrinsics to refer to it.
96 if (IID == llvm::Intrinsic::coro_id) {
97 createCoroData(*this, CurCoro, Call, E);
98 }
99 return RValue::get(Call);
100}