[clang] [CIR][WIP] Make BeginCatchOp target-independent (PR #190612)
Amr Hesham via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 10 11:03:07 PDT 2026
https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/190612
>From 1428bb5cbf931e8588856c8f3c83ada9dc277a91 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Mon, 6 Apr 2026 15:57:11 +0200
Subject: [PATCH 1/2] [CIR] Make BeginCatch target-independent
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 22 +++--
clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 74 +++++------------
.../CIR/Dialect/Transforms/EHABILowering.cpp | 81 +++++++++++++++++--
.../CodeGen/try-catch-all-with-cleanup.cpp | 16 ++--
clang/test/CIR/CodeGen/try-catch.cpp | 65 ++++++---------
clang/test/CIR/IR/catch-param.cir | 4 +-
clang/test/CIR/IR/eh-flat.cir | 20 +++--
clang/test/CIR/IR/try-catch.cir | 16 ++--
8 files changed, 165 insertions(+), 133 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index b806800275c7b..1f0bbe5b507d7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -7333,6 +7333,14 @@ def CIR_EndCleanupOp : CIR_Op<"end_cleanup"> {
// EH Operations: BeginCatchOp
//===----------------------------------------------------------------------===//
+def CIR_BeginCatchKind : CIR_I32EnumAttr<"BeginCatchKind", "beginCatchKind", [
+ I32EnumAttrCase<"Default", 0, "default">,
+ I32EnumAttrCase<"LoadStore", 1, "load_store">,
+ I32EnumAttrCase<"Store", 2, "store">,
+ I32EnumAttrCase<"Memcopy", 3, "memcopy">,
+ I32EnumAttrCase<"Reference", 4, "reference">,
+]>;
+
def CIR_BeginCatchOp : CIR_Op<"begin_catch"> {
let summary = "Begin a catch handler";
let description = [{
@@ -7380,13 +7388,17 @@ def CIR_BeginCatchOp : CIR_Op<"begin_catch"> {
```
}];
- let arguments = (ins CIR_EhTokenType:$eh_token);
- let results = (outs CIR_CatchTokenType:$catch_token,
- CIR_PointerType:$exn_ptr);
+ let arguments = (ins
+ CIR_EhTokenType:$eh_token,
+ Optional<CIR_PointerType>:$exn_ptr,
+ CIR_BeginCatchKind:$kind
+ );
+
+ let results = (outs CIR_CatchTokenType:$catch_token);
let assemblyFormat = [{
- $eh_token `:` type($eh_token) `->` `(` type($catch_token) `,`
- qualified(type($exn_ptr)) `)` attr-dict
+ $kind $eh_token `:` type($eh_token) (`,` $exn_ptr^ `:` qualified(type($exn_ptr)))?
+ `->` type($catch_token) attr-dict
}];
let hasLLVMLowering = false;
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 75658b23790bf..471c48da8d2b8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -2523,12 +2523,14 @@ struct CallEndCatch final : EHScopeStack::Cleanup {
};
} // namespace
-static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken,
- mlir::Type exnPtrTy, bool endMightThrow) {
+static mlir::Value
+callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken, mlir::Value exnPtr,
+ mlir::Type exnPtrTy, bool endMightThrow,
+ cir::BeginCatchKind kind = cir::BeginCatchKind::Default) {
auto catchTokenTy = cir::CatchTokenType::get(cgf.getBuilder().getContext());
- auto beginCatch = cir::BeginCatchOp::create(cgf.getBuilder(),
- cgf.getBuilder().getUnknownLoc(),
- catchTokenTy, exnPtrTy, ehToken);
+ auto beginCatch = cir::BeginCatchOp::create(
+ cgf.getBuilder(), cgf.getBuilder().getUnknownLoc(), catchTokenTy, ehToken,
+ exnPtr, kind);
cgf.ehStack.pushCleanup<CallEndCatch>(
NormalAndEHCleanup,
@@ -2553,8 +2555,8 @@ static void initCatchParam(CIRGenFunction &cgf, mlir::Value ehToken,
QualType caughtType = cast<ReferenceType>(catchType)->getPointeeType();
bool endCatchMightThrow = caughtType->isRecordType();
- mlir::Value adjustedExn =
- callBeginCatch(cgf, ehToken, cirCatchTy, endCatchMightThrow);
+ callBeginCatch(cgf, ehToken, paramAddr.getPointer(), cirCatchTy,
+ endCatchMightThrow, cir::BeginCatchKind::Reference);
// We have no way to tell the personality function that we're
// catching by reference, so if we're catching a pointer,
@@ -2566,24 +2568,8 @@ static void initCatchParam(CIRGenFunction &cgf, mlir::Value ehToken,
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;
}
@@ -2594,8 +2580,8 @@ static void initCatchParam(CIRGenFunction &cgf, mlir::Value ehToken,
// 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);
+ callBeginCatch(cgf, ehToken, paramAddr.getPointer(), cirCatchTy,
+ /*endMightThrow=*/false, cir::BeginCatchKind::Store);
switch (catchType.getQualifiers().getObjCLifetime()) {
case Qualifiers::OCL_Strong:
cgf.cgm.errorNYI(loc,
@@ -2609,7 +2595,6 @@ static void initCatchParam(CIRGenFunction &cgf, mlir::Value ehToken,
return;
case Qualifiers::OCL_None:
- cgf.getBuilder().createStore(cgf.getLoc(loc), catchParam, paramAddr);
return;
case Qualifiers::OCL_Weak:
@@ -2622,44 +2607,21 @@ static void initCatchParam(CIRGenFunction &cgf, mlir::Value ehToken,
// 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");
+ callBeginCatch(cgf, ehToken, paramAddr.getPointer(),
+ cgf.getBuilder().getPointerTo(cirCatchTy),
+ /*endMightThrow=*/false, cir::BeginCatchKind::LoadStore);
+ return;
}
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);
+ callBeginCatch(cgf, ehToken, paramAddr.getPointer(), cirCatchPtrTy,
+ /*endMightThrow=*/true, cir::BeginCatchKind::Memcopy);
return;
}
@@ -2696,7 +2658,7 @@ void CIRGenItaniumCXXABI::emitBeginCatch(CIRGenFunction &cgf,
VarDecl *catchParam = catchStmt->getExceptionDecl();
if (!catchParam) {
- callBeginCatch(cgf, ehToken, cgf.getBuilder().getVoidPtrTy(),
+ callBeginCatch(cgf, ehToken, {}, cgf.getBuilder().getVoidPtrTy(),
/*endMightThrow=*/true);
return;
}
diff --git a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
index abdc32951f857..771203213dc49 100644
--- a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
@@ -395,13 +395,82 @@ void ItaniumEHLowering::lowerEhInitiate(
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::TypedValue<cir::PointerType> exnPtrAddr = op.getExnPtr();
+ if (exnPtrAddr) {
+ 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);
+
+ switch (op.getKind()) {
+ case cir::BeginCatchKind::LoadStore: {
+ auto loadExnPtr =
+ cir::LoadOp::create(builder, op->getLoc(), castResult);
+ cir::StoreOp::create(builder, op.getLoc(), loadExnPtr, exnPtrAddr,
+ {}, {}, {}, {});
+ break;
+ }
+ case cir::BeginCatchKind::Store: {
+ mlir::Type exceptionType =
+ mlir::cast<cir::PointerType>(expectedPtrType).getPointee();
+ castResult =
+ cir::CastOp::create(builder, op.getLoc(), exceptionType,
+ cir::CastKind::bitcast, callOp.getResult());
+ cir::StoreOp::create(builder, op.getLoc(), castResult, exnPtrAddr,
+ {}, {}, {}, {});
+ break;
+ }
+ case cir::BeginCatchKind::Memcopy: {
+ cir::CopyOp::create(builder, op->getLoc(), exnPtrAddr, castResult);
+ break;
+ }
+ case cir::BeginCatchKind::Reference: {
+ mlir::Type exceptionType =
+ mlir::cast<cir::PointerType>(expectedPtrType).getPointee();
+ mlir::Type exceptionTypePointee =
+ mlir::cast<cir::PointerType>(exceptionType).getPointee();
+ bool isPointer = mlir::isa<cir::PointerType>(exceptionTypePointee);
+ if (isPointer) {
+ cir::FuncOp 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));
+ }
+
+ castResult = cir::CastOp::create(
+ builder, op.getLoc(), exceptionType, cir::CastKind::bitcast,
+ callOp.getResult());
+
+ cir::StoreOp::create(builder, op.getLoc(), castResult, exnPtrTmp,
+ {}, {}, {}, {});
+
+ castResult = exnPtrTmp;
+ }
+
+ castResult =
+ cir::CastOp::create(builder, op.getLoc(), exceptionType,
+ cir::CastKind::bitcast, castResult);
+ cir::StoreOp::create(builder, op.getLoc(), castResult, exnPtrAddr,
+ {}, {}, {}, {});
+ break;
+ }
+ case cir::BeginCatchKind::Default: {
+ break;
+ }
+ }
+ }
+
op.erase();
+ // Extra load and store
} else if (auto op = mlir::dyn_cast<cir::EhDispatchOp>(user)) {
// Read catch types from the dispatch and set them on the inflight op.
mlir::ArrayAttr catchTypes = op.getCatchTypesAttr();
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..2e93d096237af 100644
--- a/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp
+++ b/clang/test/CIR/CodeGen/try-catch-all-with-cleanup.cpp
@@ -36,7 +36,7 @@ void test_catch_all_with_cleanup() {
// CIR: }
// CIR: cir.yield
// CIR: } catch all (%{{.*}}: !cir.eh_token {{.*}}) {
-// CIR: %{{.*}}, %{{.*}} = cir.begin_catch
+// CIR: %{{.*}} = cir.begin_catch
// CIR: cir.cleanup.scope {
// CIR: cir.yield
// CIR: } cleanup all {
@@ -88,7 +88,7 @@ void test_catch_all_with_cleanup() {
//
// Catch handler.
// CIR-FLAT: ^[[CATCH_ALL]](%[[CA_ET:.*]]: !cir.eh_token):
-// CIR-FLAT: %{{.*}}, %{{.*}} = cir.begin_catch %[[CA_ET]]
+// CIR-FLAT: %{{.*}} = cir.begin_catch default %[[CA_ET]]
// CIR-FLAT: cir.end_catch
// CIR-FLAT: cir.return
@@ -161,10 +161,8 @@ 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: %{{.*}} = cir.begin_catch load_store %{{.*}} : !cir.eh_token, %[[E]] : !cir.ptr<!s32i> -> !cir.catch_token
// 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
@@ -172,7 +170,7 @@ void test_catch_all_and_specific_with_cleanup() {
// CIR: }
// CIR: cir.yield
// CIR: } catch all (%{{.*}}: !cir.eh_token {{.*}}) {
-// CIR: %{{.*}}, %{{.*}} = cir.begin_catch %{{.*}} : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CIR: %{{.*}} = cir.begin_catch default %{{.*}} : !cir.eh_token -> !cir.catch_token
// CIR: cir.cleanup.scope {
// CIR: cir.yield
// CIR: } cleanup all {
@@ -226,15 +224,13 @@ 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.begin_catch load_store %{{.*}} : !cir.eh_token, %[[E]] : !cir.ptr<!s32i> -> !cir.catch_token
// CIR-FLAT: cir.end_catch %{{.*}} : !cir.catch_token
// CIR-FLAT: cir.br ^{{.*}}
//
// Catch-all handler.
// CIR-FLAT: ^[[CATCH_ALL]](%[[CA_ET:.*]]: !cir.eh_token):
-// CIR-FLAT: %{{.*}}, %{{.*}} = cir.begin_catch %[[CA_ET]]
+// CIR-FLAT: %{{.*}} = cir.begin_catch default %[[CA_ET]]
// CIR-FLAT: cir.br ^{{.*}}
// 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 fd8b9294c9f92..1679a75ffe476 100644
--- a/clang/test/CIR/CodeGen/try-catch.cpp
+++ b/clang/test/CIR/CodeGen/try-catch.cpp
@@ -210,7 +210,7 @@ void call_function_inside_try_catch_all() {
// CIR: %[[CALL:.*]] = cir.call @_Z8divisionv()
// CIR: cir.yield
// CIR: } catch all (%[[EH_TOKEN:.*]]: !cir.eh_token{{.*}}) {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CIR: %[[CATCH_TOKEN:.*]] = cir.begin_catch default %[[EH_TOKEN]] : !cir.eh_token -> !cir.catch_token
// CIR: cir.cleanup.scope {
// CIR: cir.yield
// CIR: } cleanup {{.*}} {
@@ -296,10 +296,8 @@ 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:.*]] = cir.begin_catch load_store %[[EH_TOKEN]] : !cir.eh_token, %[[EXCEPTION_ADDR]] : !cir.ptr<!s32i> -> !cir.catch_token
// 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: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -340,10 +338,10 @@ void call_function_inside_try_catch_with_exception_type() {
// LLVM: %[[EXN_OBJ_PHI2:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[EH_SELECTOR_PHI2:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
// 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 %[[CATCH_BODY:.*]]
+// LLVM: [[CATCH_BODY]]:
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
@@ -414,9 +412,8 @@ 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<!s32i>)
+// CIR: %[[CATCH_TOKEN:.*]] = cir.begin_catch reference %{{.*}} : !cir.eh_token, %[[EXCEPTION_ADDR]] : !cir.ptr<!cir.ptr<!s32i>> -> !cir.catch_token
// 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
@@ -457,9 +454,9 @@ void call_function_inside_try_catch_with_ref_exception_type() {
// LLVM: %[[EXN_OBJ_PHI2:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[EH_SELECTOR_PHI2:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
+// LLVM: store ptr %[[TOKEN]], ptr %{{.*}}, align 8
// 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()
@@ -529,10 +526,8 @@ 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:.*]] = cir.begin_catch load_store %[[EH_TOKEN]] : !cir.eh_token, %[[EXCEPTION_ADDR]] : !cir.ptr<!cir.complex<!s32i>> -> !cir.catch_token
// 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: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -573,10 +568,10 @@ void call_function_inside_try_catch_with_complex_exception_type() {
// LLVM: %[[EXN_OBJ_PHI2:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[EH_SELECTOR_PHI2:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
// 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 %[[CATCH_BODY:.*]]
+// LLVM: [[CATCH_BODY]]:
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
@@ -653,9 +648,8 @@ 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<!s32i>)
+// CIR: %[[CATCH_TOKEN:.*]] = cir.begin_catch store %[[EH_TOKEN]] : !cir.eh_token, %[[E_ADDR]] : !cir.ptr<!cir.ptr<!s32i>> -> !cir.catch_token
// 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: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -696,9 +690,9 @@ void call_function_inside_try_catch_with_array_exception_type() {
// LLVM: %[[EXN_OBJ_PHI2:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[EH_SELECTOR_PHI2:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
+// LLVM: store ptr %[[TOKEN]], ptr {{.*}}, align 8
// 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()
@@ -769,10 +763,8 @@ 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:.*]] = cir.begin_catch load_store %[[EH_TOKEN]] : !cir.eh_token, %[[EXCEPTION_ADDR]] : !cir.ptr<!s32i> -> !cir.catch_token
// 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: cir.end_catch %[[CATCH_TOKEN]] : !cir.catch_token
@@ -780,7 +772,7 @@ void call_function_inside_try_catch_with_exception_type_and_catch_all() {
// CIR: }
// CIR: cir.yield
// CIR: } catch all (%[[EH_TOKEN2:.*]]: !cir.eh_token{{.*}}) {
-// CIR: %[[CATCH_TOKEN2:.*]], %{{.*}} = cir.begin_catch %[[EH_TOKEN2]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CIR: %[[CATCH_TOKEN2:.*]] = cir.begin_catch default %[[EH_TOKEN2]] : !cir.eh_token -> !cir.catch_token
// CIR: cir.cleanup.scope {
// CIR: cir.yield
// CIR: } cleanup {{.*}} {
@@ -820,10 +812,10 @@ void call_function_inside_try_catch_with_exception_type_and_catch_all() {
// LLVM: %[[EXN_OBJ_PHI2:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[EH_SELECTOR_PHI2:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
// 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 %[[CATCH_BODY:.*]]
+// LLVM: [[CATCH_BODY]]:
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
@@ -912,7 +904,7 @@ void cleanup_inside_try_body() {
// CIR: }
// CIR: cir.yield
// CIR: } catch all (%[[TOKEN:.*]]: !cir.eh_token {{.*}}) {
-// CIR: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CIR: %[[CATCH_TOKEN:.*]] = cir.begin_catch default %[[TOKEN]] : !cir.eh_token -> !cir.catch_token
// CIR: cir.cleanup.scope {
// CIR: cir.yield
// CIR: } cleanup all {
@@ -1016,9 +1008,8 @@ 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:.*]] = cir.begin_catch memcopy {{.*}} : !cir.eh_token, %[[E_ADDR]] : !cir.ptr<!rec_CustomError> -> !cir.catch_token
// 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
@@ -1059,9 +1050,9 @@ void call_function_inside_try_catch_with_aggregate_exception_type() {
// LLVM: %[[EXN_OBJ_PHI2:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[EH_SELECTOR_PHI2:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[TOKEN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ_PHI2]])
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %{{.*}}, ptr %[[TOKEN]], i64 4, i1 false)
// 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()
@@ -1131,16 +1122,12 @@ 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
// 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:.*]] = cir.begin_catch reference %[[EH_TOKEN]] : !cir.eh_token, %[[E_ADDR]] : !cir.ptr<!cir.ptr<!cir.ptr<!rec_Record>>> -> !cir.catch_token
// 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 +1140,8 @@ 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: %[[E_ADDR:.*]] = alloca ptr
// LLVM: br label %[[TRY_SCOPE:.*]]
// LLVM: [[TRY_SCOPE]]:
// LLVM: br label %[[TRY_BEGIN:.*]]
@@ -1183,10 +1170,10 @@ void call_function_inside_try_catch_with_ref_ptr_of_record_exception_type() {
// LLVM: %[[EXN_OBJ_PHI2:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[EH_SELECTOR_PHI2:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
// 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 %[[CATCH_BODY:.*]]
+// LLVM: [[CATCH_BODY]]:
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
@@ -1258,10 +1245,8 @@ 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:.*]] = cir.begin_catch load_store %{{.*}} : !cir.eh_token, %[[E_ADDR]] : !cir.ptr<!s64i> -> !cir.catch_token
// 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
@@ -1302,10 +1287,10 @@ void call_function_inside_try_catch_with_exception_member_ptr_type() {
// LLVM: %[[EXN_OBJ_PHI2:.*]] = phi ptr [ %[[EXN_OBJ_PHI1:.*]], %[[DISPATCH:.*]] ]
// LLVM: %[[EH_SELECTOR_PHI2:.*]] = phi i32 [ %[[EH_SELECTOR_PHI1:.*]], %[[DISPATCH:.*]] ]
// 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 %[[CATCH_BODY:.*]]
+// LLVM: [[CATCH_BODY]]:
// LLVM: br label %[[END_CATCH:.*]]
// LLVM: [[END_CATCH]]:
// LLVM: call void @__cxa_end_catch()
diff --git a/clang/test/CIR/IR/catch-param.cir b/clang/test/CIR/IR/catch-param.cir
index 3734917c35877..6f1fb08cb66ae 100644
--- a/clang/test/CIR/IR/catch-param.cir
+++ b/clang/test/CIR/IR/catch-param.cir
@@ -10,7 +10,7 @@ cir.func @begin_catch_inside_catch() {
cir.try {
cir.yield
} catch all (%eh_token : !cir.eh_token) {
- %catch_token, %exception = cir.begin_catch %eh_token : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+ %catch_token = cir.begin_catch default %eh_token : !cir.eh_token -> !cir.catch_token
cir.cleanup.scope {
cir.yield
} cleanup eh {
@@ -28,7 +28,7 @@ cir.func @begin_catch_inside_catch() {
// CHECK: cir.try {
// CHECK: cir.yield
// CHECK: } catch all (%[[EH_TOKEN:.*]]: !cir.eh_token) {
-// CHECK: %[[CATCH_TOKEN:.*]], %[[EXCEPTION:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CHECK: %[[CATCH_TOKEN:.*]] = cir.begin_catch default %[[EH_TOKEN]] : !cir.eh_token -> !cir.catch_token
// CHECK: cir.cleanup.scope {
// CHECK: cir.yield
// CHECK: } cleanup eh {
diff --git a/clang/test/CIR/IR/eh-flat.cir b/clang/test/CIR/IR/eh-flat.cir
index c6799dcda766c..b6aab9099f4bc 100644
--- a/clang/test/CIR/IR/eh-flat.cir
+++ b/clang/test/CIR/IR/eh-flat.cir
@@ -148,26 +148,28 @@ cir.func @cleanup_ops(%eh_token: !cir.eh_token) {
// Test cir.begin_catch and cir.end_catch
cir.func @catch_ops(%eh_token: !cir.eh_token) {
- %catch_token, %exn_ptr = cir.begin_catch %eh_token : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+ %exn_addr = cir.alloca !s32i, !cir.ptr<!s32i>, ["e"] {alignment = 4 : i64}
+ %catch_token = cir.begin_catch load_store %eh_token : !cir.eh_token, %exn_addr : !cir.ptr<!s32i> -> !cir.catch_token
cir.end_catch %catch_token : !cir.catch_token
cir.return
}
// CHECK: cir.func @catch_ops(%arg0: !cir.eh_token) {
-// CHECK: %[[CATCH:.*]], %[[EXN:.*]] = cir.begin_catch %arg0 : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+// CHECK: %[[EXN_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e"] {alignment = 4 : i64}
+// CHECK: %[[CATCH:.*]] = cir.begin_catch load_store %arg0 : !cir.eh_token, %[[EXN_ADDR]] : !cir.ptr<!s32i> -> !cir.catch_token
// CHECK: cir.end_catch %[[CATCH]] : !cir.catch_token
// CHECK: cir.return
// CHECK: }
// Test cir.begin_catch with void pointer (catch all)
cir.func @catch_all_ops(%eh_token: !cir.eh_token) {
- %catch_token, %exn_ptr = cir.begin_catch %eh_token : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+ %catch_token = cir.begin_catch default %eh_token : !cir.eh_token -> !cir.catch_token
cir.end_catch %catch_token : !cir.catch_token
cir.return
}
// CHECK: cir.func @catch_all_ops(%arg0: !cir.eh_token) {
-// CHECK: %[[CATCH:.*]], %[[EXN:.*]] = cir.begin_catch %arg0 : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CHECK: %[[CATCH:.*]] = cir.begin_catch default %arg0 : !cir.eh_token -> !cir.catch_token
// CHECK: cir.end_catch %[[CATCH]] : !cir.catch_token
// CHECK: cir.return
// CHECK: }
@@ -177,6 +179,7 @@ cir.func private @mayThrow() -> ()
cir.func private @destructor() -> ()
cir.func @complete_example() {
+ %exn_addr = cir.alloca !s32i, !cir.ptr<!s32i>, ["e"] {alignment = 4 : i64}
cir.try_call @mayThrow() ^bb1, ^bb2 : () -> ()
^bb1: // Normal return
cir.return
@@ -190,16 +193,17 @@ cir.func @complete_example() {
catch_all : ^catch_all
]
^catch_int:
- %catch_token, %exn_ptr = cir.begin_catch %eh_token : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+ %catch_token = cir.begin_catch load_store %eh_token : !cir.eh_token, %exn_addr : !cir.ptr<!s32i> -> !cir.catch_token
cir.end_catch %catch_token : !cir.catch_token
cir.return
^catch_all:
- %catch_token2, %exn_ptr2 = cir.begin_catch %eh_token : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+ %catch_token2= cir.begin_catch default %eh_token : !cir.eh_token -> !cir.catch_token
cir.end_catch %catch_token2 : !cir.catch_token
cir.return
}
// CHECK: cir.func @complete_example()
+// CHECK: %[[EXN_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e"]
// CHECK: cir.try_call @mayThrow() ^bb1, ^bb2 : () -> ()
// CHECK: ^bb1:
// CHECK: cir.return
@@ -213,11 +217,11 @@ cir.func @complete_example() {
// CHECK: catch_all : ^bb4
// CHECK: ]
// CHECK: ^bb3:
-// CHECK: %[[CATCH1:.*]], %{{.*}} = cir.begin_catch %[[EH]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+// CHECK: %[[CATCH1:.*]] = cir.begin_catch load_store %[[EH]] : !cir.eh_token, %[[EXN_ADDR]] : !cir.ptr<!s32i> -> !cir.catch_token
// CHECK: cir.end_catch %[[CATCH1]] : !cir.catch_token
// CHECK: cir.return
// CHECK: ^bb4:
-// CHECK: %[[CATCH2:.*]], %{{.*}} = cir.begin_catch %[[EH]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CHECK: %[[CATCH2:.*]] = cir.begin_catch default %[[EH]] : !cir.eh_token -> !cir.catch_token
// CHECK: cir.end_catch %[[CATCH2]] : !cir.catch_token
// CHECK: cir.return
// CHECK: }
diff --git a/clang/test/CIR/IR/try-catch.cir b/clang/test/CIR/IR/try-catch.cir
index 203ec340d7f6e..d865038198bf5 100644
--- a/clang/test/CIR/IR/try-catch.cir
+++ b/clang/test/CIR/IR/try-catch.cir
@@ -14,7 +14,7 @@ cir.func dso_local @empty_try_block_with_catch_all() {
cir.try {
cir.yield
} catch all (%eh_token : !cir.eh_token) {
- %catch_token, %0 = cir.begin_catch %eh_token : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+ %catch_token= cir.begin_catch default %eh_token : !cir.eh_token -> !cir.catch_token
cir.cleanup.scope {
cir.yield
} cleanup eh {
@@ -32,7 +32,7 @@ cir.func dso_local @empty_try_block_with_catch_all() {
// CHECK: cir.try {
// CHECK: cir.yield
// CHECK: } catch all (%[[EH_TOKEN:.*]]: !cir.eh_token) {
-// CHECK: %[[CATCH_TOKEN:.*]], %[[EXN_PTR:.*]] = cir.begin_catch %[[EH_TOKEN]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+// CHECK: %[[CATCH_TOKEN:.*]] = cir.begin_catch default %[[EH_TOKEN]] : !cir.eh_token -> !cir.catch_token
// CHECK: cir.cleanup.scope {
// CHECK: cir.yield
// CHECK: } cleanup eh {
@@ -68,11 +68,13 @@ cir.func dso_local @empty_try_block_with_catch_unwind() {
// CHECK: }
cir.func dso_local @empty_try_block_with_catch_ist() {
+ %exn_addr = cir.alloca !s32i, !cir.ptr<!s32i>, ["e"] {alignment = 4 : i64}
+ %exn_addr_2 = cir.alloca !cir.ptr<!u8i>, !cir.ptr<!cir.ptr<!u8i>>, ["e2"] {alignment = 4 : i64}
cir.scope {
cir.try {
cir.yield
} catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] (%eh_token : !cir.eh_token) {
- %catch_token, %0 = cir.begin_catch %eh_token : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+ %catch_token = cir.begin_catch load_store %eh_token : !cir.eh_token, %exn_addr : !cir.ptr<!s32i> -> !cir.catch_token
cir.cleanup.scope {
cir.yield
} cleanup eh {
@@ -81,7 +83,7 @@ cir.func dso_local @empty_try_block_with_catch_ist() {
}
cir.yield
} catch [type #cir.global_view<@_ZTIPKc> : !cir.ptr<!u8i>] (%eh_token_1 : !cir.eh_token) {
- %catch_token_1, %1 = cir.begin_catch %eh_token_1 : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.ptr<!u8i>>)
+ %catch_token_1 = cir.begin_catch store %eh_token_1 : !cir.eh_token, %exn_addr_2 : !cir.ptr<!cir.ptr<!u8i>> -> !cir.catch_token
cir.cleanup.scope {
cir.yield
} cleanup eh {
@@ -97,11 +99,13 @@ cir.func dso_local @empty_try_block_with_catch_ist() {
}
// CHECK: cir.func dso_local @empty_try_block_with_catch_ist() {
+// CHECK: %[[EXN_ADDR1:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e"]
+// CHECK: %[[EXN_ADDR2:.*]] = cir.alloca !cir.ptr<!u8i>, !cir.ptr<!cir.ptr<!u8i>>
// CHECK: cir.scope {
// CHECK: cir.try {
// CHECK: cir.yield
// CHECK: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>] (%[[EH1:.*]]: !cir.eh_token) {
-// CHECK: %[[CT1:.*]], %{{.*}} = cir.begin_catch %[[EH1]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!s32i>)
+// CHECK: %[[CT1:.*]] = cir.begin_catch load_store %[[EH1]] : !cir.eh_token, %[[EXN_ADDR1]] : !cir.ptr<!s32i> -> !cir.catch_token
// CHECK: cir.cleanup.scope {
// CHECK: cir.yield
// CHECK: } cleanup eh {
@@ -110,7 +114,7 @@ cir.func dso_local @empty_try_block_with_catch_ist() {
// CHECK: }
// CHECK: cir.yield
// CHECK: } catch [type #cir.global_view<@_ZTIPKc> : !cir.ptr<!u8i>] (%[[EH2:.*]]: !cir.eh_token) {
-// CHECK: %[[CT2:.*]], %{{.*}} = cir.begin_catch %[[EH2]] : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!cir.ptr<!u8i>>)
+// CHECK: %[[CT2:.*]] = cir.begin_catch store %[[EH2]] : !cir.eh_token, %[[EXN_ADDR2]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.catch_token
// CHECK: cir.cleanup.scope {
// CHECK: cir.yield
// CHECK: } cleanup eh {
>From 1868e1146abcecd649a601c7366a27b2e07e7711 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Fri, 10 Apr 2026 19:55:04 +0200
Subject: [PATCH 2/2] Move initCatchParam out of CIRGenItaniumCXXABI
---
clang/lib/CIR/CodeGen/CIRGenCXXABI.h | 4 -
clang/lib/CIR/CodeGen/CIRGenException.cpp | 200 +++++++++++++++++-
clang/lib/CIR/CodeGen/CIRGenFunction.h | 3 +
clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 200 ------------------
4 files changed, 202 insertions(+), 205 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..e2bc3aa75d784 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -273,6 +273,204 @@ 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::Value exnPtr,
+ mlir::Type exnPtrTy, bool endMightThrow,
+ cir::BeginCatchKind kind = cir::BeginCatchKind::Default) {
+ auto catchTokenTy = cir::CatchTokenType::get(cgf.getBuilder().getContext());
+ auto beginCatch = cir::BeginCatchOp::create(
+ cgf.getBuilder(), cgf.getBuilder().getUnknownLoc(), catchTokenTy, ehToken,
+ exnPtr, kind);
+
+ 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();
+
+ callBeginCatch(cgf, ehToken, paramAddr.getPointer(), cirCatchTy,
+ endCatchMightThrow, cir::BeginCatchKind::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 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;
+ }
+
+ // 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()) {
+ callBeginCatch(cgf, ehToken, paramAddr.getPointer(), cirCatchTy,
+ /*endMightThrow=*/false, cir::BeginCatchKind::Store);
+ 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:
+ 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);
+ callBeginCatch(cgf, ehToken, paramAddr.getPointer(),
+ cgf.getBuilder().getPointerTo(cirCatchTy),
+ /*endMightThrow=*/false, cir::BeginCatchKind::LoadStore);
+ return;
+ }
+
+ assert(isa<RecordType>(catchType) && "unexpected catch type!");
+
+ // 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);
+ callBeginCatch(cgf, ehToken, paramAddr.getPointer(), cirCatchPtrTy,
+ /*endMightThrow=*/true, cir::BeginCatchKind::Memcopy);
+ 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(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);
+}
+
mlir::LogicalResult
CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s,
cxxTryBodyEmitter &bodyCallback) {
@@ -384,7 +582,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(*this, 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 88c7996eab569..aa25ad9ca5905 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1635,6 +1635,9 @@ class CIRGenFunction : public CIRGenTypeCache {
virtual ~cxxTryBodyEmitter() = default;
};
+ void emitBeginCatch(CIRGenFunction &cgf, 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 471c48da8d2b8..7e48277688473 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -82,8 +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 {
@@ -2492,204 +2490,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::Value exnPtr,
- mlir::Type exnPtrTy, bool endMightThrow,
- cir::BeginCatchKind kind = cir::BeginCatchKind::Default) {
- auto catchTokenTy = cir::CatchTokenType::get(cgf.getBuilder().getContext());
- auto beginCatch = cir::BeginCatchOp::create(
- cgf.getBuilder(), cgf.getBuilder().getUnknownLoc(), catchTokenTy, ehToken,
- exnPtr, kind);
-
- 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();
-
- callBeginCatch(cgf, ehToken, paramAddr.getPointer(), cirCatchTy,
- endCatchMightThrow, cir::BeginCatchKind::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 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;
- }
-
- // 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()) {
- callBeginCatch(cgf, ehToken, paramAddr.getPointer(), cirCatchTy,
- /*endMightThrow=*/false, cir::BeginCatchKind::Store);
- 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:
- 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);
- callBeginCatch(cgf, ehToken, paramAddr.getPointer(),
- cgf.getBuilder().getPointerTo(cirCatchTy),
- /*endMightThrow=*/false, cir::BeginCatchKind::LoadStore);
- return;
- }
-
- assert(isa<RecordType>(catchType) && "unexpected catch type!");
-
- // 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);
- callBeginCatch(cgf, ehToken, paramAddr.getPointer(), cirCatchPtrTy,
- /*endMightThrow=*/true, cir::BeginCatchKind::Memcopy);
- 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);
More information about the cfe-commits
mailing list