[clang] [CIR] Handle landing pads in nested regions in EHABILowering (PR #230509)
Morris Hafner via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 9 06:51:11 PDT 2026
https://github.com/mmha created https://github.com/llvm/llvm-project/pull/230509
FlattenCFG retains `omp.parallel` regions, so landing pads for a `try/catch` inside a `#pragma omp parallel` must be created in the parallel region.
EHABILowering currently only erases `!cir.eh_token` block arguments in the top level function blocks and skips over nests like a parallel region.
Erase the token arguments recursively instead. Create the terminate landing pad in the region of the `catch` parameter.
That enables `catch(...)` inside a parallel region. Add a diagnostic for `catch(E)` in DirectToLLVM lowering. This requires the outliner to support `llvm.eh.typeid.for` (see #38893).
>From 15db9119caddb620b7eb7f2ce9940780e3e70d50 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhafner at nvidia.com>
Date: Fri, 9 Oct 2026 13:46:10 +0000
Subject: [PATCH] [CIR] Handle landing pads in nested regions in EHABILowering
FlattenCFG retains `omp.parallel` regions, so landing pads for a `try/catch` inside
a `#pragma omp parallel` must be created in the parallel region.
EHABILowering currently only erases `!cir.eh_token` block arguments in the top
level function blocks and skips over nests like a parallel region.
Erase the token arguments recursively instead. Create the terminate landing pad in the region of the `catch` parameter.
That enables `catch(...)` inside a parallel region. Add a diagnostic
for `catch(E)` in DirectToLLVM lowering. This requires the outliner to support
`llvm.eh.typeid.for` (see #38893).
Co-Authored-By: Claude Opus 5.5 <noreply at anthropic.com>
---
.../CIR/Dialect/Transforms/EHABILowering.cpp | 35 ++--
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 4 +
clang/test/CIR/CodeGenOpenMP/try-catch.cpp | 154 ++++++++++++++++++
.../eh-abi-lowering-construct-catch.cir | 100 +++++++++++-
.../Transforms/eh-abi-lowering-itanium.cir | 48 +++++-
5 files changed, 317 insertions(+), 24 deletions(-)
create mode 100644 clang/test/CIR/CodeGenOpenMP/try-catch.cpp
diff --git a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
index 4b765b1f75fca7..278ac8109e6634 100644
--- a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
@@ -145,7 +145,7 @@ class ItaniumEHLowering : public EHABILowering {
void ensureCxaThrowDecl(mlir::Location loc);
void ensureCxaRethrowDecl(mlir::Location loc);
void ensureCxaCallUnexpectedDecl(mlir::Location loc);
- mlir::Block *buildTerminateBlock(cir::FuncOp funcOp, mlir::Location loc);
+ mlir::Block *buildTerminateBlock(mlir::Region ®ion, mlir::Location loc);
mlir::FailureOr<cir::FuncOp>
resolveCatchCopyThunk(cir::ConstructCatchParamOp op);
mlir::LogicalResult lowerFunc(cir::FuncOp funcOp);
@@ -301,15 +301,16 @@ void ItaniumEHLowering::ensureCxaCallUnexpectedDecl(mlir::Location loc) {
mod, loc, "__cxa_call_unexpected", unexpectedFuncTy);
}
-/// Create a terminate landing pad block at the end of the specified function.
-mlir::Block *ItaniumEHLowering::buildTerminateBlock(cir::FuncOp funcOp,
+/// Create a terminate landing pad block at the end of \p region of the calls
+/// that unwind the block. Usually that is the function body but can also be
+/// a omp.parallel region nest.
+mlir::Block *ItaniumEHLowering::buildTerminateBlock(mlir::Region ®ion,
mlir::Location loc) {
// TODO(cir): set the runtime calling convention on the runtime calls below.
assert(!cir::MissingFeatures::opFuncCallingConv());
assert(clangCallTerminateFunc &&
"ensureClangCallTerminate must run before buildTerminateBlock");
- mlir::Region &body = funcOp.getRegion();
- mlir::Block *terminateBlock = builder.createBlock(&body, body.end());
+ mlir::Block *terminateBlock = builder.createBlock(®ion, region.end());
auto inflight = cir::EhInflightOp::create(
builder, loc, /*cleanup=*/false, /*catch_all=*/true,
/*catch_type_list=*/mlir::ArrayAttr{},
@@ -441,13 +442,13 @@ mlir::LogicalResult ItaniumEHLowering::lowerFunc(cir::FuncOp funcOp) {
}
// Remove the !cir.eh_token block arguments that were replaced by (ptr, u32)
- // pairs. Iterate in reverse to preserve argument indices during removal.
- for (mlir::Block &block : funcOp.getBody()) {
- for (int i = block.getNumArguments() - 1; i >= 0; --i) {
- if (mlir::isa<cir::EhTokenType>(block.getArgument(i).getType()))
- block.eraseArgument(i);
- }
- }
+ // pairs. The landing pads can be in nested regions, so visit every block in
+ // the function recursively.
+ funcOp.walk([](mlir::Block *block) {
+ block->eraseArguments([](mlir::BlockArgument arg) {
+ return mlir::isa<cir::EhTokenType>(arg.getType());
+ });
+ });
// Lower any cir.init_catch_param ops in this function. These materialize
// the catch parameter local from the (already lowered) begin_catch result,
@@ -898,6 +899,7 @@ ItaniumEHLowering::lowerConstructCatchParam(cir::ConstructCatchParamOp op,
if (!callOp.getNothrow())
throwingCalls.push_back(callOp);
}
+ mlir::Region ®ion = *op->getParentRegion();
op.erase();
if (throwingCalls.empty())
@@ -905,14 +907,11 @@ ItaniumEHLowering::lowerConstructCatchParam(cir::ConstructCatchParamOp op,
// All calls in the copy (which is usually just a single call) need to
// unwind to a terminate block if it throws an exception.
+ mlir::Block *terminateBlock =
+ buildTerminateBlock(region, throwingCalls.front().getLoc());
mlir::IRRewriter rewriter(builder);
- mlir::Block *terminateBlock = nullptr;
- for (cir::CallOp call : throwingCalls) {
- if (!terminateBlock)
- terminateBlock = buildTerminateBlock(call->getParentOfType<cir::FuncOp>(),
- call.getLoc());
+ for (cir::CallOp call : throwingCalls)
cir::replaceCallWithTryCall(call, terminateBlock, call.getLoc(), rewriter);
- }
return mlir::success();
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 7a1e61b5262642..a19dd4b3069922 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -4927,6 +4927,10 @@ mlir::LogicalResult CIRToLLVMResumeFlatOpLowering::matchAndRewrite(
mlir::LogicalResult CIRToLLVMEhTypeIdOpLowering::matchAndRewrite(
cir::EhTypeIdOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
+ if (op->getParentOfType<mlir::omp::ParallelOp>())
+ return op.emitError("catching a specific exception type inside an OpenMP "
+ "parallel region is not yet implemented");
+
mlir::Value addrOp = mlir::LLVM::AddressOfOp::create(
rewriter, op.getLoc(),
mlir::LLVM::LLVMPointerType::get(rewriter.getContext()),
diff --git a/clang/test/CIR/CodeGenOpenMP/try-catch.cpp b/clang/test/CIR/CodeGenOpenMP/try-catch.cpp
new file mode 100644
index 00000000000000..86ee94a1eb16ed
--- /dev/null
+++ b/clang/test/CIR/CodeGenOpenMP/try-catch.cpp
@@ -0,0 +1,154 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fopenmp -fcxx-exceptions -fexceptions -fclangir -emit-cir %s -o %t.parallel.cir
+// RUN: FileCheck --input-file=%t.parallel.cir %s --check-prefix=PARALLEL-CIR
+// RUN: cir-opt -cir-hoist-allocas -cir-flatten-cfg -cir-eh-abi-lowering %t.parallel.cir -o %t.parallel.eh.cir
+// RUN: FileCheck --input-file=%t.parallel.eh.cir %s --check-prefix=PARALLEL-EH --implicit-check-not='!cir.eh_token'
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fopenmp -fcxx-exceptions -fexceptions -fclangir -emit-llvm -DOMIT_PARALLEL_TYPED_CATCH %s -o %t.parallel-cir.ll
+// RUN: FileCheck --input-file=%t.parallel-cir.ll %s --check-prefix=PARALLEL-LLVM
+// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fopenmp -fcxx-exceptions -fexceptions -fclangir -emit-llvm %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=PARALLEL-TYPED-ERR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fopenmp -fcxx-exceptions -fexceptions -emit-llvm %s -o %t.parallel.ll
+// RUN: FileCheck --input-file=%t.parallel.ll %s --check-prefix=PARALLEL-OGCG
+
+void mayThrow();
+
+struct MyException {
+ MyException();
+ MyException(const MyException &);
+ ~MyException();
+ int get();
+};
+
+// Test whether landing pads are in the omp.parallel region, not in the function body.
+// Also test whether EH ABI lowering performs its lowering within those regions.
+
+void catch_all_in_parallel() {
+#pragma omp parallel
+ {
+ try {
+ mayThrow();
+ } catch (...) {
+ }
+ }
+}
+
+// PARALLEL-CIR-LABEL: cir.func {{.*}} @_Z21catch_all_in_parallelv()
+// PARALLEL-CIR: omp.parallel {
+// PARALLEL-CIR: cir.try {
+// PARALLEL-CIR: cir.call @_Z8mayThrowv()
+// PARALLEL-CIR: } catch all (%{{.*}}: !cir.eh_token {{.*}}) {
+// PARALLEL-CIR: omp.terminator
+
+// PARALLEL-EH-LABEL: cir.func {{.*}} @_Z21catch_all_in_parallelv()
+// PARALLEL-EH: omp.parallel {
+// PARALLEL-EH: cir.try_call @_Z8mayThrowv() ^{{.*}}, ^[[LPAD:bb[0-9]+]]
+// PARALLEL-EH: ^[[LPAD]]:
+// PARALLEL-EH: %[[EXN:.*]], %[[TID:.*]] = cir.eh.inflight_exception catch_all
+// PARALLEL-EH: cir.br ^[[DISPATCH:bb[0-9]+]](%[[EXN]], %[[TID]] : !cir.ptr<!void>, !u32i)
+// PARALLEL-EH: ^[[DISPATCH]](%[[D_EXN:.*]]: !cir.ptr<!void>, %[[D_TID:.*]]: !u32i):
+// PARALLEL-EH: cir.br ^[[CATCH:bb[0-9]+]](%[[D_EXN]], %[[D_TID]] : !cir.ptr<!void>, !u32i)
+// PARALLEL-EH: ^[[CATCH]](%[[C_EXN:.*]]: !cir.ptr<!void>, %{{.*}}: !u32i):
+// PARALLEL-EH: cir.call @__cxa_begin_catch(%[[C_EXN]])
+// PARALLEL-EH: cir.call @__cxa_end_catch()
+// PARALLEL-EH: omp.terminator
+// PARALLEL-EH-NEXT: }
+// PARALLEL-EH-NEXT: cir.return
+
+// PARALLEL-LLVM-LABEL: define dso_local void @_Z21catch_all_in_parallelv()
+// PARALLEL-LLVM: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @{{.*}}, i32 0, ptr @_Z21catch_all_in_parallelv..omp_par)
+
+// PARALLEL-LLVM-LABEL: define internal void @_Z21catch_all_in_parallelv..omp_par(
+// PARALLEL-LLVM-SAME: personality ptr @__gxx_personality_v0
+// PARALLEL-LLVM: invoke void @_Z8mayThrowv()
+// PARALLEL-LLVM-NEXT: to label %{{.*}} unwind label %[[LPAD:.*]]
+// PARALLEL-LLVM: [[LPAD]]:
+// PARALLEL-LLVM-NEXT: %{{.*}} = landingpad { ptr, i32 }
+// PARALLEL-LLVM-NEXT: catch ptr null
+// PARALLEL-LLVM: call ptr @__cxa_begin_catch(ptr %{{.*}})
+// FIXME: Classic CodeGen invokes __cxa_end_catch with a terminate landing pad.
+// PARALLEL-LLVM: call void @__cxa_end_catch()
+
+// PARALLEL-OGCG-LABEL: define dso_local void @_Z21catch_all_in_parallelv()
+// PARALLEL-OGCG: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @{{.*}}, i32 0, ptr @_Z21catch_all_in_parallelv.omp_outlined)
+
+// PARALLEL-OGCG-LABEL: define internal void @_Z21catch_all_in_parallelv.omp_outlined(
+// PARALLEL-OGCG-SAME: personality ptr @__gxx_personality_v0
+// PARALLEL-OGCG: invoke void @_Z8mayThrowv()
+// PARALLEL-OGCG-NEXT: to label %{{.*}} unwind label %[[LPAD:.*]]
+// PARALLEL-OGCG: [[LPAD]]:
+// PARALLEL-OGCG-NEXT: %{{.*}} = landingpad { ptr, i32 }
+// PARALLEL-OGCG-NEXT: catch ptr null
+// PARALLEL-OGCG: call ptr @__cxa_begin_catch(ptr %{{.*}})
+// PARALLEL-OGCG: invoke void @__cxa_end_catch()
+
+// PARALLEL-TYPED-ERR: try-catch.cpp:[[#@LINE+5]]:5: error: catching a specific exception type inside an OpenMP parallel region is not yet implemented
+#ifndef OMIT_PARALLEL_TYPED_CATCH
+void catch_by_copy_in_parallel() {
+#pragma omp parallel
+ {
+ try {
+ mayThrow();
+ } catch (MyException e) {
+ }
+ }
+}
+#endif
+
+// PARALLEL-CIR-LABEL: cir.func {{.*}} @_Z25catch_by_copy_in_parallelv()
+// PARALLEL-CIR: omp.parallel {
+// PARALLEL-CIR: %[[E:.*]] = cir.alloca "e"
+// PARALLEL-CIR: cir.try {
+// PARALLEL-CIR: cir.call @_Z8mayThrowv()
+// PARALLEL-CIR: } catch [type #cir.global_view<@_ZTI11MyException> : !cir.ptr<!u8i>] (%[[TOK:.*]]: !cir.eh_token {{.*}}) {
+// PARALLEL-CIR: cir.construct_catch_param non_trivial_copy %[[TOK]] to %[[E]] using @__clang_cir_catch_copy__ZTS11MyException
+// PARALLEL-CIR: } unwind (%[[UTOK:.*]]: !cir.eh_token {{.*}}) {
+// PARALLEL-CIR: cir.resume %[[UTOK]] : !cir.eh_token
+// PARALLEL-CIR: omp.terminator
+
+// The copy constructor can throw, so it unwinds to a terminate landing pad,
+// which must be in the omp.parallel region with the call.
+// PARALLEL-EH-LABEL: cir.func {{.*}} @_Z25catch_by_copy_in_parallelv()
+// PARALLEL-EH: omp.parallel {
+// PARALLEL-EH: %[[E:.*]] = cir.alloca "e"
+// PARALLEL-EH: cir.try_call @_Z8mayThrowv() ^{{.*}}, ^[[LPAD:bb[0-9]+]]
+// PARALLEL-EH: ^[[LPAD]]:
+// PARALLEL-EH: %[[EXN:.*]], %[[TID:.*]] = cir.eh.inflight_exception [@_ZTI11MyException]
+// PARALLEL-EH: cir.br ^[[DISPATCH:bb[0-9]+]](%[[EXN]], %[[TID]] : !cir.ptr<!void>, !u32i)
+// PARALLEL-EH: ^[[DISPATCH]](%[[D_EXN:.*]]: !cir.ptr<!void>, %[[D_TID:.*]]: !u32i):
+// PARALLEL-EH: cir.br ^[[CMP:bb[0-9]+]](%[[D_EXN]], %[[D_TID]] : !cir.ptr<!void>, !u32i)
+// PARALLEL-EH: ^[[CMP]](%[[CMP_EXN:.*]]: !cir.ptr<!void>, %[[CMP_TID:.*]]: !u32i):
+// PARALLEL-EH: %[[TYPEID:.*]] = cir.eh.typeid @_ZTI11MyException
+// PARALLEL-EH: %[[MATCH:.*]] = cir.cmp eq %[[CMP_TID]], %[[TYPEID]] : !u32i
+// PARALLEL-EH: cir.brcond %[[MATCH]] ^[[CATCH:bb[0-9]+]](%[[CMP_EXN]], %[[CMP_TID]] : !cir.ptr<!void>, !u32i), ^[[RESUME:bb[0-9]+]](%[[CMP_EXN]], %[[CMP_TID]] : !cir.ptr<!void>, !u32i)
+// PARALLEL-EH: ^[[CATCH]](%[[C_EXN:.*]]: !cir.ptr<!void>, %{{.*}}: !u32i):
+// PARALLEL-EH: %[[EXN_OBJ:.*]] = cir.call @__cxa_get_exception_ptr(%[[C_EXN]]) nothrow
+// PARALLEL-EH: %[[EXN_E:.*]] = cir.cast bitcast %[[EXN_OBJ]] : !cir.ptr<!u8i> -> !cir.ptr<!rec_MyException>
+// PARALLEL-EH: cir.try_call @_ZN11MyExceptionC1ERKS_(%[[E]], %[[EXN_E]]) ^[[COPIED:bb[0-9]+]], ^[[TERMINATE:bb[0-9]+]]
+// PARALLEL-EH: ^[[COPIED]]:
+// PARALLEL-EH: cir.call @__cxa_begin_catch(%[[C_EXN]])
+// PARALLEL-EH: cir.call @_ZN11MyExceptionD1Ev(%[[E]]) nothrow
+// PARALLEL-EH: cir.call @__cxa_end_catch()
+// FIXME: Classic CodeGen calls __clang_call_terminate for an unmatched
+// exception instead of resuming it out of the parallel region.
+// PARALLEL-EH: ^[[RESUME]](%[[R_EXN:.*]]: !cir.ptr<!void>, %[[R_TID:.*]]: !u32i):
+// PARALLEL-EH: cir.resume.flat %[[R_EXN]], %[[R_TID]]
+// PARALLEL-EH: omp.terminator
+// PARALLEL-EH: ^[[TERMINATE]]:
+// PARALLEL-EH-NEXT: %[[T_EXN:.*]], %{{.*}} = cir.eh.inflight_exception catch_all
+// PARALLEL-EH-NEXT: cir.call @__clang_call_terminate(%[[T_EXN]]) nothrow {noreturn}
+// PARALLEL-EH-NEXT: cir.unreachable
+// PARALLEL-EH-NEXT: }
+// PARALLEL-EH-NEXT: cir.return
+
+// PARALLEL-OGCG-LABEL: define internal void @_Z25catch_by_copy_in_parallelv.omp_outlined(
+// PARALLEL-OGCG-SAME: personality ptr @__gxx_personality_v0
+// PARALLEL-OGCG: invoke void @_Z8mayThrowv()
+// PARALLEL-OGCG: landingpad { ptr, i32 }
+// PARALLEL-OGCG-NEXT: catch ptr @_ZTI11MyException
+// PARALLEL-OGCG-NEXT: catch ptr null
+// PARALLEL-OGCG: call ptr @__cxa_get_exception_ptr(ptr %{{.*}})
+// PARALLEL-OGCG: invoke void @_ZN11MyExceptionC1ERKS_(ptr {{.*}} %e, ptr {{.*}})
+// PARALLEL-OGCG-NEXT: to label %{{.*}} unwind label %[[TERMINATE:.*]]
+// PARALLEL-OGCG: [[TERMINATE]]:
+// PARALLEL-OGCG-NEXT: %[[T_LP:.*]] = landingpad { ptr, i32 }
+// PARALLEL-OGCG-NEXT: catch ptr null
+// PARALLEL-OGCG-NEXT: %[[T_EXN:.*]] = extractvalue { ptr, i32 } %[[T_LP]], 0
+// PARALLEL-OGCG-NEXT: call void @__clang_call_terminate(ptr %[[T_EXN]])
diff --git a/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch.cir b/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch.cir
index 25c8e5695c0d5b..2f422868e890b7 100644
--- a/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch.cir
+++ b/clang/test/CIR/Transforms/eh-abi-lowering-construct-catch.cir
@@ -1,5 +1,5 @@
// RUN: cir-opt %s -cir-eh-abi-lowering -o %t.cir
-// RUN: FileCheck --input-file=%t.cir %s
+// RUN: FileCheck --input-file=%t.cir %s --implicit-check-not='!cir.eh_token'
// Test the Itanium ABI lowering of cir.construct_catch_param.
//
@@ -13,8 +13,8 @@
// thunk's body in place; any potentially-throwing `cir.call` becomes a
// `cir.try_call` whose unwind path runs `__clang_call_terminate`
// (Itanium's terminate scope around the catch-parameter copy). The
-// terminate block is appended at the end of the function as a cold
-// landing pad.
+// terminate block is appended at the end of the enclosing region (the
+// function body here) as a cold landing pad.
// - Drop any catch-copy thunks that end up uncalled after lowering.
!s8i = !cir.int<s, 8>
@@ -111,8 +111,8 @@ cir.func @test_basic_construct_catch() {
// CHECK: ^[[RETURN]]:
// CHECK: cir.return
//
-// Terminate scope appended at the end of the function: control reaches it
-// only if the catch-parameter copy throws.
+// Terminate scope appended at the end of the enclosing region, here the
+// function body: control reaches it only if the catch-parameter copy throws.
// CHECK: ^[[TERMINATE]]:
// CHECK: %[[T_EXN:.*]], %{{.*}} = cir.eh.inflight_exception catch_all
// CHECK: cir.call @__clang_call_terminate(%[[T_EXN]]){{.*}}noreturn
@@ -206,6 +206,96 @@ cir.func linkonce_odr hidden @__clang_cir_catch_copy__ZTS1E_unused(
cir.return
}
+//===----------------------------------------------------------------------===//
+// Case 4: catch (E) with a throwing copy in the function body and in a nested
+// omp.parallel region.
+//===----------------------------------------------------------------------===//
+
+cir.func @test_catch_copy_in_body_and_parallel() {
+ %0 = cir.alloca "e" align(1) : !cir.ptr<!rec_E>
+ cir.try_call @_Z8mayThrowv() ^bb1, ^bb2 : () -> ()
+^bb1:
+ cir.br ^bb6
+^bb2:
+ %1 = cir.eh.initiate : !cir.eh_token
+ cir.br ^bb3(%1 : !cir.eh_token)
+^bb3(%eh_token: !cir.eh_token):
+ cir.eh.dispatch %eh_token : !cir.eh_token [
+ catch(#cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>) : ^bb4,
+ unwind : ^bb5
+ ]
+^bb4(%eh_token.1: !cir.eh_token):
+ cir.construct_catch_param non_trivial_copy %eh_token.1 to %0
+ using @__clang_cir_catch_copy__ZTS1E : !cir.ptr<!rec_E>
+ %ct, %exn = cir.begin_catch %eh_token.1
+ : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+ cir.call @_ZN1ED1Ev(%0) nothrow : (!cir.ptr<!rec_E>) -> ()
+ cir.end_catch %ct : !cir.catch_token
+ cir.br ^bb6
+^bb5(%eh_token.2: !cir.eh_token):
+ cir.resume %eh_token.2 : !cir.eh_token
+^bb6:
+ omp.parallel {
+ %2 = cir.alloca "e" align(1) : !cir.ptr<!rec_E>
+ cir.try_call @_Z8mayThrowv() ^bb1, ^bb2 : () -> ()
+ ^bb1:
+ cir.br ^bb6
+ ^bb2:
+ %3 = cir.eh.initiate : !cir.eh_token
+ cir.br ^bb3(%3 : !cir.eh_token)
+ ^bb3(%eh_token.3: !cir.eh_token):
+ cir.eh.dispatch %eh_token.3 : !cir.eh_token [
+ catch(#cir.global_view<@_ZTI1E> : !cir.ptr<!u8i>) : ^bb4,
+ unwind : ^bb5
+ ]
+ ^bb4(%eh_token.4: !cir.eh_token):
+ cir.construct_catch_param non_trivial_copy %eh_token.4 to %2
+ using @__clang_cir_catch_copy__ZTS1E : !cir.ptr<!rec_E>
+ %ct.1, %exn.1 = cir.begin_catch %eh_token.4
+ : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+ cir.call @_ZN1ED1Ev(%2) nothrow : (!cir.ptr<!rec_E>) -> ()
+ cir.end_catch %ct.1 : !cir.catch_token
+ cir.br ^bb6
+ ^bb5(%eh_token.5: !cir.eh_token):
+ cir.resume %eh_token.5 : !cir.eh_token
+ ^bb6:
+ omp.terminator
+ }
+ cir.return
+}
+
+// CHECK-LABEL: cir.func @test_catch_copy_in_body_and_parallel()
+// CHECK-SAME: personality(@__gxx_personality_v0)
+// CHECK: %[[E:.*]] = cir.alloca "e"
+// CHECK: cir.try_call @_Z8mayThrowv() ^{{bb[0-9]+}}, ^[[UNWIND:bb[0-9]+]]
+// CHECK: ^[[UNWIND]]:
+// CHECK: cir.eh.inflight_exception [@_ZTI1E]
+// CHECK: cir.call @__cxa_get_exception_ptr
+// CHECK: cir.try_call @_ZN1EC1ERKS_(%[[E]], %{{.*}}) ^{{bb[0-9]+}}, ^[[TERMINATE:bb[0-9]+]]
+// CHECK: cir.resume.flat
+//
+// CHECK: omp.parallel {
+// CHECK: %[[P_E:.*]] = cir.alloca "e"
+// CHECK: cir.try_call @_Z8mayThrowv() ^{{bb[0-9]+}}, ^[[P_UNWIND:bb[0-9]+]]
+// CHECK: ^[[P_UNWIND]]:
+// CHECK: cir.eh.inflight_exception [@_ZTI1E]
+// CHECK: cir.call @__cxa_get_exception_ptr
+// CHECK: cir.try_call @_ZN1EC1ERKS_(%[[P_E]], %{{.*}}) ^{{bb[0-9]+}}, ^[[P_TERMINATE:bb[0-9]+]]
+// CHECK: cir.resume.flat
+// CHECK: omp.terminator
+// CHECK: ^[[P_TERMINATE]]:
+// CHECK-NEXT: %[[P_T_EXN:.*]], %{{.*}} = cir.eh.inflight_exception catch_all
+// CHECK-NEXT: cir.call @__clang_call_terminate(%[[P_T_EXN]]) nothrow {noreturn}
+// CHECK-NEXT: cir.unreachable
+// CHECK-NEXT: }
+// CHECK-NEXT: cir.return
+//
+// CHECK: ^[[TERMINATE]]:
+// CHECK-NEXT: %[[T_EXN:.*]], %{{.*}} = cir.eh.inflight_exception catch_all
+// CHECK-NEXT: cir.call @__clang_call_terminate(%[[T_EXN]]) nothrow {noreturn}
+// CHECK-NEXT: cir.unreachable
+// CHECK-NEXT: }
+
// All three catch-copy thunks above (basic, shared, unused) are unreferenced
// after inlining and must be erased by the lowering pass.
// CHECK-NOT: cir.eh.catch_copy_thunk
diff --git a/clang/test/CIR/Transforms/eh-abi-lowering-itanium.cir b/clang/test/CIR/Transforms/eh-abi-lowering-itanium.cir
index 06bae1fbdc5bcc..ba230250c18cc3 100644
--- a/clang/test/CIR/Transforms/eh-abi-lowering-itanium.cir
+++ b/clang/test/CIR/Transforms/eh-abi-lowering-itanium.cir
@@ -1,5 +1,5 @@
// RUN: cir-opt %s -cir-eh-abi-lowering -o %t.cir
-// RUN: FileCheck --input-file=%t.cir %s
+// RUN: FileCheck --input-file=%t.cir %s --implicit-check-not='!cir.eh_token'
// Test Itanium ABI lowering of flattened CIR exception handling operations.
// The input is the form produced by cir-flatten-cfg, and the output should
@@ -549,6 +549,52 @@ cir.func @test_eh_terminate() {
// CHECK: cir.call @__clang_call_terminate(%[[T_EXN]]) nothrow {noreturn}
// CHECK: cir.unreachable
+// Test: catch (...) inside omp.parallel. The EH token arguments in nested
+// blocks must be replaced by (ptr, u32) pairs, just like top-level blocks.
+
+cir.func @test_catch_all_in_parallel() {
+ omp.parallel {
+ cir.try_call @mayThrow() ^bb1, ^bb2 : () -> ()
+ ^bb1:
+ cir.br ^bb5
+ ^bb2:
+ %0 = cir.eh.initiate : !cir.eh_token
+ cir.br ^bb3(%0 : !cir.eh_token)
+ ^bb3(%eh_token: !cir.eh_token):
+ cir.eh.dispatch %eh_token : !cir.eh_token [
+ catch_all : ^bb4
+ ]
+ ^bb4(%eh_token.1: !cir.eh_token):
+ %ct, %exn = cir.begin_catch %eh_token.1
+ : !cir.eh_token -> (!cir.catch_token, !cir.ptr<!void>)
+ cir.end_catch %ct : !cir.catch_token
+ cir.br ^bb5
+ ^bb5:
+ omp.terminator
+ }
+ cir.return
+}
+
+// CHECK-LABEL: cir.func @test_catch_all_in_parallel()
+// CHECK-SAME: personality(@__gxx_personality_v0)
+// CHECK: omp.parallel {
+// CHECK: cir.try_call @mayThrow() ^[[NORMAL:bb[0-9]+]], ^[[UNWIND:bb[0-9]+]]
+// CHECK: ^[[NORMAL]]:
+// CHECK: cir.br ^[[EXIT:bb[0-9]+]]
+// CHECK: ^[[UNWIND]]:
+// CHECK: %[[EXN:.*]], %[[TID:.*]] = cir.eh.inflight_exception catch_all
+// CHECK: cir.br ^[[DISPATCH:bb[0-9]+]](%[[EXN]], %[[TID]] : !cir.ptr<!void>, !u32i)
+// CHECK: ^[[DISPATCH]](%[[D_EXN:.*]]: !cir.ptr<!void>, %[[D_TID:.*]]: !u32i):
+// CHECK: cir.br ^[[CATCH:bb[0-9]+]](%[[D_EXN]], %[[D_TID]] : !cir.ptr<!void>, !u32i)
+// CHECK: ^[[CATCH]](%[[C_EXN:.*]]: !cir.ptr<!void>, %{{.*}}: !u32i):
+// CHECK: cir.call @__cxa_begin_catch(%[[C_EXN]])
+// CHECK: cir.call @__cxa_end_catch()
+// CHECK: cir.br ^[[EXIT]]
+// CHECK: ^[[EXIT]]:
+// CHECK-NEXT: omp.terminator
+// CHECK-NEXT: }
+// CHECK-NEXT: cir.return
+
// Verify that runtime function declarations are added.
// CHECK: cir.func private @__gxx_personality_v0(...)
// CHECK: cir.func private @__cxa_begin_catch(!cir.ptr<!void>)
More information about the cfe-commits
mailing list