• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "mlir/IR/RegionKindInterface.h"
17 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/Support/GenericDomTreeConstruction.h"
19 
20 using namespace mlir;
21 using namespace mlir::detail;
22 
23 template class llvm::DominatorTreeBase<Block, /*IsPostDom=*/false>;
24 template class llvm::DominatorTreeBase<Block, /*IsPostDom=*/true>;
25 template class llvm::DomTreeNodeBase<Block>;
26 
27 /// Return true if the region with the given index inside the operation
28 /// has SSA dominance.
hasSSADominance(Operation * op,unsigned index)29 static bool hasSSADominance(Operation *op, unsigned index) {
30   auto kindInterface = dyn_cast<RegionKindInterface>(op);
31   return op->isRegistered() &&
32          (!kindInterface || kindInterface.hasSSADominance(index));
33 }
34 
35 //===----------------------------------------------------------------------===//
36 // DominanceInfoBase
37 //===----------------------------------------------------------------------===//
38 
39 template <bool IsPostDom>
recalculate(Operation * op)40 void DominanceInfoBase<IsPostDom>::recalculate(Operation *op) {
41   dominanceInfos.clear();
42 
43   // Build the dominance for each of the operation regions.
44   op->walk([&](Operation *op) {
45     auto kindInterface = dyn_cast<RegionKindInterface>(op);
46     unsigned numRegions = op->getNumRegions();
47     for (unsigned i = 0; i < numRegions; i++) {
48       Region &region = op->getRegion(i);
49       // Don't compute dominance if the region is empty.
50       if (region.empty())
51         continue;
52 
53       // Dominance changes based on the region type. Avoid the helper
54       // function here so we don't do the region cast repeatedly.
55       bool hasSSADominance =
56           op->isRegistered() &&
57           (!kindInterface || kindInterface.hasSSADominance(i));
58       // If a region has SSADominance, then compute detailed dominance
59       // info.  Otherwise, all values in the region are live anywhere
60       // in the region, which is represented as an empty entry in the
61       // dominanceInfos map.
62       if (hasSSADominance) {
63         auto opDominance = std::make_unique<base>();
64         opDominance->recalculate(region);
65         dominanceInfos.try_emplace(&region, std::move(opDominance));
66       }
67     }
68   });
69 }
70 
71 /// Walks up the list of containers of the given block and calls the
72 /// user-defined traversal function for every pair of a region and block that
73 /// could be found during traversal. If the user-defined function returns true
74 /// for a given pair, traverseAncestors will return the current block. Nullptr
75 /// otherwise.
76 template <typename FuncT>
traverseAncestors(Block * block,const FuncT & func)77 Block *traverseAncestors(Block *block, const FuncT &func) {
78   // Invoke the user-defined traversal function in the beginning for the current
79   // block.
80   if (func(block))
81     return block;
82 
83   Region *region = block->getParent();
84   while (region) {
85     Operation *ancestor = region->getParentOp();
86     // If we have reached to top... return.
87     if (!ancestor || !(block = ancestor->getBlock()))
88       break;
89 
90     // Update the nested region using the new ancestor block.
91     region = block->getParent();
92 
93     // Invoke the user-defined traversal function and check whether we can
94     // already return.
95     if (func(block))
96       return block;
97   }
98   return nullptr;
99 }
100 
101 /// Tries to update the given block references to live in the same region by
102 /// exploring the relationship of both blocks with respect to their regions.
tryGetBlocksInSameRegion(Block * & a,Block * & b)103 static bool tryGetBlocksInSameRegion(Block *&a, Block *&b) {
104   // If both block do not live in the same region, we will have to check their
105   // parent operations.
106   if (a->getParent() == b->getParent())
107     return true;
108 
109   // Iterate over all ancestors of a and insert them into the map. This allows
110   // for efficient lookups to find a commonly shared region.
111   llvm::SmallDenseMap<Region *, Block *, 4> ancestors;
112   traverseAncestors(a, [&](Block *block) {
113     ancestors[block->getParent()] = block;
114     return false;
115   });
116 
117   // Try to find a common ancestor starting with regionB.
118   b = traverseAncestors(
119       b, [&](Block *block) { return ancestors.count(block->getParent()) > 0; });
120 
121   // If there is no match, we will not be able to find a common dominator since
122   // both regions do not share a common parent region.
123   if (!b)
124     return false;
125 
126   // We have found a common parent region. Update block a to refer to this
127   // region.
128   auto it = ancestors.find(b->getParent());
129   assert(it != ancestors.end());
130   a = it->second;
131   return true;
132 }
133 
134 template <bool IsPostDom>
135 Block *
findNearestCommonDominator(Block * a,Block * b) const136 DominanceInfoBase<IsPostDom>::findNearestCommonDominator(Block *a,
137                                                          Block *b) const {
138   // If either a or b are null, then conservatively return nullptr.
139   if (!a || !b)
140     return nullptr;
141 
142   // Try to find blocks that are in the same region.
143   if (!tryGetBlocksInSameRegion(a, b))
144     return nullptr;
145 
146   // Get and verify dominance information of the common parent region.
147   Region *parentRegion = a->getParent();
148   auto infoAIt = dominanceInfos.find(parentRegion);
149   if (infoAIt == dominanceInfos.end())
150     return nullptr;
151 
152   // Since the blocks live in the same region, we can rely on already
153   // existing dominance functionality.
154   return infoAIt->second->findNearestCommonDominator(a, b);
155 }
156 
157 template <bool IsPostDom>
getNode(Block * a)158 DominanceInfoNode *DominanceInfoBase<IsPostDom>::getNode(Block *a) {
159   Region *region = a->getParent();
160   assert(dominanceInfos.count(region) != 0);
161   return dominanceInfos[region]->getNode(a);
162 }
163 
164 /// Return true if the specified block A properly dominates block B.
165 template <bool IsPostDom>
properlyDominates(Block * a,Block * b) const166 bool DominanceInfoBase<IsPostDom>::properlyDominates(Block *a, Block *b) const {
167   // A block dominates itself but does not properly dominate itself.
168   if (a == b)
169     return false;
170 
171   // If either a or b are null, then conservatively return false.
172   if (!a || !b)
173     return false;
174 
175   // If both blocks are not in the same region, 'a' properly dominates 'b' if
176   // 'b' is defined in an operation region that (recursively) ends up being
177   // dominated by 'a'. Walk up the list of containers enclosing B.
178   Region *regionA = a->getParent();
179   if (regionA != b->getParent()) {
180     b = traverseAncestors(
181         b, [&](Block *block) { return block->getParent() == regionA; });
182 
183     // If we could not find a valid block b then it is a not a dominator.
184     if (!b)
185       return false;
186 
187     // Check to see if the ancestor of 'b' is the same block as 'a'.
188     if (a == b)
189       return true;
190   }
191 
192   // Otherwise, use the standard dominance functionality.
193 
194   // If we don't have a dominance information for this region, assume that b is
195   // dominated by anything.
196   auto baseInfoIt = dominanceInfos.find(regionA);
197   if (baseInfoIt == dominanceInfos.end())
198     return true;
199   return baseInfoIt->second->properlyDominates(a, b);
200 }
201 
202 /// Return true if the specified block is reachable from the entry block of its
203 /// region.
204 template <bool IsPostDom>
isReachableFromEntry(Block * a) const205 bool DominanceInfoBase<IsPostDom>::isReachableFromEntry(Block *a) const {
206   Region *regionA = a->getParent();
207   auto baseInfoIt = dominanceInfos.find(regionA);
208   if (baseInfoIt == dominanceInfos.end())
209     return true;
210   return baseInfoIt->second->isReachableFromEntry(a);
211 }
212 
213 template class detail::DominanceInfoBase</*IsPostDom=*/true>;
214 template class detail::DominanceInfoBase</*IsPostDom=*/false>;
215 
216 //===----------------------------------------------------------------------===//
217 // DominanceInfo
218 //===----------------------------------------------------------------------===//
219 
220 /// Return true if operation A properly dominates operation B.
properlyDominates(Operation * a,Operation * b) const221 bool DominanceInfo::properlyDominates(Operation *a, Operation *b) const {
222   Block *aBlock = a->getBlock(), *bBlock = b->getBlock();
223   Region *aRegion = a->getParentRegion();
224   unsigned aRegionNum = aRegion->getRegionNumber();
225   Operation *ancestor = aRegion->getParentOp();
226 
227   // If a or b are not within a block, then a does not dominate b.
228   if (!aBlock || !bBlock)
229     return false;
230 
231   if (aBlock == bBlock) {
232     // Dominance changes based on the region type. In a region with SSA
233     // dominance, uses inside the same block must follow defs. In other
234     // regions kinds, uses and defs can come in any order inside a block.
235     if (hasSSADominance(ancestor, aRegionNum)) {
236       // If the blocks are the same, then check if b is before a in the block.
237       return a->isBeforeInBlock(b);
238     }
239     return true;
240   }
241 
242   // Traverse up b's hierarchy to check if b's block is contained in a's.
243   if (auto *bAncestor = aBlock->findAncestorOpInBlock(*b)) {
244     // Since we already know that aBlock != bBlock, here bAncestor != b.
245     // a and bAncestor are in the same block; check if 'a' dominates
246     // bAncestor.
247     return dominates(a, bAncestor);
248   }
249 
250   // If the blocks are different, check if a's block dominates b's.
251   return properlyDominates(aBlock, bBlock);
252 }
253 
254 /// Return true if value A properly dominates operation B.
properlyDominates(Value a,Operation * b) const255 bool DominanceInfo::properlyDominates(Value a, Operation *b) const {
256   if (auto *aOp = a.getDefiningOp()) {
257     // Dominance changes based on the region type.
258     auto *aRegion = aOp->getParentRegion();
259     unsigned aRegionNum = aRegion->getRegionNumber();
260     Operation *ancestor = aRegion->getParentOp();
261     // Dominance changes based on the region type. In a region with SSA
262     // dominance, values defined by an operation cannot be used by the
263     // operation. In other regions kinds they can be used the operation.
264     if (hasSSADominance(ancestor, aRegionNum)) {
265       // The values defined by an operation do *not* dominate any nested
266       // operations.
267       if (aOp->getParentRegion() != b->getParentRegion() && aOp->isAncestor(b))
268         return false;
269     }
270     return properlyDominates(aOp, b);
271   }
272 
273   // block arguments properly dominate all operations in their own block, so
274   // we use a dominates check here, not a properlyDominates check.
275   return dominates(a.cast<BlockArgument>().getOwner(), b->getBlock());
276 }
277 
updateDFSNumbers()278 void DominanceInfo::updateDFSNumbers() {
279   for (auto &iter : dominanceInfos)
280     iter.second->updateDFSNumbers();
281 }
282 
283 //===----------------------------------------------------------------------===//
284 // PostDominanceInfo
285 //===----------------------------------------------------------------------===//
286 
287 /// Returns true if statement 'a' properly postdominates statement b.
properlyPostDominates(Operation * a,Operation * b)288 bool PostDominanceInfo::properlyPostDominates(Operation *a, Operation *b) {
289   auto *aBlock = a->getBlock(), *bBlock = b->getBlock();
290   auto *aRegion = a->getParentRegion();
291   unsigned aRegionNum = aRegion->getRegionNumber();
292   Operation *ancestor = aRegion->getParentOp();
293 
294   // If a or b are not within a block, then a does not post dominate b.
295   if (!aBlock || !bBlock)
296     return false;
297 
298   // If the blocks are the same, check if b is before a in the block.
299   if (aBlock == bBlock) {
300     // Dominance changes based on the region type.
301     if (hasSSADominance(ancestor, aRegionNum)) {
302       // If the blocks are the same, then check if b is before a in the block.
303       return b->isBeforeInBlock(a);
304     }
305     return true;
306   }
307 
308   // Traverse up b's hierarchy to check if b's block is contained in a's.
309   if (auto *bAncestor = a->getBlock()->findAncestorOpInBlock(*b))
310     // Since we already know that aBlock != bBlock, here bAncestor != b.
311     // a and bAncestor are in the same block; check if 'a' postdominates
312     // bAncestor.
313     return postDominates(a, bAncestor);
314 
315   // If the blocks are different, check if a's block post dominates b's.
316   return properlyDominates(aBlock, bBlock);
317 }
318