github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/mlir/lib/Analysis/NestedMatcher.cpp (about) 1 //===- NestedMatcher.cpp - NestedMatcher Impl ----------------------------===// 2 // 3 // Copyright 2019 The MLIR Authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // ============================================================================= 17 18 #include "mlir/Analysis/NestedMatcher.h" 19 #include "mlir/Dialect/AffineOps/AffineOps.h" 20 #include "mlir/Dialect/StandardOps/Ops.h" 21 22 #include "llvm/ADT/ArrayRef.h" 23 #include "llvm/ADT/STLExtras.h" 24 #include "llvm/Support/Allocator.h" 25 #include "llvm/Support/raw_ostream.h" 26 27 using namespace mlir; 28 29 llvm::BumpPtrAllocator *&NestedMatch::allocator() { 30 thread_local llvm::BumpPtrAllocator *allocator = nullptr; 31 return allocator; 32 } 33 34 NestedMatch NestedMatch::build(Operation *operation, 35 ArrayRef<NestedMatch> nestedMatches) { 36 auto *result = allocator()->Allocate<NestedMatch>(); 37 auto *children = allocator()->Allocate<NestedMatch>(nestedMatches.size()); 38 std::uninitialized_copy(nestedMatches.begin(), nestedMatches.end(), children); 39 new (result) NestedMatch(); 40 result->matchedOperation = operation; 41 result->matchedChildren = 42 ArrayRef<NestedMatch>(children, nestedMatches.size()); 43 return *result; 44 } 45 46 llvm::BumpPtrAllocator *&NestedPattern::allocator() { 47 thread_local llvm::BumpPtrAllocator *allocator = nullptr; 48 return allocator; 49 } 50 51 NestedPattern::NestedPattern(ArrayRef<NestedPattern> nested, 52 FilterFunctionType filter) 53 : nestedPatterns(), filter(filter), skip(nullptr) { 54 if (!nested.empty()) { 55 auto *newNested = allocator()->Allocate<NestedPattern>(nested.size()); 56 std::uninitialized_copy(nested.begin(), nested.end(), newNested); 57 nestedPatterns = ArrayRef<NestedPattern>(newNested, nested.size()); 58 } 59 } 60 61 unsigned NestedPattern::getDepth() const { 62 if (nestedPatterns.empty()) { 63 return 1; 64 } 65 unsigned depth = 0; 66 for (auto &c : nestedPatterns) { 67 depth = std::max(depth, c.getDepth()); 68 } 69 return depth + 1; 70 } 71 72 /// Matches a single operation in the following way: 73 /// 1. checks the kind of operation against the matcher, if different then 74 /// there is no match; 75 /// 2. calls the customizable filter function to refine the single operation 76 /// match with extra semantic constraints; 77 /// 3. if all is good, recursivey matches the nested patterns; 78 /// 4. if all nested match then the single operation matches too and is 79 /// appended to the list of matches; 80 /// 5. TODO(ntv) Optionally applies actions (lambda), in which case we will 81 /// want to traverse in post-order DFS to avoid invalidating iterators. 82 void NestedPattern::matchOne(Operation *op, 83 SmallVectorImpl<NestedMatch> *matches) { 84 if (skip == op) { 85 return; 86 } 87 // Local custom filter function 88 if (!filter(*op)) { 89 return; 90 } 91 92 if (nestedPatterns.empty()) { 93 SmallVector<NestedMatch, 8> nestedMatches; 94 matches->push_back(NestedMatch::build(op, nestedMatches)); 95 return; 96 } 97 // Take a copy of each nested pattern so we can match it. 98 for (auto nestedPattern : nestedPatterns) { 99 SmallVector<NestedMatch, 8> nestedMatches; 100 // Skip elem in the walk immediately following. Without this we would 101 // essentially need to reimplement walk here. 102 nestedPattern.skip = op; 103 nestedPattern.match(op, &nestedMatches); 104 // If we could not match even one of the specified nestedPattern, early exit 105 // as this whole branch is not a match. 106 if (nestedMatches.empty()) { 107 return; 108 } 109 matches->push_back(NestedMatch::build(op, nestedMatches)); 110 } 111 } 112 113 static bool isAffineForOp(Operation &op) { return isa<AffineForOp>(op); } 114 115 static bool isAffineIfOp(Operation &op) { return isa<AffineIfOp>(op); } 116 117 namespace mlir { 118 namespace matcher { 119 120 NestedPattern Op(FilterFunctionType filter) { 121 return NestedPattern({}, filter); 122 } 123 124 NestedPattern If(NestedPattern child) { 125 return NestedPattern(child, isAffineIfOp); 126 } 127 NestedPattern If(FilterFunctionType filter, NestedPattern child) { 128 return NestedPattern(child, [filter](Operation &op) { 129 return isAffineIfOp(op) && filter(op); 130 }); 131 } 132 NestedPattern If(ArrayRef<NestedPattern> nested) { 133 return NestedPattern(nested, isAffineIfOp); 134 } 135 NestedPattern If(FilterFunctionType filter, ArrayRef<NestedPattern> nested) { 136 return NestedPattern(nested, [filter](Operation &op) { 137 return isAffineIfOp(op) && filter(op); 138 }); 139 } 140 141 NestedPattern For(NestedPattern child) { 142 return NestedPattern(child, isAffineForOp); 143 } 144 NestedPattern For(FilterFunctionType filter, NestedPattern child) { 145 return NestedPattern( 146 child, [=](Operation &op) { return isAffineForOp(op) && filter(op); }); 147 } 148 NestedPattern For(ArrayRef<NestedPattern> nested) { 149 return NestedPattern(nested, isAffineForOp); 150 } 151 NestedPattern For(FilterFunctionType filter, ArrayRef<NestedPattern> nested) { 152 return NestedPattern( 153 nested, [=](Operation &op) { return isAffineForOp(op) && filter(op); }); 154 } 155 156 bool isLoadOrStore(Operation &op) { 157 return isa<AffineLoadOp>(op) || isa<AffineStoreOp>(op); 158 } 159 160 } // end namespace matcher 161 } // end namespace mlir