clang: lib/CIR/CodeGen/CIRGenCoroutine.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
14#include "mlir/Support/LLVM.h"
20
21using namespace clang;
23
25
26
27
29
30
32
33
35
36
38};
39
40
43
44namespace {
45
46
47
48
49struct GetParamRef : public StmtVisitor {
50public:
52 GetParamRef() {}
54 assert(expr == nullptr && "multilple declref in param move");
56 }
58 for (Stmt *c : s->children()) {
59 if (c)
60 Visit(c);
61 }
62 }
63};
64
65
66
67
68struct ParamReferenceReplacerRAII {
71
73 : localDeclMap(localDeclMap) {}
74
75 void addCopy(const DeclStmt *pm) {
76
77
79 const VarDecl *vd = static_cast<const VarDecl *>(pm->getSingleDecl());
80 const Expr *initExpr = vd->getInit();
81 GetParamRef visitor;
82 visitor.Visit(const_cast<Expr *>(initExpr));
83 assert(visitor.expr);
84 DeclRefExpr *dreOrig = visitor.expr;
85 auto *pd = dreOrig->getDecl();
86
87 auto it = localDeclMap.find(pd);
88 assert(it != localDeclMap.end() && "parameter is not found");
89 savedLocals.insert({pd, it->second});
90
91 auto copyIt = localDeclMap.find(vd);
92 assert(copyIt != localDeclMap.end() && "parameter copy is not found");
93 it->second = copyIt->getSecond();
94 }
95
96 ~ParamReferenceReplacerRAII() {
97 for (auto &&savedLocal : savedLocals) {
98 localDeclMap.insert({savedLocal.first, savedLocal.second});
99 }
100 }
101};
102}
103
107 }
108 cgm.errorNYI("NYI");
110}
111
114 cir::CallOp coroId) {
115 assert(.data && "EmitCoroutineBodyStatement called twice?");
116
117 curCoro.data = std::make_unique();
119}
120
122 mlir::Value nullPtr) {
123 cir::IntType int32Ty = builder.getUInt32Ty();
124
125 const TargetInfo &ti = cgm.getASTContext().getTargetInfo();
127
128 mlir::Operation *builtin = cgm.getGlobalValue(cgm.builtinCoroId);
129
130 cir::FuncOp fnOp;
131 if (!builtin) {
132 fnOp = cgm.createCIRBuiltinFunction(
133 loc, cgm.builtinCoroId,
134 cir::FuncType::get({int32Ty, voidPtrTy, voidPtrTy, voidPtrTy}, int32Ty),
135 nullptr);
136 assert(fnOp && "should always succeed");
137 } else {
139 }
140
141 return builder.createCallOp(loc, fnOp,
142 mlir::ValueRange{builder.getUInt32(newAlign, loc),
143 nullPtr, nullPtr, nullPtr});
144}
145
147 cir::BoolType boolTy = builder.getBoolTy();
148
149 mlir::Operation *builtin = cgm.getGlobalValue(cgm.builtinCoroAlloc);
150
151 cir::FuncOp fnOp;
152 if (!builtin) {
153 fnOp = cgm.createCIRBuiltinFunction(loc, cgm.builtinCoroAlloc,
154 cir::FuncType::get({uInt32Ty}, boolTy),
155 nullptr);
156 assert(fnOp && "should always succeed");
157 } else {
159 }
160
161 return builder.createCallOp(
162 loc, fnOp, mlir::ValueRange{curCoro.data->coroId.getResult()});
163}
164
165cir::CallOp
167 mlir::Value coroframeAddr) {
168 mlir::Operation *builtin = cgm.getGlobalValue(cgm.builtinCoroBegin);
169
170 cir::FuncOp fnOp;
171 if (!builtin) {
172 fnOp = cgm.createCIRBuiltinFunction(
173 loc, cgm.builtinCoroBegin,
174 cir::FuncType::get({uInt32Ty, voidPtrTy}, voidPtrTy),
175 nullptr);
176 assert(fnOp && "should always succeed");
177 } else {
179 }
180
181 return builder.createCallOp(
182 loc, fnOp,
183 mlir::ValueRange{curCoro.data->coroId.getResult(), coroframeAddr});
184}
185
186mlir::LogicalResult
188 mlir::Location openCurlyLoc = getLoc(s.getBeginLoc());
189 cir::ConstantOp nullPtrCst = builder.getNullPtr(voidPtrTy, openCurlyLoc);
190
191 auto fn = mlir::castcir::FuncOp(curFn);
192 fn.setCoroutine(true);
195
196
197
199
200
201 CanQualType astVoidPtrTy = cgm.getASTContext().VoidPtrTy;
205 openCurlyLoc, "__coro_frame_addr",
206 nullptr);
207
208 mlir::Value storeAddr = coroFrame.getPointer();
209 builder.CIRBaseBuilderTy::createStore(openCurlyLoc, nullPtrCst, storeAddr);
210 cir::IfOp::create(
211 builder, openCurlyLoc, coroAlloc.getResult(),
212 false,
213 [&](mlir::OpBuilder &b, mlir::Location loc) {
214 builder.CIRBaseBuilderTy::createStore(
215 loc, emitScalarExpr(s.getAllocate()), storeAddr);
216 cir::YieldOp::create(builder, loc);
217 });
218 curCoro.data->coroBegin =
220 openCurlyLoc,
221 cir::LoadOp::create(builder, openCurlyLoc, allocaTy, storeAddr))
222 .getResult();
223
224
225 if (s.getReturnStmtOnAllocFailure())
226 cgm.errorNYI("handle coroutine return alloc failure");
227
228 {
230 ParamReferenceReplacerRAII paramReplacer(localDeclMap);
231
232
234 assert((paramMoves.size() == 0 || (paramMoves.size() == fnArgs.size())) &&
235 "ParamMoves and FnArgs should be the same size for coroutine "
236 "function");
237
239
240
241
242
244 for (auto *pm : paramMoves) {
245 if (emitStmt(pm, true).failed())
246 return mlir::failure();
248 }
249
250 if (emitStmt(s.getPromiseDeclStmt(), true).failed())
251 return mlir::failure();
252
253
254 assert(returnValue.isValid() == (bool)s.getReturnStmt());
255
256
257
258
259
260
261
262
263
266 s.getReturnValue()->getType().getQualifiers(),
267 true);
268
270
271 curCoro.data->currentAwaitKind = cir::AwaitKind::Init;
272 if (emitStmt(s.getInitSuspendStmt(), true).failed())
273 return mlir::failure();
275 }
276 return mlir::success();
277}
278
280 if (const auto *ce = dyn_cast(e))
281 if (const auto *proto =
285 return false;
286 return true;
287}
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305namespace {
306struct LValueOrRValue {
307 LValue lv;
308 RValue rv;
309};
310}
311
312static LValueOrRValue
316 mlir::Block *scopeParentBlock,
317 mlir::Value &tmpResumeRValAddr, bool forLValue) {
318 [[maybe_unused]] mlir::LogicalResult awaitBuild = mlir::success();
319 LValueOrRValue awaitRes;
320
324 [[maybe_unused]] cir::AwaitOp awaitOp = cir::AwaitOp::create(
325 builder, cgf.getLoc(s.getSourceRange()), kind,
326
327 [&](mlir::OpBuilder &b, mlir::Location loc) {
328 Expr *condExpr = s.getReadyExpr()->IgnoreParens();
329 builder.createCondition(cgf.evaluateExprAsBool(condExpr));
330 },
331
332 [&](mlir::OpBuilder &b, mlir::Location loc) {
333
334
335
336
337
338 mlir::Value suspendRet = cgf.emitScalarExpr(s.getSuspendExpr());
339
340
341 if (suspendRet) {
342 cgf.cgm.errorNYI("Veto await_suspend");
343 }
344
345
346 cir::YieldOp::create(builder, loc);
347 },
348
349 [&](mlir::OpBuilder &b, mlir::Location loc) {
350
351
352
353 CXXTryStmt *tryStmt = nullptr;
354 if (coro.exceptionHandler && kind == cir::AwaitKind::Init &&
356 cgf.cgm.errorNYI("Coro resume Exception");
357
358
359
360 if (forLValue) {
362 } else {
363 awaitRes.rv =
364 cgf.emitAnyExpr(s.getResumeExpr(), aggSlot, ignoreResult);
365 if (!awaitRes.rv.isIgnored())
366
367
369 }
370
371 if (tryStmt)
372 cgf.cgm.errorNYI("Coro tryStmt");
373
374
375 cir::YieldOp::create(builder, loc);
376 });
377
378 assert(awaitBuild.succeeded() && "Should know how to codegen");
379 return awaitRes;
380}
381
385 bool ignoreResult) {
388
389
390
391
392
393
394
396 [[maybe_unused]] mlir::Value tmpResumeRValAddr;
397
398
399
401 ignoreResult, currEntryBlock, tmpResumeRValAddr,
402 false)
403 .rv;
404
405 if (ignoreResult || rval.isIgnored())
406 return rval;
407
411 tmpResumeRValAddr));
413
414
415 cgf.cgm.errorNYI("emitSuspendExpr Aggregate");
416 } else {
417 cgf.cgm.errorNYI("emitSuspendExpr Complex");
418 }
419 return rval;
420}
421
424 bool ignoreResult) {
426 ignoreResult);
427}
static LValueOrRValue emitSuspendExpression(CIRGenFunction &cgf, CGCoroData &coro, CoroutineSuspendExpr const &s, cir::AwaitKind kind, AggValueSlot aggSlot, bool ignoreResult, mlir::Block *scopeParentBlock, mlir::Value &tmpResumeRValAddr, bool forLValue)
Definition CIRGenCoroutine.cpp:313
static RValue emitSuspendExpr(CIRGenFunction &cgf, const CoroutineSuspendExpr &e, cir::AwaitKind kind, AggValueSlot aggSlot, bool ignoreResult)
Definition CIRGenCoroutine.cpp:382
static bool memberCallExpressionCanThrow(const Expr *e)
Definition CIRGenCoroutine.cpp:279
static void createCoroData(CIRGenFunction &cgf, CIRGenFunction::CGCoroInfo &curCoro, cir::CallOp coroId)
Definition CIRGenCoroutine.cpp:112
__device__ __2f16 float __ockl_bool s
__device__ __2f16 float c
mlir::Value getPointer() const
An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.
cir::CallOp emitCoroIDBuiltinCall(mlir::Location loc, mlir::Value nullPtr)
Definition CIRGenCoroutine.cpp:121
cir::AllocaOp createTempAlloca(mlir::Type ty, mlir::Location loc, const Twine &name="tmp", mlir::Value arraySize=nullptr, bool insertIntoFnEntryBlock=false)
This creates an alloca and inserts it into the entry block if ArraySize is nullptr,...
llvm::DenseMap< const clang::Decl *, Address > DeclMapTy
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
void emitAnyExprToMem(const Expr *e, Address location, Qualifiers quals, bool isInitializer)
Emits the code necessary to evaluate an arbitrary expression into the given memory location.
mlir::Operation * curFn
The current function or global initializer that is generated code for.
llvm::SmallVector< const ParmVarDecl * > fnArgs
Save Parameter Decl for coroutine.
mlir::Type convertTypeForMem(QualType t)
cir::CallOp emitCoroAllocBuiltinCall(mlir::Location loc)
Definition CIRGenCoroutine.cpp:146
RValue emitCoroutineFrame()
Definition CIRGenCoroutine.cpp:104
Address returnValue
The temporary alloca to hold the return value.
CIRGenBuilderTy & getBuilder()
DeclMapTy localDeclMap
This keeps track of the CIR allocas or globals for local C declarations.
RValue emitCoawaitExpr(const CoawaitExpr &e, AggValueSlot aggSlot=AggValueSlot::ignored(), bool ignoreResult=false)
Definition CIRGenCoroutine.cpp:422
LexicalScope * curLexScope
clang::ASTContext & getContext() const
mlir::LogicalResult emitCoroutineBody(const CoroutineBodyStmt &s)
Definition CIRGenCoroutine.cpp:187
cir::CallOp emitCoroBeginBuiltinCall(mlir::Location loc, mlir::Value coroframeAddr)
Definition CIRGenCoroutine.cpp:166
mlir::LogicalResult emitStmt(const clang::Stmt *s, bool useCurrentScope, llvm::ArrayRef< const Attr * > attrs={})
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
This trivial value class is used to represent the result of an expression that is evaluated.
static RValue get(mlir::Value v)
mlir::Value getValue() const
Return the value of this scalar value.
Represents a 'co_await' expression.
Represents the body of a coroutine.
Represents an expression that might suspend coroutine execution; either a co_await or co_yield expres...
A reference to a declared variable, function, enum, etc.
bool isSingleDecl() const
isSingleDecl - This method returns true if this DeclStmt refers to a single Decl.
const Decl * getSingleDecl() const
This represents one expression.
Represents a prototype with parameter type info, e.g.
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Exposes information about the current target.
unsigned getNewAlign() const
Return the largest alignment for which a suitably-sized allocation with 'operator new(size_t)' is gua...
unsigned getCharWidth() const
const Expr * getInit() const
Defines the clang::TargetInfo interface.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isNoexceptExceptionSpec(ExceptionSpecificationType ESpecType)
U cast(CodeGen::Address addr)
static bool ehCleanupScope()
static bool coroCoReturn()
static bool emitBodyAndFallthrough()
static bool coroOutsideFrameMD()
static bool coroCoYield()
static bool generateDebugInfo()
Definition CIRGenCoroutine.cpp:24
cir::AwaitKind currentAwaitKind
Definition CIRGenCoroutine.cpp:28
cir::CallOp coroId
Definition CIRGenCoroutine.cpp:31
mlir::Value coroBegin
Definition CIRGenCoroutine.cpp:34
Stmt * exceptionHandler
Definition CIRGenCoroutine.cpp:37
CGCoroInfo()
Definition CIRGenCoroutine.cpp:41
std::unique_ptr< CGCoroData > data
~CGCoroInfo()
Definition CIRGenCoroutine.cpp:42
mlir::Block * getEntryBlock()
cir::PointerType voidPtrTy
void* in address space 0