blob: ba28b3e368eaab0cd872264ebc5992630c45326d [file] [log] [blame]
Uday Bondhugulab553adb2018-08-25 17:17:56 -07001//===- HyperRectangularSet.h - MLIR HyperRectangle Class --------*- C++ -*-===//
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// A symbolic hyper-rectangular set of integer points for analysis.
19//
20//===----------------------------------------------------------------------===//
21
22#ifndef MLIR_ANALYSIS_HYPER_RECTANGULAR_SET_H
23#define MLIR_ANALYSIS_HYPER_RECTANGULAR_SET_H
24
25#include <vector>
26
27#include "mlir/Analysis/AffineStructures.h"
28#include "llvm/ADT/ilist.h"
29#include "llvm/ADT/ilist_node.h"
30
31namespace mlir {
32
33class AffineExpr;
34class AffineApplyOp;
35class AffineBound;
36class AffineCondition;
37class AffineMap;
38class IntegerSet;
39class MLIRContext;
40class MLValue;
41class MutableIntegerSet;
42class FlatAffineConstraints;
43class HyperRectangleList;
44
45/// A list of affine bounds.
46// Not using a MutableAffineMap here since numSymbols is the same as the
47// containing HyperRectangularSet's numSymbols, and its numDims is 0.
48typedef SmallVector<AffineExpr *, 4> AffineBoundExprList;
49
50/// A HyperRectangularSet is a symbolic set of integer points contained in a
51/// hyper-rectangular space. It supports set manipulation operations
52/// and other queries to aid analysis of multi-dimensional integer sets that can
53/// be represented as integer points inside a symbolic hyper-rectangle, i.e.,
54/// an interval is associated with each dimension, and the lower and upper
55/// bounds of each interval are symbolic affine expressions. The bounds on
56/// a 'dimension' can't depend on other 'dimensions'. The fields of this set are
57/// always maintained in an irredundant form (no redundant bounds), and the
58/// bounds are simplified under its context field.
59//
60// Example: dims: (d0, d1), symbols: (M, N)
61// 0 <= d0 <= 511
62// max(128,M) <= d1 <= min(N-1,256)
63//
64// Symbols here aren't necessarily associated with MLFunction's symbols; they
65// could also correspond to outer loop IVs for example or anything abstract. The
66// binding to SSA values for dimensions/symbols is optional, and these are in an
67// abstract integer domain. As an example, to describe data accessed in a tile
68// surrounded by loop i0, i1, the following set symbolic in i0, i1 is a
69// hyper-rectangular set:
70//
71// 128*i <= d0 <= min(128*i0 + 127, N-1)
72// 128*i <= d1 <= min(128*i1 + 127, N-1)
73//
74// The context field specifies constraints on the symbols, and the set is always
75// kept in a form simplified under 'context', i.e., information implied by
76// context is used to simplify bounds. For eg., if the context includes (N >=
77// 0), a bound such as d0 >= max(0, N) will never arise. This would be
78// simplified to d0 >= N at construction time or when the context is updated.
79// As another example, if N%128 = 0, M <= N-1 floordiv 128 is specified, we will
80// never have a bound such as d0 <= min(128*M + 127, N-1); this would be
81// simplified to d0 <= 128*M + 127 (since 128*M + 127 is always <= N-1 under
82// such circumstances). In the context of code generation, such simplification
83// leads to code that explicitly scans "full" tiles / no boundary case and with
84// lower control overhead.
85//
86class HyperRectangularSet
87 : public llvm::ilist_node_with_parent<HyperRectangularSet,
88 HyperRectangleList> {
89public:
90 /// Construct a hyper-rectangular set from FlatAffineConstraints if possible;
91 /// returns nullptr if it cannot.
92 static std::unique_ptr<HyperRectangularSet>
93 getFromFlatAffineConstraints(const FlatAffineConstraints &cst);
94
95 HyperRectangularSet(unsigned numDims, unsigned numSymbols,
96 ArrayRef<ArrayRef<AffineExpr *>> lbs,
97 ArrayRef<ArrayRef<AffineExpr *>> ubs,
98 IntegerSet *symbolContext = nullptr);
99
100 unsigned getNumDims() const { return numDims; }
101 unsigned getNumSymbols() const { return numSymbols; }
102
103 ArrayRef<AffineBoundExprList> getLowerBounds() const { return lowerBounds; }
104 ArrayRef<AffineBoundExprList> getUpperBounds() const { return upperBounds; }
105
106 AffineBoundExprList &getLowerBound(unsigned idx) { return lowerBounds[idx]; }
107 AffineBoundExprList &getUpperBound(unsigned idx) { return upperBounds[idx]; }
108
109 const AffineBoundExprList &getLowerBound(unsigned idx) const {
110 return lowerBounds[idx];
111 }
112 const AffineBoundExprList &getUpperBound(unsigned idx) const {
113 return upperBounds[idx];
114 }
115
116 /// Intersects 'rhs' with this set.
117 void intersect(const HyperRectangularSet &rhs);
118
119 /// Performs a union of 'rhs' with this set.
120 void unionize(const HyperRectangularSet &rhs);
121
122 /// Project out num dimensions starting from 'idx'. This is equivalent to
123 /// taking an image of this set on the remaining dimensions.
124 void projectOut(unsigned idx, unsigned num);
125
126 /// Returns true if the set has no integer points in it.
127 bool empty() const;
128
129 /// Add a lower bound expression to dimension position 'idx'.
130 void addLowerBoundExpr(unsigned idx, AffineExpr *expr);
131
132 /// Add an upper bound expression to dimension position 'idx'.
133 void addUpperBoundExpr(unsigned idx, AffineExpr *expr);
134
135 /// Clear this set's context, i.e., make it the universal set.
136 void clearContext() { context.clear(); }
137
138 void print(raw_ostream &os) const;
139 void dump() const;
140
141private:
142 /// Simplify this set under the symbolic context 'context'.
143 void simplifyUnderContext() {}
144
145 /// The lower bound along any dimension is a max of several pure
146 /// symbolic/constant affine expressions. A bound cannot be mutated from
147 /// outside the class, it has to be to be updated through
148 /// addLowerBoundExpr/addUpperBoundExpr.
149 std::vector<AffineBoundExprList> lowerBounds;
150 // Each upper bound is a min of several pure symbolic/constant affine
151 // expressions.
152 std::vector<AffineBoundExprList> upperBounds;
153
154 Optional<SmallVector<MLValue *, 8>> dims = None;
155 Optional<SmallVector<MLValue *, 4>> symbols = None;
156
157 /// Number of real dimensions.
158 unsigned numDims;
159
160 /// Number of symbols (unknown but constant)
161 unsigned numSymbols;
162
163 // Constraints on the symbols. The representation of the set is kept
164 // simplified under this context.
165 MutableIntegerSet context;
166};
167
168//===--------------------------------------------------------------------===//
169// Out of place operations.
170//===--------------------------------------------------------------------===//
171
172static std::unique_ptr<HyperRectangularSet>
173intersection(const HyperRectangularSet &lhs, const HyperRectangularSet &rhs);
174
175static std::unique_ptr<HyperRectangleList>
176intersection(const HyperRectangleList &lhs, const HyperRectangleList &rhs);
177
178/// Performs a union of 'lhs' and 'rhs'.
179static std::unique_ptr<HyperRectangleList>
180unionize(const HyperRectangularSet &lhs, const HyperRectangularSet &rhs);
181static std::unique_ptr<HyperRectangleList>
182unionize(const HyperRectangleList &lhs, const HyperRectangleList &rhs);
183
184/// Subtract 'rhs' from this lhs and return the result.
185static std::unique_ptr<HyperRectangleList>
186difference(const HyperRectangularSet &lhs, const HyperRectangularSet &rhs);
187static std::unique_ptr<HyperRectangleList>
188difference(const HyperRectangleList &lhs, const HyperRectangleList &rhs);
189
190/// Project out num dimensions starting from 'idx'. This is equivalent to
191/// taking an image of this set on the remaining dimensions.
192static std::unique_ptr<HyperRectangularSet>
193projectOut(const HyperRectangularSet &set, unsigned idx, unsigned num);
194
195} // namespace mlir
196
197namespace llvm {
198
199template <> struct ilist_traits<::mlir::HyperRectangularSet> {
200 using HyperRectangularSet = ::mlir::HyperRectangularSet;
201 using set_iterator = simple_ilist<HyperRectangularSet>::iterator;
202
203 static void deleteNode(HyperRectangularSet *set) { delete set; }
204
205 void addNodeToList(HyperRectangularSet *set);
206 void removeNodeFromList(HyperRectangularSet *set);
207 void transferNodesFromList(ilist_traits<HyperRectangularSet> &otherList,
208 set_iterator first, set_iterator last);
209
210private:
211 mlir::HyperRectangleList *getContainingBlock();
212};
213
214} // namespace llvm
215
216namespace mlir {
217
218/// A list of hyper-rectangular sets lying in the same space of dimensional
219/// and symbolic identifiers. The individual set elements are always kept
220/// disjoint (re-evaluate choice) and minimal, i.e., the union of any subset of
221/// the contained hyperrectangles can't be coalesced into a single
222/// hyper-rectangle.
223class HyperRectangleList {
224public:
225 /// Construct a constraint system reserving memory for the specified number of
226 /// constraints and identifiers.
227 explicit HyperRectangleList(const FlatAffineConstraints &cst);
228
229 HyperRectangleList(unsigned numDims, unsigned numSymbols,
230 ArrayRef<std::unique_ptr<HyperRectangularSet>> sets);
231
232 unsigned getNumDims() const { return numDims; }
233 unsigned getNumSymbols() const { return numSymbols; }
234
235 // In-place operations.
236
237 /// Intersects a hyper rectangular set list 'rhs' with this set.
238 void intersect(const HyperRectangleList &rhs);
239
240 /// Intersects 'rhs' with this set.
241 void intersect(const HyperRectangularSet &rhs);
242
243 /// Performs a union of 'rhs' with this set.
244 void unionize(const HyperRectangleList &rhs);
245
246 /// Performs a union of 'rhs' with this set.
247 void unionize(const HyperRectangularSet &rhs);
248
249 /// Project out num dimensions starting from 'idx'. This is equivalent to
250 /// taking an image of this set on the remaining dimensions.
251 void projectOut(unsigned idx, unsigned num);
252
253 /// Returns true if all the sets are empty.
254 bool empty() const;
255
256 //===--------------------------------------------------------------------===//
257 // Hyper-rectangular set list management.
258 //===--------------------------------------------------------------------===//
259
260 /// These are for the list of hyper-rectangular set elements.
261 typedef ::llvm::iplist<HyperRectangularSet> HyperRectangleListTy;
262 HyperRectangleListTy &getRectangles() { return hyperRectangles; }
263
264 // Iteration over the statements in the block.
265 using const_iterator = HyperRectangleListTy::const_iterator;
266
267 const_iterator begin() const { return hyperRectangles.begin(); }
268 const_iterator end() const { return hyperRectangles.end(); }
269
270 bool listEmpty() const { return hyperRectangles.empty(); }
271
272 void addSet(std::unique_ptr<HyperRectangularSet> set) {
273 set->clearContext();
274 hyperRectangles.push_back(set.release());
275 }
276
277private:
278 // Mutable versions of the iterators are private.
279 using iterator = HyperRectangleListTy::iterator;
280 iterator begin() { return hyperRectangles.begin(); }
281 iterator end() { return hyperRectangles.end(); }
282
283 /// Simplify under the symbolic context 'context'.
284 void simplifyUnderContext() {}
285
286 /// Number of identifiers corresponding to real dimensions.
287 unsigned numDims;
288
289 /// Number of identifiers corresponding to symbols (unknown but constant)
290 unsigned numSymbols;
291
292 /// The list of hyper-rectangular sets contained.
293 HyperRectangleListTy hyperRectangles;
294
295 // Constraints on the symbols. The representation of the set is kept
296 // simplified under this context.
297 MutableIntegerSet context;
298};
299
300// Out of place operations.
301
302// Return a bounding box of this list of hyper-rectangles. This is notionally
303// equivanelt to a rectangular/convex hull.
304std::unique_ptr<HyperRectangularSet> boundingBox();
305
306/// Intersects and returns the result.
307static std::unique_ptr<HyperRectangleList>
308intersection(const HyperRectangleList &lhs, const HyperRectangleList &rhs);
309
310/// Performs a union and returns the result.
311static std::unique_ptr<HyperRectangleList>
312unionize(const HyperRectangleList &lhs, const HyperRectangleList &rhs);
313
314/// Subtracts 'rhs' from this lhs and return the result.
315static std::unique_ptr<HyperRectangleList>
316difference(const HyperRectangleList &lhs, const HyperRectangleList &rhs);
317
318} // end namespace mlir.
319
320#endif // MLIR_ANALYSIS_HYPER_RECTANGULAR_SET_H