[Mlir-commits] [mlir] 697bd97 - Give each mlir::Block a stable ID within its parent region (#207617)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Jul 8 19:34:53 PDT 2026
Author: Fangrui Song
Date: 2026-07-08T19:34:48-07:00
New Revision: 697bd9704894691d6b0f40b3150d70047a6f181f
URL: https://github.com/llvm/llvm-project/commit/697bd9704894691d6b0f40b3150d70047a6f181f
DIFF: https://github.com/llvm/llvm-project/commit/697bd9704894691d6b0f40b3150d70047a6f181f.diff
LOG: Give each mlir::Block a stable ID within its parent region (#207617)
Assign each mlir::Block a stable ID within its parent region, mirroring
llvm::BasicBlock/llvm::Function (called ID, not number, since a block/op
number denotes position in MLIR): Block gains getBlockID() and reads -1u
while it has no parent region; Region gains nextBlockID with
getMaxBlockID() and getBlockIDEpoch(); the block ilist traits assign the
ID on add/transfer and invalidate it on removal; and
GraphTraits<mlir::Block*>/<mlir::Region*> expose
getNumber/getMaxNumber/getNumberEpoch. This makes
GraphHasNodeNumbers<mlir::Block*> true, moving MLIR's CFGLoopInfo and
dominator tree onto the number-indexed path. MLIR never renumbers
blocks,
so the epoch is a fixed 0.
Prerequisite for requiring GraphHasNodeNumbers in llvm::LoopInfoBase and
dropping its DenseMap fallback.
Aided by Claude Opus 4.8
Added:
Modified:
mlir/include/mlir/IR/Block.h
mlir/include/mlir/IR/Region.h
mlir/include/mlir/IR/RegionGraphTraits.h
mlir/lib/IR/Region.cpp
Removed:
################################################################################
diff --git a/mlir/include/mlir/IR/Block.h b/mlir/include/mlir/IR/Block.h
index bb3484af2aaf7..c84921db220af 100644
--- a/mlir/include/mlir/IR/Block.h
+++ b/mlir/include/mlir/IR/Block.h
@@ -52,6 +52,20 @@ class alignas(8) Block : public IRObjectWithUseList<BlockOperand>,
/// model.
Region *getParent() const;
+ /// Return an ID uniquely identifying this block within its parent region.
+ /// The ID is assigned when the block joins a region and reassigned when the
+ /// block is moved to a
diff erent region; it is stable while the block stays
+ /// in a region, and removing a block leaves a hole (IDs are not reused). Only
+ /// valid for a block that is in a region.
+ ///
+ /// Unlike computeBlockNumber(), this is O(1) and stable; it exists so that
+ /// generic graph algorithms (e.g. LoopInfo, DominatorTree) can index blocks
+ /// by ID.
+ unsigned getBlockID() const {
+ assert(getParent() && "only blocks in a region have a valid ID");
+ return blockID;
+ }
+
/// Returns the closest surrounding operation that contains this block.
Operation *getParentOp();
@@ -422,6 +436,10 @@ class alignas(8) Block : public IRObjectWithUseList<BlockOperand>,
/// the operations within this block have a valid ordering.
llvm::PointerIntPair<Region *, /*IntBits=*/1, bool> parentValidOpOrderPair;
+ /// Unique ID of this block within its parent region, (re)assigned when the
+ /// block joins a region; -1u while the block has no parent. See getBlockID().
+ unsigned blockID = -1u;
+
/// This is the list of operations in the block.
OpListType operations;
@@ -432,6 +450,7 @@ class alignas(8) Block : public IRObjectWithUseList<BlockOperand>,
void operator=(Block &) = delete;
friend struct llvm::ilist_traits<Block>;
+ friend class Region;
};
raw_ostream &operator<<(raw_ostream &, Block &);
diff --git a/mlir/include/mlir/IR/Region.h b/mlir/include/mlir/IR/Region.h
index 13b54991832cb..fa9d8f08d84bb 100644
--- a/mlir/include/mlir/IR/Region.h
+++ b/mlir/include/mlir/IR/Region.h
@@ -72,6 +72,19 @@ class Region {
return &Region::blocks;
}
+ //===--------------------------------------------------------------------===//
+ // Block numbering
+ //===--------------------------------------------------------------------===//
+
+ /// One past the largest block ID handed out in this region; block IDs lie in
+ /// [0, getMaxBlockID()). See Block::getBlockID().
+ unsigned getMaxBlockID() const { return nextBlockID; }
+
+ /// The block-ID epoch, part of the generic number-indexed graph contract
+ /// (LoopInfo, DominatorTree) for detecting stale IDs. MLIR never renumbers a
+ /// region's blocks, so this is a fixed 0. See Block::getBlockID().
+ unsigned getBlockIDEpoch() const { return 0; }
+
//===--------------------------------------------------------------------===//
// Argument Handling
//===--------------------------------------------------------------------===//
@@ -343,6 +356,11 @@ class Region {
/// This is the object we are part of.
Operation *container = nullptr;
+
+ /// Next block ID to hand out. See Block::getBlockID().
+ unsigned nextBlockID = 0;
+
+ friend struct llvm::ilist_traits<Block>;
};
/// This class provides an abstraction over the
diff erent types of ranges over
diff --git a/mlir/include/mlir/IR/RegionGraphTraits.h b/mlir/include/mlir/IR/RegionGraphTraits.h
index d7d80d9b35806..bf21d9720169c 100644
--- a/mlir/include/mlir/IR/RegionGraphTraits.h
+++ b/mlir/include/mlir/IR/RegionGraphTraits.h
@@ -31,6 +31,8 @@ struct GraphTraits<mlir::Block *> {
return node->succ_begin();
}
static ChildIteratorType child_end(NodeRef node) { return node->succ_end(); }
+
+ static unsigned getNumber(NodeRef node) { return node->getBlockID(); }
};
template <>
@@ -63,6 +65,8 @@ struct GraphTraits<const mlir::Block *> {
static ChildIteratorType child_end(NodeRef node) {
return const_cast<mlir::Block *>(node)->succ_end();
}
+
+ static unsigned getNumber(NodeRef node) { return node->getBlockID(); }
};
template <>
@@ -97,6 +101,13 @@ struct GraphTraits<mlir::Region *> : public GraphTraits<mlir::Block *> {
static nodes_iterator nodes_end(GraphType fn) {
return nodes_iterator(fn->end());
}
+
+ static unsigned getMaxNumber(GraphType region) {
+ return region->getMaxBlockID();
+ }
+ static unsigned getNumberEpoch(GraphType region) {
+ return region->getBlockIDEpoch();
+ }
};
template <>
diff --git a/mlir/lib/IR/Region.cpp b/mlir/lib/IR/Region.cpp
index 15a941f380225..775485a3755e0 100644
--- a/mlir/lib/IR/Region.cpp
+++ b/mlir/lib/IR/Region.cpp
@@ -194,7 +194,9 @@ Region *llvm::ilist_traits<::mlir::Block>::getParentRegion() {
/// We keep the region pointer up to date.
void llvm::ilist_traits<::mlir::Block>::addNodeToList(Block *block) {
assert(!block->getParent() && "already in a region!");
- block->parentValidOpOrderPair.setPointer(getParentRegion());
+ Region *region = getParentRegion();
+ block->parentValidOpOrderPair.setPointer(region);
+ block->blockID = region->nextBlockID++;
}
/// This is a trait method invoked when an operation is removed from a
@@ -202,6 +204,8 @@ void llvm::ilist_traits<::mlir::Block>::addNodeToList(Block *block) {
void llvm::ilist_traits<::mlir::Block>::removeNodeFromList(Block *block) {
assert(block->getParent() && "not already in a region!");
block->parentValidOpOrderPair.setPointer(nullptr);
+ // The ID is invalid until the block is added to a region again.
+ block->blockID = -1u;
}
/// This is a trait method invoked when an operation is moved from one block
@@ -214,9 +218,12 @@ void llvm::ilist_traits<::mlir::Block>::transferNodesFromList(
if (curParent == otherList.getParentRegion())
return;
- // Update the 'parent' member of each Block.
- for (; first != last; ++first)
+ // Update the 'parent' member of each Block and give it an ID in its new
+ // region.
+ for (; first != last; ++first) {
first->parentValidOpOrderPair.setPointer(curParent);
+ first->blockID = curParent->nextBlockID++;
+ }
}
//===----------------------------------------------------------------------===//
More information about the Mlir-commits
mailing list