[clang] [CIR] Upstream Re-Throw with no return (PR #154994)
Amr Hesham via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 29 10:31:07 PDT 2025
https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/154994
>From f8c9593d519edadfe46a796333f1a590a6f0cdd4 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Fri, 22 Aug 2025 15:34:47 +0200
Subject: [PATCH 1/5] [CIR] Upstream Re-Throw with no return
---
.../CIR/Dialect/Builder/CIRBaseBuilder.h | 21 +++++++-
clang/include/clang/CIR/Dialect/IR/CIROps.td | 54 +++++++++++++++++++
clang/lib/CIR/CodeGen/CIRGenCXXABI.h | 4 +-
clang/lib/CIR/CodeGen/CIRGenException.cpp | 41 ++++++++++++++
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 5 ++
clang/lib/CIR/CodeGen/CIRGenFunction.h | 2 +
clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 50 ++++++++++++++++-
clang/lib/CIR/CodeGen/CMakeLists.txt | 1 +
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 18 +++++++
.../Dialect/Transforms/LoweringPrepare.cpp | 24 ++++++++-
clang/test/CIR/CodeGen/exceptions.cpp | 19 +++++++
11 files changed, 235 insertions(+), 4 deletions(-)
create mode 100644 clang/lib/CIR/CodeGen/CIRGenException.cpp
create mode 100644 clang/test/CIR/CodeGen/exceptions.cpp
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index d29e5687d2544..aba4615b2a7f4 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -19,7 +19,6 @@
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
-#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Location.h"
#include "mlir/IR/Types.h"
@@ -313,6 +312,26 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
resOperands, attrs);
}
+ cir::CallOp
+ createTryCallOp(mlir::Location loc,
+ mlir::SymbolRefAttr callee = mlir::SymbolRefAttr(),
+ mlir::Type returnType = cir::VoidType(),
+ mlir::ValueRange operands = mlir::ValueRange(),
+ cir::SideEffect sideEffect = cir::SideEffect::All) {
+ assert(!cir::MissingFeatures::opCallCallConv());
+ return createCallOp(loc, callee, returnType, operands);
+ }
+
+ cir::CallOp
+ createTryCallOp(mlir::Location loc, cir::FuncOp callee,
+ mlir::ValueRange operands,
+ cir::SideEffect sideEffect = cir::SideEffect::All) {
+ assert(!cir::MissingFeatures::opCallCallConv());
+ return createTryCallOp(loc, mlir::SymbolRefAttr::get(callee),
+ callee.getFunctionType().getReturnType(), operands,
+ sideEffect);
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 2b7a709b80c26..c922c9f099ac4 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3864,4 +3864,58 @@ def CIR_VAArgOp : CIR_Op<"va_arg"> {
}];
}
+//===----------------------------------------------------------------------===//
+// ThrowOp
+//===----------------------------------------------------------------------===//
+
+def CIR_ThrowOp : CIR_Op<"throw"> {
+ let summary = "(Re)Throws an exception";
+ let description = [{
+ Very similar to __cxa_throw:
+
+ ```
+ void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
+ void (*dest) (void *));
+ ```
+
+ The absense of arguments for `cir.throw` means it rethrows.
+
+ For the no-rethrow version, it must have at least two operands, the RTTI
+ information, a pointer to the exception object (likely allocated via
+ `cir.cxa.allocate_exception`) and finally an optional dtor, which might
+ run as part of this operation.
+
+ Example:
+ ```mlir
+ // throw;
+ cir.throw
+
+ // if (b == 0)
+ // throw "Division by zero condition!";
+ cir.if %cond {
+ %exception_addr = cir.alloc_exception 8 -> !cir.ptr<!void>
+ ...
+ cir.store %string_addr, %exception_addr : // Store string addr for "Division by zero condition!"
+ cir.throw %exception_addr : !cir.ptr<!cir.ptr<!u8i>>, @"typeinfo for char const*"
+ ```
+ }];
+
+ let arguments = (ins Optional<CIR_PointerType>:$exception_ptr,
+ OptionalAttr<FlatSymbolRefAttr>:$type_info,
+ OptionalAttr<FlatSymbolRefAttr>:$dtor);
+
+ let assemblyFormat = [{
+ ($exception_ptr^ `:` type($exception_ptr))?
+ (`,` $type_info^)?
+ (`,` $dtor^)?
+ attr-dict
+ }];
+
+ let extraClassDeclaration = [{
+ bool rethrows() { return getNumOperands() == 0; }
+ }];
+
+ let hasVerifier = 1;
+}
+
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index df7ffbb4a2759..7c620301499ff 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -53,9 +53,11 @@ class CIRGenCXXABI {
}
/// Emit the ABI-specific prolog for the function
- virtual void emitInstanceFunctionProlog(SourceLocation Loc,
+ virtual void emitInstanceFunctionProlog(SourceLocation loc,
CIRGenFunction &cgf) = 0;
+ virtual void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) = 0;
+
/// Get the type of the implicit "this" parameter used by a method. May return
/// zero if no specific type is applicable, e.g. if the ABI expects the "this"
/// parameter to point to some artificial offset in a complete object due to
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp
new file mode 100644
index 0000000000000..7fcb39a2b74c4
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -0,0 +1,41 @@
+//===--- CIRGenException.cpp - Emit CIR Code for C++ exceptions -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code dealing with C++ exception related code generation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenCXXABI.h"
+#include "CIRGenFunction.h"
+
+#include "clang/AST/StmtVisitor.h"
+
+using namespace clang;
+using namespace clang::CIRGen;
+
+void CIRGenFunction::emitCXXThrowExpr(const CXXThrowExpr *e) {
+ const llvm::Triple &triple = getTarget().getTriple();
+ if (cgm.getLangOpts().OpenMPIsTargetDevice &&
+ (triple.isNVPTX() || triple.isAMDGCN())) {
+ cgm.errorNYI("emitCXXThrowExpr OpenMP with NVPTX or AMDGCN Triples");
+ return;
+ }
+
+ if (const Expr *subExpr = e->getSubExpr()) {
+ QualType throwType = subExpr->getType();
+ if (throwType->isObjCObjectPointerType()) {
+ cgm.errorNYI("emitCXXThrowExpr ObjCObjectPointerType");
+ return;
+ } else {
+ cgm.errorNYI("emitCXXThrowExpr with subExpr");
+ return;
+ }
+ } else {
+ cgm.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);
+ }
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 46934e7155adf..f0bebfeb19430 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -657,6 +657,11 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
return cgf.emitCXXNewExpr(e);
}
+ mlir::Value VisitCXXThrowExpr(const CXXThrowExpr *e) {
+ cgf.emitCXXThrowExpr(e);
+ return nullptr;
+ }
+
/// Emit a conversion from the specified type to the specified destination
/// type, both of which are CIR scalar types.
/// TODO: do we need ScalarConversionOpts here? Should be done in another
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index c799ecdc27538..39bacfb97a3ec 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1143,6 +1143,8 @@ class CIRGenFunction : public CIRGenTypeCache {
RValue emitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *expr);
+ void emitCXXThrowExpr(const CXXThrowExpr *e);
+
void emitCtorPrologue(const clang::CXXConstructorDecl *ctor,
clang::CXXCtorType ctorType, FunctionArgList &args);
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 4fd5a278e1a99..120c3331ff58a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -56,6 +56,8 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
bool delegating, Address thisAddr,
QualType thisTy) override;
+ void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
+
bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
CXXDtorType dt) const override {
// Itanium does not emit any destructor variant as an inline thunk.
@@ -125,7 +127,7 @@ void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc,
// Find out how to cirgen the complete destructor and constructor
namespace {
enum class StructorCIRGen { Emit, RAUW, Alias, COMDAT };
-}
+} // namespace
static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm,
const CXXMethodDecl *md) {
@@ -352,6 +354,52 @@ void CIRGenItaniumCXXABI::emitDestructorCall(
vttTy, nullptr);
}
+// The idea here is creating a separate block for the throw with an
+// `UnreachableOp` as the terminator. So, we branch from the current block
+// to the throw block and create a block for the remaining operations.
+static void insertThrowAndSplit(mlir::OpBuilder &builder, mlir::Location loc,
+ mlir::Value exceptionPtr = {},
+ mlir::FlatSymbolRefAttr typeInfo = {},
+ mlir::FlatSymbolRefAttr dtor = {}) {
+ mlir::Block *currentBlock = builder.getInsertionBlock();
+ mlir::Region *region = currentBlock->getParent();
+
+ if (currentBlock->empty()) {
+ cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);
+ cir::UnreachableOp::create(builder, loc);
+ } else {
+ mlir::Block *throwBlock = builder.createBlock(region);
+
+ cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);
+ cir::UnreachableOp::create(builder, loc);
+
+ builder.setInsertionPointToEnd(currentBlock);
+ cir::BrOp::create(builder, loc, throwBlock);
+ }
+
+ (void)builder.createBlock(region);
+
+ // This will be erased during codegen, it acts as a placeholder for the
+ // operations to be inserted (if any)
+ cir::ScopeOp::create(builder, loc, /*scopeBuilder=*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ b.create<cir::YieldOp>(loc);
+ });
+}
+
+void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &cgf, bool isNoReturn) {
+ // void __cxa_rethrow();
+
+ if (isNoReturn) {
+ CIRGenBuilderTy &builder = cgf.getBuilder();
+ assert(cgf.currSrcLoc && "expected source location");
+ mlir::Location loc = *cgf.currSrcLoc;
+ insertThrowAndSplit(builder, loc);
+ } else {
+ cgm.errorNYI("emitRethrow with isNoReturn false");
+ }
+}
+
CIRGenCXXABI *clang::CIRGen::CreateCIRGenItaniumCXXABI(CIRGenModule &cgm) {
switch (cgm.getASTContext().getCXXABIKind()) {
case TargetCXXABI::GenericItanium:
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt
index 7366446a33c6e..6d7072ad18696 100644
--- a/clang/lib/CIR/CodeGen/CMakeLists.txt
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -20,6 +20,7 @@ add_clang_library(clangCIR
CIRGenBuiltin.cpp
CIRGenDecl.cpp
CIRGenDeclOpenACC.cpp
+ CIRGenException.cpp
CIRGenExpr.cpp
CIRGenExprAggregate.cpp
CIRGenExprComplex.cpp
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 83fff09d4fab3..aa3bf26610a13 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2697,6 +2697,24 @@ ParseResult cir::InlineAsmOp::parse(OpAsmParser &parser,
return mlir::success();
}
+//===----------------------------------------------------------------------===//
+// ThrowOp
+//===----------------------------------------------------------------------===//
+
+mlir::LogicalResult cir::ThrowOp::verify() {
+ // For the no-rethrow version, it must have at least the exception pointer.
+ if (rethrows())
+ return success();
+
+ if (getNumOperands() == 1) {
+ if (getTypeInfo())
+ return success();
+ return emitOpError() << "'type_info' symbol attribute missing";
+ }
+
+ return failure();
+}
+
//===----------------------------------------------------------------------===//
// TableGen'd op method definitions
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index c15637d297cd1..cccfe9b444a31 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -32,6 +32,7 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
void lowerUnaryOp(cir::UnaryOp op);
void lowerArrayDtor(cir::ArrayDtor op);
void lowerArrayCtor(cir::ArrayCtor op);
+ void lowerThrowOp(ThrowOp op);
cir::FuncOp buildRuntimeFunction(
mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
@@ -680,6 +681,24 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) {
true);
}
+void LoweringPreparePass::lowerThrowOp(ThrowOp op) {
+ if (op.rethrows()) {
+ CIRBaseBuilderTy builder(getContext());
+ auto voidTy = cir::VoidType::get(builder.getContext());
+ auto fnType = cir::FuncType::get({}, voidTy);
+
+ builder.setInsertionPointToStart(&mlirModule.getBodyRegion().front());
+ FuncOp f =
+ buildRuntimeFunction(builder, "__cxa_rethrow", op.getLoc(), fnType);
+
+ builder.setInsertionPointAfter(op.getOperation());
+ cir::CallOp call = builder.createTryCallOp(op.getLoc(), f, {});
+
+ op->replaceAllUsesWith(call);
+ op->erase();
+ }
+}
+
void LoweringPreparePass::runOnOp(mlir::Operation *op) {
if (auto arrayCtor = dyn_cast<ArrayCtor>(op))
lowerArrayCtor(arrayCtor);
@@ -693,6 +712,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
lowerComplexMulOp(complexMul);
else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op))
lowerUnaryOp(unary);
+ else if (auto throwOp = mlir::dyn_cast<cir::ThrowOp>(op))
+ lowerThrowOp(throwOp);
}
void LoweringPreparePass::runOnOperation() {
@@ -704,7 +725,8 @@ void LoweringPreparePass::runOnOperation() {
op->walk([&](mlir::Operation *op) {
if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
- cir::ComplexMulOp, cir::ComplexDivOp, cir::UnaryOp>(op))
+ cir::ComplexMulOp, cir::ComplexDivOp, cir::UnaryOp,
+ cir::ThrowOp>(op))
opsToTransform.push_back(op);
});
diff --git a/clang/test/CIR/CodeGen/exceptions.cpp b/clang/test/CIR/CodeGen/exceptions.cpp
new file mode 100644
index 0000000000000..a1a87bcb2f393
--- /dev/null
+++ b/clang/test/CIR/CodeGen/exceptions.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fcxx-exceptions -fexceptions -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+void foo() {
+ throw;
+}
+
+// CIR: cir.call @__cxa_rethrow() : () -> ()
+// CIR: cir.unreachable
+
+// LLVM: call void @__cxa_rethrow()
+// LLVM: unreachable
+
+// OGCG: call void @__cxa_rethrow()
+// OGCG: unreachable
>From 726d5baf6552766919e300d18c92ccdab74dac7d Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Fri, 22 Aug 2025 20:46:26 +0200
Subject: [PATCH 2/5] Rename test file to throws to be alligned with incubator
for now
---
clang/test/CIR/CodeGen/{exceptions.cpp => throws.cpp} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename clang/test/CIR/CodeGen/{exceptions.cpp => throws.cpp} (100%)
diff --git a/clang/test/CIR/CodeGen/exceptions.cpp b/clang/test/CIR/CodeGen/throws.cpp
similarity index 100%
rename from clang/test/CIR/CodeGen/exceptions.cpp
rename to clang/test/CIR/CodeGen/throws.cpp
>From 50e221c51a051e7851d1eef0938dae22a1739c98 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Fri, 22 Aug 2025 23:53:41 +0200
Subject: [PATCH 3/5] Address code review comments
---
.../CIR/Dialect/Builder/CIRBaseBuilder.h | 23 +++----
clang/include/clang/CIR/Dialect/IR/CIROps.td | 2 +-
clang/include/clang/CIR/MissingFeatures.h | 1 +
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 2 +-
clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 10 +--
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 2 +-
.../Dialect/Transforms/LoweringPrepare.cpp | 24 +------
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 45 ++++++++++--
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 10 +++
clang/test/CIR/CodeGen/throws.cpp | 68 ++++++++++++++++++-
clang/test/CIR/IR/invalid-throw.cir | 16 +++++
clang/test/CIR/IR/throw.cir | 63 +++++++++++++++++
12 files changed, 214 insertions(+), 52 deletions(-)
create mode 100644 clang/test/CIR/IR/invalid-throw.cir
create mode 100644 clang/test/CIR/IR/throw.cir
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index aba4615b2a7f4..96f55f5c66071 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -312,24 +312,23 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
resOperands, attrs);
}
- cir::CallOp
- createTryCallOp(mlir::Location loc,
- mlir::SymbolRefAttr callee = mlir::SymbolRefAttr(),
- mlir::Type returnType = cir::VoidType(),
- mlir::ValueRange operands = mlir::ValueRange(),
- cir::SideEffect sideEffect = cir::SideEffect::All) {
+ cir::CallOp createTryCallOp(
+ mlir::Location loc, mlir::SymbolRefAttr callee = mlir::SymbolRefAttr(),
+ mlir::Type returnType = cir::VoidType(),
+ mlir::ValueRange operands = mlir::ValueRange(),
+ [[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) {
assert(!cir::MissingFeatures::opCallCallConv());
+ assert(!cir::MissingFeatures::opCallSideEffect());
return createCallOp(loc, callee, returnType, operands);
}
- cir::CallOp
- createTryCallOp(mlir::Location loc, cir::FuncOp callee,
- mlir::ValueRange operands,
- cir::SideEffect sideEffect = cir::SideEffect::All) {
+ cir::CallOp createTryCallOp(
+ mlir::Location loc, cir::FuncOp callee, mlir::ValueRange operands,
+ [[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) {
assert(!cir::MissingFeatures::opCallCallConv());
+ assert(!cir::MissingFeatures::opCallSideEffect());
return createTryCallOp(loc, mlir::SymbolRefAttr::get(callee),
- callee.getFunctionType().getReturnType(), operands,
- sideEffect);
+ callee.getFunctionType().getReturnType(), operands);
}
//===--------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index c922c9f099ac4..7c231e187f10c 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3871,7 +3871,7 @@ def CIR_VAArgOp : CIR_Op<"va_arg"> {
def CIR_ThrowOp : CIR_Op<"throw"> {
let summary = "(Re)Throws an exception";
let description = [{
- Very similar to __cxa_throw:
+ It's equivalent __cxa_throw:
```
void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index a8be2a2374d6e..6a8bab2b7f069 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -93,6 +93,7 @@ struct MissingFeatures {
static bool opCallReturn() { return false; }
static bool opCallArgEvaluationOrder() { return false; }
static bool opCallCallConv() { return false; }
+ static bool opCallSideEffect() { return false; }
static bool opCallMustTail() { return false; }
static bool opCallInAlloca() { return false; }
static bool opCallAttrs() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index f0bebfeb19430..406d8398098b3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -659,7 +659,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
mlir::Value VisitCXXThrowExpr(const CXXThrowExpr *e) {
cgf.emitCXXThrowExpr(e);
- return nullptr;
+ return {};
}
/// Emit a conversion from the specified type to the specified destination
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 120c3331ff58a..ab7a0699637b9 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -127,7 +127,7 @@ void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc,
// Find out how to cirgen the complete destructor and constructor
namespace {
enum class StructorCIRGen { Emit, RAUW, Alias, COMDAT };
-} // namespace
+}
static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm,
const CXXMethodDecl *md) {
@@ -378,18 +378,10 @@ static void insertThrowAndSplit(mlir::OpBuilder &builder, mlir::Location loc,
}
(void)builder.createBlock(region);
-
- // This will be erased during codegen, it acts as a placeholder for the
- // operations to be inserted (if any)
- cir::ScopeOp::create(builder, loc, /*scopeBuilder=*/
- [&](mlir::OpBuilder &b, mlir::Location loc) {
- b.create<cir::YieldOp>(loc);
- });
}
void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &cgf, bool isNoReturn) {
// void __cxa_rethrow();
-
if (isNoReturn) {
CIRGenBuilderTy &builder = cgf.getBuilder();
assert(cgf.currSrcLoc && "expected source location");
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index aa3bf26610a13..80ca2d371792a 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2706,7 +2706,7 @@ mlir::LogicalResult cir::ThrowOp::verify() {
if (rethrows())
return success();
- if (getNumOperands() == 1) {
+ if (getNumOperands() != 0) {
if (getTypeInfo())
return success();
return emitOpError() << "'type_info' symbol attribute missing";
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index cccfe9b444a31..c15637d297cd1 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -32,7 +32,6 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
void lowerUnaryOp(cir::UnaryOp op);
void lowerArrayDtor(cir::ArrayDtor op);
void lowerArrayCtor(cir::ArrayCtor op);
- void lowerThrowOp(ThrowOp op);
cir::FuncOp buildRuntimeFunction(
mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
@@ -681,24 +680,6 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) {
true);
}
-void LoweringPreparePass::lowerThrowOp(ThrowOp op) {
- if (op.rethrows()) {
- CIRBaseBuilderTy builder(getContext());
- auto voidTy = cir::VoidType::get(builder.getContext());
- auto fnType = cir::FuncType::get({}, voidTy);
-
- builder.setInsertionPointToStart(&mlirModule.getBodyRegion().front());
- FuncOp f =
- buildRuntimeFunction(builder, "__cxa_rethrow", op.getLoc(), fnType);
-
- builder.setInsertionPointAfter(op.getOperation());
- cir::CallOp call = builder.createTryCallOp(op.getLoc(), f, {});
-
- op->replaceAllUsesWith(call);
- op->erase();
- }
-}
-
void LoweringPreparePass::runOnOp(mlir::Operation *op) {
if (auto arrayCtor = dyn_cast<ArrayCtor>(op))
lowerArrayCtor(arrayCtor);
@@ -712,8 +693,6 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
lowerComplexMulOp(complexMul);
else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op))
lowerUnaryOp(unary);
- else if (auto throwOp = mlir::dyn_cast<cir::ThrowOp>(op))
- lowerThrowOp(throwOp);
}
void LoweringPreparePass::runOnOperation() {
@@ -725,8 +704,7 @@ void LoweringPreparePass::runOnOperation() {
op->walk([&](mlir::Operation *op) {
if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
- cir::ComplexMulOp, cir::ComplexDivOp, cir::UnaryOp,
- cir::ThrowOp>(op))
+ cir::ComplexMulOp, cir::ComplexDivOp, cir::UnaryOp>(op))
opsToTransform.push_back(op);
});
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 03955dc737828..f1fdfed166bbc 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2435,6 +2435,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMStackRestoreOpLowering,
CIRToLLVMStackSaveOpLowering,
CIRToLLVMSwitchFlatOpLowering,
+ CIRToLLVMThrowOpLowering,
CIRToLLVMTrapOpLowering,
CIRToLLVMUnaryOpLowering,
CIRToLLVMUnreachableOpLowering,
@@ -2515,6 +2516,42 @@ mlir::LogicalResult CIRToLLVMUnreachableOpLowering::matchAndRewrite(
return mlir::success();
}
+void createLLVMFuncOpIfNotExist(mlir::ConversionPatternRewriter &rewriter,
+ mlir::Operation *srcOp, llvm::StringRef fnName,
+ mlir::Type fnTy) {
+ auto modOp = srcOp->getParentOfType<mlir::ModuleOp>();
+ auto enclosingFnOp = srcOp->getParentOfType<mlir::LLVM::LLVMFuncOp>();
+ mlir::Operation *sourceSymbol =
+ mlir::SymbolTable::lookupSymbolIn(modOp, fnName);
+ if (!sourceSymbol) {
+ mlir::OpBuilder::InsertionGuard guard(rewriter);
+ rewriter.setInsertionPoint(enclosingFnOp);
+ rewriter.create<mlir::LLVM::LLVMFuncOp>(srcOp->getLoc(), fnName, fnTy);
+ }
+}
+
+mlir::LogicalResult CIRToLLVMThrowOpLowering::matchAndRewrite(
+ cir::ThrowOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ if (op.rethrows()) {
+ auto voidTy = mlir::LLVM::LLVMVoidType::get(getContext());
+ auto funcTy =
+ mlir::LLVM::LLVMFunctionType::get(getContext(), voidTy, {}, false);
+
+ auto mlirModule = op->getParentOfType<mlir::ModuleOp>();
+ rewriter.setInsertionPointToStart(&mlirModule.getBodyRegion().front());
+
+ const llvm::StringRef functionName = "__cxa_rethrow";
+ createLLVMFuncOpIfNotExist(rewriter, op, functionName, funcTy);
+
+ rewriter.setInsertionPointAfter(op.getOperation());
+ rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
+ op, mlir::TypeRange{}, functionName, mlir::ValueRange{});
+ }
+
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMTrapOpLowering::matchAndRewrite(
cir::TrapOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -3160,7 +3197,7 @@ mlir::LogicalResult CIRToLLVMInlineAsmOpLowering::matchAndRewrite(
SmallVector<mlir::Value> llvmOperands;
SmallVector<mlir::Value> cirOperands;
- for (auto const&[llvmOp, cirOp] :
+ for (auto const &[llvmOp, cirOp] :
zip(adaptor.getAsmOperands(), op.getAsmOperands())) {
append_range(llvmOperands, llvmOp);
append_range(cirOperands, cirOp);
@@ -3168,15 +3205,15 @@ mlir::LogicalResult CIRToLLVMInlineAsmOpLowering::matchAndRewrite(
// so far we infer the llvm dialect element type attr from
// CIR operand type.
- for (auto const&[cirOpAttr, cirOp] : zip(op.getOperandAttrs(), cirOperands)) {
+ for (auto const &[cirOpAttr, cirOp] :
+ zip(op.getOperandAttrs(), cirOperands)) {
if (!cirOpAttr) {
opAttrs.push_back(mlir::Attribute());
continue;
}
llvm::SmallVector<mlir::NamedAttribute, 1> attrs;
- cir::PointerType typ =
- mlir::cast<cir::PointerType>(cirOp.getType());
+ cir::PointerType typ = mlir::cast<cir::PointerType>(cirOp.getType());
mlir::TypeAttr typAttr = mlir::TypeAttr::get(convertTypeForMemory(
*getTypeConverter(), dataLayout, typ.getPointee()));
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 513ad37839f1b..da7df8982d34c 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -735,6 +735,16 @@ class CIRToLLVMInlineAsmOpLowering
mlir::ConversionPatternRewriter &) const override;
};
+class CIRToLLVMThrowOpLowering
+ : public mlir::OpConversionPattern<cir::ThrowOp> {
+public:
+ using mlir::OpConversionPattern<cir::ThrowOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::ThrowOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
class CIRToLLVMVAStartOpLowering
: public mlir::OpConversionPattern<cir::VAStartOp> {
public:
diff --git a/clang/test/CIR/CodeGen/throws.cpp b/clang/test/CIR/CodeGen/throws.cpp
index a1a87bcb2f393..0122f3088f0bf 100644
--- a/clang/test/CIR/CodeGen/throws.cpp
+++ b/clang/test/CIR/CodeGen/throws.cpp
@@ -9,7 +9,7 @@ void foo() {
throw;
}
-// CIR: cir.call @__cxa_rethrow() : () -> ()
+// CIR: cir.throw
// CIR: cir.unreachable
// LLVM: call void @__cxa_rethrow()
@@ -17,3 +17,69 @@ void foo() {
// OGCG: call void @__cxa_rethrow()
// OGCG: unreachable
+
+int foo1(int a, int b) {
+ if (b == 0)
+ throw;
+ return a / b;
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init]
+// CIR: %[[RES_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
+// CIR: cir.store %{{.*}}, %[[A_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.store %{{.*}}, %[[B_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.scope {
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: %[[IS_B_ZERO:.*]] = cir.cmp(eq, %[[TMP_B]], %[[CONST_0]]) : !s32i, !cir.bool
+// CIR: cir.if %[[IS_B_ZERO]] {
+// CIR: cir.throw
+// CIR: cir.unreachable
+// CIR: }
+// CIR: }
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[DIV_A_B:.*]] = cir.binop(div, %[[TMP_A:.*]], %[[TMP_B:.*]]) : !s32i
+// CIR: cir.store %[[DIV_A_B]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[RESULT:.*]] = cir.load %[[RES_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR: cir.return %[[RESULT]] : !s32i
+
+// LLVM: %[[A_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM: %[[B_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM: %[[RES_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM: store i32 %{{.*}}, ptr %[[A_ADDR]], align 4
+// LLVM: store i32 %{{.*}}, ptr %[[B_ADDR]], align 4
+// LLVM: br label %[[CHECK_COND:.*]]
+// LLVM: [[CHECK_COND]]:
+// LLVM: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// LLVM: %[[IS_B_ZERO:.*]] = icmp eq i32 %[[TMP_B]], 0
+// LLVM: br i1 %[[IS_B_ZERO]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+// LLVM: [[IF_THEN]]:
+// LLVM: call void @__cxa_rethrow()
+// LLVM: unreachable
+// LLVM: [[IF_ELSE]]:
+// LLVM: br label %[[IF_END:.*]]
+// LLVM: [[IF_END]]:
+// LLVM: %[[TMP_A:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// LLVM: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// LLVM: %[[DIV_A_B:.*]] = sdiv i32 %[[TMP_A]], %[[TMP_B]]
+// LLVM: store i32 %[[DIV_A_B]], ptr %[[RES_ADDR]], align 4
+// LLVM: %[[RESULT:.*]] = load i32, ptr %[[RES_ADDR]], align 4
+// LLVM: ret i32 %[[RESULT]]
+
+// OGCG: %[[A_ADDR:.*]] = alloca i32, align 4
+// OGCG: %[[B_ADDR:.*]] = alloca i32, align 4
+// OGCG: store i32 %{{.*}}, ptr %[[A_ADDR]], align 4
+// OGCG: store i32 %{{.*}}, ptr %[[B_ADDR]], align 4
+// OGCG: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// OGCG: %[[IS_B_ZERO:.*]] = icmp eq i32 %[[TMP_B]], 0
+// OGCG: br i1 %[[IS_B_ZERO]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
+// OGCG: [[IF_THEN]]:
+// OGCG: call void @__cxa_rethrow()
+// OGCG: unreachable
+// OGCG: [[IF_END]]:
+// OGCG: %[[TMP_A:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// OGCG: %[[DIV_A_B:.*]] = sdiv i32 %[[TMP_A]], %[[TMP_B]]
+// OGCG: ret i32 %[[DIV_A_B]]
diff --git a/clang/test/CIR/IR/invalid-throw.cir b/clang/test/CIR/IR/invalid-throw.cir
new file mode 100644
index 0000000000000..53582a11b285e
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-throw.cir
@@ -0,0 +1,16 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+!s32i = !cir.int<s, 32>
+
+module {
+
+cir.func dso_local @throw_without_type_info() {
+ %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["a"]
+ // expected-error @below {{'cir.throw' op 'type_info' symbol attribute missing}}
+ cir.throw %0 : !cir.ptr<!s32i>
+ cir.unreachable
+ ^bb1:
+ cir.return
+}
+
+}
diff --git a/clang/test/CIR/IR/throw.cir b/clang/test/CIR/IR/throw.cir
new file mode 100644
index 0000000000000..8b24b481057b1
--- /dev/null
+++ b/clang/test/CIR/IR/throw.cir
@@ -0,0 +1,63 @@
+// RUN: cir-opt %s | FileCheck %s
+
+!s32i = !cir.int<s, 32>
+
+module {
+
+cir.func @throw_with_no_return() {
+ cir.throw
+ cir.unreachable
+}
+
+// CHECK: cir.func @throw_with_no_return() {
+// CHECK: cir.throw
+// CHECK: cir.unreachable
+// CHECK: }
+
+cir.func @throw_with_no_return_2(%arg0: !s32i, %arg1: !s32i) -> !s32i {
+ %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
+ %1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init]
+ %2 = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
+ cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i>
+ cir.store %arg1, %1 : !s32i, !cir.ptr<!s32i>
+ cir.scope {
+ %7 = cir.load align(4) %1 : !cir.ptr<!s32i>, !s32i
+ %8 = cir.const #cir.int<0> : !s32i
+ %9 = cir.cmp(eq, %7, %8) : !s32i, !cir.bool
+ cir.if %9 {
+ cir.throw
+ cir.unreachable
+ }
+ }
+ %3 = cir.load align(4) %0 : !cir.ptr<!s32i>, !s32i
+ %4 = cir.load align(4) %1 : !cir.ptr<!s32i>, !s32i
+ %5 = cir.binop(div, %3, %4) : !s32i
+ cir.store %5, %2 : !s32i, !cir.ptr<!s32i>
+ %6 = cir.load %2 : !cir.ptr<!s32i>, !s32i
+ cir.return %6 : !s32i
+}
+
+// CHECK: cir.func @throw_with_no_return_2(%[[ARG_0:.*]]: !s32i, %[[ARG_1:.*]]: !s32i) -> !s32i {
+// CHECK: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
+// CHECK: %[[B_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init]
+// CHECK: %[[RES_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
+// CHECK: cir.store %[[ARG_0]], %[[A_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CHECK: cir.store %[[ARG_1]], %[[B_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CHECK: cir.scope {
+// CHECK: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CHECK: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i
+// CHECK: %[[IS_B_ZERO:.*]] = cir.cmp(eq, %[[TMP_B]], %[[CONST_0]]) : !s32i, !cir.bool
+// CHECK: cir.if %[[IS_B_ZERO]] {
+// CHECK: cir.throw
+// CHECK: cir.unreachable
+// CHECK: }
+// CHECK: }
+// CHECK: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CHECK: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CHECK: %[[DIV_A_B:.*]] = cir.binop(div, %[[TMP_A:.*]], %[[TMP_B:.*]]) : !s32i
+// CHECK: cir.store %[[DIV_A_B]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CHECK: %[[RESULT:.*]] = cir.load %[[RES_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CHECK: cir.return %[[RESULT]] : !s32i
+// CHECK: }
+
+}
>From 498c1210c42018d38930bca84e1d829dbe9ec6db Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Sat, 23 Aug 2025 17:18:59 +0200
Subject: [PATCH 4/5] Address code review comments
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 33 +++++++++++---------
1 file changed, 19 insertions(+), 14 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 7c231e187f10c..fd3588bded74b 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3882,27 +3882,32 @@ def CIR_ThrowOp : CIR_Op<"throw"> {
For the no-rethrow version, it must have at least two operands, the RTTI
information, a pointer to the exception object (likely allocated via
- `cir.cxa.allocate_exception`) and finally an optional dtor, which might
- run as part of this operation.
+ `cir.alloc_exception`) and finally an optional dtor, which might run as
+ part of this operation.
Example:
```mlir
- // throw;
- cir.throw
+ // throw;
+ cir.throw
- // if (b == 0)
- // throw "Division by zero condition!";
- cir.if %cond {
- %exception_addr = cir.alloc_exception 8 -> !cir.ptr<!void>
- ...
- cir.store %string_addr, %exception_addr : // Store string addr for "Division by zero condition!"
- cir.throw %exception_addr : !cir.ptr<!cir.ptr<!u8i>>, @"typeinfo for char const*"
+ // if (b == 0)
+ // throw "Division by zero condition!";
+ cir.if %cond {
+ %exception_addr = cir.alloc_exception 8 -> !cir.ptr<!void>
+ ...
+ // Store string addr for "Division by zero condition!"
+ cir.store %string_addr, %exception_addr : !cir.ptr<!s8i>,
+ !cir.ptr<!cir.ptr<!s8i>>
+ cir.throw %exception_addr : !cir.ptr<!cir.ptr<!u8i>>,
+ @"typeinfo for char const*"
```
}];
- let arguments = (ins Optional<CIR_PointerType>:$exception_ptr,
- OptionalAttr<FlatSymbolRefAttr>:$type_info,
- OptionalAttr<FlatSymbolRefAttr>:$dtor);
+ let arguments = (ins
+ Optional<CIR_PointerType>:$exception_ptr,
+ OptionalAttr<FlatSymbolRefAttr>:$type_info,
+ OptionalAttr<FlatSymbolRefAttr>:$dtor
+ );
let assemblyFormat = [{
($exception_ptr^ `:` type($exception_ptr))?
>From 22b5a3320b2caab711f981a29186e1eb8b9ce887 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Fri, 29 Aug 2025 19:18:23 +0200
Subject: [PATCH 5/5] Address code review comments
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index fd3588bded74b..982533f5e3b84 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3871,12 +3871,8 @@ def CIR_VAArgOp : CIR_Op<"va_arg"> {
def CIR_ThrowOp : CIR_Op<"throw"> {
let summary = "(Re)Throws an exception";
let description = [{
- It's equivalent __cxa_throw:
-
- ```
- void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
- void (*dest) (void *));
- ```
+ This operation is equivalent to either __cxa_throw or __cxa_rethrow,
+ depending on the arguments.
The absense of arguments for `cir.throw` means it rethrows.
@@ -3886,12 +3882,16 @@ def CIR_ThrowOp : CIR_Op<"throw"> {
part of this operation.
Example:
+
```mlir
- // throw;
+ // re-throw;
cir.throw
// if (b == 0)
// throw "Division by zero condition!";
+
+ // Type info for char const*
+ cir.global "private" constant external @_ZTIPKc : !cir.ptr<!u8i>
cir.if %cond {
%exception_addr = cir.alloc_exception 8 -> !cir.ptr<!void>
...
@@ -3899,7 +3899,7 @@ def CIR_ThrowOp : CIR_Op<"throw"> {
cir.store %string_addr, %exception_addr : !cir.ptr<!s8i>,
!cir.ptr<!cir.ptr<!s8i>>
cir.throw %exception_addr : !cir.ptr<!cir.ptr<!u8i>>,
- @"typeinfo for char const*"
+ @_ZTIPKc
```
}];
More information about the cfe-commits
mailing list