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