1 //===- Dominance.cpp - Dominator analysis for CFGs ------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implementation of dominance related classes and instantiations of extern
10 // templates.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "mlir/IR/Dominance.h"
15 #include "mlir/IR/Operation.h"
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/Support/GenericDomTreeConstruction.h"
18 
19 using namespace mlir;
20 using namespace mlir::detail;
21 
22 template class llvm::DominatorTreeBase<Block, /*IsPostDom=*/false>;
23 template class llvm::DominatorTreeBase<Block, /*IsPostDom=*/true>;
24 template class llvm::DomTreeNodeBase<Block>;
25 
26 //===----------------------------------------------------------------------===//
27 // DominanceInfoBase
28 //===----------------------------------------------------------------------===//
29 
30 template <bool IsPostDom>
31 void DominanceInfoBase<IsPostDom>::recalculate(Operation *op) {
32   dominanceInfos.clear();
33 
34   /// Build the dominance for each of the operation regions.
35   op->walk([&](Operation *op) {
36     for (auto &region : op->getRegions()) {
37       // Don't compute dominance if the region is empty.
38       if (region.empty())
39         continue;
40       auto opDominance = std::make_unique<base>();
41       opDominance->recalculate(region);
42       dominanceInfos.try_emplace(&region, std::move(opDominance));
43     }
44   });
45 }
46 
47 /// Walks up the list of containers of the given block and calls the
48 /// user-defined traversal function for every pair of a region and block that
49 /// could be found during traversal. If the user-defined function returns true
50 /// for a given pair, traverseAncestors will return the current block. Nullptr
51 /// otherwise.
52 template <typename FuncT>
53 Block *traverseAncestors(Block *block, const FuncT &func) {
54   // Invoke the user-defined traversal function in the beginning for the current
55   // block.
56   if (func(block))
57     return block;
58 
59   Region *region = block->getParent();
60   while (region) {
61     Operation *ancestor = region->getParentOp();
62     // If we have reached to top... return.
63     if (!ancestor || !(block = ancestor->getBlock()))
64       break;
65 
66     // Update the nested region using the new ancestor block.
67     region = block->getParent();
68 
69     // Invoke the user-defined traversal function and check whether we can
70     // already return.
71     if (func(block))
72       return block;
73   }
74   return nullptr;
75 }
76 
77 /// Tries to update the given block references to live in the same region by
78 /// exploring the relationship of both blocks with respect to their regions.
79 static bool tryGetBlocksInSameRegion(Block *&a, Block *&b) {
80   // If both block do not live in the same region, we will have to check their
81   // parent operations.
82   if (a->getParent() == b->getParent())
83     return true;
84 
85   // Iterate over all ancestors of a and insert them into the map. This allows
86   // for efficient lookups to find a commonly shared region.
87   llvm::SmallDenseMap<Region *, Block *, 4> ancestors;
88   traverseAncestors(a, [&](Block *block) {
89     ancestors[block->getParent()] = block;
90     return false;
91   });
92 
93   // Try to find a common ancestor starting with regionB.
94   b = traverseAncestors(
95       b, [&](Block *block) { return ancestors.count(block->getParent()) > 0; });
96 
97   // If there is no match, we will not be able to find a common dominator since
98   // both regions do not share a common parent region.
99   if (!b)
100     return false;
101 
102   // We have found a common parent region. Update block a to refer to this
103   // region.
104   auto it = ancestors.find(b->getParent());
105   assert(it != ancestors.end());
106   a = it->second;
107   return true;
108 }
109 
110 template <bool IsPostDom>
111 Block *
112 DominanceInfoBase<IsPostDom>::findNearestCommonDominator(Block *a,
113                                                          Block *b) const {
114   // If either a or b are null, then conservatively return nullptr.
115   if (!a || !b)
116     return nullptr;
117 
118   // Try to find blocks that are in the same region.
119   if (!tryGetBlocksInSameRegion(a, b))
120     return nullptr;
121 
122   // Get and verify dominance information of the common parent region.
123   Region *parentRegion = a->getParent();
124   auto infoAIt = dominanceInfos.find(parentRegion);
125   if (infoAIt == dominanceInfos.end())
126     return nullptr;
127 
128   // Since the blocks live in the same region, we can rely on already
129   // existing dominance functionality.
130   return infoAIt->second->findNearestCommonDominator(a, b);
131 }
132 
133 template <bool IsPostDom>
134 DominanceInfoNode *DominanceInfoBase<IsPostDom>::getNode(Block *a) {
135   auto *region = a->getParent();
136   assert(dominanceInfos.count(region) != 0);
137   return dominanceInfos[region]->getNode(a);
138 }
139 
140 /// Return true if the specified block A properly dominates block B.
141 template <bool IsPostDom>
142 bool DominanceInfoBase<IsPostDom>::properlyDominates(Block *a, Block *b) const {
143   // A block dominates itself but does not properly dominate itself.
144   if (a == b)
145     return false;
146 
147   // If either a or b are null, then conservatively return false.
148   if (!a || !b)
149     return false;
150 
151   // If both blocks are not in the same region, 'a' properly dominates 'b' if
152   // 'b' is defined in an operation region that (recursively) ends up being
153   // dominated by 'a'. Walk up the list of containers enclosing B.
154   auto *regionA = a->getParent();
155   if (regionA != b->getParent()) {
156     b = traverseAncestors(
157         b, [&](Block *block) { return block->getParent() == regionA; });
158 
159     // If we could not find a valid block b then it is either a not a dominator
160     // or a post dominator.
161     if (!b)
162       return IsPostDom;
163 
164     // Check to see if the ancestor of 'b' is the same block as 'a'.
165     if (a == b)
166       return true;
167   }
168 
169   // Otherwise, use the standard dominance functionality.
170 
171   // If we don't have a dominance information for this region, assume that b is
172   // dominated by anything.
173   auto baseInfoIt = dominanceInfos.find(regionA);
174   if (baseInfoIt == dominanceInfos.end())
175     return true;
176   return baseInfoIt->second->properlyDominates(a, b);
177 }
178 
179 /// Return true if the specified block is reachable from the entry block of its
180 /// region.
181 template <bool IsPostDom>
182 bool DominanceInfoBase<IsPostDom>::isReachableFromEntry(Block *a) const {
183   auto *regionA = a->getParent();
184   auto baseInfoIt = dominanceInfos.find(regionA);
185   if (baseInfoIt == dominanceInfos.end())
186     return true;
187   return baseInfoIt->second->isReachableFromEntry(a);
188 }
189 
190 template class mlir::detail::DominanceInfoBase</*IsPostDom=*/true>;
191 template class mlir::detail::DominanceInfoBase</*IsPostDom=*/false>;
192 
193 //===----------------------------------------------------------------------===//
194 // DominanceInfo
195 //===----------------------------------------------------------------------===//
196 
197 /// Return true if operation A properly dominates operation B.
198 bool DominanceInfo::properlyDominates(Operation *a, Operation *b) const {
199   auto *aBlock = a->getBlock(), *bBlock = b->getBlock();
200 
201   // If a or b are not within a block, then a does not dominate b.
202   if (!aBlock || !bBlock)
203     return false;
204 
205   // If the blocks are the same, then check if b is before a in the block.
206   if (aBlock == bBlock)
207     return a->isBeforeInBlock(b);
208 
209   // Traverse up b's hierarchy to check if b's block is contained in a's.
210   if (auto *bAncestor = aBlock->findAncestorOpInBlock(*b)) {
211     // Since we already know that aBlock != bBlock, here bAncestor != b.
212     // a and bAncestor are in the same block; check if 'a' dominates
213     // bAncestor.
214     return dominates(a, bAncestor);
215   }
216 
217   // If the blocks are different, check if a's block dominates b's.
218   return properlyDominates(aBlock, bBlock);
219 }
220 
221 /// Return true if value A properly dominates operation B.
222 bool DominanceInfo::properlyDominates(Value a, Operation *b) const {
223   if (auto *aOp = a.getDefiningOp()) {
224     // The values defined by an operation do *not* dominate any nested
225     // operations.
226     if (aOp->getParentRegion() != b->getParentRegion() && aOp->isAncestor(b))
227       return false;
228     return properlyDominates(aOp, b);
229   }
230 
231   // block arguments properly dominate all operations in their own block, so
232   // we use a dominates check here, not a properlyDominates check.
233   return dominates(a.cast<BlockArgument>().getOwner(), b->getBlock());
234 }
235 
236 void DominanceInfo::updateDFSNumbers() {
237   for (auto &iter : dominanceInfos)
238     iter.second->updateDFSNumbers();
239 }
240 
241 //===----------------------------------------------------------------------===//
242 // PostDominanceInfo
243 //===----------------------------------------------------------------------===//
244 
245 /// Returns true if statement 'a' properly postdominates statement b.
246 bool PostDominanceInfo::properlyPostDominates(Operation *a, Operation *b) {
247   auto *aBlock = a->getBlock(), *bBlock = b->getBlock();
248 
249   // If a or b are not within a block, then a does not post dominate b.
250   if (!aBlock || !bBlock)
251     return false;
252 
253   // If the blocks are the same, check if b is before a in the block.
254   if (aBlock == bBlock)
255     return b->isBeforeInBlock(a);
256 
257   // Traverse up b's hierarchy to check if b's block is contained in a's.
258   if (auto *bAncestor = a->getBlock()->findAncestorOpInBlock(*b))
259     // Since we already know that aBlock != bBlock, here bAncestor != b.
260     // a and bAncestor are in the same block; check if 'a' postdominates
261     // bAncestor.
262     return postDominates(a, bAncestor);
263 
264   // If the blocks are different, check if a's block post dominates b's.
265   return properlyDominates(aBlock, bBlock);
266 }
267