Skip to content

Conversation

AmrDeveloper
Copy link
Member

This change adds support for the throw op without sub expression and with noreturn

Issue #154992

@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Aug 22, 2025
@llvmbot
Copy link
Member

llvmbot commented Aug 22, 2025

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clangir

Author: Amr Hesham (AmrDeveloper)

Changes

This change adds support for the throw op without sub expression and with noreturn

Issue #154992


Full diff: https://github.com/llvm/llvm-project/pull/154994.diff

11 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h (+20-1)
  • (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+54)
  • (modified) clang/lib/CIR/CodeGen/CIRGenCXXABI.h (+3-1)
  • (added) clang/lib/CIR/CodeGen/CIRGenException.cpp (+41)
  • (modified) clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp (+5)
  • (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+2)
  • (modified) clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp (+49-1)
  • (modified) clang/lib/CIR/CodeGen/CMakeLists.txt (+1)
  • (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+18)
  • (modified) clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp (+28-8)
  • (added) clang/test/CIR/CodeGen/exceptions.cpp (+19)
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 f237642700924..708dd35694913 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3757,4 +3757,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 3f1cb8363a556..104844859382c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -47,9 +47,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 f6b2c88f2cfb4..d4efd046f7474 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 0ef8e7b7fbcac..af08bd465b2d2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1140,6 +1140,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 347656b5f6488..283376188267f 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.
@@ -123,7 +125,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) {
@@ -289,6 +291,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 167b970cdda12..ea39db64622bc 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2646,6 +2646,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 66260eb36e002..8f192eae3926b 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -8,7 +8,6 @@
 
 #include "PassDetail.h"
 #include "clang/AST/ASTContext.h"
-#include "clang/AST/CharUnits.h"
 #include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "clang/CIR/Dialect/IR/CIROpsEnums.h"
@@ -31,6 +30,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,
@@ -405,17 +405,37 @@ 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);
   else if (auto arrayDtor = dyn_cast<cir::ArrayDtor>(op))
     lowerArrayDtor(arrayDtor);
-  else if (auto cast = mlir::dyn_cast<cir::CastOp>(op))
-    lowerCastOp(cast);
-  else if (auto complexMul = mlir::dyn_cast<cir::ComplexMulOp>(op))
-    lowerComplexMulOp(complexMul);
-  else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op))
-    lowerUnaryOp(unary);
+  else if (auto castOp = mlir::dyn_cast<cir::CastOp>(op))
+    lowerCastOp(castOp);
+  else if (auto complexMulOp = mlir::dyn_cast<cir::ComplexMulOp>(op))
+    lowerComplexMulOp(complexMulOp);
+  else if (auto unaryOp = mlir::dyn_cast<cir::UnaryOp>(op))
+    lowerUnaryOp(unaryOp);
+  else if (auto throwOp = mlir::dyn_cast<cir::ThrowOp>(op))
+    lowerThrowOp(throwOp);
 }
 
 void LoweringPreparePass::runOnOperation() {
@@ -427,7 +447,7 @@ void LoweringPreparePass::runOnOperation() {
 
   op->walk([&](mlir::Operation *op) {
     if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
-                  cir::ComplexMulOp, cir::UnaryOp>(op))
+                  cir::ComplexMulOp, 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

@AmrDeveloper
Copy link
Member Author

  • For the verification tests, I will add it in the emitThrow PR

def CIR_ThrowOp : CIR_Op<"throw"> {
let summary = "(Re)Throws an exception";
let description = [{
Very similar to __cxa_throw:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is is "very similar" or is it "equivalent"?

@@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return nullptr;
return {};

@@ -123,7 +125,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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, unrelated cleanups like this are discouraged. It's better to leave it until this code is being modified or add it as a separate commit.

(void)builder.createBlock(region);

// This will be erased during codegen, it acts as a placeholder for the
// operations to be inserted (if any)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which operations will be inserted here? It looks like any instructions following the throw will get inserted in the block created above, but it doesn't look like they go into the scope.

https://godbolt.org/z/7s6KWeb8v

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right, it's more clear when I tested it with code after throw, Thanks

if (rethrows())
return success();

if (getNumOperands() == 1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (getNumOperands() == 1) {
if (getNumOperands() != 0) {

I don't think this will ever be 1. In fact, maybe we should check for that. We need at least type info and an exception pointer if this isn't a rethrow.

When RTTI is implemented, it might be good to add a check to verify that type_info references valid type info, and perhaps also that dtor, if present, references a destructor.

@@ -405,17 +405,37 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) {
true);
}

void LoweringPreparePass::lowerThrowOp(ThrowOp op) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this happen here rather than in LowerToLLVM?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved it, it was confusing that rethrow is in LP but throw in LowerToLLVM 🤔

@AmrDeveloper AmrDeveloper force-pushed the cir_exception_throw branch 2 times, most recently from 7091a4d to 9faf678 Compare August 23, 2025 11:06
// if (b == 0)
// throw "Division by zero condition!";
cir.if %cond {
%exception_addr = cir.alloc_exception 8 -> !cir.ptr<!void>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment above mentions cir.cxa.allocate_exception which one is true?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the CIR_AllocExceptionOp description, running a sample locally cir.alloc_exception is the correct one. I will update the description. Thanks

Comment on lines 3839 to 3841
let arguments = (ins Optional<CIR_PointerType>:$exception_ptr,
OptionalAttr<FlatSymbolRefAttr>:$type_info,
OptionalAttr<FlatSymbolRefAttr>:$dtor);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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
);

Copy link
Member

@bcardosolopes bcardosolopes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM once all existing comments are addressed (not clear if they all did)

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good. I have a lot of suggestions for updating the op description, but feel free to merge after updating those.

def CIR_ThrowOp : CIR_Op<"throw"> {
let summary = "(Re)Throws an exception";
let description = [{
It's equivalent __cxa_throw:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It's equivalent __cxa_throw:
This operation is equivalent to either __cxa_throw or __cxa_rethrow, depending on the arguments.

It's equivalent __cxa_throw:

```
void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this adds any useful information. I'd remove it.


Example:
```mlir
// throw;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// throw;
// re-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*"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@"typeinfo for char const*"
@_ZTIPKc


// if (b == 0)
// throw "Division by zero condition!";
cir.if %cond {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cir.if %cond {
// Type info for char const*
cir.global "private" constant external @_ZTIPKc : !cir.ptr<!u8i>
cir.if %cond {

@AmrDeveloper AmrDeveloper merged commit 0499eb8 into llvm:main Aug 29, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants