https://github.com/erichkeane updated 
https://github.com/llvm/llvm-project/pull/186869

>From f8059fc05fb8095a710954817298aa8fe99d9bcc Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Mon, 16 Mar 2026 11:46:52 -0700
Subject: [PATCH 1/2] [CIR] Fix bug where block after-unreachable wasn't
 CXXABILowered

If a TU has an 'unreachable' block, it wouldn't be CXXABILower'ed, which
would cause a legalization failure.  This patch adds the same solution
we do in LowerToLLVM, which is to make sure we transform those sections
separately.
---
 .../CIR/Dialect/Transforms/CXXABILowering.cpp | 69 ++++++++++++++++++-
 .../CodeGen/abi-lower-after-unreachable.cpp   | 31 +++++++++
 2 files changed, 99 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CIR/CodeGen/abi-lower-after-unreachable.cpp

diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index d2c7ac37e8a96..fcaa38683c396 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -538,6 +538,69 @@ populateCXXABIConversionTarget(mlir::ConversionTarget 
&target,
 // The Pass
 
//===----------------------------------------------------------------------===//
 
+// The applyPartialConversion function traverses blocks in the dominance order,
+// so it does not lower and operations that are not reachachable from the
+// operations passed in as arguments. Since we do need to lower such code in
+// order to avoid verification errors occur, we cannot just pass the module op
+// to applyPartialConversion. We must build a set of unreachable ops and
+// explicitly add them, along with the module, to the vector we pass to
+// applyPartialConversion.
+//
+// For instance, this CIR code:
+//
+//    cir.func @foo(%arg0: !s32i) -> !s32i {
+//      %4 = cir.cast int_to_bool %arg0 : !s32i -> !cir.bool
+//      cir.if %4 {
+//        %5 = cir.const #cir.int<1> : !s32i
+//        cir.return %5 : !s32i
+//      } else {
+//        %5 = cir.const #cir.int<0> : !s32i
+//       cir.return %5 : !s32i
+//      }
+//      cir.return %arg0 : !s32i
+//    }
+//
+// contains an unreachable return operation (the last one). After the CXXABI
+// pass it will be placed into the unreachable block.  This will error because
+// it will have not converted the types in the block, making the legalizer 
fail.
+//
+// In the future we may want to get rid of this function and use a DCE pass or
+// something similar. But for now we need to guarantee the absence of the
+// dialect verification errors. Note: We do the same in LowerToLLVM as well,
+// this is a striaght copy/paste including most of the comment. We might wi sh
+// to combine these if we don't want to do a DCE pass/etc.
+static void collectUnreachable(mlir::Operation *parent,
+                               llvm::SmallVector<mlir::Operation *> &ops) {
+
+  llvm::SmallVector<mlir::Block *> unreachableBlocks;
+  parent->walk([&](mlir::Block *blk) { // check
+    if (blk->hasNoPredecessors() && !blk->isEntryBlock())
+      unreachableBlocks.push_back(blk);
+  });
+
+  std::set<mlir::Block *> visited;
+  for (mlir::Block *root : unreachableBlocks) {
+    // We create a work list for each unreachable block.
+    // Thus we traverse operations in some order.
+    std::deque<mlir::Block *> workList;
+    workList.push_back(root);
+
+    while (!workList.empty()) {
+      mlir::Block *blk = workList.back();
+      workList.pop_back();
+      if (visited.count(blk))
+        continue;
+      visited.emplace(blk);
+
+      for (mlir::Operation &op : *blk)
+        ops.push_back(&op);
+
+      for (mlir::Block *succ : blk->getSuccessors())
+        workList.push_back(succ);
+    }
+  }
+}
+
 void CXXABILoweringPass::runOnOperation() {
   auto mod = mlir::cast<mlir::ModuleOp>(getOperation());
   mlir::MLIRContext *ctx = mod.getContext();
@@ -566,7 +629,11 @@ void CXXABILoweringPass::runOnOperation() {
   mlir::ConversionTarget target(*ctx);
   populateCXXABIConversionTarget(target, typeConverter);
 
-  if (failed(mlir::applyPartialConversion(mod, target, std::move(patterns))))
+  llvm::SmallVector<mlir::Operation *> ops;
+  ops.push_back(mod);
+  collectUnreachable(mod, ops);
+
+  if (failed(mlir::applyPartialConversion(ops, target, std::move(patterns))))
     signalPassFailure();
 }
 
diff --git a/clang/test/CIR/CodeGen/abi-lower-after-unreachable.cpp 
b/clang/test/CIR/CodeGen/abi-lower-after-unreachable.cpp
new file mode 100644
index 0000000000000..180bf365940ef
--- /dev/null
+++ b/clang/test/CIR/CodeGen/abi-lower-after-unreachable.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -I%S/Inputs %s -triple x86_64-unknown-linux-gnu -fclangir 
-emit-cir -mmlir --mlir-print-ir-before=cir-cxxabi-lowering -o %t.cir 2> 
%t-before.cir
+// RUN: FileCheck %s --input-file=%t-before.cir --check-prefixes=CIR,CIR-BEFORE
+// RUN: FileCheck %s --input-file=%t.cir --check-prefixes=CIR,CIR-AFTER
+struct Base1 {
+  virtual ~Base1();
+};
+
+struct Base2 {
+  virtual ~Base2();
+};
+
+struct Derived final : Base1 {};
+
+using PMFTy = void(Derived::*)(void);
+
+void untransformed_after_unreachable(Base2 &ref, PMFTy pmf) {
+    auto badcast = dynamic_cast<Derived &>(ref);
+    (badcast.*pmf)();
+
+// CIR-LABEL: cir.func 
{{.*}}@_Z31untransformed_after_unreachableR5Base2M7DerivedFvvE
+//         CIR:    %[[PMF:.*]] = cir.alloca !{{.*}} ["pmf", init]
+//         CIR:    %[[DERIVED:.*]] = cir.alloca !rec_Derived
+//         CIR:    cir.load %{{.*}} : !cir.ptr<!cir.ptr<!rec_Base2>>, 
!cir.ptr<!rec_Base2>
+//    CIR-NEXT:    cir.call @__cxa_bad_cast() : () -> ()
+//    CIR-NEXT:    cir.unreachable
+//  CIR-BEFORE:    %[[PMF_LOAD:.*]] = cir.load{{.*}} %[[PMF]]
+//  CIR-BEFORE:    cir.get_method %[[PMF_LOAD]], %[[DERIVED]]
+//   CIR-AFTER:    %[[PMF_LOAD:.*]] = cir.load{{.*}} %[[PMF]]
+//   CIR-AFTER:    %[[PMF_EXTRACT:.*]] = cir.extract_member %[[PMF_LOAD]][1]
+//   CIR-AFTER:    %[[PMF_EXTRACT:.*]] = cir.extract_member %[[PMF_LOAD]][0]
+}

>From e216f502cb549b096ec080f4ed91bebaaa6a025e Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Mon, 16 Mar 2026 12:57:22 -0700
Subject: [PATCH 2/2] Add 'deque' include, since apparently it was transitively
 included on my computer but not on one of the CI bots

---
 clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index fcaa38683c396..a68256ed76b6f 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -6,6 +6,8 @@
 //
 
//===----------------------------------------------------------------------===//
 
+#include <deque>
+
 #include "PassDetail.h"
 #include "TargetLowering/LowerModule.h"
 

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

Reply via email to