[Mlir-commits] [mlir] [mlir][IR][NFC] Add `Block::computeBlockNumber` convenience helper (PR #173475)

Matthias Springer llvmlistbot at llvm.org
Wed Dec 24 02:45:07 PST 2025


https://github.com/matthias-springer created https://github.com/llvm/llvm-project/pull/173475

Add a helper function to compute the number of a block. Recommended only for debugging purposes and to print error messages.

>From 36a141a09b3288365bfef3d8bfb68cada785e0f0 Mon Sep 17 00:00:00 2001
From: Matthias Springer <me at m-sp.org>
Date: Wed, 24 Dec 2025 10:38:55 +0000
Subject: [PATCH] [mlir][IR][NFC] Add `Block::computeBlockNumber` helper

---
 mlir/include/mlir/IR/Block.h                         | 12 ++++++++++++
 .../Transform/DebugExtension/DebugExtensionOps.cpp   |  5 ++---
 .../Transform/Interfaces/TransformInterfaces.cpp     |  3 +--
 mlir/lib/IR/Block.cpp                                |  5 +++++
 mlir/lib/IR/Unit.cpp                                 |  4 +---
 mlir/lib/IR/Verifier.cpp                             |  2 +-
 mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp        |  9 ++-------
 mlir/lib/Transforms/RemoveDeadValues.cpp             |  2 +-
 mlir/test/lib/Analysis/TestAliasAnalysis.cpp         |  3 +--
 9 files changed, 26 insertions(+), 19 deletions(-)

diff --git a/mlir/include/mlir/IR/Block.h b/mlir/include/mlir/IR/Block.h
index 85ce66f69df48..3d737fa3e0659 100644
--- a/mlir/include/mlir/IR/Block.h
+++ b/mlir/include/mlir/IR/Block.h
@@ -77,6 +77,18 @@ class alignas(8) Block : public IRObjectWithUseList<BlockOperand>,
   /// Unlink this Block from its parent region and delete it.
   void erase();
 
+  /// Compute the position of this block within its parent region.
+  ///
+  /// Note: There is no semantic meaning to a block number. Blocks are used for
+  /// unstructured control flow and relying on block numbers for functional
+  /// purposes may indicate a design flaw. (You can give semantic meaning to
+  /// region numbers instead.) Block numbers are useful for debugging purposes
+  /// and for error messages.
+  ///
+  /// This function has a complexity of O(N) because it iterates over a linked
+  /// list of blocks.
+  unsigned computeBlockNumber();
+
   //===--------------------------------------------------------------------===//
   // Block argument management
   //===--------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/Transform/DebugExtension/DebugExtensionOps.cpp b/mlir/lib/Dialect/Transform/DebugExtension/DebugExtensionOps.cpp
index a963b3f063a8a..9f9695b7d348b 100644
--- a/mlir/lib/Dialect/Transform/DebugExtension/DebugExtensionOps.cpp
+++ b/mlir/lib/Dialect/Transform/DebugExtension/DebugExtensionOps.cpp
@@ -34,9 +34,8 @@ transform::EmitRemarkAtOp::apply(transform::TransformRewriter &rewriter,
     os << "value handle points to ";
     if (auto arg = llvm::dyn_cast<BlockArgument>(value)) {
       os << "a block argument #" << arg.getArgNumber() << " in block #"
-         << std::distance(arg.getOwner()->getParent()->begin(),
-                          arg.getOwner()->getIterator())
-         << " in region #" << arg.getOwner()->getParent()->getRegionNumber();
+         << arg.getOwner()->computeBlockNumber() << " in region #"
+         << arg.getOwner()->getParent()->getRegionNumber();
     } else {
       os << "an op result #" << llvm::cast<OpResult>(value).getResultNumber();
     }
diff --git a/mlir/lib/Dialect/Transform/Interfaces/TransformInterfaces.cpp b/mlir/lib/Dialect/Transform/Interfaces/TransformInterfaces.cpp
index 4f09782859e07..c1fc1d53742ea 100644
--- a/mlir/lib/Dialect/Transform/Interfaces/TransformInterfaces.cpp
+++ b/mlir/lib/Dialect/Transform/Interfaces/TransformInterfaces.cpp
@@ -554,8 +554,7 @@ void transform::TransformState::recordValueHandleInvalidationByOpHandleOne(
       auto arg = llvm::cast<BlockArgument>(payloadValue);
       definingOp = arg.getParentBlock()->getParentOp();
       argumentNo = arg.getArgNumber();
-      blockNo = std::distance(arg.getOwner()->getParent()->begin(),
-                              arg.getOwner()->getIterator());
+      blockNo = arg.getOwner()->computeBlockNumber();
       regionNo = arg.getOwner()->getParent()->getRegionNumber();
     }
     assert(definingOp && "expected the value to be defined by an op as result "
diff --git a/mlir/lib/IR/Block.cpp b/mlir/lib/IR/Block.cpp
index 27b47e2d2653d..1a06c576fd01c 100644
--- a/mlir/lib/IR/Block.cpp
+++ b/mlir/lib/IR/Block.cpp
@@ -141,6 +141,11 @@ void Block::recomputeOpOrder() {
     op.orderIndex = (orderIndex += Operation::kOrderStride);
 }
 
+unsigned Block::computeBlockNumber() {
+  assert(getParent() && "cannot compute block number of detached block");
+  return std::distance(getParent()->begin(), getIterator());
+}
+
 //===----------------------------------------------------------------------===//
 // Argument list management.
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/IR/Unit.cpp b/mlir/lib/IR/Unit.cpp
index 58c1d27db87f0..158fa13bf9e5f 100644
--- a/mlir/lib/IR/Unit.cpp
+++ b/mlir/lib/IR/Unit.cpp
@@ -37,9 +37,7 @@ static void printRegion(llvm::raw_ostream &os, Region *region,
 static void printBlock(llvm::raw_ostream &os, Block *block,
                        OpPrintingFlags &flags) {
   Region *region = block->getParent();
-  Block *entry = &region->front();
-  int blockId = std::distance(entry->getIterator(), block->getIterator());
-  os << "Block #" << blockId << " for ";
+  os << "Block #" << block->computeBlockNumber() << " for ";
   bool shouldSkipRegions = flags.shouldSkipRegions();
   printRegion(os, region, flags.skipRegions());
   if (!shouldSkipRegions)
diff --git a/mlir/lib/IR/Verifier.cpp b/mlir/lib/IR/Verifier.cpp
index 3ced663a87be1..e19537a901d18 100644
--- a/mlir/lib/IR/Verifier.cpp
+++ b/mlir/lib/IR/Verifier.cpp
@@ -364,7 +364,7 @@ static void diagnoseInvalidOperandDominance(Operation &op, unsigned operandNo) {
   }
   if (block1 == block2)
     llvm::report_fatal_error("Internal error in dominance verification");
-  int index = std::distance(region2->begin(), block2->getIterator());
+  unsigned index = block2->computeBlockNumber();
   note << "operand defined as a block argument (block #" << index;
   if (region1 == region2)
     note << " in the same region)";
diff --git a/mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp b/mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp
index 248f885505819..05ab4fb4f07cd 100644
--- a/mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp
+++ b/mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp
@@ -172,11 +172,6 @@ static std::optional<StringRef> getTextFromRange(SMRange range) {
   return StringRef(startPtr, range.End.getPointer() - startPtr);
 }
 
-/// Given a block, return its position in its parent region.
-static unsigned getBlockNumber(Block *block) {
-  return std::distance(block->getParent()->begin(), block->getIterator());
-}
-
 /// Given a block and source location, print the source name of the block to the
 /// given output stream.
 static void printDefBlockName(raw_ostream &os, Block *block, SMRange loc = {}) {
@@ -188,7 +183,7 @@ static void printDefBlockName(raw_ostream &os, Block *block, SMRange loc = {}) {
   }
 
   // Otherwise, we don't have a name so print the block number.
-  os << "<Block #" << getBlockNumber(block) << ">";
+  os << "<Block #" << block->computeBlockNumber() << ">";
 }
 static void printDefBlockName(raw_ostream &os,
                               const AsmParserState::BlockDefinition &def) {
@@ -622,7 +617,7 @@ MLIRDocument::buildHoverForBlock(SMRange hoverRange,
 
   // Display the parent operation, block number, predecessors, and successors.
   os << "Operation: \"" << block.block->getParentOp()->getName() << "\"\n\n"
-     << "Block #" << getBlockNumber(block.block) << "\n\n";
+     << "Block #" << block.block->computeBlockNumber() << "\n\n";
   if (!block.block->hasNoPredecessors()) {
     os << "Predecessors: ";
     llvm::interleaveComma(block.block->getPredecessors(), os,
diff --git a/mlir/lib/Transforms/RemoveDeadValues.cpp b/mlir/lib/Transforms/RemoveDeadValues.cpp
index 10942923ba1e1..04658b31c2466 100644
--- a/mlir/lib/Transforms/RemoveDeadValues.cpp
+++ b/mlir/lib/Transforms/RemoveDeadValues.cpp
@@ -795,7 +795,7 @@ static void cleanUpDeadVals(RDVFinalCleanupList &list) {
     LDBG_OS([&](raw_ostream &os) {
       os << "Erasing non-live arguments [";
       llvm::interleaveComma(b.nonLiveArgs.set_bits(), os);
-      os << "] from block: " << b.b << " in region "
+      os << "] from block #" << b.b->computeBlockNumber() << " in region #"
          << b.b->getParent()->getRegionNumber() << " of operation "
          << OpWithFlags(b.b->getParent()->getParentOp(),
                         OpPrintingFlags().skipRegions().printGenericOpForm());
diff --git a/mlir/test/lib/Analysis/TestAliasAnalysis.cpp b/mlir/test/lib/Analysis/TestAliasAnalysis.cpp
index 65e3490953d6e..0125e403272a8 100644
--- a/mlir/test/lib/Analysis/TestAliasAnalysis.cpp
+++ b/mlir/test/lib/Analysis/TestAliasAnalysis.cpp
@@ -26,8 +26,7 @@ static void printAliasOperand(Operation *op) {
 static void printAliasOperand(Value value) {
   if (BlockArgument arg = dyn_cast<BlockArgument>(value)) {
     Region *region = arg.getParentRegion();
-    unsigned parentBlockNumber =
-        std::distance(region->begin(), arg.getOwner()->getIterator());
+    unsigned parentBlockNumber = arg.getOwner()->computeBlockNumber();
     llvm::errs() << region->getParentOp()
                         ->getAttrOfType<StringAttr>("test.ptr")
                         .getValue()



More information about the Mlir-commits mailing list