14#include "mlir/Support/LLVM.h"
57struct GetParamRef :
public StmtVisitor<GetParamRef> {
62 assert(
expr ==
nullptr &&
"multilple declref in param move");
65 void VisitStmt(
Stmt *
s) {
66 for (
Stmt *
c :
s->children()) {
76struct ParamReferenceReplacerRAII {
81 : localDeclMap(localDeclMap) {}
83 void addCopy(
const DeclStmt *pm) {
87 const VarDecl *vd =
static_cast<const VarDecl *
>(pm->
getSingleDecl());
88 const Expr *initExpr = vd->
getInit();
90 visitor.Visit(
const_cast<Expr *
>(initExpr));
92 DeclRefExpr *dreOrig = visitor.expr;
95 auto it = localDeclMap.find(pd);
96 assert(it != localDeclMap.end() &&
"parameter is not found");
97 savedLocals.insert({pd, it->second});
99 auto copyIt = localDeclMap.find(vd);
100 assert(copyIt != localDeclMap.end() &&
"parameter copy is not found");
101 it->second = copyIt->getSecond();
104 ~ParamReferenceReplacerRAII() {
105 for (
auto &&savedLocal : savedLocals) {
106 localDeclMap.insert({savedLocal.first, savedLocal.second});
114struct CallCoroDelete final :
public EHScopeStack::Cleanup {
124 void emit(CIRGenFunction &cgf, Flags)
override {
129 if (cgf.
emitStmt(deallocate,
true).failed()) {
130 cgf.
cgm.
error(deallocate->getBeginLoc(),
131 "failed to emit coroutine deallocation expression");
136 cir::CallOp coroFree = cgf.
curCoro.
data->lastCoroFree;
139 cgf.
cgm.
error(deallocate->getBeginLoc(),
140 "Deallocation expression does not refer to coro.free");
144 builder.setInsertionPointAfter(coroFree);
147 llvm::SmallVector<mlir::Operation *> opsToMove;
148 mlir::Block *block = builder.getInsertionBlock();
149 mlir::Block::iterator it(isPtrNotNull.getDefiningOp());
151 for (++it; it != block->end(); ++it)
152 opsToMove.push_back(&*it);
155 cir::IfOp::create(builder, cgf.
getLoc(deallocate->getSourceRange()),
157 [&](mlir::OpBuilder &builder, mlir::Location loc) {
158 cir::YieldOp::create(builder, loc);
161 mlir::Operation *yieldOp = ifOp.getThenRegion().back().getTerminator();
162 for (
auto *op : opsToMove)
163 op->moveBefore(yieldOp);
165 explicit CallCoroDelete(Stmt *deallocStmt) : deallocate(deallocStmt) {}
179 cir::CallOp coroId) {
180 assert(!
curCoro.
data &&
"EmitCoroutineBodyStatement called twice?");
186static mlir::LogicalResult
190 if (cgf.
emitStmt(body,
true).failed())
191 return mlir::failure();
200 const bool canFallthrough = !currLexScope->
hasCoreturn();
202 if (
Stmt *onFallthrough =
s.getFallthroughHandler())
203 if (cgf.
emitStmt(onFallthrough,
true).failed())
204 return mlir::failure();
206 return mlir::success();
210 mlir::Value nullPtr) {
211 cir::IntType int32Ty = builder.getUInt32Ty();
216 mlir::Operation *builtin =
cgm.getGlobalValue(
cgm.builtinCoroId);
220 fnOp =
cgm.createCIRBuiltinFunction(
221 loc,
cgm.builtinCoroId,
222 cir::FuncType::get({int32Ty, voidPtrTy, voidPtrTy, voidPtrTy}, int32Ty),
224 assert(fnOp &&
"should always succeed");
229 return builder.createCallOp(loc, fnOp,
230 mlir::ValueRange{builder.getUInt32(newAlign, loc),
231 nullPtr, nullPtr, nullPtr});
235 cir::BoolType boolTy = builder.getBoolTy();
237 mlir::Operation *builtin =
cgm.getGlobalValue(
cgm.builtinCoroAlloc);
241 fnOp =
cgm.createCIRBuiltinFunction(loc,
cgm.builtinCoroAlloc,
242 cir::FuncType::get({uInt32Ty}, boolTy),
244 assert(fnOp &&
"should always succeed");
249 return builder.createCallOp(
250 loc, fnOp, mlir::ValueRange{
curCoro.data->coroId.getResult()});
255 mlir::Value coroframeAddr) {
256 mlir::Operation *builtin =
cgm.getGlobalValue(
cgm.builtinCoroBegin);
260 fnOp =
cgm.createCIRBuiltinFunction(
261 loc,
cgm.builtinCoroBegin,
262 cir::FuncType::get({uInt32Ty, voidPtrTy},
voidPtrTy),
264 assert(fnOp &&
"should always succeed");
269 return builder.createCallOp(
271 mlir::ValueRange{
curCoro.data->coroId.getResult(), coroframeAddr});
275 mlir::Value nullPtr) {
276 cir::BoolType boolTy = builder.getBoolTy();
277 mlir::Operation *builtin =
cgm.getGlobalValue(
cgm.builtinCoroEnd);
281 fnOp =
cgm.createCIRBuiltinFunction(
282 loc,
cgm.builtinCoroEnd,
283 cir::FuncType::get({voidPtrTy, boolTy}, boolTy),
285 assert(fnOp &&
"should always succeed");
290 return builder.createCallOp(
291 loc, fnOp, mlir::ValueRange{nullPtr, builder.getBool(
false, loc)});
295 mlir::Operation *builtin =
cgm.getGlobalValue(
cgm.builtinCoroFree);
299 fnOp =
cgm.createCIRBuiltinFunction(
300 loc,
cgm.builtinCoroFree,
301 cir::FuncType::get({uInt32Ty, voidPtrTy},
voidPtrTy),
303 assert(fnOp &&
"should always succeed");
307 cir::CallOp coroFree =
308 builder.createCallOp(loc, fnOp,
309 mlir::ValueRange{
curCoro.data->coroId.getResult(),
312 curCoro.data->lastCoroFree = coroFree;
318 mlir::Location openCurlyLoc =
getLoc(
s.getBeginLoc());
319 cir::ConstantOp nullPtrCst = builder.getNullPtr(
voidPtrTy, openCurlyLoc);
321 auto fn = mlir::cast<cir::FuncOp>(
curFn);
322 fn.setCoroutine(
true);
335 openCurlyLoc,
"__coro_frame_addr",
338 mlir::Value storeAddr = coroFrame.
getPointer();
339 builder.CIRBaseBuilderTy::createStore(openCurlyLoc, nullPtrCst, storeAddr);
341 builder, openCurlyLoc, coroAlloc.getResult(),
343 [&](mlir::OpBuilder &
b, mlir::Location loc) {
344 builder.CIRBaseBuilderTy::createStore(
345 loc, emitScalarExpr(s.getAllocate()), storeAddr);
346 cir::YieldOp::create(builder, loc);
351 cir::LoadOp::create(builder, openCurlyLoc, allocaTy, storeAddr))
355 if (
s.getReturnStmtOnAllocFailure())
356 cgm.errorNYI(
"handle coroutine return alloc failure");
366 assert((paramMoves.size() == 0 || (paramMoves.size() ==
fnArgs.size())) &&
367 "ParamMoves and FnArgs should be the same size for coroutine "
376 for (
auto *pm : paramMoves) {
378 return mlir::failure();
382 if (
emitStmt(
s.getPromiseDeclStmt(),
true).failed())
383 return mlir::failure();
386 assert(
returnValue.isValid() == (
bool)
s.getReturnStmt());
398 s.getReturnValue()->getType().getQualifiers(),
403 curCoro.data->currentAwaitKind = cir::AwaitKind::Init;
404 if (
emitStmt(
s.getInitSuspendStmt(),
true).failed())
405 return mlir::failure();
407 curCoro.data->currentAwaitKind = cir::AwaitKind::User;
409 mlir::OpBuilder::InsertPoint userBody;
411 cir::CoroBodyOp::create(builder, openCurlyLoc,
412 [&](mlir::OpBuilder &
b, mlir::Location loc) {
413 userBody =
b.saveInsertionPoint();
416 mlir::OpBuilder::InsertionGuard guard(builder);
417 builder.restoreInsertionPoint(userBody);
419 if (
s.getExceptionHandler()) {
421 cgm.errorNYI(
"exceptions in coroutines are not yet supported in CIR");
424 return mlir::failure();
428 mlir::Block &coroBodyBlock = coroBodyOp.getBody().back();
429 if (!coroBodyBlock.mightHaveTerminator()) {
430 mlir::OpBuilder::InsertionGuard guard(builder);
431 builder.setInsertionPointToEnd(&coroBodyBlock);
432 cir::YieldOp::create(builder, openCurlyLoc);
443 const bool canFallthrough =
curLexScope->hasCoreturn();
444 const bool hasCoreturns =
curCoro.data->coreturnCount > 0;
445 if (canFallthrough || hasCoreturns) {
446 curCoro.data->currentAwaitKind = cir::AwaitKind::Final;
448 mlir::OpBuilder::InsertionGuard guard(builder);
449 if (
emitStmt(
s.getFinalSuspendStmt(),
true)
451 return mlir::failure();
457 openCurlyLoc, builder.getNullPtr(builder.getVoidPtrTy(), openCurlyLoc));
458 if (
auto *ret = cast_or_null<ReturnStmt>(
s.getReturnStmt())) {
461 Expr *previousRetValue = ret->getRetValue();
462 ret->setRetValue(
nullptr);
464 return mlir::failure();
467 ret->setRetValue(previousRetValue);
469 return mlir::success();
473 if (
const auto *ce = dyn_cast<CXXMemberCallExpr>(e))
474 if (
const auto *proto =
499struct LValueOrRValue {
509 mlir::Block *scopeParentBlock,
510 mlir::Value &tmpResumeRValAddr,
bool forLValue) {
511 [[maybe_unused]] mlir::LogicalResult awaitBuild = mlir::success();
512 LValueOrRValue awaitRes;
517 [[maybe_unused]] cir::AwaitOp awaitOp = cir::AwaitOp::create(
520 [&](mlir::OpBuilder &
b, mlir::Location loc) {
521 Expr *condExpr = s.getReadyExpr()->IgnoreParens();
522 builder.createCondition(cgf.evaluateExprAsBool(condExpr));
525 [&](mlir::OpBuilder &
b, mlir::Location loc) {
531 mlir::Value suspendRet = cgf.emitScalarExpr(s.getSuspendExpr());
535 cgf.cgm.errorNYI(
"Veto await_suspend");
539 cir::YieldOp::create(builder, loc);
542 [&](mlir::OpBuilder &
b, mlir::Location loc) {
546 CXXTryStmt *tryStmt =
nullptr;
547 if (coro.exceptionHandler &&
kind == cir::AwaitKind::Init &&
557 cgf.
emitAnyExpr(
s.getResumeExpr(), aggSlot, ignoreResult);
558 if (!awaitRes.rv.isIgnored()) {
562 RValue rv = awaitRes.rv;
568 cgf.
cgm.
errorNYI(
"emitSuspendExpression: Aggregate value");
574 builder.getBestAllocaInsertPoint(scopeParentBlock));
576 builder.CIRBaseBuilderTy::createStore(loc, value,
585 cir::YieldOp::create(builder, loc);
588 assert(awaitBuild.succeeded() &&
"Should know how to codegen");
606 [[maybe_unused]] mlir::Value tmpResumeRValAddr;
611 ignoreResult, currEntryBlock, tmpResumeRValAddr,
652 const Expr *rv =
s.getOperand();
660 if (
emitStmt(
s.getPromiseCall(),
true).failed())
661 return mlir::failure();
665 mlir::Location loc =
getLoc(
s.getSourceRange());
666 cir::CoReturnOp::create(builder, loc);
668 return mlir::success();
static void emit(Program &P, llvm::SmallVectorImpl< std::byte > &Code, const T &Val, bool &Success)
Helper to write bytecode and bail out if 32-bit offsets become invalid.
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)
static RValue emitSuspendExpr(CIRGenFunction &cgf, const CoroutineSuspendExpr &e, cir::AwaitKind kind, AggValueSlot aggSlot, bool ignoreResult)
static bool memberCallExpressionCanThrow(const Expr *e)
static mlir::LogicalResult emitBodyAndFallthrough(CIRGenFunction &cgf, const CoroutineBodyStmt &s, Stmt *body, const CIRGenFunction::LexicalScope *currLexScope)
static void createCoroData(CIRGenFunction &cgf, CIRGenFunction::CGCoroInfo &curCoro, cir::CallOp coroId)
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
__device__ __2f16 float __ockl_bool s
__device__ __2f16 float c
mlir::Value createPtrIsNotNull(mlir::Value ptr)
mlir::Value getPointer() const
An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.
Enters a new scope for capturing cleanups, all of which will be executed once the scope is exited.
cir::CallOp emitCoroEndBuiltinCall(mlir::Location loc, mlir::Value nullPtr)
cir::CallOp emitCoroIDBuiltinCall(mlir::Location loc, mlir::Value nullPtr)
mlir::LogicalResult emitCoreturnStmt(const CoreturnStmt &s)
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
LValue emitLValue(const clang::Expr *e)
Emit code to compute a designator that specifies the location of the expression.
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.
cir::CallOp emitCoroFreeBuiltin(const CallExpr *e)
RValue emitCoyieldExpr(const CoyieldExpr &e, AggValueSlot aggSlot=AggValueSlot::ignored(), bool ignoreResult=false)
mlir::Operation * curFn
The current function or global initializer that is generated code for.
EHScopeStack ehStack
Tracks function scope overall cleanup handling.
llvm::SmallVector< const ParmVarDecl * > fnArgs
Save Parameter Decl for coroutine.
mlir::Type convertTypeForMem(QualType t)
cir::CallOp emitCoroAllocBuiltinCall(mlir::Location loc)
RValue emitCoroutineFrame()
mlir::Value emitAlloca(llvm::StringRef name, mlir::Type ty, mlir::Location loc, clang::CharUnits alignment, bool insertIntoFnEntryBlock, mlir::Value arraySize=nullptr)
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)
RValue emitAnyExpr(const clang::Expr *e, AggValueSlot aggSlot=AggValueSlot::ignored(), bool ignoreResult=false)
Emit code to compute the specified expression which can have any type.
LexicalScope * curLexScope
clang::ASTContext & getContext() const
mlir::LogicalResult emitCoroutineBody(const CoroutineBodyStmt &s)
cir::CallOp emitCoroBeginBuiltinCall(mlir::Location loc, mlir::Value coroframeAddr)
mlir::LogicalResult emitStmt(const clang::Stmt *s, bool useCurrentScope, llvm::ArrayRef< const Attr * > attrs={})
void emitIgnoredExpr(const clang::Expr *e)
Emit code to compute the specified expression, ignoring the result.
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
void error(SourceLocation loc, llvm::StringRef error)
Emit a general error that something can't be done.
This trivial value class is used to represent the result of an expression that is evaluated.
static RValue get(mlir::Value v)
static RValue getComplex(mlir::Value v)
mlir::Value getValue() const
Return the value of this scalar value.
mlir::Value getComplexValue() const
Return the value of this complex value.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
SourceLocation getBeginLoc() const
static CharUnits One()
One - Construct a CharUnits quantity of one.
Represents a 'co_await' expression.
Represents a 'co_return' statement in the C++ Coroutines TS.
Represents the body of a coroutine.
Represents an expression that might suspend coroutine execution; either a co_await or co_yield expres...
Represents a 'co_yield' expression.
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 isa(CodeGen::Address addr)
bool isNoexceptExceptionSpec(ExceptionSpecificationType ESpecType)
U cast(CodeGen::Address addr)
static bool ehCleanupScope()
static bool coroutineExceptions()
static bool coroOutsideFrameMD()
static bool generateDebugInfo()
cir::AwaitKind currentAwaitKind
std::unique_ptr< CGCoroData > data
Represents a scope, including function bodies, compound statements, and the substatements of if/while...
mlir::Block * getEntryBlock()
cir::PointerType voidPtrTy
void* in address space 0