[clang] [CIR] Make BeginCatchOp target-independent (PR #190612)
Amr Hesham via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 29 13:05:58 PDT 2026
https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/190612
>From f9ef77a6d2562258c9d3d35e7545ef11dcbb3524 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Sun, 12 Apr 2026 17:56:43 +0200
Subject: [PATCH 1/5] [CIR] Make BeginCatchOp target-independent
---
clang/lib/CIR/CodeGen/CIRGenCXXABI.h | 4 -
clang/lib/CIR/CodeGen/CIRGenException.cpp | 180 +++++++++-
clang/lib/CIR/CodeGen/CIRGenFunction.h | 2 +
clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 239 -------------
.../CIR/Dialect/Transforms/EHABILowering.cpp | 50 ++-
.../CodeGen/try-catch-all-with-cleanup.cpp | 9 -
clang/test/CIR/CodeGen/try-catch.cpp | 332 +++++++++++++++---
7 files changed, 509 insertions(+), 307 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index 614d62fda44a5..bb100f7afd929 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -134,10 +134,6 @@ class CIRGenCXXABI {
virtual void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) = 0;
- virtual void emitBeginCatch(CIRGenFunction &cgf,
- const CXXCatchStmt *catchStmt,
- mlir::Value ehToken) = 0;
-
virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
QualType ty) = 0;
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index c80f292553a1c..7dd2a8d59199e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -273,6 +273,184 @@ void CIRGenFunction::addCatchHandlerAttr(
}
}
+namespace {
+/// From traditional LLVM, useful info for LLVM lowering support:
+/// A cleanup to call __cxa_end_catch. In many cases, the caught
+/// exception type lets us state definitively that the thrown exception
+/// type does not have a destructor. In particular:
+/// - Catch-alls tell us nothing, so we have to conservatively
+/// assume that the thrown exception might have a destructor.
+/// - Catches by reference behave according to their base types.
+/// - Catches of non-record types will only trigger for exceptions
+/// of non-record types, which never have destructors.
+/// - Catches of record types can trigger for arbitrary subclasses
+/// of the caught type, so we have to assume the actual thrown
+/// exception type might have a throwing destructor, even if the
+/// caught type's destructor is trivial or nothrow.
+struct CallEndCatch final : EHScopeStack::Cleanup {
+ CallEndCatch(bool mightThrow, mlir::Value catchToken)
+ : mightThrow(mightThrow), catchToken(catchToken) {}
+ bool mightThrow;
+ mlir::Value catchToken;
+
+ void emit(CIRGenFunction &cgf, Flags flags) override {
+ // Traditional LLVM codegen would emit a call to __cxa_end_catch
+ // here. For CIR, just let it pass since the cleanup is going
+ // to be emitted on a later pass when lowering the catch region.
+ // CGF.EmitRuntimeCallOrTryCall(getEndCatchFn(CGF.CGM));
+ cir::EndCatchOp::create(cgf.getBuilder(), *cgf.currSrcLoc, catchToken);
+ cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
+ }
+};
+} // namespace
+
+static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken,
+ mlir::Type exnPtrTy, bool endMightThrow) {
+ auto catchTokenTy = cir::CatchTokenType::get(cgf.getBuilder().getContext());
+ auto beginCatch = cir::BeginCatchOp::create(cgf.getBuilder(),
+ cgf.getBuilder().getUnknownLoc(),
+ catchTokenTy, exnPtrTy, ehToken);
+
+ cgf.ehStack.pushCleanup<CallEndCatch>(
+ NormalAndEHCleanup,
+ endMightThrow && !cgf.cgm.getLangOpts().AssumeNothrowExceptionDtor,
+ beginCatch.getCatchToken());
+
+ return beginCatch.getExnPtr();
+}
+
+/// A "special initializer" callback for initializing a catch
+/// parameter during catch initialization.
+static void initCatchParam(CIRGenFunction &cgf, mlir::Value ehToken,
+ const VarDecl &catchParam, Address paramAddr,
+ SourceLocation loc) {
+ CIRGenBuilderTy builder = cgf.getBuilder();
+ CanQualType catchType =
+ cgf.cgm.getASTContext().getCanonicalType(catchParam.getType());
+ mlir::Type cirCatchTy = cgf.convertTypeForMem(catchType);
+ mlir::Type exnPtrTy = builder.getPointerTo(cirCatchTy);
+ CharUnits caughtExnAlignment = cgf.getPointerAlign();
+
+ // If we're catching by reference, we can just cast the object
+ // pointer to the appropriate pointer.
+ if (isa<ReferenceType>(catchType)) {
+ QualType caughtType = cast<ReferenceType>(catchType)->getPointeeType();
+ // We have no way to tell the personality function that we're
+ // catching by reference, so if we're catching a pointer,
+ // __cxa_begin_catch will actually return that pointer by value.
+ if (const PointerType *pt = dyn_cast<PointerType>(caughtType)) {
+ QualType pointeeType = pt->getPointeeType();
+ // When catching by reference, generally we should just ignore
+ // this by-value pointer and use the exception object instead.
+ if (!pointeeType->isRecordType()) {
+ cgf.cgm.errorNYI(loc,
+ "initCatchParam: catching a pointer of non-record");
+ return;
+ }
+ }
+
+ bool endCatchMightThrow = caughtType->isRecordType();
+ mlir::Value exnPtr =
+ callBeginCatch(cgf, ehToken, exnPtrTy, endCatchMightThrow);
+ Address exnPtrAddr = Address(exnPtr, caughtExnAlignment);
+ cgf.setAddrOfLocalVar(&catchParam, exnPtrAddr);
+ return;
+ }
+
+ // Scalars and complexes.
+ cir::TypeEvaluationKind tek = cgf.getEvaluationKind(catchType);
+ if (tek != cir::TEK_Aggregate) {
+ // Notes for LLVM lowering:
+ // If the catch type is a pointer type, __cxa_begin_catch returns
+ // the pointer by value.
+ if (catchType->hasPointerRepresentation()) {
+ switch (catchType.getQualifiers().getObjCLifetime()) {
+ case Qualifiers::OCL_Strong:
+ cgf.cgm.errorNYI(loc,
+ "initCatchParam: PointerRepresentation OCL_Strong");
+ return;
+
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ cgf.cgm.errorNYI(loc, "initCatchParam: PointerRepresentation "
+ "OCL_ExplicitNone & OCL_Autoreleasing");
+ return;
+
+ case Qualifiers::OCL_None:
+ break;
+
+ case Qualifiers::OCL_Weak:
+ cgf.cgm.errorNYI(loc, "initCatchParam: PointerRepresentation OCL_Weak");
+ return;
+ }
+ }
+
+ // Otherwise, it returns a pointer into the exception object.
+ mlir::Value exnPtr = callBeginCatch(cgf, ehToken, exnPtrTy,
+ /*endMightThrow=*/false);
+ Address exnPtrAddr = Address(exnPtr, caughtExnAlignment);
+ cgf.setAddrOfLocalVar(&catchParam, exnPtrAddr);
+ return;
+ }
+
+ assert(isa<RecordType>(catchType) && "unexpected catch type!");
+ auto *catchRD = catchType->getAsCXXRecordDecl();
+ caughtExnAlignment = cgf.cgm.getClassPointerAlignment(catchRD);
+
+ // Check for a copy expression. If we don't have a copy expression,
+ // that means a trivial copy is okay.
+ const Expr *copyExpr = catchParam.getInit();
+ if (!copyExpr) {
+ mlir::Value exnPtr =
+ callBeginCatch(cgf, ehToken, exnPtrTy, /*endMightThrow=*/true);
+ Address exnPtrAddr = Address(exnPtr, caughtExnAlignment);
+ cgf.setAddrOfLocalVar(&catchParam, exnPtrAddr);
+ return;
+ }
+
+ cgf.cgm.errorNYI(loc, "initCatchParam: cir::TEK_Aggregate non-trivial copy");
+}
+
+/// Begins a catch statement by initializing the catch variable and
+/// calling __cxa_begin_catch.
+void CIRGenFunction::emitBeginCatch(const CXXCatchStmt *catchStmt,
+ mlir::Value ehToken) {
+ // We have to be very careful with the ordering of cleanups here:
+ // C++ [except.throw]p4:
+ // The destruction [of the exception temporary] occurs
+ // immediately after the destruction of the object declared in
+ // the exception-declaration in the handler.
+ //
+ // So the precise ordering is:
+ // 1. Construct catch variable.
+ // 2. __cxa_begin_catch
+ // 3. Enter __cxa_end_catch cleanup
+ // 4. Enter dtor cleanup
+ //
+ // We do this by using a slightly abnormal initialization process.
+ // Delegation sequence:
+ // - ExitCXXTryStmt opens a RunCleanupsScope
+ // - EmitAutoVarAlloca creates the variable and debug info
+ // - InitCatchParam initializes the variable from the exception
+ // - CallBeginCatch calls __cxa_begin_catch
+ // - CallBeginCatch enters the __cxa_end_catch cleanup
+ // - EmitAutoVarCleanups enters the variable destructor cleanup
+ // - EmitCXXTryStmt emits the code for the catch body
+ // - EmitCXXTryStmt close the RunCleanupsScope
+ VarDecl *catchParam = catchStmt->getExceptionDecl();
+ if (!catchParam) {
+ callBeginCatch(*this, ehToken, builder.getVoidPtrTy(),
+ /*endMightThrow=*/true);
+ return;
+ }
+
+ // Emit the local. Make sure the alloca's superseed the current scope, since
+ // these are going to be consumed by `cir.catch`, which is not within the
+ // current scope.
+ initCatchParam(*this, ehToken, *catchParam, Address::invalid(),
+ catchStmt->getBeginLoc());
+}
+
mlir::LogicalResult
CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s,
cxxTryBodyEmitter &bodyCallback) {
@@ -384,7 +562,7 @@ CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s,
// Initialize the catch variable.
// TODO(cir): Move this out of CXXABI.
assert(!cir::MissingFeatures::currentFuncletPad());
- cgm.getCXXABI().emitBeginCatch(*this, catchStmt, ehToken);
+ emitBeginCatch(catchStmt, ehToken);
// Emit the PGO counter increment.
assert(!cir::MissingFeatures::incrementProfileCounter());
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index f3eb5982c041f..aadd2ff741650 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1798,6 +1798,8 @@ class CIRGenFunction : public CIRGenTypeCache {
virtual ~cxxTryBodyEmitter() = default;
};
+ void emitBeginCatch(const CXXCatchStmt *catchStmt, mlir::Value ehToken);
+
mlir::LogicalResult emitCXXTryStmt(const clang::CXXTryStmt &s,
cxxTryBodyEmitter &bodyCallback);
mlir::LogicalResult emitCXXTryStmt(const clang::CXXTryStmt &s);
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index b7b149923e78f..daff196b0355a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -82,9 +82,6 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;
- void emitBeginCatch(CIRGenFunction &cgf, const CXXCatchStmt *catchStmt,
- mlir::Value ehToken) override;
-
bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
CXXDtorType dt) const override {
// Itanium does not emit any destructor variant as an inline thunk.
@@ -2483,242 +2480,6 @@ Address CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
return Address(finalPtr, newPtr.getElementType(), finalAlignment);
}
-namespace {
-/// From traditional LLVM, useful info for LLVM lowering support:
-/// A cleanup to call __cxa_end_catch. In many cases, the caught
-/// exception type lets us state definitively that the thrown exception
-/// type does not have a destructor. In particular:
-/// - Catch-alls tell us nothing, so we have to conservatively
-/// assume that the thrown exception might have a destructor.
-/// - Catches by reference behave according to their base types.
-/// - Catches of non-record types will only trigger for exceptions
-/// of non-record types, which never have destructors.
-/// - Catches of record types can trigger for arbitrary subclasses
-/// of the caught type, so we have to assume the actual thrown
-/// exception type might have a throwing destructor, even if the
-/// caught type's destructor is trivial or nothrow.
-struct CallEndCatch final : EHScopeStack::Cleanup {
- CallEndCatch(bool mightThrow, mlir::Value catchToken)
- : mightThrow(mightThrow), catchToken(catchToken) {}
- bool mightThrow;
- mlir::Value catchToken;
-
- void emit(CIRGenFunction &cgf, Flags flags) override {
- // Traditional LLVM codegen would emit a call to __cxa_end_catch
- // here. For CIR, just let it pass since the cleanup is going
- // to be emitted on a later pass when lowering the catch region.
- // CGF.EmitRuntimeCallOrTryCall(getEndCatchFn(CGF.CGM));
- cir::EndCatchOp::create(cgf.getBuilder(), *cgf.currSrcLoc, catchToken);
- cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
- }
-};
-} // namespace
-
-static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken,
- mlir::Type exnPtrTy, bool endMightThrow) {
- auto catchTokenTy = cir::CatchTokenType::get(cgf.getBuilder().getContext());
- auto beginCatch = cir::BeginCatchOp::create(cgf.getBuilder(),
- cgf.getBuilder().getUnknownLoc(),
- catchTokenTy, exnPtrTy, ehToken);
-
- cgf.ehStack.pushCleanup<CallEndCatch>(
- NormalAndEHCleanup,
- endMightThrow && !cgf.cgm.getLangOpts().AssumeNothrowExceptionDtor,
- beginCatch.getCatchToken());
-
- return beginCatch.getExnPtr();
-}
-
-/// A "special initializer" callback for initializing a catch
-/// parameter during catch initialization.
-static void initCatchParam(CIRGenFunction &cgf, mlir::Value ehToken,
- const VarDecl &catchParam, Address paramAddr,
- SourceLocation loc) {
- CanQualType catchType =
- cgf.cgm.getASTContext().getCanonicalType(catchParam.getType());
- mlir::Type cirCatchTy = cgf.convertTypeForMem(catchType);
-
- // If we're catching by reference, we can just cast the object
- // pointer to the appropriate pointer.
- if (isa<ReferenceType>(catchType)) {
- QualType caughtType = cast<ReferenceType>(catchType)->getPointeeType();
- bool endCatchMightThrow = caughtType->isRecordType();
-
- mlir::Value adjustedExn =
- callBeginCatch(cgf, ehToken, cirCatchTy, endCatchMightThrow);
-
- // We have no way to tell the personality function that we're
- // catching by reference, so if we're catching a pointer,
- // __cxa_begin_catch will actually return that pointer by value.
- if (const PointerType *pt = dyn_cast<PointerType>(caughtType)) {
- QualType pointeeType = pt->getPointeeType();
- // When catching by reference, generally we should just ignore
- // this by-value pointer and use the exception object instead.
- if (!pointeeType->isRecordType()) {
- cgf.cgm.errorNYI(loc,
- "initCatchParam: catching a pointer of non-record");
- } else {
- // Pull the pointer for the reference type off.
- mlir::Type ptrTy = cgf.convertTypeForMem(caughtType);
-
- // Create the temporary and write the adjusted pointer into it.
- Address exnPtrTmp = cgf.createTempAlloca(
- ptrTy, cgf.getPointerAlign(), cgf.getLoc(loc), "exn.byref.tmp");
- mlir::Value casted = cgf.getBuilder().createBitcast(adjustedExn, ptrTy);
- cgf.getBuilder().createStore(cgf.getLoc(loc), casted, exnPtrTmp);
-
- // Bind the reference to the temporary.
- adjustedExn = exnPtrTmp.emitRawPointer();
- }
- }
-
- mlir::Value exnCast =
- cgf.getBuilder().createBitcast(adjustedExn, cirCatchTy);
- cgf.getBuilder().createStore(cgf.getLoc(loc), exnCast, paramAddr);
- return;
- }
-
- // Scalars and complexes.
- cir::TypeEvaluationKind tek = cgf.getEvaluationKind(catchType);
- if (tek != cir::TEK_Aggregate) {
- // Notes for LLVM lowering:
- // If the catch type is a pointer type, __cxa_begin_catch returns
- // the pointer by value.
- if (catchType->hasPointerRepresentation()) {
- mlir::Value catchParam =
- callBeginCatch(cgf, ehToken, cirCatchTy, /*endMightThrow=*/false);
- switch (catchType.getQualifiers().getObjCLifetime()) {
- case Qualifiers::OCL_Strong:
- cgf.cgm.errorNYI(loc,
- "initCatchParam: PointerRepresentation OCL_Strong");
- return;
-
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- cgf.cgm.errorNYI(loc, "initCatchParam: PointerRepresentation "
- "OCL_ExplicitNone & OCL_Autoreleasing");
- return;
-
- case Qualifiers::OCL_None:
- cgf.getBuilder().createStore(cgf.getLoc(loc), catchParam, paramAddr);
- return;
-
- case Qualifiers::OCL_Weak:
- cgf.cgm.errorNYI(loc, "initCatchParam: PointerRepresentation OCL_Weak");
- return;
- }
-
- llvm_unreachable("bad ownership qualifier!");
- }
-
- // Otherwise, it returns a pointer into the exception object.
- mlir::Type cirCatchTy = cgf.convertTypeForMem(catchType);
- mlir::Value catchParam =
- callBeginCatch(cgf, ehToken, cgf.getBuilder().getPointerTo(cirCatchTy),
- /*endMightThrow=*/false);
- LValue srcLV = cgf.makeNaturalAlignAddrLValue(catchParam, catchType);
- LValue destLV = cgf.makeAddrLValue(paramAddr, catchType);
- switch (tek) {
- case cir::TEK_Complex: {
- mlir::Value load = cgf.emitLoadOfComplex(srcLV, loc);
- cgf.emitStoreOfComplex(cgf.getLoc(loc), load, destLV, /*isInit=*/true);
- return;
- }
- case cir::TEK_Scalar: {
- mlir::Value exnLoad = cgf.emitLoadOfScalar(srcLV, loc);
- cgf.emitStoreOfScalar(exnLoad, destLV, /*isInit=*/true);
- return;
- }
- case cir::TEK_Aggregate:
- llvm_unreachable("evaluation kind filtered out!");
- }
-
- llvm_unreachable("bad evaluation kind");
- }
-
- assert(isa<RecordType>(catchType) && "unexpected catch type!");
- auto *catchRD = catchType->getAsCXXRecordDecl();
- CharUnits caughtExnAlignment = cgf.cgm.getClassPointerAlignment(catchRD);
-
- // Check for a copy expression. If we don't have a copy expression,
- // that means a trivial copy is okay.
- const Expr *copyExpr = catchParam.getInit();
- if (!copyExpr) {
- mlir::Type cirCatchPtrTy = cgf.getBuilder().getPointerTo(cirCatchTy);
- mlir::Value rawAdjustedExn =
- callBeginCatch(cgf, ehToken, cirCatchPtrTy, /*endMightThrow=*/true);
- Address adjustedExn(rawAdjustedExn, cirCatchTy, caughtExnAlignment);
- LValue dest = cgf.makeAddrLValue(paramAddr, catchType);
- LValue src = cgf.makeAddrLValue(adjustedExn, catchType);
- cgf.emitAggregateCopy(dest, src, catchType, AggValueSlot::DoesNotOverlap);
- return;
- }
-
- cgf.cgm.errorNYI(loc, "initCatchParam: cir::TEK_Aggregate non-trivial copy");
-}
-
-/// Begins a catch statement by initializing the catch variable and
-/// calling __cxa_begin_catch.
-void CIRGenItaniumCXXABI::emitBeginCatch(CIRGenFunction &cgf,
- const CXXCatchStmt *catchStmt,
- mlir::Value ehToken) {
- // We have to be very careful with the ordering of cleanups here:
- // C++ [except.throw]p4:
- // The destruction [of the exception temporary] occurs
- // immediately after the destruction of the object declared in
- // the exception-declaration in the handler.
- //
- // So the precise ordering is:
- // 1. Construct catch variable.
- // 2. __cxa_begin_catch
- // 3. Enter __cxa_end_catch cleanup
- // 4. Enter dtor cleanup
- //
- // We do this by using a slightly abnormal initialization process.
- // Delegation sequence:
- // - ExitCXXTryStmt opens a RunCleanupsScope
- // - EmitAutoVarAlloca creates the variable and debug info
- // - InitCatchParam initializes the variable from the exception
- // - CallBeginCatch calls __cxa_begin_catch
- // - CallBeginCatch enters the __cxa_end_catch cleanup
- // - EmitAutoVarCleanups enters the variable destructor cleanup
- // - EmitCXXTryStmt emits the code for the catch body
- // - EmitCXXTryStmt close the RunCleanupsScope
-
- VarDecl *catchParam = catchStmt->getExceptionDecl();
- if (!catchParam) {
- callBeginCatch(cgf, ehToken, cgf.getBuilder().getVoidPtrTy(),
- /*endMightThrow=*/true);
- return;
- }
-
- auto getCatchParamAllocaIP = [&]() {
- cir::CIRBaseBuilderTy::InsertPoint currIns =
- cgf.getBuilder().saveInsertionPoint();
- mlir::Operation *currParent = currIns.getBlock()->getParentOp();
-
- mlir::Block *insertBlock = nullptr;
- if (auto scopeOp = currParent->getParentOfType<cir::ScopeOp>()) {
- insertBlock = &scopeOp.getScopeRegion().getBlocks().back();
- } else if (auto fnOp = currParent->getParentOfType<cir::FuncOp>()) {
- insertBlock = &fnOp.getRegion().getBlocks().back();
- } else {
- llvm_unreachable("unknown outermost scope-like parent");
- }
- return cgf.getBuilder().getBestAllocaInsertPoint(insertBlock);
- };
-
- // Emit the local. Make sure the alloca's superseed the current scope, since
- // these are going to be consumed by `cir.catch`, which is not within the
- // current scope.
-
- CIRGenFunction::AutoVarEmission var =
- cgf.emitAutoVarAlloca(*catchParam, getCatchParamAllocaIP());
- initCatchParam(cgf, ehToken, *catchParam, var.getObjectAddress(cgf),
- catchStmt->getBeginLoc());
- cgf.emitAutoVarCleanups(var);
-}
-
bool CIRGenItaniumCXXABI::hasAnyUnusedVirtualInlineFunction(
const CXXRecordDecl *rd) const {
const auto &vtableLayout = cgm.getItaniumVTableContext().getVTableLayout(rd);
diff --git a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
index abdc32951f857..e9b11595163b5 100644
--- a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
@@ -281,6 +281,47 @@ mlir::LogicalResult ItaniumEHLowering::lowerFunc(cir::FuncOp funcOp) {
return mlir::success();
}
+static mlir::Value initCatchParam(mlir::OpBuilder &builder,
+ cir::BeginCatchOp op,
+ mlir::Value beginCatchCall) {
+ mlir::Value result = beginCatchCall;
+ mlir::Type expectedPtrType = op.getExnPtr().getType();
+
+ auto exceptionType =
+ mlir::cast<cir::PointerType>(expectedPtrType).getPointee();
+
+ if (auto exnPointeeType = mlir::dyn_cast<cir::PointerType>(exceptionType)) {
+ if (auto exnPointeePtrType =
+ mlir::dyn_cast<cir::PointerType>(exnPointeeType.getPointee())) {
+ if (mlir::isa<cir::RecordType>(exnPointeePtrType.getPointee())) {
+ auto parentFunc = op->getParentOfType<cir::FuncOp>();
+ mlir::Block *entryBlock = &parentFunc.getRegion().front();
+
+ mlir::Value exnPtrTmp;
+ {
+ mlir::OpBuilder::InsertionGuard guard(builder);
+ builder.setInsertionPointToStart(entryBlock);
+ exnPtrTmp = cir::AllocaOp::create(
+ builder, op->getLoc(), expectedPtrType, exceptionType,
+ "exn.byref.tmp", builder.getI64IntegerAttr(8));
+ }
+
+ result = cir::CastOp::create(builder, op.getLoc(), exceptionType,
+ cir::CastKind::bitcast, result);
+
+ cir::StoreOp::create(builder, op.getLoc(), result, exnPtrTmp, {}, {},
+ {}, {});
+ result = exnPtrTmp;
+ }
+ }
+ }
+
+ return result.getType() == expectedPtrType
+ ? result
+ : cir::CastOp::create(builder, op->getLoc(), expectedPtrType,
+ cir::CastKind::bitcast, result);
+}
+
/// Lower all EH operations connected to a single cir.eh.initiate.
///
/// The cir.eh.initiate is the root of a token graph. The token it produces
@@ -394,13 +435,8 @@ void ItaniumEHLowering::lowerEhInitiate(
auto callOp = cir::CallOp::create(
builder, op.getLoc(), mlir::FlatSymbolRefAttr::get(beginCatchFunc),
u8PtrType, mlir::ValueRange{exnPtr});
- mlir::Value castResult = callOp.getResult();
- mlir::Type expectedPtrType = op.getExnPtr().getType();
- if (castResult.getType() != expectedPtrType)
- castResult =
- cir::CastOp::create(builder, op.getLoc(), expectedPtrType,
- cir::CastKind::bitcast, callOp.getResult());
- op.getExnPtr().replaceAllUsesWith(castResult);
+ mlir::Value result = initCatchParam(builder, op, callOp.getResult());
+ op.getExnPtr().replaceAllUsesWith(result);
op.erase();
} else if (auto op = mlir::dyn_cast<cir::EhDispatchOp>(user)) {
// Read catch types from the dispatch and set them on the inflight op.
diff --git a/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp b/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp
index 3827275bfc1be..5e1cc064e5ea5 100644
--- a/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp
+++ b/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp
@@ -149,7 +149,6 @@ void test_catch_all_and_specific_with_cleanup() {
// CIR-LABEL: cir.func {{.*}} @_Z40test_catch_all_and_specific_with_cleanupv()
// CIR: cir.scope {
// CIR: %[[S:.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s", init]
-// CIR: %[[E:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e"]
// CIR: cir.try {
// CIR: cir.call @_ZN1SC1Ev(%[[S]])
// CIR: cir.cleanup.scope {
@@ -163,8 +162,6 @@ void test_catch_all_and_specific_with_cleanup() {
// CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] (%{{.*}}: !cir.eh_token {{.*}}) {
// CIR: %{{.*}}, %[[EXN:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
// CIR: cir.cleanup.scope {
-// CIR: cir.load{{.*}} %[[EXN]] : !cir.ptr<!s32i>, !s32i
-// CIR: cir.store{{.*}} %{{.*}}, %[[E]] : !s32i, !cir.ptr<!s32i>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %{{.*}} : !cir.catch_token
@@ -186,7 +183,6 @@ void test_catch_all_and_specific_with_cleanup() {
// CIR-FLAT-LABEL: cir.func {{.*}} @_Z40test_catch_all_and_specific_with_cleanupv()
//
// CIR-FLAT: %[[S:.*]] = cir.alloca !rec_S
-// CIR-FLAT: %[[E:.*]] = cir.alloca !s32i
//
// Ctor may throw; unwinds directly to the dispatch (no cleanup needed yet).
// CIR-FLAT: cir.try_call @_ZN1SC1Ev(%[[S]]) ^[[AFTER_CTOR:bb[0-9]+]], ^[[CTOR_UNWIND:bb[0-9]+]]
@@ -227,8 +223,6 @@ void test_catch_all_and_specific_with_cleanup() {
// Catch (int): bind e, end_catch, merge to return.
// CIR-FLAT: ^[[CATCH_INT]](%{{.*}}: !cir.eh_token):
// CIR-FLAT: %{{.*}}, %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
-// CIR-FLAT: cir.load{{.*}} %[[EXN_PTR]] : !cir.ptr<!s32i>, !s32i
-// CIR-FLAT: cir.store{{.*}} %{{.*}}, %[[E]] : !s32i, !cir.ptr<!s32i>
// CIR-FLAT: cir.end_catch %{{.*}} : !cir.catch_token
// CIR-FLAT: cir.br ^{{.*}}
//
@@ -248,7 +242,6 @@ void test_catch_all_and_specific_with_cleanup() {
// LLVM-LABEL: define {{.*}} void @_Z40test_catch_all_and_specific_with_cleanupv()
// LLVM-SAME: personality ptr @__gxx_personality_v0
// LLVM: %[[S:.*]] = alloca %struct.S
-// LLVM: %[[E:.*]] = alloca i32
// LLVM: invoke void @_ZN1SC1Ev({{.*}}%[[S]])
// LLVM: to label %[[AFTER_CTOR:.*]] unwind label %[[CTOR_LP:.*]]
// LLVM: [[AFTER_CTOR]]:
@@ -269,8 +262,6 @@ void test_catch_all_and_specific_with_cleanup() {
// LLVM: icmp eq i32 {{.*}}, {{.*}}
// LLVM: {{.*}}:
// LLVM: call ptr @__cxa_begin_catch
-// LLVM: load i32, ptr {{.*}}
-// LLVM: store i32 {{.*}}, ptr %[[E]]
// LLVM: call void @__cxa_end_catch()
// LLVM: {{.*}}:
// LLVM: call ptr @__cxa_begin_catch
diff --git a/clang/test/CIR/CodeGen/try-catch.cpp b/clang/test/CIR/CodeGen/try-catch.cpp
index 7f50c7ca6ec28..d90f90619520e 100644
--- a/clang/test/CIR/CodeGen/try-catch.cpp
+++ b/clang/test/CIR/CodeGen/try-catch.cpp
@@ -127,6 +127,7 @@ void try_catch_with_alloca() {
}
}
+// CIR: cir.func {{.*}} @_Z21try_catch_with_allocav() personality(@__gxx_personality_v0)
// CIR: cir.scope {
// CIR: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a"]
// CIR: %[[B_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b"]
@@ -213,7 +214,7 @@ void call_function_inside_try_catch_all() {
// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
// CIR: cir.yield
-// CIR: } cleanup {{.*}} {
+// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
// CIR: cir.yield
// CIR: }
@@ -291,17 +292,14 @@ void call_function_inside_try_catch_with_exception_type() {
// CIR: cir.func {{.*}} @_Z50call_function_inside_try_catch_with_exception_typev() personality(@__gxx_personality_v0)
// CIR: cir.scope {
-// CIR: %[[EXCEPTION_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e"]
// CIR: cir.try {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv()
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] (%[[EH_TOKEN:.*]]: !cir.eh_token{{.*}}) {
// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
// CIR: cir.cleanup.scope {
-// CIR: %[[TMP:.*]] = cir.load {{.*}} %[[EXN_PTR]] : !cir.ptr<!s32i>, !s32i
-// CIR: cir.store {{.*}} %[[TMP]], %[[EXCEPTION_ADDR]] : !s32i, !cir.ptr<!s32i>
// CIR: cir.yield
-// CIR: } cleanup {{.*}} {
+// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
// CIR: cir.yield
// CIR: }
@@ -342,8 +340,6 @@ void call_function_inside_try_catch_with_exception_type() {
// LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
// LLVM: br label %[[CATCH_BODY:.*]]
// LLVM: [[CATCH_BODY]]:
-// LLVM: %[[LOAD:.*]] = load i32, ptr %[[TOKEN]], align 4
-// LLVM: store i32 %[[LOAD]], ptr {{.*}}, align 4
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
@@ -409,14 +405,12 @@ void call_function_inside_try_catch_with_ref_exception_type() {
// CIR: cir.func {{.*}} @_Z54call_function_inside_try_catch_with_ref_exception_typev() personality(@__gxx_personality_v0)
// CIR: cir.scope {
-// CIR: %[[EXCEPTION_ADDR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["ref", const]
// CIR: cir.try {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv()
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] (%{{.*}}: !cir.eh_token {{.*}}) {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.ptr<!s32i>>)
// CIR: cir.cleanup.scope {
-// CIR: cir.store {{.*}} %[[EXN_PTR]], %[[EXCEPTION_ADDR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -459,7 +453,6 @@ void call_function_inside_try_catch_with_ref_exception_type() {
// LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
// LLVM: br label %[[CATCH_BODY:.*]]
// LLVM: [[CATCH_BODY]]:
-// LLVM: store ptr %[[TOKEN]], ptr %{{.*}}, align 8
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
@@ -524,17 +517,14 @@ void call_function_inside_try_catch_with_complex_exception_type() {
// CIR: cir.func {{.*}} @_Z58call_function_inside_try_catch_with_complex_exception_typev() personality(@__gxx_personality_v0)
// CIR: cir.scope {
-// CIR: %[[EXCEPTION_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["e"]
// CIR: cir.try {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv()
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTICi> : !cir.ptr<!u8i>] (%[[EH_TOKEN:.*]]: !cir.eh_token{{.*}}) {
// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.complex<!s32i>>)
// CIR: cir.cleanup.scope {
-// CIR: %[[TMP:.*]] = cir.load {{.*}} %[[EXN_PTR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
-// CIR: cir.store {{.*}} %[[TMP]], %[[EXCEPTION_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
// CIR: cir.yield
-// CIR: } cleanup {{.*}} {
+// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
// CIR: cir.yield
// CIR: }
@@ -575,8 +565,6 @@ void call_function_inside_try_catch_with_complex_exception_type() {
// LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
// LLVM: br label %[[CATCH_BODY:.*]]
// LLVM: [[CATCH_BODY]]:
-// LLVM: %[[LOAD:.*]] = load { i32, i32 }, ptr %[[TOKEN]], align 4
-// LLVM: store { i32, i32 } %[[LOAD]], ptr {{.*}}, align 4
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
@@ -648,16 +636,14 @@ void call_function_inside_try_catch_with_array_exception_type() {
// CIR: cir.func {{.*}} @_Z56call_function_inside_try_catch_with_array_exception_typev() personality(@__gxx_personality_v0)
// CIR: cir.scope {
-// CIR: %[[E_ADDR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["e"]
// CIR: cir.try {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv()
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIPi> : !cir.ptr<!u8i>] (%[[EH_TOKEN:.*]]: !cir.eh_token{{.*}}) {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.ptr<!s32i>>)
// CIR: cir.cleanup.scope {
-// CIR: cir.store {{.*}} %[[EXN_PTR]], %[[E_ADDR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
// CIR: cir.yield
-// CIR: } cleanup {{.*}} {
+// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
// CIR: cir.yield
// CIR: }
@@ -698,7 +684,6 @@ void call_function_inside_try_catch_with_array_exception_type() {
// LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
// LLVM: br label %[[CATCH_BODY:.*]]
// LLVM: [[CATCH_BODY]]:
-// LLVM: store ptr %[[TOKEN]], ptr {{.*}}, align 8
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
@@ -764,17 +749,14 @@ void call_function_inside_try_catch_with_exception_type_and_catch_all() {
// CIR: cir.func {{.*}} @_Z64call_function_inside_try_catch_with_exception_type_and_catch_allv() personality(@__gxx_personality_v0)
// CIR: cir.scope {
-// CIR: %[[EXCEPTION_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e"]
// CIR: cir.try {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv()
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] (%[[EH_TOKEN:.*]]: !cir.eh_token{{.*}}) {
// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
// CIR: cir.cleanup.scope {
-// CIR: %[[TMP:.*]] = cir.load {{.*}} %[[EXN_PTR]] : !cir.ptr<!s32i>, !s32i
-// CIR: cir.store {{.*}} %[[TMP]], %[[EXCEPTION_ADDR]] : !s32i, !cir.ptr<!s32i>
// CIR: cir.yield
-// CIR: } cleanup {{.*}} {
+// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
// CIR: cir.yield
// CIR: }
@@ -783,7 +765,7 @@ void call_function_inside_try_catch_with_exception_type_and_catch_all() {
// CIR: %[[CATCH_TOKEN2:.*]], %{{.*}} = cir.begin_catch %[[EH_TOKEN2]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
// CIR: cir.yield
-// CIR: } cleanup {{.*}} {
+// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN2]] : !cir.catch_token
// CIR: cir.yield
// CIR: }
@@ -822,8 +804,6 @@ void call_function_inside_try_catch_with_exception_type_and_catch_all() {
// LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
// LLVM: br label %[[CATCH_BODY:.*]]
// LLVM: [[CATCH_BODY]]:
-// LLVM: %[[LOAD:.*]] = load i32, ptr %[[TOKEN]], align 4
-// LLVM: store i32 %[[LOAD]], ptr {{.*}}, align 4
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
@@ -1011,14 +991,12 @@ void call_function_inside_try_catch_with_aggregate_exception_type() {
// CIR: cir.func {{.*}} @_Z60call_function_inside_try_catch_with_aggregate_exception_typev(){{.*}} personality(@__gxx_personality_v0){{.*}} {
// CIR: cir.scope {
-// CIR: %[[E_ADDR:.*]] = cir.alloca !rec_CustomError, !cir.ptr<!rec_CustomError>, ["e"]
// CIR: cir.try {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef})
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTI11CustomError> : !cir.ptr<!u8i>] (%{{.*}}: !cir.eh_token {{.*}}) {
// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!rec_CustomError>)
// CIR: cir.cleanup.scope {
-// CIR: cir.copy %[[EXN_PTR]] to %[[E_ADDR]] : !cir.ptr<!rec_CustomError>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -1061,7 +1039,6 @@ void call_function_inside_try_catch_with_aggregate_exception_type() {
// LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
// LLVM: br label %[[CATCH_BODY:.*]]
// LLVM: [[CATCH_BODY]]:
-// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %{{.*}}, ptr %[[TOKEN]], i64 4, i1 false)
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
@@ -1136,11 +1113,8 @@ void call_function_inside_try_catch_with_ref_ptr_of_record_exception_type() {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef})
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIP6Record> : !cir.ptr<!u8i>] (%[[EH_TOKEN:.*]]: !cir.eh_token {{.*}}) {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.ptr<!rec_Record>>)
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>>)
// CIR: cir.cleanup.scope {
-// CIR: %[[EXN_PTR_REC_PTR:.*]] = cir.cast bitcast %[[EXN_PTR]] : !cir.ptr<!cir.ptr<!rec_Record>> -> !cir.ptr<!rec_Record>
-// CIR: cir.store {{.*}} %[[EXN_PTR_REC_PTR]], %[[EXN_BYREF_TMP]] : !cir.ptr<!rec_Record>, !cir.ptr<!cir.ptr<!rec_Record>>
-// CIR: cir.store {{.*}} %[[EXN_BYREF_TMP]], %[[E_ADDR]] : !cir.ptr<!cir.ptr<!rec_Record>>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -1153,8 +1127,6 @@ void call_function_inside_try_catch_with_ref_ptr_of_record_exception_type() {
// CIR: }
// LLVM: define {{.*}} void @_Z68call_function_inside_try_catch_with_ref_ptr_of_record_exception_typev() {{.*}} personality ptr @__gxx_personality_v0
-// LLVM: %[[E_ADDR:.*]] = alloca ptr
-// LLVM: %[[EXN_BYREF_TMP:.*]] = alloca ptr
// LLVM: br label %[[TRY_SCOPE:.*]]
// LLVM: [[TRY_SCOPE]]:
// LLVM: br label %[[TRY_BEGIN:.*]]
@@ -1185,8 +1157,6 @@ void call_function_inside_try_catch_with_ref_ptr_of_record_exception_type() {
// LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
// LLVM: br label %[[CATCH_BODY:.*]]
// LLVM: [[CATCH_BODY]]:
-// LLVM: store ptr %[[TOKEN]], ptr %[[EXN_BYREF_TMP]], align 8
-// LLVM: store ptr %[[EXN_BYREF_TMP]], ptr %[[E_ADDR]], align 8
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
@@ -1253,15 +1223,12 @@ void call_function_inside_try_catch_with_exception_member_ptr_type() {
// CIR: cir.func {{.*}} @_Z61call_function_inside_try_catch_with_exception_member_ptr_typev(){{.*}} personality(@__gxx_personality_v0){{.*}} {
// CIR: cir.scope {
-// CIR: %[[E_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["memberPtr"]
// CIR: cir.try {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef})
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIM6Recordi> : !cir.ptr<!u8i>] (%{{.*}}: !cir.eh_token {{.*}} {
// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s64i>)
// CIR: cir.cleanup.scope {
-// CIR: %[[TMP:.*]] = cir.load {{.*}} %[[EXN_PTR]] : !cir.ptr<!s64i>, !s64i
-// CIR: cir.store {{.*}} %[[TMP]], %[[E_ADDR]] : !s64i, !cir.ptr<!s64i>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -1293,8 +1260,8 @@ void call_function_inside_try_catch_with_exception_member_ptr_type() {
// LLVM: %[[EH_SELECTOR_PHI:.*]] = phi i32 [ %[[EH_SELECTOR_VAL:.*]], %[[LANDING_PAD:.*]] ]
// LLVM: br label %[[DISPATCH:.*]]
// LLVM: [[DISPATCH]]:
-// LLVM: %[[EXN_OBJ_PHI1:.*]] = phi ptr [ %[[EXN_OBJ_PHI:.*]], %[[CATCH:.*]] ]
-// LLVM: %[[EH_SELECTOR_PHI1:.*]] = phi i32 [ %[[EH_SELECTOR_PHI:.*]], %[[CATCH:.*]] ]
+// LLVM: %[[EXN_OBJ_PHI1:.*]] = phi ptr [ %[[EXN_OBJ_PHI:.*]], %[[CATCH]] ]
+// LLVM: %[[EH_SELECTOR_PHI1:.*]] = phi i32 [ %[[EH_SELECTOR_PHI:.*]], %[[CATCH]] ]
// LLVM: %[[EH_TYPE_ID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIM6Recordi)
// LLVM: %[[TYPE_ID_EQ:.*]] = icmp eq i32 %[[EH_SELECTOR_PHI1]], %[[EH_TYPE_ID]]
// LLVM: br i1 %[[TYPE_ID_EQ]], label %[[BEGIN_CATCH:.*]], label %[[RESUME:.*]]
@@ -1304,8 +1271,6 @@ void call_function_inside_try_catch_with_exception_member_ptr_type() {
// LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
// LLVM: br label %[[CATCH_BODY:.*]]
// LLVM: [[CATCH_BODY]]:
-// LLVM: %[[LOAD:.*]] = load i64, ptr %[[TOKEN]], align 8
-// LLVM: store i64 %[[LOAD]], ptr {{.*}}, align 8
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
@@ -1362,3 +1327,276 @@ void call_function_inside_try_catch_with_exception_member_ptr_type() {
// OGCG: %[[EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } %[[TMP_EXCEPTION_INFO]], i32 %[[TMP_EH_TYPE_ID]], 1
// OGCG: resume { ptr, i32 } %[[EXCEPTION_INFO]]
+int init_catch_param_with_type_int() {
+ int rv = 0;
+ try {
+ division();
+ } catch (int x) {
+ rv = x;
+ }
+ return rv;
+}
+
+// CIR: cir.func {{.*}} @_Z30init_catch_param_with_type_intv() {{.*}} personality(@__gxx_personality_v0)
+// CIR: %[[RET_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
+// CIR: %[[RV_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["rv", init]
+// CIR: cir.scope {
+// CIR: cir.try {
+// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef})
+// CIR: cir.yield
+// CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] (%{{.*}}: !cir.eh_token {{.*}}) {
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+// CIR: cir.cleanup.scope {
+// CIR: %[[TMP_EXN:.*]] = cir.load {{.*}} %[[EXN_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.store {{.*}} %[[TMP_EXN]], %[[RV_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.yield
+// CIR: } cleanup all {
+// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
+// CIR: cir.yield
+// CIR: }
+// CIR: cir.yield
+// CIR: } unwind (%{{.*}}: !cir.eh_token {{.*}}) {
+// CIR: cir.resume %{{.*}} : !cir.eh_token
+// CIR: }
+// CIR: }
+// CIR: %[[TMP_RV:.*]] = cir.load {{.*}} %[[RV_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.store %[[TMP_RV]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.return %[[TMP_RET]] : !s32i
+
+// LLVM: define {{.*}} i32 @_Z30init_catch_param_with_type_intv() {{.*}} personality ptr @__gxx_personality_v0
+// LLVM: %[[RET_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM: %[[RV_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM: br label %[[TRY_SCOPE:.*]]
+// LLVM: [[TRY_SCOPE]]:
+// LLVM: br label %[[TRY_BEGIN:.*]]
+// LLVM: [[TRY_BEGIN]]:
+// LLVM: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
+// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[LANDING_PAD:.*]]
+// LLVM: [[INVOKE_CONT]]:
+// LLVM: br label %[[TRY_CONT:.*]]
+// LLVM: [[LANDING_PAD]]:
+// LLVM: %[[LP:.*]] = landingpad { ptr, i32 }
+// LLVM: catch ptr @_ZTIi
+// LLVM: %[[EXN_OBJ:.*]] = extractvalue { ptr, i32 } %[[LP]], 0
+// LLVM: %[[EH_SELECTOR_VAL:.*]] = extractvalue { ptr, i32 } %[[LP]], 1
+// LLVM: br label %[[CATCH:.*]]
+// LLVM: [[CATCH]]:
+// LLVM: %[[EXN_OBJ_PHI:.*]] = phi ptr [ %[[EXN_OBJ:.*]], %[[LANDING_PAD:.*]] ]
+// LLVM: %[[EH_SELECTOR_PHI:.*]] = phi i32 [ %[[EH_SELECTOR_VAL:.*]], %[[LANDING_PAD:.*]] ]
+// LLVM: br label %[[DISPATCH:.*]]
+// LLVM: [[DISPATCH]]:
+// LLVM: %[[EXN_OBJ_PHI1:.*]] = phi ptr [ %[[EXN_OBJ_PHI:.*]], %[[CATCH:.*]] ]
+// LLVM: %[[EH_SELECTOR_PHI1:.*]] = phi i32 [ %[[EH_SELECTOR_PHI:.*]], %[[CATCH]] ]
+// LLVM: %[[EH_TYPE_ID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi)
+// LLVM: %[[TYPE_ID_EQ:.*]] = icmp eq i32 %[[EH_SELECTOR_PHI1]], %[[EH_TYPE_ID]]
+// LLVM: br i1 %[[TYPE_ID_EQ]], label %[[BEGIN_CATCH:.*]], label %[[RESUME:.*]]
+// LLVM: [[BEGIN_CATCH]]:
+// LLVM: %[[EXN_OBJ_PHI2:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
+// LLVM: %[[EH_SELECTOR_PHI2:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
+// LLVM: %[[EXN_PTR:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
+// LLVM: br label %[[CATCH_BODY:.*]]
+// LLVM: [[CATCH_BODY]]:
+// LLVM: %[[TMP_EXN:.*]] = load i32, ptr %[[EXN_PTR]], align 8
+// LLVM: store i32 %[[TMP_EXN]], ptr %[[RV_ADDR]], align 4
+// LLVM: br label %[[END_CATCH:.*]]
+// LLVM: [[END_CATCH]]:
+// LLVM: call void @__cxa_end_catch()
+// LLVM: br label %[[END_DISPATCH:.*]]
+// LLVM: [[END_DISPATCH]]:
+// LLVM: br label %[[END_TRY:.*]]
+// LLVM: [[END_TRY]]:
+// LLVM: br label %[[TRY_CONT:.*]]
+// LLVM: [[RESUME]]:
+// LLVM: %[[EXN_OBJ_PHI3:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
+// LLVM: %[[EH_SELECTOR_PHI3:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
+// LLVM: %[[TMP_EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } poison, ptr %[[EXN_OBJ_PHI3]], 0
+// LLVM: %[[EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } %[[TMP_EXCEPTION_INFO]], i32 %[[EH_SELECTOR_PHI3]], 1
+// LLVM: resume { ptr, i32 } %[[EXCEPTION_INFO]]
+// LLVM: [[TRY_CONT]]:
+// LLVM: br label %[[DONE:.*]]
+// LLVM: [[DONE]]:
+// LLVM: %[[TMP_RV:.*]] = load i32, ptr %[[RV_ADDR]], align 4
+// LLVM: store i32 %[[TMP_RV]], ptr %[[RET_ADDR]], align 4
+// LLVM: %[[TMP_RET:.*]] = load i32, ptr %[[RET_ADDR]], align 4
+// LLVM: ret i32 %[[TMP_RET]]
+
+// OGCG: define {{.*}} i32 @_Z30init_catch_param_with_type_intv() {{.*}} personality ptr @__gxx_personality_v0
+// OGCG: %[[RV_ADDR:.*]] = alloca i32, align 4
+// OGCG: %[[EXCEPTION_ADDR:.*]] = alloca ptr, align 8
+// OGCG: %[[EH_TYPE_ID_ADDR:.*]] = alloca i32, align 4
+// OGCG: %[[X_ADDR:.*]] = alloca i32, align 4
+// OGCG: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
+// OGCG: to label %[[INVOKE_NORMAL:.*]] unwind label %[[INVOKE_UNWIND:.*]]
+// OGCG: [[INVOKE_NORMAL]]:
+// OGCG: br label %[[TRY_CONT:.*]]
+// OGCG: [[INVOKE_UNWIND]]:
+// OGCG: %[[LANDING_PAD:.*]] = landingpad { ptr, i32 }
+// OGCG: catch ptr @_ZTIi
+// OGCG: %[[EXCEPTION:.*]] = extractvalue { ptr, i32 } %[[LANDING_PAD]], 0
+// OGCG: store ptr %[[EXCEPTION]], ptr %[[EXCEPTION_ADDR]], align 8
+// OGCG: %[[EH_TYPE_ID:.*]] = extractvalue { ptr, i32 } %[[LANDING_PAD]], 1
+// OGCG: store i32 %[[EH_TYPE_ID]], ptr %[[EH_TYPE_ID_ADDR]], align 4
+// OGCG: br label %[[CATCH_DISPATCH]]
+// OGCG: [[CATCH_DISPATCH]]:
+// OGCG: %[[TMP_EH_TYPE_ID:.*]] = load i32, ptr %[[EH_TYPE_ID_ADDR]], align 4
+// OGCG: %[[EH_TYPE_ID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi)
+// OGCG: %[[TYPE_ID_EQ:.*]] = icmp eq i32 %[[TMP_EH_TYPE_ID]], %[[EH_TYPE_ID]]
+// OGCG: br i1 %[[TYPE_ID_EQ]], label %[[CATCH_EXCEPTION:.*]], label %[[EH_RESUME:.*]]
+// OGCG: [[CATCH_EXCEPTION]]:
+// OGCG: %[[TMP_EXCEPTION:.*]] = load ptr, ptr %[[EXCEPTION_ADDR]], align 8
+// OGCG: %[[BEGIN_CATCH:.*]] = call ptr @__cxa_begin_catch(ptr %[[TMP_EXCEPTION]])
+// OGCG: %[[TMP_BEGIN_CATCH:.*]] = load i32, ptr %[[BEGIN_CATCH]], align 4
+// OGCG: store i32 %[[TMP_BEGIN_CATCH]], ptr %[[X_ADDR]], align 4
+// OGCG: %[[TMP_X:.*]] = load i32, ptr %[[X_ADDR]], align 4
+// OGCG: store i32 %[[TMP_X]], ptr %[[RV_ADDR]], align 4
+// OGCG: call void @__cxa_end_catch()
+// OGCG: br label %[[TRY_CONT]]
+// OGCG: [[TRY_CONT]]:
+// OGCG: %[[TMP_RV:.*]] = load i32, ptr %[[RV_ADDR]], align 4
+// OGCG: ret i32 %[[TMP_RV]]
+// OGCG: [[EH_RESUME]]:
+// OGCG: %[[TMP_EXCEPTION:.*]] = load ptr, ptr %[[EXCEPTION_ADDR]], align 8
+// OGCG: %[[TMP_EH_TYPE_ID:.*]] = load i32, ptr %[[EH_TYPE_ID_ADDR]], align 4
+// OGCG: %[[TMP_EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } poison, ptr %[[TMP_EXCEPTION]], 0
+// OGCG: %[[EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } %[[TMP_EXCEPTION_INFO]], i32 %[[TMP_EH_TYPE_ID]], 1
+// OGCG: resume { ptr, i32 } %[[EXCEPTION_INFO]]
+
+
+int init_catch_param_with_type_int_ptr() {
+ int rv = 0;
+ try {
+ division();
+ } catch (int *x) {
+ rv = *x;
+ }
+ return rv;
+}
+
+// CIR: cir.func {{.*}} @_Z34init_catch_param_with_type_int_ptrv() {{.*}} personality(@__gxx_personality_v0)
+// CIR: %[[RET_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
+// CIR: %[[RV_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["rv", init]
+// CIR: cir.scope {
+// CIR: cir.try {
+// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef})
+// CIR: cir.yield
+// CIR: } catch [type #cir.global_view<@_ZTIPi> : !cir.ptr<!u8i>] (%{{.*}}: !cir.eh_token {{.*}}) {
+// CIR: %catch_token, %exn_ptr = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.ptr<!s32i>>)
+// CIR: cir.cleanup.scope {
+// CIR: %[[DEREF_EXN_PTR:.*]] = cir.load deref {{.*}} %[[EXN_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+// CIR: %[[EXN_PTR:.*]] = cir.load {{.*}} %[[DEREF_EXN_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.store {{.*}} %[[EXN_PTR]], %[[RV_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.yield
+// CIR: } cleanup all {
+// CIR: cir.end_catch %catch_token : !cir.catch_token
+// CIR: cir.yield
+// CIR: }
+// CIR: cir.yield
+// CIR: } unwind (%{{.*}}: !cir.eh_token {{.*}} {
+// CIR: cir.resume %{{.*}} : !cir.eh_token
+// CIR: }
+// CIR: }
+// CIR: %[[TMP_RV:.*]] = cir.load {{.*}} %[[RV_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.store %[[TMP_RV]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.return %[[TMP_RET]] : !s32i
+
+// LLVM: define {{.*}} i32 @_Z34init_catch_param_with_type_int_ptrv() {{.*}} personality ptr @__gxx_personality_v0
+// LLVM: %[[RET_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM: %[[RV_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM: br label %[[TRY_SCOPE:.*]]
+// LLVM: [[TRY_SCOPE]]:
+// LLVM: br label %[[TRY_BEGIN:.*]]
+// LLVM: [[TRY_BEGIN]]:
+// LLVM: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
+// LLVM: to label %[[INVOKE_CONT:.*]] unwind label %[[LANDING_PAD:.*]]
+// LLVM: [[INVOKE_CONT]]:
+// LLVM: br label %[[TRY_CONT:.*]]
+// LLVM: [[LANDING_PAD]]:
+// LLVM: %[[LP:.*]] = landingpad { ptr, i32 }
+// LLVM: catch ptr @_ZTIPi
+// LLVM: %[[EXN_OBJ:.*]] = extractvalue { ptr, i32 } %[[LP]], 0
+// LLVM: %[[EH_SELECTOR_VAL:.*]] = extractvalue { ptr, i32 } %[[LP]], 1
+// LLVM: br label %[[CATCH:.*]]
+// LLVM: [[CATCH]]:
+// LLVM: %[[EXN_OBJ_PHI:.*]] = phi ptr [ %[[EXN_OBJ:.*]], %[[LANDING_PAD:.*]] ]
+// LLVM: %[[EH_SELECTOR_PHI:.*]] = phi i32 [ %[[EH_SELECTOR_VAL:.*]], %[[LANDING_PAD:.*]] ]
+// LLVM: br label %[[DISPATCH:.*]]
+// LLVM: [[DISPATCH]]:
+// LLVM: %[[EXN_OBJ_PHI1:.*]] = phi ptr [ %[[EXN_OBJ_PHI:.*]], %[[CATCH:.*]] ]
+// LLVM: %[[EH_SELECTOR_PHI1:.*]] = phi i32 [ %[[EH_SELECTOR_PHI:.*]], %[[CATCH]] ]
+// LLVM: %[[EH_TYPE_ID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIPi)
+// LLVM: %[[TYPE_ID_EQ:.*]] = icmp eq i32 %[[EH_SELECTOR_PHI1]], %[[EH_TYPE_ID]]
+// LLVM: br i1 %[[TYPE_ID_EQ]], label %[[BEGIN_CATCH:.*]], label %[[RESUME:.*]]
+// LLVM: [[BEGIN_CATCH]]:
+// LLVM: %[[EXN_OBJ_PHI2:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
+// LLVM: %[[EH_SELECTOR_PHI2:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
+// LLVM: %[[EXN_PTR:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
+// LLVM: br label %[[CATCH_BODY:.*]]
+// LLVM: [[CATCH_BODY]]:
+// LLVM: %[[DEREF_EXN_PTR:.*]] = load ptr, ptr %[[EXN_PTR]], align 8
+// LLVM: %[[TMP_EXN:.*]] = load i32, ptr %[[DEREF_EXN_PTR]], align 4
+// LLVM: store i32 %[[TMP_EXN]], ptr %[[RV_ADDR]], align 4
+// LLVM: br label %[[END_CATCH:.*]]
+// LLVM: [[END_CATCH]]:
+// LLVM: call void @__cxa_end_catch()
+// LLVM: br label %[[END_DISPATCH:.*]]
+// LLVM: [[END_DISPATCH]]:
+// LLVM: br label %[[END_TRY:.*]]
+// LLVM: [[END_TRY]]:
+// LLVM: br label %[[TRY_CONT:.*]]
+// LLVM: [[RESUME]]:
+// LLVM: %[[EXN_OBJ_PHI3:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
+// LLVM: %[[EH_SELECTOR_PHI3:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
+// LLVM: %[[TMP_EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } poison, ptr %[[EXN_OBJ_PHI3]], 0
+// LLVM: %[[EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } %[[TMP_EXCEPTION_INFO]], i32 %[[EH_SELECTOR_PHI3]], 1
+// LLVM: resume { ptr, i32 } %[[EXCEPTION_INFO]]
+// LLVM: [[TRY_CONT]]:
+// LLVM: br label %[[DONE:.*]]
+// LLVM: [[DONE]]:
+// LLVM: %[[TMP_RV:.*]] = load i32, ptr %[[RV_ADDR]], align 4
+// LLVM: store i32 %[[TMP_RV]], ptr %[[RET_ADDR]], align 4
+// LLVM: %[[TMP_RET:.*]] = load i32, ptr %[[RET_ADDR]], align 4
+// LLVM: ret i32 %[[TMP_RET]]
+
+
+// OGCG: define {{.*}} i32 @_Z34init_catch_param_with_type_int_ptrv() {{.*}} personality ptr @__gxx_personality_v0
+// OGCG: %[[RV_ADDR:.*]] = alloca i32, align 4
+// OGCG: %[[EXCEPTION_ADDR:.*]] = alloca ptr, align 8
+// OGCG: %[[EH_TYPE_ID_ADDR:.*]] = alloca i32, align 4
+// OGCG: %[[C_ADDR:.*]] = alloca ptr, align 8
+// OGCG: %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
+// OGCG: to label %[[INVOKE_NORMAL:.*]] unwind label %[[INVOKE_UNWIND:.*]]
+// OGCG: [[INVOKE_NORMAL]]:
+// OGCG: br label %[[TRY_CONT:.*]]
+// OGCG: [[INVOKE_UNWIND]]:
+// OGCG: %[[LANDING_PAD:.*]] = landingpad { ptr, i32 }
+// OGCG: catch ptr @_ZTIPi
+// OGCG: %[[EXCEPTION:.*]] = extractvalue { ptr, i32 } %[[LANDING_PAD]], 0
+// OGCG: store ptr %[[EXCEPTION]], ptr %[[EXCEPTION_ADDR]], align 8
+// OGCG: %[[EH_TYPE_ID:.*]] = extractvalue { ptr, i32 } %[[LANDING_PAD]], 1
+// OGCG: store i32 %[[EH_TYPE_ID]], ptr %[[EH_TYPE_ID_ADDR]], align 4
+// OGCG: br label %[[CATCH_DISPATCH]]
+// OGCG: [[CATCH_DISPATCH]]:
+// OGCG: %[[TMP_EH_TYPE_ID:.*]] = load i32, ptr %[[EH_TYPE_ID_ADDR]], align 4
+// OGCG: %[[EH_TYPE_ID:.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIPi)
+// OGCG: %[[TYPE_ID_EQ:.*]] = icmp eq i32 %[[TMP_EH_TYPE_ID]], %[[EH_TYPE_ID]]
+// OGCG: br i1 %[[TYPE_ID_EQ]], label %[[CATCH_EXCEPTION:.*]], label %[[EH_RESUME:.*]]
+// OGCG: [[CATCH_EXCEPTION]]:
+// OGCG: %[[TMP_EXCEPTION:.*]] = load ptr, ptr %[[EXCEPTION_ADDR]], align 8
+// OGCG: %[[BEGIN_CATCH:.*]] = call ptr @__cxa_begin_catch(ptr %[[TMP_EXCEPTION]])
+// OGCG: store ptr %[[BEGIN_CATCH]], ptr %[[X_ADDR]], align 8
+// OGCG: %[[DEREF_X:.*]] = load ptr, ptr %[[X_ADDR]], align 8
+// OGCG: %[[TMP_X:.*]] = load i32, ptr %[[DEREF_X]], align 4
+// OGCG: store i32 %[[TMP_X]], ptr %[[RV_ADDR]], align 4
+// OGCG: call void @__cxa_end_catch()
+// OGCG: br label %[[TRY_CONT]]
+// OGCG: [[TRY_CONT]]:
+// OGCG: %[[TMP_RV:.*]] = load i32, ptr %[[RV_ADDR]], align 4
+// OGCG: ret i32 %[[TMP_RV]]
+// OGCG: [[EH_RESUME]]:
+// OGCG: %[[TMP_EXCEPTION:.*]] = load ptr, ptr %[[EXCEPTION_ADDR]], align 8
+// OGCG: %[[TMP_EH_TYPE_ID:.*]] = load i32, ptr %[[EH_TYPE_ID_ADDR]], align 4
+// OGCG: %[[TMP_EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } poison, ptr %[[TMP_EXCEPTION]], 0
+// OGCG: %[[EXCEPTION_INFO:.*]] = insertvalue { ptr, i32 } %[[TMP_EXCEPTION_INFO]], i32 %[[TMP_EH_TYPE_ID]], 1
+// OGCG: resume { ptr, i32 } %[[EXCEPTION_INFO]]
>From dc5f4310a18d8cb361a515b367047c1d2ca42730 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Tue, 28 Apr 2026 20:52:47 +0200
Subject: [PATCH 2/5] Add InitCatchParamOp & InitCatchKind
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 53 +++++++
clang/lib/CIR/CodeGen/CIRGenException.cpp | 142 +++++++----------
.../CIR/Dialect/Transforms/EHABILowering.cpp | 147 ++++++++++++------
.../CodeGen/try-catch-all-with-cleanup.cpp | 7 +-
clang/test/CIR/CodeGen/try-catch.cpp | 56 ++++---
5 files changed, 249 insertions(+), 156 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 73012187483e3..74207c93646e4 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -7631,6 +7631,59 @@ def CIR_EndCatchOp : CIR_Op<"end_catch"> {
let hasLLVMLowering = false;
}
+//===----------------------------------------------------------------------===//
+// EH Operations: InitCatchParamOp
+//===----------------------------------------------------------------------===//
+
+def CIR_InitCatchKind : CIR_I32EnumAttr<
+ "InitCatchKind", "", [
+ I32EnumAttrCase<"Reference", 0, "reference">,
+ I32EnumAttrCase<"Pointer", 1, "pointer">,
+ I32EnumAttrCase<"Scalar", 2, "scalar">,
+ I32EnumAttrCase<"Objc", 3, "objc">,
+ I32EnumAttrCase<"TrivilCopy", 4, "trivil_copy">,
+ I32EnumAttrCase<"NonTrivilCopy", 5, "non_trivil_copy">,
+]>;
+
+def CIR_InitCatchParamOp : CIR_Op<"init_catch_param"> {
+ let summary = "Initialize a catch parameter from the exception pointer";
+ let description = [{
+ `cir.init_catch_param` represents copying or otherwise materializing the
+ caught exception object into the local catch parameter variable. It takes
+ the exception pointer returned by `cir.begin_catch` and the address of
+ the alloca created for the catch parameter, and has no result.
+
+ This operation is target-independent. It is replaced during EHABI
+ lowering with the appropriate target/ABI-specific sequence (for example,
+ the Itanium C++ ABI may emit a load and store for scalar/pointer catch
+ types, an aggregate copy for record types, or a call to a copy
+ constructor when one is required).
+
+ Example:
+
+ ```
+ %catch_token, %exn_ptr = cir.begin_catch %eh_token
+ : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+ %param_addr = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
+ cir.init_catch_param %exn_ptr to %param_addr
+ : !cir.ptr<!s32i>, !cir.ptr<!s32i>
+ ```
+ }];
+
+ let arguments = (ins
+ CIR_PointerType:$exn_ptr,
+ CIR_PointerType:$param_addr,
+ CIR_InitCatchKind:$kind
+ );
+
+ let assemblyFormat = [{
+ $kind $exn_ptr `to` $param_addr `:`
+ qualified(type($exn_ptr)) `,` qualified(type($param_addr)) attr-dict
+ }];
+
+ let hasLLVMLowering = false;
+}
+
//===----------------------------------------------------------------------===//
// Atomic operations
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 7dd2a8d59199e..8f8e88d42b89a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -321,94 +321,59 @@ static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken,
/// A "special initializer" callback for initializing a catch
/// parameter during catch initialization.
-static void initCatchParam(CIRGenFunction &cgf, mlir::Value ehToken,
- const VarDecl &catchParam, Address paramAddr,
- SourceLocation loc) {
- CIRGenBuilderTy builder = cgf.getBuilder();
+static void initCatchParam(CIRGenFunction &cgf, CIRGenBuilderTy &builder,
+ mlir::Value ehToken, const VarDecl &catchParam,
+ Address paramAddr, SourceLocation loc) {
CanQualType catchType =
cgf.cgm.getASTContext().getCanonicalType(catchParam.getType());
- mlir::Type cirCatchTy = cgf.convertTypeForMem(catchType);
- mlir::Type exnPtrTy = builder.getPointerTo(cirCatchTy);
- CharUnits caughtExnAlignment = cgf.getPointerAlign();
+ // mlir::Type cirCatchTy = cgf.convertTypeForMem(catchType);
+ // mlir::Type exnPtrTy = builder.getPointerTo(cirCatchTy);
+ // CharUnits caughtExnAlignment = cgf.getPointerAlign();
+ cir::InitCatchKind kind;
+ bool endCatchMightThrow = true;
// If we're catching by reference, we can just cast the object
// pointer to the appropriate pointer.
if (isa<ReferenceType>(catchType)) {
QualType caughtType = cast<ReferenceType>(catchType)->getPointeeType();
- // We have no way to tell the personality function that we're
- // catching by reference, so if we're catching a pointer,
- // __cxa_begin_catch will actually return that pointer by value.
- if (const PointerType *pt = dyn_cast<PointerType>(caughtType)) {
- QualType pointeeType = pt->getPointeeType();
- // When catching by reference, generally we should just ignore
- // this by-value pointer and use the exception object instead.
- if (!pointeeType->isRecordType()) {
- cgf.cgm.errorNYI(loc,
- "initCatchParam: catching a pointer of non-record");
- return;
- }
- }
-
- bool endCatchMightThrow = caughtType->isRecordType();
- mlir::Value exnPtr =
- callBeginCatch(cgf, ehToken, exnPtrTy, endCatchMightThrow);
- Address exnPtrAddr = Address(exnPtr, caughtExnAlignment);
- cgf.setAddrOfLocalVar(&catchParam, exnPtrAddr);
- return;
- }
-
- // Scalars and complexes.
- cir::TypeEvaluationKind tek = cgf.getEvaluationKind(catchType);
- if (tek != cir::TEK_Aggregate) {
- // Notes for LLVM lowering:
- // If the catch type is a pointer type, __cxa_begin_catch returns
- // the pointer by value.
- if (catchType->hasPointerRepresentation()) {
- switch (catchType.getQualifiers().getObjCLifetime()) {
- case Qualifiers::OCL_Strong:
- cgf.cgm.errorNYI(loc,
- "initCatchParam: PointerRepresentation OCL_Strong");
- return;
-
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- cgf.cgm.errorNYI(loc, "initCatchParam: PointerRepresentation "
- "OCL_ExplicitNone & OCL_Autoreleasing");
- return;
-
- case Qualifiers::OCL_None:
- break;
-
- case Qualifiers::OCL_Weak:
- cgf.cgm.errorNYI(loc, "initCatchParam: PointerRepresentation OCL_Weak");
- return;
+ endCatchMightThrow = caughtType->isRecordType();
+ kind = cir::InitCatchKind::Reference;
+ } else {
+ cir::TypeEvaluationKind tek = cgf.getEvaluationKind(catchType);
+ if (tek == cir::TEK_Aggregate) {
+ assert(isa<RecordType>(catchType) && "unexpected catch type!");
+ const Expr *copyExpr = catchParam.getInit();
+ kind = !copyExpr ? cir::InitCatchKind::TrivilCopy
+ : cir::InitCatchKind::NonTrivilCopy;
+ } else {
+ endCatchMightThrow = false;
+
+ // Scalars and complexes.
+ if (catchType->hasPointerRepresentation()) {
+ switch (catchType.getQualifiers().getObjCLifetime()) {
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Strong:
+ kind = cir::InitCatchKind::Objc;
+ break;
+
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ case Qualifiers::OCL_None:
+ kind = cir::InitCatchKind::Pointer;
+ break;
+ }
+ } else {
+ kind = cir::InitCatchKind::Scalar;
}
}
-
- // Otherwise, it returns a pointer into the exception object.
- mlir::Value exnPtr = callBeginCatch(cgf, ehToken, exnPtrTy,
- /*endMightThrow=*/false);
- Address exnPtrAddr = Address(exnPtr, caughtExnAlignment);
- cgf.setAddrOfLocalVar(&catchParam, exnPtrAddr);
- return;
- }
-
- assert(isa<RecordType>(catchType) && "unexpected catch type!");
- auto *catchRD = catchType->getAsCXXRecordDecl();
- caughtExnAlignment = cgf.cgm.getClassPointerAlignment(catchRD);
-
- // Check for a copy expression. If we don't have a copy expression,
- // that means a trivial copy is okay.
- const Expr *copyExpr = catchParam.getInit();
- if (!copyExpr) {
- mlir::Value exnPtr =
- callBeginCatch(cgf, ehToken, exnPtrTy, /*endMightThrow=*/true);
- Address exnPtrAddr = Address(exnPtr, caughtExnAlignment);
- cgf.setAddrOfLocalVar(&catchParam, exnPtrAddr);
- return;
}
- cgf.cgm.errorNYI(loc, "initCatchParam: cir::TEK_Aggregate non-trivial copy");
+ mlir::Value exnPtr =
+ callBeginCatch(cgf, ehToken, builder.getVoidPtrTy(), endCatchMightThrow);
+ CIRGenFunction::AutoVarEmission var = cgf.emitAutoVarAlloca(catchParam);
+ cir::InitCatchParamOp::create(builder, builder.getUnknownLoc(), exnPtr,
+ var.getAllocatedAddress().getPointer(), kind);
+ cgf.emitAutoVarCleanups(var);
}
/// Begins a catch statement by initializing the catch variable and
@@ -447,7 +412,7 @@ void CIRGenFunction::emitBeginCatch(const CXXCatchStmt *catchStmt,
// Emit the local. Make sure the alloca's superseed the current scope, since
// these are going to be consumed by `cir.catch`, which is not within the
// current scope.
- initCatchParam(*this, ehToken, *catchParam, Address::invalid(),
+ initCatchParam(*this, builder, ehToken, *catchParam, Address::invalid(),
catchStmt->getBeginLoc());
}
@@ -473,8 +438,8 @@ CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s,
builder.restoreInsertionPoint(scopeIP);
const llvm::Triple &t = getTarget().getTriple();
- // If we encounter a try statement on in an OpenMP target region offloaded to
- // a GPU, we treat it as a basic block.
+ // If we encounter a try statement on in an OpenMP target region offloaded
+ // to a GPU, we treat it as a basic block.
const bool isTargetDevice =
(cgm.getLangOpts().OpenMPIsTargetDevice && (t.isNVPTX() || t.isAMDGCN()));
if (isTargetDevice) {
@@ -613,15 +578,16 @@ mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s) {
return emitCXXTryStmt(s, emitter);
}
-// in classic codegen this function is mapping to `isInvokeDest` previously and
-// currently it's mapping to the conditions that performs early returns in
-// `getInvokeDestImpl`, in CIR we need the condition to know if the EH scope may
-// throw exception or now.
+// in classic codegen this function is mapping to `isInvokeDest` previously
+// and currently it's mapping to the conditions that performs early returns in
+// `getInvokeDestImpl`, in CIR we need the condition to know if the EH scope
+// may throw exception or now.
bool CIRGenFunction::isCatchOrCleanupRequired() {
- // If exceptions are disabled/ignored and SEH is not in use, then there is no
- // invoke destination. SEH "works" even if exceptions are off. In practice,
- // this means that C++ destructors and other EH cleanups don't run, which is
- // consistent with MSVC's behavior, except in the presence of -EHa
+ // If exceptions are disabled/ignored and SEH is not in use, then there is
+ // no invoke destination. SEH "works" even if exceptions are off. In
+ // practice, this means that C++ destructors and other EH cleanups don't
+ // run, which is consistent with MSVC's behavior, except in the presence of
+ // -EHa
const LangOptions &lo = cgm.getLangOpts();
if (!lo.Exceptions || lo.IgnoreExceptions) {
if (!lo.Borland && !lo.MicrosoftExt)
diff --git a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
index e9b11595163b5..81f38403d9c60 100644
--- a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
@@ -130,6 +130,7 @@ class ItaniumEHLowering : public EHABILowering {
void lowerDispatch(cir::EhDispatchOp dispatch, mlir::Value exnPtr,
mlir::Value typeId,
SmallVectorImpl<mlir::Operation *> &deadOps);
+ void lowerInitCatchParam(cir::InitCatchParamOp op);
};
/// Lower all EH operations in the module to the Itanium-specific form.
@@ -278,48 +279,15 @@ mlir::LogicalResult ItaniumEHLowering::lowerFunc(cir::FuncOp funcOp) {
}
}
- return mlir::success();
-}
-
-static mlir::Value initCatchParam(mlir::OpBuilder &builder,
- cir::BeginCatchOp op,
- mlir::Value beginCatchCall) {
- mlir::Value result = beginCatchCall;
- mlir::Type expectedPtrType = op.getExnPtr().getType();
-
- auto exceptionType =
- mlir::cast<cir::PointerType>(expectedPtrType).getPointee();
-
- if (auto exnPointeeType = mlir::dyn_cast<cir::PointerType>(exceptionType)) {
- if (auto exnPointeePtrType =
- mlir::dyn_cast<cir::PointerType>(exnPointeeType.getPointee())) {
- if (mlir::isa<cir::RecordType>(exnPointeePtrType.getPointee())) {
- auto parentFunc = op->getParentOfType<cir::FuncOp>();
- mlir::Block *entryBlock = &parentFunc.getRegion().front();
-
- mlir::Value exnPtrTmp;
- {
- mlir::OpBuilder::InsertionGuard guard(builder);
- builder.setInsertionPointToStart(entryBlock);
- exnPtrTmp = cir::AllocaOp::create(
- builder, op->getLoc(), expectedPtrType, exceptionType,
- "exn.byref.tmp", builder.getI64IntegerAttr(8));
- }
-
- result = cir::CastOp::create(builder, op.getLoc(), exceptionType,
- cir::CastKind::bitcast, result);
-
- cir::StoreOp::create(builder, op.getLoc(), result, exnPtrTmp, {}, {},
- {}, {});
- result = exnPtrTmp;
- }
- }
- }
+ // Lower any cir.init_catch_param ops in this function. These materialize
+ // the catch parameter local from the (already lowered) begin_catch result,
+ // and are independent of the eh_token graph traversal above.
+ SmallVector<cir::InitCatchParamOp> initCatchOps;
+ funcOp.walk([&](cir::InitCatchParamOp op) { initCatchOps.push_back(op); });
+ for (cir::InitCatchParamOp op : initCatchOps)
+ lowerInitCatchParam(op);
- return result.getType() == expectedPtrType
- ? result
- : cir::CastOp::create(builder, op->getLoc(), expectedPtrType,
- cir::CastKind::bitcast, result);
+ return mlir::success();
}
/// Lower all EH operations connected to a single cir.eh.initiate.
@@ -435,8 +403,13 @@ void ItaniumEHLowering::lowerEhInitiate(
auto callOp = cir::CallOp::create(
builder, op.getLoc(), mlir::FlatSymbolRefAttr::get(beginCatchFunc),
u8PtrType, mlir::ValueRange{exnPtr});
- mlir::Value result = initCatchParam(builder, op, callOp.getResult());
- op.getExnPtr().replaceAllUsesWith(result);
+ mlir::Value castResult = callOp.getResult();
+ mlir::Type expectedPtrType = op.getExnPtr().getType();
+ if (castResult.getType() != expectedPtrType)
+ castResult =
+ cir::CastOp::create(builder, op.getLoc(), expectedPtrType,
+ cir::CastKind::bitcast, callOp.getResult());
+ op.getExnPtr().replaceAllUsesWith(castResult);
op.erase();
} else if (auto op = mlir::dyn_cast<cir::EhDispatchOp>(user)) {
// Read catch types from the dispatch and set them on the inflight op.
@@ -565,6 +538,88 @@ void ItaniumEHLowering::lowerDispatch(
deadOps.push_back(dispatch);
}
+/// Lower a cir.init_catch_param into the Itanium-specific sequence that
+/// materializes the catch parameter's local variable from the exception
+/// pointer returned by __cxa_begin_catch. The shape of the lowering
+/// depends on the init catch kind:
+///
+/// - Reference: the begin_catch result is
+/// the pointer value itself, so just bitcast and store it into the alloca
+/// except if it reference of pointer of record.
+/// - Pointer: the begin_catch result is
+/// the pointer value itself, so just bitcast and store it into the
+/// alloca.
+/// - Scalar (any other by-value catch): treat the begin_catch result as a
+/// pointer to the value, load it, and store it into the alloca.
+/// - Objc: Handle pointer representation with ObjCLifetime.
+/// - TrivilCopy: copy the exception
+/// object's bytes into the alloca via cir.copy.
+/// - NonTrivilCopy: copy the exception
+/// object's bytes into the alloca via copy constructor.
+///
+void ItaniumEHLowering::lowerInitCatchParam(cir::InitCatchParamOp op) {
+ builder.setInsertionPoint(op);
+ mlir::Location loc = op.getLoc();
+ mlir::Value exnPtr = op.getExnPtr();
+ mlir::Value paramAddr = op.getParamAddr();
+ auto paramAddrType = mlir::cast<cir::PointerType>(paramAddr.getType());
+ mlir::Type elementType = paramAddrType.getPointee();
+ cir::InitCatchKind kind = op.getKind();
+
+ switch (kind) {
+ case InitCatchKind::Reference: {
+ // We have no way to tell the personality function that we're
+ // catching by reference, so if we're catching a pointer,
+ // __cxa_begin_catch will actually return that pointer by value.
+ if (const auto ref = mlir::dyn_cast<cir::PointerType>(elementType)) {
+ // When catching by reference, generally we should just ignore
+ // this by-value pointer and use the exception object instead.
+ if (auto ptr = mlir::dyn_cast<cir::PointerType>(ref.getPointee()))
+ if (!mlir::isa<cir::RecordType>(ptr.getPointee()))
+ llvm_unreachable(
+ "InitCatchParam: reference of pointer or non-record is NYI");
+ }
+
+ mlir::Value casted = cir::CastOp::create(builder, loc, elementType,
+ cir::CastKind::bitcast, exnPtr);
+ cir::StoreOp::create(builder, loc, casted, paramAddr, {}, {}, {}, {});
+ break;
+ }
+ case InitCatchKind::TrivilCopy: {
+ mlir::Value srcPtr = cir::CastOp::create(builder, loc, paramAddrType,
+ cir::CastKind::bitcast, exnPtr);
+ cir::CopyOp::create(builder, loc, paramAddr, srcPtr, {}, {});
+ break;
+ }
+ case InitCatchKind::NonTrivilCopy: {
+ llvm_unreachable("InitCatchParam: non-trivil-copy is NYI");
+ break;
+ }
+ case InitCatchKind::Scalar: {
+ // Scalar by-value catch (integer, float, complex, etc.). The begin_catch
+ // result points into the exception object; load the value through a
+ // typed pointer and store it into the alloca.
+ mlir::Value srcPtr = cir::CastOp::create(builder, loc, paramAddrType,
+ cir::CastKind::bitcast, exnPtr);
+ auto loadOp = cir::LoadOp::create(builder, loc, elementType, srcPtr);
+ cir::StoreOp::create(builder, loc, loadOp.getResult(), paramAddr, {}, {},
+ {}, {});
+ break;
+ }
+ case InitCatchKind::Pointer: {
+ mlir::Value casted = cir::CastOp::create(builder, loc, elementType,
+ cir::CastKind::bitcast, exnPtr);
+ cir::StoreOp::create(builder, loc, casted, paramAddr, {}, {}, {}, {});
+ break;
+ }
+ case InitCatchKind::Objc:
+ llvm_unreachable("InitCatchParam: ObjCLifetime");
+ break;
+ }
+
+ op.erase();
+}
+
//===----------------------------------------------------------------------===//
// The Pass
//===----------------------------------------------------------------------===//
@@ -578,9 +633,9 @@ struct CIREHABILoweringPass
void CIREHABILoweringPass::runOnOperation() {
auto mod = mlir::cast<mlir::ModuleOp>(getOperation());
- // The target triple is attached to the module as the "cir.triple" attribute.
- // If it is absent (e.g. a CIR module parsed from text without a triple) we
- // cannot determine the ABI and must skip the pass.
+ // The target triple is attached to the module as the "cir.triple"
+ // attribute. If it is absent (e.g. a CIR module parsed from text without a
+ // triple) we cannot determine the ABI and must skip the pass.
auto tripleAttr = mlir::dyn_cast_if_present<mlir::StringAttr>(
mod->getAttr(cir::CIRDialect::getTripleAttrName()));
if (!tripleAttr) {
diff --git a/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp b/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp
index 5e1cc064e5ea5..6594165b823cb 100644
--- a/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp
+++ b/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp
@@ -149,6 +149,7 @@ void test_catch_all_and_specific_with_cleanup() {
// CIR-LABEL: cir.func {{.*}} @_Z40test_catch_all_and_specific_with_cleanupv()
// CIR: cir.scope {
// CIR: %[[S:.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s", init]
+// CIR: %[[E:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e"]
// CIR: cir.try {
// CIR: cir.call @_ZN1SC1Ev(%[[S]])
// CIR: cir.cleanup.scope {
@@ -160,8 +161,9 @@ void test_catch_all_and_specific_with_cleanup() {
// CIR: }
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] (%{{.*}}: !cir.eh_token {{.*}}) {
-// CIR: %{{.*}}, %[[EXN:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+// CIR: %{{.*}}, %[[EXN:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
+// CIR: cir.init_catch_param scalar %[[EXN]] to %[[E]] : !cir.ptr<!void>, !cir.ptr<!s32i>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %{{.*}} : !cir.catch_token
@@ -222,7 +224,8 @@ void test_catch_all_and_specific_with_cleanup() {
//
// Catch (int): bind e, end_catch, merge to return.
// CIR-FLAT: ^[[CATCH_INT]](%{{.*}}: !cir.eh_token):
-// CIR-FLAT: %{{.*}}, %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+// CIR-FLAT: %{{.*}}, %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CIR-FLAT: cir.init_catch_param scalar %[[EXN_PTR]] to %{{.*}} : !cir.ptr<!void>, !cir.ptr<!s32i>
// CIR-FLAT: cir.end_catch %{{.*}} : !cir.catch_token
// CIR-FLAT: cir.br ^{{.*}}
//
diff --git a/clang/test/CIR/CodeGen/try-catch.cpp b/clang/test/CIR/CodeGen/try-catch.cpp
index d90f90619520e..3a51ae30864fd 100644
--- a/clang/test/CIR/CodeGen/try-catch.cpp
+++ b/clang/test/CIR/CodeGen/try-catch.cpp
@@ -296,8 +296,9 @@ void call_function_inside_try_catch_with_exception_type() {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv()
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] (%[[EH_TOKEN:.*]]: !cir.eh_token{{.*}}) {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
+// CIR: cir.init_catch_param scalar %[[EXN_PTR]] to %{{.*}} : !cir.ptr<!void>, !cir.ptr<!s32i>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -409,8 +410,9 @@ void call_function_inside_try_catch_with_ref_exception_type() {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv()
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] (%{{.*}}: !cir.eh_token {{.*}}) {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.ptr<!s32i>>)
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
+// CIR: cir.init_catch_param reference %[[EXN_PTR]] to %{{.*}} : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!s32i>>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -521,8 +523,9 @@ void call_function_inside_try_catch_with_complex_exception_type() {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv()
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTICi> : !cir.ptr<!u8i>] (%[[EH_TOKEN:.*]]: !cir.eh_token{{.*}}) {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.complex<!s32i>>)
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
+// CIR: cir.init_catch_param scalar %[[EXN_PTR]] to %{{.*}} : !cir.ptr<!void>, !cir.ptr<!cir.complex<!s32i>>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -640,8 +643,9 @@ void call_function_inside_try_catch_with_array_exception_type() {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv()
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIPi> : !cir.ptr<!u8i>] (%[[EH_TOKEN:.*]]: !cir.eh_token{{.*}}) {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.ptr<!s32i>>)
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
+// CIR: cir.init_catch_param pointer %[[EXN_PTR]] to %{{.*}} : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!s32i>>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -753,8 +757,9 @@ void call_function_inside_try_catch_with_exception_type_and_catch_all() {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv()
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] (%[[EH_TOKEN:.*]]: !cir.eh_token{{.*}}) {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
+// CIR: cir.init_catch_param scalar %[[EXN_PTR]] to %{{.*}} : !cir.ptr<!void>, !cir.ptr<!s32i>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -995,8 +1000,9 @@ void call_function_inside_try_catch_with_aggregate_exception_type() {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef})
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTI11CustomError> : !cir.ptr<!u8i>] (%{{.*}}: !cir.eh_token {{.*}}) {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!rec_CustomError>)
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
+// CIR: cir.init_catch_param trivil_copy %[[EXN_PTR]] to %{{.*}} : !cir.ptr<!void>, !cir.ptr<!rec_CustomError>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -1113,8 +1119,9 @@ void call_function_inside_try_catch_with_ref_ptr_of_record_exception_type() {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef})
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIP6Record> : !cir.ptr<!u8i>] (%[[EH_TOKEN:.*]]: !cir.eh_token {{.*}}) {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>>)
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
+// CIR: cir.init_catch_param reference %[[EXN_PTR]] to %{{.*}} : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -1227,8 +1234,9 @@ void call_function_inside_try_catch_with_exception_member_ptr_type() {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef})
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIM6Recordi> : !cir.ptr<!u8i>] (%{{.*}}: !cir.eh_token {{.*}} {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s64i>)
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
+// CIR: cir.init_catch_param scalar %[[EXN_PTR]] to %{{.*}} : !cir.ptr<!void>, !cir.ptr<!s64i>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -1341,13 +1349,15 @@ int init_catch_param_with_type_int() {
// CIR: %[[RET_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
// CIR: %[[RV_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["rv", init]
// CIR: cir.scope {
+// CIR: %[[X_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x"]
// CIR: cir.try {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef})
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] (%{{.*}}: !cir.eh_token {{.*}}) {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
-// CIR: %[[TMP_EXN:.*]] = cir.load {{.*}} %[[EXN_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.init_catch_param scalar %[[EXN_PTR]] to %[[X_ADDR]] : !cir.ptr<!void>, !cir.ptr<!s32i>
+// CIR: %[[TMP_EXN:.*]] = cir.load {{.*}} %[[X_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.store {{.*}} %[[TMP_EXN]], %[[RV_ADDR]] : !s32i, !cir.ptr<!s32i>
// CIR: cir.yield
// CIR: } cleanup all {
@@ -1365,6 +1375,7 @@ int init_catch_param_with_type_int() {
// CIR: cir.return %[[TMP_RET]] : !s32i
// LLVM: define {{.*}} i32 @_Z30init_catch_param_with_type_intv() {{.*}} personality ptr @__gxx_personality_v0
+// LLVM: %[[X_ADDR:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[RET_ADDR:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[RV_ADDR:.*]] = alloca i32, i64 1, align 4
// LLVM: br label %[[TRY_SCOPE:.*]]
@@ -1397,8 +1408,10 @@ int init_catch_param_with_type_int() {
// LLVM: %[[EXN_PTR:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
// LLVM: br label %[[CATCH_BODY:.*]]
// LLVM: [[CATCH_BODY]]:
-// LLVM: %[[TMP_EXN:.*]] = load i32, ptr %[[EXN_PTR]], align 8
-// LLVM: store i32 %[[TMP_EXN]], ptr %[[RV_ADDR]], align 4
+// LLVM: %[[TMP_EXN:.*]] = load i32, ptr %[[EXN_PTR]], align 4
+// LLVM: store i32 %[[TMP_EXN]], ptr %[[X_ADDR]], align 4
+// LLVM: %[[TMP_X:.*]] = load i32, ptr %[[X_ADDR]], align 4
+// LLVM: store i32 %[[TMP_X]], ptr %[[RV_ADDR]], align 4
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
@@ -1477,18 +1490,20 @@ int init_catch_param_with_type_int_ptr() {
// CIR: %[[RET_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
// CIR: %[[RV_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["rv", init]
// CIR: cir.scope {
+// CIR: %[[X_ADDR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["x"]
// CIR: cir.try {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef})
// CIR: cir.yield
// CIR: } catch [type #cir.global_view<@_ZTIPi> : !cir.ptr<!u8i>] (%{{.*}}: !cir.eh_token {{.*}}) {
-// CIR: %catch_token, %exn_ptr = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.ptr<!s32i>>)
+// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
-// CIR: %[[DEREF_EXN_PTR:.*]] = cir.load deref {{.*}} %[[EXN_PTR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
-// CIR: %[[EXN_PTR:.*]] = cir.load {{.*}} %[[DEREF_EXN_PTR]] : !cir.ptr<!s32i>, !s32i
-// CIR: cir.store {{.*}} %[[EXN_PTR]], %[[RV_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.init_catch_param pointer %[[EXN_PTR]] to %[[X_ADDR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!s32i>>
+// CIR: %[[DEREF_X:.*]] = cir.load deref {{.*}} %[[X_ADDR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+// CIR: %[[LOADED_INT:.*]] = cir.load {{.*}} %[[DEREF_X]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.store {{.*}} %[[LOADED_INT]], %[[RV_ADDR]] : !s32i, !cir.ptr<!s32i>
// CIR: cir.yield
// CIR: } cleanup all {
-// CIR: cir.end_catch %catch_token : !cir.catch_token
+// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
// CIR: cir.yield
// CIR: }
// CIR: cir.yield
@@ -1502,6 +1517,7 @@ int init_catch_param_with_type_int_ptr() {
// CIR: cir.return %[[TMP_RET]] : !s32i
// LLVM: define {{.*}} i32 @_Z34init_catch_param_with_type_int_ptrv() {{.*}} personality ptr @__gxx_personality_v0
+// LLVM: %[[X_ADDR:.*]] = alloca ptr, i64 1, align 8
// LLVM: %[[RET_ADDR:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[RV_ADDR:.*]] = alloca i32, i64 1, align 4
// LLVM: br label %[[TRY_SCOPE:.*]]
@@ -1534,9 +1550,9 @@ int init_catch_param_with_type_int_ptr() {
// LLVM: %[[EXN_PTR:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
// LLVM: br label %[[CATCH_BODY:.*]]
// LLVM: [[CATCH_BODY]]:
-// LLVM: %[[DEREF_EXN_PTR:.*]] = load ptr, ptr %[[EXN_PTR]], align 8
-// LLVM: %[[TMP_EXN:.*]] = load i32, ptr %[[DEREF_EXN_PTR]], align 4
-// LLVM: store i32 %[[TMP_EXN]], ptr %[[RV_ADDR]], align 4
+// LLVM: store ptr %[[EXN_PTR]], ptr %[[X_ADDR]], align 8
+// LLVM: %[[DEREF_X:.*]] = load ptr, ptr %[[X_ADDR]], align 8
+// LLVM: %[[TMP_EXN:.*]] = load i32, ptr %[[DEREF_X]], align 4
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
>From 94fc6b84f9a8b4b8c61b0e84316f7d8b9af077c7 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Tue, 28 Apr 2026 22:15:18 +0200
Subject: [PATCH 3/5] Update op example
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 74207c93646e4..9201bfba0b7e5 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -7663,10 +7663,10 @@ def CIR_InitCatchParamOp : CIR_Op<"init_catch_param"> {
```
%catch_token, %exn_ptr = cir.begin_catch %eh_token
- : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+ : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
%param_addr = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
cir.init_catch_param %exn_ptr to %param_addr
- : !cir.ptr<!s32i>, !cir.ptr<!s32i>
+ : !cir.ptr<!void>, !cir.ptr<!s32i>
```
}];
>From a6116696624300c8c6aa7436cb6fde20d4216817 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Tue, 28 Apr 2026 22:15:58 +0200
Subject: [PATCH 4/5] Remove old comments
---
clang/lib/CIR/CodeGen/CIRGenException.cpp | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 8f8e88d42b89a..a29a5a00a20c0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -323,12 +323,9 @@ static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken,
/// parameter during catch initialization.
static void initCatchParam(CIRGenFunction &cgf, CIRGenBuilderTy &builder,
mlir::Value ehToken, const VarDecl &catchParam,
- Address paramAddr, SourceLocation loc) {
+ SourceLocation loc) {
CanQualType catchType =
cgf.cgm.getASTContext().getCanonicalType(catchParam.getType());
- // mlir::Type cirCatchTy = cgf.convertTypeForMem(catchType);
- // mlir::Type exnPtrTy = builder.getPointerTo(cirCatchTy);
- // CharUnits caughtExnAlignment = cgf.getPointerAlign();
cir::InitCatchKind kind;
bool endCatchMightThrow = true;
@@ -371,7 +368,7 @@ static void initCatchParam(CIRGenFunction &cgf, CIRGenBuilderTy &builder,
mlir::Value exnPtr =
callBeginCatch(cgf, ehToken, builder.getVoidPtrTy(), endCatchMightThrow);
CIRGenFunction::AutoVarEmission var = cgf.emitAutoVarAlloca(catchParam);
- cir::InitCatchParamOp::create(builder, builder.getUnknownLoc(), exnPtr,
+ cir::InitCatchParamOp::create(builder, cgf.getLoc(loc), exnPtr,
var.getAllocatedAddress().getPointer(), kind);
cgf.emitAutoVarCleanups(var);
}
@@ -412,7 +409,7 @@ void CIRGenFunction::emitBeginCatch(const CXXCatchStmt *catchStmt,
// Emit the local. Make sure the alloca's superseed the current scope, since
// these are going to be consumed by `cir.catch`, which is not within the
// current scope.
- initCatchParam(*this, builder, ehToken, *catchParam, Address::invalid(),
+ initCatchParam(*this, builder, ehToken, *catchParam,
catchStmt->getBeginLoc());
}
>From 2b7067af387ff4b9ee9879a8f751ea0ecf540bde Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Wed, 29 Apr 2026 18:42:40 +0200
Subject: [PATCH 5/5] Address code review comments
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 4 +-
clang/lib/CIR/CodeGen/CIRGenException.cpp | 58 ++++---------------
.../CIR/Dialect/Transforms/EHABILowering.cpp | 12 ++--
clang/test/CIR/CodeGen/try-catch.cpp | 3 +-
4 files changed, 19 insertions(+), 58 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 9201bfba0b7e5..b30dd980f5569 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -7641,8 +7641,8 @@ def CIR_InitCatchKind : CIR_I32EnumAttr<
I32EnumAttrCase<"Pointer", 1, "pointer">,
I32EnumAttrCase<"Scalar", 2, "scalar">,
I32EnumAttrCase<"Objc", 3, "objc">,
- I32EnumAttrCase<"TrivilCopy", 4, "trivil_copy">,
- I32EnumAttrCase<"NonTrivilCopy", 5, "non_trivil_copy">,
+ I32EnumAttrCase<"TrivialCopy", 4, "trivial_copy">,
+ I32EnumAttrCase<"NonTrivialCopy", 5, "non_trivial_copy">,
]>;
def CIR_InitCatchParamOp : CIR_Op<"init_catch_param"> {
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index a29a5a00a20c0..3c956801f6b52 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -274,30 +274,11 @@ void CIRGenFunction::addCatchHandlerAttr(
}
namespace {
-/// From traditional LLVM, useful info for LLVM lowering support:
-/// A cleanup to call __cxa_end_catch. In many cases, the caught
-/// exception type lets us state definitively that the thrown exception
-/// type does not have a destructor. In particular:
-/// - Catch-alls tell us nothing, so we have to conservatively
-/// assume that the thrown exception might have a destructor.
-/// - Catches by reference behave according to their base types.
-/// - Catches of non-record types will only trigger for exceptions
-/// of non-record types, which never have destructors.
-/// - Catches of record types can trigger for arbitrary subclasses
-/// of the caught type, so we have to assume the actual thrown
-/// exception type might have a throwing destructor, even if the
-/// caught type's destructor is trivial or nothrow.
struct CallEndCatch final : EHScopeStack::Cleanup {
- CallEndCatch(bool mightThrow, mlir::Value catchToken)
- : mightThrow(mightThrow), catchToken(catchToken) {}
- bool mightThrow;
+ CallEndCatch(mlir::Value catchToken) : catchToken(catchToken) {}
mlir::Value catchToken;
void emit(CIRGenFunction &cgf, Flags flags) override {
- // Traditional LLVM codegen would emit a call to __cxa_end_catch
- // here. For CIR, just let it pass since the cleanup is going
- // to be emitted on a later pass when lowering the catch region.
- // CGF.EmitRuntimeCallOrTryCall(getEndCatchFn(CGF.CGM));
cir::EndCatchOp::create(cgf.getBuilder(), *cgf.currSrcLoc, catchToken);
cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
}
@@ -305,16 +286,14 @@ struct CallEndCatch final : EHScopeStack::Cleanup {
} // namespace
static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken,
- mlir::Type exnPtrTy, bool endMightThrow) {
+ mlir::Type exnPtrTy) {
auto catchTokenTy = cir::CatchTokenType::get(cgf.getBuilder().getContext());
auto beginCatch = cir::BeginCatchOp::create(cgf.getBuilder(),
cgf.getBuilder().getUnknownLoc(),
catchTokenTy, exnPtrTy, ehToken);
- cgf.ehStack.pushCleanup<CallEndCatch>(
- NormalAndEHCleanup,
- endMightThrow && !cgf.cgm.getLangOpts().AssumeNothrowExceptionDtor,
- beginCatch.getCatchToken());
+ cgf.ehStack.pushCleanup<CallEndCatch>(NormalAndEHCleanup,
+ beginCatch.getCatchToken());
return beginCatch.getExnPtr();
}
@@ -327,24 +306,19 @@ static void initCatchParam(CIRGenFunction &cgf, CIRGenBuilderTy &builder,
CanQualType catchType =
cgf.cgm.getASTContext().getCanonicalType(catchParam.getType());
cir::InitCatchKind kind;
- bool endCatchMightThrow = true;
// If we're catching by reference, we can just cast the object
// pointer to the appropriate pointer.
if (isa<ReferenceType>(catchType)) {
- QualType caughtType = cast<ReferenceType>(catchType)->getPointeeType();
- endCatchMightThrow = caughtType->isRecordType();
kind = cir::InitCatchKind::Reference;
} else {
cir::TypeEvaluationKind tek = cgf.getEvaluationKind(catchType);
if (tek == cir::TEK_Aggregate) {
assert(isa<RecordType>(catchType) && "unexpected catch type!");
const Expr *copyExpr = catchParam.getInit();
- kind = !copyExpr ? cir::InitCatchKind::TrivilCopy
- : cir::InitCatchKind::NonTrivilCopy;
+ kind = !copyExpr ? cir::InitCatchKind::TrivialCopy
+ : cir::InitCatchKind::NonTrivialCopy;
} else {
- endCatchMightThrow = false;
-
// Scalars and complexes.
if (catchType->hasPointerRepresentation()) {
switch (catchType.getQualifiers().getObjCLifetime()) {
@@ -365,8 +339,7 @@ static void initCatchParam(CIRGenFunction &cgf, CIRGenBuilderTy &builder,
}
}
- mlir::Value exnPtr =
- callBeginCatch(cgf, ehToken, builder.getVoidPtrTy(), endCatchMightThrow);
+ mlir::Value exnPtr = callBeginCatch(cgf, ehToken, builder.getVoidPtrTy());
CIRGenFunction::AutoVarEmission var = cgf.emitAutoVarAlloca(catchParam);
cir::InitCatchParamOp::create(builder, cgf.getLoc(loc), exnPtr,
var.getAllocatedAddress().getPointer(), kind);
@@ -385,24 +358,13 @@ void CIRGenFunction::emitBeginCatch(const CXXCatchStmt *catchStmt,
//
// So the precise ordering is:
// 1. Construct catch variable.
- // 2. __cxa_begin_catch
- // 3. Enter __cxa_end_catch cleanup
+ // 2. begin_catch
+ // 3. Enter CallEndCatch cleanup
// 4. Enter dtor cleanup
//
- // We do this by using a slightly abnormal initialization process.
- // Delegation sequence:
- // - ExitCXXTryStmt opens a RunCleanupsScope
- // - EmitAutoVarAlloca creates the variable and debug info
- // - InitCatchParam initializes the variable from the exception
- // - CallBeginCatch calls __cxa_begin_catch
- // - CallBeginCatch enters the __cxa_end_catch cleanup
- // - EmitAutoVarCleanups enters the variable destructor cleanup
- // - EmitCXXTryStmt emits the code for the catch body
- // - EmitCXXTryStmt close the RunCleanupsScope
VarDecl *catchParam = catchStmt->getExceptionDecl();
if (!catchParam) {
- callBeginCatch(*this, ehToken, builder.getVoidPtrTy(),
- /*endMightThrow=*/true);
+ callBeginCatch(*this, ehToken, builder.getVoidPtrTy());
return;
}
diff --git a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
index 81f38403d9c60..baec91de9f89c 100644
--- a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
@@ -552,9 +552,9 @@ void ItaniumEHLowering::lowerDispatch(
/// - Scalar (any other by-value catch): treat the begin_catch result as a
/// pointer to the value, load it, and store it into the alloca.
/// - Objc: Handle pointer representation with ObjCLifetime.
-/// - TrivilCopy: copy the exception
+/// - TrivialCopy: copy the exception
/// object's bytes into the alloca via cir.copy.
-/// - NonTrivilCopy: copy the exception
+/// - NonTrivialCopy: copy the exception
/// object's bytes into the alloca via copy constructor.
///
void ItaniumEHLowering::lowerInitCatchParam(cir::InitCatchParamOp op) {
@@ -585,14 +585,14 @@ void ItaniumEHLowering::lowerInitCatchParam(cir::InitCatchParamOp op) {
cir::StoreOp::create(builder, loc, casted, paramAddr, {}, {}, {}, {});
break;
}
- case InitCatchKind::TrivilCopy: {
+ case InitCatchKind::TrivialCopy: {
mlir::Value srcPtr = cir::CastOp::create(builder, loc, paramAddrType,
cir::CastKind::bitcast, exnPtr);
cir::CopyOp::create(builder, loc, paramAddr, srcPtr, {}, {});
break;
}
- case InitCatchKind::NonTrivilCopy: {
- llvm_unreachable("InitCatchParam: non-trivil-copy is NYI");
+ case InitCatchKind::NonTrivialCopy: {
+ llvm_unreachable("InitCatchParam: non-trivial-copy is NYI");
break;
}
case InitCatchKind::Scalar: {
@@ -613,7 +613,7 @@ void ItaniumEHLowering::lowerInitCatchParam(cir::InitCatchParamOp op) {
break;
}
case InitCatchKind::Objc:
- llvm_unreachable("InitCatchParam: ObjCLifetime");
+ llvm_unreachable("InitCatchParam: ObjCLifetime is NYI");
break;
}
diff --git a/clang/test/CIR/CodeGen/try-catch.cpp b/clang/test/CIR/CodeGen/try-catch.cpp
index 3a51ae30864fd..dd9ed9d97b795 100644
--- a/clang/test/CIR/CodeGen/try-catch.cpp
+++ b/clang/test/CIR/CodeGen/try-catch.cpp
@@ -1002,7 +1002,7 @@ void call_function_inside_try_catch_with_aggregate_exception_type() {
// CIR: } catch [type #cir.global_view<@_ZTI11CustomError> : !cir.ptr<!u8i>] (%{{.*}}: !cir.eh_token {{.*}}) {
// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
// CIR: cir.cleanup.scope {
-// CIR: cir.init_catch_param trivil_copy %[[EXN_PTR]] to %{{.*}} : !cir.ptr<!void>, !cir.ptr<!rec_CustomError>
+// CIR: cir.init_catch_param trivial_copy %[[EXN_PTR]] to %{{.*}} : !cir.ptr<!void>, !cir.ptr<!rec_CustomError>
// CIR: cir.yield
// CIR: } cleanup all {
// CIR: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -1114,7 +1114,6 @@ void call_function_inside_try_catch_with_ref_ptr_of_record_exception_type() {
// CIR: cir.func {{.*}} @_Z68call_function_inside_try_catch_with_ref_ptr_of_record_exception_typev(){{.*}} personality(@__gxx_personality_v0){{.*}} {
// CIR: %[[E_ADDR:.*]] = cir.alloca !cir.ptr<!cir.ptr<!rec_Record>>, !cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>>, ["ref_ptr", const]
-// CIR: %[[EXN_BYREF_TMP:.*]] = cir.alloca !cir.ptr<!rec_Record>, !cir.ptr<!cir.ptr<!rec_Record>>, ["exn.byref.tmp"]
// CIR: cir.try {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> (!s32i {llvm.noundef})
// CIR: cir.yield
More information about the cfe-commits
mailing list