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