1 //===- PatternMatch.cpp - Base classes for pattern match ------------------===// 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 #include "mlir/IR/PatternMatch.h" 10 #include "mlir/IR/BlockAndValueMapping.h" 11 #include "mlir/IR/Operation.h" 12 #include "mlir/IR/Value.h" 13 14 using namespace mlir; 15 16 PatternBenefit::PatternBenefit(unsigned benefit) : representation(benefit) { 17 assert(representation == benefit && benefit != ImpossibleToMatchSentinel && 18 "This pattern match benefit is too large to represent"); 19 } 20 21 unsigned short PatternBenefit::getBenefit() const { 22 assert(!isImpossibleToMatch() && "Pattern doesn't match"); 23 return representation; 24 } 25 26 //===----------------------------------------------------------------------===// 27 // Pattern implementation 28 //===----------------------------------------------------------------------===// 29 30 Pattern::Pattern(StringRef rootName, PatternBenefit benefit, 31 MLIRContext *context) 32 : rootKind(OperationName(rootName, context)), benefit(benefit) {} 33 Pattern::Pattern(PatternBenefit benefit, MatchAnyOpTypeTag) 34 : benefit(benefit) {} 35 36 // Out-of-line vtable anchor. 37 void Pattern::anchor() {} 38 39 //===----------------------------------------------------------------------===// 40 // RewritePattern and PatternRewriter implementation 41 //===----------------------------------------------------------------------===// 42 43 void RewritePattern::rewrite(Operation *op, PatternRewriter &rewriter) const { 44 llvm_unreachable("need to implement either matchAndRewrite or one of the " 45 "rewrite functions!"); 46 } 47 48 LogicalResult RewritePattern::match(Operation *op) const { 49 llvm_unreachable("need to implement either match or matchAndRewrite!"); 50 } 51 52 RewritePattern::RewritePattern(StringRef rootName, 53 ArrayRef<StringRef> generatedNames, 54 PatternBenefit benefit, MLIRContext *context) 55 : Pattern(rootName, benefit, context) { 56 generatedOps.reserve(generatedNames.size()); 57 std::transform(generatedNames.begin(), generatedNames.end(), 58 std::back_inserter(generatedOps), [context](StringRef name) { 59 return OperationName(name, context); 60 }); 61 } 62 RewritePattern::RewritePattern(ArrayRef<StringRef> generatedNames, 63 PatternBenefit benefit, MLIRContext *context, 64 MatchAnyOpTypeTag tag) 65 : Pattern(benefit, tag) { 66 generatedOps.reserve(generatedNames.size()); 67 std::transform(generatedNames.begin(), generatedNames.end(), 68 std::back_inserter(generatedOps), [context](StringRef name) { 69 return OperationName(name, context); 70 }); 71 } 72 73 PatternRewriter::~PatternRewriter() { 74 // Out of line to provide a vtable anchor for the class. 75 } 76 77 /// This method performs the final replacement for a pattern, where the 78 /// results of the operation are updated to use the specified list of SSA 79 /// values. 80 void PatternRewriter::replaceOp(Operation *op, ValueRange newValues) { 81 // Notify the rewriter subclass that we're about to replace this root. 82 notifyRootReplaced(op); 83 84 assert(op->getNumResults() == newValues.size() && 85 "incorrect # of replacement values"); 86 op->replaceAllUsesWith(newValues); 87 88 notifyOperationRemoved(op); 89 op->erase(); 90 } 91 92 /// This method erases an operation that is known to have no uses. The uses of 93 /// the given operation *must* be known to be dead. 94 void PatternRewriter::eraseOp(Operation *op) { 95 assert(op->use_empty() && "expected 'op' to have no uses"); 96 notifyOperationRemoved(op); 97 op->erase(); 98 } 99 100 void PatternRewriter::eraseBlock(Block *block) { 101 for (auto &op : llvm::make_early_inc_range(llvm::reverse(*block))) { 102 assert(op.use_empty() && "expected 'op' to have no uses"); 103 eraseOp(&op); 104 } 105 block->erase(); 106 } 107 108 /// Merge the operations of block 'source' into the end of block 'dest'. 109 /// 'source's predecessors must be empty or only contain 'dest`. 110 /// 'argValues' is used to replace the block arguments of 'source' after 111 /// merging. 112 void PatternRewriter::mergeBlocks(Block *source, Block *dest, 113 ValueRange argValues) { 114 assert(llvm::all_of(source->getPredecessors(), 115 [dest](Block *succ) { return succ == dest; }) && 116 "expected 'source' to have no predecessors or only 'dest'"); 117 assert(argValues.size() == source->getNumArguments() && 118 "incorrect # of argument replacement values"); 119 120 // Replace all of the successor arguments with the provided values. 121 for (auto it : llvm::zip(source->getArguments(), argValues)) 122 std::get<0>(it).replaceAllUsesWith(std::get<1>(it)); 123 124 // Splice the operations of the 'source' block into the 'dest' block and erase 125 // it. 126 dest->getOperations().splice(dest->end(), source->getOperations()); 127 source->dropAllUses(); 128 source->erase(); 129 } 130 131 // Merge the operations of block 'source' before the operation 'op'. Source 132 // block should not have existing predecessors or successors. 133 void PatternRewriter::mergeBlockBefore(Block *source, Operation *op, 134 ValueRange argValues) { 135 assert(source->hasNoPredecessors() && 136 "expected 'source' to have no predecessors"); 137 assert(source->hasNoSuccessors() && 138 "expected 'source' to have no successors"); 139 140 // Split the block containing 'op' into two, one containg all operations 141 // before 'op' (prologue) and another (epilogue) containing 'op' and all 142 // operations after it. 143 Block *prologue = op->getBlock(); 144 Block *epilogue = splitBlock(prologue, op->getIterator()); 145 146 // Merge the source block at the end of the prologue. 147 mergeBlocks(source, prologue, argValues); 148 149 // Merge the epilogue at the end the prologue. 150 mergeBlocks(epilogue, prologue); 151 } 152 153 /// Split the operations starting at "before" (inclusive) out of the given 154 /// block into a new block, and return it. 155 Block *PatternRewriter::splitBlock(Block *block, Block::iterator before) { 156 return block->splitBlock(before); 157 } 158 159 /// 'op' and 'newOp' are known to have the same number of results, replace the 160 /// uses of op with uses of newOp 161 void PatternRewriter::replaceOpWithResultsOfAnotherOp(Operation *op, 162 Operation *newOp) { 163 assert(op->getNumResults() == newOp->getNumResults() && 164 "replacement op doesn't match results of original op"); 165 if (op->getNumResults() == 1) 166 return replaceOp(op, newOp->getResult(0)); 167 return replaceOp(op, newOp->getResults()); 168 } 169 170 /// Move the blocks that belong to "region" before the given position in 171 /// another region. The two regions must be different. The caller is in 172 /// charge to update create the operation transferring the control flow to the 173 /// region and pass it the correct block arguments. 174 void PatternRewriter::inlineRegionBefore(Region ®ion, Region &parent, 175 Region::iterator before) { 176 parent.getBlocks().splice(before, region.getBlocks()); 177 } 178 void PatternRewriter::inlineRegionBefore(Region ®ion, Block *before) { 179 inlineRegionBefore(region, *before->getParent(), before->getIterator()); 180 } 181 182 /// Clone the blocks that belong to "region" before the given position in 183 /// another region "parent". The two regions must be different. The caller is 184 /// responsible for creating or updating the operation transferring flow of 185 /// control to the region and passing it the correct block arguments. 186 void PatternRewriter::cloneRegionBefore(Region ®ion, Region &parent, 187 Region::iterator before, 188 BlockAndValueMapping &mapping) { 189 region.cloneInto(&parent, before, mapping); 190 } 191 void PatternRewriter::cloneRegionBefore(Region ®ion, Region &parent, 192 Region::iterator before) { 193 BlockAndValueMapping mapping; 194 cloneRegionBefore(region, parent, before, mapping); 195 } 196 void PatternRewriter::cloneRegionBefore(Region ®ion, Block *before) { 197 cloneRegionBefore(region, *before->getParent(), before->getIterator()); 198 } 199 200 //===----------------------------------------------------------------------===// 201 // PatternMatcher implementation 202 //===----------------------------------------------------------------------===// 203 204 void PatternApplicator::applyCostModel(CostModel model) { 205 // Separate patterns by root kind to simplify lookup later on. 206 patterns.clear(); 207 anyOpPatterns.clear(); 208 for (const auto &pat : owningPatternList) { 209 // If the pattern is always impossible to match, just ignore it. 210 if (pat->getBenefit().isImpossibleToMatch()) 211 continue; 212 if (Optional<OperationName> opName = pat->getRootKind()) 213 patterns[*opName].push_back(pat.get()); 214 else 215 anyOpPatterns.push_back(pat.get()); 216 } 217 218 // Sort the patterns using the provided cost model. 219 llvm::SmallDenseMap<RewritePattern *, PatternBenefit> benefits; 220 auto cmp = [&benefits](RewritePattern *lhs, RewritePattern *rhs) { 221 return benefits[lhs] > benefits[rhs]; 222 }; 223 auto processPatternList = [&](SmallVectorImpl<RewritePattern *> &list) { 224 // Special case for one pattern in the list, which is the most common case. 225 if (list.size() == 1) { 226 if (model(*list.front()).isImpossibleToMatch()) 227 list.clear(); 228 return; 229 } 230 231 // Collect the dynamic benefits for the current pattern list. 232 benefits.clear(); 233 for (RewritePattern *pat : list) 234 benefits.try_emplace(pat, model(*pat)); 235 236 // Sort patterns with highest benefit first, and remove those that are 237 // impossible to match. 238 std::stable_sort(list.begin(), list.end(), cmp); 239 while (!list.empty() && benefits[list.back()].isImpossibleToMatch()) 240 list.pop_back(); 241 }; 242 for (auto &it : patterns) 243 processPatternList(it.second); 244 processPatternList(anyOpPatterns); 245 } 246 247 void PatternApplicator::walkAllPatterns( 248 function_ref<void(const RewritePattern &)> walk) { 249 for (auto &it : owningPatternList) 250 walk(*it); 251 } 252 253 LogicalResult PatternApplicator::matchAndRewrite( 254 Operation *op, PatternRewriter &rewriter, 255 function_ref<bool(const RewritePattern &)> canApply, 256 function_ref<void(const RewritePattern &)> onFailure, 257 function_ref<LogicalResult(const RewritePattern &)> onSuccess) { 258 // Check to see if there are patterns matching this specific operation type. 259 MutableArrayRef<RewritePattern *> opPatterns; 260 auto patternIt = patterns.find(op->getName()); 261 if (patternIt != patterns.end()) 262 opPatterns = patternIt->second; 263 264 // Process the patterns for that match the specific operation type, and any 265 // operation type in an interleaved fashion. 266 // FIXME: It'd be nice to just write an llvm::make_merge_range utility 267 // and pass in a comparison function. That would make this code trivial. 268 auto opIt = opPatterns.begin(), opE = opPatterns.end(); 269 auto anyIt = anyOpPatterns.begin(), anyE = anyOpPatterns.end(); 270 while (opIt != opE && anyIt != anyE) { 271 // Try to match the pattern providing the most benefit. 272 RewritePattern *pattern; 273 if ((*opIt)->getBenefit() >= (*anyIt)->getBenefit()) 274 pattern = *(opIt++); 275 else 276 pattern = *(anyIt++); 277 278 // Otherwise, try to match the generic pattern. 279 if (succeeded(matchAndRewrite(op, *pattern, rewriter, canApply, onFailure, 280 onSuccess))) 281 return success(); 282 } 283 // If we break from the loop, then only one of the ranges can still have 284 // elements. Loop over both without checking given that we don't need to 285 // interleave anymore. 286 for (RewritePattern *pattern : llvm::concat<RewritePattern *>( 287 llvm::make_range(opIt, opE), llvm::make_range(anyIt, anyE))) { 288 if (succeeded(matchAndRewrite(op, *pattern, rewriter, canApply, onFailure, 289 onSuccess))) 290 return success(); 291 } 292 return failure(); 293 } 294 295 LogicalResult PatternApplicator::matchAndRewrite( 296 Operation *op, const RewritePattern &pattern, PatternRewriter &rewriter, 297 function_ref<bool(const RewritePattern &)> canApply, 298 function_ref<void(const RewritePattern &)> onFailure, 299 function_ref<LogicalResult(const RewritePattern &)> onSuccess) { 300 // Check that the pattern can be applied. 301 if (canApply && !canApply(pattern)) 302 return failure(); 303 304 // Try to match and rewrite this pattern. The patterns are sorted by 305 // benefit, so if we match we can immediately rewrite. 306 rewriter.setInsertionPoint(op); 307 if (succeeded(pattern.matchAndRewrite(op, rewriter))) 308 return success(!onSuccess || succeeded(onSuccess(pattern))); 309 310 if (onFailure) 311 onFailure(pattern); 312 return failure(); 313 } 314