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 */ |