-
Couldn't load subscription status.
- Fork 15k
[CIR] Upstream the CatchParamOp #165110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[CIR] Upstream the CatchParamOp #165110
Conversation
|
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) ChangesUpstream the CatchParamOp as a prerequisite for implementing exception handlers Issue #154992 Full diff: https://github.com/llvm/llvm-project/pull/165110.diff 4 Files Affected:
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
+}
+
+}
+
|
| 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>`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth expanding on how the two modes are used (one that assumes structured control and the other one for lower level lowering). An alternative design would be split this into two operations (let's see if others have any strong opinions here).
Upstream the CatchParamOp as a prerequisite for implementing exception handlers
Issue #154992