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

>From 49898be8068694b9ddc5a7d6bf7a20c383db5cde Mon Sep 17 00:00:00 2001
From: Amr Hesham <[email protected]>
Date: Sat, 25 Oct 2025 21:17:00 +0200
Subject: [PATCH 1/2] [CIR] Upstream non-empty Try block with catch all

---
 clang/lib/CIR/CodeGen/CIRGenCall.cpp      |  48 +++-
 clang/lib/CIR/CodeGen/CIRGenCleanup.cpp   |  10 +-
 clang/lib/CIR/CodeGen/CIRGenCleanup.h     |   7 +-
 clang/lib/CIR/CodeGen/CIRGenException.cpp | 304 +++++++++++++++++++++-
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp  |  10 +
 clang/lib/CIR/CodeGen/CIRGenFunction.h    |  17 +-
 clang/lib/CIR/CodeGen/EHScopeStack.h      |   2 +
 clang/test/CIR/CodeGen/try-catch-tmp.cpp  |  44 ++++
 8 files changed, 434 insertions(+), 8 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/try-catch-tmp.cpp

diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 50d4c035d30a1..ea44c65636c6c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -465,12 +465,48 @@ static cir::CIRCallOpInterface
 emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
                cir::FuncType indirectFuncTy, mlir::Value indirectFuncVal,
                cir::FuncOp directFuncOp,
-               const SmallVectorImpl<mlir::Value> &cirCallArgs,
+               const SmallVectorImpl<mlir::Value> &cirCallArgs, bool isInvoke,
                const mlir::NamedAttrList &attrs) {
   CIRGenBuilderTy &builder = cgf.getBuilder();
 
   assert(!cir::MissingFeatures::opCallSurroundingTry());
-  assert(!cir::MissingFeatures::invokeOp());
+
+  if (isInvoke) {
+    // This call can throw, few options:
+    //  - If this call does not have an associated cir.try, use the
+    //    one provided by InvokeDest,
+    //  - User written try/catch clauses require calls to handle
+    //    exceptions under cir.try.
+
+    // In OG, we build the landing pad for this scope. In CIR, we emit a
+    // synthetic cir.try because this didn't come from code generating from a
+    // try/catch in C++.
+    assert(cgf.curLexScope && "expected scope");
+    cir::TryOp tryOp = cgf.curLexScope->getClosestTryParent();
+    if (!tryOp) {
+      cgf.cgm.errorNYI(
+          "emitCallLikeOp: call does not have an associated cir.try");
+      return {};
+    }
+
+    if (tryOp.getSynthetic()) {
+      cgf.cgm.errorNYI("emitCallLikeOp: tryOp synthetic");
+      return {};
+    }
+
+    cir::CallOp callOpWithExceptions;
+    if (indirectFuncTy) {
+      cgf.cgm.errorNYI("emitCallLikeOp: indirect function type");
+      return {};
+    }
+
+    callOpWithExceptions =
+        builder.createTryCallOp(callLoc, directFuncOp, cirCallArgs);
+
+    (void)cgf.getInvokeDest(tryOp);
+
+    return callOpWithExceptions;
+  }
 
   assert(builder.getInsertionBlock() && "expected valid basic block");
 
@@ -628,10 +664,16 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo 
&funcInfo,
     indirectFuncVal = calleePtr->getResult(0);
   }
 
+  // TODO(cir): currentFunctionUsesSEHTry
+  // TODO(cir): check for MSVCXXPersonality
+  // TODO(cir): Create NoThrowAttr
+  bool cannotThrow = attrs.getNamed("nothrow").has_value();
+  bool isInvoke = !cannotThrow && isInvokeDest();
+
   mlir::Location callLoc = loc;
   cir::CIRCallOpInterface theCall =
       emitCallLikeOp(*this, loc, indirectFuncTy, indirectFuncVal, directFuncOp,
-                     cirCallArgs, attrs);
+                     cirCallArgs, isInvoke, attrs);
 
   if (callOp)
     *callOp = theCall;
diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
index 437db306f3369..3550a78cc1816 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
@@ -188,9 +188,17 @@ void EHScopeStack::popCleanup() {
   }
 }
 
+bool EHScopeStack::requiresLandingPad() const {
+  for (stable_iterator si = getInnermostEHScope(); si != stable_end();) {
+    // TODO(cir): Skip lifetime markers.
+    assert(!cir::MissingFeatures::emitLifetimeMarkers());
+    return true;
+  }
+  return false;
+}
+
 EHCatchScope *EHScopeStack::pushCatch(unsigned numHandlers) {
   char *buffer = allocate(EHCatchScope::getSizeForNumHandlers(numHandlers));
-  assert(!cir::MissingFeatures::innermostEHScope());
   EHCatchScope *scope =
       new (buffer) EHCatchScope(numHandlers, innermostEHScope);
   innermostEHScope = stable_begin();
diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.h 
b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
index a035d792ef6d1..4e4e913574991 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
@@ -38,6 +38,8 @@ class EHScope {
   };
   enum { NumCommonBits = 3 };
 
+  bool isScopeMayThrow;
+
 protected:
   class CatchBitFields {
     friend class EHCatchScope;
@@ -92,10 +94,11 @@ class EHScope {
     // Traditional LLVM codegen also checks for `!block->use_empty()`, but
     // in CIRGen the block content is not important, just used as a way to
     // signal `hasEHBranches`.
-    assert(!cir::MissingFeatures::ehstackBranches());
-    return false;
+    return isScopeMayThrow;
   }
 
+  void setMayThrow(bool mayThrow) { isScopeMayThrow = mayThrow; }
+
   EHScopeStack::stable_iterator getEnclosingEHScope() const {
     return enclosingEHScope;
   }
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 67f46ffde8fda..700e5e0c67c45 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -14,6 +14,7 @@
 #include "CIRGenFunction.h"
 
 #include "clang/AST/StmtVisitor.h"
+#include "llvm/Support/SaveAndRestore.h"
 
 using namespace clang;
 using namespace clang::CIRGen;
@@ -354,6 +355,33 @@ void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &s, 
cir::TryOp tryOp,
   }
 }
 
+/// Emit the structure of the dispatch block for the given catch scope.
+/// It is an invariant that the dispatch block already exists.
+static void emitCatchDispatchBlock(CIRGenFunction &cgf,
+                                   EHCatchScope &catchScope, cir::TryOp tryOp) 
{
+  if (EHPersonality::get(cgf).isWasmPersonality()) {
+    cgf.cgm.errorNYI("emitCatchDispatchBlock: WASM personality");
+    return;
+  }
+
+  if (EHPersonality::get(cgf).usesFuncletPads()) {
+    cgf.cgm.errorNYI("emitCatchDispatchBlock: usesFuncletPads");
+    return;
+  }
+
+  assert(catchScope.mayThrow() &&
+         "Expected catchScope that may throw exception");
+
+  // If there's only a single catch-all, getEHDispatchBlock returned
+  // that catch-all as the dispatch block.
+  if (catchScope.getNumHandlers() == 1 &&
+      catchScope.getHandler(0).isCatchAll()) {
+    return;
+  }
+
+  cgf.cgm.errorNYI("emitCatchDispatchBlock: non-catch all handler");
+}
+
 void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) {
   unsigned numHandlers = s.getNumHandlers();
   EHCatchScope &catchScope = cast<EHCatchScope>(*ehStack.begin());
@@ -382,5 +410,279 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, 
bool isFnTryBlock) {
     return;
   }
 
-  cgm.errorNYI("exitCXXTryStmt: Required catch");
+  // Emit the structure of the EH dispatch for this catch.
+  emitCatchDispatchBlock(*this, catchScope, tryOp);
+
+  // Copy the handler blocks off before we pop the EH stack.  Emitting
+  // the handlers might scribble on this memory.
+  SmallVector<EHCatchScope::Handler, 8> handlers(
+      catchScope.begin(), catchScope.begin() + numHandlers);
+
+  ehStack.popCatch();
+
+  // Determine if we need an implicit rethrow for all these catch handlers;
+  // see the comment below.
+  bool doImplicitRethrow =
+      isFnTryBlock && isa<CXXDestructorDecl, CXXConstructorDecl>(curCodeDecl);
+
+  // Wasm uses Windows-style EH instructions, but merges all catch clauses into
+  // one big catchpad. So we save the old funclet pad here before we traverse
+  // each catch handler.
+  if (EHPersonality::get(*this).isWasmPersonality()) {
+    cgm.errorNYI("exitCXXTryStmt: WASM personality");
+    return;
+  }
+
+  bool hasCatchAll = false;
+  for (unsigned i = numHandlers; i != 0; --i) {
+    hasCatchAll |= handlers[i - 1].isCatchAll();
+    mlir::Region *catchRegion = handlers[i - 1].region;
+
+    mlir::OpBuilder::InsertionGuard guard(builder);
+    builder.setInsertionPointToStart(&catchRegion->front());
+
+    const CXXCatchStmt *catchStmt = s.getHandler(i - 1);
+
+    // Enter a cleanup scope, including the catch variable and the
+    // end-catch.
+    RunCleanupsScope catchScope(*this);
+
+    // Initialize the catch variable and set up the cleanups.
+    // TODO: emitBeginCatch
+
+    // Emit the PGO counter increment.
+    assert(!cir::MissingFeatures::incrementProfileCounter());
+
+    // Perform the body of the catch.
+    mlir::LogicalResult emitResult =
+        emitStmt(catchStmt->getHandlerBlock(), /*useCurrentScope=*/true);
+    assert(emitResult.succeeded() && "failed to emit catch handler block");
+
+    // TODO(cir): This yeild should replaced by CatchParamOp once it upstreamed
+    cir::YieldOp::create(builder, tryOp->getLoc());
+
+    // [except.handle]p11:
+    //   The currently handled exception is rethrown if control
+    //   reaches the end of a handler of the function-try-block of a
+    //   constructor or destructor.
+
+    // It is important that we only do this on fallthrough and not on
+    // return.  Note that it's illegal to put a return in a
+    // constructor function-try-block's catch handler (p14), so this
+    // really only applies to destructors.
+    if (doImplicitRethrow) {
+      cgm.errorNYI("exitCXXTryStmt: doImplicitRethrow");
+      return;
+    }
+
+    // Fall out through the catch cleanups.
+    catchScope.forceCleanup();
+  }
+
+  // Because in wasm we merge all catch clauses into one big catchpad, in case
+  // none of the types in catch handlers matches after we test against each of
+  // them, we should unwind to the next EH enclosing scope. We generate a call
+  // to rethrow function here to do that.
+  if (EHPersonality::get(*this).isWasmPersonality() && !hasCatchAll) {
+    cgm.errorNYI("exitCXXTryStmt: WASM personality without catch all");
+  }
+
+  assert(!cir::MissingFeatures::incrementProfileCounter());
+}
+
+mlir::Operation *CIRGenFunction::emitLandingPad(cir::TryOp tryOp) {
+  assert(ehStack.requiresLandingPad());
+  assert(!cgm.getLangOpts().IgnoreExceptions &&
+         "LandingPad should not be emitted when -fignore-exceptions are in "
+         "effect.");
+
+  EHScope &innermostEHScope = *ehStack.find(ehStack.getInnermostEHScope());
+  switch (innermostEHScope.getKind()) {
+  case EHScope::Terminate:
+    cgm.errorNYI("emitLandingPad: terminate");
+    return {};
+
+  case EHScope::Catch:
+  case EHScope::Cleanup:
+  case EHScope::Filter:
+    // CIR does not cache landing pads.
+    break;
+  }
+
+  // If there's an existing TryOp, it means we got a `cir.try` scope
+  // that leads to this "landing pad" creation site. Otherwise, exceptions
+  // are enabled but a throwing function is called anyways (common pattern
+  // with function local static initializers).
+  mlir::ArrayAttr handlerTypesAttr = tryOp.getHandlerTypesAttr();
+  if (!handlerTypesAttr || handlerTypesAttr.empty()) {
+    // Accumulate all the handlers in scope.
+    bool hasCatchAll = false;
+    llvm::SmallVector<mlir::Attribute, 4> handlerAttrs;
+    for (EHScopeStack::iterator i = ehStack.begin(), e = ehStack.end(); i != e;
+         ++i) {
+      switch (i->getKind()) {
+      case EHScope::Cleanup: {
+        cgm.errorNYI("emitLandingPad: Cleanup");
+        return {};
+      }
+
+      case EHScope::Filter: {
+        cgm.errorNYI("emitLandingPad: Filter");
+        return {};
+      }
+
+      case EHScope::Terminate: {
+        cgm.errorNYI("emitLandingPad: Terminate");
+        return {};
+      }
+
+      case EHScope::Catch:
+        break;
+      }
+
+      EHCatchScope &catchScope = cast<EHCatchScope>(*i);
+      for (unsigned handlerIdx = 0, he = catchScope.getNumHandlers();
+           handlerIdx != he; ++handlerIdx) {
+        EHCatchScope::Handler handler = catchScope.getHandler(handlerIdx);
+        assert(handler.type.flags == 0 &&
+               "landingpads do not support catch handler flags");
+
+        // If this is a catch-all, register that and abort.
+        if (handler.isCatchAll()) {
+          assert(!hasCatchAll);
+          hasCatchAll = true;
+          goto done;
+        }
+
+        cgm.errorNYI("emitLandingPad: non catch-all");
+        return {};
+      }
+
+      goto done;
+    }
+
+  done:
+    if (hasCatchAll) {
+      handlerAttrs.push_back(cir::CatchAllAttr::get(&getMLIRContext()));
+    } else {
+      cgm.errorNYI("emitLandingPad: non catch-all");
+      return {};
+    }
+
+    // Add final array of clauses into TryOp.
+    tryOp.setHandlerTypesAttr(
+        mlir::ArrayAttr::get(&getMLIRContext(), handlerAttrs));
+  }
+
+  // In traditional LLVM codegen. this tells the backend how to generate the
+  // landing pad by generating a branch to the dispatch block. In CIR,
+  // getEHDispatchBlock is used to populate blocks for later filing during
+  // cleanup handling.
+  (void)getEHDispatchBlock(ehStack.getInnermostEHScope(), tryOp);
+
+  return tryOp;
+}
+
+// Differently from LLVM traditional codegen, there are no dispatch blocks
+// to look at given cir.try_call does not jump to blocks like invoke does.
+// However, we keep this around since other parts of CIRGen use
+// getCachedEHDispatchBlock to infer state.
+mlir::Block *
+CIRGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator scope,
+                                   cir::TryOp tryOp) {
+  if (EHPersonality::get(*this).usesFuncletPads()) {
+    cgm.errorNYI("getEHDispatchBlock: usesFuncletPads");
+    return {};
+  }
+
+  // Otherwise, we should look at the actual scope.
+  EHScope &ehScope = *ehStack.find(scope);
+  bool mayThrow = ehScope.mayThrow();
+
+  mlir::Block *originalBlock = nullptr;
+  if (mayThrow && tryOp) {
+    // If the dispatch is cached but comes from a different tryOp, make sure:
+    // - Populate current `tryOp` with a new dispatch block regardless.
+    // - Update the map to enqueue new dispatchBlock to also get a cleanup. See
+    // code at the end of the function.
+    cgm.errorNYI("getEHDispatchBlock: mayThrow & tryOp");
+    return {};
+  }
+
+  if (!mayThrow) {
+    switch (ehScope.getKind()) {
+    case EHScope::Catch: {
+      // LLVM does some optimization with branches here, CIR just keep track of
+      // the corresponding calls.
+      EHCatchScope &catchScope = cast<EHCatchScope>(ehScope);
+      if (catchScope.getNumHandlers() == 1 &&
+          catchScope.getHandler(0).isCatchAll()) {
+        mayThrow = true;
+        break;
+      }
+      cgm.errorNYI("getEHDispatchBlock: mayThrow non-catch all");
+      return {};
+    }
+    case EHScope::Cleanup: {
+      cgm.errorNYI("getEHDispatchBlock: mayThrow & cleanup");
+      return {};
+    }
+    case EHScope::Filter: {
+      cgm.errorNYI("getEHDispatchBlock: mayThrow & Filter");
+      return {};
+    }
+    case EHScope::Terminate: {
+      cgm.errorNYI("getEHDispatchBlock: mayThrow & Terminate");
+      return {};
+    }
+    }
+  }
+
+  if (originalBlock) {
+    cgm.errorNYI("getEHDispatchBlock: originalBlock");
+    return {};
+  }
+
+  ehScope.setMayThrow(mayThrow);
+  return {};
+}
+
+bool CIRGenFunction::isInvokeDest() {
+  if (!ehStack.requiresLandingPad())
+    return false;
+
+  // If exceptions are disabled/ignored and SEH is not in use, then there is no
+  // invoke destination. SEH "works" even if exceptions are off. In practice,
+  // this means that C++ destructors and other EH cleanups don't run, which is
+  // consistent with MSVC's behavior, except in the presence of -EHa
+  const LangOptions &lo = cgm.getLangOpts();
+  if (!lo.Exceptions || lo.IgnoreExceptions) {
+    cgm.errorNYI("isInvokeDest: no exceptions or ignore exception");
+    return false;
+  }
+
+  // CUDA device code doesn't have exceptions.
+  if (lo.CUDA && lo.CUDAIsDevice)
+    return false;
+
+  return true;
+}
+
+mlir::Operation *CIRGenFunction::getInvokeDestImpl(cir::TryOp tryOp) {
+  assert(ehStack.requiresLandingPad());
+  assert(!ehStack.empty());
+
+  // TODO(cir): add personality function
+
+  // CIR does not cache landing pads.
+  const EHPersonality &personality = EHPersonality::get(*this);
+
+  mlir::Operation *lp = nullptr;
+  if (personality.usesFuncletPads()) {
+    cgm.errorNYI("getInvokeDestImpl: usesFuncletPads");
+  } else {
+    lp = emitLandingPad(tryOp);
+  }
+
+  return lp;
 }
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 5d5209b9ffb60..7422940fe4b2b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -412,6 +412,16 @@ void CIRGenFunction::LexicalScope::emitImplicitReturn() {
   (void)emitReturn(localScope->endLoc);
 }
 
+cir::TryOp CIRGenFunction::LexicalScope::getClosestTryParent() {
+  LexicalScope *scope = this;
+  while (scope) {
+    if (scope->isTry())
+      return scope->getTry();
+    scope = scope->parentScope;
+  }
+  return nullptr;
+}
+
 void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
                                    cir::FuncOp fn, cir::FuncType funcType,
                                    FunctionArgList args, SourceLocation loc,
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 1c52a78d72e33..82b5405abb633 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -916,10 +916,23 @@ class CIRGenFunction : public CIRGenTypeCache {
     return false;
   }
 
+  mlir::Block *getEHDispatchBlock(EHScopeStack::stable_iterator scope,
+                                  cir::TryOp tryOp);
+
   /// The cleanup depth enclosing all the cleanups associated with the
   /// parameters.
   EHScopeStack::stable_iterator prologueCleanupDepth;
 
+  mlir::Operation *getInvokeDestImpl(cir::TryOp tryOp);
+  mlir::Operation *getInvokeDest(cir::TryOp tryOp) {
+    if (!ehStack.requiresLandingPad())
+      return nullptr;
+    // Return the respective cir.try, this can be used to compute
+    // any other relevant information.
+    return getInvokeDestImpl(tryOp);
+  }
+  bool isInvokeDest();
+
   /// Takes the old cleanup stack size and emits the cleanup blocks
   /// that have been added.
   void popCleanupBlocks(EHScopeStack::stable_iterator oldCleanupStackDepth);
@@ -1063,7 +1076,7 @@ class CIRGenFunction : public CIRGenTypeCache {
     bool isSwitch() { return scopeKind == Kind::Switch; }
     bool isTernary() { return scopeKind == Kind::Ternary; }
     bool isTry() { return scopeKind == Kind::Try; }
-
+    cir::TryOp getClosestTryParent();
     void setAsGlobalInit() { scopeKind = Kind::GlobalInit; }
     void setAsSwitch() { scopeKind = Kind::Switch; }
     void setAsTernary() { scopeKind = Kind::Ternary; }
@@ -1591,6 +1604,8 @@ class CIRGenFunction : public CIRGenTypeCache {
   void emitLambdaDelegatingInvokeBody(const CXXMethodDecl *md);
   void emitLambdaStaticInvokeBody(const CXXMethodDecl *md);
 
+  mlir::Operation *emitLandingPad(cir::TryOp tryOp);
+
   mlir::LogicalResult emitIfStmt(const clang::IfStmt &s);
 
   /// Emit code to compute the specified expression,
diff --git a/clang/lib/CIR/CodeGen/EHScopeStack.h 
b/clang/lib/CIR/CodeGen/EHScopeStack.h
index 9005b0106b2a4..699ef0b799c37 100644
--- a/clang/lib/CIR/CodeGen/EHScopeStack.h
+++ b/clang/lib/CIR/CodeGen/EHScopeStack.h
@@ -217,6 +217,8 @@ class EHScopeStack {
   /// Determines whether the exception-scopes stack is empty.
   bool empty() const { return startOfData == endOfBuffer; }
 
+  bool requiresLandingPad() const;
+
   /// Determines whether there are any normal cleanups on the stack.
   bool hasNormalCleanups() const {
     return innermostNormalCleanup != stable_end();
diff --git a/clang/test/CIR/CodeGen/try-catch-tmp.cpp 
b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
new file mode 100644
index 0000000000000..078447f844d9a
--- /dev/null
+++ b/clang/test/CIR/CodeGen/try-catch-tmp.cpp
@@ -0,0 +1,44 @@
+// 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 -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+int division();
+
+void calling_division_inside_try_block() {
+  try {
+    division();
+  } catch (...) {
+  }
+}
+
+// CIR: cir.scope {
+// CIR:   cir.try {
+// CIR:       %[[CALL:.*]] = cir.call @_Z8divisionv() : () -> !s32i
+// CIR:       cir.yield
+// CIR:   } catch all {
+// CIR:       cir.yield
+// CIR:   }
+// CIR: }
+
+// OGCG:   %[[EXN_OBJ_ADDR:.*]] = alloca ptr, align 8
+// OGCG:   %[[EH_SELECTOR_ADDR:.*]] = alloca i32, align 4
+// OGCG:   %[[CALL:.*]] = invoke noundef i32 @_Z8divisionv()
+// OGCG:           to label %[[INVOKE_CONT:.*]] unwind label 
%[[LANDING_PAD:.*]]
+// OGCG: [[INVOKE_CONT]]:
+// OGCG:   br label %[[TRY_CONT:.*]]
+// OGCG: [[LANDING_PAD]]:
+// OGCG:   %[[LP:.*]] = landingpad { ptr, i32 }
+// OGCG:           catch ptr null
+// OGCG:   %[[EXN_OBJ:.*]] = extractvalue { ptr, i32 } %[[LP]], 0
+// OGCG:   store ptr %[[EXN_OBJ]], ptr %[[EXN_OBJ_ADDR]], align 8
+// OGCG:   %[[EH_SELECTOR_VAL:.*]] = extractvalue { ptr, i32 } %[[LP]], 1
+// OGCG:   store i32 %[[EH_SELECTOR_VAL]], ptr %[[EH_SELECTOR_ADDR]], align 4
+// OGCG:   br label %[[CATCH:.*]]
+// OGCG: [[CATCH]]:
+// OGCG:   %[[EXN_OBJ:.*]] = load ptr, ptr %[[EXN_OBJ_ADDR]], align 8
+// OGCG:   %[[CATCH_BEGIN:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN_OBJ]])
+// OGCG:   call void @__cxa_end_catch()
+// OGCG:   br label %[[TRY_CONT]]
+// OGCG: [[TRY_CONT]]:
+// OGCG:   ret void

>From a682866b7bdaa526377393a059bf6e88c275c18d Mon Sep 17 00:00:00 2001
From: Amr Hesham <[email protected]>
Date: Wed, 5 Nov 2025 21:57:33 +0100
Subject: [PATCH 2/2] Address code review comments

---
 .../CIR/Dialect/Builder/CIRBaseBuilder.h      | 19 -------
 clang/lib/CIR/CodeGen/CIRGenCall.cpp          | 12 ++--
 clang/lib/CIR/CodeGen/CIRGenCleanup.cpp       |  2 +-
 clang/lib/CIR/CodeGen/CIRGenCleanup.h         |  6 +-
 clang/lib/CIR/CodeGen/CIRGenException.cpp     | 57 +++++--------------
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |  8 +--
 clang/lib/CIR/CodeGen/EHScopeStack.h          |  2 +-
 7 files changed, 28 insertions(+), 78 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 3288f5b12c77e..de98495fcd653 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -389,25 +389,6 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     return createCallOp(loc, callee, cir::VoidType(), operands, attrs);
   }
 
-  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,
-      [[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);
-  }
-
   
//===--------------------------------------------------------------------===//
   // Cast/Conversion Operators
   
//===--------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index ea44c65636c6c..2168f8bffb9b0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -472,11 +472,11 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location 
callLoc,
   assert(!cir::MissingFeatures::opCallSurroundingTry());
 
   if (isInvoke) {
-    // This call can throw, few options:
-    //  - If this call does not have an associated cir.try, use the
-    //    one provided by InvokeDest,
-    //  - User written try/catch clauses require calls to handle
-    //    exceptions under cir.try.
+    // This call may throw and requires catch and/or cleanup handling.
+    // If this call does not appear within the `try` region of an existing
+    // TryOp, we must create a synthetic TryOp to contain the call. This
+    // happens when a call that may throw appears within a cleanup
+    // scope.
 
     // In OG, we build the landing pad for this scope. In CIR, we emit a
     // synthetic cir.try because this didn't come from code generating from a
@@ -501,7 +501,7 @@ emitCallLikeOp(CIRGenFunction &cgf, mlir::Location callLoc,
     }
 
     callOpWithExceptions =
-        builder.createTryCallOp(callLoc, directFuncOp, cirCallArgs);
+        builder.createCallOp(callLoc, directFuncOp, cirCallArgs);
 
     (void)cgf.getInvokeDest(tryOp);
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
index 3550a78cc1816..9be17ce3f431f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
@@ -188,7 +188,7 @@ void EHScopeStack::popCleanup() {
   }
 }
 
-bool EHScopeStack::requiresLandingPad() const {
+bool EHScopeStack::requiresCatchOrCleanup() const {
   for (stable_iterator si = getInnermostEHScope(); si != stable_end();) {
     // TODO(cir): Skip lifetime markers.
     assert(!cir::MissingFeatures::emitLifetimeMarkers());
diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.h 
b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
index 4e4e913574991..eec33aa5ad8d2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
@@ -38,7 +38,7 @@ class EHScope {
   };
   enum { NumCommonBits = 3 };
 
-  bool isScopeMayThrow;
+  bool scopeMayThrow;
 
 protected:
   class CatchBitFields {
@@ -94,10 +94,10 @@ class EHScope {
     // Traditional LLVM codegen also checks for `!block->use_empty()`, but
     // in CIRGen the block content is not important, just used as a way to
     // signal `hasEHBranches`.
-    return isScopeMayThrow;
+    return scopeMayThrow;
   }
 
-  void setMayThrow(bool mayThrow) { isScopeMayThrow = mayThrow; }
+  void setMayThrow(bool mayThrow) { scopeMayThrow = mayThrow; }
 
   EHScopeStack::stable_iterator getEnclosingEHScope() const {
     return enclosingEHScope;
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp 
b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 700e5e0c67c45..061ef81023c70 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -355,33 +355,6 @@ void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &s, 
cir::TryOp tryOp,
   }
 }
 
-/// Emit the structure of the dispatch block for the given catch scope.
-/// It is an invariant that the dispatch block already exists.
-static void emitCatchDispatchBlock(CIRGenFunction &cgf,
-                                   EHCatchScope &catchScope, cir::TryOp tryOp) 
{
-  if (EHPersonality::get(cgf).isWasmPersonality()) {
-    cgf.cgm.errorNYI("emitCatchDispatchBlock: WASM personality");
-    return;
-  }
-
-  if (EHPersonality::get(cgf).usesFuncletPads()) {
-    cgf.cgm.errorNYI("emitCatchDispatchBlock: usesFuncletPads");
-    return;
-  }
-
-  assert(catchScope.mayThrow() &&
-         "Expected catchScope that may throw exception");
-
-  // If there's only a single catch-all, getEHDispatchBlock returned
-  // that catch-all as the dispatch block.
-  if (catchScope.getNumHandlers() == 1 &&
-      catchScope.getHandler(0).isCatchAll()) {
-    return;
-  }
-
-  cgf.cgm.errorNYI("emitCatchDispatchBlock: non-catch all handler");
-}
-
 void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) {
   unsigned numHandlers = s.getNumHandlers();
   EHCatchScope &catchScope = cast<EHCatchScope>(*ehStack.begin());
@@ -410,9 +383,6 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, 
bool isFnTryBlock) {
     return;
   }
 
-  // Emit the structure of the EH dispatch for this catch.
-  emitCatchDispatchBlock(*this, catchScope, tryOp);
-
   // Copy the handler blocks off before we pop the EH stack.  Emitting
   // the handlers might scribble on this memory.
   SmallVector<EHCatchScope::Handler, 8> handlers(
@@ -490,8 +460,8 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, 
bool isFnTryBlock) {
   assert(!cir::MissingFeatures::incrementProfileCounter());
 }
 
-mlir::Operation *CIRGenFunction::emitLandingPad(cir::TryOp tryOp) {
-  assert(ehStack.requiresLandingPad());
+mlir::Operation *CIRGenFunction::populateCatchHandlers(cir::TryOp tryOp) {
+  assert(ehStack.requiresCatchOrCleanup());
   assert(!cgm.getLangOpts().IgnoreExceptions &&
          "LandingPad should not be emitted when -fignore-exceptions are in "
          "effect.");
@@ -551,17 +521,17 @@ mlir::Operation 
*CIRGenFunction::emitLandingPad(cir::TryOp tryOp) {
         if (handler.isCatchAll()) {
           assert(!hasCatchAll);
           hasCatchAll = true;
-          goto done;
+          break;
         }
 
         cgm.errorNYI("emitLandingPad: non catch-all");
         return {};
       }
 
-      goto done;
+      if (hasCatchAll)
+        break;
     }
 
-  done:
     if (hasCatchAll) {
       handlerAttrs.push_back(cir::CatchAllAttr::get(&getMLIRContext()));
     } else {
@@ -576,20 +546,19 @@ mlir::Operation 
*CIRGenFunction::emitLandingPad(cir::TryOp tryOp) {
 
   // In traditional LLVM codegen. this tells the backend how to generate the
   // landing pad by generating a branch to the dispatch block. In CIR,
-  // getEHDispatchBlock is used to populate blocks for later filing during
+  // this is used to populate blocks for later filing during
   // cleanup handling.
-  (void)getEHDispatchBlock(ehStack.getInnermostEHScope(), tryOp);
+  (void)populateEHCatchRegions(ehStack.getInnermostEHScope(), tryOp);
 
   return tryOp;
 }
 
 // Differently from LLVM traditional codegen, there are no dispatch blocks
 // to look at given cir.try_call does not jump to blocks like invoke does.
-// However, we keep this around since other parts of CIRGen use
-// getCachedEHDispatchBlock to infer state.
+// However.
 mlir::Block *
-CIRGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator scope,
-                                   cir::TryOp tryOp) {
+CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator scope,
+                                       cir::TryOp tryOp) {
   if (EHPersonality::get(*this).usesFuncletPads()) {
     cgm.errorNYI("getEHDispatchBlock: usesFuncletPads");
     return {};
@@ -648,7 +617,7 @@ 
CIRGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator scope,
 }
 
 bool CIRGenFunction::isInvokeDest() {
-  if (!ehStack.requiresLandingPad())
+  if (!ehStack.requiresCatchOrCleanup())
     return false;
 
   // If exceptions are disabled/ignored and SEH is not in use, then there is no
@@ -669,7 +638,7 @@ bool CIRGenFunction::isInvokeDest() {
 }
 
 mlir::Operation *CIRGenFunction::getInvokeDestImpl(cir::TryOp tryOp) {
-  assert(ehStack.requiresLandingPad());
+  assert(ehStack.requiresCatchOrCleanup());
   assert(!ehStack.empty());
 
   // TODO(cir): add personality function
@@ -681,7 +650,7 @@ mlir::Operation 
*CIRGenFunction::getInvokeDestImpl(cir::TryOp tryOp) {
   if (personality.usesFuncletPads()) {
     cgm.errorNYI("getInvokeDestImpl: usesFuncletPads");
   } else {
-    lp = emitLandingPad(tryOp);
+    lp = populateCatchHandlers(tryOp);
   }
 
   return lp;
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 82b5405abb633..5e5af61dc028f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -916,8 +916,8 @@ class CIRGenFunction : public CIRGenTypeCache {
     return false;
   }
 
-  mlir::Block *getEHDispatchBlock(EHScopeStack::stable_iterator scope,
-                                  cir::TryOp tryOp);
+  mlir::Block *populateEHCatchRegions(EHScopeStack::stable_iterator scope,
+                                      cir::TryOp tryOp);
 
   /// The cleanup depth enclosing all the cleanups associated with the
   /// parameters.
@@ -925,7 +925,7 @@ class CIRGenFunction : public CIRGenTypeCache {
 
   mlir::Operation *getInvokeDestImpl(cir::TryOp tryOp);
   mlir::Operation *getInvokeDest(cir::TryOp tryOp) {
-    if (!ehStack.requiresLandingPad())
+    if (!ehStack.requiresCatchOrCleanup())
       return nullptr;
     // Return the respective cir.try, this can be used to compute
     // any other relevant information.
@@ -1604,7 +1604,7 @@ class CIRGenFunction : public CIRGenTypeCache {
   void emitLambdaDelegatingInvokeBody(const CXXMethodDecl *md);
   void emitLambdaStaticInvokeBody(const CXXMethodDecl *md);
 
-  mlir::Operation *emitLandingPad(cir::TryOp tryOp);
+  mlir::Operation *populateCatchHandlers(cir::TryOp tryOp);
 
   mlir::LogicalResult emitIfStmt(const clang::IfStmt &s);
 
diff --git a/clang/lib/CIR/CodeGen/EHScopeStack.h 
b/clang/lib/CIR/CodeGen/EHScopeStack.h
index 699ef0b799c37..6455bd8a55c83 100644
--- a/clang/lib/CIR/CodeGen/EHScopeStack.h
+++ b/clang/lib/CIR/CodeGen/EHScopeStack.h
@@ -217,7 +217,7 @@ class EHScopeStack {
   /// Determines whether the exception-scopes stack is empty.
   bool empty() const { return startOfData == endOfBuffer; }
 
-  bool requiresLandingPad() const;
+  bool requiresCatchOrCleanup() const;
 
   /// Determines whether there are any normal cleanups on the stack.
   bool hasNormalCleanups() const {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to