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 ®ion : 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(®ion, 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