[clang] [CIR] Upstream TryCallOp (PR #165303)
Amr Hesham via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 27 12:00:36 PST 2025
https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/165303
>From ef76e39c5904c22ee8895ae00047960f2a43a9bf Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Mon, 27 Oct 2025 19:55:44 +0100
Subject: [PATCH 1/5] [CIR] Upstream TryCallOp
---
.../clang/CIR/Dialect/IR/CIRDialect.td | 1 +
clang/include/clang/CIR/Dialect/IR/CIROps.td | 94 ++++++++-
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 197 +++++++++++++++++-
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 24 ++-
clang/test/CIR/IR/try-call.cir | 31 +++
5 files changed, 335 insertions(+), 12 deletions(-)
create mode 100644 clang/test/CIR/IR/try-call.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index e91537186df59..34df9af7fc06d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -44,6 +44,7 @@ def CIR_Dialect : Dialect {
static llvm::StringRef getModuleLevelAsmAttrName() { return "cir.module_asm"; }
static llvm::StringRef getGlobalCtorsAttrName() { return "cir.global_ctors"; }
static llvm::StringRef getGlobalDtorsAttrName() { return "cir.global_dtors"; }
+ static llvm::StringRef getOperandSegmentSizesAttrName() { return "operandSegmentSizes"; }
void registerAttributes();
void registerTypes();
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 777b49434f119..c483764632bf3 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2728,7 +2728,7 @@ def CIR_LLVMIntrinsicCallOp : CIR_Op<"call_llvm_intrinsic"> {
}
//===----------------------------------------------------------------------===//
-// CallOp
+// CallOp and TryCallOp
//===----------------------------------------------------------------------===//
def CIR_SideEffect : CIR_I32EnumAttr<
@@ -2855,6 +2855,98 @@ def CIR_CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> {
];
}
+def CIR_TryCallOp : CIR_CallOpBase<"try_call",[
+ DeclareOpInterfaceMethods<BranchOpInterface>,
+ Terminator, AttrSizedOperandSegments
+]> {
+ let summary = "try_call operation";
+
+ let description = [{
+ Mostly similar to cir.call but requires two destination
+ branches, one for handling exceptions in case its thrown and
+ the other one to follow on regular control-flow.
+
+ Example:
+
+ ```mlir
+ // Direct call
+ %result = cir.try_call @division(%a, %b) ^continue, ^landing_pad
+ : (f32, f32) -> f32
+ ```
+ }];
+
+ let arguments = !con((ins
+ Variadic<CIR_AnyType>:$contOperands,
+ Variadic<CIR_AnyType>:$landingPadOperands
+ ), commonArgs);
+
+ let results = (outs Optional<CIR_AnyType>:$result);
+ let successors = (successor AnySuccessor:$cont, AnySuccessor:$landing_pad);
+
+ let skipDefaultBuilders = 1;
+
+ let builders = [
+ OpBuilder<(ins "mlir::SymbolRefAttr":$callee, "mlir::Type":$resType,
+ "mlir::Block *":$cont, "mlir::Block *":$landing_pad,
+ CArg<"mlir::ValueRange", "{}">:$operands,
+ CArg<"mlir::ValueRange", "{}">:$contOperands,
+ CArg<"mlir::ValueRange", "{}">:$landingPadOperands,
+ CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{
+ $_state.addOperands(operands);
+ if (callee)
+ $_state.addAttribute("callee", callee);
+ if (resType && !isa<VoidType>(resType))
+ $_state.addTypes(resType);
+
+ $_state.addAttribute("side_effect",
+ SideEffectAttr::get($_builder.getContext(), sideEffect));
+
+ // Handle branches
+ $_state.addOperands(contOperands);
+ $_state.addOperands(landingPadOperands);
+ // The TryCall ODS layout is: cont, landing_pad, operands.
+ llvm::copy(::llvm::ArrayRef<int32_t>({
+ static_cast<int32_t>(contOperands.size()),
+ static_cast<int32_t>(landingPadOperands.size()),
+ static_cast<int32_t>(operands.size())
+ }),
+ odsState.getOrAddProperties<Properties>().operandSegmentSizes.begin());
+ $_state.addSuccessors(cont);
+ $_state.addSuccessors(landing_pad);
+ }]>,
+ OpBuilder<(ins "mlir::Value":$ind_target,
+ "FuncType":$fn_type,
+ "mlir::Block *":$cont, "mlir::Block *":$landing_pad,
+ CArg<"mlir::ValueRange", "{}">:$operands,
+ CArg<"mlir::ValueRange", "{}">:$contOperands,
+ CArg<"mlir::ValueRange", "{}">:$landingPadOperands,
+ CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{
+ ::llvm::SmallVector<mlir::Value, 4> finalCallOperands({ind_target});
+ finalCallOperands.append(operands.begin(), operands.end());
+ $_state.addOperands(finalCallOperands);
+
+ if (!fn_type.hasVoidReturn())
+ $_state.addTypes(fn_type.getReturnType());
+
+ $_state.addAttribute("side_effect",
+ SideEffectAttr::get($_builder.getContext(), sideEffect));
+
+ // Handle branches
+ $_state.addOperands(contOperands);
+ $_state.addOperands(landingPadOperands);
+ // The TryCall ODS layout is: cont, landing_pad, operands.
+ llvm::copy(::llvm::ArrayRef<int32_t>({
+ static_cast<int32_t>(contOperands.size()),
+ static_cast<int32_t>(landingPadOperands.size()),
+ static_cast<int32_t>(finalCallOperands.size())
+ }),
+ odsState.getOrAddProperties<Properties>().operandSegmentSizes.begin());
+ $_state.addSuccessors(cont);
+ $_state.addSuccessors(landing_pad);
+ }]>
+ ];
+}
+
//===----------------------------------------------------------------------===//
// AwaitOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index f1bacff7fc691..32e42203c880a 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -721,13 +721,78 @@ unsigned cir::CallOp::getNumArgOperands() {
return this->getOperation()->getNumOperands();
}
+static mlir::ParseResult
+parseTryCallBranches(mlir::OpAsmParser &parser, mlir::OperationState &result,
+ llvm::SmallVectorImpl<mlir::OpAsmParser::UnresolvedOperand>
+ &continueOperands,
+ llvm::SmallVectorImpl<mlir::OpAsmParser::UnresolvedOperand>
+ &landingPadOperands,
+ llvm::SmallVectorImpl<mlir::Type> &continueTypes,
+ llvm::SmallVectorImpl<mlir::Type> &landingPadTypes,
+ llvm::SMLoc &continueOperandsLoc,
+ llvm::SMLoc &landingPadOperandsLoc) {
+ mlir::Block *continueSuccessor = nullptr;
+ mlir::Block *landingPadSuccessor = nullptr;
+
+ if (parser.parseSuccessor(continueSuccessor))
+ return mlir::failure();
+
+ if (mlir::succeeded(parser.parseOptionalLParen())) {
+ continueOperandsLoc = parser.getCurrentLocation();
+ if (parser.parseOperandList(continueOperands))
+ return mlir::failure();
+ if (parser.parseColon())
+ return mlir::failure();
+
+ if (parser.parseTypeList(continueTypes))
+ return mlir::failure();
+ if (parser.parseRParen())
+ return mlir::failure();
+ }
+
+ if (parser.parseComma())
+ return mlir::failure();
+
+ if (parser.parseSuccessor(landingPadSuccessor))
+ return mlir::failure();
+
+ if (mlir::succeeded(parser.parseOptionalLParen())) {
+ landingPadOperandsLoc = parser.getCurrentLocation();
+ if (parser.parseOperandList(landingPadOperands))
+ return mlir::failure();
+ if (parser.parseColon())
+ return mlir::failure();
+
+ if (parser.parseTypeList(landingPadTypes))
+ return mlir::failure();
+ if (parser.parseRParen())
+ return mlir::failure();
+ }
+
+ if (parser.parseOptionalAttrDict(result.attributes))
+ return mlir::failure();
+
+ result.addSuccessors(continueSuccessor);
+ result.addSuccessors(landingPadSuccessor);
+ return mlir::success();
+}
+
static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
- mlir::OperationState &result) {
+ mlir::OperationState &result,
+ bool hasDestinationBlocks = false) {
llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand, 4> ops;
llvm::SMLoc opsLoc;
mlir::FlatSymbolRefAttr calleeAttr;
llvm::ArrayRef<mlir::Type> allResultTypes;
+ // TryCall control flow related
+ llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand, 4> continueOperands;
+ llvm::SMLoc continueOperandsLoc;
+ llvm::SmallVector<mlir::Type, 1> continueTypes;
+ llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand, 4> landingPadOperands;
+ llvm::SMLoc landingPadOperandsLoc;
+ llvm::SmallVector<mlir::Type, 1> landingPadTypes;
+
// If we cannot parse a string callee, it means this is an indirect call.
if (!parser
.parseOptionalAttribute(calleeAttr, CIRDialect::getCalleeAttrName(),
@@ -749,6 +814,14 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
if (parser.parseRParen())
return mlir::failure();
+ if (hasDestinationBlocks &&
+ parseTryCallBranches(parser, result, continueOperands, landingPadOperands,
+ continueTypes, landingPadTypes, continueOperandsLoc,
+ landingPadOperandsLoc)
+ .failed()) {
+ return ::mlir::failure();
+ }
+
if (parser.parseOptionalKeyword("nothrow").succeeded())
result.addAttribute(CIRDialect::getNoThrowAttrName(),
mlir::UnitAttr::get(parser.getContext()));
@@ -781,6 +854,24 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
if (parser.resolveOperands(ops, opsFnTy.getInputs(), opsLoc, result.operands))
return mlir::failure();
+ if (hasDestinationBlocks) {
+ // The TryCall ODS layout is: cont, landing_pad, operands.
+ llvm::copy(::llvm::ArrayRef<int32_t>(
+ {static_cast<int32_t>(continueOperands.size()),
+ static_cast<int32_t>(landingPadOperands.size()),
+ static_cast<int32_t>(ops.size())}),
+ result.getOrAddProperties<cir::TryCallOp::Properties>()
+ .operandSegmentSizes.begin());
+
+ if (parser.resolveOperands(continueOperands, continueTypes,
+ continueOperandsLoc, result.operands))
+ return ::mlir::failure();
+
+ if (parser.resolveOperands(landingPadOperands, landingPadTypes,
+ landingPadOperandsLoc, result.operands))
+ return ::mlir::failure();
+ }
+
return mlir::success();
}
@@ -788,7 +879,9 @@ static void printCallCommon(mlir::Operation *op,
mlir::FlatSymbolRefAttr calleeSym,
mlir::Value indirectCallee,
mlir::OpAsmPrinter &printer, bool isNothrow,
- cir::SideEffect sideEffect) {
+ cir::SideEffect sideEffect,
+ mlir::Block *cont = nullptr,
+ mlir::Block *landingPad = nullptr) {
printer << ' ';
auto callLikeOp = mlir::cast<cir::CIRCallOpInterface>(op);
@@ -802,8 +895,35 @@ static void printCallCommon(mlir::Operation *op,
assert(indirectCallee);
printer << indirectCallee;
}
+
printer << "(" << ops << ")";
+ if (cont) {
+ assert(landingPad && "expected two successors");
+ auto tryCall = dyn_cast<cir::TryCallOp>(op);
+ assert(tryCall && "regular calls do not branch");
+ printer << ' ' << tryCall.getCont();
+ if (!tryCall.getContOperands().empty()) {
+ printer << "(";
+ printer << tryCall.getContOperands();
+ printer << ' ' << ":";
+ printer << ' ';
+ printer << tryCall.getContOperands().getTypes();
+ printer << ")";
+ }
+ printer << ",";
+ printer << ' ';
+ printer << tryCall.getLandingPad();
+ if (!tryCall.getLandingPadOperands().empty()) {
+ printer << "(";
+ printer << tryCall.getLandingPadOperands();
+ printer << ' ' << ":";
+ printer << ' ';
+ printer << tryCall.getLandingPadOperands().getTypes();
+ printer << ")";
+ }
+ }
+
if (isNothrow)
printer << " nothrow";
@@ -813,10 +933,11 @@ static void printCallCommon(mlir::Operation *op,
printer << ")";
}
- printer.printOptionalAttrDict(op->getAttrs(),
- {CIRDialect::getCalleeAttrName(),
- CIRDialect::getNoThrowAttrName(),
- CIRDialect::getSideEffectAttrName()});
+ llvm::SmallVector<::llvm::StringRef, 4> elidedAttrs = {
+ CIRDialect::getCalleeAttrName(), CIRDialect::getNoThrowAttrName(),
+ CIRDialect::getSideEffectAttrName(),
+ CIRDialect::getOperandSegmentSizesAttrName()};
+ printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
printer << " : ";
printer.printFunctionalType(op->getOperands().getTypes(),
@@ -898,6 +1019,70 @@ cir::CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
return verifyCallCommInSymbolUses(*this, symbolTable);
}
+//===----------------------------------------------------------------------===//
+// TryCallOp
+//===----------------------------------------------------------------------===//
+
+mlir::OperandRange cir::TryCallOp::getArgOperands() {
+ if (isIndirect())
+ return getArgs().drop_front(1);
+ return getArgs();
+}
+
+mlir::MutableOperandRange cir::TryCallOp::getArgOperandsMutable() {
+ mlir::MutableOperandRange args = getArgsMutable();
+ if (isIndirect())
+ return args.slice(1, args.size() - 1);
+ return args;
+}
+
+mlir::Value cir::TryCallOp::getIndirectCall() {
+ assert(isIndirect());
+ return getOperand(0);
+}
+
+/// Return the operand at index 'i'.
+Value cir::TryCallOp::getArgOperand(unsigned i) {
+ if (isIndirect())
+ ++i;
+ return getOperand(i);
+}
+
+/// Return the number of operands.
+unsigned cir::TryCallOp::getNumArgOperands() {
+ if (isIndirect())
+ return this->getOperation()->getNumOperands() - 1;
+ return this->getOperation()->getNumOperands();
+}
+
+LogicalResult
+cir::TryCallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
+ return verifyCallCommInSymbolUses(*this, symbolTable);
+}
+
+mlir::ParseResult cir::TryCallOp::parse(mlir::OpAsmParser &parser,
+ mlir::OperationState &result) {
+ return parseCallCommon(parser, result, /*hasDestinationBlocks=*/true);
+}
+
+void cir::TryCallOp::print(::mlir::OpAsmPrinter &p) {
+ mlir::Value indirectCallee = isIndirect() ? getIndirectCall() : nullptr;
+ cir::SideEffect sideEffect = getSideEffect();
+ printCallCommon(*this, getCalleeAttr(), indirectCallee, p, getNothrow(),
+ sideEffect, getCont(), getLandingPad());
+}
+
+mlir::SuccessorOperands cir::TryCallOp::getSuccessorOperands(unsigned index) {
+ assert(index < getNumSuccessors() && "invalid successor index");
+ if (index == 0)
+ return SuccessorOperands(getContOperandsMutable());
+ if (index == 1)
+ return SuccessorOperands(getLandingPadOperandsMutable());
+
+ // index == 2
+ return SuccessorOperands(getArgOperandsMutable());
+}
+
//===----------------------------------------------------------------------===//
// ReturnOp
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 0c34d87734c3e..e1d3674b294eb 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1494,7 +1494,9 @@ static mlir::LogicalResult
rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
mlir::ConversionPatternRewriter &rewriter,
const mlir::TypeConverter *converter,
- mlir::FlatSymbolRefAttr calleeAttr) {
+ mlir::FlatSymbolRefAttr calleeAttr,
+ mlir::Block *continueBlock = nullptr,
+ mlir::Block *landingPadBlock = nullptr) {
llvm::SmallVector<mlir::Type, 8> llvmResults;
mlir::ValueTypeRange<mlir::ResultRange> cirResults = op->getResultTypes();
auto call = cast<cir::CIRCallOpInterface>(op);
@@ -1523,7 +1525,7 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
llvmFnTy = converter->convertType<mlir::LLVM::LLVMFunctionType>(
fn.getFunctionType());
assert(llvmFnTy && "Failed to convert function type");
- } else if (auto alias = mlir::cast<mlir::LLVM::AliasOp>(callee)) {
+ } else if (auto alias = mlir::dyn_cast<mlir::LLVM::AliasOp>(callee)) {
// If the callee was an alias. In that case,
// we need to prepend the address of the alias to the operands. The
// way aliases work in the LLVM dialect is a little counter-intuitive.
@@ -1561,17 +1563,21 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
converter->convertType(calleeFuncTy));
}
- assert(!cir::MissingFeatures::opCallLandingPad());
- assert(!cir::MissingFeatures::opCallContinueBlock());
assert(!cir::MissingFeatures::opCallCallConv());
+ if (landingPadBlock) {
+ rewriter.replaceOpWithNewOp<mlir::LLVM::InvokeOp>(
+ op, llvmFnTy, calleeAttr, callOperands, continueBlock,
+ mlir::ValueRange{}, landingPadBlock, mlir::ValueRange{});
+ return mlir::success();
+ }
+
auto newOp = rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
op, llvmFnTy, calleeAttr, callOperands);
if (memoryEffects)
newOp.setMemoryEffectsAttr(memoryEffects);
newOp.setNoUnwind(noUnwind);
newOp.setWillReturn(willReturn);
-
return mlir::success();
}
@@ -1582,6 +1588,14 @@ mlir::LogicalResult CIRToLLVMCallOpLowering::matchAndRewrite(
getTypeConverter(), op.getCalleeAttr());
}
+mlir::LogicalResult CIRToLLVMTryCallOpLowering::matchAndRewrite(
+ cir::TryCallOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ return rewriteCallOrInvoke(op.getOperation(), adaptor.getOperands(), rewriter,
+ getTypeConverter(), op.getCalleeAttr(),
+ op.getCont(), op.getLandingPad());
+}
+
mlir::LogicalResult CIRToLLVMReturnAddrOpLowering::matchAndRewrite(
cir::ReturnAddrOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/IR/try-call.cir b/clang/test/CIR/IR/try-call.cir
new file mode 100644
index 0000000000000..6c23d3add15c8
--- /dev/null
+++ b/clang/test/CIR/IR/try-call.cir
@@ -0,0 +1,31 @@
+// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
+
+!s32i = !cir.int<s, 32>
+
+module {
+
+cir.func private @division(%a: !s32i, %b: !s32i) -> !s32i
+
+cir.func @flatten_structure_with_try_call_op() {
+ %a = cir.const #cir.int<1> : !s32i
+ %b = cir.const #cir.int<2> : !s32i
+ %3 = cir.try_call @division(%a, %b) ^continue, ^landing_pad : (!s32i, !s32i) -> !s32i
+ ^continue:
+ cir.br ^landing_pad
+ ^landing_pad:
+ cir.return
+}
+
+// CHECK: cir.func private @division(!s32i, !s32i) -> !s32i
+
+// CHECK: cir.func @flatten_structure_with_try_call_op() {
+// CHECK-NEXT: %[[CONST_0:.*]] = cir.const #cir.int<1> : !s32i
+// CHECK-NEXT: %[[CONST_1:.*]] = cir.const #cir.int<2> : !s32i
+// CHECK-NEXT: %[[CALL:.*]] = cir.try_call @division(%0, %1) ^[[CONTINUE:.*]], ^[[LANDING_PAD:.*]] : (!s32i, !s32i) -> !s32i
+// CHECK-NEXT: ^[[CONTINUE]]:
+// CHECK-NEXT: cir.br ^[[LANDING_PAD]]
+// CHECK-NEXT: ^[[LANDING_PAD]]:
+// CHECK-NEXT: cir.return
+// CHECK-NEXT: }
+
+}
>From fd5c5004c56b95e537c72271651a2ce93be5e19c Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Thu, 20 Nov 2025 18:42:47 +0100
Subject: [PATCH 2/5] WIP
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 47 +++++-----
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 86 +++++--------------
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 24 ++----
3 files changed, 53 insertions(+), 104 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index c483764632bf3..e2c6d4b4b771f 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2870,27 +2870,29 @@ def CIR_TryCallOp : CIR_CallOpBase<"try_call",[
```mlir
// Direct call
- %result = cir.try_call @division(%a, %b) ^continue, ^landing_pad
+ %result = cir.try_call @division(%a, %b) ^normalDest, ^unwindDest
: (f32, f32) -> f32
```
}];
let arguments = !con((ins
- Variadic<CIR_AnyType>:$contOperands,
- Variadic<CIR_AnyType>:$landingPadOperands
+ Variadic<CIR_AnyType>:$normalDestOperands,
+ Variadic<CIR_AnyType>:$unwindDestOperands
), commonArgs);
let results = (outs Optional<CIR_AnyType>:$result);
- let successors = (successor AnySuccessor:$cont, AnySuccessor:$landing_pad);
+ let successors = (successor AnySuccessor:$normalDest, AnySuccessor:$unwindDest);
let skipDefaultBuilders = 1;
+ let hasLLVMLowering = false;
let builders = [
OpBuilder<(ins "mlir::SymbolRefAttr":$callee, "mlir::Type":$resType,
- "mlir::Block *":$cont, "mlir::Block *":$landing_pad,
+ "mlir::Block *":$normalDest,
+ "mlir::Block *":$unwindDest,
CArg<"mlir::ValueRange", "{}">:$operands,
- CArg<"mlir::ValueRange", "{}">:$contOperands,
- CArg<"mlir::ValueRange", "{}">:$landingPadOperands,
+ CArg<"mlir::ValueRange", "{}">:$normalDestOperands,
+ CArg<"mlir::ValueRange", "{}">:$unwindDestOperands,
CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{
$_state.addOperands(operands);
if (callee)
@@ -2902,24 +2904,25 @@ def CIR_TryCallOp : CIR_CallOpBase<"try_call",[
SideEffectAttr::get($_builder.getContext(), sideEffect));
// Handle branches
- $_state.addOperands(contOperands);
- $_state.addOperands(landingPadOperands);
+ $_state.addOperands(normalDestOperands);
+ $_state.addOperands(unwindDestOperands);
// The TryCall ODS layout is: cont, landing_pad, operands.
llvm::copy(::llvm::ArrayRef<int32_t>({
- static_cast<int32_t>(contOperands.size()),
- static_cast<int32_t>(landingPadOperands.size()),
+ static_cast<int32_t>(normalDestOperands.size()),
+ static_cast<int32_t>(unwindDestOperands.size()),
static_cast<int32_t>(operands.size())
}),
odsState.getOrAddProperties<Properties>().operandSegmentSizes.begin());
- $_state.addSuccessors(cont);
- $_state.addSuccessors(landing_pad);
+ $_state.addSuccessors(normalDest);
+ $_state.addSuccessors(unwindDest);
}]>,
OpBuilder<(ins "mlir::Value":$ind_target,
"FuncType":$fn_type,
- "mlir::Block *":$cont, "mlir::Block *":$landing_pad,
+ "mlir::Block *":$normalDest,
+ "mlir::Block *":$unwindDest,
CArg<"mlir::ValueRange", "{}">:$operands,
- CArg<"mlir::ValueRange", "{}">:$contOperands,
- CArg<"mlir::ValueRange", "{}">:$landingPadOperands,
+ CArg<"mlir::ValueRange", "{}">:$normalDestOperands,
+ CArg<"mlir::ValueRange", "{}">:$unwindDestOperands,
CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{
::llvm::SmallVector<mlir::Value, 4> finalCallOperands({ind_target});
finalCallOperands.append(operands.begin(), operands.end());
@@ -2932,17 +2935,17 @@ def CIR_TryCallOp : CIR_CallOpBase<"try_call",[
SideEffectAttr::get($_builder.getContext(), sideEffect));
// Handle branches
- $_state.addOperands(contOperands);
- $_state.addOperands(landingPadOperands);
+ $_state.addOperands(normalDestOperands);
+ $_state.addOperands(unwindDestOperands);
// The TryCall ODS layout is: cont, landing_pad, operands.
llvm::copy(::llvm::ArrayRef<int32_t>({
- static_cast<int32_t>(contOperands.size()),
- static_cast<int32_t>(landingPadOperands.size()),
+ static_cast<int32_t>(normalDestOperands.size()),
+ static_cast<int32_t>(unwindDestOperands.size()),
static_cast<int32_t>(finalCallOperands.size())
}),
odsState.getOrAddProperties<Properties>().operandSegmentSizes.begin());
- $_state.addSuccessors(cont);
- $_state.addSuccessors(landing_pad);
+ $_state.addSuccessors(normalDest);
+ $_state.addSuccessors(unwindDest);
}]>
];
}
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 32e42203c880a..a8ccd1b559360 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -722,58 +722,21 @@ unsigned cir::CallOp::getNumArgOperands() {
}
static mlir::ParseResult
-parseTryCallBranches(mlir::OpAsmParser &parser, mlir::OperationState &result,
- llvm::SmallVectorImpl<mlir::OpAsmParser::UnresolvedOperand>
- &continueOperands,
- llvm::SmallVectorImpl<mlir::OpAsmParser::UnresolvedOperand>
- &landingPadOperands,
- llvm::SmallVectorImpl<mlir::Type> &continueTypes,
- llvm::SmallVectorImpl<mlir::Type> &landingPadTypes,
- llvm::SMLoc &continueOperandsLoc,
- llvm::SMLoc &landingPadOperandsLoc) {
- mlir::Block *continueSuccessor = nullptr;
- mlir::Block *landingPadSuccessor = nullptr;
-
- if (parser.parseSuccessor(continueSuccessor))
+parseTryCallDestinations(mlir::OpAsmParser &parser,
+ mlir::OperationState &result) {
+ mlir::Block *normalDestSuccessor;
+ if (parser.parseSuccessor(normalDestSuccessor))
return mlir::failure();
- if (mlir::succeeded(parser.parseOptionalLParen())) {
- continueOperandsLoc = parser.getCurrentLocation();
- if (parser.parseOperandList(continueOperands))
- return mlir::failure();
- if (parser.parseColon())
- return mlir::failure();
-
- if (parser.parseTypeList(continueTypes))
- return mlir::failure();
- if (parser.parseRParen())
- return mlir::failure();
- }
-
if (parser.parseComma())
return mlir::failure();
- if (parser.parseSuccessor(landingPadSuccessor))
- return mlir::failure();
-
- if (mlir::succeeded(parser.parseOptionalLParen())) {
- landingPadOperandsLoc = parser.getCurrentLocation();
- if (parser.parseOperandList(landingPadOperands))
- return mlir::failure();
- if (parser.parseColon())
- return mlir::failure();
-
- if (parser.parseTypeList(landingPadTypes))
- return mlir::failure();
- if (parser.parseRParen())
- return mlir::failure();
- }
-
- if (parser.parseOptionalAttrDict(result.attributes))
+ mlir::Block *unwindDestSuccessor;
+ if (parser.parseSuccessor(unwindDestSuccessor))
return mlir::failure();
- result.addSuccessors(continueSuccessor);
- result.addSuccessors(landingPadSuccessor);
+ result.addSuccessors(normalDestSuccessor);
+ result.addSuccessors(unwindDestSuccessor);
return mlir::success();
}
@@ -815,10 +778,7 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
return mlir::failure();
if (hasDestinationBlocks &&
- parseTryCallBranches(parser, result, continueOperands, landingPadOperands,
- continueTypes, landingPadTypes, continueOperandsLoc,
- landingPadOperandsLoc)
- .failed()) {
+ parseTryCallDestinations(parser, result).failed()) {
return ::mlir::failure();
}
@@ -880,8 +840,8 @@ static void printCallCommon(mlir::Operation *op,
mlir::Value indirectCallee,
mlir::OpAsmPrinter &printer, bool isNothrow,
cir::SideEffect sideEffect,
- mlir::Block *cont = nullptr,
- mlir::Block *landingPad = nullptr) {
+ mlir::Block *normalDest = nullptr,
+ mlir::Block *unwindDest = nullptr) {
printer << ' ';
auto callLikeOp = mlir::cast<cir::CIRCallOpInterface>(op);
@@ -898,28 +858,28 @@ static void printCallCommon(mlir::Operation *op,
printer << "(" << ops << ")";
- if (cont) {
+ if (normalDest) {
assert(landingPad && "expected two successors");
auto tryCall = dyn_cast<cir::TryCallOp>(op);
assert(tryCall && "regular calls do not branch");
- printer << ' ' << tryCall.getCont();
- if (!tryCall.getContOperands().empty()) {
+ printer << ' ' << tryCall.getNormalDest();
+ if (!tryCall.getNormalDestOperands().empty()) {
printer << "(";
- printer << tryCall.getContOperands();
+ printer << tryCall.getNormalDestOperands();
printer << ' ' << ":";
printer << ' ';
- printer << tryCall.getContOperands().getTypes();
+ printer << tryCall.getNormalDestOperands().getTypes();
printer << ")";
}
printer << ",";
printer << ' ';
- printer << tryCall.getLandingPad();
- if (!tryCall.getLandingPadOperands().empty()) {
+ printer << tryCall.getUnwindDest();
+ if (!tryCall.getUnwindDestOperands().empty()) {
printer << "(";
- printer << tryCall.getLandingPadOperands();
+ printer << tryCall.getUnwindDestOperands();
printer << ' ' << ":";
printer << ' ';
- printer << tryCall.getLandingPadOperands().getTypes();
+ printer << tryCall.getUnwindDestOperands().getTypes();
printer << ")";
}
}
@@ -1069,15 +1029,15 @@ void cir::TryCallOp::print(::mlir::OpAsmPrinter &p) {
mlir::Value indirectCallee = isIndirect() ? getIndirectCall() : nullptr;
cir::SideEffect sideEffect = getSideEffect();
printCallCommon(*this, getCalleeAttr(), indirectCallee, p, getNothrow(),
- sideEffect, getCont(), getLandingPad());
+ sideEffect, getNormalDest(), getUnwindDest());
}
mlir::SuccessorOperands cir::TryCallOp::getSuccessorOperands(unsigned index) {
assert(index < getNumSuccessors() && "invalid successor index");
if (index == 0)
- return SuccessorOperands(getContOperandsMutable());
+ return SuccessorOperands(getNormalDestOperandsMutable());
if (index == 1)
- return SuccessorOperands(getLandingPadOperandsMutable());
+ return SuccessorOperands(getUnwindDestOperandsMutable());
// index == 2
return SuccessorOperands(getArgOperandsMutable());
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index e1d3674b294eb..0c34d87734c3e 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1494,9 +1494,7 @@ static mlir::LogicalResult
rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
mlir::ConversionPatternRewriter &rewriter,
const mlir::TypeConverter *converter,
- mlir::FlatSymbolRefAttr calleeAttr,
- mlir::Block *continueBlock = nullptr,
- mlir::Block *landingPadBlock = nullptr) {
+ mlir::FlatSymbolRefAttr calleeAttr) {
llvm::SmallVector<mlir::Type, 8> llvmResults;
mlir::ValueTypeRange<mlir::ResultRange> cirResults = op->getResultTypes();
auto call = cast<cir::CIRCallOpInterface>(op);
@@ -1525,7 +1523,7 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
llvmFnTy = converter->convertType<mlir::LLVM::LLVMFunctionType>(
fn.getFunctionType());
assert(llvmFnTy && "Failed to convert function type");
- } else if (auto alias = mlir::dyn_cast<mlir::LLVM::AliasOp>(callee)) {
+ } else if (auto alias = mlir::cast<mlir::LLVM::AliasOp>(callee)) {
// If the callee was an alias. In that case,
// we need to prepend the address of the alias to the operands. The
// way aliases work in the LLVM dialect is a little counter-intuitive.
@@ -1563,21 +1561,17 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
converter->convertType(calleeFuncTy));
}
+ assert(!cir::MissingFeatures::opCallLandingPad());
+ assert(!cir::MissingFeatures::opCallContinueBlock());
assert(!cir::MissingFeatures::opCallCallConv());
- if (landingPadBlock) {
- rewriter.replaceOpWithNewOp<mlir::LLVM::InvokeOp>(
- op, llvmFnTy, calleeAttr, callOperands, continueBlock,
- mlir::ValueRange{}, landingPadBlock, mlir::ValueRange{});
- return mlir::success();
- }
-
auto newOp = rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
op, llvmFnTy, calleeAttr, callOperands);
if (memoryEffects)
newOp.setMemoryEffectsAttr(memoryEffects);
newOp.setNoUnwind(noUnwind);
newOp.setWillReturn(willReturn);
+
return mlir::success();
}
@@ -1588,14 +1582,6 @@ mlir::LogicalResult CIRToLLVMCallOpLowering::matchAndRewrite(
getTypeConverter(), op.getCalleeAttr());
}
-mlir::LogicalResult CIRToLLVMTryCallOpLowering::matchAndRewrite(
- cir::TryCallOp op, OpAdaptor adaptor,
- mlir::ConversionPatternRewriter &rewriter) const {
- return rewriteCallOrInvoke(op.getOperation(), adaptor.getOperands(), rewriter,
- getTypeConverter(), op.getCalleeAttr(),
- op.getCont(), op.getLandingPad());
-}
-
mlir::LogicalResult CIRToLLVMReturnAddrOpLowering::matchAndRewrite(
cir::ReturnAddrOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
>From 92fb0a8ddaa9a2bf3b7a6bd76317988976030bdd Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Thu, 20 Nov 2025 21:57:46 +0100
Subject: [PATCH 3/5] Address code review comments
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 76 +++++++++-----------
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 53 --------------
2 files changed, 35 insertions(+), 94 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index e2c6d4b4b771f..a4f995b1a463a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2856,45 +2856,59 @@ def CIR_CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> {
}
def CIR_TryCallOp : CIR_CallOpBase<"try_call",[
- DeclareOpInterfaceMethods<BranchOpInterface>,
- Terminator, AttrSizedOperandSegments
+ Terminator
]> {
let summary = "try_call operation";
-
let description = [{
- Mostly similar to cir.call but requires two destination
- branches, one for handling exceptions in case its thrown and
- the other one to follow on regular control-flow.
+ Mostly similar to `cir.call` but requires two destination
+ branches, one for follow on regular control-flow, and the other
+ one for handling exceptions in case it's thrown.
+
+ This operation is used only after the CFG flatterning pass.
Example:
```mlir
- // Direct call
- %result = cir.try_call @division(%a, %b) ^normalDest, ^unwindDest
+ // Before CFG flattening
+ cir.try {
+ %call = cir.call @division(%a, %b) : () -> !s32i
+ cir.yield
+ } catch all {
+ cir.yield
+ }
+
+ // After CFG flattening
+ %call = cir.try_call @division(%a, %b) ^normalDest, ^unwindDest
: (f32, f32) -> f32
+ ^normalDest:
+ cir.br ^afterTryBlock
+ ^unwindDest:
+ %exception_ptr, %type_id = cir.eh.inflight_exception
+ cir.br ^catchHandlerBlock(%exception_ptr : !cir.ptr<!void>)
+ ^catchHandlerBlock:
+ ...
```
}];
- let arguments = !con((ins
- Variadic<CIR_AnyType>:$normalDestOperands,
- Variadic<CIR_AnyType>:$unwindDestOperands
- ), commonArgs);
-
+ let arguments = commonArgs;
let results = (outs Optional<CIR_AnyType>:$result);
- let successors = (successor AnySuccessor:$normalDest, AnySuccessor:$unwindDest);
+ let successors = (successor
+ AnySuccessor:$normalDest,
+ AnySuccessor:$unwindDest
+ );
let skipDefaultBuilders = 1;
let hasLLVMLowering = false;
let builders = [
- OpBuilder<(ins "mlir::SymbolRefAttr":$callee, "mlir::Type":$resType,
+ OpBuilder<(ins "mlir::SymbolRefAttr":$callee,
+ "mlir::Type":$resType,
"mlir::Block *":$normalDest,
"mlir::Block *":$unwindDest,
- CArg<"mlir::ValueRange", "{}">:$operands,
- CArg<"mlir::ValueRange", "{}">:$normalDestOperands,
- CArg<"mlir::ValueRange", "{}">:$unwindDestOperands,
+ CArg<"mlir::ValueRange", "{}">:$callOperands,
CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{
- $_state.addOperands(operands);
+ $_state.addOperands(callOperands);
+
if (callee)
$_state.addAttribute("callee", callee);
if (resType && !isa<VoidType>(resType))
@@ -2904,15 +2918,6 @@ def CIR_TryCallOp : CIR_CallOpBase<"try_call",[
SideEffectAttr::get($_builder.getContext(), sideEffect));
// Handle branches
- $_state.addOperands(normalDestOperands);
- $_state.addOperands(unwindDestOperands);
- // The TryCall ODS layout is: cont, landing_pad, operands.
- llvm::copy(::llvm::ArrayRef<int32_t>({
- static_cast<int32_t>(normalDestOperands.size()),
- static_cast<int32_t>(unwindDestOperands.size()),
- static_cast<int32_t>(operands.size())
- }),
- odsState.getOrAddProperties<Properties>().operandSegmentSizes.begin());
$_state.addSuccessors(normalDest);
$_state.addSuccessors(unwindDest);
}]>,
@@ -2920,12 +2925,10 @@ def CIR_TryCallOp : CIR_CallOpBase<"try_call",[
"FuncType":$fn_type,
"mlir::Block *":$normalDest,
"mlir::Block *":$unwindDest,
- CArg<"mlir::ValueRange", "{}">:$operands,
- CArg<"mlir::ValueRange", "{}">:$normalDestOperands,
- CArg<"mlir::ValueRange", "{}">:$unwindDestOperands,
+ CArg<"mlir::ValueRange", "{}">:$callOperands,
CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{
::llvm::SmallVector<mlir::Value, 4> finalCallOperands({ind_target});
- finalCallOperands.append(operands.begin(), operands.end());
+ finalCallOperands.append(callOperands.begin(), callOperands.end());
$_state.addOperands(finalCallOperands);
if (!fn_type.hasVoidReturn())
@@ -2935,15 +2938,6 @@ def CIR_TryCallOp : CIR_CallOpBase<"try_call",[
SideEffectAttr::get($_builder.getContext(), sideEffect));
// Handle branches
- $_state.addOperands(normalDestOperands);
- $_state.addOperands(unwindDestOperands);
- // The TryCall ODS layout is: cont, landing_pad, operands.
- llvm::copy(::llvm::ArrayRef<int32_t>({
- static_cast<int32_t>(normalDestOperands.size()),
- static_cast<int32_t>(unwindDestOperands.size()),
- static_cast<int32_t>(finalCallOperands.size())
- }),
- odsState.getOrAddProperties<Properties>().operandSegmentSizes.begin());
$_state.addSuccessors(normalDest);
$_state.addSuccessors(unwindDest);
}]>
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index a8ccd1b559360..50e1eeea2944f 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -748,14 +748,6 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
mlir::FlatSymbolRefAttr calleeAttr;
llvm::ArrayRef<mlir::Type> allResultTypes;
- // TryCall control flow related
- llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand, 4> continueOperands;
- llvm::SMLoc continueOperandsLoc;
- llvm::SmallVector<mlir::Type, 1> continueTypes;
- llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand, 4> landingPadOperands;
- llvm::SMLoc landingPadOperandsLoc;
- llvm::SmallVector<mlir::Type, 1> landingPadTypes;
-
// If we cannot parse a string callee, it means this is an indirect call.
if (!parser
.parseOptionalAttribute(calleeAttr, CIRDialect::getCalleeAttrName(),
@@ -814,24 +806,6 @@ static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,
if (parser.resolveOperands(ops, opsFnTy.getInputs(), opsLoc, result.operands))
return mlir::failure();
- if (hasDestinationBlocks) {
- // The TryCall ODS layout is: cont, landing_pad, operands.
- llvm::copy(::llvm::ArrayRef<int32_t>(
- {static_cast<int32_t>(continueOperands.size()),
- static_cast<int32_t>(landingPadOperands.size()),
- static_cast<int32_t>(ops.size())}),
- result.getOrAddProperties<cir::TryCallOp::Properties>()
- .operandSegmentSizes.begin());
-
- if (parser.resolveOperands(continueOperands, continueTypes,
- continueOperandsLoc, result.operands))
- return ::mlir::failure();
-
- if (parser.resolveOperands(landingPadOperands, landingPadTypes,
- landingPadOperandsLoc, result.operands))
- return ::mlir::failure();
- }
-
return mlir::success();
}
@@ -863,25 +837,9 @@ static void printCallCommon(mlir::Operation *op,
auto tryCall = dyn_cast<cir::TryCallOp>(op);
assert(tryCall && "regular calls do not branch");
printer << ' ' << tryCall.getNormalDest();
- if (!tryCall.getNormalDestOperands().empty()) {
- printer << "(";
- printer << tryCall.getNormalDestOperands();
- printer << ' ' << ":";
- printer << ' ';
- printer << tryCall.getNormalDestOperands().getTypes();
- printer << ")";
- }
printer << ",";
printer << ' ';
printer << tryCall.getUnwindDest();
- if (!tryCall.getUnwindDestOperands().empty()) {
- printer << "(";
- printer << tryCall.getUnwindDestOperands();
- printer << ' ' << ":";
- printer << ' ';
- printer << tryCall.getUnwindDestOperands().getTypes();
- printer << ")";
- }
}
if (isNothrow)
@@ -1032,17 +990,6 @@ void cir::TryCallOp::print(::mlir::OpAsmPrinter &p) {
sideEffect, getNormalDest(), getUnwindDest());
}
-mlir::SuccessorOperands cir::TryCallOp::getSuccessorOperands(unsigned index) {
- assert(index < getNumSuccessors() && "invalid successor index");
- if (index == 0)
- return SuccessorOperands(getNormalDestOperandsMutable());
- if (index == 1)
- return SuccessorOperands(getUnwindDestOperandsMutable());
-
- // index == 2
- return SuccessorOperands(getArgOperandsMutable());
-}
-
//===----------------------------------------------------------------------===//
// ReturnOp
//===----------------------------------------------------------------------===//
>From 664ae531ed10a26e31e9ffe2e912b2929d444d42 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Wed, 26 Nov 2025 19:20:32 +0100
Subject: [PATCH 4/5] Address code review comments
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 7 +++---
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 6 ++---
clang/test/CIR/IR/try-call.cir | 24 ++++++++++++--------
3 files changed, 20 insertions(+), 17 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index a4f995b1a463a..5f5fab6f12300 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2860,9 +2860,10 @@ def CIR_TryCallOp : CIR_CallOpBase<"try_call",[
]> {
let summary = "try_call operation";
let description = [{
- Mostly similar to `cir.call` but requires two destination
- branches, one for follow on regular control-flow, and the other
- one for handling exceptions in case it's thrown.
+ Similar to `cir.call` but requires two destination blocks,
+ one which is used if the call returns without throwing an
+ exception (the "normal" destination) and another which is used
+ if an exception is thrown (the "unwind" destination).
This operation is used only after the CFG flatterning pass.
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 50e1eeea2944f..93c6370d3c1f8 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -833,9 +833,8 @@ static void printCallCommon(mlir::Operation *op,
printer << "(" << ops << ")";
if (normalDest) {
- assert(landingPad && "expected two successors");
- auto tryCall = dyn_cast<cir::TryCallOp>(op);
- assert(tryCall && "regular calls do not branch");
+ assert(unwindDest && "expected two successors");
+ auto tryCall = cast<cir::TryCallOp>(op);
printer << ' ' << tryCall.getNormalDest();
printer << ",";
printer << ' ';
@@ -856,7 +855,6 @@ static void printCallCommon(mlir::Operation *op,
CIRDialect::getSideEffectAttrName(),
CIRDialect::getOperandSegmentSizesAttrName()};
printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
-
printer << " : ";
printer.printFunctionalType(op->getOperands().getTypes(),
op->getResultTypes());
diff --git a/clang/test/CIR/IR/try-call.cir b/clang/test/CIR/IR/try-call.cir
index 6c23d3add15c8..bb3f83071e5f7 100644
--- a/clang/test/CIR/IR/try-call.cir
+++ b/clang/test/CIR/IR/try-call.cir
@@ -9,22 +9,26 @@ cir.func private @division(%a: !s32i, %b: !s32i) -> !s32i
cir.func @flatten_structure_with_try_call_op() {
%a = cir.const #cir.int<1> : !s32i
%b = cir.const #cir.int<2> : !s32i
- %3 = cir.try_call @division(%a, %b) ^continue, ^landing_pad : (!s32i, !s32i) -> !s32i
- ^continue:
- cir.br ^landing_pad
- ^landing_pad:
+ %3 = cir.try_call @division(%a, %b) ^normal, ^unwind : (!s32i, !s32i) -> !s32i
+ ^normal:
+ cir.br ^end
+ ^unwind:
+ cir.br ^end
+ ^end:
cir.return
}
// CHECK: cir.func private @division(!s32i, !s32i) -> !s32i
// CHECK: cir.func @flatten_structure_with_try_call_op() {
-// CHECK-NEXT: %[[CONST_0:.*]] = cir.const #cir.int<1> : !s32i
-// CHECK-NEXT: %[[CONST_1:.*]] = cir.const #cir.int<2> : !s32i
-// CHECK-NEXT: %[[CALL:.*]] = cir.try_call @division(%0, %1) ^[[CONTINUE:.*]], ^[[LANDING_PAD:.*]] : (!s32i, !s32i) -> !s32i
-// CHECK-NEXT: ^[[CONTINUE]]:
-// CHECK-NEXT: cir.br ^[[LANDING_PAD]]
-// CHECK-NEXT: ^[[LANDING_PAD]]:
+// CHECK-NEXT: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i
+// CHECK-NEXT: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i
+// CHECK-NEXT: %[[CALL:.*]] = cir.try_call @division(%[[CONST_1]], %[[CONST_2]]) ^[[NORMAL:.*]], ^[[UNWIND:.*]] : (!s32i, !s32i) -> !s32i
+// CHECK-NEXT: ^[[normal]]:
+// CHECK-NEXT: cir.br ^[[END:.*]]
+// CHECK-NEXT: ^[[unwind]]:
+// CHECK-NEXT: cir.br ^[[END:.*]]
+// CHECK-NEXT: ^[[END]]:
// CHECK-NEXT: cir.return
// CHECK-NEXT: }
>From ddec3434696fcf518faec421a7335b2d89827bc9 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Thu, 27 Nov 2025 21:00:08 +0100
Subject: [PATCH 5/5] Address code review comments
---
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 93c6370d3c1f8..d505ca141d383 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -850,7 +850,7 @@ static void printCallCommon(mlir::Operation *op,
printer << ")";
}
- llvm::SmallVector<::llvm::StringRef, 4> elidedAttrs = {
+ llvm::SmallVector<::llvm::StringRef> elidedAttrs = {
CIRDialect::getCalleeAttrName(), CIRDialect::getNoThrowAttrName(),
CIRDialect::getSideEffectAttrName(),
CIRDialect::getOperandSegmentSizesAttrName()};
More information about the cfe-commits
mailing list