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