blob: 8956aeb0f89be3d7c2fd1405ed00c1a951302d9c [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,
Uday Bondhugula83a41c92018-08-30 17:35:15 -070098 MLIRContext *context,
Uday Bondhugulab553adb2018-08-25 17:17:56 -070099 IntegerSet *symbolContext = nullptr);
100
101 unsigned getNumDims() const { return numDims; }
102 unsigned getNumSymbols() const { return numSymbols; }
103
104 ArrayRef<AffineBoundExprList> getLowerBounds() const { return lowerBounds; }
105 ArrayRef<AffineBoundExprList> getUpperBounds() const { return upperBounds; }
106
107 AffineBoundExprList &getLowerBound(unsigned idx) { return lowerBounds[idx]; }
108 AffineBoundExprList &getUpperBound(unsigned idx) { return upperBounds[idx]; }
109
110 const AffineBoundExprList &getLowerBound(unsigned idx) const {
111 return lowerBounds[idx];
112 }
113 const AffineBoundExprList &getUpperBound(unsigned idx) const {
114 return upperBounds[idx];
115 }
116
117 /// Intersects 'rhs' with this set.
118 void intersect(const HyperRectangularSet &rhs);
119
120 /// Performs a union of 'rhs' with this set.
121 void unionize(const HyperRectangularSet &rhs);
122
123 /// Project out num dimensions starting from 'idx'. This is equivalent to
124 /// taking an image of this set on the remaining dimensions.
125 void projectOut(unsigned idx, unsigned num);
126
127 /// Returns true if the set has no integer points in it.
128 bool empty() const;
129
130 /// Add a lower bound expression to dimension position 'idx'.
131 void addLowerBoundExpr(unsigned idx, AffineExpr *expr);
132
133 /// Add an upper bound expression to dimension position 'idx'.
134 void addUpperBoundExpr(unsigned idx, AffineExpr *expr);
135
136 /// Clear this set's context, i.e., make it the universal set.
137 void clearContext() { context.clear(); }
138
139 void print(raw_ostream &os) const;
140 void dump() const;
141
142private:
143 /// Simplify this set under the symbolic context 'context'.
144 void simplifyUnderContext() {}
145
146 /// The lower bound along any dimension is a max of several pure
147 /// symbolic/constant affine expressions. A bound cannot be mutated from
148 /// outside the class, it has to be to be updated through
149 /// addLowerBoundExpr/addUpperBoundExpr.
150 std::vector<AffineBoundExprList> lowerBounds;
151 // Each upper bound is a min of several pure symbolic/constant affine
152 // expressions.
153 std::vector<AffineBoundExprList> upperBounds;
154
155 Optional<SmallVector<MLValue *, 8>> dims = None;
156 Optional<SmallVector<MLValue *, 4>> symbols = None;
157
158 /// Number of real dimensions.
159 unsigned numDims;
160
161 /// Number of symbols (unknown but constant)
162 unsigned numSymbols;
163
164 // Constraints on the symbols. The representation of the set is kept
165 // simplified under this context.
166 MutableIntegerSet context;
167};
168
169//===--------------------------------------------------------------------===//
170// Out of place operations.
171//===--------------------------------------------------------------------===//
172
173static std::unique_ptr<HyperRectangularSet>
174intersection(const HyperRectangularSet &lhs, const HyperRectangularSet &rhs);
175
176static std::unique_ptr<HyperRectangleList>
177intersection(const HyperRectangleList &lhs, const HyperRectangleList &rhs);
178
179/// Performs a union of 'lhs' and 'rhs'.
180static std::unique_ptr<HyperRectangleList>
181unionize(const HyperRectangularSet &lhs, const HyperRectangularSet &rhs);
182static std::unique_ptr<HyperRectangleList>
183unionize(const HyperRectangleList &lhs, const HyperRectangleList &rhs);
184
185/// Subtract 'rhs' from this lhs and return the result.
186static std::unique_ptr<HyperRectangleList>
187difference(const HyperRectangularSet &lhs, const HyperRectangularSet &rhs);
188static std::unique_ptr<HyperRectangleList>
189difference(const HyperRectangleList &lhs, const HyperRectangleList &rhs);
190
191/// Project out num dimensions starting from 'idx'. This is equivalent to
192/// taking an image of this set on the remaining dimensions.
193static std::unique_ptr<HyperRectangularSet>
194projectOut(const HyperRectangularSet &set, unsigned idx, unsigned num);
195
196} // namespace mlir
197
198namespace llvm {
199
200template <> struct ilist_traits<::mlir::HyperRectangularSet> {
201 using HyperRectangularSet = ::mlir::HyperRectangularSet;
202 using set_iterator = simple_ilist<HyperRectangularSet>::iterator;
203
204 static void deleteNode(HyperRectangularSet *set) { delete set; }
205
206 void addNodeToList(HyperRectangularSet *set);
207 void removeNodeFromList(HyperRectangularSet *set);
208 void transferNodesFromList(ilist_traits<HyperRectangularSet> &otherList,
209 set_iterator first, set_iterator last);
210
211private:
212 mlir::HyperRectangleList *getContainingBlock();
213};
214
215} // namespace llvm
216
217namespace mlir {
218
219/// A list of hyper-rectangular sets lying in the same space of dimensional
220/// and symbolic identifiers. The individual set elements are always kept
221/// disjoint (re-evaluate choice) and minimal, i.e., the union of any subset of
222/// the contained hyperrectangles can't be coalesced into a single
223/// hyper-rectangle.
224class HyperRectangleList {
225public:
226 /// Construct a constraint system reserving memory for the specified number of
227 /// constraints and identifiers.
228 explicit HyperRectangleList(const FlatAffineConstraints &cst);
229
230 HyperRectangleList(unsigned numDims, unsigned numSymbols,
231 ArrayRef<std::unique_ptr<HyperRectangularSet>> sets);
232
233 unsigned getNumDims() const { return numDims; }
234 unsigned getNumSymbols() const { return numSymbols; }
235
236 // In-place operations.
237
238 /// Intersects a hyper rectangular set list 'rhs' with this set.
239 void intersect(const HyperRectangleList &rhs);
240
241 /// Intersects 'rhs' with this set.
242 void intersect(const HyperRectangularSet &rhs);
243
244 /// Performs a union of 'rhs' with this set.
245 void unionize(const HyperRectangleList &rhs);
246
247 /// Performs a union of 'rhs' with this set.
248 void unionize(const HyperRectangularSet &rhs);
249
250 /// Project out num dimensions starting from 'idx'. This is equivalent to
251 /// taking an image of this set on the remaining dimensions.
252 void projectOut(unsigned idx, unsigned num);
253
254 /// Returns true if all the sets are empty.
255 bool empty() const;
256
257 //===--------------------------------------------------------------------===//
258 // Hyper-rectangular set list management.
259 //===--------------------------------------------------------------------===//
260
261 /// These are for the list of hyper-rectangular set elements.
262 typedef ::llvm::iplist<HyperRectangularSet> HyperRectangleListTy;
263 HyperRectangleListTy &getRectangles() { return hyperRectangles; }
264
265 // Iteration over the statements in the block.
266 using const_iterator = HyperRectangleListTy::const_iterator;
267
268 const_iterator begin() const { return hyperRectangles.begin(); }
269 const_iterator end() const { return hyperRectangles.end(); }
270
271 bool listEmpty() const { return hyperRectangles.empty(); }
272
273 void addSet(std::unique_ptr<HyperRectangularSet> set) {
274 set->clearContext();
275 hyperRectangles.push_back(set.release());
276 }
277
278private:
279 // Mutable versions of the iterators are private.
280 using iterator = HyperRectangleListTy::iterator;
281 iterator begin() { return hyperRectangles.begin(); }
282 iterator end() { return hyperRectangles.end(); }
283
284 /// Simplify under the symbolic context 'context'.
285 void simplifyUnderContext() {}
286
287 /// Number of identifiers corresponding to real dimensions.
288 unsigned numDims;
289
290 /// Number of identifiers corresponding to symbols (unknown but constant)
291 unsigned numSymbols;
292
293 /// The list of hyper-rectangular sets contained.
294 HyperRectangleListTy hyperRectangles;
295
296 // Constraints on the symbols. The representation of the set is kept
297 // simplified under this context.
298 MutableIntegerSet context;
299};
300
301// Out of place operations.
302
303// Return a bounding box of this list of hyper-rectangles. This is notionally
304// equivanelt to a rectangular/convex hull.
305std::unique_ptr<HyperRectangularSet> boundingBox();
306
307/// Intersects and returns the result.
308static std::unique_ptr<HyperRectangleList>
309intersection(const HyperRectangleList &lhs, const HyperRectangleList &rhs);
310
311/// Performs a union and returns the result.
312static std::unique_ptr<HyperRectangleList>
313unionize(const HyperRectangleList &lhs, const HyperRectangleList &rhs);
314
315/// Subtracts 'rhs' from this lhs and return the result.
316static std::unique_ptr<HyperRectangleList>
317difference(const HyperRectangleList &lhs, const HyperRectangleList &rhs);
318
319} // end namespace mlir.
320
321#endif // MLIR_ANALYSIS_HYPER_RECTANGULAR_SET_H