[Mlir-commits] [mlir] [mlir] Report block argument removal from runRegionDCE (PR #232211)

Hideto Ueno llvmlistbot at llvm.org
Thu Oct 15 18:49:23 PDT 2026


https://github.com/uenoku updated https://github.com/llvm/llvm-project/pull/232211

>From 9947331ca17c66a83a434936c3194c88c31c48a6 Mon Sep 17 00:00:00 2001
From: Hideto Ueno <uenoku.tokotoko at gmail.com>
Date: Thu, 15 Oct 2026 00:08:22 -0700
Subject: [PATCH 1/3] [mlir] Report block argument removal from runRegionDCE

runRegionDCE reports whether it changed the IR, but deleteDeadness did not
include dead non-entry block arguments in its change flag. Track their removal
so callers detect argument-only changes.
---
 mlir/lib/Transforms/Utils/RegionUtils.cpp |  7 +++-
 mlir/unittests/Transforms/CMakeLists.txt  |  3 ++
 mlir/unittests/Transforms/RegionUtils.cpp | 47 +++++++++++++++++++++++
 3 files changed, 55 insertions(+), 2 deletions(-)
 create mode 100644 mlir/unittests/Transforms/RegionUtils.cpp

diff --git a/mlir/lib/Transforms/Utils/RegionUtils.cpp b/mlir/lib/Transforms/Utils/RegionUtils.cpp
index cc90df06918000..9cc20b54f8d849 100644
--- a/mlir/lib/Transforms/Utils/RegionUtils.cpp
+++ b/mlir/lib/Transforms/Utils/RegionUtils.cpp
@@ -473,8 +473,11 @@ static LogicalResult deleteDeadness(RewriterBase &rewriter,
     // The entry block has an unknown contract with their enclosing block, so
     // skip it.
     for (Block &block : llvm::drop_begin(region.getBlocks(), 1)) {
-      block.eraseArguments(
-          [&](BlockArgument arg) { return !liveMap.wasProvenLive(arg); });
+      block.eraseArguments([&](BlockArgument arg) {
+        bool isDead = !liveMap.wasProvenLive(arg);
+        erasedAnything |= isDead;
+        return isDead;
+      });
     }
   }
   return success(erasedAnything);
diff --git a/mlir/unittests/Transforms/CMakeLists.txt b/mlir/unittests/Transforms/CMakeLists.txt
index dc5920087b505e..8fbf18fc7e53bd 100644
--- a/mlir/unittests/Transforms/CMakeLists.txt
+++ b/mlir/unittests/Transforms/CMakeLists.txt
@@ -1,8 +1,11 @@
 add_mlir_unittest(MLIRTransformsTests
   Canonicalizer.cpp
   DialectConversion.cpp
+  RegionUtils.cpp
 )
 mlir_target_link_libraries(MLIRTransformsTests
   PRIVATE
+  MLIRControlFlowDialect
+  MLIRFuncDialect
   MLIRParser
   MLIRTransforms)
diff --git a/mlir/unittests/Transforms/RegionUtils.cpp b/mlir/unittests/Transforms/RegionUtils.cpp
new file mode 100644
index 00000000000000..2828785b9a5fca
--- /dev/null
+++ b/mlir/unittests/Transforms/RegionUtils.cpp
@@ -0,0 +1,47 @@
+//===- RegionUtils.cpp - Region utility unit tests ------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Transforms/RegionUtils.h"
+#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/Parser/Parser.h"
+#include "gtest/gtest.h"
+
+using namespace mlir;
+
+namespace {
+TEST(RegionUtilsTest, ReportsDeadBlockArgumentRemoval) {
+  MLIRContext context;
+  context.getOrLoadDialect<cf::ControlFlowDialect>();
+  context.getOrLoadDialect<func::FuncDialect>();
+
+  auto module = parseSourceString<ModuleOp>(R"mlir(
+    func.func @f(%arg0: i32) {
+      cf.br ^bb1(%arg0 : i32)
+    ^bb1(%unused: i32):
+      return
+    }
+  )mlir",
+                                            &context);
+  ASSERT_TRUE(module);
+
+  func::FuncOp func = module->lookupSymbol<func::FuncOp>("f");
+  ASSERT_TRUE(func);
+  Region &region = func.getBody();
+  ASSERT_EQ(region.getBlocks().size(), 2u);
+  ASSERT_EQ(region.back().getNumArguments(), 1u);
+
+  IRRewriter rewriter(&context);
+  EXPECT_TRUE(
+      succeeded(runRegionDCE(rewriter, func.getOperation()->getRegions())));
+  EXPECT_EQ(region.back().getNumArguments(), 0u);
+  EXPECT_EQ(region.front().getTerminator()->getNumOperands(), 0u);
+}
+} // namespace

>From ebbb69246c122086842dc3976ed97ca219f07498 Mon Sep 17 00:00:00 2001
From: Hideto Ueno <uenoku.tokotoko at gmail.com>
Date: Thu, 15 Oct 2026 00:26:50 -0700
Subject: [PATCH 2/3] [mlir] Keep region DCE regression test self-contained

Define a local test branch operation instead of linking the Func and ControlFlow dialect libraries. This preserves a CFG regression test for runRegionDCE's change result without adding dialect dependencies to the unit-test target.
---
 mlir/unittests/Transforms/CMakeLists.txt  |  2 -
 mlir/unittests/Transforms/RegionUtils.cpp | 57 +++++++++++++++++------
 2 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/mlir/unittests/Transforms/CMakeLists.txt b/mlir/unittests/Transforms/CMakeLists.txt
index 8fbf18fc7e53bd..c0129be9b13fd3 100644
--- a/mlir/unittests/Transforms/CMakeLists.txt
+++ b/mlir/unittests/Transforms/CMakeLists.txt
@@ -5,7 +5,5 @@ add_mlir_unittest(MLIRTransformsTests
 )
 mlir_target_link_libraries(MLIRTransformsTests
   PRIVATE
-  MLIRControlFlowDialect
-  MLIRFuncDialect
   MLIRParser
   MLIRTransforms)
diff --git a/mlir/unittests/Transforms/RegionUtils.cpp b/mlir/unittests/Transforms/RegionUtils.cpp
index 2828785b9a5fca..c7f6286c9dc6a6 100644
--- a/mlir/unittests/Transforms/RegionUtils.cpp
+++ b/mlir/unittests/Transforms/RegionUtils.cpp
@@ -7,41 +7,72 @@
 //===----------------------------------------------------------------------===//
 
 #include "mlir/Transforms/RegionUtils.h"
-#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
-#include "mlir/Dialect/Func/IR/FuncOps.h"
 #include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/Dialect.h"
+#include "mlir/IR/OpDefinition.h"
 #include "mlir/IR/PatternMatch.h"
+#include "mlir/Interfaces/ControlFlowInterfaces.h"
 #include "mlir/Parser/Parser.h"
 #include "gtest/gtest.h"
 
 using namespace mlir;
 
 namespace {
+class TestBranchOp
+    : public Op<TestBranchOp, OpTrait::VariadicOperands, OpTrait::ZeroResults,
+                OpTrait::OneSuccessor, OpTrait::IsTerminator,
+                BranchOpInterface::Trait> {
+public:
+  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestBranchOp)
+
+  using Op::Op;
+
+  static StringRef getOperationName() { return "test.br"; }
+  static ArrayRef<StringRef> getAttributeNames() { return {}; }
+
+  SuccessorOperands getSuccessorOperands(unsigned index) {
+    assert(index == 0 && "invalid successor index");
+    return SuccessorOperands(MutableOperandRange(getOperation()));
+  }
+};
+
+class TestDialect : public Dialect {
+public:
+  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDialect)
+
+  static StringRef getDialectNamespace() { return "test"; }
+
+  explicit TestDialect(MLIRContext *context)
+      : Dialect(getDialectNamespace(), context, TypeID::get<TestDialect>()) {
+    addOperations<TestBranchOp>();
+    allowUnknownOperations();
+  }
+};
+
 TEST(RegionUtilsTest, ReportsDeadBlockArgumentRemoval) {
   MLIRContext context;
-  context.getOrLoadDialect<cf::ControlFlowDialect>();
-  context.getOrLoadDialect<func::FuncDialect>();
+  context.getOrLoadDialect<TestDialect>();
 
   auto module = parseSourceString<ModuleOp>(R"mlir(
-    func.func @f(%arg0: i32) {
-      cf.br ^bb1(%arg0 : i32)
+    "test.container"() ({
+    ^bb0(%arg0: i32):
+      "test.br"(%arg0)[^bb1] : (i32) -> ()
     ^bb1(%unused: i32):
-      return
-    }
+      "test.br"(%unused)[^bb1] : (i32) -> ()
+    }) : () -> ()
   )mlir",
                                             &context);
   ASSERT_TRUE(module);
 
-  func::FuncOp func = module->lookupSymbol<func::FuncOp>("f");
-  ASSERT_TRUE(func);
-  Region &region = func.getBody();
+  Operation *container = &module->getBody()->front();
+  Region &region = container->getRegion(0);
   ASSERT_EQ(region.getBlocks().size(), 2u);
   ASSERT_EQ(region.back().getNumArguments(), 1u);
 
   IRRewriter rewriter(&context);
-  EXPECT_TRUE(
-      succeeded(runRegionDCE(rewriter, func.getOperation()->getRegions())));
+  EXPECT_TRUE(succeeded(runRegionDCE(rewriter, container->getRegions())));
   EXPECT_EQ(region.back().getNumArguments(), 0u);
   EXPECT_EQ(region.front().getTerminator()->getNumOperands(), 0u);
+  EXPECT_EQ(region.back().getTerminator()->getNumOperands(), 0u);
 }
 } // namespace

>From 5189b3f8304d3ccec9a0b0a1e4055592aa23a214 Mon Sep 17 00:00:00 2001
From: Hideto Ueno <uenoku.tokotoko at gmail.com>
Date: Thu, 15 Oct 2026 18:47:26 -0700
Subject: [PATCH 3/3] Remove a test for now

---
 mlir/unittests/Transforms/CMakeLists.txt  |  1 -
 mlir/unittests/Transforms/RegionUtils.cpp | 78 -----------------------
 2 files changed, 79 deletions(-)
 delete mode 100644 mlir/unittests/Transforms/RegionUtils.cpp

diff --git a/mlir/unittests/Transforms/CMakeLists.txt b/mlir/unittests/Transforms/CMakeLists.txt
index c0129be9b13fd3..dc5920087b505e 100644
--- a/mlir/unittests/Transforms/CMakeLists.txt
+++ b/mlir/unittests/Transforms/CMakeLists.txt
@@ -1,7 +1,6 @@
 add_mlir_unittest(MLIRTransformsTests
   Canonicalizer.cpp
   DialectConversion.cpp
-  RegionUtils.cpp
 )
 mlir_target_link_libraries(MLIRTransformsTests
   PRIVATE
diff --git a/mlir/unittests/Transforms/RegionUtils.cpp b/mlir/unittests/Transforms/RegionUtils.cpp
deleted file mode 100644
index c7f6286c9dc6a6..00000000000000
--- a/mlir/unittests/Transforms/RegionUtils.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-//===- RegionUtils.cpp - Region utility unit tests ------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "mlir/Transforms/RegionUtils.h"
-#include "mlir/IR/BuiltinOps.h"
-#include "mlir/IR/Dialect.h"
-#include "mlir/IR/OpDefinition.h"
-#include "mlir/IR/PatternMatch.h"
-#include "mlir/Interfaces/ControlFlowInterfaces.h"
-#include "mlir/Parser/Parser.h"
-#include "gtest/gtest.h"
-
-using namespace mlir;
-
-namespace {
-class TestBranchOp
-    : public Op<TestBranchOp, OpTrait::VariadicOperands, OpTrait::ZeroResults,
-                OpTrait::OneSuccessor, OpTrait::IsTerminator,
-                BranchOpInterface::Trait> {
-public:
-  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestBranchOp)
-
-  using Op::Op;
-
-  static StringRef getOperationName() { return "test.br"; }
-  static ArrayRef<StringRef> getAttributeNames() { return {}; }
-
-  SuccessorOperands getSuccessorOperands(unsigned index) {
-    assert(index == 0 && "invalid successor index");
-    return SuccessorOperands(MutableOperandRange(getOperation()));
-  }
-};
-
-class TestDialect : public Dialect {
-public:
-  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDialect)
-
-  static StringRef getDialectNamespace() { return "test"; }
-
-  explicit TestDialect(MLIRContext *context)
-      : Dialect(getDialectNamespace(), context, TypeID::get<TestDialect>()) {
-    addOperations<TestBranchOp>();
-    allowUnknownOperations();
-  }
-};
-
-TEST(RegionUtilsTest, ReportsDeadBlockArgumentRemoval) {
-  MLIRContext context;
-  context.getOrLoadDialect<TestDialect>();
-
-  auto module = parseSourceString<ModuleOp>(R"mlir(
-    "test.container"() ({
-    ^bb0(%arg0: i32):
-      "test.br"(%arg0)[^bb1] : (i32) -> ()
-    ^bb1(%unused: i32):
-      "test.br"(%unused)[^bb1] : (i32) -> ()
-    }) : () -> ()
-  )mlir",
-                                            &context);
-  ASSERT_TRUE(module);
-
-  Operation *container = &module->getBody()->front();
-  Region &region = container->getRegion(0);
-  ASSERT_EQ(region.getBlocks().size(), 2u);
-  ASSERT_EQ(region.back().getNumArguments(), 1u);
-
-  IRRewriter rewriter(&context);
-  EXPECT_TRUE(succeeded(runRegionDCE(rewriter, container->getRegions())));
-  EXPECT_EQ(region.back().getNumArguments(), 0u);
-  EXPECT_EQ(region.front().getTerminator()->getNumOperands(), 0u);
-  EXPECT_EQ(region.back().getTerminator()->getNumOperands(), 0u);
-}
-} // namespace



More information about the Mlir-commits mailing list