[clang] [CIR] Upstream the CatchParamOp (PR #165110)

Amr Hesham via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 27 14:22:06 PDT 2025


https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/165110

>From 533012edfaf7feaaa15f049a7e1e9d24b18eeab5 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Sat, 25 Oct 2025 19:11:37 +0200
Subject: [PATCH 1/3] [CIR] Upstream the CatchParamOp

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 44 +++++++++++++
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 17 +++++
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 29 +++++++++
 clang/test/CIR/IR/invalid-catch-param.cir     | 65 +++++++++++++++++++
 4 files changed, 155 insertions(+)
 create mode 100644 clang/test/CIR/IR/invalid-catch-param.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 2b361ed0982c6..57736cd9c93c2 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4490,6 +4490,50 @@ def CIR_TryOp : CIR_Op<"try",[
   let hasLLVMLowering = false;
 }
 
+//===----------------------------------------------------------------------===//
+// CatchParamOp
+//===----------------------------------------------------------------------===//
+
+def CIR_CatchParamKind  : CIR_I32EnumAttr<
+  "CatchParamKind", "Designate limits for begin/end of catch param handling", [
+    I32EnumAttrCase<"Begin", 0, "begin">,
+    I32EnumAttrCase<"End",  1, "end">
+]>;
+
+def CIR_CatchParamOp : CIR_Op<"catch_param"> {
+  let summary = "Represents catch clause formal parameter";
+  let description = [{
+    The `cir.catch_param` can operate in two modes: within catch regions of
+    `cir.try` or anywhere else with the `begin` or `end` markers. The `begin`
+    version requires an exception pointer of `cir.ptr<!void>`.
+
+    Example:
+
+    ```mlir
+    %exception = cir.catch_param begin %exception_obj -> !cir.ptr<!s32i>
+
+    %exception = cir.catch_param -> !cir.ptr<!void>
+
+    cir.catch_param end
+    ```
+  }];
+
+  let arguments = (ins
+    Optional<CIR_VoidPtrType>:$exception_ptr,
+    OptionalAttr<CIR_CatchParamKind>:$kind
+  );
+
+  let results = (outs Optional<CIR_AnyType>:$param);
+  let assemblyFormat = [{
+    ($kind^)?
+    ($exception_ptr^)?
+    (`->` qualified(type($param))^)?
+    attr-dict
+  }];
+
+  let hasVerifier = 1;
+}
+
 //===----------------------------------------------------------------------===//
 // Atomic operations
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 2d2ef422bfaef..3531af762fabf 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -3096,6 +3096,23 @@ static mlir::ParseResult parseTryHandlerRegions(
   return mlir::success();
 }
 
+//===----------------------------------------------------------------------===//
+// CatchParamOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::CatchParamOp::verify() {
+  std::optional<cir::CatchParamKind> kind = getKind();
+  if (getExceptionPtr()) {
+    if (!kind || *kind != cir::CatchParamKind::Begin)
+      return emitOpError("needs 'begin' to work with exception pointer");
+    return success();
+  }
+
+  if (!kind && !(*this)->getParentOfType<cir::TryOp>())
+    return emitOpError("without 'kind' requires 'cir.try' surrounding scope");
+  return success();
+}
+
 //===----------------------------------------------------------------------===//
 // TableGen'd op method definitions
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 5a6193fa8d840..b4c815065b2af 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2981,6 +2981,35 @@ mlir::LogicalResult CIRToLLVMThrowOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRToLLVMCatchParamOpLowering::matchAndRewrite(
+    cir::CatchParamOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  std::optional<cir::CatchParamKind> kind = op.getKind();
+  if (!kind)
+    llvm_unreachable("only begin/end supposed to make to lowering stage");
+
+  if (kind == cir::CatchParamKind::Begin) {
+    // Get or create `declare ptr @__cxa_begin_catch(ptr)`
+    const llvm::StringRef fnName = "__cxa_begin_catch";
+    auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
+    auto fnTy = mlir::LLVM::LLVMFunctionType::get(llvmPtrTy, {llvmPtrTy});
+    createLLVMFuncOpIfNotExist(rewriter, op, fnName, fnTy);
+    rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
+        op, mlir::TypeRange{llvmPtrTy}, fnName,
+        mlir::ValueRange{adaptor.getExceptionPtr()});
+    return mlir::success();
+  }
+
+  // Get or create `declare void @__cxa_end_catch()`
+  const llvm::StringRef fnName = "__cxa_end_catch";
+  auto voidTy = mlir::LLVM::LLVMVoidType::get(rewriter.getContext());
+  auto fnTy = mlir::LLVM::LLVMFunctionType::get(voidTy, {});
+  createLLVMFuncOpIfNotExist(rewriter, op, fnName, fnTy);
+  rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(op, mlir::TypeRange{}, fnName,
+                                                  mlir::ValueRange{});
+  return mlir::success();
+}
+
 mlir::LogicalResult CIRToLLVMAllocExceptionOpLowering::matchAndRewrite(
     cir::AllocExceptionOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/IR/invalid-catch-param.cir b/clang/test/CIR/IR/invalid-catch-param.cir
new file mode 100644
index 0000000000000..87e90b983da50
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-catch-param.cir
@@ -0,0 +1,65 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+!s32i = !cir.int<s, 32>
+!void = !cir.void
+
+module {
+
+cir.func dso_local @catch_param_without_kind_and_without_try_scope() {
+  // expected-error @below {{'cir.catch_param' op without 'kind' requires 'cir.try' surrounding scope}}
+  %0 = cir.catch_param -> !cir.ptr<!void>
+  cir.return
+}
+
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!void = !cir.void
+
+module {
+
+cir.func private @division() -> !s32i
+cir.func dso_local @catch_param_with_exception_ptr_but_without_kind() {
+  cir.scope {
+    cir.try {
+      %0 = cir.call @division() : () -> !s32i
+      cir.yield
+    } catch all {
+      %0 = cir.const #cir.ptr<null> : !cir.ptr<!void>
+      // expected-error @below {{'cir.catch_param' op needs 'begin' to work with exception pointer}}
+      %1 = cir.catch_param %0 -> !cir.ptr<!void>
+      cir.yield
+    }
+  }
+  cir.return
+}
+
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!void = !cir.void
+
+module {
+
+cir.func private @division() -> !s32i
+cir.func dso_local @catch_param_with_exception_ptr_but_with_end_kind() {
+  cir.scope {
+    cir.try {
+      %0 = cir.call @division() : () -> !s32i
+      cir.yield
+    } catch all {
+      %0 = cir.const #cir.ptr<null> : !cir.ptr<!void>
+      // expected-error @below {{'cir.catch_param' op needs 'begin' to work with exception pointer}}
+      %1 = cir.catch_param end %0 -> !cir.ptr<!void>
+      cir.yield
+    }
+  }
+  cir.return
+}
+
+}
+

>From 9453b1a741f37a23926ef04838edbdc4276ed9dc Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Mon, 27 Oct 2025 21:25:49 +0100
Subject: [PATCH 2/3] Address code review comments

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td |  2 -
 clang/test/CIR/IR/catch-param.cir            | 59 ++++++++++++++++++++
 2 files changed, 59 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CIR/IR/catch-param.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 57736cd9c93c2..2ef301ee1199a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4511,9 +4511,7 @@ def CIR_CatchParamOp : CIR_Op<"catch_param"> {
 
     ```mlir
     %exception = cir.catch_param begin %exception_obj -> !cir.ptr<!s32i>
-
     %exception = cir.catch_param -> !cir.ptr<!void>
-
     cir.catch_param end
     ```
   }];
diff --git a/clang/test/CIR/IR/catch-param.cir b/clang/test/CIR/IR/catch-param.cir
new file mode 100644
index 0000000000000..3e4ebce2085a9
--- /dev/null
+++ b/clang/test/CIR/IR/catch-param.cir
@@ -0,0 +1,59 @@
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s  
+ 
+!s32i = !cir.int<s, 32>
+!void = !cir.void
+
+module {
+
+cir.func dso_local @catch_param_inside_catch() {
+  cir.scope {
+    cir.try {
+      cir.yield
+    } catch all {
+      cir.catch_param -> !cir.ptr<!void> 
+      cir.yield
+    }
+  }
+  cir.return
+}
+
+// CHECK: cir.func dso_local @catch_param_inside_catch() {
+// CHECK:   cir.scope {
+// CHECK:     cir.try {
+// CHECK:       cir.yield
+// CHECK:     } catch all {
+// CHECK:       cir.catch_param -> !cir.ptr<!void> 
+// CHECK:       cir.yield
+// CHECK:     }
+// CHECK:   }
+// CHECK:   cir.return
+// CHECK: }
+
+cir.func dso_local @catch_begin_and_end() {
+    %exn_addr = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["exn_addr"]
+    %tmp_exn_ptr = cir.load %exn_addr : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+    cir.br ^bb1(%tmp_exn_ptr : !cir.ptr<!void>)
+  ^bb1(%exn_ptr : !cir.ptr<!void>):
+    %begin = cir.catch_param begin %exn_ptr -> !cir.ptr<!s32i>
+    cir.catch_param end
+    cir.br ^bb2
+  ^bb2:
+    cir.return
+}
+
+
+// CHECK: cir.func dso_local @catch_begin_and_end() {
+// CHECK:   %[[EXN_ADDR:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["exn_addr"]
+// CHECK:   %[[TMP_EXN_PTR:.*]] = cir.load %[[EXN_ADDR]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+// CHECK:   cir.br ^bb1(%[[TMP_EXN_PTR]] : !cir.ptr<!void>)
+// CHECK: ^bb1(%[[EXN_PTR:.*]]: !cir.ptr<!void>):
+// CHECK:   %[[BEGIN:.*]] = cir.catch_param begin %[[EXN_PTR]] -> !cir.ptr<!s32i>
+// CHECK:   cir.catch_param end
+// CHECK:   cir.br ^bb2
+// CHECK: ^bb2:
+// CHECK:   cir.return
+// CHECK: }
+
+}
+
+

>From e6633f33224d50f58948191f2c8e7eea4b29b30b Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Mon, 27 Oct 2025 22:20:49 +0100
Subject: [PATCH 3/3] Address code review comments

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td |  2 +-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp      |  4 ++--
 clang/test/CIR/IR/catch-param.cir            |  9 ++++-----
 clang/test/CIR/IR/invalid-catch-param.cir    | 12 ++++++------
 4 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 2ef301ee1199a..34fdd91dd300e 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4525,7 +4525,7 @@ def CIR_CatchParamOp : CIR_Op<"catch_param"> {
   let assemblyFormat = [{
     ($kind^)?
     ($exception_ptr^)?
-    (`->` qualified(type($param))^)?
+    (`:` qualified(type($param))^)?
     attr-dict
   }];
 
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 3531af762fabf..39cb55df46bf7 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -3104,12 +3104,12 @@ LogicalResult cir::CatchParamOp::verify() {
   std::optional<cir::CatchParamKind> kind = getKind();
   if (getExceptionPtr()) {
     if (!kind || *kind != cir::CatchParamKind::Begin)
-      return emitOpError("needs 'begin' to work with exception pointer");
+      return emitOpError("with exception pointer must be of `begin` kind");
     return success();
   }
 
   if (!kind && !(*this)->getParentOfType<cir::TryOp>())
-    return emitOpError("without 'kind' requires 'cir.try' surrounding scope");
+    return emitOpError("without `kind` requires `cir.try` surrounding scope");
   return success();
 }
 
diff --git a/clang/test/CIR/IR/catch-param.cir b/clang/test/CIR/IR/catch-param.cir
index 3e4ebce2085a9..32b1d10d4f9b4 100644
--- a/clang/test/CIR/IR/catch-param.cir
+++ b/clang/test/CIR/IR/catch-param.cir
@@ -10,7 +10,7 @@ cir.func dso_local @catch_param_inside_catch() {
     cir.try {
       cir.yield
     } catch all {
-      cir.catch_param -> !cir.ptr<!void> 
+      cir.catch_param : !cir.ptr<!void> 
       cir.yield
     }
   }
@@ -22,7 +22,7 @@ cir.func dso_local @catch_param_inside_catch() {
 // CHECK:     cir.try {
 // CHECK:       cir.yield
 // CHECK:     } catch all {
-// CHECK:       cir.catch_param -> !cir.ptr<!void> 
+// CHECK:       cir.catch_param : !cir.ptr<!void> 
 // CHECK:       cir.yield
 // CHECK:     }
 // CHECK:   }
@@ -34,20 +34,19 @@ cir.func dso_local @catch_begin_and_end() {
     %tmp_exn_ptr = cir.load %exn_addr : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
     cir.br ^bb1(%tmp_exn_ptr : !cir.ptr<!void>)
   ^bb1(%exn_ptr : !cir.ptr<!void>):
-    %begin = cir.catch_param begin %exn_ptr -> !cir.ptr<!s32i>
+    %begin = cir.catch_param begin %exn_ptr : !cir.ptr<!s32i>
     cir.catch_param end
     cir.br ^bb2
   ^bb2:
     cir.return
 }
 
-
 // CHECK: cir.func dso_local @catch_begin_and_end() {
 // CHECK:   %[[EXN_ADDR:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["exn_addr"]
 // CHECK:   %[[TMP_EXN_PTR:.*]] = cir.load %[[EXN_ADDR]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
 // CHECK:   cir.br ^bb1(%[[TMP_EXN_PTR]] : !cir.ptr<!void>)
 // CHECK: ^bb1(%[[EXN_PTR:.*]]: !cir.ptr<!void>):
-// CHECK:   %[[BEGIN:.*]] = cir.catch_param begin %[[EXN_PTR]] -> !cir.ptr<!s32i>
+// CHECK:   %[[BEGIN:.*]] = cir.catch_param begin %[[EXN_PTR]] : !cir.ptr<!s32i>
 // CHECK:   cir.catch_param end
 // CHECK:   cir.br ^bb2
 // CHECK: ^bb2:
diff --git a/clang/test/CIR/IR/invalid-catch-param.cir b/clang/test/CIR/IR/invalid-catch-param.cir
index 87e90b983da50..e3d212b118798 100644
--- a/clang/test/CIR/IR/invalid-catch-param.cir
+++ b/clang/test/CIR/IR/invalid-catch-param.cir
@@ -6,8 +6,8 @@
 module {
 
 cir.func dso_local @catch_param_without_kind_and_without_try_scope() {
-  // expected-error @below {{'cir.catch_param' op without 'kind' requires 'cir.try' surrounding scope}}
-  %0 = cir.catch_param -> !cir.ptr<!void>
+  // expected-error @below {{op without `kind` requires `cir.try` surrounding scope}}
+  %0 = cir.catch_param : !cir.ptr<!void>
   cir.return
 }
 
@@ -28,8 +28,8 @@ cir.func dso_local @catch_param_with_exception_ptr_but_without_kind() {
       cir.yield
     } catch all {
       %0 = cir.const #cir.ptr<null> : !cir.ptr<!void>
-      // expected-error @below {{'cir.catch_param' op needs 'begin' to work with exception pointer}}
-      %1 = cir.catch_param %0 -> !cir.ptr<!void>
+      // expected-error @below {{op with exception pointer must be of `begin` kind}}
+      %1 = cir.catch_param %0 : !cir.ptr<!void>
       cir.yield
     }
   }
@@ -53,8 +53,8 @@ cir.func dso_local @catch_param_with_exception_ptr_but_with_end_kind() {
       cir.yield
     } catch all {
       %0 = cir.const #cir.ptr<null> : !cir.ptr<!void>
-      // expected-error @below {{'cir.catch_param' op needs 'begin' to work with exception pointer}}
-      %1 = cir.catch_param end %0 -> !cir.ptr<!void>
+      // expected-error @below {{'cir.catch_param' op with exception pointer must be of `begin` kind}}
+      %1 = cir.catch_param end %0 : !cir.ptr<!void>
       cir.yield
     }
   }



More information about the cfe-commits mailing list