[Mlir-commits] [mlir] [mlir][IR] Add `OpBuilder::setInsertionPointAfterValues` (PR #114940)
Matthias Springer
llvmlistbot at llvm.org
Sun Nov 10 18:50:59 PST 2024
https://github.com/matthias-springer updated https://github.com/llvm/llvm-project/pull/114940
>From 8bc07a5ef3409b412e046fe1aef5cbcea9d262e7 Mon Sep 17 00:00:00 2001
From: Matthias Springer <mspringer at nvidia.com>
Date: Fri, 8 Nov 2024 07:52:27 +0100
Subject: [PATCH 1/4] [mlir][IR][NFC] `DominanceInfo`: Minor code cleanups
---
mlir/include/mlir/IR/Dominance.h | 11 +----------
mlir/lib/IR/Dominance.cpp | 8 ++++----
2 files changed, 5 insertions(+), 14 deletions(-)
diff --git a/mlir/include/mlir/IR/Dominance.h b/mlir/include/mlir/IR/Dominance.h
index 66b9456533ae04..2947bdc21dfebf 100644
--- a/mlir/include/mlir/IR/Dominance.h
+++ b/mlir/include/mlir/IR/Dominance.h
@@ -147,9 +147,7 @@ class DominanceInfo : public detail::DominanceInfoBase</*IsPostDom=*/false> {
/// The `enclosingOpOk` flag says whether we should return true if the B op
/// is enclosed by a region on A.
bool properlyDominates(Operation *a, Operation *b,
- bool enclosingOpOk = true) const {
- return properlyDominatesImpl(a, b, enclosingOpOk);
- }
+ bool enclosingOpOk = true) const;
/// Return true if operation A dominates operation B, i.e. if A and B are the
/// same operation or A properly dominates B.
@@ -187,13 +185,6 @@ class DominanceInfo : public detail::DominanceInfoBase</*IsPostDom=*/false> {
bool properlyDominates(Block *a, Block *b) const {
return super::properlyDominates(a, b);
}
-
-private:
- // Return true if operation A properly dominates operation B. The
- /// 'enclosingOpOk' flag says whether we should return true if the b op is
- /// enclosed by a region on 'A'.
- bool properlyDominatesImpl(Operation *a, Operation *b,
- bool enclosingOpOk) const;
};
/// A class for computing basic postdominance information.
diff --git a/mlir/lib/IR/Dominance.cpp b/mlir/lib/IR/Dominance.cpp
index 62477a823acaaf..c9b8ee69c24570 100644
--- a/mlir/lib/IR/Dominance.cpp
+++ b/mlir/lib/IR/Dominance.cpp
@@ -230,7 +230,7 @@ bool DominanceInfoBase<IsPostDom>::properlyDominates(Block *a, Block *b) const {
if (regionA != b->getParent()) {
b = regionA ? regionA->findAncestorBlockInRegion(*b) : nullptr;
// If we could not find a valid block b then it is a not a dominator.
- if (b == nullptr)
+ if (!b)
return false;
// Check to see if the ancestor of `b` is the same block as `a`. A properly
@@ -266,8 +266,8 @@ template class detail::DominanceInfoBase</*IsPostDom=*/false>;
/// Return true if operation `a` properly dominates operation `b`. The
/// 'enclosingOpOk' flag says whether we should return true if the `b` op is
/// enclosed by a region on 'a'.
-bool DominanceInfo::properlyDominatesImpl(Operation *a, Operation *b,
- bool enclosingOpOk) const {
+bool DominanceInfo::properlyDominates(Operation *a, Operation *b,
+ bool enclosingOpOk) const {
Block *aBlock = a->getBlock(), *bBlock = b->getBlock();
assert(aBlock && bBlock && "operations must be in a block");
@@ -319,7 +319,7 @@ bool DominanceInfo::properlyDominates(Value a, Operation *b) const {
// `a` properlyDominates `b` if the operation defining `a` properlyDominates
// `b`, but `a` does not itself enclose `b` in one of its regions.
- return properlyDominatesImpl(a.getDefiningOp(), b, /*enclosingOpOk=*/false);
+ return properlyDominates(a.getDefiningOp(), b, /*enclosingOpOk=*/false);
}
//===----------------------------------------------------------------------===//
>From 213a01bb92eeab460fd82d881f53e96768e161ca Mon Sep 17 00:00:00 2001
From: Matthias Springer <mspringer at nvidia.com>
Date: Fri, 8 Nov 2024 08:12:08 +0100
Subject: [PATCH 2/4] [mlir][IR] `DominanceInfo`: Deduplicate
`properlyDominates` implementation
The implementations of `DominanceInfo::properlyDominates` and `PostDominanceInfo::properlyPostDominates` are almost identical: only one line of code is different. Define the function in `DominanceInfoBase` to avoid the code duplication.
Note: This commit is not marked as NFC because `PostDominanceInfo::properlyPostDominates` now also has an `enclosingOpOk` argument.
---
mlir/include/mlir/IR/Dominance.h | 21 ++++--
mlir/lib/IR/Dominance.cpp | 111 +++++++++----------------------
2 files changed, 48 insertions(+), 84 deletions(-)
diff --git a/mlir/include/mlir/IR/Dominance.h b/mlir/include/mlir/IR/Dominance.h
index 2947bdc21dfebf..16d17b9c0f3d01 100644
--- a/mlir/include/mlir/IR/Dominance.h
+++ b/mlir/include/mlir/IR/Dominance.h
@@ -113,8 +113,12 @@ class DominanceInfoBase {
llvm::PointerIntPair<DomTree *, 1, bool>
getDominanceInfo(Region *region, bool needsDomTree) const;
- /// Return true if the specified block A properly dominates block B.
- bool properlyDominates(Block *a, Block *b) const;
+ /// Return "true" if the specified block A properly (post)dominates block B.
+ bool properlyDominatesImpl(Block *a, Block *b) const;
+
+ /// Return "true" if the specified op A properly (post)dominates op B.
+ bool properlyDominatesImpl(Operation *a, Operation *b,
+ bool enclosingOpOk = true) const;
/// A mapping of regions to their base dominator tree and a cached
/// "hasSSADominance" bit. This map does not contain dominator trees for
@@ -147,7 +151,9 @@ class DominanceInfo : public detail::DominanceInfoBase</*IsPostDom=*/false> {
/// The `enclosingOpOk` flag says whether we should return true if the B op
/// is enclosed by a region on A.
bool properlyDominates(Operation *a, Operation *b,
- bool enclosingOpOk = true) const;
+ bool enclosingOpOk = true) const {
+ return super::properlyDominatesImpl(a, b, enclosingOpOk);
+ }
/// Return true if operation A dominates operation B, i.e. if A and B are the
/// same operation or A properly dominates B.
@@ -183,7 +189,7 @@ class DominanceInfo : public detail::DominanceInfoBase</*IsPostDom=*/false> {
/// dominance" of ops, the single block is considered to properly dominate
/// itself in a graph region.
bool properlyDominates(Block *a, Block *b) const {
- return super::properlyDominates(a, b);
+ return super::properlyDominatesImpl(a, b);
}
};
@@ -193,7 +199,10 @@ class PostDominanceInfo : public detail::DominanceInfoBase</*IsPostDom=*/true> {
using super::super;
/// Return true if operation A properly postdominates operation B.
- bool properlyPostDominates(Operation *a, Operation *b) const;
+ bool properlyPostDominates(Operation *a, Operation *b,
+ bool enclosingOpOk = true) const {
+ return super::properlyDominatesImpl(a, b, enclosingOpOk);
+ }
/// Return true if operation A postdominates operation B.
bool postDominates(Operation *a, Operation *b) const {
@@ -202,7 +211,7 @@ class PostDominanceInfo : public detail::DominanceInfoBase</*IsPostDom=*/true> {
/// Return true if the specified block A properly postdominates block B.
bool properlyPostDominates(Block *a, Block *b) const {
- return super::properlyDominates(a, b);
+ return super::properlyDominatesImpl(a, b);
}
/// Return true if the specified block A postdominates block B.
diff --git a/mlir/lib/IR/Dominance.cpp b/mlir/lib/IR/Dominance.cpp
index c9b8ee69c24570..406e0f2d62d640 100644
--- a/mlir/lib/IR/Dominance.cpp
+++ b/mlir/lib/IR/Dominance.cpp
@@ -215,7 +215,8 @@ DominanceInfoBase<IsPostDom>::findNearestCommonDominator(Block *a,
/// Return true if the specified block A properly dominates block B.
template <bool IsPostDom>
-bool DominanceInfoBase<IsPostDom>::properlyDominates(Block *a, Block *b) const {
+bool DominanceInfoBase<IsPostDom>::properlyDominatesImpl(Block *a,
+ Block *b) const {
assert(a && b && "null blocks not allowed");
// A block dominates, but does not properly dominate, itself unless this
@@ -243,36 +244,14 @@ bool DominanceInfoBase<IsPostDom>::properlyDominates(Block *a, Block *b) const {
return getDomTree(regionA).properlyDominates(a, b);
}
-/// Return true if the specified block is reachable from the entry block of
-/// its region.
template <bool IsPostDom>
-bool DominanceInfoBase<IsPostDom>::isReachableFromEntry(Block *a) const {
- // If this is the first block in its region, then it is obviously reachable.
- Region *region = a->getParent();
- if (®ion->front() == a)
- return true;
-
- // Otherwise this is some block in a multi-block region. Check DomTree.
- return getDomTree(region).isReachableFromEntry(a);
-}
-
-template class detail::DominanceInfoBase</*IsPostDom=*/true>;
-template class detail::DominanceInfoBase</*IsPostDom=*/false>;
-
-//===----------------------------------------------------------------------===//
-// DominanceInfo
-//===----------------------------------------------------------------------===//
-
-/// Return true if operation `a` properly dominates operation `b`. The
-/// 'enclosingOpOk' flag says whether we should return true if the `b` op is
-/// enclosed by a region on 'a'.
-bool DominanceInfo::properlyDominates(Operation *a, Operation *b,
- bool enclosingOpOk) const {
+bool DominanceInfoBase<IsPostDom>::properlyDominatesImpl(
+ Operation *a, Operation *b, bool enclosingOpOk) const {
Block *aBlock = a->getBlock(), *bBlock = b->getBlock();
assert(aBlock && bBlock && "operations must be in a block");
- // An operation dominates, but does not properly dominate, itself unless this
- // is a graph region.
+ // An operation (pos)dominates, but does not properly (pos)dominate, itself
+ // unless this is a graph region.
if (a == b)
return !hasSSADominance(aBlock);
@@ -280,14 +259,14 @@ bool DominanceInfo::properlyDominates(Operation *a, Operation *b,
Region *aRegion = aBlock->getParent();
if (aRegion != bBlock->getParent()) {
// Scoot up b's region tree until we find an operation in A's region that
- // encloses it. If this fails, then we know there is no post-dom relation.
+ // encloses it. If this fails, then we know there is no (post)dom relation.
b = aRegion ? aRegion->findAncestorOpInRegion(*b) : nullptr;
if (!b)
return false;
bBlock = b->getBlock();
assert(bBlock->getParent() == aRegion);
- // If 'a' encloses 'b', then we consider it to dominate.
+ // If 'a' encloses 'b', then we consider it to (post)dominate.
if (a == b && enclosingOpOk)
return true;
}
@@ -297,17 +276,39 @@ bool DominanceInfo::properlyDominates(Operation *a, Operation *b,
// Dominance changes based on the region type. In a region with SSA
// dominance, uses inside the same block must follow defs. In other
// regions kinds, uses and defs can come in any order inside a block.
- if (hasSSADominance(aBlock)) {
- // If the blocks are the same, then check if b is before a in the block.
+ if (!hasSSADominance(aBlock))
+ return true;
+ if constexpr (IsPostDom) {
+ return b->isBeforeInBlock(a);
+ } else {
return a->isBeforeInBlock(b);
}
- return true;
}
// If the blocks are different, use DomTree to resolve the query.
return getDomTree(aRegion).properlyDominates(aBlock, bBlock);
}
+/// Return true if the specified block is reachable from the entry block of
+/// its region.
+template <bool IsPostDom>
+bool DominanceInfoBase<IsPostDom>::isReachableFromEntry(Block *a) const {
+ // If this is the first block in its region, then it is obviously reachable.
+ Region *region = a->getParent();
+ if (®ion->front() == a)
+ return true;
+
+ // Otherwise this is some block in a multi-block region. Check DomTree.
+ return getDomTree(region).isReachableFromEntry(a);
+}
+
+template class detail::DominanceInfoBase</*IsPostDom=*/true>;
+template class detail::DominanceInfoBase</*IsPostDom=*/false>;
+
+//===----------------------------------------------------------------------===//
+// DominanceInfo
+//===----------------------------------------------------------------------===//
+
/// Return true if the `a` value properly dominates operation `b`, i.e if the
/// operation that defines `a` properlyDominates `b` and the operation that
/// defines `a` does not contain `b`.
@@ -321,49 +322,3 @@ bool DominanceInfo::properlyDominates(Value a, Operation *b) const {
// `b`, but `a` does not itself enclose `b` in one of its regions.
return properlyDominates(a.getDefiningOp(), b, /*enclosingOpOk=*/false);
}
-
-//===----------------------------------------------------------------------===//
-// PostDominanceInfo
-//===----------------------------------------------------------------------===//
-
-/// Returns true if statement 'a' properly postdominates statement b.
-bool PostDominanceInfo::properlyPostDominates(Operation *a,
- Operation *b) const {
- auto *aBlock = a->getBlock(), *bBlock = b->getBlock();
- assert(aBlock && bBlock && "operations must be in a block");
-
- // An instruction postDominates, but does not properlyPostDominate, itself
- // unless this is a graph region.
- if (a == b)
- return !hasSSADominance(aBlock);
-
- // If these ops are in different regions, then normalize one into the other.
- Region *aRegion = aBlock->getParent();
- if (aRegion != bBlock->getParent()) {
- // Scoot up b's region tree until we find an operation in A's region that
- // encloses it. If this fails, then we know there is no post-dom relation.
- b = aRegion ? aRegion->findAncestorOpInRegion(*b) : nullptr;
- if (!b)
- return false;
- bBlock = b->getBlock();
- assert(bBlock->getParent() == aRegion);
-
- // If 'a' encloses 'b', then we consider it to postdominate.
- if (a == b)
- return true;
- }
-
- // Ok, they are in the same region. If they are in the same block, check if b
- // is before a in the block.
- if (aBlock == bBlock) {
- // Dominance changes based on the region type.
- if (hasSSADominance(aBlock)) {
- // If the blocks are the same, then check if b is before a in the block.
- return b->isBeforeInBlock(a);
- }
- return true;
- }
-
- // If the blocks are different, check if a's block post dominates b's.
- return getDomTree(aRegion).properlyDominates(aBlock, bBlock);
-}
>From 57bd3919c4976f01fb0b6a15928545744e25d0cb Mon Sep 17 00:00:00 2001
From: Matthias Springer <mspringer at nvidia.com>
Date: Sat, 9 Nov 2024 07:13:07 +0100
Subject: [PATCH 3/4] [mlir][IR][NFC] `DominanceInfo`: Share same impl for
block/op dominance
The `properlyDominates` implementations for blocks and ops are very similar. This commit replaces them with a single implementation that operates on block iterators. That implementation can be used to implement both `properlyDominates` variants.
Note: A subsequent commit will add a new public `properlyDominates` overload that accepts block iterators. That functionality can then be used to find a valid insertion point at which a range of values is defined (by utilizing post dominance).
Depends on #115433.
---
mlir/include/mlir/IR/Dominance.h | 28 +++----
mlir/lib/IR/Dominance.cpp | 124 ++++++++++++++++++++-----------
2 files changed, 92 insertions(+), 60 deletions(-)
diff --git a/mlir/include/mlir/IR/Dominance.h b/mlir/include/mlir/IR/Dominance.h
index 16d17b9c0f3d01..63504cad211a4d 100644
--- a/mlir/include/mlir/IR/Dominance.h
+++ b/mlir/include/mlir/IR/Dominance.h
@@ -113,12 +113,12 @@ class DominanceInfoBase {
llvm::PointerIntPair<DomTree *, 1, bool>
getDominanceInfo(Region *region, bool needsDomTree) const;
- /// Return "true" if the specified block A properly (post)dominates block B.
- bool properlyDominatesImpl(Block *a, Block *b) const;
-
- /// Return "true" if the specified op A properly (post)dominates op B.
- bool properlyDominatesImpl(Operation *a, Operation *b,
- bool enclosingOpOk = true) const;
+ /// Return "true" if block iterator A properly (post)dominates block iterator
+ /// B. If `enclosingOk` is set, A is considered to (post)dominate B if A
+ /// encloses B.
+ bool properlyDominatesImpl(Block *aBlock, Block::iterator aIt, Block *bBlock,
+ Block::iterator bIt,
+ bool enclosingOk = true) const;
/// A mapping of regions to their base dominator tree and a cached
/// "hasSSADominance" bit. This map does not contain dominator trees for
@@ -151,9 +151,7 @@ class DominanceInfo : public detail::DominanceInfoBase</*IsPostDom=*/false> {
/// The `enclosingOpOk` flag says whether we should return true if the B op
/// is enclosed by a region on A.
bool properlyDominates(Operation *a, Operation *b,
- bool enclosingOpOk = true) const {
- return super::properlyDominatesImpl(a, b, enclosingOpOk);
- }
+ bool enclosingOpOk = true) const;
/// Return true if operation A dominates operation B, i.e. if A and B are the
/// same operation or A properly dominates B.
@@ -188,9 +186,7 @@ class DominanceInfo : public detail::DominanceInfoBase</*IsPostDom=*/false> {
/// Graph regions have only a single block. To be consistent with "proper
/// dominance" of ops, the single block is considered to properly dominate
/// itself in a graph region.
- bool properlyDominates(Block *a, Block *b) const {
- return super::properlyDominatesImpl(a, b);
- }
+ bool properlyDominates(Block *a, Block *b) const;
};
/// A class for computing basic postdominance information.
@@ -200,9 +196,7 @@ class PostDominanceInfo : public detail::DominanceInfoBase</*IsPostDom=*/true> {
/// Return true if operation A properly postdominates operation B.
bool properlyPostDominates(Operation *a, Operation *b,
- bool enclosingOpOk = true) const {
- return super::properlyDominatesImpl(a, b, enclosingOpOk);
- }
+ bool enclosingOpOk = true) const;
/// Return true if operation A postdominates operation B.
bool postDominates(Operation *a, Operation *b) const {
@@ -210,9 +204,7 @@ class PostDominanceInfo : public detail::DominanceInfoBase</*IsPostDom=*/true> {
}
/// Return true if the specified block A properly postdominates block B.
- bool properlyPostDominates(Block *a, Block *b) const {
- return super::properlyDominatesImpl(a, b);
- }
+ bool properlyPostDominates(Block *a, Block *b) const;
/// Return true if the specified block A postdominates block B.
bool postDominates(Block *a, Block *b) const {
diff --git a/mlir/lib/IR/Dominance.cpp b/mlir/lib/IR/Dominance.cpp
index 406e0f2d62d640..1c54e09d29b9b5 100644
--- a/mlir/lib/IR/Dominance.cpp
+++ b/mlir/lib/IR/Dominance.cpp
@@ -213,61 +213,73 @@ DominanceInfoBase<IsPostDom>::findNearestCommonDominator(Block *a,
return getDomTree(a->getParent()).findNearestCommonDominator(a, b);
}
-/// Return true if the specified block A properly dominates block B.
-template <bool IsPostDom>
-bool DominanceInfoBase<IsPostDom>::properlyDominatesImpl(Block *a,
- Block *b) const {
- assert(a && b && "null blocks not allowed");
+/// Returns the given block iterator if it lies within the region region.
+/// Otherwise, otherwise finds the ancestor of the given block iterator that
+/// lies within the given region. Returns and "empty" iterator if the latter
+/// fails.
+///
+/// Note: This is a variant of Region::findAncestorOpInRegion that operates on
+/// block iterators instead of ops.
+static std::pair<Block *, Block::iterator>
+findAncestorIteratorInRegion(Region *r, Block *b, Block::iterator it) {
+ // Case 1: The iterator lies within the region region.
+ if (b->getParent() == r)
+ return std::make_pair(b, it);
+
+ // Otherwise: Find ancestor iterator. Bail if we run out of parent ops.
+ Operation *parentOp = b->getParentOp();
+ if (!parentOp)
+ return std::make_pair(static_cast<Block *>(nullptr), Block::iterator());
+ Operation *op = r->findAncestorOpInRegion(*parentOp);
+ if (!op)
+ return std::make_pair(static_cast<Block *>(nullptr), Block::iterator());
+ return std::make_pair(op->getBlock(), op->getIterator());
+}
- // A block dominates, but does not properly dominate, itself unless this
- // is a graph region.
+/// Given two iterators into the same block, return "true" if `a` is before `b.
+/// Note: This is a variant of Operation::isBeforeInBlock that operates on
+/// block iterators instead of ops.
+static bool isBeforeInBlock(Block *block, Block::iterator a,
+ Block::iterator b) {
if (a == b)
- return !hasSSADominance(a);
-
- // If both blocks are not in the same region, `a` properly dominates `b` if
- // `b` is defined in an operation region that (recursively) ends up being
- // dominated by `a`. Walk up the list of containers enclosing B.
- Region *regionA = a->getParent();
- if (regionA != b->getParent()) {
- b = regionA ? regionA->findAncestorBlockInRegion(*b) : nullptr;
- // If we could not find a valid block b then it is a not a dominator.
- if (!b)
- return false;
-
- // Check to see if the ancestor of `b` is the same block as `a`. A properly
- // dominates B if it contains an op that contains the B block.
- if (a == b)
- return true;
- }
-
- // Otherwise, they are two different blocks in the same region, use DomTree.
- return getDomTree(regionA).properlyDominates(a, b);
+ return false;
+ if (a == block->end())
+ return false;
+ if (b == block->end())
+ return true;
+ return a->isBeforeInBlock(&*b);
}
template <bool IsPostDom>
bool DominanceInfoBase<IsPostDom>::properlyDominatesImpl(
- Operation *a, Operation *b, bool enclosingOpOk) const {
- Block *aBlock = a->getBlock(), *bBlock = b->getBlock();
- assert(aBlock && bBlock && "operations must be in a block");
+ Block *aBlock, Block::iterator aIt, Block *bBlock, Block::iterator bIt,
+ bool enclosingOk) const {
+ assert(aBlock && bBlock && "expected non-null blocks");
- // An operation (pos)dominates, but does not properly (pos)dominate, itself
- // unless this is a graph region.
- if (a == b)
+ // A block iterator (post)dominates, but does not properly (post)dominate,
+ // itself unless this is a graph region.
+ if (aBlock == bBlock && aIt == bIt)
return !hasSSADominance(aBlock);
- // If these ops are in different regions, then normalize one into the other.
+ // If the iterators are in different regions, then normalize one into the
+ // other.
Region *aRegion = aBlock->getParent();
if (aRegion != bBlock->getParent()) {
- // Scoot up b's region tree until we find an operation in A's region that
+ // Scoot up b's region tree until we find a location in A's region that
// encloses it. If this fails, then we know there is no (post)dom relation.
- b = aRegion ? aRegion->findAncestorOpInRegion(*b) : nullptr;
- if (!b)
+ if (!aRegion) {
+ bBlock = nullptr;
+ bIt = Block::iterator();
+ } else {
+ std::tie(bBlock, bIt) =
+ findAncestorIteratorInRegion(aRegion, bBlock, bIt);
+ }
+ if (!bBlock)
return false;
- bBlock = b->getBlock();
- assert(bBlock->getParent() == aRegion);
+ assert(bBlock->getParent() == aRegion && "expected block in regionA");
// If 'a' encloses 'b', then we consider it to (post)dominate.
- if (a == b && enclosingOpOk)
+ if (aBlock == bBlock && aIt == bIt && enclosingOk)
return true;
}
@@ -279,9 +291,9 @@ bool DominanceInfoBase<IsPostDom>::properlyDominatesImpl(
if (!hasSSADominance(aBlock))
return true;
if constexpr (IsPostDom) {
- return b->isBeforeInBlock(a);
+ return isBeforeInBlock(aBlock, bIt, aIt);
} else {
- return a->isBeforeInBlock(b);
+ return isBeforeInBlock(aBlock, aIt, bIt);
}
}
@@ -309,6 +321,18 @@ template class detail::DominanceInfoBase</*IsPostDom=*/false>;
// DominanceInfo
//===----------------------------------------------------------------------===//
+bool DominanceInfo::properlyDominates(Operation *a, Operation *b,
+ bool enclosingOpOk) const {
+ return super::properlyDominatesImpl(a->getBlock(), a->getIterator(),
+ b->getBlock(), b->getIterator(),
+ enclosingOpOk);
+}
+
+bool DominanceInfo::properlyDominates(Block *a, Block *b) const {
+ return super::properlyDominatesImpl(a, a->begin(), b, b->begin(),
+ /*enclosingOk=*/true);
+}
+
/// Return true if the `a` value properly dominates operation `b`, i.e if the
/// operation that defines `a` properlyDominates `b` and the operation that
/// defines `a` does not contain `b`.
@@ -322,3 +346,19 @@ bool DominanceInfo::properlyDominates(Value a, Operation *b) const {
// `b`, but `a` does not itself enclose `b` in one of its regions.
return properlyDominates(a.getDefiningOp(), b, /*enclosingOpOk=*/false);
}
+
+//===----------------------------------------------------------------------===//
+// PostDominanceInfo
+//===----------------------------------------------------------------------===//
+
+bool PostDominanceInfo::properlyPostDominates(Operation *a, Operation *b,
+ bool enclosingOpOk) const {
+ return super::properlyDominatesImpl(a->getBlock(), a->getIterator(),
+ b->getBlock(), b->getIterator(),
+ enclosingOpOk);
+}
+
+bool PostDominanceInfo::properlyPostDominates(Block *a, Block *b) const {
+ return super::properlyDominatesImpl(a, a->end(), b, b->end(),
+ /*enclosingOk=*/true);
+}
>From df995200947a6f01661aaa8196b7edc2236ac3bd Mon Sep 17 00:00:00 2001
From: Matthias Springer <mspringer at nvidia.com>
Date: Sat, 9 Nov 2024 12:29:16 +0100
Subject: [PATCH 4/4] [mlir][IR] Add `OpBuilder::setInsertionPointAfterValues`
---
mlir/include/mlir/IR/Builders.h | 14 +++++++++++
mlir/include/mlir/IR/Dominance.h | 23 +++++++++++++++++
mlir/lib/IR/Builders.cpp | 42 ++++++++++++++++++++++++++++++++
3 files changed, 79 insertions(+)
diff --git a/mlir/include/mlir/IR/Builders.h b/mlir/include/mlir/IR/Builders.h
index 6fb71ccefda151..bd3642f9f413dc 100644
--- a/mlir/include/mlir/IR/Builders.h
+++ b/mlir/include/mlir/IR/Builders.h
@@ -16,6 +16,7 @@
namespace mlir {
class AffineExpr;
+class PostDominanceInfo;
class IRMapping;
class UnknownLoc;
class FileLineColLoc;
@@ -435,6 +436,19 @@ class OpBuilder : public Builder {
}
}
+ /// Sets the insertion point to a place that post-dominates the definitions
+ /// of all given values. Returns "failure" and leaves the current insertion
+ /// point unchanged if no such insertion point exists.
+ ///
+ /// There may be multiple suitable insertion points. This function chooses an
+ /// insertion right after one of the given values.
+ ///
+ /// Note: Some of the given values may already have gone out of scope at the
+ /// selected insertion point. (E.g., because they are defined in a nested
+ /// region.)
+ LogicalResult setInsertionPointAfterValues(ArrayRef<Value> values,
+ const PostDominanceInfo &domInfo);
+
/// Sets the insertion point to the start of the specified block.
void setInsertionPointToStart(Block *block) {
setInsertionPoint(block, block->begin());
diff --git a/mlir/include/mlir/IR/Dominance.h b/mlir/include/mlir/IR/Dominance.h
index 63504cad211a4d..be2dcec380b6cc 100644
--- a/mlir/include/mlir/IR/Dominance.h
+++ b/mlir/include/mlir/IR/Dominance.h
@@ -187,6 +187,17 @@ class DominanceInfo : public detail::DominanceInfoBase</*IsPostDom=*/false> {
/// dominance" of ops, the single block is considered to properly dominate
/// itself in a graph region.
bool properlyDominates(Block *a, Block *b) const;
+
+ bool properlyDominantes(Block *aBlock, Block::iterator aIt, Block *bBlock,
+ Block::iterator bIt, bool enclosingOk = true) const {
+ return super::properlyDominatesImpl(aBlock, aIt, bBlock, bIt, enclosingOk);
+ }
+
+ bool dominantes(Block *aBlock, Block::iterator aIt, Block *bBlock,
+ Block::iterator bIt, bool enclosingOk = true) const {
+ return (aBlock == bBlock && aIt == bIt) ||
+ super::properlyDominatesImpl(aBlock, aIt, bBlock, bIt, enclosingOk);
+ }
};
/// A class for computing basic postdominance information.
@@ -210,6 +221,18 @@ class PostDominanceInfo : public detail::DominanceInfoBase</*IsPostDom=*/true> {
bool postDominates(Block *a, Block *b) const {
return a == b || properlyPostDominates(a, b);
}
+
+ bool properlyPostDominantes(Block *aBlock, Block::iterator aIt, Block *bBlock,
+ Block::iterator bIt,
+ bool enclosingOk = true) const {
+ return super::properlyDominatesImpl(aBlock, aIt, bBlock, bIt, enclosingOk);
+ }
+
+ bool postDominantes(Block *aBlock, Block::iterator aIt, Block *bBlock,
+ Block::iterator bIt, bool enclosingOk = true) const {
+ return (aBlock == bBlock && aIt == bIt) ||
+ super::properlyDominatesImpl(aBlock, aIt, bBlock, bIt, enclosingOk);
+ }
};
} // namespace mlir
diff --git a/mlir/lib/IR/Builders.cpp b/mlir/lib/IR/Builders.cpp
index 5397fbabc5c95e..0f4b5123326502 100644
--- a/mlir/lib/IR/Builders.cpp
+++ b/mlir/lib/IR/Builders.cpp
@@ -11,6 +11,7 @@
#include "mlir/IR/AffineMap.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
+#include "mlir/IR/Dominance.h"
#include "mlir/IR/IRMapping.h"
#include "mlir/IR/IntegerSet.h"
#include "mlir/IR/Matchers.h"
@@ -641,3 +642,44 @@ void OpBuilder::cloneRegionBefore(Region ®ion, Region &parent,
void OpBuilder::cloneRegionBefore(Region ®ion, Block *before) {
cloneRegionBefore(region, *before->getParent(), before->getIterator());
}
+
+LogicalResult
+OpBuilder::setInsertionPointAfterValues(ArrayRef<Value> values,
+ const PostDominanceInfo &domInfo) {
+ // Helper function that computes the point after v's definition.
+ auto computeAfterIp = [](Value v) -> std::pair<Block *, Block::iterator> {
+ if (auto blockArg = dyn_cast<BlockArgument>(v))
+ return std::make_pair(blockArg.getOwner(), blockArg.getOwner()->begin());
+ Operation *op = v.getDefiningOp();
+ return std::make_pair(op->getBlock(), op->getIterator());
+ };
+
+ // Compute the insertion point after the first value is defined.
+ assert(!values.empty() && "expected at least one Value");
+ auto [block, blockIt] = computeAfterIp(values.front());
+
+ // Check the other values one-by-one and update the insertion point if
+ // needed.
+ for (Value v : values.drop_front()) {
+ auto [candidateBlock, candidateBlockIt] = computeAfterIp(v);
+ if (domInfo.postDominantes(candidateBlock, candidateBlockIt, block,
+ blockIt)) {
+ // The point after v's definition post-dominates the current (and all
+ // previous) insertion points. Note: Post-dominance is transitive.
+ block = candidateBlock;
+ blockIt = candidateBlockIt;
+ continue;
+ }
+
+ if (!domInfo.postDominantes(block, blockIt, candidateBlock,
+ candidateBlockIt)) {
+ // The point after v's definition and the current insertion point do not
+ // post-dominate each other. Therefore, there is no insertion point that
+ // post-dominates all values.
+ return failure();
+ }
+ }
+
+ setInsertionPoint(block, blockIt);
+ return success();
+}
More information about the Mlir-commits
mailing list