14#include "mlir/Support/LLVM.h"
69struct GetParamRef :
public StmtVisitor<GetParamRef> {
74 assert(
expr ==
nullptr &&
"multilple declref in param move");
77 void VisitStmt(
Stmt *s) {
88struct ParamReferenceReplacerRAII {
93 : localDeclMap(localDeclMap) {}
95 void addCopy(
const DeclStmt *pm) {
99 const VarDecl *vd =
static_cast<const VarDecl *
>(pm->
getSingleDecl());
100 const Expr *initExpr = vd->
getInit();
102 visitor.Visit(
const_cast<Expr *
>(initExpr));
103 assert(visitor.expr);
104 DeclRefExpr *dreOrig = visitor.expr;
107 auto it = localDeclMap.find(pd);
108 assert(it != localDeclMap.end() &&
"parameter is not found");
109 savedLocals.insert({pd, it->second});
111 auto copyIt = localDeclMap.find(vd);
112 assert(copyIt != localDeclMap.end() &&
"parameter copy is not found");
113 it->second = copyIt->getSecond();
116 ~ParamReferenceReplacerRAII() {
117 for (
auto &&savedLocal : savedLocals) {
118 localDeclMap.insert({savedLocal.first, savedLocal.second});
126struct CallCoroDelete final :
public EHScopeStack::Cleanup {
136 void emit(CIRGenFunction &cgf, Flags)
override {
141 if (cgf.
emitStmt(deallocate,
true).failed()) {
142 cgf.
cgm.
error(deallocate->getBeginLoc(),
143 "failed to emit coroutine deallocation expression");
148 cir::CoroFreeOp coroFree = cgf.
curCoro.
data->lastCoroFree;
151 cgf.
cgm.
error(deallocate->getBeginLoc(),
152 "Deallocation expression does not refer to coro.free");
156 builder.setInsertionPointAfter(coroFree);
159 llvm::SmallVector<mlir::Operation *> opsToMove;
160 mlir::Block *block = builder.getInsertionBlock();
161 mlir::Block::iterator it(isPtrNotNull.getDefiningOp());
163 for (++it; it != block->end(); ++it)
164 opsToMove.push_back(&*it);
167 cir::IfOp::create(builder, cgf.
getLoc(deallocate->getSourceRange()),
169 [&](mlir::OpBuilder &builder, mlir::Location loc) {
170 cir::YieldOp::create(builder, loc);
173 mlir::Operation *yieldOp = ifOp.getThenRegion().back().getTerminator();
174 for (
auto *op : opsToMove)
175 op->moveBefore(yieldOp);
177 explicit CallCoroDelete(Stmt *deallocStmt) : deallocate(deallocStmt) {}
191 cir::CoroIdOp coroId,
192 CallExpr const *coroIdExpr =
nullptr) {
196 cgf.
cgm.
error(coroIdExpr->getBeginLoc(),
197 "only one __builtin_coro_id can be used in a function");
199 cgf.
cgm.
error(coroIdExpr->getBeginLoc(),
200 "__builtin_coro_id shall not be used in a C++ coroutine");
202 llvm_unreachable(
"EmitCoroutineBodyStatement called twice?");
212static mlir::LogicalResult
216 if (cgf.
emitStmt(body,
true).failed())
217 return mlir::failure();
226 const bool canFallthrough = !currLexScope->
hasCoreturn();
229 if (cgf.
emitStmt(onFallthrough,
true).failed())
230 return mlir::failure();
232 return mlir::success();
242 auto coroId = cir::CoroIdOp::create(
cgm.getBuilder(), loc, args);
250 cgm.error(e->
getBeginLoc(),
"this builtin expect that __builtin_coro_id has"
251 " been used earlier in this function");
255 return cir::CoroAllocOp::create(
256 cgm.getBuilder(), loc,
257 mlir::ValueRange{curCoro.data->coroId.getResult()});
264 cgm.error(e->
getBeginLoc(),
"this builtin expect that __builtin_coro_id has"
265 " been used earlier in this function");
269 args.push_back(
curCoro.data->coroId.getResult());
273 auto coroBegin = cir::CoroBeginOp::create(
cgm.getBuilder(), loc, args);
274 curCoro.data->coroBegin = coroBegin;
285 args.push_back(cir::TokenNoneOp::create(builder, loc));
286 return cir::CoroEndOp::create(builder, loc, {
cgm.voidTy}, args);
293 cgm.error(e->
getBeginLoc(),
"this builtin expect that __builtin_coro_id has"
294 " been used earlier in this function");
299 cir::CoroFreeOp::create(
cgm.getBuilder(), loc,
300 mlir::ValueRange{curCoro.data->coroId.getResult(),
301 curCoro.data->coroBegin});
303 curCoro.data->lastCoroFree = coroFree;
309 return cir::CoroSizeOp::create(
cgm.getBuilder(), loc);
320 auto coroPromise = cir::CoroPromiseOp::create(
cgm.getBuilder(), loc, args);
324static mlir::LogicalResult
338 ~handlerEmitter()
override =
default;
349 cir::ConstantOp nullPtrCst = builder.getNullPtr(
voidPtrTy, openCurlyLoc);
351 auto fn = mlir::cast<cir::FuncOp>(
curFn);
352 fn.setCoroutine(
true);
356 cir::CoroIdOp coroId = cir::CoroIdOp::create(
357 cgm.getBuilder(), openCurlyLoc,
358 mlir::ValueRange{builder.getUInt32(newAlign, openCurlyLoc), nullPtrCst,
359 nullPtrCst, nullPtrCst});
364 cir::CoroAllocOp coroAlloc = cir::CoroAllocOp::create(
365 cgm.getBuilder(), openCurlyLoc,
366 mlir::ValueRange{curCoro.data->coroId.getResult()});
373 openCurlyLoc,
"__coro_frame_addr",
376 mlir::Value storeAddr = coroFrame.
getPointer();
377 builder.CIRBaseBuilderTy::createStore(openCurlyLoc, nullPtrCst, storeAddr);
378 mlir::LogicalResult res = mlir::success();
380 builder, openCurlyLoc, coroAlloc.getResult(),
382 [&](mlir::OpBuilder &b, mlir::Location loc) {
383 mlir::Value allocatedPtr = emitScalarExpr(s.getAllocate());
384 builder.CIRBaseBuilderTy::createStore(loc, allocatedPtr, storeAddr);
386 if (Stmt *retOnAllocFailure = s.getReturnStmtOnAllocFailure()) {
387 mlir::Value isPtrNull = builder.createPtrIsNull(allocatedPtr);
388 assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
389 cir::IfOp::create(builder, loc, isPtrNull, false,
390 [&](mlir::OpBuilder &b, mlir::Location loc) {
391 res = emitStmt(retOnAllocFailure,
393 cir::UnreachableOp::create(builder, loc);
396 cir::YieldOp::create(builder, loc);
402 curCoro.
data->coroBegin = cir::CoroBeginOp::create(
405 curCoro.data->coroId.getResult(),
406 cir::LoadOp::create(builder, openCurlyLoc, allocaTy, storeAddr)});
411 RunCleanupsScope resumeScope(*
this);
416 assert((paramMoves.size() == 0 || (paramMoves.size() ==
fnArgs.size())) &&
417 "ParamMoves and FnArgs should be the same size for coroutine "
426 for (
auto *pm : paramMoves) {
428 return mlir::failure();
432 if (
emitStmt(s.getPromiseDeclStmt(),
true).failed())
433 return mlir::failure();
448 s.getReturnValue()->getType().getQualifiers(),
453 curCoro.
data->currentAwaitKind = cir::AwaitKind::Init;
454 curCoro.
data->exceptionHandler = s.getExceptionHandler();
456 if (
emitStmt(s.getInitSuspendStmt(),
true).failed())
457 return mlir::failure();
459 curCoro.
data->currentAwaitKind = cir::AwaitKind::User;
461 mlir::OpBuilder::InsertPoint userBody;
463 cir::CoroBodyOp::create(builder, openCurlyLoc,
464 [&](mlir::OpBuilder &b, mlir::Location loc) {
465 userBody = b.saveInsertionPoint();
468 mlir::OpBuilder::InsertionGuard guard(builder);
469 builder.restoreInsertionPoint(userBody);
488 openCurlyLoc,
curCoro.
data->resumeEHVar.getPointer());
489 mlir::LogicalResult res = mlir::success();
490 cir::IfOp::create(builder, openCurlyLoc, shouldSkip,
492 [&](mlir::OpBuilder &b, mlir::Location loc) {
498 return mlir::failure();
501 return mlir::failure();
505 return mlir::failure();
509 mlir::Block &coroBodyBlock = coroBodyOp.getBody().back();
510 if (!coroBodyBlock.mightHaveTerminator()) {
511 mlir::OpBuilder::InsertionGuard guard(builder);
512 builder.setInsertionPointToEnd(&coroBodyBlock);
513 cir::YieldOp::create(builder, openCurlyLoc);
524 const bool canFallthrough =
curLexScope->hasCoreturn();
525 const bool hasCoreturns =
curCoro.data->coreturnCount > 0;
526 if (canFallthrough || hasCoreturns) {
527 curCoro.data->currentAwaitKind = cir::AwaitKind::Final;
529 mlir::OpBuilder::InsertionGuard guard(builder);
530 if (
emitStmt(s.getFinalSuspendStmt(),
true)
532 return mlir::failure();
537 cir::ConstantOp nullHandler =
538 builder.getNullPtr(builder.getVoidPtrTy(), openCurlyLoc);
539 cir::ConstantOp noUnwind = builder.getBool(
false, openCurlyLoc);
540 auto tkNone = cir::TokenNoneOp::create(builder, openCurlyLoc);
541 cir::CoroEndOp::create(builder, openCurlyLoc, nullHandler, noUnwind, tkNone);
543 if (
auto *ret = cast_or_null<ReturnStmt>(s.getReturnStmt())) {
546 Expr *previousRetValue = ret->getRetValue();
547 ret->setRetValue(
nullptr);
549 return mlir::failure();
552 ret->setRetValue(previousRetValue);
554 return mlir::success();
558 if (
const auto *ce = dyn_cast<CXXMemberCallExpr>(e))
559 if (
const auto *proto =
584struct LValueOrRValue {
594 mlir::Block *scopeParentBlock,
595 mlir::Value &tmpResumeRValAddr,
bool forLValue) {
596 [[maybe_unused]] mlir::LogicalResult awaitBuild = mlir::success();
597 LValueOrRValue awaitRes;
602 [[maybe_unused]] cir::AwaitOp awaitOp = cir::AwaitOp::create(
605 [&](mlir::OpBuilder &b, mlir::Location loc) {
606 Expr *condExpr = s.getReadyExpr()->IgnoreParens();
607 builder.createCondition(cgf.evaluateExprAsBool(condExpr));
610 [&](mlir::OpBuilder &b, mlir::Location loc) {
616 mlir::Value suspendRet = cgf.emitScalarExpr(s.getSuspendExpr());
620 cgf.cgm.errorNYI(
"Veto await_suspend");
624 cir::YieldOp::create(builder, loc);
627 [&](mlir::OpBuilder &b, mlir::Location loc) {
631 if (coro.exceptionHandler &&
kind == cir::AwaitKind::Init &&
644 SourceLocation resumeLoc = s.getResumeExpr()->getExprLoc();
645 mlir::Location mlirLoc = cgf.
getLoc(resumeLoc);
649 builder.createFlagStore(mlirLoc,
false,
650 coro.resumeEHVar.getPointer());
652 CXXCatchStmt catchStmt(resumeLoc,
653 nullptr, coro.exceptionHandler);
656 resumeLoc, resumeLoc);
657 CXXTryStmt *tryStmt =
660 struct resumeEmitter final : CIRGenFunction::cxxTryBodyEmitter {
661 const CXXTryStmt &tryStmt;
663 mlir::Value resumeEHVar;
664 resumeEmitter(
const CXXTryStmt &tryStmt, mlir::Location loc,
666 : tryStmt(tryStmt), loc(loc),
667 resumeEHVar(resumeEHVar.getPointer()) {}
669 mlir::LogicalResult operator()(CIRGenFunction &cgf)
override {
670 mlir::LogicalResult res =
671 cgf.
emitStmt(tryStmt.getTryBlock(),
true);
676 ~resumeEmitter()
override =
default;
677 } emitter{*tryStmt, mlirLoc, coro.resumeEHVar};
683 }
else if (forLValue) {
686 awaitRes.lv = cgf.
emitLValue(s.getResumeExpr());
689 cgf.
emitAnyExpr(s.getResumeExpr(), aggSlot, ignoreResult);
690 if (!awaitRes.rv.isIgnored()) {
694 RValue rv = awaitRes.rv;
700 cgf.
cgm.
errorNYI(
"emitSuspendExpression: Aggregate value");
706 builder.getBestAllocaInsertPoint(scopeParentBlock));
708 builder.CIRBaseBuilderTy::createStore(loc, value,
714 cir::YieldOp::create(builder, loc);
717 assert(awaitBuild.succeeded() &&
"Should know how to codegen");
735 [[maybe_unused]] mlir::Value tmpResumeRValAddr;
740 ignoreResult, currEntryBlock, tmpResumeRValAddr,
790 return mlir::failure();
795 cir::CoReturnOp::create(builder, loc);
797 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 void createCoroData(CIRGenFunction &cgf, CIRGenFunction::CGCoroInfo &curCoro, cir::CoroIdOp coroId, CallExpr const *coroIdExpr=nullptr)
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 coroutineBodyExceptionHelper(CIRGenFunction &cgf, const CoroutineBodyStmt &s)
static mlir::LogicalResult emitBodyAndFallthrough(CIRGenFunction &cgf, const CoroutineBodyStmt &s, Stmt *body, const CIRGenFunction::LexicalScope *currLexScope)
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
cir::StoreOp createFlagStore(mlir::Location loc, bool val, mlir::Value dst)
mlir::Value createPtrIsNotNull(mlir::Value ptr)
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
cir::LoadOp createFlagLoad(mlir::Location loc, mlir::Value addr)
Emit a load from an boolean flag variable.
CharUnits getTypeAlignInChars(QualType T) const
Return the ABI-specified alignment of a (complete) type T, in characters.
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.
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,...
cir::CoroAllocOp emitCoroAllocBuiltinCall(const CallExpr *e)
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.
cir::CoroBeginOp emitCoroBeginBuiltinCall(const CallExpr *e)
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.
RValue emitCoyieldExpr(const CoyieldExpr &e, AggValueSlot aggSlot=AggValueSlot::ignored(), bool ignoreResult=false)
cir::CoroFreeOp emitCoroFreeBuiltin(const CallExpr *e)
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)
mlir::LogicalResult emitCXXTryStmt(const clang::CXXTryStmt &s, cxxTryBodyEmitter &bodyCallback)
RValue emitCoroutineFrame()
mlir::Value emitAlloca(llvm::StringRef name, mlir::Type ty, mlir::Location loc, clang::CharUnits alignment, bool insertIntoFnEntryBlock, mlir::Value arraySize=nullptr)
cir::CoroPromiseOp emitCoroPromiseBuiltinCall(const CallExpr *e)
Address returnValue
The temporary alloca to hold the return value.
cir::CoroEndOp emitCoroEndBuiltinCall(const CallExpr *e)
mlir::Value emitScalarExpr(const clang::Expr *e, bool ignoreResultAssign=false)
Emit the computation of the specified expression of scalar type.
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.
cir::CoroSizeOp emitCoroSizeBuiltinCall(const CallExpr *e)
LexicalScope * curLexScope
cir::CoroIdOp emitCoroIDBuiltinCall(const CallExpr *e)
clang::ASTContext & getContext() const
mlir::LogicalResult emitCoroutineBody(const CoroutineBodyStmt &s)
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.
CIRGenBuilderTy & getBuilder()
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.
static RValue getIgnored()
CXXCatchStmt - This represents a C++ catch block.
static CXXTryStmt * Create(const ASTContext &C, SourceLocation tryLoc, CompoundStmt *tryBlock, ArrayRef< Stmt * > handlers)
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.
static CompoundStmt * Create(const ASTContext &C, ArrayRef< Stmt * > Stmts, FPOptionsOverride FPFeatures, SourceLocation LB, SourceLocation RB)
Represents a 'co_return' statement in the C++ Coroutines TS.
Expr * getOperand() const
Retrieve the operand of the 'co_return' statement.
Expr * getPromiseCall() const
Retrieve the promise call that results from this 'co_return' statement.
Represents the body of a coroutine.
CompoundStmt * getBody() const
Retrieve the body of the coroutine as written.
Stmt * getFallthroughHandler() const
SourceLocation getBeginLoc() const LLVM_READONLY
Represents an expression that might suspend coroutine execution; either a co_await or co_yield expres...
OpaqueValueExpr * getOpaqueValue() const
getOpaqueValue - Return the opaque value placeholder.
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.
Top level wrappers for InstallAPI frontend operations.
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 coroOutsideFrameMD()
static bool generateDebugInfo()
cir::AwaitKind currentAwaitKind
CallExpr const * coroIdExpr
cir::CoroFreeOp lastCoroFree
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