Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -4490,6 +4490,48 @@ 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>`.
Copy link
Member

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).


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
//===----------------------------------------------------------------------===//
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
//===----------------------------------------------------------------------===//
Expand Down
29 changes: 29 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
59 changes: 59 additions & 0 deletions clang/test/CIR/IR/catch-param.cir
Original file line number Diff line number Diff line change
@@ -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: }

}


65 changes: 65 additions & 0 deletions clang/test/CIR/IR/invalid-catch-param.cir
Original file line number Diff line number Diff line change
@@ -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
}

}

Loading