[clang] [CIR] Emit CatchParamOp in the catch region (PR #171169)

2025-12-10 Thread LLVM Continuous Integration via cfe-commits

llvm-ci wrote:

LLVM Buildbot has detected a new failure on builder `openmp-s390x-linux` 
running on `systemz-1` while building `clang` at step 6 "test-openmp".

Full details are available at: 
https://lab.llvm.org/buildbot/#/builders/88/builds/18879


Here is the relevant piece of the build log for the reference

```
Step 6 (test-openmp) failure: test (failure)
 TEST 'libomp :: tasking/issue-94260-2.c' FAILED 

Exit Code: -11

Command Output (stdout):
--
# RUN: at line 1
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/./bin/clang 
-fopenmp   -I 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src
 -I 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test 
-L 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src
  -fno-omit-frame-pointer -mbackchain -I 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/ompt
 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c
 -o 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
 -lm -latomic && 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
# executed command: 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/./bin/clang 
-fopenmp -I 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src
 -I 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test 
-L 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src
 -fno-omit-frame-pointer -mbackchain -I 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/ompt
 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c
 -o 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
 -lm -latomic
# executed command: 
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
# note: command had no output on stdout or stderr
# error: command failed with exit status: -11

--




```



https://github.com/llvm/llvm-project/pull/171169
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Emit CatchParamOp in the catch region (PR #171169)

2025-12-10 Thread Amr Hesham via cfe-commits

https://github.com/AmrDeveloper closed 
https://github.com/llvm/llvm-project/pull/171169
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Emit CatchParamOp in the catch region (PR #171169)

2025-12-09 Thread Andy Kaylor via cfe-commits

https://github.com/andykaylor approved this pull request.

I think we'll eventually want to have a target-independent way of representing 
C++ exception handling. What you have here is actually target-independent 
except for the fact that it's implemented in `CIRGenItaniumCXXABI`. We can 
clean that up later when we have a more complete implementation.

This looks good for now.

https://github.com/llvm/llvm-project/pull/171169
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Emit CatchParamOp in the catch region (PR #171169)

2025-12-09 Thread Amr Hesham via cfe-commits

https://github.com/AmrDeveloper updated 
https://github.com/llvm/llvm-project/pull/171169

>From 71b1af890dcafa70c2f237af1061cd299563365c Mon Sep 17 00:00:00 2001
From: Amr Hesham 
Date: Sun, 7 Dec 2025 18:25:44 +0100
Subject: [PATCH 1/2] [CIR] Emit CatchParamOp in the catch region

---
 clang/lib/CIR/CodeGen/CIRGenCXXABI.h  |   3 +
 clang/lib/CIR/CodeGen/CIRGenException.cpp |   3 +-
 clang/lib/CIR/CodeGen/CIRGenFunction.h|   1 +
 clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 163 ++
 clang/test/CIR/CodeGen/try-catch-tmp.cpp  |   1 +
 5 files changed, 170 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h 
b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index 57b1a1f20aa17..b96d656b91e62 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -126,6 +126,9 @@ class CIRGenCXXABI {
 
   virtual void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) = 0;
 
+  virtual void emitBeginCatch(CIRGenFunction &cgf,
+  const CXXCatchStmt *catchStmt) = 0;
+
   virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
   QualType ty) = 0;
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 375828421eb1b..3fbf8953531e5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -419,7 +419,8 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, 
bool isFnTryBlock) {
 RunCleanupsScope catchScope(*this);
 
 // Initialize the catch variable and set up the cleanups.
-assert(!cir::MissingFeatures::catchParamOp());
+SaveAndRestore restoreCurrentFuncletPad(currentFuncletPad);
+cgm.getCXXABI().emitBeginCatch(*this, catchStmt);
 
 // Emit the PGO counter increment.
 assert(!cir::MissingFeatures::incrementProfileCounter());
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 0df812bcfb94e..b5879f9945f22 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1231,6 +1231,7 @@ class CIRGenFunction : public CIRGenTypeCache {
   };
 
   LexicalScope *curLexScope = nullptr;
+  mlir::Operation *currentFuncletPad = nullptr;
 
   typedef void Destroyer(CIRGenFunction &cgf, Address addr, QualType ty);
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp 
b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 7e145f2c57ce6..95ad50135b587 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -81,6 +81,9 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
   void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
   void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;
 
+  void emitBeginCatch(CIRGenFunction &cgf,
+  const CXXCatchStmt *catchStmt) override;
+
   bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
   CXXDtorType dt) const override {
 // Itanium does not emit any destructor variant as an inline thunk.
@@ -2266,3 +2269,163 @@ Address 
CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
   CharUnits finalAlignment = baseAlignment.alignmentAtOffset(cookieSize);
   return Address(finalPtr, newPtr.getElementType(), finalAlignment);
 }
+
+namespace {
+/// From traditional LLVM, useful info for LLVM lowering support:
+/// A cleanup to call __cxa_end_catch.  In many cases, the caught
+/// exception type lets us state definitively that the thrown exception
+/// type does not have a destructor.  In particular:
+///   - Catch-alls tell us nothing, so we have to conservatively
+/// assume that the thrown exception might have a destructor.
+///   - Catches by reference behave according to their base types.
+///   - Catches of non-record types will only trigger for exceptions
+/// of non-record types, which never have destructors.
+///   - Catches of record types can trigger for arbitrary subclasses
+/// of the caught type, so we have to assume the actual thrown
+/// exception type might have a throwing destructor, even if the
+/// caught type's destructor is trivial or nothrow.
+struct CallEndCatch final : EHScopeStack::Cleanup {
+  CallEndCatch(bool mightThrow) : mightThrow(mightThrow) {}
+  bool mightThrow;
+
+  void emit(CIRGenFunction &cgf, Flags flags) override {
+if (!mightThrow) {
+  // Traditional LLVM codegen would emit a call to __cxa_end_catch
+  // here. For CIR, just let it pass since the cleanup is going
+  // to be emitted on a later pass when lowering the catch region.
+  // CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
+  cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
+  return;
+}
+
+// Traditional LLVM codegen would emit a call to __cxa_end_catch
+// here. For CIR, just

[clang] [CIR] Emit CatchParamOp in the catch region (PR #171169)

2025-12-09 Thread Amr Hesham via cfe-commits


@@ -1231,6 +1231,7 @@ class CIRGenFunction : public CIRGenTypeCache {
   };
 
   LexicalScope *curLexScope = nullptr;
+  mlir::Operation *currentFuncletPad = nullptr;

AmrDeveloper wrote:

Maybe we can add it to the MissingFeatures with explanation comment 🤔 

https://github.com/llvm/llvm-project/pull/171169
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Emit CatchParamOp in the catch region (PR #171169)

2025-12-09 Thread Amr Hesham via cfe-commits


@@ -2266,3 +2269,163 @@ Address 
CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
   CharUnits finalAlignment = baseAlignment.alignmentAtOffset(cookieSize);
   return Address(finalPtr, newPtr.getElementType(), finalAlignment);
 }
+
+namespace {
+/// From traditional LLVM, useful info for LLVM lowering support:
+/// A cleanup to call __cxa_end_catch.  In many cases, the caught
+/// exception type lets us state definitively that the thrown exception
+/// type does not have a destructor.  In particular:
+///   - Catch-alls tell us nothing, so we have to conservatively
+/// assume that the thrown exception might have a destructor.
+///   - Catches by reference behave according to their base types.
+///   - Catches of non-record types will only trigger for exceptions
+/// of non-record types, which never have destructors.
+///   - Catches of record types can trigger for arbitrary subclasses
+/// of the caught type, so we have to assume the actual thrown
+/// exception type might have a throwing destructor, even if the
+/// caught type's destructor is trivial or nothrow.
+struct CallEndCatch final : EHScopeStack::Cleanup {
+  CallEndCatch(bool mightThrow) : mightThrow(mightThrow) {}
+  bool mightThrow;
+
+  void emit(CIRGenFunction &cgf, Flags flags) override {
+if (!mightThrow) {
+  // Traditional LLVM codegen would emit a call to __cxa_end_catch
+  // here. For CIR, just let it pass since the cleanup is going
+  // to be emitted on a later pass when lowering the catch region.
+  // CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
+  cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
+  return;
+}
+
+// Traditional LLVM codegen would emit a call to __cxa_end_catch
+// here. For CIR, just let it pass since the cleanup is going
+// to be emitted on a later pass when lowering the catch region.
+// CGF.EmitRuntimeCallOrTryCall(getEndCatchFn(CGF.CGM));
+if (!cgf.getBuilder().getBlock()->mightHaveTerminator())
+  cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
+  }
+};
+} // namespace
+
+static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Type paramTy,
+  bool endMightThrow) {
+
+  auto catchParam = cir::CatchParamOp::create(
+  cgf.getBuilder(), cgf.getBuilder().getUnknownLoc(), paramTy);
+
+  cgf.ehStack.pushCleanup(
+  NormalAndEHCleanup,
+  endMightThrow && !cgf.cgm.getLangOpts().AssumeNothrowExceptionDtor);
+
+  return catchParam.getParam();
+}
+
+/// A "special initializer" callback for initializing a catch
+/// parameter during catch initialization.
+static void initCatchParam(CIRGenFunction &cgf, const VarDecl &catchParam,
+   Address paramAddr, SourceLocation loc) {
+  CanQualType catchType =
+  cgf.cgm.getASTContext().getCanonicalType(catchParam.getType());
+  // If we're catching by reference, we can just cast the object
+  // pointer to the appropriate pointer.
+  if (isa(catchType)) {
+cgf.cgm.errorNYI(loc, "initCatchParam: ReferenceType");
+return;
+  }
+
+  // Scalars and complexes.
+  cir::TypeEvaluationKind tek = cgf.getEvaluationKind(catchType);
+  if (tek != cir::TEK_Aggregate) {
+// Notes for LLVM lowering:
+// If the catch type is a pointer type, __cxa_begin_catch returns
+// the pointer by value.
+if (catchType->hasPointerRepresentation()) {
+  cgf.cgm.errorNYI(loc, "initCatchParam: hasPointerRepresentation");
+  return;
+}
+
+mlir::Type cirCatchTy = cgf.convertTypeForMem(catchType);
+mlir::Value catchParam =
+callBeginCatch(cgf, cgf.getBuilder().getPointerTo(cirCatchTy), false);
+LValue srcLV = cgf.makeNaturalAlignAddrLValue(catchParam, catchType);
+LValue destLV = cgf.makeAddrLValue(paramAddr, catchType);
+switch (tek) {
+case cir::TEK_Complex: {
+  cgf.cgm.errorNYI(loc, "initCatchParam: cir::TEK_Complex");
+  return;
+}
+case cir::TEK_Scalar: {
+  auto exnLoad = cgf.emitLoadOfScalar(srcLV, loc);
+  cgf.emitStoreOfScalar(exnLoad, destLV, /*isInit=*/true);
+  return;
+}
+case cir::TEK_Aggregate:
+  llvm_unreachable("evaluation kind filtered out!");
+}
+
+// Otherwise, it returns a pointer into the exception object.
+llvm_unreachable("bad evaluation kind");
+  }
+
+  cgf.cgm.errorNYI(loc, "initCatchParam: cir::TEK_Aggregate");
+}
+
+/// Begins a catch statement by initializing the catch variable and
+/// calling __cxa_begin_catch.
+void CIRGenItaniumCXXABI::emitBeginCatch(CIRGenFunction &cgf,
+ const CXXCatchStmt *catchStmt) {
+  // We have to be very careful with the ordering of cleanups here:
+  //   C++ [except.throw]p4:
+  // The destruction [of the exception temporary] occurs
+  // immediately after the destruction of the object declared in
+  // the exception-declaration in the handler.
+  //
+  // So the precise or

[clang] [CIR] Emit CatchParamOp in the catch region (PR #171169)

2025-12-08 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clangir

Author: Amr Hesham (AmrDeveloper)


Changes

Emit structured CatchParamOp in the catch region

Issue https://github.com/llvm/llvm-project/issues/154992

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


5 Files Affected:

- (modified) clang/lib/CIR/CodeGen/CIRGenCXXABI.h (+3) 
- (modified) clang/lib/CIR/CodeGen/CIRGenException.cpp (+2-1) 
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+1) 
- (modified) clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp (+163) 
- (modified) clang/test/CIR/CodeGen/try-catch-tmp.cpp (+1) 


``diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h 
b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index 57b1a1f20aa17..b96d656b91e62 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -126,6 +126,9 @@ class CIRGenCXXABI {
 
   virtual void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) = 0;
 
+  virtual void emitBeginCatch(CIRGenFunction &cgf,
+  const CXXCatchStmt *catchStmt) = 0;
+
   virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
   QualType ty) = 0;
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 375828421eb1b..3fbf8953531e5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -419,7 +419,8 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, 
bool isFnTryBlock) {
 RunCleanupsScope catchScope(*this);
 
 // Initialize the catch variable and set up the cleanups.
-assert(!cir::MissingFeatures::catchParamOp());
+SaveAndRestore restoreCurrentFuncletPad(currentFuncletPad);
+cgm.getCXXABI().emitBeginCatch(*this, catchStmt);
 
 // Emit the PGO counter increment.
 assert(!cir::MissingFeatures::incrementProfileCounter());
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 0df812bcfb94e..b5879f9945f22 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1231,6 +1231,7 @@ class CIRGenFunction : public CIRGenTypeCache {
   };
 
   LexicalScope *curLexScope = nullptr;
+  mlir::Operation *currentFuncletPad = nullptr;
 
   typedef void Destroyer(CIRGenFunction &cgf, Address addr, QualType ty);
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp 
b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 7e145f2c57ce6..95ad50135b587 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -81,6 +81,9 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
   void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
   void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;
 
+  void emitBeginCatch(CIRGenFunction &cgf,
+  const CXXCatchStmt *catchStmt) override;
+
   bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
   CXXDtorType dt) const override {
 // Itanium does not emit any destructor variant as an inline thunk.
@@ -2266,3 +2269,163 @@ Address 
CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
   CharUnits finalAlignment = baseAlignment.alignmentAtOffset(cookieSize);
   return Address(finalPtr, newPtr.getElementType(), finalAlignment);
 }
+
+namespace {
+/// From traditional LLVM, useful info for LLVM lowering support:
+/// A cleanup to call __cxa_end_catch.  In many cases, the caught
+/// exception type lets us state definitively that the thrown exception
+/// type does not have a destructor.  In particular:
+///   - Catch-alls tell us nothing, so we have to conservatively
+/// assume that the thrown exception might have a destructor.
+///   - Catches by reference behave according to their base types.
+///   - Catches of non-record types will only trigger for exceptions
+/// of non-record types, which never have destructors.
+///   - Catches of record types can trigger for arbitrary subclasses
+/// of the caught type, so we have to assume the actual thrown
+/// exception type might have a throwing destructor, even if the
+/// caught type's destructor is trivial or nothrow.
+struct CallEndCatch final : EHScopeStack::Cleanup {
+  CallEndCatch(bool mightThrow) : mightThrow(mightThrow) {}
+  bool mightThrow;
+
+  void emit(CIRGenFunction &cgf, Flags flags) override {
+if (!mightThrow) {
+  // Traditional LLVM codegen would emit a call to __cxa_end_catch
+  // here. For CIR, just let it pass since the cleanup is going
+  // to be emitted on a later pass when lowering the catch region.
+  // CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
+  cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
+  return;
+}
+
+// Traditional LLVM codegen would emit a call to __cxa_end_catch
+// here. For CIR, just let it pass since t

[clang] [CIR] Emit CatchParamOp in the catch region (PR #171169)

2025-12-08 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Amr Hesham (AmrDeveloper)


Changes

Emit structured CatchParamOp in the catch region

Issue https://github.com/llvm/llvm-project/issues/154992

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


5 Files Affected:

- (modified) clang/lib/CIR/CodeGen/CIRGenCXXABI.h (+3) 
- (modified) clang/lib/CIR/CodeGen/CIRGenException.cpp (+2-1) 
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+1) 
- (modified) clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp (+163) 
- (modified) clang/test/CIR/CodeGen/try-catch-tmp.cpp (+1) 


``diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h 
b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index 57b1a1f20aa17..b96d656b91e62 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -126,6 +126,9 @@ class CIRGenCXXABI {
 
   virtual void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) = 0;
 
+  virtual void emitBeginCatch(CIRGenFunction &cgf,
+  const CXXCatchStmt *catchStmt) = 0;
+
   virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
   QualType ty) = 0;
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 375828421eb1b..3fbf8953531e5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -419,7 +419,8 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, 
bool isFnTryBlock) {
 RunCleanupsScope catchScope(*this);
 
 // Initialize the catch variable and set up the cleanups.
-assert(!cir::MissingFeatures::catchParamOp());
+SaveAndRestore restoreCurrentFuncletPad(currentFuncletPad);
+cgm.getCXXABI().emitBeginCatch(*this, catchStmt);
 
 // Emit the PGO counter increment.
 assert(!cir::MissingFeatures::incrementProfileCounter());
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 0df812bcfb94e..b5879f9945f22 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1231,6 +1231,7 @@ class CIRGenFunction : public CIRGenTypeCache {
   };
 
   LexicalScope *curLexScope = nullptr;
+  mlir::Operation *currentFuncletPad = nullptr;
 
   typedef void Destroyer(CIRGenFunction &cgf, Address addr, QualType ty);
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp 
b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 7e145f2c57ce6..95ad50135b587 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -81,6 +81,9 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
   void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
   void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;
 
+  void emitBeginCatch(CIRGenFunction &cgf,
+  const CXXCatchStmt *catchStmt) override;
+
   bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
   CXXDtorType dt) const override {
 // Itanium does not emit any destructor variant as an inline thunk.
@@ -2266,3 +2269,163 @@ Address 
CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
   CharUnits finalAlignment = baseAlignment.alignmentAtOffset(cookieSize);
   return Address(finalPtr, newPtr.getElementType(), finalAlignment);
 }
+
+namespace {
+/// From traditional LLVM, useful info for LLVM lowering support:
+/// A cleanup to call __cxa_end_catch.  In many cases, the caught
+/// exception type lets us state definitively that the thrown exception
+/// type does not have a destructor.  In particular:
+///   - Catch-alls tell us nothing, so we have to conservatively
+/// assume that the thrown exception might have a destructor.
+///   - Catches by reference behave according to their base types.
+///   - Catches of non-record types will only trigger for exceptions
+/// of non-record types, which never have destructors.
+///   - Catches of record types can trigger for arbitrary subclasses
+/// of the caught type, so we have to assume the actual thrown
+/// exception type might have a throwing destructor, even if the
+/// caught type's destructor is trivial or nothrow.
+struct CallEndCatch final : EHScopeStack::Cleanup {
+  CallEndCatch(bool mightThrow) : mightThrow(mightThrow) {}
+  bool mightThrow;
+
+  void emit(CIRGenFunction &cgf, Flags flags) override {
+if (!mightThrow) {
+  // Traditional LLVM codegen would emit a call to __cxa_end_catch
+  // here. For CIR, just let it pass since the cleanup is going
+  // to be emitted on a later pass when lowering the catch region.
+  // CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
+  cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
+  return;
+}
+
+// Traditional LLVM codegen would emit a call to __cxa_end_catch
+// here. For CIR, just let it pass since the

[clang] [CIR] Emit CatchParamOp in the catch region (PR #171169)

2025-12-08 Thread Amr Hesham via cfe-commits

https://github.com/AmrDeveloper created 
https://github.com/llvm/llvm-project/pull/171169

Emit structured CatchParamOp in the catch region

Issue https://github.com/llvm/llvm-project/issues/154992

>From b74f4e3e89687c3354bee707bab8812bf72128c8 Mon Sep 17 00:00:00 2001
From: Amr Hesham 
Date: Sun, 7 Dec 2025 18:25:44 +0100
Subject: [PATCH] [CIR] Emit CatchParamOp in the catch region

---
 clang/lib/CIR/CodeGen/CIRGenCXXABI.h  |   3 +
 clang/lib/CIR/CodeGen/CIRGenException.cpp |   3 +-
 clang/lib/CIR/CodeGen/CIRGenFunction.h|   1 +
 clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 163 ++
 clang/test/CIR/CodeGen/try-catch-tmp.cpp  |   1 +
 5 files changed, 170 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h 
b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index 57b1a1f20aa17..b96d656b91e62 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -126,6 +126,9 @@ class CIRGenCXXABI {
 
   virtual void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) = 0;
 
+  virtual void emitBeginCatch(CIRGenFunction &cgf,
+  const CXXCatchStmt *catchStmt) = 0;
+
   virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
   QualType ty) = 0;
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 375828421eb1b..3fbf8953531e5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -419,7 +419,8 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, 
bool isFnTryBlock) {
 RunCleanupsScope catchScope(*this);
 
 // Initialize the catch variable and set up the cleanups.
-assert(!cir::MissingFeatures::catchParamOp());
+SaveAndRestore restoreCurrentFuncletPad(currentFuncletPad);
+cgm.getCXXABI().emitBeginCatch(*this, catchStmt);
 
 // Emit the PGO counter increment.
 assert(!cir::MissingFeatures::incrementProfileCounter());
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 0df812bcfb94e..b5879f9945f22 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1231,6 +1231,7 @@ class CIRGenFunction : public CIRGenTypeCache {
   };
 
   LexicalScope *curLexScope = nullptr;
+  mlir::Operation *currentFuncletPad = nullptr;
 
   typedef void Destroyer(CIRGenFunction &cgf, Address addr, QualType ty);
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp 
b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 7e145f2c57ce6..95ad50135b587 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -81,6 +81,9 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
   void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
   void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;
 
+  void emitBeginCatch(CIRGenFunction &cgf,
+  const CXXCatchStmt *catchStmt) override;
+
   bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
   CXXDtorType dt) const override {
 // Itanium does not emit any destructor variant as an inline thunk.
@@ -2266,3 +2269,163 @@ Address 
CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
   CharUnits finalAlignment = baseAlignment.alignmentAtOffset(cookieSize);
   return Address(finalPtr, newPtr.getElementType(), finalAlignment);
 }
+
+namespace {
+/// From traditional LLVM, useful info for LLVM lowering support:
+/// A cleanup to call __cxa_end_catch.  In many cases, the caught
+/// exception type lets us state definitively that the thrown exception
+/// type does not have a destructor.  In particular:
+///   - Catch-alls tell us nothing, so we have to conservatively
+/// assume that the thrown exception might have a destructor.
+///   - Catches by reference behave according to their base types.
+///   - Catches of non-record types will only trigger for exceptions
+/// of non-record types, which never have destructors.
+///   - Catches of record types can trigger for arbitrary subclasses
+/// of the caught type, so we have to assume the actual thrown
+/// exception type might have a throwing destructor, even if the
+/// caught type's destructor is trivial or nothrow.
+struct CallEndCatch final : EHScopeStack::Cleanup {
+  CallEndCatch(bool mightThrow) : mightThrow(mightThrow) {}
+  bool mightThrow;
+
+  void emit(CIRGenFunction &cgf, Flags flags) override {
+if (!mightThrow) {
+  // Traditional LLVM codegen would emit a call to __cxa_end_catch
+  // here. For CIR, just let it pass since the cleanup is going
+  // to be emitted on a later pass when lowering the catch region.
+  // CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
+  cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
+  return;
+