Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===------ ISLTools.h ------------------------------------------*- C++ -*-===// |
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 | // Tools, utilities, helpers and extensions useful in conjunction with the |
||
10 | // Integer Set Library (isl). |
||
11 | // |
||
12 | //===----------------------------------------------------------------------===// |
||
13 | |||
14 | #ifndef POLLY_ISLTOOLS_H |
||
15 | #define POLLY_ISLTOOLS_H |
||
16 | |||
17 | #include "llvm/ADT/Sequence.h" |
||
18 | #include "llvm/ADT/iterator.h" |
||
19 | #include "isl/isl-noexceptions.h" |
||
20 | #include <algorithm> |
||
21 | #include <cassert> |
||
22 | |||
23 | /// In debug builds assert that the @p Size is valid, in non-debug builds |
||
24 | /// disable the mandatory state checking but do not enforce the error checking. |
||
25 | inline void islAssert(const isl::size &Size) { |
||
26 | #ifdef NDEBUG |
||
27 | // Calling is_error() marks that the error status has been checked which |
||
28 | // disables the error-status-not-checked errors that would otherwise occur |
||
29 | // when using the value. |
||
30 | (void)Size.is_error(); |
||
31 | #else |
||
32 | // Assert on error in debug builds. |
||
33 | assert(!Size.is_error()); |
||
34 | #endif |
||
35 | } |
||
36 | |||
37 | /// Check that @p Size is valid (only on debug builds) and cast it to unsigned. |
||
38 | /// Cast the @p Size to unsigned. If the @p Size is not valid (Size.is_error() |
||
39 | /// == true) then an assert and an abort are triggered. |
||
40 | inline unsigned unsignedFromIslSize(const isl::size &Size) { |
||
41 | islAssert(Size); |
||
42 | return static_cast<unsigned>(Size); |
||
43 | } |
||
44 | |||
45 | namespace isl { |
||
46 | inline namespace noexceptions { |
||
47 | |||
48 | template <typename ListT> |
||
49 | using list_element_type = decltype(std::declval<ListT>().get_at(0)); |
||
50 | |||
51 | template <typename ListT> |
||
52 | class isl_iterator |
||
53 | : public llvm::iterator_facade_base<isl_iterator<ListT>, |
||
54 | std::forward_iterator_tag, |
||
55 | list_element_type<ListT>> { |
||
56 | public: |
||
57 | using ElementT = list_element_type<ListT>; |
||
58 | |||
59 | explicit isl_iterator(const ListT &List) |
||
60 | : List(&List), Position(std::max(List.size().release(), 0)) {} |
||
61 | isl_iterator(const ListT &List, int Position) |
||
62 | : List(&List), Position(Position) {} |
||
63 | |||
64 | bool operator==(const isl_iterator &O) const { |
||
65 | return List == O.List && Position == O.Position; |
||
66 | } |
||
67 | |||
68 | isl_iterator &operator++() { |
||
69 | ++Position; |
||
70 | return *this; |
||
71 | } |
||
72 | |||
73 | isl_iterator operator++(int) { |
||
74 | isl_iterator Copy{*this}; |
||
75 | ++Position; |
||
76 | return Copy; |
||
77 | } |
||
78 | |||
79 | ElementT operator*() const { return List->get_at(this->Position); } |
||
80 | |||
81 | protected: |
||
82 | const ListT *List; |
||
83 | int Position = 0; |
||
84 | }; |
||
85 | |||
86 | template <typename T> isl_iterator<T> begin(const T &t) { |
||
87 | return isl_iterator<T>(t, 0); |
||
88 | } |
||
89 | template <typename T> isl_iterator<T> end(const T &t) { |
||
90 | return isl_iterator<T>(t); |
||
91 | } |
||
92 | |||
93 | } // namespace noexceptions |
||
94 | } // namespace isl |
||
95 | |||
96 | namespace polly { |
||
97 | |||
98 | /// Return the range elements that are lexicographically smaller. |
||
99 | /// |
||
100 | /// @param Map { Space[] -> Scatter[] } |
||
101 | /// @param Strict True for strictly lexicographically smaller elements (exclude |
||
102 | /// same timepoints from the result). |
||
103 | /// |
||
104 | /// @return { Space[] -> Scatter[] } |
||
105 | /// A map to all timepoints that happen before the timepoints the input |
||
106 | /// mapped to. |
||
107 | isl::map beforeScatter(isl::map Map, bool Strict); |
||
108 | |||
109 | /// Piecewise beforeScatter(isl::map,bool). |
||
110 | isl::union_map beforeScatter(isl::union_map UMap, bool Strict); |
||
111 | |||
112 | /// Return the range elements that are lexicographically larger. |
||
113 | /// |
||
114 | /// @param Map { Space[] -> Scatter[] } |
||
115 | /// @param Strict True for strictly lexicographically larger elements (exclude |
||
116 | /// same timepoints from the result). |
||
117 | /// |
||
118 | /// @return { Space[] -> Scatter[] } |
||
119 | /// A map to all timepoints that happen after the timepoints the input |
||
120 | /// map originally mapped to. |
||
121 | isl::map afterScatter(isl::map Map, bool Strict); |
||
122 | |||
123 | /// Piecewise afterScatter(isl::map,bool). |
||
124 | isl::union_map afterScatter(const isl::union_map &UMap, bool Strict); |
||
125 | |||
126 | /// Construct a range of timepoints between two timepoints. |
||
127 | /// |
||
128 | /// Example: |
||
129 | /// From := { A[] -> [0]; B[] -> [0] } |
||
130 | /// To := { B[] -> [10]; C[] -> [20] } |
||
131 | /// |
||
132 | /// Result: |
||
133 | /// { B[] -> [i] : 0 < i < 10 } |
||
134 | /// |
||
135 | /// Note that A[] and C[] are not in the result because they do not have a start |
||
136 | /// or end timepoint. If a start (or end) timepoint is not unique, the first |
||
137 | /// (respectively last) is chosen. |
||
138 | /// |
||
139 | /// @param From { Space[] -> Scatter[] } |
||
140 | /// Map to start timepoints. |
||
141 | /// @param To { Space[] -> Scatter[] } |
||
142 | /// Map to end timepoints. |
||
143 | /// @param InclFrom Whether to include the start timepoints in the result. In |
||
144 | /// the example, this would add { B[] -> [0] } |
||
145 | /// @param InclTo Whether to include the end timepoints in the result. In this |
||
146 | /// example, this would add { B[] -> [10] } |
||
147 | /// |
||
148 | /// @return { Space[] -> Scatter[] } |
||
149 | /// A map for each domain element of timepoints between two extreme |
||
150 | /// points, or nullptr if @p From or @p To is nullptr, or the isl max |
||
151 | /// operations is exceeded. |
||
152 | isl::map betweenScatter(isl::map From, isl::map To, bool InclFrom, bool InclTo); |
||
153 | |||
154 | /// Piecewise betweenScatter(isl::map,isl::map,bool,bool). |
||
155 | isl::union_map betweenScatter(isl::union_map From, isl::union_map To, |
||
156 | bool InclFrom, bool InclTo); |
||
157 | |||
158 | /// If by construction a union map is known to contain only a single map, return |
||
159 | /// it. |
||
160 | /// |
||
161 | /// This function combines isl_map_from_union_map() and |
||
162 | /// isl_union_map_extract_map(). isl_map_from_union_map() fails if the map is |
||
163 | /// empty because it does not know which space it would be in. |
||
164 | /// isl_union_map_extract_map() on the other hand does not check whether there |
||
165 | /// is (at most) one isl_map in the union, i.e. how it has been constructed is |
||
166 | /// probably wrong. |
||
167 | isl::map singleton(isl::union_map UMap, isl::space ExpectedSpace); |
||
168 | |||
169 | /// If by construction an isl_union_set is known to contain only a single |
||
170 | /// isl_set, return it. |
||
171 | /// |
||
172 | /// This function combines isl_set_from_union_set() and |
||
173 | /// isl_union_set_extract_set(). isl_map_from_union_set() fails if the set is |
||
174 | /// empty because it does not know which space it would be in. |
||
175 | /// isl_union_set_extract_set() on the other hand does not check whether there |
||
176 | /// is (at most) one isl_set in the union, i.e. how it has been constructed is |
||
177 | /// probably wrong. |
||
178 | isl::set singleton(isl::union_set USet, isl::space ExpectedSpace); |
||
179 | |||
180 | /// Determine how many dimensions the scatter space of @p Schedule has. |
||
181 | /// |
||
182 | /// The schedule must not be empty and have equal number of dimensions of any |
||
183 | /// subspace it contains. |
||
184 | /// |
||
185 | /// The implementation currently returns the maximum number of dimensions it |
||
186 | /// encounters, if different, and 0 if none is encountered. However, most other |
||
187 | /// code will most likely fail if one of these happen. |
||
188 | unsigned getNumScatterDims(const isl::union_map &Schedule); |
||
189 | |||
190 | /// Return the scatter space of a @p Schedule. |
||
191 | /// |
||
192 | /// This is basically the range space of the schedule map, but harder to |
||
193 | /// determine because it is an isl_union_map. |
||
194 | isl::space getScatterSpace(const isl::union_map &Schedule); |
||
195 | |||
196 | /// Construct an identity map for the given domain values. |
||
197 | /// |
||
198 | /// @param USet { Space[] } |
||
199 | /// The returned map's domain and range. |
||
200 | /// @param RestrictDomain If true, the returned map only maps elements contained |
||
201 | /// in @p Set and no other. If false, it returns an |
||
202 | /// overapproximation with the identity maps of any space |
||
203 | /// in @p Set, not just the elements in it. |
||
204 | /// |
||
205 | /// @return { Space[] -> Space[] } |
||
206 | /// A map that maps each value of @p Set to itself. |
||
207 | isl::map makeIdentityMap(const isl::set &Set, bool RestrictDomain); |
||
208 | |||
209 | /// Construct an identity map for the given domain values. |
||
210 | /// |
||
211 | /// There is no type resembling isl_union_space, hence we have to pass an |
||
212 | /// isl_union_set as the map's domain and range space. |
||
213 | /// |
||
214 | /// @param USet { Space[] } |
||
215 | /// The returned map's domain and range. |
||
216 | /// @param RestrictDomain If true, the returned map only maps elements contained |
||
217 | /// in @p USet and no other. If false, it returns an |
||
218 | /// overapproximation with the identity maps of any space |
||
219 | /// in @p USet, not just the elements in it. |
||
220 | /// |
||
221 | /// @return { Space[] -> Space[] } |
||
222 | /// A map that maps each value of @p USet to itself. |
||
223 | isl::union_map makeIdentityMap(const isl::union_set &USet, bool RestrictDomain); |
||
224 | |||
225 | /// Reverse the nested map tuple in @p Map's domain. |
||
226 | /// |
||
227 | /// @param Map { [Space1[] -> Space2[]] -> Space3[] } |
||
228 | /// |
||
229 | /// @return { [Space2[] -> Space1[]] -> Space3[] } |
||
230 | isl::map reverseDomain(isl::map Map); |
||
231 | |||
232 | /// Piecewise reverseDomain(isl::map). |
||
233 | isl::union_map reverseDomain(const isl::union_map &UMap); |
||
234 | |||
235 | /// Add a constant to one dimension of a set. |
||
236 | /// |
||
237 | /// @param Map The set to shift a dimension in. |
||
238 | /// @param Pos The dimension to shift. If negative, the dimensions are |
||
239 | /// counted from the end instead from the beginning. E.g. -1 is |
||
240 | /// the last dimension in the tuple. |
||
241 | /// @param Amount The offset to add to the specified dimension. |
||
242 | /// |
||
243 | /// @return The modified set. |
||
244 | isl::set shiftDim(isl::set Set, int Pos, int Amount); |
||
245 | |||
246 | /// Piecewise shiftDim(isl::set,int,int). |
||
247 | isl::union_set shiftDim(isl::union_set USet, int Pos, int Amount); |
||
248 | |||
249 | /// Add a constant to one dimension of a map. |
||
250 | /// |
||
251 | /// @param Map The map to shift a dimension in. |
||
252 | /// @param Type A tuple of @p Map which contains the dimension to shift. |
||
253 | /// @param Pos The dimension to shift. If negative, the dimensions are |
||
254 | /// counted from the end instead from the beginning. Eg. -1 is the last |
||
255 | /// dimension in the tuple. |
||
256 | /// @param Amount The offset to add to the specified dimension. |
||
257 | /// |
||
258 | /// @return The modified map. |
||
259 | isl::map shiftDim(isl::map Map, isl::dim Dim, int Pos, int Amount); |
||
260 | |||
261 | /// Add a constant to one dimension of a each map in a union map. |
||
262 | /// |
||
263 | /// @param UMap The maps to shift a dimension in. |
||
264 | /// @param Type The tuple which contains the dimension to shift. |
||
265 | /// @param Pos The dimension to shift. If negative, the dimensions are |
||
266 | /// counted from the ends of each map of union instead from their |
||
267 | /// beginning. E.g. -1 is the last dimension of any map. |
||
268 | /// @param Amount The offset to add to the specified dimension. |
||
269 | /// |
||
270 | /// @return The union of all modified maps. |
||
271 | isl::union_map shiftDim(isl::union_map UMap, isl::dim Dim, int Pos, int Amount); |
||
272 | |||
273 | /// Simplify a set inplace. |
||
274 | void simplify(isl::set &Set); |
||
275 | |||
276 | /// Simplify a union set inplace. |
||
277 | void simplify(isl::union_set &USet); |
||
278 | |||
279 | /// Simplify a map inplace. |
||
280 | void simplify(isl::map &Map); |
||
281 | |||
282 | /// Simplify a union map inplace. |
||
283 | void simplify(isl::union_map &UMap); |
||
284 | |||
285 | /// Compute the reaching definition statement or the next overwrite for each |
||
286 | /// definition of an array element. |
||
287 | /// |
||
288 | /// The reaching definition of an array element at a specific timepoint is the |
||
289 | /// statement instance that has written the current element's content. |
||
290 | /// Alternatively, this function determines for each timepoint and element which |
||
291 | /// write is going to overwrite an element at a future timepoint. This can be |
||
292 | /// seen as "reaching definition in reverse" where definitions are found in the |
||
293 | /// past. |
||
294 | /// |
||
295 | /// For example: |
||
296 | /// |
||
297 | /// Schedule := { Write[] -> [0]; Overwrite[] -> [10] } |
||
298 | /// Defs := { Write[] -> A[5]; Overwrite[] -> A[5] } |
||
299 | /// |
||
300 | /// If index 5 of array A is written at timepoint 0 and 10, the resulting |
||
301 | /// reaching definitions are: |
||
302 | /// |
||
303 | /// { [A[5] -> [i]] -> Write[] : 0 < i < 10; |
||
304 | /// [A[5] -> [i]] -> Overwrite[] : 10 < i } |
||
305 | /// |
||
306 | /// Between timepoint 0 (Write[]) and timepoint 10 (Overwrite[]), the |
||
307 | /// content of A[5] is written by statement instance Write[] and after |
||
308 | /// timepoint 10 by Overwrite[]. Values not defined in the map have no known |
||
309 | /// definition. This includes the statement instance timepoints themselves, |
||
310 | /// because reads at those timepoints could either read the old or the new |
||
311 | /// value, defined only by the statement itself. But this can be changed by @p |
||
312 | /// InclPrevDef and @p InclNextDef. InclPrevDef=false and InclNextDef=true |
||
313 | /// returns a zone. Unless @p InclPrevDef and @p InclNextDef are both true, |
||
314 | /// there is only one unique definition per element and timepoint. |
||
315 | /// |
||
316 | /// @param Schedule { DomainWrite[] -> Scatter[] } |
||
317 | /// Schedule of (at least) all array writes. Instances not in |
||
318 | /// @p Writes are ignored. |
||
319 | /// @param Writes { DomainWrite[] -> Element[] } |
||
320 | /// Elements written to by the statement instances. |
||
321 | /// @param Reverse If true, look for definitions in the future. That is, |
||
322 | /// find the write that is overwrites the current value. |
||
323 | /// @param InclPrevDef Include the definition's timepoint to the set of |
||
324 | /// well-defined elements (any load at that timepoint happen |
||
325 | /// at the writes). In the example, enabling this option adds |
||
326 | /// {[A[5] -> [0]] -> Write[]; [A[5] -> [10]] -> Overwrite[]} |
||
327 | /// to the result. |
||
328 | /// @param InclNextDef Whether to assume that at the timepoint where an element |
||
329 | /// is overwritten, it still contains the old value (any load |
||
330 | /// at that timepoint would happen before the overwrite). In |
||
331 | /// this example, enabling this adds |
||
332 | /// { [A[] -> [10]] -> Write[] } to the result. |
||
333 | /// |
||
334 | /// @return { [Element[] -> Scatter[]] -> DomainWrite[] } |
||
335 | /// The reaching definitions or future overwrite as described above, or |
||
336 | /// nullptr if either @p Schedule or @p Writes is nullptr, or the isl |
||
337 | /// max operations count has exceeded. |
||
338 | isl::union_map computeReachingWrite(isl::union_map Schedule, |
||
339 | isl::union_map Writes, bool Reverse, |
||
340 | bool InclPrevDef, bool InclNextDef); |
||
341 | |||
342 | /// Compute the timepoints where the contents of an array element are not used. |
||
343 | /// |
||
344 | /// An element is unused at a timepoint when the element is overwritten in |
||
345 | /// the future, but it is not read in between. Another way to express this: the |
||
346 | /// time from when the element is written, to the most recent read before it, or |
||
347 | /// infinitely into the past if there is no read before. Such unused elements |
||
348 | /// can be overwritten by any value without changing the scop's semantics. An |
||
349 | /// example: |
||
350 | /// |
||
351 | /// Schedule := { Read[] -> [0]; Write[] -> [10]; Def[] -> [20] } |
||
352 | /// Writes := { Write[] -> A[5]; Def[] -> A[6] } |
||
353 | /// Reads := { Read[] -> A[5] } |
||
354 | /// |
||
355 | /// The result is: |
||
356 | /// |
||
357 | /// { A[5] -> [i] : 0 < i < 10; |
||
358 | /// A[6] -> [i] : i < 20 } |
||
359 | /// |
||
360 | /// That is, A[5] is unused between timepoint 0 (the read) and timepoint 10 (the |
||
361 | /// write). A[6] is unused before timepoint 20, but might be used after the |
||
362 | /// scop's execution (A[5] and any other A[i] as well). Use InclLastRead=false |
||
363 | /// and InclWrite=true to interpret the result as zone. |
||
364 | /// |
||
365 | /// @param Schedule { Domain[] -> Scatter[] } |
||
366 | /// The schedule of (at least) all statement instances |
||
367 | /// occurring in @p Writes or @p Reads. All other |
||
368 | /// instances are ignored. |
||
369 | /// @param Writes { DomainWrite[] -> Element[] } |
||
370 | /// Elements written to by the statement instances. |
||
371 | /// @param Reads { DomainRead[] -> Element[] } |
||
372 | /// Elements read from by the statement instances. |
||
373 | /// @param ReadEltInSameInst Whether a load reads the value from a write |
||
374 | /// that is scheduled at the same timepoint (Writes |
||
375 | /// happen before reads). Otherwise, loads use the |
||
376 | /// value of an element that it had before the |
||
377 | /// timepoint (Reads before writes). For example: |
||
378 | /// { Read[] -> [0]; Write[] -> [0] } |
||
379 | /// With ReadEltInSameInst=false it is assumed that the |
||
380 | /// read happens before the write, such that the |
||
381 | /// element is never unused, or just at timepoint 0, |
||
382 | /// depending on InclLastRead/InclWrite. |
||
383 | /// With ReadEltInSameInst=false it assumes that the |
||
384 | /// value just written is used. Anything before |
||
385 | /// timepoint 0 is considered unused. |
||
386 | /// @param InclLastRead Whether a timepoint where an element is last read |
||
387 | /// counts as unused (the read happens at the beginning |
||
388 | /// of its timepoint, and nothing (else) can use it |
||
389 | /// during the timepoint). In the example, this option |
||
390 | /// adds { A[5] -> [0] } to the result. |
||
391 | /// @param InclWrite Whether the timepoint where an element is written |
||
392 | /// itself counts as unused (the write happens at the |
||
393 | /// end of its timepoint; no (other) operations uses |
||
394 | /// the element during the timepoint). In this example, |
||
395 | /// this adds |
||
396 | /// { A[5] -> [10]; A[6] -> [20] } to the result. |
||
397 | /// |
||
398 | /// @return { Element[] -> Scatter[] } |
||
399 | /// The unused timepoints as defined above, or nullptr if either @p |
||
400 | /// Schedule, @p Writes are @p Reads is nullptr, or the ISL max |
||
401 | /// operations count is exceeded. |
||
402 | isl::union_map computeArrayUnused(isl::union_map Schedule, |
||
403 | isl::union_map Writes, isl::union_map Reads, |
||
404 | bool ReadEltInSameInst, bool InclLastRead, |
||
405 | bool InclWrite); |
||
406 | |||
407 | /// Convert a zone (range between timepoints) to timepoints. |
||
408 | /// |
||
409 | /// A zone represents the time between (integer) timepoints, but not the |
||
410 | /// timepoints themselves. This function can be used to determine whether a |
||
411 | /// timepoint lies within a zone. |
||
412 | /// |
||
413 | /// For instance, the range (1,3), representing the time between 1 and 3, is |
||
414 | /// represented by the zone |
||
415 | /// |
||
416 | /// { [i] : 1 < i <= 3 } |
||
417 | /// |
||
418 | /// The set of timepoints that lie completely within this range is |
||
419 | /// |
||
420 | /// { [i] : 1 < i < 3 } |
||
421 | /// |
||
422 | /// A typical use-case is the range in which a value written by a store is |
||
423 | /// available until it is overwritten by another value. If the write is at |
||
424 | /// timepoint 1 and its value is overwritten by another value at timepoint 3, |
||
425 | /// the value is available between those timepoints: timepoint 2 in this |
||
426 | /// example. |
||
427 | /// |
||
428 | /// |
||
429 | /// When InclStart is true, the range is interpreted left-inclusive, i.e. adds |
||
430 | /// the timepoint 1 to the result: |
||
431 | /// |
||
432 | /// { [i] : 1 <= i < 3 } |
||
433 | /// |
||
434 | /// In the use-case mentioned above that means that the value written at |
||
435 | /// timepoint 1 is already available in timepoint 1 (write takes place before |
||
436 | /// any read of it even if executed at the same timepoint) |
||
437 | /// |
||
438 | /// When InclEnd is true, the range is interpreted right-inclusive, i.e. adds |
||
439 | /// the timepoint 3 to the result: |
||
440 | /// |
||
441 | /// { [i] : 1 < i <= 3 } |
||
442 | /// |
||
443 | /// In the use-case mentioned above that means that although the value is |
||
444 | /// overwritten in timepoint 3, the old value is still available at timepoint 3 |
||
445 | /// (write takes place after any read even if executed at the same timepoint) |
||
446 | /// |
||
447 | /// @param Zone { Zone[] } |
||
448 | /// @param InclStart Include timepoints adjacent to the beginning of a zone. |
||
449 | /// @param InclEnd Include timepoints adjacent to the ending of a zone. |
||
450 | /// |
||
451 | /// @return { Scatter[] } |
||
452 | isl::union_set convertZoneToTimepoints(isl::union_set Zone, bool InclStart, |
||
453 | bool InclEnd); |
||
454 | |||
455 | /// Like convertZoneToTimepoints(isl::union_set,InclStart,InclEnd), but convert |
||
456 | /// either the domain or the range of a map. |
||
457 | isl::union_map convertZoneToTimepoints(isl::union_map Zone, isl::dim Dim, |
||
458 | bool InclStart, bool InclEnd); |
||
459 | |||
460 | /// Overload of convertZoneToTimepoints(isl::map,InclStart,InclEnd) to process |
||
461 | /// only a single map. |
||
462 | isl::map convertZoneToTimepoints(isl::map Zone, isl::dim Dim, bool InclStart, |
||
463 | bool InclEnd); |
||
464 | |||
465 | /// Distribute the domain to the tuples of a wrapped range map. |
||
466 | /// |
||
467 | /// @param Map { Domain[] -> [Range1[] -> Range2[]] } |
||
468 | /// |
||
469 | /// @return { [Domain[] -> Range1[]] -> [Domain[] -> Range2[]] } |
||
470 | isl::map distributeDomain(isl::map Map); |
||
471 | |||
472 | /// Apply distributeDomain(isl::map) to each map in the union. |
||
473 | isl::union_map distributeDomain(isl::union_map UMap); |
||
474 | |||
475 | /// Prepend a space to the tuples of a map. |
||
476 | /// |
||
477 | /// @param UMap { Domain[] -> Range[] } |
||
478 | /// @param Factor { Factor[] } |
||
479 | /// |
||
480 | /// @return { [Factor[] -> Domain[]] -> [Factor[] -> Range[]] } |
||
481 | isl::union_map liftDomains(isl::union_map UMap, isl::union_set Factor); |
||
482 | |||
483 | /// Apply a map to the 'middle' of another relation. |
||
484 | /// |
||
485 | /// @param UMap { [DomainDomain[] -> DomainRange[]] -> Range[] } |
||
486 | /// @param Func { DomainRange[] -> NewDomainRange[] } |
||
487 | /// |
||
488 | /// @return { [DomainDomain[] -> NewDomainRange[]] -> Range[] } |
||
489 | isl::union_map applyDomainRange(isl::union_map UMap, isl::union_map Func); |
||
490 | |||
491 | /// Intersect the range of @p Map with @p Range. |
||
492 | /// |
||
493 | /// Since @p Map is an isl::map, the result will be a single space, even though |
||
494 | /// @p Range is an isl::union_set. This is the only difference to |
||
495 | /// isl::map::intersect_range and isl::union_map::interset_range. |
||
496 | /// |
||
497 | /// @param Map { Domain[] -> Range[] } |
||
498 | /// @param Range { Range[] } |
||
499 | /// |
||
500 | /// @return { Domain[] -> Range[] } |
||
501 | isl::map intersectRange(isl::map Map, isl::union_set Range); |
||
502 | |||
503 | /// Subtract the parameter space @p Params from @p Map. |
||
504 | /// This is akin to isl::map::intersect_params. |
||
505 | /// |
||
506 | /// Example: |
||
507 | /// subtractParams( |
||
508 | /// { [i] -> [i] }, |
||
509 | /// [x] -> { : x < 0 } |
||
510 | /// ) = [x] -> { [i] -> [i] : x >= 0 } |
||
511 | /// |
||
512 | /// @param Map Remove the conditions of @p Params from this map. |
||
513 | /// @param Params Parameter set to subtract. |
||
514 | /// |
||
515 | /// @param The map with the parameter conditions removed. |
||
516 | isl::map subtractParams(isl::map Map, isl::set Params); |
||
517 | |||
518 | /// Subtract the parameter space @p Params from @p Set. |
||
519 | isl::set subtractParams(isl::set Set, isl::set Params); |
||
520 | |||
521 | /// If @p PwAff maps to a constant, return said constant. If @p Max/@p Min, it |
||
522 | /// can also be a piecewise constant and it would return the minimum/maximum |
||
523 | /// value. Otherwise, return NaN. |
||
524 | isl::val getConstant(isl::pw_aff PwAff, bool Max, bool Min); |
||
525 | |||
526 | /// If the relation @p PwAff lies on a hyperplane where the given |
||
527 | /// dimension @p Pos with the type @p Dim has a fixed value, then |
||
528 | /// return that value. Otherwise return NaN. |
||
529 | isl::val getConstant(isl::map Map, isl::dim Dim, int Pos); |
||
530 | |||
531 | /// Check that @p End is valid and return an iterator from @p Begin to @p End |
||
532 | /// |
||
533 | /// Use case example: |
||
534 | /// for (unsigned i : rangeIslSize(0, Map.domain_tuple_dim())) |
||
535 | /// // do stuff |
||
536 | llvm::iota_range<unsigned> rangeIslSize(unsigned Begin, isl::size End); |
||
537 | |||
538 | /// Dump a description of the argument to llvm::errs(). |
||
539 | /// |
||
540 | /// In contrast to isl's dump function, there are a few differences: |
||
541 | /// - Each polyhedron (pieces) is written on its own line. |
||
542 | /// - Spaces are sorted by structure. E.g. maps with same domain space are |
||
543 | /// grouped. Isl sorts them according to the space's hash function. |
||
544 | /// - Pieces of the same space are sorted using their lower bound. |
||
545 | /// - A more compact to_str representation is used instead of Isl's dump |
||
546 | /// functions that try to show the internal representation. |
||
547 | /// |
||
548 | /// The goal is to get a better understandable representation that is also |
||
549 | /// useful to compare two sets. As all dump() functions, its intended use is to |
||
550 | /// be called in a debugger only. |
||
551 | /// |
||
552 | /// isl_map_dump example: |
||
553 | /// [p_0, p_1, p_2] -> { Stmt0[i0] -> [o0, o1] : (o0 = i0 and o1 = 0 and i0 > 0 |
||
554 | /// and i0 <= 5 - p_2) or (i0 = 0 and o0 = 0 and o1 = 0); Stmt3[i0] -> [o0, o1] |
||
555 | /// : (o0 = i0 and o1 = 3 and i0 > 0 and i0 <= 5 - p_2) or (i0 = 0 and o0 = 0 |
||
556 | /// and o1 = 3); Stmt2[i0] -> [o0, o1] : (o0 = i0 and o1 = 1 and i0 >= 3 + p_0 - |
||
557 | /// p_1 and i0 > 0 and i0 <= 5 - p_2) or (o0 = i0 and o1 = 1 and i0 > 0 and i0 |
||
558 | /// <= 5 - p_2 and i0 < p_0 - p_1) or (i0 = 0 and o0 = 0 and o1 = 1 and p_1 >= 3 |
||
559 | /// + p_0) or (i0 = 0 and o0 = 0 and o1 = 1 and p_1 < p_0) or (p_0 = 0 and i0 = |
||
560 | /// 2 - p_1 and o0 = 2 - p_1 and o1 = 1 and p_2 <= 3 + p_1 and p_1 <= 1) or (p_1 |
||
561 | /// = 1 + p_0 and i0 = 0 and o0 = 0 and o1 = 1) or (p_0 = 0 and p_1 = 2 and i0 = |
||
562 | /// 0 and o0 = 0 and o1 = 1) or (p_0 = -1 and p_1 = -1 and i0 = 0 and o0 = 0 and |
||
563 | /// o1 = 1); Stmt1[i0] -> [o0, o1] : (p_0 = -1 and i0 = 1 - p_1 and o0 = 1 - p_1 |
||
564 | /// and o1 = 2 and p_2 <= 4 + p_1 and p_1 <= 0) or (p_0 = 0 and i0 = -p_1 and o0 |
||
565 | /// = -p_1 and o1 = 2 and p_2 <= 5 + p_1 and p_1 < 0) or (p_0 = -1 and p_1 = 1 |
||
566 | /// and i0 = 0 and o0 = 0 and o1 = 2) or (p_0 = 0 and p_1 = 0 and i0 = 0 and o0 |
||
567 | /// = 0 and o1 = 2) } |
||
568 | /// |
||
569 | /// dumpPw example (same set): |
||
570 | /// [p_0, p_1, p_2] -> { |
||
571 | /// Stmt0[0] -> [0, 0]; |
||
572 | /// Stmt0[i0] -> [i0, 0] : 0 < i0 <= 5 - p_2; |
||
573 | /// Stmt1[0] -> [0, 2] : p_1 = 1 and p_0 = -1; |
||
574 | /// Stmt1[0] -> [0, 2] : p_1 = 0 and p_0 = 0; |
||
575 | /// Stmt1[1 - p_1] -> [1 - p_1, 2] : p_0 = -1 and p_1 <= 0 and p_2 <= 4 + p_1; |
||
576 | /// Stmt1[-p_1] -> [-p_1, 2] : p_0 = 0 and p_1 < 0 and p_2 <= 5 + p_1; |
||
577 | /// Stmt2[0] -> [0, 1] : p_1 >= 3 + p_0; |
||
578 | /// Stmt2[0] -> [0, 1] : p_1 < p_0; |
||
579 | /// Stmt2[0] -> [0, 1] : p_1 = 1 + p_0; |
||
580 | /// Stmt2[0] -> [0, 1] : p_1 = 2 and p_0 = 0; |
||
581 | /// Stmt2[0] -> [0, 1] : p_1 = -1 and p_0 = -1; |
||
582 | /// Stmt2[i0] -> [i0, 1] : i0 >= 3 + p_0 - p_1 and 0 < i0 <= 5 - p_2; |
||
583 | /// Stmt2[i0] -> [i0, 1] : 0 < i0 <= 5 - p_2 and i0 < p_0 - p_1; |
||
584 | /// Stmt2[2 - p_1] -> [2 - p_1, 1] : p_0 = 0 and p_1 <= 1 and p_2 <= 3 + p_1; |
||
585 | /// Stmt3[0] -> [0, 3]; |
||
586 | /// Stmt3[i0] -> [i0, 3] : 0 < i0 <= 5 - p_2 |
||
587 | /// } |
||
588 | /// @{ |
||
589 | void dumpPw(const isl::set &Set); |
||
590 | void dumpPw(const isl::map &Map); |
||
591 | void dumpPw(const isl::union_set &USet); |
||
592 | void dumpPw(const isl::union_map &UMap); |
||
593 | void dumpPw(__isl_keep isl_set *Set); |
||
594 | void dumpPw(__isl_keep isl_map *Map); |
||
595 | void dumpPw(__isl_keep isl_union_set *USet); |
||
596 | void dumpPw(__isl_keep isl_union_map *UMap); |
||
597 | /// @} |
||
598 | |||
599 | /// Dump all points of the argument to llvm::errs(). |
||
600 | /// |
||
601 | /// Before being printed by dumpPw(), the argument's pieces are expanded to |
||
602 | /// contain only single points. If a dimension is unbounded, it keeps its |
||
603 | /// representation. |
||
604 | /// |
||
605 | /// This is useful for debugging reduced cases where parameters are set to |
||
606 | /// constants to keep the example simple. Such sets can still contain |
||
607 | /// existential dimensions which makes the polyhedral hard to compare. |
||
608 | /// |
||
609 | /// Example: |
||
610 | /// { [MemRef_A[i0] -> [i1]] : (exists (e0 = floor((1 + i1)/3): i0 = 1 and 3e0 |
||
611 | /// <= i1 and 3e0 >= -1 + i1 and i1 >= 15 and i1 <= 25)) or (exists (e0 = |
||
612 | /// floor((i1)/3): i0 = 0 and 3e0 < i1 and 3e0 >= -2 + i1 and i1 > 0 and i1 <= |
||
613 | /// 11)) } |
||
614 | /// |
||
615 | /// dumpExpanded: |
||
616 | /// { |
||
617 | /// [MemRef_A[0] ->[1]]; |
||
618 | /// [MemRef_A[0] ->[2]]; |
||
619 | /// [MemRef_A[0] ->[4]]; |
||
620 | /// [MemRef_A[0] ->[5]]; |
||
621 | /// [MemRef_A[0] ->[7]]; |
||
622 | /// [MemRef_A[0] ->[8]]; |
||
623 | /// [MemRef_A[0] ->[10]]; |
||
624 | /// [MemRef_A[0] ->[11]]; |
||
625 | /// [MemRef_A[1] ->[15]]; |
||
626 | /// [MemRef_A[1] ->[16]]; |
||
627 | /// [MemRef_A[1] ->[18]]; |
||
628 | /// [MemRef_A[1] ->[19]]; |
||
629 | /// [MemRef_A[1] ->[21]]; |
||
630 | /// [MemRef_A[1] ->[22]]; |
||
631 | /// [MemRef_A[1] ->[24]]; |
||
632 | /// [MemRef_A[1] ->[25]] |
||
633 | /// } |
||
634 | /// @{ |
||
635 | void dumpExpanded(const isl::set &Set); |
||
636 | void dumpExpanded(const isl::map &Map); |
||
637 | void dumpExpanded(const isl::union_set &USet); |
||
638 | void dumpExpanded(const isl::union_map &UMap); |
||
639 | void dumpExpanded(__isl_keep isl_set *Set); |
||
640 | void dumpExpanded(__isl_keep isl_map *Map); |
||
641 | void dumpExpanded(__isl_keep isl_union_set *USet); |
||
642 | void dumpExpanded(__isl_keep isl_union_map *UMap); |
||
643 | /// @} |
||
644 | } // namespace polly |
||
645 | |||
646 | #endif /* POLLY_ISLTOOLS_H */ |