1 //===- SDBM.h - MLIR SDBM declaration ---------------------------*- 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 // A striped difference-bound matrix (SDBM) is a set in Z^N (or R^N) defined
10 // as {(x_1, ... x_n) | f(x_1, ... x_n) >= 0} where f is an SDBM expression.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef MLIR_DIALECT_SDBM_SDBM_H
15 #define MLIR_DIALECT_SDBM_SDBM_H
16 
17 #include "mlir/Support/LLVM.h"
18 #include "llvm/ADT/DenseMap.h"
19 
20 namespace mlir {
21 
22 class MLIRContext;
23 class SDBMDialect;
24 class SDBMExpr;
25 class SDBMTermExpr;
26 
27 /// A utility class for SDBM to represent an integer with potentially infinite
28 /// positive value. This uses the largest value of int64_t to represent infinity
29 /// and redefines the arithmetic operators so that the infinity "saturates":
30 ///   inf + x = inf,
31 ///   inf - x = inf.
32 /// If a sum of two finite values reaches the largest value of int64_t, the
33 /// behavior of IntInfty is undefined (in practice, it asserts), similarly to
34 /// regular signed integer overflow.
35 class IntInfty {
36 public:
37   constexpr static int64_t infty = std::numeric_limits<int64_t>::max();
38 
IntInfty(int64_t v)39   /*implicit*/ IntInfty(int64_t v) : value(v) {}
40 
41   IntInfty &operator=(int64_t v) {
42     value = v;
43     return *this;
44   }
45 
infinity()46   static IntInfty infinity() { return IntInfty(infty); }
47 
getValue()48   int64_t getValue() const { return value; }
int64_t()49   explicit operator int64_t() const { return value; }
50 
isFinite()51   bool isFinite() { return value != infty; }
52 
53 private:
54   int64_t value;
55 };
56 
57 inline IntInfty operator+(IntInfty lhs, IntInfty rhs) {
58   if (!lhs.isFinite() || !rhs.isFinite())
59     return IntInfty::infty;
60 
61   // Check for overflows, treating the sum of two values adding up to INT_MAX as
62   // overflow.  Convert values to unsigned to get an extra bit and avoid the
63   // undefined behavior of signed integer overflows.
64   assert((lhs.getValue() <= 0 || rhs.getValue() <= 0 ||
65           static_cast<uint64_t>(lhs.getValue()) +
66                   static_cast<uint64_t>(rhs.getValue()) <
67               static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) &&
68          "IntInfty overflow");
69   // Check for underflows by converting values to unsigned to avoid undefined
70   // behavior of signed integers perform the addition (bitwise result is same
71   // because numbers are required to be two's complement in C++) and check if
72   // the sign bit remains negative.
73   assert((lhs.getValue() >= 0 || rhs.getValue() >= 0 ||
74           ((static_cast<uint64_t>(lhs.getValue()) +
75             static_cast<uint64_t>(rhs.getValue())) >>
76            63) == 1) &&
77          "IntInfty underflow");
78 
79   return lhs.getValue() + rhs.getValue();
80 }
81 
82 inline bool operator<(IntInfty lhs, IntInfty rhs) {
83   return lhs.getValue() < rhs.getValue();
84 }
85 
86 inline bool operator<=(IntInfty lhs, IntInfty rhs) {
87   return lhs.getValue() <= rhs.getValue();
88 }
89 
90 inline bool operator==(IntInfty lhs, IntInfty rhs) {
91   return lhs.getValue() == rhs.getValue();
92 }
93 
94 inline bool operator!=(IntInfty lhs, IntInfty rhs) { return !(lhs == rhs); }
95 
96 /// Striped difference-bound matrix is a representation of an integer set bound
97 /// by a system of SDBMExprs interpreted as inequalities "expr <= 0".
98 class SDBM {
99 public:
100   /// Obtain an SDBM from a list of SDBM expressions treated as inequalities and
101   /// equalities with zero.
102   static SDBM get(ArrayRef<SDBMExpr> inequalities,
103                   ArrayRef<SDBMExpr> equalities);
104 
105   void getSDBMExpressions(SDBMDialect *dialect,
106                           SmallVectorImpl<SDBMExpr> &inequalities,
107                           SmallVectorImpl<SDBMExpr> &equalities);
108 
109   void print(raw_ostream &os);
110   void dump();
111 
operator()112   IntInfty operator()(int i, int j) { return at(i, j); }
113 
114 private:
115   /// Get the given element of the difference bounds matrix.  First index
116   /// corresponds to the negative term of the difference, second index
117   /// corresponds to the positive term of the difference.
at(int i,int j)118   IntInfty &at(int i, int j) { return matrix[i * getNumVariables() + j]; }
119 
120   /// Populate `inequalities` and `equalities` based on the values at(row,col)
121   /// and at(col,row) of the DBM.  Depending on the values being finite and
122   /// being subsumed by stripe expressions, this may or may not add elements to
123   /// the lists of equalities and inequalities.
124   void convertDBMElement(unsigned row, unsigned col, SDBMTermExpr rowExpr,
125                          SDBMTermExpr colExpr,
126                          SmallVectorImpl<SDBMExpr> &inequalities,
127                          SmallVectorImpl<SDBMExpr> &equalities);
128 
129   /// Populate `inequalities` based on the value at(pos,pos) of the DBM. Only
130   /// adds new inequalities if the inequality is not trivially true.
131   void convertDBMDiagonalElement(unsigned pos, SDBMTermExpr expr,
132                                  SmallVectorImpl<SDBMExpr> &inequalities);
133 
134   /// Get the total number of elements in the matrix.
getNumVariables()135   unsigned getNumVariables() const {
136     return 1 + numDims + numSymbols + numTemporaries;
137   }
138 
139   /// Get the position in the matrix that corresponds to the given dimension.
getDimPosition(unsigned position)140   unsigned getDimPosition(unsigned position) const { return 1 + position; }
141 
142   /// Get the position in the matrix that corresponds to the given symbol.
getSymbolPosition(unsigned position)143   unsigned getSymbolPosition(unsigned position) const {
144     return 1 + numDims + position;
145   }
146 
147   /// Get the position in the matrix that corresponds to the given temporary.
getTemporaryPosition(unsigned position)148   unsigned getTemporaryPosition(unsigned position) const {
149     return 1 + numDims + numSymbols + position;
150   }
151 
152   /// Number of dimensions in the system,
153   unsigned numDims;
154   /// Number of symbols in the system.
155   unsigned numSymbols;
156   /// Number of temporary variables in the system.
157   unsigned numTemporaries;
158 
159   /// Difference bounds matrix, stored as a linearized row-major vector.
160   /// Each value in this matrix corresponds to an inequality
161   ///
162   ///   v@col - v@row <= at(row, col)
163   ///
164   /// where v@col and v@row are the variables that correspond to the linearized
165   /// position in the matrix.  The positions correspond to
166   ///
167   ///   - constant 0 (producing constraints v@col <= X and -v@row <= Y);
168   ///   - SDBM expression dimensions (d0, d1, ...);
169   ///   - SDBM expression symbols (s0, s1, ...);
170   ///   - temporary variables (t0, t1, ...).
171   ///
172   /// Temporary variables are introduced to represent expressions that are not
173   /// trivially a difference between two variables.  For example, if one side of
174   /// a difference expression is itself a stripe expression, it will be replaced
175   /// with a temporary variable assigned equal to this expression.
176   ///
177   /// Infinite entries in the matrix correspond correspond to an absence of a
178   /// constraint:
179   ///
180   ///   v@col - v@row <= infinity
181   ///
182   /// is trivially true.  Negated values at symmetric positions in the matrix
183   /// allow one to couple two inequalities into a single equality.
184   std::vector<IntInfty> matrix;
185 
186   /// The mapping between the indices of variables in the DBM and the stripe
187   /// expressions they are equal to.  These expressions are stored as they
188   /// appeared when constructing an SDBM from a SDBMExprs, in particular no
189   /// temporaries can appear in these expressions.  This removes the need to
190   /// iteratively substitute definitions of the temporaries in the reverse
191   /// conversion.
192   DenseMap<unsigned, SDBMExpr> stripeToPoint;
193 };
194 
195 } // namespace mlir
196 
197 #endif // MLIR_DIALECT_SDBM_SDBM_H
198