MLIR 22.0.0git
NestedMatcher.cpp
Go to the documentation of this file.
1//===- NestedMatcher.cpp - NestedMatcher Impl ----------------------------===//
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 <utility>
10
13
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/Support/Allocator.h"
16
17using namespace mlir;
18using namespace mlir::affine;
19
20llvm::BumpPtrAllocator *&NestedMatch::allocator() {
21 thread_local llvm::BumpPtrAllocator *allocator = nullptr;
22 return allocator;
23}
24
26 ArrayRef<NestedMatch> nestedMatches) {
27 auto *result = allocator()->Allocate<NestedMatch>();
28 auto *children = allocator()->Allocate<NestedMatch>(nestedMatches.size());
29 llvm::uninitialized_copy(nestedMatches, children);
30 new (result) NestedMatch();
31 result->matchedOperation = operation;
32 result->matchedChildren =
33 ArrayRef<NestedMatch>(children, nestedMatches.size());
34 return *result;
35}
36
37llvm::BumpPtrAllocator *&NestedPattern::allocator() {
38 thread_local llvm::BumpPtrAllocator *allocator = nullptr;
39 return allocator;
40}
41
42void NestedPattern::copyNestedToThis(ArrayRef<NestedPattern> nested) {
43 if (nested.empty())
44 return;
45
46 auto *newNested = allocator()->Allocate<NestedPattern>(nested.size());
47 llvm::uninitialized_copy(nested, newNested);
48 nestedPatterns = ArrayRef<NestedPattern>(newNested, nested.size());
49}
50
51void NestedPattern::freeNested() {
52 for (const auto &p : nestedPatterns)
53 p.~NestedPattern();
54}
55
57 FilterFunctionType filter)
58 : filter(std::move(filter)), skip(nullptr) {
59 copyNestedToThis(nested);
60}
61
63 : filter(other.filter), skip(other.skip) {
64 copyNestedToThis(other.nestedPatterns);
65}
66
68 freeNested();
69 filter = other.filter;
70 skip = other.skip;
71 copyNestedToThis(other.nestedPatterns);
72 return *this;
73}
74
75unsigned NestedPattern::getDepth() const {
76 if (nestedPatterns.empty()) {
77 return 1;
78 }
79 unsigned depth = 0;
80 for (auto &c : nestedPatterns) {
81 depth = std::max(depth, c.getDepth());
82 }
83 return depth + 1;
84}
85
86/// Matches a single operation in the following way:
87/// 1. checks the kind of operation against the matcher, if different then
88/// there is no match;
89/// 2. calls the customizable filter function to refine the single operation
90/// match with extra semantic constraints;
91/// 3. if all is good, recursively matches the nested patterns;
92/// 4. if all nested match then the single operation matches too and is
93/// appended to the list of matches;
94/// 5. TODO: Optionally applies actions (lambda), in which case we will want
95/// to traverse in post-order DFS to avoid invalidating iterators.
96void NestedPattern::matchOne(Operation *op,
98 if (skip == op) {
99 return;
100 }
101 // Local custom filter function
102 if (!filter(*op)) {
103 return;
104 }
105
106 if (nestedPatterns.empty()) {
107 SmallVector<NestedMatch, 8> nestedMatches;
108 matches->push_back(NestedMatch::build(op, nestedMatches));
109 return;
110 }
111 // Take a copy of each nested pattern so we can match it.
112 for (auto nestedPattern : nestedPatterns) {
113 SmallVector<NestedMatch, 8> nestedMatches;
114 // Skip elem in the walk immediately following. Without this we would
115 // essentially need to reimplement walk here.
116 nestedPattern.skip = op;
117 nestedPattern.match(op, &nestedMatches);
118 // If we could not match even one of the specified nestedPattern, early exit
119 // as this whole branch is not a match.
120 if (nestedMatches.empty()) {
121 return;
122 }
123 matches->push_back(NestedMatch::build(op, nestedMatches));
124 }
125}
126
127static bool isAffineForOp(Operation &op) { return isa<AffineForOp>(op); }
128
129static bool isAffineIfOp(Operation &op) { return isa<AffineIfOp>(op); }
130
131namespace mlir {
132namespace affine {
133namespace matcher {
134
136 return NestedPattern({}, std::move(filter));
137}
138
140 return NestedPattern(child, isAffineIfOp);
141}
142NestedPattern If(const FilterFunctionType &filter, const NestedPattern &child) {
143 return NestedPattern(child, [filter](Operation &op) {
144 return isAffineIfOp(op) && filter(op);
145 });
146}
152 return NestedPattern(nested, [filter](Operation &op) {
153 return isAffineIfOp(op) && filter(op);
154 });
155}
156
158 return NestedPattern(child, isAffineForOp);
159}
161 const NestedPattern &child) {
162 return NestedPattern(
163 child, [=](Operation &op) { return isAffineForOp(op) && filter(op); });
164}
170 return NestedPattern(
171 nested, [=](Operation &op) { return isAffineForOp(op) && filter(op); });
172}
173
175 return isa<AffineLoadOp, AffineStoreOp>(op);
176}
177
178} // namespace matcher
179} // namespace affine
180} // namespace mlir
static bool isAffineForOp(Operation &op)
static bool isAffineIfOp(Operation &op)
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
NestedMatch(const NestedMatch &)=default
static NestedMatch build(Operation *operation, ArrayRef< NestedMatch > nestedMatches)
unsigned getDepth() const
Returns the depth of the pattern.
NestedPattern & operator=(const NestedPattern &other)
NestedPattern(ArrayRef< NestedPattern > nested, FilterFunctionType filter=defaultFilterFunction)
NestedPattern If(const NestedPattern &child)
NestedPattern For(const NestedPattern &child)
bool isLoadOrStore(Operation &op)
NestedPattern Op(FilterFunctionType filter=defaultFilterFunction)
std::function< bool(Operation &)> FilterFunctionType
A NestedPattern is a nested operation walker that:
Include the generated interface declarations.