reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303
  304
  305
  306
  307
  308
  309
  310
  311
  312
  313
  314
  315
  316
  317
  318
  319
  320
  321
  322
  323
  324
  325
  326
  327
  328
  329
  330
  331
  332
  333
  334
  335
  336
  337
  338
  339
  340
  341
  342
  343
  344
  345
  346
  347
  348
  349
  350
  351
  352
  353
  354
  355
  356
  357
  358
  359
  360
  361
  362
  363
  364
  365
  366
  367
  368
  369
  370
  371
  372
  373
  374
  375
  376
  377
  378
  379
  380
  381
  382
  383
  384
  385
  386
  387
  388
  389
  390
  391
  392
  393
  394
  395
  396
  397
  398
  399
  400
  401
  402
  403
  404
  405
  406
  407
  408
  409
  410
  411
  412
  413
  414
  415
  416
  417
  418
  419
  420
  421
  422
  423
  424
  425
  426
  427
  428
  429
  430
  431
  432
  433
  434
  435
  436
  437
  438
  439
  440
  441
  442
  443
  444
  445
  446
  447
  448
  449
  450
  451
  452
  453
  454
  455
  456
  457
  458
  459
  460
  461
  462
  463
  464
  465
  466
  467
  468
  469
  470
  471
  472
  473
  474
  475
  476
  477
  478
  479
  480
  481
  482
  483
  484
  485
  486
  487
  488
  489
  490
  491
  492
  493
  494
  495
  496
  497
  498
  499
  500
  501
  502
  503
  504
  505
  506
  507
  508
  509
  510
  511
  512
  513
  514
  515
  516
  517
  518
  519
  520
  521
  522
  523
  524
  525
  526
  527
  528
  529
  530
  531
  532
  533
  534
  535
  536
  537
  538
  539
  540
  541
  542
  543
  544
  545
  546
  547
  548
  549
  550
  551
  552
  553
  554
  555
  556
  557
  558
  559
  560
  561
  562
  563
  564
  565
  566
  567
  568
  569
  570
  571
  572
  573
  574
  575
  576
  577
  578
  579
  580
  581
  582
  583
  584
  585
  586
  587
  588
  589
  590
  591
  592
  593
  594
//===------ ISLTools.h ------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Tools, utilities, helpers and extensions useful in conjunction with the
// Integer Set Library (isl).
//
//===----------------------------------------------------------------------===//

#ifndef POLLY_ISLTOOLS_H
#define POLLY_ISLTOOLS_H

#include "llvm/ADT/iterator.h"
#include "isl/isl-noexceptions.h"

namespace isl {
inline namespace noexceptions {

template <typename ListT>
using list_element_type = decltype(std::declval<ListT>().get_at(0));

template <typename ListT>
struct isl_iterator
    : public llvm::iterator_facade_base<isl_iterator<ListT>,
                                        std::forward_iterator_tag,
                                        list_element_type<ListT>> {

  using ElementT = list_element_type<ListT>;

  explicit isl_iterator(const ListT &List)
      : List(&List), Position(List.size()) {}
  isl_iterator(const ListT &List, int Position)
      : List(&List), Position(Position) {}
  isl_iterator &operator=(const isl_iterator &R) = default;

  bool operator==(const isl_iterator &O) const {
    return List == O.List && Position == O.Position;
  }

  isl_iterator &operator++() {
    ++Position;
    return *this;
  }

  isl_iterator operator++(int) {
    isl_iterator Copy{*this};
    ++Position;
    return Copy;
  }

  ElementT operator*() const { return List->get_at(this->Position); }

protected:
  const ListT *List;
  int Position = 0;
};

template <typename T> isl_iterator<T> begin(const T &t) {
  return isl_iterator<T>(t, 0);
}
template <typename T> isl_iterator<T> end(const T &t) {
  return isl_iterator<T>(t);
}

} // namespace noexceptions
} // namespace isl

namespace polly {

/// Return the range elements that are lexicographically smaller.
///
/// @param Map    { Space[] -> Scatter[] }
/// @param Strict True for strictly lexicographically smaller elements (exclude
///               same timepoints from the result).
///
/// @return { Space[] -> Scatter[] }
///         A map to all timepoints that happen before the timepoints the input
///         mapped to.
isl::map beforeScatter(isl::map Map, bool Strict);

/// Piecewise beforeScatter(isl::map,bool).
isl::union_map beforeScatter(isl::union_map UMap, bool Strict);

/// Return the range elements that are lexicographically larger.
///
/// @param Map    { Space[] -> Scatter[] }
/// @param Strict True for strictly lexicographically larger elements (exclude
///               same timepoints from the result).
///
/// @return { Space[] -> Scatter[] }
///         A map to all timepoints that happen after the timepoints the input
///         map originally mapped to.
isl::map afterScatter(isl::map Map, bool Strict);

/// Piecewise afterScatter(isl::map,bool).
isl::union_map afterScatter(const isl::union_map &UMap, bool Strict);

/// Construct a range of timepoints between two timepoints.
///
/// Example:
/// From := { A[] -> [0]; B[] -> [0] }
/// To   := {             B[] -> [10]; C[] -> [20] }
///
/// Result:
/// { B[] -> [i] : 0 < i < 10 }
///
/// Note that A[] and C[] are not in the result because they do not have a start
/// or end timepoint. If a start (or end) timepoint is not unique, the first
/// (respectively last) is chosen.
///
/// @param From     { Space[] -> Scatter[] }
///                 Map to start timepoints.
/// @param To       { Space[] -> Scatter[] }
///                 Map to end timepoints.
/// @param InclFrom Whether to include the start timepoints in the result. In
///                 the example, this would add { B[] -> [0] }
/// @param InclTo   Whether to include the end timepoints in the result. In this
///                 example, this would add { B[] -> [10] }
///
/// @return { Space[] -> Scatter[] }
///         A map for each domain element of timepoints between two extreme
///         points, or nullptr if @p From or @p To is nullptr, or the isl max
///         operations is exceeded.
isl::map betweenScatter(isl::map From, isl::map To, bool InclFrom, bool InclTo);

/// Piecewise betweenScatter(isl::map,isl::map,bool,bool).
isl::union_map betweenScatter(isl::union_map From, isl::union_map To,
                              bool InclFrom, bool InclTo);

/// If by construction a union map is known to contain only a single map, return
/// it.
///
/// This function combines isl_map_from_union_map() and
/// isl_union_map_extract_map(). isl_map_from_union_map() fails if the map is
/// empty because it does not know which space it would be in.
/// isl_union_map_extract_map() on the other hand does not check whether there
/// is (at most) one isl_map in the union, i.e. how it has been constructed is
/// probably wrong.
isl::map singleton(isl::union_map UMap, isl::space ExpectedSpace);

/// If by construction an isl_union_set is known to contain only a single
/// isl_set, return it.
///
/// This function combines isl_set_from_union_set() and
/// isl_union_set_extract_set(). isl_map_from_union_set() fails if the set is
/// empty because it does not know which space it would be in.
/// isl_union_set_extract_set() on the other hand does not check whether there
/// is (at most) one isl_set in the union, i.e. how it has been constructed is
/// probably wrong.
isl::set singleton(isl::union_set USet, isl::space ExpectedSpace);

/// Determine how many dimensions the scatter space of @p Schedule has.
///
/// The schedule must not be empty and have equal number of dimensions of any
/// subspace it contains.
///
/// The implementation currently returns the maximum number of dimensions it
/// encounters, if different, and 0 if none is encountered. However, most other
/// code will most likely fail if one of these happen.
unsigned getNumScatterDims(const isl::union_map &Schedule);

/// Return the scatter space of a @p Schedule.
///
/// This is basically the range space of the schedule map, but harder to
/// determine because it is an isl_union_map.
isl::space getScatterSpace(const isl::union_map &Schedule);

/// Construct an identity map for the given domain values.
///
/// There is no type resembling isl_union_space, hence we have to pass an
/// isl_union_set as the map's domain and range space.
///
/// @param USet           { Space[] }
///                       The returned map's domain and range.
/// @param RestrictDomain If true, the returned map only maps elements contained
///                       in @p USet and no other. If false, it returns an
///                       overapproximation with the identity maps of any space
///                       in @p USet, not just the elements in it.
///
/// @return { Space[] -> Space[] }
///         A map that maps each value of @p USet to itself.
isl::union_map makeIdentityMap(const isl::union_set &USet, bool RestrictDomain);

/// Reverse the nested map tuple in @p Map's domain.
///
/// @param Map { [Space1[] -> Space2[]] -> Space3[] }
///
/// @return { [Space2[] -> Space1[]] -> Space3[] }
isl::map reverseDomain(isl::map Map);

/// Piecewise reverseDomain(isl::map).
isl::union_map reverseDomain(const isl::union_map &UMap);

/// Add a constant to one dimension of a set.
///
/// @param Map    The set to shift a dimension in.
/// @param Pos    The dimension to shift. If negative, the dimensions are
///               counted from the end instead from the beginning. E.g. -1 is
///               the last dimension in the tuple.
/// @param Amount The offset to add to the specified dimension.
///
/// @return The modified set.
isl::set shiftDim(isl::set Set, int Pos, int Amount);

/// Piecewise shiftDim(isl::set,int,int).
isl::union_set shiftDim(isl::union_set USet, int Pos, int Amount);

/// Add a constant to one dimension of a map.
///
/// @param Map    The map to shift a dimension in.
/// @param Type   A tuple of @p Map which contains the dimension to shift.
/// @param Pos    The dimension to shift. If negative, the dimensions are
/// counted from the end instead from the beginning. Eg. -1 is the last
/// dimension in the tuple.
/// @param Amount The offset to add to the specified dimension.
///
/// @return The modified map.
isl::map shiftDim(isl::map Map, isl::dim Dim, int Pos, int Amount);

/// Add a constant to one dimension of a each map in a union map.
///
/// @param UMap   The maps to shift a dimension in.
/// @param Type   The tuple which contains the dimension to shift.
/// @param Pos    The dimension to shift. If negative, the dimensions are
///               counted from the ends of each map of union instead from their
///               beginning. E.g. -1 is the last dimension of any map.
/// @param Amount The offset to add to the specified dimension.
///
/// @return The union of all modified maps.
isl::union_map shiftDim(isl::union_map UMap, isl::dim Dim, int Pos, int Amount);

/// Simplify a set inplace.
void simplify(isl::set &Set);

/// Simplify a union set inplace.
void simplify(isl::union_set &USet);

/// Simplify a map inplace.
void simplify(isl::map &Map);

/// Simplify a union map inplace.
void simplify(isl::union_map &UMap);

/// Compute the reaching definition statement or the next overwrite for each
/// definition of an array element.
///
/// The reaching definition of an array element at a specific timepoint is the
/// statement instance that has written the current element's content.
/// Alternatively, this function determines for each timepoint and element which
/// write is going to overwrite an element at a future timepoint. This can be
/// seen as "reaching definition in reverse" where definitions are found in the
/// past.
///
/// For example:
///
/// Schedule := { Write[] -> [0]; Overwrite[] -> [10] }
/// Defs := { Write[] -> A[5]; Overwrite[] -> A[5] }
///
/// If index 5 of array A is written at timepoint 0 and 10, the resulting
/// reaching definitions are:
///
/// { [A[5] -> [i]] -> Write[] : 0 < i < 10;
///   [A[5] -> [i]] -> Overwrite[] : 10 < i }
///
/// Between timepoint 0 (Write[]) and timepoint 10 (Overwrite[]), the
/// content of A[5] is written by statement instance Write[] and after
/// timepoint 10 by Overwrite[]. Values not defined in the map have no known
/// definition. This includes the statement instance timepoints themselves,
/// because reads at those timepoints could either read the old or the new
/// value, defined only by the statement itself. But this can be changed by @p
/// InclPrevDef and @p InclNextDef. InclPrevDef=false and InclNextDef=true
/// returns a zone. Unless @p InclPrevDef and @p InclNextDef are both true,
/// there is only one unique definition per element and timepoint.
///
/// @param Schedule    { DomainWrite[] -> Scatter[] }
///                    Schedule of (at least) all array writes. Instances not in
///                    @p Writes are ignored.
/// @param Writes      { DomainWrite[] -> Element[] }
///                    Elements written to by the statement instances.
/// @param Reverse     If true, look for definitions in the future. That is,
///                    find the write that is overwrites the current value.
/// @param InclPrevDef Include the definition's timepoint to the set of
///                    well-defined elements (any load at that timepoint happen
///                    at the writes). In the example, enabling this option adds
///                    {[A[5] -> [0]] -> Write[]; [A[5] -> [10]] -> Overwrite[]}
///                    to the result.
/// @param InclNextDef Whether to assume that at the timepoint where an element
///                    is overwritten, it still contains the old value (any load
///                    at that timepoint would happen before the overwrite). In
///                    this example, enabling this adds
///                    { [A[] -> [10]] -> Write[] } to the result.
///
/// @return { [Element[] -> Scatter[]] -> DomainWrite[] }
///         The reaching definitions or future overwrite as described above, or
///         nullptr if either @p Schedule or @p Writes is nullptr, or the isl
///         max operations count has exceeded.
isl::union_map computeReachingWrite(isl::union_map Schedule,
                                    isl::union_map Writes, bool Reverse,
                                    bool InclPrevDef, bool InclNextDef);

/// Compute the timepoints where the contents of an array element are not used.
///
/// An element is unused at a timepoint when the element is overwritten in
/// the future, but it is not read in between. Another way to express this: the
/// time from when the element is written, to the most recent read before it, or
/// infinitely into the past if there is no read before. Such unused elements
/// can be overwritten by any value without changing the scop's semantics. An
/// example:
///
/// Schedule := { Read[] -> [0]; Write[] -> [10]; Def[] -> [20] }
/// Writes := { Write[] -> A[5]; Def[] -> A[6] }
/// Reads := { Read[] -> A[5] }
///
/// The result is:
///
/// { A[5] -> [i] : 0 < i < 10;
///   A[6] -> [i] : i < 20 }
///
/// That is, A[5] is unused between timepoint 0 (the read) and timepoint 10 (the
/// write). A[6] is unused before timepoint 20, but might be used after the
/// scop's execution (A[5] and any other A[i] as well). Use InclLastRead=false
/// and InclWrite=true to interpret the result as zone.
///
/// @param Schedule          { Domain[] -> Scatter[] }
///                          The schedule of (at least) all statement instances
///                          occurring in @p Writes or @p Reads. All other
///                          instances are ignored.
/// @param Writes            { DomainWrite[] -> Element[] }
///                          Elements written to by the statement instances.
/// @param Reads             { DomainRead[] -> Element[] }
///                          Elements read from by the statement instances.
/// @param ReadEltInSameInst Whether a load reads the value from a write
///                          that is scheduled at the same timepoint (Writes
///                          happen before reads). Otherwise, loads use the
///                          value of an element that it had before the
///                          timepoint (Reads before writes). For example:
///                          { Read[] -> [0]; Write[] -> [0] }
///                          With ReadEltInSameInst=false it is assumed that the
///                          read happens before the write, such that the
///                          element is never unused, or just at timepoint 0,
///                          depending on InclLastRead/InclWrite.
///                          With ReadEltInSameInst=false it assumes that the
///                          value just written is used. Anything before
///                          timepoint 0 is considered unused.
/// @param InclLastRead      Whether a timepoint where an element is last read
///                          counts as unused (the read happens at the beginning
///                          of its timepoint, and nothing (else) can use it
///                          during the timepoint). In the example, this option
///                          adds { A[5] -> [0] } to the result.
/// @param InclWrite         Whether the timepoint where an element is written
///                          itself counts as unused (the write happens at the
///                          end of its timepoint; no (other) operations uses
///                          the element during the timepoint). In this example,
///                          this adds
///                          { A[5] -> [10]; A[6] -> [20] } to the result.
///
/// @return { Element[] -> Scatter[] }
///         The unused timepoints as defined above, or nullptr if either @p
///         Schedule, @p Writes are @p Reads is nullptr, or the ISL max
///         operations count is exceeded.
isl::union_map computeArrayUnused(isl::union_map Schedule,
                                  isl::union_map Writes, isl::union_map Reads,
                                  bool ReadEltInSameInst, bool InclLastRead,
                                  bool InclWrite);

/// Convert a zone (range between timepoints) to timepoints.
///
/// A zone represents the time between (integer) timepoints, but not the
/// timepoints themselves. This function can be used to determine whether a
/// timepoint lies within a zone.
///
/// For instance, the range (1,3), representing the time between 1 and 3, is
/// represented by the zone
///
/// { [i] : 1 < i <= 3 }
///
/// The set of timepoints that lie completely within this range is
///
/// { [i] : 1 < i < 3 }
///
/// A typical use-case is the range in which a value written by a store is
/// available until it is overwritten by another value. If the write is at
/// timepoint 1 and its value is overwritten by another value at timepoint 3,
/// the value is available between those timepoints: timepoint 2 in this
/// example.
///
///
/// When InclStart is true, the range is interpreted left-inclusive, i.e. adds
/// the timepoint 1 to the result:
///
/// { [i] : 1 <= i < 3 }
///
/// In the use-case mentioned above that means that the value written at
/// timepoint 1 is already available in timepoint 1 (write takes place before
/// any read of it even if executed at the same timepoint)
///
/// When InclEnd is true, the range is interpreted right-inclusive, i.e. adds
/// the timepoint 3 to the result:
///
/// { [i] : 1 < i <= 3 }
///
/// In the use-case mentioned above that means that although the value is
/// overwritten in timepoint 3, the old value is still available at timepoint 3
/// (write takes place after any read even if executed at the same timepoint)
///
/// @param Zone      { Zone[] }
/// @param InclStart Include timepoints adjacent to the beginning of a zone.
/// @param InclEnd   Include timepoints adjacent to the ending of a zone.
///
/// @return { Scatter[] }
isl::union_set convertZoneToTimepoints(isl::union_set Zone, bool InclStart,
                                       bool InclEnd);

/// Like convertZoneToTimepoints(isl::union_set,InclStart,InclEnd), but convert
/// either the domain or the range of a map.
isl::union_map convertZoneToTimepoints(isl::union_map Zone, isl::dim Dim,
                                       bool InclStart, bool InclEnd);

/// Overload of convertZoneToTimepoints(isl::map,InclStart,InclEnd) to process
/// only a single map.
isl::map convertZoneToTimepoints(isl::map Zone, isl::dim Dim, bool InclStart,
                                 bool InclEnd);

/// Distribute the domain to the tuples of a wrapped range map.
///
/// @param Map { Domain[] -> [Range1[] -> Range2[]] }
///
/// @return { [Domain[] -> Range1[]] -> [Domain[] -> Range2[]] }
isl::map distributeDomain(isl::map Map);

/// Apply distributeDomain(isl::map) to each map in the union.
isl::union_map distributeDomain(isl::union_map UMap);

/// Prepend a space to the tuples of a map.
///
/// @param UMap   { Domain[] -> Range[] }
/// @param Factor { Factor[] }
///
/// @return { [Factor[] -> Domain[]] -> [Factor[] -> Range[]] }
isl::union_map liftDomains(isl::union_map UMap, isl::union_set Factor);

/// Apply a map to the 'middle' of another relation.
///
/// @param UMap { [DomainDomain[] -> DomainRange[]] -> Range[] }
/// @param Func { DomainRange[] -> NewDomainRange[] }
///
/// @return { [DomainDomain[] -> NewDomainRange[]] -> Range[] }
isl::union_map applyDomainRange(isl::union_map UMap, isl::union_map Func);

/// Intersect the range of @p Map with @p Range.
///
/// Since @p Map is an isl::map, the result will be a single space, even though
/// @p Range is an isl::union_set. This is the only difference to
/// isl::map::intersect_range and isl::union_map::interset_range.
///
/// @param Map   { Domain[] -> Range[] }
/// @param Range { Range[] }
///
/// @return { Domain[] -> Range[] }
isl::map intersectRange(isl::map Map, isl::union_set Range);

/// Subtract the parameter space @p Params from @p Map.
/// This is akin to isl::map::intersect_params.
///
/// Example:
///   subtractParams(
///     { [i] -> [i] },
///     [x] -> { : x < 0 }
///   ) = [x] -> { [i] -> [i] : x >= 0 }
///
/// @param Map    Remove the conditions of @p Params from this map.
/// @param Params Parameter set to subtract.
///
/// @param The map with the parameter conditions removed.
isl::map subtractParams(isl::map Map, isl::set Params);

/// If @p PwAff maps to a constant, return said constant. If @p Max/@p Min, it
/// can also be a piecewise constant and it would return the minimum/maximum
/// value. Otherwise, return NaN.
isl::val getConstant(isl::pw_aff PwAff, bool Max, bool Min);

/// Dump a description of the argument to llvm::errs().
///
/// In contrast to isl's dump function, there are a few differences:
/// - Each polyhedron (pieces) is written on its own line.
/// - Spaces are sorted by structure. E.g. maps with same domain space are
///   grouped. Isl sorts them according to the space's hash function.
/// - Pieces of the same space are sorted using their lower bound.
/// - A more compact to_str representation is used instead of Isl's dump
///   functions that try to show the internal representation.
///
/// The goal is to get a better understandable representation that is also
/// useful to compare two sets. As all dump() functions, its intended use is to
/// be called in a debugger only.
///
/// isl_map_dump example:
/// [p_0, p_1, p_2] -> { Stmt0[i0] -> [o0, o1] : (o0 = i0 and o1 = 0 and i0 > 0
/// and i0 <= 5 - p_2) or (i0 = 0 and o0 = 0 and o1 = 0); Stmt3[i0] -> [o0, o1]
/// : (o0 = i0 and o1 = 3 and i0 > 0 and i0 <= 5 - p_2) or (i0 = 0 and o0 = 0
/// and o1 = 3); Stmt2[i0] -> [o0, o1] : (o0 = i0 and o1 = 1 and i0 >= 3 + p_0 -
/// p_1 and i0 > 0 and i0 <= 5 - p_2) or (o0 = i0 and o1 = 1 and i0 > 0 and i0
/// <= 5 - p_2 and i0 < p_0 - p_1) or (i0 = 0 and o0 = 0 and o1 = 1 and p_1 >= 3
/// + p_0) or (i0 = 0 and o0 = 0 and o1 = 1 and p_1 < p_0) or (p_0 = 0 and i0 =
/// 2 - p_1 and o0 = 2 - p_1 and o1 = 1 and p_2 <= 3 + p_1 and p_1 <= 1) or (p_1
/// = 1 + p_0 and i0 = 0 and o0 = 0 and o1 = 1) or (p_0 = 0 and p_1 = 2 and i0 =
/// 0 and o0 = 0 and o1 = 1) or (p_0 = -1 and p_1 = -1 and i0 = 0 and o0 = 0 and
/// o1 = 1); Stmt1[i0] -> [o0, o1] : (p_0 = -1 and i0 = 1 - p_1 and o0 = 1 - p_1
/// and o1 = 2 and p_2 <= 4 + p_1 and p_1 <= 0) or (p_0 = 0 and i0 = -p_1 and o0
/// = -p_1 and o1 = 2 and p_2 <= 5 + p_1 and p_1 < 0) or (p_0 = -1 and p_1 = 1
/// and i0 = 0 and o0 = 0 and o1 = 2) or (p_0 = 0 and p_1 = 0 and i0 = 0 and o0
/// = 0 and o1 = 2) }
///
/// dumpPw example (same set):
/// [p_0, p_1, p_2] -> {
///   Stmt0[0] -> [0, 0];
///   Stmt0[i0] -> [i0, 0] : 0 < i0 <= 5 - p_2;
///   Stmt1[0] -> [0, 2] : p_1 = 1 and p_0 = -1;
///   Stmt1[0] -> [0, 2] : p_1 = 0 and p_0 = 0;
///   Stmt1[1 - p_1] -> [1 - p_1, 2] : p_0 = -1 and p_1 <= 0 and p_2 <= 4 + p_1;
///   Stmt1[-p_1] -> [-p_1, 2] : p_0 = 0 and p_1 < 0 and p_2 <= 5 + p_1;
///   Stmt2[0] -> [0, 1] : p_1 >= 3 + p_0;
///   Stmt2[0] -> [0, 1] : p_1 < p_0;
///   Stmt2[0] -> [0, 1] : p_1 = 1 + p_0;
///   Stmt2[0] -> [0, 1] : p_1 = 2 and p_0 = 0;
///   Stmt2[0] -> [0, 1] : p_1 = -1 and p_0 = -1;
///   Stmt2[i0] -> [i0, 1] : i0 >= 3 + p_0 - p_1 and 0 < i0 <= 5 - p_2;
///   Stmt2[i0] -> [i0, 1] : 0 < i0 <= 5 - p_2 and i0 < p_0 - p_1;
///   Stmt2[2 - p_1] -> [2 - p_1, 1] : p_0 = 0 and p_1 <= 1 and p_2 <= 3 + p_1;
///   Stmt3[0] -> [0, 3];
///   Stmt3[i0] -> [i0, 3] : 0 < i0 <= 5 - p_2
/// }
/// @{
void dumpPw(const isl::set &Set);
void dumpPw(const isl::map &Map);
void dumpPw(const isl::union_set &USet);
void dumpPw(const isl::union_map &UMap);
void dumpPw(__isl_keep isl_set *Set);
void dumpPw(__isl_keep isl_map *Map);
void dumpPw(__isl_keep isl_union_set *USet);
void dumpPw(__isl_keep isl_union_map *UMap);
/// @}

/// Dump all points of the argument to llvm::errs().
///
/// Before being printed by dumpPw(), the argument's pieces are expanded to
/// contain only single points. If a dimension is unbounded, it keeps its
/// representation.
///
/// This is useful for debugging reduced cases where parameters are set to
/// constants to keep the example simple. Such sets can still contain
/// existential dimensions which makes the polyhedral hard to compare.
///
/// Example:
///   { [MemRef_A[i0] -> [i1]] : (exists (e0 = floor((1 + i1)/3): i0 = 1 and 3e0
///   <= i1 and 3e0 >= -1 + i1 and i1 >= 15 and i1 <= 25)) or (exists (e0 =
///   floor((i1)/3): i0 = 0 and 3e0 < i1 and 3e0 >= -2 + i1 and i1 > 0 and i1 <=
///   11)) }
///
/// dumpExpanded:
/// {
///   [MemRef_A[0] ->[1]];
///   [MemRef_A[0] ->[2]];
///   [MemRef_A[0] ->[4]];
///   [MemRef_A[0] ->[5]];
///   [MemRef_A[0] ->[7]];
///   [MemRef_A[0] ->[8]];
///   [MemRef_A[0] ->[10]];
///   [MemRef_A[0] ->[11]];
///   [MemRef_A[1] ->[15]];
///   [MemRef_A[1] ->[16]];
///   [MemRef_A[1] ->[18]];
///   [MemRef_A[1] ->[19]];
///   [MemRef_A[1] ->[21]];
///   [MemRef_A[1] ->[22]];
///   [MemRef_A[1] ->[24]];
///   [MemRef_A[1] ->[25]]
/// }
/// @{
void dumpExpanded(const isl::set &Set);
void dumpExpanded(const isl::map &Map);
void dumpExpanded(const isl::union_set &USet);
void dumpExpanded(const isl::union_map &UMap);
void dumpExpanded(__isl_keep isl_set *Set);
void dumpExpanded(__isl_keep isl_map *Map);
void dumpExpanded(__isl_keep isl_union_set *USet);
void dumpExpanded(__isl_keep isl_union_map *UMap);
/// @}
} // namespace polly

#endif /* POLLY_ISLTOOLS_H */