From 533012edfaf7feaaa15f049a7e1e9d24b18eeab5 Mon Sep 17 00:00:00 2001 From: Amr Hesham 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`. + + Example: + + ```mlir + %exception = cir.catch_param begin %exception_obj -> !cir.ptr + + %exception = cir.catch_param -> !cir.ptr + + cir.catch_param end + ``` + }]; + + let arguments = (ins + Optional:$exception_ptr, + OptionalAttr:$kind + ); + + let results = (outs Optional:$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 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()) + 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 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( + 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(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 +!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 + cir.return +} + +} + +// ----- + +!s32i = !cir.int +!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 : !cir.ptr + // expected-error @below {{'cir.catch_param' op needs 'begin' to work with exception pointer}} + %1 = cir.catch_param %0 -> !cir.ptr + cir.yield + } + } + cir.return +} + +} + +// ----- + +!s32i = !cir.int +!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 : !cir.ptr + // expected-error @below {{'cir.catch_param' op needs 'begin' to work with exception pointer}} + %1 = cir.catch_param end %0 -> !cir.ptr + cir.yield + } + } + cir.return +} + +} + From 9453b1a741f37a23926ef04838edbdc4276ed9dc Mon Sep 17 00:00:00 2001 From: Amr Hesham 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 - %exception = cir.catch_param -> !cir.ptr - 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 +!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 + 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 +// CHECK: cir.yield +// CHECK: } +// CHECK: } +// CHECK: cir.return +// CHECK: } + +cir.func dso_local @catch_begin_and_end() { + %exn_addr = cir.alloca !cir.ptr, !cir.ptr>, ["exn_addr"] + %tmp_exn_ptr = cir.load %exn_addr : !cir.ptr>, !cir.ptr + cir.br ^bb1(%tmp_exn_ptr : !cir.ptr) + ^bb1(%exn_ptr : !cir.ptr): + %begin = cir.catch_param begin %exn_ptr -> !cir.ptr + 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, !cir.ptr>, ["exn_addr"] +// CHECK: %[[TMP_EXN_PTR:.*]] = cir.load %[[EXN_ADDR]] : !cir.ptr>, !cir.ptr +// CHECK: cir.br ^bb1(%[[TMP_EXN_PTR]] : !cir.ptr) +// CHECK: ^bb1(%[[EXN_PTR:.*]]: !cir.ptr): +// CHECK: %[[BEGIN:.*]] = cir.catch_param begin %[[EXN_PTR]] -> !cir.ptr +// 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 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 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()) - 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 + cir.catch_param : !cir.ptr 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 +// CHECK: cir.catch_param : !cir.ptr // 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 cir.br ^bb1(%tmp_exn_ptr : !cir.ptr) ^bb1(%exn_ptr : !cir.ptr): - %begin = cir.catch_param begin %exn_ptr -> !cir.ptr + %begin = cir.catch_param begin %exn_ptr : !cir.ptr 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, !cir.ptr>, ["exn_addr"] // CHECK: %[[TMP_EXN_PTR:.*]] = cir.load %[[EXN_ADDR]] : !cir.ptr>, !cir.ptr // CHECK: cir.br ^bb1(%[[TMP_EXN_PTR]] : !cir.ptr) // CHECK: ^bb1(%[[EXN_PTR:.*]]: !cir.ptr): -// CHECK: %[[BEGIN:.*]] = cir.catch_param begin %[[EXN_PTR]] -> !cir.ptr +// CHECK: %[[BEGIN:.*]] = cir.catch_param begin %[[EXN_PTR]] : !cir.ptr // 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 + // expected-error @below {{op without `kind` requires `cir.try` surrounding scope}} + %0 = cir.catch_param : !cir.ptr 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 : !cir.ptr - // expected-error @below {{'cir.catch_param' op needs 'begin' to work with exception pointer}} - %1 = cir.catch_param %0 -> !cir.ptr + // expected-error @below {{op with exception pointer must be of `begin` kind}} + %1 = cir.catch_param %0 : !cir.ptr 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 : !cir.ptr - // expected-error @below {{'cir.catch_param' op needs 'begin' to work with exception pointer}} - %1 = cir.catch_param end %0 -> !cir.ptr + // expected-error @below {{'cir.catch_param' op with exception pointer must be of `begin` kind}} + %1 = cir.catch_param end %0 : !cir.ptr cir.yield } }