https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/165303
>From 4ced0fbcfd6a9c2b5a6a0a1c2fc14e8e57d65a62 Mon Sep 17 00:00:00 2001 From: Amr Hesham <[email protected]> Date: Mon, 27 Oct 2025 19:55:44 +0100 Subject: [PATCH 1/3] [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 a19c4f951fff9..09ac92d2598d8 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 6bf543cf794b7..9f820319eaf10 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -715,13 +715,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(), @@ -743,6 +808,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())); @@ -775,6 +848,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(); } @@ -782,7 +873,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); @@ -796,8 +889,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"; @@ -807,10 +927,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(), @@ -892,6 +1013,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 6136d48204e0c..81a791a6ad1e0 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1478,7 +1478,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); @@ -1507,7 +1509,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. @@ -1545,17 +1547,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(); } @@ -1566,6 +1572,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 84daae623163971ae714f9d4e9d9d126901df588 Mon Sep 17 00:00:00 2001 From: Amr Hesham <[email protected]> Date: Thu, 20 Nov 2025 18:42:47 +0100 Subject: [PATCH 2/3] 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 09ac92d2598d8..87f9b6f70130c 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 9f820319eaf10..686b476e07321 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -716,58 +716,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(); } @@ -809,10 +772,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(); } @@ -874,8 +834,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); @@ -892,28 +852,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 << ")"; } } @@ -1063,15 +1023,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 81a791a6ad1e0..6136d48204e0c 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1478,9 +1478,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); @@ -1509,7 +1507,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. @@ -1547,21 +1545,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(); } @@ -1572,14 +1566,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 d03d7ea608b02074caa80876c0f4426254848769 Mon Sep 17 00:00:00 2001 From: Amr Hesham <[email protected]> Date: Thu, 20 Nov 2025 21:57:46 +0100 Subject: [PATCH 3/3] 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 87f9b6f70130c..8438a8a0c46f9 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 686b476e07321..4baf4358aedff 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -742,14 +742,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(), @@ -808,24 +800,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(); } @@ -857,25 +831,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) @@ -1026,17 +984,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 //===----------------------------------------------------------------------===// _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
