15#include "mlir/IR/Block.h"
16#include "mlir/IR/Location.h"
20#include "llvm/Support/SaveAndRestore.h"
48 auto funcTy = cir::FuncType::get({}, i32Ty,
true);
53 return personalityFn.getSymName();
57 if (!
cgm.getLangOpts().CXXExceptions)
60 const FunctionDecl *fd = dyn_cast_or_null<FunctionDecl>(d);
64 if (
const CapturedDecl *cd = dyn_cast_or_null<CapturedDecl>(d)) {
66 cgm.errorNYI(cd->getSourceRange(),
67 "emitStartEHSpec CapturedDecl nothrow");
82 !
cgm.getCodeGenOpts().hasWasmExceptions());
93 if (
getTarget().getCXXABI().isMicrosoft())
100 if (
cgm.getCodeGenOpts().hasWasmExceptions()) {
102 diag::warn_wasm_dynamic_exception_spec_ignored)
112 if (
getTarget().getCXXABI() == TargetCXXABI::WebAssembly &&
113 (
cgm.getCodeGenOpts().getExceptionHandling() ==
115 cgm.getCodeGenOpts().getExceptionHandling() ==
119 diag::warn_wasm_dynamic_exception_spec_ignored)
121 }
else if (!needsTerminate) {
131 permittedTypes.push_back(
132 cgm.getAddrOfRTTIDescriptor(loc, exceptType,
true));
136 cir::FuncOp funcOp = mlir::cast<cir::FuncOp>(
curFn);
137 if (!funcOp.getPersonality())
140 bool emptyFilter = permittedTypes.empty();
145 [](mlir::OpBuilder &, mlir::Location) {},
147 [&](mlir::OpBuilder &b, mlir::Location loc,
148 mlir::OperationState &result) {
149 mlir::OpBuilder::InsertionGuard guard(b);
152 if (needsTerminate) {
153 mlir::Block *terminateBlock = b.createBlock(
154 result.addRegion(), {}, {ehTokenTy}, {loc});
155 cir::EhTerminateOp::create(b, loc, terminateBlock->getArgument(0));
159 mlir::Block *filterBlock = b.createBlock(
160 result.addRegion(), {}, {ehTokenTy}, {loc});
162 cir::UnreachableOp::create(b, loc);
164 cir::ResumeOp::create(b, loc, filterBlock->getArgument(0));
166 mlir::Block *unexpectedBlock = b.createBlock(
167 result.addRegion(), {}, {ehTokenTy}, {loc});
168 cir::EhUnexpectedOp::create(b, loc, unexpectedBlock->getArgument(0));
172 if (needsTerminate) {
176 handlerAttrs.push_back(cir::CatchAllAttr::get(&
getMLIRContext()));
178 handlerAttrs.push_back(cir::EhFilterAttr::get(
180 handlerAttrs.push_back(cir::EhUnexpectedAttr::get(&
getMLIRContext()));
186 builder.setInsertionPointToEnd(&
ehSpecTryOp.getTryRegion().front());
198 mlir::Block *bodyExit = &tryOp.getTryRegion().back();
199 if (bodyExit->empty() ||
200 !bodyExit->back().hasTrait<mlir::OpTrait::IsTerminator>()) {
201 mlir::OpBuilder::InsertionGuard guard(builder);
202 builder.setInsertionPointToEnd(bodyExit);
203 builder.createYield(tryOp.getLoc());
207 builder.setInsertionPointAfter(tryOp);
212 if (
cgm.getLangOpts().OpenMPIsTargetDevice &&
213 (triple.isNVPTX() || triple.isAMDGCN())) {
214 cgm.errorNYI(
"emitCXXThrowExpr OpenMP with NVPTX or AMDGCN Triples");
219 QualType throwType = subExpr->getType();
221 cgm.errorNYI(
"emitCXXThrowExpr ObjCObjectPointerType");
225 cgm.getCXXABI().emitThrow(*
this, e);
229 cgm.getCXXABI().emitRethrow(*
this,
true);
269 QualType caughtType =
cgm.getASTContext().getUnqualifiedArrayType(
272 cgm.errorNYI(
"addCatchHandlerAttr: caughtType ObjCObjectPointerType");
278 handlerAttrs.push_back(typeInfo.
rtti);
281 handlerAttrs.push_back(cir::CatchAllAttr::get(&
getMLIRContext()));
287 CallEndCatch(mlir::Value catchToken) : catchToken(catchToken) {}
288 mlir::Value catchToken;
299 mlir::Type exnPtrTy) {
300 auto catchTokenTy = cir::CatchTokenType::get(cgf.
getBuilder().getContext());
301 auto beginCatch = cir::BeginCatchOp::create(cgf.
getBuilder(),
303 catchTokenTy, exnPtrTy, ehToken);
306 beginCatch.getCatchToken());
308 return beginCatch.getExnPtr();
321 cir::PointerType paramAddrType,
323 mlir::Location loc = cgf.
getLoc(clangLoc);
329 assert(copyExpr &&
"non-trivial copy expects a copy expression");
332 llvm::raw_svector_ostream thunkNameStream(thunkName);
333 thunkNameStream <<
"__clang_cir_catch_copy_";
335 catchParam.
getType(), thunkNameStream);
340 mlir::Type voidTy = cir::VoidType::get(builder.getContext());
341 auto thunkTy = cir::FuncType::get({paramAddrType, paramAddrType}, voidTy,
344 mlir::OpBuilder::InsertionGuard guard(builder);
345 builder.setInsertionPointToEnd(mod.getBody());
346 cir::FuncOp thunk = cir::FuncOp::create(builder, loc, thunkName, thunkTy);
348 thunk.setLinkage(cir::GlobalLinkageKind::LinkOnceODRLinkage);
349 thunk.setGlobalVisibility(cir::VisibilityKind::Hidden);
350 thunk->setAttr(cir::CIRDialect::getCatchCopyThunkAttrName(),
351 builder.getUnitAttr());
353 mlir::Block *entry = thunk.addEntryBlock();
354 builder.setInsertionPointToStart(entry);
362 subCgf.
curFn = thunk;
389 cir::ReturnOp::create(builder, loc);
396 mlir::Value ehToken,
const VarDecl &catchParam,
400 cir::InitCatchKind
kind;
404 const PointerType *ptr = dyn_cast<PointerType>(caughtType);
406 kind = cir::InitCatchKind::Reference;
408 kind = cir::InitCatchKind::ReferenceToRecordPointer;
410 kind = cir::InitCatchKind::ReferenceToPointer;
416 kind = !copyExpr ? cir::InitCatchKind::TrivialCopy
417 : cir::InitCatchKind::NonTrivialCopy;
420 if (catchType->hasPointerRepresentation()) {
424 kind = cir::InitCatchKind::Objc;
430 kind = cir::InitCatchKind::Pointer;
434 kind = cir::InitCatchKind::Scalar;
440 Address paramAddr = var.getAllocatedAddress();
441 mlir::Location mloc = cgf.
getLoc(loc);
443 if (
kind == cir::InitCatchKind::NonTrivialCopy ||
444 kind == cir::InitCatchKind::ReferenceToPointer) {
450 mlir::FlatSymbolRefAttr copyFun{};
451 if (
kind == cir::InitCatchKind::NonTrivialCopy) {
453 mlir::cast<cir::PointerType>(paramAddr.
getPointer().getType());
456 copyFun = mlir::FlatSymbolRefAttr::get(thunk.getSymNameAttr());
459 cir::ConstructCatchParamOp::create(builder, mloc, ehToken,
464 cir::InitCatchParamOp::create(builder, mloc, exnPtr, paramAddr.
getPointer(),
472 mlir::Value ehToken) {
503 mlir::OpBuilder::InsertPoint scopeIP;
504 cir::ScopeOp::create(
506 [&](mlir::OpBuilder &b, mlir::Location loc) {
507 scopeIP = builder.saveInsertionPoint();
511 auto funcOp = mlir::cast<cir::FuncOp>(
curFn);
512 if (!funcOp.getPersonality())
515 mlir::OpBuilder::InsertionGuard guard(builder);
516 builder.restoreInsertionPoint(scopeIP);
521 const bool isTargetDevice =
522 (
cgm.getLangOpts().OpenMPIsTargetDevice && (t.isNVPTX() || t.isAMDGCN()));
523 if (isTargetDevice) {
524 cgm.errorNYI(
"emitCXXTryStmt: OpenMP target region offloaded to GPU");
525 return mlir::success();
532 builder.getInsertionBlock()};
535 cgm.errorNYI(
"enterCXXTryStmt: EHAsynch");
536 return mlir::failure();
540 mlir::LogicalResult tryRes = mlir::success();
541 auto tryOp = cir::TryOp::create(
544 [&](mlir::OpBuilder &b, mlir::Location loc) {
549 if (bodyCallback(*this).failed())
550 tryRes = mlir::failure();
552 if (!builder.getBlock()->mightHaveTerminator() ||
553 !builder.getBlock()->getTerminator())
554 cir::YieldOp::create(builder, loc);
557 [&](mlir::OpBuilder &b, mlir::Location loc,
558 mlir::OperationState &result) {
559 mlir::OpBuilder::InsertionGuard guard(b);
560 bool hasCatchAll =
false;
563 for (
unsigned i = 0; i != numHandlers; ++i) {
567 mlir::Region *region = result.addRegion();
568 builder.createBlock(region, {}, {ehTokenTy}, {loc});
573 mlir::Region *region = result.addRegion();
574 mlir::Block *unwindBlock =
575 builder.createBlock(region, {}, {ehTokenTy}, {loc});
576 cir::ResumeOp::create(builder, loc, unwindBlock->getArgument(0));
582 return mlir::failure();
585 tryOp.setHandlerTypesAttr(
590 const bool doImplicitRethrow =
598 for (
unsigned i = 0; i != numHandlers; ++i) {
600 mlir::Region *handler = &tryOp.getHandlerRegions()[i];
603 mlir::OpBuilder::InsertionGuard guard(builder);
604 builder.setInsertionPointToStart(&handler->front());
607 mlir::Value ehToken = handler->front().getArgument(0);
622 [[maybe_unused]] mlir::LogicalResult emitResult =
624 assert(emitResult.succeeded() &&
"failed to emit catch handler block");
636 cgm.getCXXABI().emitRethrow(*
this,
true);
641 mlir::Block *block = &handler->getBlocks().back();
642 if (block->empty() ||
643 !block->back().hasTrait<mlir::OpTrait::IsTerminator>()) {
644 mlir::OpBuilder::InsertionGuard guard(builder);
645 builder.setInsertionPointToEnd(block);
646 builder.createYield(handlerLoc);
650 return mlir::success();
655 return mlir::LogicalResult::success();
662 return cgf.
emitStmt(s.getTryBlock(),
true);
664 ~simpleTryBodyEmitter()
override =
default;
667 simpleTryBodyEmitter emitter{s};
683 if (!lo.Exceptions || lo.IgnoreExceptions) {
684 if (!lo.Borland && !lo.MicrosoftExt)
686 cgm.errorNYI(
"isInvokeDest: no exceptions or ignore exception");
691 if (lo.CUDA && lo.CUDAIsDevice)
694 return ehStack.requiresCatchOrCleanup();
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 cir::FuncOp getOrCreateCopyThunk(CIRGenFunction &cgf, const VarDecl &catchParam, cir::PointerType paramAddrType, SourceLocation clangLoc)
Get or create the catch-init copy thunk for catchParam.
static llvm::StringRef getPersonalityFn(CIRGenModule &cgm, const EHPersonality &personality)
static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken, mlir::Type exnPtrTy)
static void initCatchParam(CIRGenFunction &cgf, CIRGenBuilderTy &builder, mlir::Value ehToken, const VarDecl &catchParam, SourceLocation loc)
A "special initializer" callback for initializing a catch parameter during catch initialization.
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
cir::PointerType getVoidPtrTy(clang::LangAS langAS=clang::LangAS::Default)
static CanQualType getCanonicalType(QualType T)
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
mlir::Value getPointer() const
Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const
Return address with different element type, a bitcast pointer, and the same alignment.
static AggValueSlot forAddr(Address addr, clang::Qualifiers quals, IsDestructed_t isDestructed, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed)
cir::IntType getSInt32Ty()
clang::MangleContext & getMangleContext()
Gets the mangle context.
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.
void forceCleanup(ArrayRef< mlir::Value * > valuesToReload={})
Force the emission of cleanups now, instead of waiting until this object is destroyed.
static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type)
Return the cir::TypeEvaluationKind of QualType type.
AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d, mlir::OpBuilder::InsertPoint ip={})
const clang::LangOptions & getLangOpts() const
const TargetInfo & getTarget() const
void addCatchHandlerAttr(const CXXCatchStmt *catchStmt, SmallVector< mlir::Attribute > &handlerAttrs)
Address makeNaturalAddressForPointer(mlir::Value ptr, QualType t, CharUnits alignment, bool forPointeeType=false, LValueBaseInfo *baseInfo=nullptr)
Construct an address with the natural alignment of T.
bool insertionPointIsReachable() const
True if code emitted at the builder's insertion point can be reached.
void emitAnyExprToExn(const Expr *e, Address addr)
LValue makeNaturalAlignAddrLValue(mlir::Value val, QualType ty)
cir::TryOp ehSpecTryOp
The cir.try wrapping a function whose exception specification has to be enforced.
void emitBeginCatch(const CXXCatchStmt *catchStmt, mlir::Value ehToken)
Begins a catch statement by initializing the catch variable and calling __cxa_begin_catch.
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.
EHScopeStack ehStack
Tracks function scope overall cleanup handling.
mlir::Type convertTypeForMem(QualType t)
mlir::LogicalResult emitCXXTryStmt(const clang::CXXTryStmt &s, cxxTryBodyEmitter &bodyCallback, bool isFnTryBlock=false)
const clang::Decl * curCodeDecl
This is the inner-most code context, which includes blocks.
CIRGenBuilderTy & getBuilder()
mlir::MLIRContext & getMLIRContext()
std::optional< SourceRange > currSrcLoc
Use to track source locations across nested visitor traversals.
void emitCXXThrowExpr(const CXXThrowExpr *e)
bool isCatchOrCleanupRequired()
void emitEndEHSpec(const clang::Decl *d)
Close the cir.try opened by emitStartEHSpec.
CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder, bool suppressNewContext=false)
void emitStartEHSpec(const clang::Decl *d)
Wrap the function body in a cir.try that enforces the exception specification of d: a filter handler ...
mlir::LogicalResult emitStmt(const clang::Stmt *s, bool useCurrentScope, llvm::ArrayRef< const Attr * > attrs={})
void emitAggExpr(const clang::Expr *e, AggValueSlot slot)
void emitAutoVarCleanups(const AutoVarEmission &emission)
This class organizes the cross-function state that is used while generating CIR code.
clang::ASTContext & getASTContext() const
void insertGlobalSymbol(mlir::Operation *op)
CIRGenBuilderTy & getBuilder()
cir::FuncOp lookupFuncOp(llvm::StringRef name)
O(1) lookup of a FuncOp by name in the symbol cache.
const clang::TargetInfo & getTarget() const
cir::FuncOp createRuntimeFunction(cir::FuncType ty, llvm::StringRef name, mlir::NamedAttrList extraAttrs={}, bool isLocal=false, bool assumeConvergent=false)
const clang::CodeGenOptions & getCodeGenOpts() const
const clang::LangOptions & getLangOpts() const
mlir::ModuleOp getModule() const
CIRGenCXXABI & getCXXABI() const
Information for lazily generating a cleanup.
CXXCatchStmt - This represents a C++ catch block.
SourceLocation getCatchLoc() const
Stmt * getHandlerBlock() const
SourceLocation getBeginLoc() const LLVM_READONLY
VarDecl * getExceptionDecl() const
QualType getCaughtType() const
A C++ throw-expression (C++ [except.throw]).
const Expr * getSubExpr() const
CXXTryStmt - A C++ try block, including all handlers.
CXXCatchStmt * getHandler(unsigned i)
unsigned getNumHandlers() const
SourceLocation getBeginLoc() const LLVM_READONLY
CompoundStmt * getTryBlock()
Qualifiers getQualifiers() const
Retrieve all qualifiers.
Represents the body of a CapturedStmt, and serves as its DeclContext.
static CharUnits Zero()
Construct a CharUnits quantity of zero.
SourceLocation getLocation() const
This represents one expression.
Represents a function declaration or definition.
SourceRange getExceptionSpecSourceRange() const
Attempt to compute an informative source range covering the function exception specification,...
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Represents a prototype with parameter type info, e.g.
ExceptionSpecificationType getExceptionSpecType() const
Get the kind of exception specification on this function.
CanThrowResult canThrow() const
Determine whether this function type has a non-throwing exception specification.
ArrayRef< QualType > exceptions() const
const Decl * getDecl() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
virtual void mangleCanonicalTypeName(QualType T, raw_ostream &, bool NormalizeIntegers=false)=0
Generates a unique string for an externally visible type for use with TBAA or type uniquing.
static const OpaqueValueExpr * findInCopyConstruct(const Expr *expr)
Given an expression which invokes a copy constructor — i.e.
PointerType - C99 6.7.5.1 - Pointer Declarators.
QualType getPointeeType() const
A (possibly-)qualified type.
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
The collection of all-type qualifiers we support.
@ OCL_Strong
Assigning into this object requires the old value to be released and the new value to be retained.
@ OCL_ExplicitNone
This object can be modified without requiring retains or releases.
@ OCL_None
There is no lifetime qualification on this type.
@ OCL_Weak
Reading or writing from this object requires a barrier call.
@ OCL_Autoreleasing
Assigning into this object requires a lifetime extension.
ObjCLifetime getObjCLifetime() const
Encodes a location in the source.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
bool isObjCObjectPointerType() const
const T * getAs() const
Member-template getAs<specific type>'.
bool isRecordType() const
Represents a variable declaration or definition.
const Expr * getInit() const
const EHPersonality & getEHPersonality(CIRGenModule &cgm, const clang::FunctionDecl *fd)
Selects the personality function to use for fd, or for the translation unit as a whole when fd is nul...
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
const EHPersonality & getEHPersonality(const TargetInfo &Target, const LangOptions &LangOpts, const CodeGenOptions &CGOpts, const FunctionDecl *FD)
Selects the personality function to use for FD, or for the translation unit as a whole when FD is nul...
Top level wrappers for InstallAPI frontend operations.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
U cast(CodeGen::Address addr)
ExceptionSpecificationType
The various types of exception specifications that exist in C++11.
@ EST_Dynamic
throw(T1, T2)
static bool ehCleanupScope()
static bool currentFuncletPad()
static bool incrementProfileCounter()
Represents a scope, including function bodies, compound statements, and the substatements of if/while...
The MS C++ ABI needs a pointer to RTTI data plus some flags to describe the type of a catch handler,...
The exceptions personality for a function.
const char * PersonalityFn