xref: /llvm-project/mlir/lib/Analysis/Presburger/IntegerRelation.cpp (revision 2740273505ab27c0d8531d35948f0647309842cd)
1bb901355SGroverkss //===- IntegerRelation.cpp - MLIR IntegerRelation Class ---------------===//
2bb901355SGroverkss //
3bb901355SGroverkss // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bb901355SGroverkss // See https://llvm.org/LICENSE.txt for license information.
5bb901355SGroverkss // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bb901355SGroverkss //
7bb901355SGroverkss //===----------------------------------------------------------------------===//
8bb901355SGroverkss //
9bb901355SGroverkss // A class to represent an relation over integer tuples. A relation is
10bb901355SGroverkss // represented as a constraint system over a space of tuples of integer valued
11d95140a5SGroverkss // variables supporting symbolic variables and existential quantification.
12bb901355SGroverkss //
13bb901355SGroverkss //===----------------------------------------------------------------------===//
14bb901355SGroverkss 
15bb901355SGroverkss #include "mlir/Analysis/Presburger/IntegerRelation.h"
162ee87cd6SMehdi Amini #include "mlir/Analysis/Presburger/Fraction.h"
17bb901355SGroverkss #include "mlir/Analysis/Presburger/LinearTransform.h"
1879ad5fb2SArjun P #include "mlir/Analysis/Presburger/PWMAFunction.h"
19ff1d9a4bSGroverkss #include "mlir/Analysis/Presburger/PresburgerRelation.h"
202ee87cd6SMehdi Amini #include "mlir/Analysis/Presburger/PresburgerSpace.h"
21bb901355SGroverkss #include "mlir/Analysis/Presburger/Simplex.h"
22bb901355SGroverkss #include "mlir/Analysis/Presburger/Utils.h"
23bb901355SGroverkss #include "llvm/ADT/DenseMap.h"
24bb901355SGroverkss #include "llvm/ADT/DenseSet.h"
252ee87cd6SMehdi Amini #include "llvm/ADT/STLExtras.h"
26562790f3SAbhinav271828 #include "llvm/ADT/Sequence.h"
272ee87cd6SMehdi Amini #include "llvm/ADT/SmallBitVector.h"
28bb901355SGroverkss #include "llvm/Support/Debug.h"
29f819302aSRamkumar Ramachandra #include "llvm/Support/LogicalResult.h"
302ee87cd6SMehdi Amini #include "llvm/Support/raw_ostream.h"
312ee87cd6SMehdi Amini #include <algorithm>
322ee87cd6SMehdi Amini #include <cassert>
332ee87cd6SMehdi Amini #include <functional>
342ee87cd6SMehdi Amini #include <memory>
35*27402735SAmy Wang #include <numeric>
36a1fe1f5fSKazu Hirata #include <optional>
37*27402735SAmy Wang #include <sstream>
38*27402735SAmy Wang #include <string>
392ee87cd6SMehdi Amini #include <utility>
402ee87cd6SMehdi Amini #include <vector>
41bb901355SGroverkss 
42bb901355SGroverkss #define DEBUG_TYPE "presburger"
43bb901355SGroverkss 
44bb901355SGroverkss using namespace mlir;
45bb901355SGroverkss using namespace presburger;
46bb901355SGroverkss 
47bb901355SGroverkss using llvm::SmallDenseMap;
48bb901355SGroverkss using llvm::SmallDenseSet;
49bb901355SGroverkss 
50bb901355SGroverkss std::unique_ptr<IntegerRelation> IntegerRelation::clone() const {
51bb901355SGroverkss   return std::make_unique<IntegerRelation>(*this);
52bb901355SGroverkss }
53bb901355SGroverkss 
54bb901355SGroverkss std::unique_ptr<IntegerPolyhedron> IntegerPolyhedron::clone() const {
55bb901355SGroverkss   return std::make_unique<IntegerPolyhedron>(*this);
56bb901355SGroverkss }
57bb901355SGroverkss 
588a7ead69SArjun P void IntegerRelation::setSpace(const PresburgerSpace &oSpace) {
59d95140a5SGroverkss   assert(space.getNumVars() == oSpace.getNumVars() && "invalid space!");
608a7ead69SArjun P   space = oSpace;
618a7ead69SArjun P }
628a7ead69SArjun P 
638a7ead69SArjun P void IntegerRelation::setSpaceExceptLocals(const PresburgerSpace &oSpace) {
64d95140a5SGroverkss   assert(oSpace.getNumLocalVars() == 0 && "no locals should be present!");
65d95140a5SGroverkss   assert(oSpace.getNumVars() <= getNumVars() && "invalid space!");
66d95140a5SGroverkss   unsigned newNumLocals = getNumVars() - oSpace.getNumVars();
678a7ead69SArjun P   space = oSpace;
68d95140a5SGroverkss   space.insertVar(VarKind::Local, 0, newNumLocals);
698a7ead69SArjun P }
708a7ead69SArjun P 
71d70bfeb4SBharathi Ramana Joshi void IntegerRelation::setId(VarKind kind, unsigned i, Identifier id) {
72d70bfeb4SBharathi Ramana Joshi   assert(space.isUsingIds() &&
73d70bfeb4SBharathi Ramana Joshi          "space must be using identifiers to set an identifier");
74d70bfeb4SBharathi Ramana Joshi   assert(kind != VarKind::Local && "local variables cannot have identifiers");
75d70bfeb4SBharathi Ramana Joshi   assert(i < space.getNumVarKind(kind) && "invalid variable index");
7624da7fa0SBharathi Ramana Joshi   space.setId(kind, i, id);
7724da7fa0SBharathi Ramana Joshi }
7824da7fa0SBharathi Ramana Joshi 
7924da7fa0SBharathi Ramana Joshi ArrayRef<Identifier> IntegerRelation::getIds(VarKind kind) {
8024da7fa0SBharathi Ramana Joshi   if (!space.isUsingIds())
8124da7fa0SBharathi Ramana Joshi     space.resetIds();
8224da7fa0SBharathi Ramana Joshi   return space.getIds(kind);
83d70bfeb4SBharathi Ramana Joshi }
84d70bfeb4SBharathi Ramana Joshi 
85bb901355SGroverkss void IntegerRelation::append(const IntegerRelation &other) {
8620aedb14SGroverkss   assert(space.isEqual(other.getSpace()) && "Spaces must be equal.");
87bb901355SGroverkss 
88bb901355SGroverkss   inequalities.reserveRows(inequalities.getNumRows() +
89bb901355SGroverkss                            other.getNumInequalities());
90bb901355SGroverkss   equalities.reserveRows(equalities.getNumRows() + other.getNumEqualities());
91bb901355SGroverkss 
92bb901355SGroverkss   for (unsigned r = 0, e = other.getNumInequalities(); r < e; r++) {
93bb901355SGroverkss     addInequality(other.getInequality(r));
94bb901355SGroverkss   }
95bb901355SGroverkss   for (unsigned r = 0, e = other.getNumEqualities(); r < e; r++) {
96bb901355SGroverkss     addEquality(other.getEquality(r));
97bb901355SGroverkss   }
98bb901355SGroverkss }
99bb901355SGroverkss 
100b68e78ceSArjun P IntegerRelation IntegerRelation::intersect(IntegerRelation other) const {
101b68e78ceSArjun P   IntegerRelation result = *this;
102d95140a5SGroverkss   result.mergeLocalVars(other);
103b68e78ceSArjun P   result.append(other);
104b68e78ceSArjun P   return result;
105b68e78ceSArjun P }
106b68e78ceSArjun P 
107bb901355SGroverkss bool IntegerRelation::isEqual(const IntegerRelation &other) const {
1088eebb47fSGroverkss   assert(space.isCompatible(other.getSpace()) && "Spaces must be compatible.");
109ff1d9a4bSGroverkss   return PresburgerRelation(*this).isEqual(PresburgerRelation(other));
110bb901355SGroverkss }
111bb901355SGroverkss 
11239b93955Sgilsaia bool IntegerRelation::isObviouslyEqual(const IntegerRelation &other) const {
113f40af3b3Sgilsaia   if (!space.isEqual(other.getSpace()))
114f40af3b3Sgilsaia     return false;
115f40af3b3Sgilsaia   if (getNumEqualities() != other.getNumEqualities())
116f40af3b3Sgilsaia     return false;
117f40af3b3Sgilsaia   if (getNumInequalities() != other.getNumInequalities())
118f40af3b3Sgilsaia     return false;
119f40af3b3Sgilsaia 
120f40af3b3Sgilsaia   unsigned cols = getNumCols();
121f40af3b3Sgilsaia   for (unsigned i = 0, eqs = getNumEqualities(); i < eqs; ++i) {
122f40af3b3Sgilsaia     for (unsigned j = 0; j < cols; ++j) {
123f40af3b3Sgilsaia       if (atEq(i, j) != other.atEq(i, j))
124f40af3b3Sgilsaia         return false;
125f40af3b3Sgilsaia     }
126f40af3b3Sgilsaia   }
127f40af3b3Sgilsaia   for (unsigned i = 0, ineqs = getNumInequalities(); i < ineqs; ++i) {
128f40af3b3Sgilsaia     for (unsigned j = 0; j < cols; ++j) {
129f40af3b3Sgilsaia       if (atIneq(i, j) != other.atIneq(i, j))
130f40af3b3Sgilsaia         return false;
131f40af3b3Sgilsaia     }
132f40af3b3Sgilsaia   }
133f40af3b3Sgilsaia   return true;
134f40af3b3Sgilsaia }
135f40af3b3Sgilsaia 
136bb901355SGroverkss bool IntegerRelation::isSubsetOf(const IntegerRelation &other) const {
1378eebb47fSGroverkss   assert(space.isCompatible(other.getSpace()) && "Spaces must be compatible.");
138ff1d9a4bSGroverkss   return PresburgerRelation(*this).isSubsetOf(PresburgerRelation(other));
139bb901355SGroverkss }
140bb901355SGroverkss 
141bb901355SGroverkss MaybeOptimum<SmallVector<Fraction, 8>>
142bb901355SGroverkss IntegerRelation::findRationalLexMin() const {
143d95140a5SGroverkss   assert(getNumSymbolVars() == 0 && "Symbols are not supported!");
144bb901355SGroverkss   MaybeOptimum<SmallVector<Fraction, 8>> maybeLexMin =
145bb901355SGroverkss       LexSimplex(*this).findRationalLexMin();
146bb901355SGroverkss 
147bb901355SGroverkss   if (!maybeLexMin.isBounded())
148bb901355SGroverkss     return maybeLexMin;
149bb901355SGroverkss 
150bb901355SGroverkss   // The Simplex returns the lexmin over all the variables including locals. But
151bb901355SGroverkss   // locals are not actually part of the space and should not be returned in the
152d95140a5SGroverkss   // result. Since the locals are placed last in the list of variables, they
153bb901355SGroverkss   // will be minimized last in the lexmin. So simply truncating out the locals
154bb901355SGroverkss   // from the end of the answer gives the desired lexmin over the dimensions.
155d95140a5SGroverkss   assert(maybeLexMin->size() == getNumVars() &&
156bb901355SGroverkss          "Incorrect number of vars in lexMin!");
157d95140a5SGroverkss   maybeLexMin->resize(getNumDimAndSymbolVars());
158bb901355SGroverkss   return maybeLexMin;
159bb901355SGroverkss }
160bb901355SGroverkss 
1611a0e67d7SRamkumar Ramachandra MaybeOptimum<SmallVector<DynamicAPInt, 8>>
1621a0e67d7SRamkumar Ramachandra IntegerRelation::findIntegerLexMin() const {
163d95140a5SGroverkss   assert(getNumSymbolVars() == 0 && "Symbols are not supported!");
1641a0e67d7SRamkumar Ramachandra   MaybeOptimum<SmallVector<DynamicAPInt, 8>> maybeLexMin =
165bb901355SGroverkss       LexSimplex(*this).findIntegerLexMin();
166bb901355SGroverkss 
167bb901355SGroverkss   if (!maybeLexMin.isBounded())
168bb901355SGroverkss     return maybeLexMin.getKind();
169bb901355SGroverkss 
170bb901355SGroverkss   // The Simplex returns the lexmin over all the variables including locals. But
171bb901355SGroverkss   // locals are not actually part of the space and should not be returned in the
172d95140a5SGroverkss   // result. Since the locals are placed last in the list of variables, they
173bb901355SGroverkss   // will be minimized last in the lexmin. So simply truncating out the locals
174bb901355SGroverkss   // from the end of the answer gives the desired lexmin over the dimensions.
175d95140a5SGroverkss   assert(maybeLexMin->size() == getNumVars() &&
176bb901355SGroverkss          "Incorrect number of vars in lexMin!");
177d95140a5SGroverkss   maybeLexMin->resize(getNumDimAndSymbolVars());
178bb901355SGroverkss   return maybeLexMin;
179bb901355SGroverkss }
180bb901355SGroverkss 
1811a0e67d7SRamkumar Ramachandra static bool rangeIsZero(ArrayRef<DynamicAPInt> range) {
1821a0e67d7SRamkumar Ramachandra   return llvm::all_of(range, [](const DynamicAPInt &x) { return x == 0; });
1838a67c6eeSArjun P }
1848a67c6eeSArjun P 
185d95140a5SGroverkss static void removeConstraintsInvolvingVarRange(IntegerRelation &poly,
186d95140a5SGroverkss                                                unsigned begin, unsigned count) {
1878a67c6eeSArjun P   // We loop until i > 0 and index into i - 1 to avoid sign issues.
1888a67c6eeSArjun P   //
1898a67c6eeSArjun P   // We iterate backwards so that whether we remove constraint i - 1 or not, the
1908a67c6eeSArjun P   // next constraint to be tested is always i - 2.
1918a67c6eeSArjun P   for (unsigned i = poly.getNumEqualities(); i > 0; i--)
1928a67c6eeSArjun P     if (!rangeIsZero(poly.getEquality(i - 1).slice(begin, count)))
1938a67c6eeSArjun P       poly.removeEquality(i - 1);
1948a67c6eeSArjun P   for (unsigned i = poly.getNumInequalities(); i > 0; i--)
1958a67c6eeSArjun P     if (!rangeIsZero(poly.getInequality(i - 1).slice(begin, count)))
1968a67c6eeSArjun P       poly.removeInequality(i - 1);
1978a67c6eeSArjun P }
19893b9f50bSArjun P 
19993b9f50bSArjun P IntegerRelation::CountsSnapshot IntegerRelation::getCounts() const {
20020aedb14SGroverkss   return {getSpace(), getNumInequalities(), getNumEqualities()};
20120aedb14SGroverkss }
20220aedb14SGroverkss 
203d95140a5SGroverkss void IntegerRelation::truncateVarKind(VarKind kind, unsigned num) {
204d95140a5SGroverkss   unsigned curNum = getNumVarKind(kind);
205d95140a5SGroverkss   assert(num <= curNum && "Can't truncate to more vars!");
206d95140a5SGroverkss   removeVarRange(kind, num, curNum);
20793b9f50bSArjun P }
20893b9f50bSArjun P 
209d95140a5SGroverkss void IntegerRelation::truncateVarKind(VarKind kind,
21093b9f50bSArjun P                                       const CountsSnapshot &counts) {
211d95140a5SGroverkss   truncateVarKind(kind, counts.getSpace().getNumVarKind(kind));
21293b9f50bSArjun P }
21393b9f50bSArjun P 
21493b9f50bSArjun P void IntegerRelation::truncate(const CountsSnapshot &counts) {
215d95140a5SGroverkss   truncateVarKind(VarKind::Domain, counts);
216d95140a5SGroverkss   truncateVarKind(VarKind::Range, counts);
217d95140a5SGroverkss   truncateVarKind(VarKind::Symbol, counts);
218d95140a5SGroverkss   truncateVarKind(VarKind::Local, counts);
21993b9f50bSArjun P   removeInequalityRange(counts.getNumIneqs(), getNumInequalities());
2209615d717SArjun P   removeEqualityRange(counts.getNumEqs(), getNumEqualities());
22193b9f50bSArjun P }
22293b9f50bSArjun P 
223dda8b1ceSArjun P PresburgerRelation IntegerRelation::computeReprWithOnlyDivLocals() const {
2248a7ead69SArjun P   // If there are no locals, we're done.
225d95140a5SGroverkss   if (getNumLocalVars() == 0)
226dda8b1ceSArjun P     return PresburgerRelation(*this);
2278a7ead69SArjun P 
2288a7ead69SArjun P   // Move all the non-div locals to the end, as the current API to
22956863adfSiambrj   // SymbolicLexOpt requires these to form a contiguous range.
2308a7ead69SArjun P   //
2318a7ead69SArjun P   // Take a copy so we can perform mutations.
232dda8b1ceSArjun P   IntegerRelation copy = *this;
233479c4f64SGroverkss   std::vector<MaybeLocalRepr> reprs(getNumLocalVars());
234479c4f64SGroverkss   copy.getLocalReprs(&reprs);
2358a7ead69SArjun P 
2368a7ead69SArjun P   // Iterate through all the locals. The last `numNonDivLocals` are the locals
2378a7ead69SArjun P   // that have been scanned already and do not have division representations.
2388a7ead69SArjun P   unsigned numNonDivLocals = 0;
239d95140a5SGroverkss   unsigned offset = copy.getVarKindOffset(VarKind::Local);
240d95140a5SGroverkss   for (unsigned i = 0, e = copy.getNumLocalVars(); i < e - numNonDivLocals;) {
2418a7ead69SArjun P     if (!reprs[i]) {
2428a7ead69SArjun P       // Whenever we come across a local that does not have a division
2438a7ead69SArjun P       // representation, we swap it to the `numNonDivLocals`-th last position
2448a7ead69SArjun P       // and increment `numNonDivLocal`s. `reprs` also needs to be swapped.
245d95140a5SGroverkss       copy.swapVar(offset + i, offset + e - numNonDivLocals - 1);
2468a7ead69SArjun P       std::swap(reprs[i], reprs[e - numNonDivLocals - 1]);
2478a7ead69SArjun P       ++numNonDivLocals;
2488a7ead69SArjun P       continue;
2498a7ead69SArjun P     }
2508a7ead69SArjun P     ++i;
2518a7ead69SArjun P   }
2528a7ead69SArjun P 
2538a7ead69SArjun P   // If there are no non-div locals, we're done.
2548a7ead69SArjun P   if (numNonDivLocals == 0)
255dda8b1ceSArjun P     return PresburgerRelation(*this);
2568a7ead69SArjun P 
2578a7ead69SArjun P   // We computeSymbolicIntegerLexMin by considering the non-div locals as
2588a7ead69SArjun P   // "non-symbols" and considering everything else as "symbols". This will
2598a7ead69SArjun P   // compute a function mapping assignments to "symbols" to the
2608a7ead69SArjun P   // lexicographically minimal valid assignment of "non-symbols", when a
2618a7ead69SArjun P   // satisfying assignment exists. It separately returns the set of assignments
2628a7ead69SArjun P   // to the "symbols" such that a satisfying assignment to the "non-symbols"
2638a7ead69SArjun P   // exists but the lexmin is unbounded. We basically want to find the set of
2648a7ead69SArjun P   // values of the "symbols" such that an assignment to the "non-symbols"
2658a7ead69SArjun P   // exists, which is the union of the domain of the returned lexmin function
2668a7ead69SArjun P   // and the returned set of assignments to the "symbols" that makes the lexmin
2678a7ead69SArjun P   // unbounded.
26856863adfSiambrj   SymbolicLexOpt lexminResult =
2698a7ead69SArjun P       SymbolicLexSimplex(copy, /*symbolOffset*/ 0,
2708a7ead69SArjun P                          IntegerPolyhedron(PresburgerSpace::getSetSpace(
271d95140a5SGroverkss                              /*numDims=*/copy.getNumVars() - numNonDivLocals)))
2728a7ead69SArjun P           .computeSymbolicIntegerLexMin();
273206a6037SBenjamin Kramer   PresburgerRelation result =
27456863adfSiambrj       lexminResult.lexopt.getDomain().unionSet(lexminResult.unboundedDomain);
2758a7ead69SArjun P 
2768a7ead69SArjun P   // The result set might lie in the wrong space -- all its ids are dims.
2778a7ead69SArjun P   // Set it to the desired space and return.
2788a7ead69SArjun P   PresburgerSpace space = getSpace();
279d95140a5SGroverkss   space.removeVarRange(VarKind::Local, 0, getNumLocalVars());
2808a7ead69SArjun P   result.setSpace(space);
2818a7ead69SArjun P   return result;
2828a7ead69SArjun P }
2838a7ead69SArjun P 
28456863adfSiambrj SymbolicLexOpt IntegerRelation::findSymbolicIntegerLexMin() const {
285c4abef28SArjun P   // Symbol and Domain vars will be used as symbols for symbolic lexmin.
286c4abef28SArjun P   // In other words, for every value of the symbols and domain, return the
287c4abef28SArjun P   // lexmin value of the (range, locals).
288c4abef28SArjun P   llvm::SmallBitVector isSymbol(getNumVars(), false);
289c4abef28SArjun P   isSymbol.set(getVarKindOffset(VarKind::Symbol),
290c4abef28SArjun P                getVarKindEnd(VarKind::Symbol));
291c4abef28SArjun P   isSymbol.set(getVarKindOffset(VarKind::Domain),
292c4abef28SArjun P                getVarKindEnd(VarKind::Domain));
29379ad5fb2SArjun P   // Compute the symbolic lexmin of the dims and locals, with the symbols being
29479ad5fb2SArjun P   // the actual symbols of this set.
295bb2226acSGroverkss   // The resultant space of lexmin is the space of the relation itself.
29656863adfSiambrj   SymbolicLexOpt result =
297c4abef28SArjun P       SymbolicLexSimplex(*this,
298c4abef28SArjun P                          IntegerPolyhedron(PresburgerSpace::getSetSpace(
299c4abef28SArjun P                              /*numDims=*/getNumDomainVars(),
300c4abef28SArjun P                              /*numSymbols=*/getNumSymbolVars())),
301c4abef28SArjun P                          isSymbol)
30279ad5fb2SArjun P           .computeSymbolicIntegerLexMin();
30379ad5fb2SArjun P 
30479ad5fb2SArjun P   // We want to return only the lexmin over the dims, so strip the locals from
30579ad5fb2SArjun P   // the computed lexmin.
30656863adfSiambrj   result.lexopt.removeOutputs(result.lexopt.getNumOutputs() - getNumLocalVars(),
30756863adfSiambrj                               result.lexopt.getNumOutputs());
30879ad5fb2SArjun P   return result;
30979ad5fb2SArjun P }
31079ad5fb2SArjun P 
31156863adfSiambrj /// findSymbolicIntegerLexMax is implemented using findSymbolicIntegerLexMin as
31256863adfSiambrj /// follows:
31356863adfSiambrj /// 1. A new relation is created which is `this` relation with the sign of
31456863adfSiambrj /// each dimension variable in range flipped;
31556863adfSiambrj /// 2. findSymbolicIntegerLexMin is called on the range negated relation to
31656863adfSiambrj /// compute the negated lexmax of `this` relation;
31756863adfSiambrj /// 3. The sign of the negated lexmax is flipped and returned.
31856863adfSiambrj SymbolicLexOpt IntegerRelation::findSymbolicIntegerLexMax() const {
31956863adfSiambrj   IntegerRelation flippedRel = *this;
32056863adfSiambrj   // Flip range sign by flipping the sign of range variables in all constraints.
32156863adfSiambrj   for (unsigned j = getNumDomainVars(),
32256863adfSiambrj                 b = getNumDomainVars() + getNumRangeVars();
32356863adfSiambrj        j < b; j++) {
32456863adfSiambrj     for (unsigned i = 0, a = getNumEqualities(); i < a; i++)
32556863adfSiambrj       flippedRel.atEq(i, j) = -1 * atEq(i, j);
32656863adfSiambrj     for (unsigned i = 0, a = getNumInequalities(); i < a; i++)
32756863adfSiambrj       flippedRel.atIneq(i, j) = -1 * atIneq(i, j);
32856863adfSiambrj   }
32956863adfSiambrj   // Compute negated lexmax by computing lexmin.
33056863adfSiambrj   SymbolicLexOpt flippedSymbolicIntegerLexMax =
33156863adfSiambrj                      flippedRel.findSymbolicIntegerLexMin(),
33256863adfSiambrj                  symbolicIntegerLexMax(
33356863adfSiambrj                      flippedSymbolicIntegerLexMax.lexopt.getSpace());
33456863adfSiambrj   // Get lexmax by flipping range sign in the PWMA constraints.
33556863adfSiambrj   for (auto &flippedPiece :
33656863adfSiambrj        flippedSymbolicIntegerLexMax.lexopt.getAllPieces()) {
337c1b99746SAbhinav271828     IntMatrix mat = flippedPiece.output.getOutputMatrix();
33856863adfSiambrj     for (unsigned i = 0, e = mat.getNumRows(); i < e; i++)
33956863adfSiambrj       mat.negateRow(i);
34056863adfSiambrj     MultiAffineFunction maf(flippedPiece.output.getSpace(), mat);
34156863adfSiambrj     PWMAFunction::Piece piece = {flippedPiece.domain, maf};
34256863adfSiambrj     symbolicIntegerLexMax.lexopt.addPiece(piece);
34356863adfSiambrj   }
34456863adfSiambrj   symbolicIntegerLexMax.unboundedDomain =
34556863adfSiambrj       flippedSymbolicIntegerLexMax.unboundedDomain;
34656863adfSiambrj   return symbolicIntegerLexMax;
34756863adfSiambrj }
34856863adfSiambrj 
349a18f843fSGroverkss PresburgerRelation
350a18f843fSGroverkss IntegerRelation::subtract(const PresburgerRelation &set) const {
351a18f843fSGroverkss   return PresburgerRelation(*this).subtract(set);
352a18f843fSGroverkss }
353a18f843fSGroverkss 
354d95140a5SGroverkss unsigned IntegerRelation::insertVar(VarKind kind, unsigned pos, unsigned num) {
355d95140a5SGroverkss   assert(pos <= getNumVarKind(kind));
356bb901355SGroverkss 
357d95140a5SGroverkss   unsigned insertPos = space.insertVar(kind, pos, num);
358bb901355SGroverkss   inequalities.insertColumns(insertPos, num);
359bb901355SGroverkss   equalities.insertColumns(insertPos, num);
360bb901355SGroverkss   return insertPos;
361bb901355SGroverkss }
362bb901355SGroverkss 
363d95140a5SGroverkss unsigned IntegerRelation::appendVar(VarKind kind, unsigned num) {
364d95140a5SGroverkss   unsigned pos = getNumVarKind(kind);
365d95140a5SGroverkss   return insertVar(kind, pos, num);
366bb901355SGroverkss }
367bb901355SGroverkss 
3681a0e67d7SRamkumar Ramachandra void IntegerRelation::addEquality(ArrayRef<DynamicAPInt> eq) {
369bb901355SGroverkss   assert(eq.size() == getNumCols());
370bb901355SGroverkss   unsigned row = equalities.appendExtraRow();
371bb901355SGroverkss   for (unsigned i = 0, e = eq.size(); i < e; ++i)
372bb901355SGroverkss     equalities(row, i) = eq[i];
373bb901355SGroverkss }
374bb901355SGroverkss 
3751a0e67d7SRamkumar Ramachandra void IntegerRelation::addInequality(ArrayRef<DynamicAPInt> inEq) {
376bb901355SGroverkss   assert(inEq.size() == getNumCols());
377bb901355SGroverkss   unsigned row = inequalities.appendExtraRow();
378bb901355SGroverkss   for (unsigned i = 0, e = inEq.size(); i < e; ++i)
379bb901355SGroverkss     inequalities(row, i) = inEq[i];
380bb901355SGroverkss }
381bb901355SGroverkss 
382d95140a5SGroverkss void IntegerRelation::removeVar(VarKind kind, unsigned pos) {
383d95140a5SGroverkss   removeVarRange(kind, pos, pos + 1);
384bb901355SGroverkss }
385bb901355SGroverkss 
386d95140a5SGroverkss void IntegerRelation::removeVar(unsigned pos) { removeVarRange(pos, pos + 1); }
387bb901355SGroverkss 
388d95140a5SGroverkss void IntegerRelation::removeVarRange(VarKind kind, unsigned varStart,
389d95140a5SGroverkss                                      unsigned varLimit) {
390d95140a5SGroverkss   assert(varLimit <= getNumVarKind(kind));
391c896e654SGroverkss 
392d95140a5SGroverkss   if (varStart >= varLimit)
393c896e654SGroverkss     return;
394c896e654SGroverkss 
395d95140a5SGroverkss   // Remove eliminated variables from the constraints.
396d95140a5SGroverkss   unsigned offset = getVarKindOffset(kind);
397d95140a5SGroverkss   equalities.removeColumns(offset + varStart, varLimit - varStart);
398d95140a5SGroverkss   inequalities.removeColumns(offset + varStart, varLimit - varStart);
399c896e654SGroverkss 
400d95140a5SGroverkss   // Remove eliminated variables from the space.
401d95140a5SGroverkss   space.removeVarRange(kind, varStart, varLimit);
402bb901355SGroverkss }
403bb901355SGroverkss 
404d95140a5SGroverkss void IntegerRelation::removeVarRange(unsigned varStart, unsigned varLimit) {
405d95140a5SGroverkss   assert(varLimit <= getNumVars());
406bb901355SGroverkss 
407d95140a5SGroverkss   if (varStart >= varLimit)
408c896e654SGroverkss     return;
409c896e654SGroverkss 
410d95140a5SGroverkss   // Helper function to remove vars of the specified kind in the given range
411c896e654SGroverkss   // [start, limit), The range is absolute (i.e. it is not relative to the kind
412d95140a5SGroverkss   // of variable). Also updates `limit` to reflect the deleted variables.
413d95140a5SGroverkss   auto removeVarKindInRange = [this](VarKind kind, unsigned &start,
414c896e654SGroverkss                                      unsigned &limit) {
415c896e654SGroverkss     if (start >= limit)
416c896e654SGroverkss       return;
417c896e654SGroverkss 
418d95140a5SGroverkss     unsigned offset = getVarKindOffset(kind);
419d95140a5SGroverkss     unsigned num = getNumVarKind(kind);
420c896e654SGroverkss 
421c896e654SGroverkss     // Get `start`, `limit` relative to the specified kind.
422c896e654SGroverkss     unsigned relativeStart =
423c896e654SGroverkss         start <= offset ? 0 : std::min(num, start - offset);
424c896e654SGroverkss     unsigned relativeLimit =
425c896e654SGroverkss         limit <= offset ? 0 : std::min(num, limit - offset);
426c896e654SGroverkss 
427d95140a5SGroverkss     // Remove vars of the specified kind in the relative range.
428d95140a5SGroverkss     removeVarRange(kind, relativeStart, relativeLimit);
429c896e654SGroverkss 
430d95140a5SGroverkss     // Update `limit` to reflect deleted variables.
431d95140a5SGroverkss     // `start` does not need to be updated because any variables that are
432c896e654SGroverkss     // deleted are after position `start`.
433c896e654SGroverkss     limit -= relativeLimit - relativeStart;
434c896e654SGroverkss   };
435c896e654SGroverkss 
436d95140a5SGroverkss   removeVarKindInRange(VarKind::Domain, varStart, varLimit);
437d95140a5SGroverkss   removeVarKindInRange(VarKind::Range, varStart, varLimit);
438d95140a5SGroverkss   removeVarKindInRange(VarKind::Symbol, varStart, varLimit);
439d95140a5SGroverkss   removeVarKindInRange(VarKind::Local, varStart, varLimit);
440bb901355SGroverkss }
441bb901355SGroverkss 
442bb901355SGroverkss void IntegerRelation::removeEquality(unsigned pos) {
443bb901355SGroverkss   equalities.removeRow(pos);
444bb901355SGroverkss }
445bb901355SGroverkss 
446bb901355SGroverkss void IntegerRelation::removeInequality(unsigned pos) {
447bb901355SGroverkss   inequalities.removeRow(pos);
448bb901355SGroverkss }
449bb901355SGroverkss 
450bb901355SGroverkss void IntegerRelation::removeEqualityRange(unsigned start, unsigned end) {
451bb901355SGroverkss   if (start >= end)
452bb901355SGroverkss     return;
453bb901355SGroverkss   equalities.removeRows(start, end - start);
454bb901355SGroverkss }
455bb901355SGroverkss 
456bb901355SGroverkss void IntegerRelation::removeInequalityRange(unsigned start, unsigned end) {
457bb901355SGroverkss   if (start >= end)
458bb901355SGroverkss     return;
459bb901355SGroverkss   inequalities.removeRows(start, end - start);
460bb901355SGroverkss }
461bb901355SGroverkss 
462d95140a5SGroverkss void IntegerRelation::swapVar(unsigned posA, unsigned posB) {
463d95140a5SGroverkss   assert(posA < getNumVars() && "invalid position A");
464d95140a5SGroverkss   assert(posB < getNumVars() && "invalid position B");
465bb901355SGroverkss 
466bb901355SGroverkss   if (posA == posB)
467bb901355SGroverkss     return;
468bb901355SGroverkss 
4698d7c9798SBharathi Ramana Joshi   VarKind kindA = space.getVarKindAt(posA);
4708d7c9798SBharathi Ramana Joshi   VarKind kindB = space.getVarKindAt(posB);
4718d7c9798SBharathi Ramana Joshi   unsigned relativePosA = posA - getVarKindOffset(kindA);
4728d7c9798SBharathi Ramana Joshi   unsigned relativePosB = posB - getVarKindOffset(kindB);
4738d7c9798SBharathi Ramana Joshi   space.swapVar(kindA, kindB, relativePosA, relativePosB);
4748d7c9798SBharathi Ramana Joshi 
475bb901355SGroverkss   inequalities.swapColumns(posA, posB);
476bb901355SGroverkss   equalities.swapColumns(posA, posB);
477bb901355SGroverkss }
478bb901355SGroverkss 
479bb901355SGroverkss void IntegerRelation::clearConstraints() {
480bb901355SGroverkss   equalities.resizeVertically(0);
481bb901355SGroverkss   inequalities.resizeVertically(0);
482bb901355SGroverkss }
483bb901355SGroverkss 
484d95140a5SGroverkss /// Gather all lower and upper bounds of the variable at `pos`, and
485bb901355SGroverkss /// optionally any equalities on it. In addition, the bounds are to be
486d95140a5SGroverkss /// independent of variables in position range [`offset`, `offset` + `num`).
487bb901355SGroverkss void IntegerRelation::getLowerAndUpperBoundIndices(
488bb901355SGroverkss     unsigned pos, SmallVectorImpl<unsigned> *lbIndices,
489bb901355SGroverkss     SmallVectorImpl<unsigned> *ubIndices, SmallVectorImpl<unsigned> *eqIndices,
490bb901355SGroverkss     unsigned offset, unsigned num) const {
491d95140a5SGroverkss   assert(pos < getNumVars() && "invalid position");
492bb901355SGroverkss   assert(offset + num < getNumCols() && "invalid range");
493bb901355SGroverkss 
494d95140a5SGroverkss   // Checks for a constraint that has a non-zero coeff for the variables in
495bb901355SGroverkss   // the position range [offset, offset + num) while ignoring `pos`.
496bb901355SGroverkss   auto containsConstraintDependentOnRange = [&](unsigned r, bool isEq) {
497bb901355SGroverkss     unsigned c, f;
498bb901355SGroverkss     auto cst = isEq ? getEquality(r) : getInequality(r);
499bb901355SGroverkss     for (c = offset, f = offset + num; c < f; ++c) {
500bb901355SGroverkss       if (c == pos)
501bb901355SGroverkss         continue;
502bb901355SGroverkss       if (cst[c] != 0)
503bb901355SGroverkss         break;
504bb901355SGroverkss     }
505bb901355SGroverkss     return c < f;
506bb901355SGroverkss   };
507bb901355SGroverkss 
508bb901355SGroverkss   // Gather all lower bounds and upper bounds of the variable. Since the
509bb901355SGroverkss   // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower
510bb901355SGroverkss   // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1.
511bb901355SGroverkss   for (unsigned r = 0, e = getNumInequalities(); r < e; r++) {
512bb901355SGroverkss     // The bounds are to be independent of [offset, offset + num) columns.
513bb901355SGroverkss     if (containsConstraintDependentOnRange(r, /*isEq=*/false))
514bb901355SGroverkss       continue;
515bb901355SGroverkss     if (atIneq(r, pos) >= 1) {
516bb901355SGroverkss       // Lower bound.
517266a5a9cSRamkumar Ramachandra       lbIndices->emplace_back(r);
518bb901355SGroverkss     } else if (atIneq(r, pos) <= -1) {
519bb901355SGroverkss       // Upper bound.
520266a5a9cSRamkumar Ramachandra       ubIndices->emplace_back(r);
521bb901355SGroverkss     }
522bb901355SGroverkss   }
523bb901355SGroverkss 
524bb901355SGroverkss   // An equality is both a lower and upper bound. Record any equalities
525d95140a5SGroverkss   // involving the pos^th variable.
526bb901355SGroverkss   if (!eqIndices)
527bb901355SGroverkss     return;
528bb901355SGroverkss 
529bb901355SGroverkss   for (unsigned r = 0, e = getNumEqualities(); r < e; r++) {
530bb901355SGroverkss     if (atEq(r, pos) == 0)
531bb901355SGroverkss       continue;
532bb901355SGroverkss     if (containsConstraintDependentOnRange(r, /*isEq=*/true))
533bb901355SGroverkss       continue;
534266a5a9cSRamkumar Ramachandra     eqIndices->emplace_back(r);
535bb901355SGroverkss   }
536bb901355SGroverkss }
537bb901355SGroverkss 
538bb901355SGroverkss bool IntegerRelation::hasConsistentState() const {
539bb901355SGroverkss   if (!inequalities.hasConsistentState())
540bb901355SGroverkss     return false;
541bb901355SGroverkss   if (!equalities.hasConsistentState())
542bb901355SGroverkss     return false;
543bb901355SGroverkss   return true;
544bb901355SGroverkss }
545bb901355SGroverkss 
5461a0e67d7SRamkumar Ramachandra void IntegerRelation::setAndEliminate(unsigned pos,
5471a0e67d7SRamkumar Ramachandra                                       ArrayRef<DynamicAPInt> values) {
548bb901355SGroverkss   if (values.empty())
549bb901355SGroverkss     return;
550d95140a5SGroverkss   assert(pos + values.size() <= getNumVars() &&
551bb901355SGroverkss          "invalid position or too many values");
552bb901355SGroverkss   // Setting x_j = p in sum_i a_i x_i + c is equivalent to adding p*a_j to the
553d95140a5SGroverkss   // constant term and removing the var x_j. We do this for all the vars
554bb901355SGroverkss   // pos, pos + 1, ... pos + values.size() - 1.
555bb901355SGroverkss   unsigned constantColPos = getNumCols() - 1;
556bb901355SGroverkss   for (unsigned i = 0, numVals = values.size(); i < numVals; ++i)
557bb901355SGroverkss     inequalities.addToColumn(i + pos, constantColPos, values[i]);
558bb901355SGroverkss   for (unsigned i = 0, numVals = values.size(); i < numVals; ++i)
559bb901355SGroverkss     equalities.addToColumn(i + pos, constantColPos, values[i]);
560d95140a5SGroverkss   removeVarRange(pos, pos + values.size());
561bb901355SGroverkss }
562bb901355SGroverkss 
563bb901355SGroverkss void IntegerRelation::clearAndCopyFrom(const IntegerRelation &other) {
564bb901355SGroverkss   *this = other;
565bb901355SGroverkss }
566bb901355SGroverkss 
567bb901355SGroverkss // Searches for a constraint with a non-zero coefficient at `colIdx` in
568bb901355SGroverkss // equality (isEq=true) or inequality (isEq=false) constraints.
569bb901355SGroverkss // Returns true and sets row found in search in `rowIdx`, false otherwise.
570bb901355SGroverkss bool IntegerRelation::findConstraintWithNonZeroAt(unsigned colIdx, bool isEq,
571bb901355SGroverkss                                                   unsigned *rowIdx) const {
572bb901355SGroverkss   assert(colIdx < getNumCols() && "position out of bounds");
5731a0e67d7SRamkumar Ramachandra   auto at = [&](unsigned rowIdx) -> DynamicAPInt {
574bb901355SGroverkss     return isEq ? atEq(rowIdx, colIdx) : atIneq(rowIdx, colIdx);
575bb901355SGroverkss   };
576bb901355SGroverkss   unsigned e = isEq ? getNumEqualities() : getNumInequalities();
577bb901355SGroverkss   for (*rowIdx = 0; *rowIdx < e; ++(*rowIdx)) {
578bb901355SGroverkss     if (at(*rowIdx) != 0) {
579bb901355SGroverkss       return true;
580bb901355SGroverkss     }
581bb901355SGroverkss   }
582bb901355SGroverkss   return false;
583bb901355SGroverkss }
584bb901355SGroverkss 
585bb901355SGroverkss void IntegerRelation::normalizeConstraintsByGCD() {
586bb901355SGroverkss   for (unsigned i = 0, e = getNumEqualities(); i < e; ++i)
587bb901355SGroverkss     equalities.normalizeRow(i);
588bb901355SGroverkss   for (unsigned i = 0, e = getNumInequalities(); i < e; ++i)
589bb901355SGroverkss     inequalities.normalizeRow(i);
590bb901355SGroverkss }
591bb901355SGroverkss 
592bb901355SGroverkss bool IntegerRelation::hasInvalidConstraint() const {
593bb901355SGroverkss   assert(hasConsistentState());
594bb901355SGroverkss   auto check = [&](bool isEq) -> bool {
595bb901355SGroverkss     unsigned numCols = getNumCols();
596bb901355SGroverkss     unsigned numRows = isEq ? getNumEqualities() : getNumInequalities();
597bb901355SGroverkss     for (unsigned i = 0, e = numRows; i < e; ++i) {
598bb901355SGroverkss       unsigned j;
599bb901355SGroverkss       for (j = 0; j < numCols - 1; ++j) {
6001a0e67d7SRamkumar Ramachandra         DynamicAPInt v = isEq ? atEq(i, j) : atIneq(i, j);
601bb901355SGroverkss         // Skip rows with non-zero variable coefficients.
602bb901355SGroverkss         if (v != 0)
603bb901355SGroverkss           break;
604bb901355SGroverkss       }
605bb901355SGroverkss       if (j < numCols - 1) {
606bb901355SGroverkss         continue;
607bb901355SGroverkss       }
608bb901355SGroverkss       // Check validity of constant term at 'numCols - 1' w.r.t 'isEq'.
609bb901355SGroverkss       // Example invalid constraints include: '1 == 0' or '-1 >= 0'
6101a0e67d7SRamkumar Ramachandra       DynamicAPInt v = isEq ? atEq(i, numCols - 1) : atIneq(i, numCols - 1);
611bb901355SGroverkss       if ((isEq && v != 0) || (!isEq && v < 0)) {
612bb901355SGroverkss         return true;
613bb901355SGroverkss       }
614bb901355SGroverkss     }
615bb901355SGroverkss     return false;
616bb901355SGroverkss   };
617bb901355SGroverkss   if (check(/*isEq=*/true))
618bb901355SGroverkss     return true;
619bb901355SGroverkss   return check(/*isEq=*/false);
620bb901355SGroverkss }
621bb901355SGroverkss 
622d95140a5SGroverkss /// Eliminate variable from constraint at `rowIdx` based on coefficient at
623bb901355SGroverkss /// pivotRow, pivotCol. Columns in range [elimColStart, pivotCol) will not be
624bb901355SGroverkss /// updated as they have already been eliminated.
625bb901355SGroverkss static void eliminateFromConstraint(IntegerRelation *constraints,
626bb901355SGroverkss                                     unsigned rowIdx, unsigned pivotRow,
627bb901355SGroverkss                                     unsigned pivotCol, unsigned elimColStart,
628bb901355SGroverkss                                     bool isEq) {
629bb901355SGroverkss   // Skip if equality 'rowIdx' if same as 'pivotRow'.
630bb901355SGroverkss   if (isEq && rowIdx == pivotRow)
631bb901355SGroverkss     return;
6321a0e67d7SRamkumar Ramachandra   auto at = [&](unsigned i, unsigned j) -> DynamicAPInt {
633bb901355SGroverkss     return isEq ? constraints->atEq(i, j) : constraints->atIneq(i, j);
634bb901355SGroverkss   };
6351a0e67d7SRamkumar Ramachandra   DynamicAPInt leadCoeff = at(rowIdx, pivotCol);
636bb901355SGroverkss   // Skip if leading coefficient at 'rowIdx' is already zero.
637bb901355SGroverkss   if (leadCoeff == 0)
638bb901355SGroverkss     return;
6391a0e67d7SRamkumar Ramachandra   DynamicAPInt pivotCoeff = constraints->atEq(pivotRow, pivotCol);
6406d6f6c4dSArjun P   int sign = (leadCoeff * pivotCoeff > 0) ? -1 : 1;
6411a0e67d7SRamkumar Ramachandra   DynamicAPInt lcm = llvm::lcm(pivotCoeff, leadCoeff);
6421a0e67d7SRamkumar Ramachandra   DynamicAPInt pivotMultiplier = sign * (lcm / abs(pivotCoeff));
6431a0e67d7SRamkumar Ramachandra   DynamicAPInt rowMultiplier = lcm / abs(leadCoeff);
644bb901355SGroverkss 
645bb901355SGroverkss   unsigned numCols = constraints->getNumCols();
646bb901355SGroverkss   for (unsigned j = 0; j < numCols; ++j) {
647bb901355SGroverkss     // Skip updating column 'j' if it was just eliminated.
648bb901355SGroverkss     if (j >= elimColStart && j < pivotCol)
649bb901355SGroverkss       continue;
6501a0e67d7SRamkumar Ramachandra     DynamicAPInt v = pivotMultiplier * constraints->atEq(pivotRow, j) +
651bb901355SGroverkss                      rowMultiplier * at(rowIdx, j);
652bb901355SGroverkss     isEq ? constraints->atEq(rowIdx, j) = v
653bb901355SGroverkss          : constraints->atIneq(rowIdx, j) = v;
654bb901355SGroverkss   }
655bb901355SGroverkss }
656bb901355SGroverkss 
657d95140a5SGroverkss /// Returns the position of the variable that has the minimum <number of lower
658bb901355SGroverkss /// bounds> times <number of upper bounds> from the specified range of
659d95140a5SGroverkss /// variables [start, end). It is often best to eliminate in the increasing
660bb901355SGroverkss /// order of these counts when doing Fourier-Motzkin elimination since FM adds
661bb901355SGroverkss /// that many new constraints.
662d95140a5SGroverkss static unsigned getBestVarToEliminate(const IntegerRelation &cst,
663d95140a5SGroverkss                                       unsigned start, unsigned end) {
664d95140a5SGroverkss   assert(start < cst.getNumVars() && end < cst.getNumVars() + 1);
665bb901355SGroverkss 
666bb901355SGroverkss   auto getProductOfNumLowerUpperBounds = [&](unsigned pos) {
667bb901355SGroverkss     unsigned numLb = 0;
668bb901355SGroverkss     unsigned numUb = 0;
669bb901355SGroverkss     for (unsigned r = 0, e = cst.getNumInequalities(); r < e; r++) {
670bb901355SGroverkss       if (cst.atIneq(r, pos) > 0) {
671bb901355SGroverkss         ++numLb;
672bb901355SGroverkss       } else if (cst.atIneq(r, pos) < 0) {
673bb901355SGroverkss         ++numUb;
674bb901355SGroverkss       }
675bb901355SGroverkss     }
676bb901355SGroverkss     return numLb * numUb;
677bb901355SGroverkss   };
678bb901355SGroverkss 
679bb901355SGroverkss   unsigned minLoc = start;
680bb901355SGroverkss   unsigned min = getProductOfNumLowerUpperBounds(start);
681bb901355SGroverkss   for (unsigned c = start + 1; c < end; c++) {
682bb901355SGroverkss     unsigned numLbUbProduct = getProductOfNumLowerUpperBounds(c);
683bb901355SGroverkss     if (numLbUbProduct < min) {
684bb901355SGroverkss       min = numLbUbProduct;
685bb901355SGroverkss       minLoc = c;
686bb901355SGroverkss     }
687bb901355SGroverkss   }
688bb901355SGroverkss   return minLoc;
689bb901355SGroverkss }
690bb901355SGroverkss 
691d95140a5SGroverkss // Checks for emptiness of the set by eliminating variables successively and
692bb901355SGroverkss // using the GCD test (on all equality constraints) and checking for trivially
693bb901355SGroverkss // invalid constraints. Returns 'true' if the constraint system is found to be
694bb901355SGroverkss // empty; false otherwise.
695bb901355SGroverkss bool IntegerRelation::isEmpty() const {
696bb901355SGroverkss   if (isEmptyByGCDTest() || hasInvalidConstraint())
697bb901355SGroverkss     return true;
698bb901355SGroverkss 
699bb901355SGroverkss   IntegerRelation tmpCst(*this);
700bb901355SGroverkss 
701bb901355SGroverkss   // First, eliminate as many local variables as possible using equalities.
702bb901355SGroverkss   tmpCst.removeRedundantLocalVars();
703bb901355SGroverkss   if (tmpCst.isEmptyByGCDTest() || tmpCst.hasInvalidConstraint())
704bb901355SGroverkss     return true;
705bb901355SGroverkss 
706d95140a5SGroverkss   // Eliminate as many variables as possible using Gaussian elimination.
707bb901355SGroverkss   unsigned currentPos = 0;
708d95140a5SGroverkss   while (currentPos < tmpCst.getNumVars()) {
709d95140a5SGroverkss     tmpCst.gaussianEliminateVars(currentPos, tmpCst.getNumVars());
710bb901355SGroverkss     ++currentPos;
711bb901355SGroverkss     // We check emptiness through trivial checks after eliminating each ID to
712bb901355SGroverkss     // detect emptiness early. Since the checks isEmptyByGCDTest() and
713bb901355SGroverkss     // hasInvalidConstraint() are linear time and single sweep on the constraint
714bb901355SGroverkss     // buffer, this appears reasonable - but can optimize in the future.
715bb901355SGroverkss     if (tmpCst.hasInvalidConstraint() || tmpCst.isEmptyByGCDTest())
716bb901355SGroverkss       return true;
717bb901355SGroverkss   }
718bb901355SGroverkss 
719bb901355SGroverkss   // Eliminate the remaining using FM.
720d95140a5SGroverkss   for (unsigned i = 0, e = tmpCst.getNumVars(); i < e; i++) {
721bb901355SGroverkss     tmpCst.fourierMotzkinEliminate(
722d95140a5SGroverkss         getBestVarToEliminate(tmpCst, 0, tmpCst.getNumVars()));
723bb901355SGroverkss     // Check for a constraint explosion. This rarely happens in practice, but
724bb901355SGroverkss     // this check exists as a safeguard against improperly constructed
725bb901355SGroverkss     // constraint systems or artificially created arbitrarily complex systems
726bb901355SGroverkss     // that aren't the intended use case for IntegerRelation. This is
727bb901355SGroverkss     // needed since FM has a worst case exponential complexity in theory.
728d95140a5SGroverkss     if (tmpCst.getNumConstraints() >= kExplosionFactor * getNumVars()) {
729bb901355SGroverkss       LLVM_DEBUG(llvm::dbgs() << "FM constraint explosion detected\n");
730bb901355SGroverkss       return false;
731bb901355SGroverkss     }
732bb901355SGroverkss 
733bb901355SGroverkss     // FM wouldn't have modified the equalities in any way. So no need to again
734bb901355SGroverkss     // run GCD test. Check for trivial invalid constraints.
735bb901355SGroverkss     if (tmpCst.hasInvalidConstraint())
736bb901355SGroverkss       return true;
737bb901355SGroverkss   }
738bb901355SGroverkss   return false;
739bb901355SGroverkss }
740bb901355SGroverkss 
74139b93955Sgilsaia bool IntegerRelation::isObviouslyEmpty() const {
7421837579bSMehdi Amini   return isEmptyByGCDTest() || hasInvalidConstraint();
74339b93955Sgilsaia }
74439b93955Sgilsaia 
745bb901355SGroverkss // Runs the GCD test on all equality constraints. Returns 'true' if this test
746bb901355SGroverkss // fails on any equality. Returns 'false' otherwise.
747bb901355SGroverkss // This test can be used to disprove the existence of a solution. If it returns
748bb901355SGroverkss // true, no integer solution to the equality constraints can exist.
749bb901355SGroverkss //
750bb901355SGroverkss // GCD test definition:
751bb901355SGroverkss //
752bb901355SGroverkss // The equality constraint:
753bb901355SGroverkss //
754bb901355SGroverkss //  c_1*x_1 + c_2*x_2 + ... + c_n*x_n = c_0
755bb901355SGroverkss //
756bb901355SGroverkss // has an integer solution iff:
757bb901355SGroverkss //
758bb901355SGroverkss //  GCD of c_1, c_2, ..., c_n divides c_0.
759bb901355SGroverkss bool IntegerRelation::isEmptyByGCDTest() const {
760bb901355SGroverkss   assert(hasConsistentState());
761bb901355SGroverkss   unsigned numCols = getNumCols();
762bb901355SGroverkss   for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) {
7631a0e67d7SRamkumar Ramachandra     DynamicAPInt gcd = abs(atEq(i, 0));
764bb901355SGroverkss     for (unsigned j = 1; j < numCols - 1; ++j) {
7651a0e67d7SRamkumar Ramachandra       gcd = llvm::gcd(gcd, abs(atEq(i, j)));
766bb901355SGroverkss     }
7671a0e67d7SRamkumar Ramachandra     DynamicAPInt v = abs(atEq(i, numCols - 1));
768bb901355SGroverkss     if (gcd > 0 && (v % gcd != 0)) {
769bb901355SGroverkss       return true;
770bb901355SGroverkss     }
771bb901355SGroverkss   }
772bb901355SGroverkss   return false;
773bb901355SGroverkss }
774bb901355SGroverkss 
775bb901355SGroverkss // Returns a matrix where each row is a vector along which the polytope is
776bb901355SGroverkss // bounded. The span of the returned vectors is guaranteed to contain all
777bb901355SGroverkss // such vectors. The returned vectors are NOT guaranteed to be linearly
778bb901355SGroverkss // independent. This function should not be called on empty sets.
779bb901355SGroverkss //
780bb901355SGroverkss // It is sufficient to check the perpendiculars of the constraints, as the set
781bb901355SGroverkss // of perpendiculars which are bounded must span all bounded directions.
782c1b99746SAbhinav271828 IntMatrix IntegerRelation::getBoundedDirections() const {
783bb901355SGroverkss   // Note that it is necessary to add the equalities too (which the constructor
784bb901355SGroverkss   // does) even though we don't need to check if they are bounded; whether an
785bb901355SGroverkss   // inequality is bounded or not depends on what other constraints, including
786bb901355SGroverkss   // equalities, are present.
787bb901355SGroverkss   Simplex simplex(*this);
788bb901355SGroverkss 
789bb901355SGroverkss   assert(!simplex.isEmpty() && "It is not meaningful to ask whether a "
790bb901355SGroverkss                                "direction is bounded in an empty set.");
791bb901355SGroverkss 
792bb901355SGroverkss   SmallVector<unsigned, 8> boundedIneqs;
793bb901355SGroverkss   // The constructor adds the inequalities to the simplex first, so this
794bb901355SGroverkss   // processes all the inequalities.
795bb901355SGroverkss   for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) {
796bb901355SGroverkss     if (simplex.isBoundedAlongConstraint(i))
797266a5a9cSRamkumar Ramachandra       boundedIneqs.emplace_back(i);
798bb901355SGroverkss   }
799bb901355SGroverkss 
800bb901355SGroverkss   // The direction vector is given by the coefficients and does not include the
801bb901355SGroverkss   // constant term, so the matrix has one fewer column.
802bb901355SGroverkss   unsigned dirsNumCols = getNumCols() - 1;
803c1b99746SAbhinav271828   IntMatrix dirs(boundedIneqs.size() + getNumEqualities(), dirsNumCols);
804bb901355SGroverkss 
805bb901355SGroverkss   // Copy the bounded inequalities.
806bb901355SGroverkss   unsigned row = 0;
807bb901355SGroverkss   for (unsigned i : boundedIneqs) {
808bb901355SGroverkss     for (unsigned col = 0; col < dirsNumCols; ++col)
809bb901355SGroverkss       dirs(row, col) = atIneq(i, col);
810bb901355SGroverkss     ++row;
811bb901355SGroverkss   }
812bb901355SGroverkss 
813bb901355SGroverkss   // Copy the equalities. All the equalities' perpendiculars are bounded.
814bb901355SGroverkss   for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) {
815bb901355SGroverkss     for (unsigned col = 0; col < dirsNumCols; ++col)
816bb901355SGroverkss       dirs(row, col) = atEq(i, col);
817bb901355SGroverkss     ++row;
818bb901355SGroverkss   }
819bb901355SGroverkss 
820bb901355SGroverkss   return dirs;
821bb901355SGroverkss }
822bb901355SGroverkss 
823d66cbc56SKazu Hirata bool IntegerRelation::isIntegerEmpty() const { return !findIntegerSample(); }
824bb901355SGroverkss 
825bb901355SGroverkss /// Let this set be S. If S is bounded then we directly call into the GBR
826bb901355SGroverkss /// sampling algorithm. Otherwise, there are some unbounded directions, i.e.,
827bb901355SGroverkss /// vectors v such that S extends to infinity along v or -v. In this case we
828bb901355SGroverkss /// use an algorithm described in the integer set library (isl) manual and used
829bb901355SGroverkss /// by the isl_set_sample function in that library. The algorithm is:
830bb901355SGroverkss ///
831bb901355SGroverkss /// 1) Apply a unimodular transform T to S to obtain S*T, such that all
832bb901355SGroverkss /// dimensions in which S*T is bounded lie in the linear span of a prefix of the
833bb901355SGroverkss /// dimensions.
834bb901355SGroverkss ///
835bb901355SGroverkss /// 2) Construct a set B by removing all constraints that involve
836bb901355SGroverkss /// the unbounded dimensions and then deleting the unbounded dimensions. Note
837bb901355SGroverkss /// that B is a Bounded set.
838bb901355SGroverkss ///
839bb901355SGroverkss /// 3) Try to obtain a sample from B using the GBR sampling
840bb901355SGroverkss /// algorithm. If no sample is found, return that S is empty.
841bb901355SGroverkss ///
842bb901355SGroverkss /// 4) Otherwise, substitute the obtained sample into S*T to obtain a set
843bb901355SGroverkss /// C. C is a full-dimensional Cone and always contains a sample.
844bb901355SGroverkss ///
845bb901355SGroverkss /// 5) Obtain an integer sample from C.
846bb901355SGroverkss ///
847bb901355SGroverkss /// 6) Return T*v, where v is the concatenation of the samples from B and C.
848bb901355SGroverkss ///
849bb901355SGroverkss /// The following is a sketch of a proof that
850bb901355SGroverkss /// a) If the algorithm returns empty, then S is empty.
851bb901355SGroverkss /// b) If the algorithm returns a sample, it is a valid sample in S.
852bb901355SGroverkss ///
853bb901355SGroverkss /// The algorithm returns empty only if B is empty, in which case S*T is
854bb901355SGroverkss /// certainly empty since B was obtained by removing constraints and then
855bb901355SGroverkss /// deleting unconstrained dimensions from S*T. Since T is unimodular, a vector
856bb901355SGroverkss /// v is in S*T iff T*v is in S. So in this case, since
857bb901355SGroverkss /// S*T is empty, S is empty too.
858bb901355SGroverkss ///
859bb901355SGroverkss /// Otherwise, the algorithm substitutes the sample from B into S*T. All the
860bb901355SGroverkss /// constraints of S*T that did not involve unbounded dimensions are satisfied
861bb901355SGroverkss /// by this substitution. All dimensions in the linear span of the dimensions
862bb901355SGroverkss /// outside the prefix are unbounded in S*T (step 1). Substituting values for
863bb901355SGroverkss /// the bounded dimensions cannot make these dimensions bounded, and these are
864bb901355SGroverkss /// the only remaining dimensions in C, so C is unbounded along every vector (in
865bb901355SGroverkss /// the positive or negative direction, or both). C is hence a full-dimensional
866bb901355SGroverkss /// cone and therefore always contains an integer point.
867bb901355SGroverkss ///
868bb901355SGroverkss /// Concatenating the samples from B and C gives a sample v in S*T, so the
869bb901355SGroverkss /// returned sample T*v is a sample in S.
8701a0e67d7SRamkumar Ramachandra std::optional<SmallVector<DynamicAPInt, 8>>
8710a81ace0SKazu Hirata IntegerRelation::findIntegerSample() const {
872bb901355SGroverkss   // First, try the GCD test heuristic.
873bb901355SGroverkss   if (isEmptyByGCDTest())
874bb901355SGroverkss     return {};
875bb901355SGroverkss 
876bb901355SGroverkss   Simplex simplex(*this);
877bb901355SGroverkss   if (simplex.isEmpty())
878bb901355SGroverkss     return {};
879bb901355SGroverkss 
880bb901355SGroverkss   // For a bounded set, we directly call into the GBR sampling algorithm.
881bb901355SGroverkss   if (!simplex.isUnbounded())
882bb901355SGroverkss     return simplex.findIntegerSample();
883bb901355SGroverkss 
884bb901355SGroverkss   // The set is unbounded. We cannot directly use the GBR algorithm.
885bb901355SGroverkss   //
886bb901355SGroverkss   // m is a matrix containing, in each row, a vector in which S is
887bb901355SGroverkss   // bounded, such that the linear span of all these dimensions contains all
888bb901355SGroverkss   // bounded dimensions in S.
889c1b99746SAbhinav271828   IntMatrix m = getBoundedDirections();
890bb901355SGroverkss   // In column echelon form, each row of m occupies only the first rank(m)
891bb901355SGroverkss   // columns and has zeros on the other columns. The transform T that brings S
892bb901355SGroverkss   // to column echelon form is unimodular as well, so this is a suitable
893bb901355SGroverkss   // transform to use in step 1 of the algorithm.
894bb901355SGroverkss   std::pair<unsigned, LinearTransform> result =
8959e2ace1cSMehdi Amini       LinearTransform::makeTransformToColumnEchelon(m);
896bb901355SGroverkss   const LinearTransform &transform = result.second;
897bb901355SGroverkss   // 1) Apply T to S to obtain S*T.
898bb901355SGroverkss   IntegerRelation transformedSet = transform.applyTo(*this);
899bb901355SGroverkss 
900bb901355SGroverkss   // 2) Remove the unbounded dimensions and constraints involving them to
901bb901355SGroverkss   // obtain a bounded set.
902bb901355SGroverkss   IntegerRelation boundedSet(transformedSet);
903bb901355SGroverkss   unsigned numBoundedDims = result.first;
904d95140a5SGroverkss   unsigned numUnboundedDims = getNumVars() - numBoundedDims;
905d95140a5SGroverkss   removeConstraintsInvolvingVarRange(boundedSet, numBoundedDims,
9068a67c6eeSArjun P                                      numUnboundedDims);
907d95140a5SGroverkss   boundedSet.removeVarRange(numBoundedDims, boundedSet.getNumVars());
908bb901355SGroverkss 
909bb901355SGroverkss   // 3) Try to obtain a sample from the bounded set.
9101a0e67d7SRamkumar Ramachandra   std::optional<SmallVector<DynamicAPInt, 8>> boundedSample =
911bb901355SGroverkss       Simplex(boundedSet).findIntegerSample();
912bb901355SGroverkss   if (!boundedSample)
913bb901355SGroverkss     return {};
914bb901355SGroverkss   assert(boundedSet.containsPoint(*boundedSample) &&
915bb901355SGroverkss          "Simplex returned an invalid sample!");
916bb901355SGroverkss 
917bb901355SGroverkss   // 4) Substitute the values of the bounded dimensions into S*T to obtain a
918bb901355SGroverkss   // full-dimensional cone, which necessarily contains an integer sample.
919bb901355SGroverkss   transformedSet.setAndEliminate(0, *boundedSample);
920bb901355SGroverkss   IntegerRelation &cone = transformedSet;
921bb901355SGroverkss 
922bb901355SGroverkss   // 5) Obtain an integer sample from the cone.
923bb901355SGroverkss   //
924bb901355SGroverkss   // We shrink the cone such that for any rational point in the shrunken cone,
925bb901355SGroverkss   // rounding up each of the point's coordinates produces a point that still
926bb901355SGroverkss   // lies in the original cone.
927bb901355SGroverkss   //
928bb901355SGroverkss   // Rounding up a point x adds a number e_i in [0, 1) to each coordinate x_i.
929bb901355SGroverkss   // For each inequality sum_i a_i x_i + c >= 0 in the original cone, the
930bb901355SGroverkss   // shrunken cone will have the inequality tightened by some amount s, such
931bb901355SGroverkss   // that if x satisfies the shrunken cone's tightened inequality, then x + e
932bb901355SGroverkss   // satisfies the original inequality, i.e.,
933bb901355SGroverkss   //
934bb901355SGroverkss   // sum_i a_i x_i + c + s >= 0 implies sum_i a_i (x_i + e_i) + c >= 0
935bb901355SGroverkss   //
936bb901355SGroverkss   // for any e_i values in [0, 1). In fact, we will handle the slightly more
937bb901355SGroverkss   // general case where e_i can be in [0, 1]. For example, consider the
938bb901355SGroverkss   // inequality 2x_1 - 3x_2 - 7x_3 - 6 >= 0, and let x = (3, 0, 0). How low
939bb901355SGroverkss   // could the LHS go if we added a number in [0, 1] to each coordinate? The LHS
940bb901355SGroverkss   // is minimized when we add 1 to the x_i with negative coefficient a_i and
941bb901355SGroverkss   // keep the other x_i the same. In the example, we would get x = (3, 1, 1),
942bb901355SGroverkss   // changing the value of the LHS by -3 + -7 = -10.
943bb901355SGroverkss   //
944bb901355SGroverkss   // In general, the value of the LHS can change by at most the sum of the
945bb901355SGroverkss   // negative a_i, so we accomodate this by shifting the inequality by this
946bb901355SGroverkss   // amount for the shrunken cone.
947bb901355SGroverkss   for (unsigned i = 0, e = cone.getNumInequalities(); i < e; ++i) {
948d95140a5SGroverkss     for (unsigned j = 0; j < cone.getNumVars(); ++j) {
9491a0e67d7SRamkumar Ramachandra       DynamicAPInt coeff = cone.atIneq(i, j);
950bb901355SGroverkss       if (coeff < 0)
951d95140a5SGroverkss         cone.atIneq(i, cone.getNumVars()) += coeff;
952bb901355SGroverkss     }
953bb901355SGroverkss   }
954bb901355SGroverkss 
955bb901355SGroverkss   // Obtain an integer sample in the cone by rounding up a rational point from
956bb901355SGroverkss   // the shrunken cone. Shrinking the cone amounts to shifting its apex
957bb901355SGroverkss   // "inwards" without changing its "shape"; the shrunken cone is still a
958bb901355SGroverkss   // full-dimensional cone and is hence non-empty.
959bb901355SGroverkss   Simplex shrunkenConeSimplex(cone);
960bb901355SGroverkss   assert(!shrunkenConeSimplex.isEmpty() && "Shrunken cone cannot be empty!");
961bb901355SGroverkss 
962bb901355SGroverkss   // The sample will always exist since the shrunken cone is non-empty.
963bb901355SGroverkss   SmallVector<Fraction, 8> shrunkenConeSample =
964bb901355SGroverkss       *shrunkenConeSimplex.getRationalSample();
965bb901355SGroverkss 
9661a0e67d7SRamkumar Ramachandra   SmallVector<DynamicAPInt, 8> coneSample(
9671a0e67d7SRamkumar Ramachandra       llvm::map_range(shrunkenConeSample, ceil));
968bb901355SGroverkss 
969bb901355SGroverkss   // 6) Return transform * concat(boundedSample, coneSample).
9701a0e67d7SRamkumar Ramachandra   SmallVector<DynamicAPInt, 8> &sample = *boundedSample;
971bb901355SGroverkss   sample.append(coneSample.begin(), coneSample.end());
972bb901355SGroverkss   return transform.postMultiplyWithColumn(sample);
973bb901355SGroverkss }
974bb901355SGroverkss 
975bb901355SGroverkss /// Helper to evaluate an affine expression at a point.
976bb901355SGroverkss /// The expression is a list of coefficients for the dimensions followed by the
977bb901355SGroverkss /// constant term.
9781a0e67d7SRamkumar Ramachandra static DynamicAPInt valueAt(ArrayRef<DynamicAPInt> expr,
9791a0e67d7SRamkumar Ramachandra                             ArrayRef<DynamicAPInt> point) {
980bb901355SGroverkss   assert(expr.size() == 1 + point.size() &&
981bb901355SGroverkss          "Dimensionalities of point and expression don't match!");
9821a0e67d7SRamkumar Ramachandra   DynamicAPInt value = expr.back();
983bb901355SGroverkss   for (unsigned i = 0; i < point.size(); ++i)
984bb901355SGroverkss     value += expr[i] * point[i];
985bb901355SGroverkss   return value;
986bb901355SGroverkss }
987bb901355SGroverkss 
988bb901355SGroverkss /// A point satisfies an equality iff the value of the equality at the
989bb901355SGroverkss /// expression is zero, and it satisfies an inequality iff the value of the
990bb901355SGroverkss /// inequality at that point is non-negative.
9911a0e67d7SRamkumar Ramachandra bool IntegerRelation::containsPoint(ArrayRef<DynamicAPInt> point) const {
992bb901355SGroverkss   for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) {
993bb901355SGroverkss     if (valueAt(getEquality(i), point) != 0)
994bb901355SGroverkss       return false;
995bb901355SGroverkss   }
996bb901355SGroverkss   for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) {
997bb901355SGroverkss     if (valueAt(getInequality(i), point) < 0)
998bb901355SGroverkss       return false;
999bb901355SGroverkss   }
1000bb901355SGroverkss   return true;
1001bb901355SGroverkss }
1002bb901355SGroverkss 
10034418669fSArjun P /// Just substitute the values given and check if an integer sample exists for
1004d95140a5SGroverkss /// the local vars.
10054418669fSArjun P ///
10064418669fSArjun P /// TODO: this could be made more efficient by handling divisions separately.
10074418669fSArjun P /// Instead of finding an integer sample over all the locals, we can first
10084418669fSArjun P /// compute the values of the locals that have division representations and
10094418669fSArjun P /// only use the integer emptiness check for the locals that don't have this.
10104418669fSArjun P /// Handling this correctly requires ordering the divs, though.
10111a0e67d7SRamkumar Ramachandra std::optional<SmallVector<DynamicAPInt, 8>>
10121a0e67d7SRamkumar Ramachandra IntegerRelation::containsPointNoLocal(ArrayRef<DynamicAPInt> point) const {
1013d95140a5SGroverkss   assert(point.size() == getNumVars() - getNumLocalVars() &&
1014d95140a5SGroverkss          "Point should contain all vars except locals!");
1015d95140a5SGroverkss   assert(getVarKindOffset(VarKind::Local) == getNumVars() - getNumLocalVars() &&
10164418669fSArjun P          "This function depends on locals being stored last!");
10174418669fSArjun P   IntegerRelation copy = *this;
10184418669fSArjun P   copy.setAndEliminate(0, point);
10194418669fSArjun P   return copy.findIntegerSample();
10204418669fSArjun P }
10214418669fSArjun P 
1022479c4f64SGroverkss DivisionRepr
1023479c4f64SGroverkss IntegerRelation::getLocalReprs(std::vector<MaybeLocalRepr> *repr) const {
1024d95140a5SGroverkss   SmallVector<bool, 8> foundRepr(getNumVars(), false);
1025d95140a5SGroverkss   for (unsigned i = 0, e = getNumDimAndSymbolVars(); i < e; ++i)
1026bb901355SGroverkss     foundRepr[i] = true;
1027bb901355SGroverkss 
1028479c4f64SGroverkss   unsigned localOffset = getVarKindOffset(VarKind::Local);
1029479c4f64SGroverkss   DivisionRepr divs(getNumVars(), getNumLocalVars());
1030bb901355SGroverkss   bool changed;
1031bb901355SGroverkss   do {
1032bb901355SGroverkss     // Each time changed is true, at end of this iteration, one or more local
1033bb901355SGroverkss     // vars have been detected as floor divs.
1034bb901355SGroverkss     changed = false;
1035d95140a5SGroverkss     for (unsigned i = 0, e = getNumLocalVars(); i < e; ++i) {
1036479c4f64SGroverkss       if (!foundRepr[i + localOffset]) {
1037479c4f64SGroverkss         MaybeLocalRepr res =
1038479c4f64SGroverkss             computeSingleVarRepr(*this, foundRepr, localOffset + i,
1039479c4f64SGroverkss                                  divs.getDividend(i), divs.getDenom(i));
1040479c4f64SGroverkss         if (!res) {
1041479c4f64SGroverkss           // No representation was found, so clear the representation and
1042479c4f64SGroverkss           // continue.
1043479c4f64SGroverkss           divs.clearRepr(i);
1044bb901355SGroverkss           continue;
1045479c4f64SGroverkss         }
1046479c4f64SGroverkss         foundRepr[localOffset + i] = true;
1047479c4f64SGroverkss         if (repr)
1048479c4f64SGroverkss           (*repr)[i] = res;
1049bb901355SGroverkss         changed = true;
1050bb901355SGroverkss       }
1051bb901355SGroverkss     }
1052bb901355SGroverkss   } while (changed);
1053bb901355SGroverkss 
1054479c4f64SGroverkss   return divs;
1055bb901355SGroverkss }
1056bb901355SGroverkss 
1057bb901355SGroverkss /// Tightens inequalities given that we are dealing with integer spaces. This is
1058bb901355SGroverkss /// analogous to the GCD test but applied to inequalities. The constant term can
1059bb901355SGroverkss /// be reduced to the preceding multiple of the GCD of the coefficients, i.e.,
1060bb901355SGroverkss ///  64*i - 100 >= 0  =>  64*i - 128 >= 0 (since 'i' is an integer). This is a
1061bb901355SGroverkss /// fast method - linear in the number of coefficients.
1062bb901355SGroverkss // Example on how this affects practical cases: consider the scenario:
1063bb901355SGroverkss // 64*i >= 100, j = 64*i; without a tightening, elimination of i would yield
1064bb901355SGroverkss // j >= 100 instead of the tighter (exact) j >= 128.
1065bb901355SGroverkss void IntegerRelation::gcdTightenInequalities() {
1066bb901355SGroverkss   unsigned numCols = getNumCols();
1067bb901355SGroverkss   for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) {
1068bb901355SGroverkss     // Normalize the constraint and tighten the constant term by the GCD.
10691a0e67d7SRamkumar Ramachandra     DynamicAPInt gcd = inequalities.normalizeRow(i, getNumCols() - 1);
1070bb901355SGroverkss     if (gcd > 1)
10716d6f6c4dSArjun P       atIneq(i, numCols - 1) = floorDiv(atIneq(i, numCols - 1), gcd);
1072bb901355SGroverkss   }
1073bb901355SGroverkss }
1074bb901355SGroverkss 
1075d95140a5SGroverkss // Eliminates all variable variables in column range [posStart, posLimit).
1076bb901355SGroverkss // Returns the number of variables eliminated.
1077d95140a5SGroverkss unsigned IntegerRelation::gaussianEliminateVars(unsigned posStart,
1078bb901355SGroverkss                                                 unsigned posLimit) {
1079d95140a5SGroverkss   // Return if variable positions to eliminate are out of range.
1080d95140a5SGroverkss   assert(posLimit <= getNumVars());
1081bb901355SGroverkss   assert(hasConsistentState());
1082bb901355SGroverkss 
1083bb901355SGroverkss   if (posStart >= posLimit)
1084bb901355SGroverkss     return 0;
1085bb901355SGroverkss 
1086bb901355SGroverkss   gcdTightenInequalities();
1087bb901355SGroverkss 
1088bb901355SGroverkss   unsigned pivotCol = 0;
1089bb901355SGroverkss   for (pivotCol = posStart; pivotCol < posLimit; ++pivotCol) {
1090bb901355SGroverkss     // Find a row which has a non-zero coefficient in column 'j'.
1091bb901355SGroverkss     unsigned pivotRow;
1092bb901355SGroverkss     if (!findConstraintWithNonZeroAt(pivotCol, /*isEq=*/true, &pivotRow)) {
1093bb901355SGroverkss       // No pivot row in equalities with non-zero at 'pivotCol'.
1094bb901355SGroverkss       if (!findConstraintWithNonZeroAt(pivotCol, /*isEq=*/false, &pivotRow)) {
1095bb901355SGroverkss         // If inequalities are also non-zero in 'pivotCol', it can be
1096bb901355SGroverkss         // eliminated.
1097bb901355SGroverkss         continue;
1098bb901355SGroverkss       }
1099bb901355SGroverkss       break;
1100bb901355SGroverkss     }
1101bb901355SGroverkss 
1102d95140a5SGroverkss     // Eliminate variable at 'pivotCol' from each equality row.
1103bb901355SGroverkss     for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) {
1104bb901355SGroverkss       eliminateFromConstraint(this, i, pivotRow, pivotCol, posStart,
1105bb901355SGroverkss                               /*isEq=*/true);
1106bb901355SGroverkss       equalities.normalizeRow(i);
1107bb901355SGroverkss     }
1108bb901355SGroverkss 
1109d95140a5SGroverkss     // Eliminate variable at 'pivotCol' from each inequality row.
1110bb901355SGroverkss     for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) {
1111bb901355SGroverkss       eliminateFromConstraint(this, i, pivotRow, pivotCol, posStart,
1112bb901355SGroverkss                               /*isEq=*/false);
1113bb901355SGroverkss       inequalities.normalizeRow(i);
1114bb901355SGroverkss     }
1115bb901355SGroverkss     removeEquality(pivotRow);
1116bb901355SGroverkss     gcdTightenInequalities();
1117bb901355SGroverkss   }
1118bb901355SGroverkss   // Update position limit based on number eliminated.
1119bb901355SGroverkss   posLimit = pivotCol;
1120bb901355SGroverkss   // Remove eliminated columns from all constraints.
1121d95140a5SGroverkss   removeVarRange(posStart, posLimit);
1122bb901355SGroverkss   return posLimit - posStart;
1123bb901355SGroverkss }
1124bb901355SGroverkss 
112539b93955Sgilsaia bool IntegerRelation::gaussianEliminate() {
112639b93955Sgilsaia   gcdTightenInequalities();
112739b93955Sgilsaia   unsigned firstVar = 0, vars = getNumVars();
112839b93955Sgilsaia   unsigned nowDone, eqs, pivotRow;
112939b93955Sgilsaia   for (nowDone = 0, eqs = getNumEqualities(); nowDone < eqs; ++nowDone) {
113039b93955Sgilsaia     // Finds the first non-empty column.
113139b93955Sgilsaia     for (; firstVar < vars; ++firstVar) {
113239b93955Sgilsaia       if (!findConstraintWithNonZeroAt(firstVar, true, &pivotRow))
113339b93955Sgilsaia         continue;
113439b93955Sgilsaia       break;
113539b93955Sgilsaia     }
113639b93955Sgilsaia     // The matrix has been normalized to row echelon form.
113739b93955Sgilsaia     if (firstVar >= vars)
113839b93955Sgilsaia       break;
113939b93955Sgilsaia 
114039b93955Sgilsaia     // The first pivot row found is below where it should currently be placed.
114139b93955Sgilsaia     if (pivotRow > nowDone) {
114239b93955Sgilsaia       equalities.swapRows(pivotRow, nowDone);
114339b93955Sgilsaia       pivotRow = nowDone;
114439b93955Sgilsaia     }
114539b93955Sgilsaia 
114639b93955Sgilsaia     // Normalize all lower equations and all inequalities.
114739b93955Sgilsaia     for (unsigned i = nowDone + 1; i < eqs; ++i) {
114839b93955Sgilsaia       eliminateFromConstraint(this, i, pivotRow, firstVar, 0, true);
114939b93955Sgilsaia       equalities.normalizeRow(i);
115039b93955Sgilsaia     }
115139b93955Sgilsaia     for (unsigned i = 0, ineqs = getNumInequalities(); i < ineqs; ++i) {
115239b93955Sgilsaia       eliminateFromConstraint(this, i, pivotRow, firstVar, 0, false);
115339b93955Sgilsaia       inequalities.normalizeRow(i);
115439b93955Sgilsaia     }
115539b93955Sgilsaia     gcdTightenInequalities();
115639b93955Sgilsaia   }
115739b93955Sgilsaia 
115839b93955Sgilsaia   // No redundant rows.
115939b93955Sgilsaia   if (nowDone == eqs)
116039b93955Sgilsaia     return false;
116139b93955Sgilsaia 
116239b93955Sgilsaia   // Check to see if the redundant rows constant is zero, a non-zero value means
116339b93955Sgilsaia   // the set is empty.
116439b93955Sgilsaia   for (unsigned i = nowDone; i < eqs; ++i) {
116539b93955Sgilsaia     if (atEq(i, vars) == 0)
116639b93955Sgilsaia       continue;
116739b93955Sgilsaia 
116839b93955Sgilsaia     *this = getEmpty(getSpace());
116939b93955Sgilsaia     return true;
117039b93955Sgilsaia   }
117139b93955Sgilsaia   // Eliminate rows that are confined to be all zeros.
117239b93955Sgilsaia   removeEqualityRange(nowDone, eqs);
117339b93955Sgilsaia   return true;
117439b93955Sgilsaia }
117539b93955Sgilsaia 
1176bb901355SGroverkss // A more complex check to eliminate redundant inequalities. Uses FourierMotzkin
1177bb901355SGroverkss // to check if a constraint is redundant.
1178bb901355SGroverkss void IntegerRelation::removeRedundantInequalities() {
1179bb901355SGroverkss   SmallVector<bool, 32> redun(getNumInequalities(), false);
1180bb901355SGroverkss   // To check if an inequality is redundant, we replace the inequality by its
1181bb901355SGroverkss   // complement (for eg., i - 1 >= 0 by i <= 0), and check if the resulting
1182bb901355SGroverkss   // system is empty. If it is, the inequality is redundant.
1183bb901355SGroverkss   IntegerRelation tmpCst(*this);
1184bb901355SGroverkss   for (unsigned r = 0, e = getNumInequalities(); r < e; r++) {
1185bb901355SGroverkss     // Change the inequality to its complement.
1186bb901355SGroverkss     tmpCst.inequalities.negateRow(r);
1187ef95a6e8SArjun P     --tmpCst.atIneq(r, tmpCst.getNumCols() - 1);
1188bb901355SGroverkss     if (tmpCst.isEmpty()) {
1189bb901355SGroverkss       redun[r] = true;
1190bb901355SGroverkss       // Zero fill the redundant inequality.
1191bb901355SGroverkss       inequalities.fillRow(r, /*value=*/0);
1192bb901355SGroverkss       tmpCst.inequalities.fillRow(r, /*value=*/0);
1193bb901355SGroverkss     } else {
1194bb901355SGroverkss       // Reverse the change (to avoid recreating tmpCst each time).
1195ef95a6e8SArjun P       ++tmpCst.atIneq(r, tmpCst.getNumCols() - 1);
1196bb901355SGroverkss       tmpCst.inequalities.negateRow(r);
1197bb901355SGroverkss     }
1198bb901355SGroverkss   }
1199bb901355SGroverkss 
1200bb901355SGroverkss   unsigned pos = 0;
1201bb901355SGroverkss   for (unsigned r = 0, e = getNumInequalities(); r < e; ++r) {
1202bb901355SGroverkss     if (!redun[r])
1203bb901355SGroverkss       inequalities.copyRow(r, pos++);
1204bb901355SGroverkss   }
1205bb901355SGroverkss   inequalities.resizeVertically(pos);
1206bb901355SGroverkss }
1207bb901355SGroverkss 
1208bb901355SGroverkss // A more complex check to eliminate redundant inequalities and equalities. Uses
1209bb901355SGroverkss // Simplex to check if a constraint is redundant.
1210bb901355SGroverkss void IntegerRelation::removeRedundantConstraints() {
1211bb901355SGroverkss   // First, we run gcdTightenInequalities. This allows us to catch some
1212bb901355SGroverkss   // constraints which are not redundant when considering rational solutions
1213bb901355SGroverkss   // but are redundant in terms of integer solutions.
1214bb901355SGroverkss   gcdTightenInequalities();
1215bb901355SGroverkss   Simplex simplex(*this);
1216bb901355SGroverkss   simplex.detectRedundant();
1217bb901355SGroverkss 
1218bb901355SGroverkss   unsigned pos = 0;
1219bb901355SGroverkss   unsigned numIneqs = getNumInequalities();
1220bb901355SGroverkss   // Scan to get rid of all inequalities marked redundant, in-place. In Simplex,
1221bb901355SGroverkss   // the first constraints added are the inequalities.
1222bb901355SGroverkss   for (unsigned r = 0; r < numIneqs; r++) {
1223bb901355SGroverkss     if (!simplex.isMarkedRedundant(r))
1224bb901355SGroverkss       inequalities.copyRow(r, pos++);
1225bb901355SGroverkss   }
1226bb901355SGroverkss   inequalities.resizeVertically(pos);
1227bb901355SGroverkss 
1228bb901355SGroverkss   // Scan to get rid of all equalities marked redundant, in-place. In Simplex,
1229bb901355SGroverkss   // after the inequalities, a pair of constraints for each equality is added.
1230bb901355SGroverkss   // An equality is redundant if both the inequalities in its pair are
1231bb901355SGroverkss   // redundant.
1232bb901355SGroverkss   pos = 0;
1233bb901355SGroverkss   for (unsigned r = 0, e = getNumEqualities(); r < e; r++) {
1234bb901355SGroverkss     if (!(simplex.isMarkedRedundant(numIneqs + 2 * r) &&
1235bb901355SGroverkss           simplex.isMarkedRedundant(numIneqs + 2 * r + 1)))
1236bb901355SGroverkss       equalities.copyRow(r, pos++);
1237bb901355SGroverkss   }
1238bb901355SGroverkss   equalities.resizeVertically(pos);
1239bb901355SGroverkss }
1240bb901355SGroverkss 
12411a0e67d7SRamkumar Ramachandra std::optional<DynamicAPInt> IntegerRelation::computeVolume() const {
1242d95140a5SGroverkss   assert(getNumSymbolVars() == 0 && "Symbols are not yet supported!");
1243bb901355SGroverkss 
1244bb901355SGroverkss   Simplex simplex(*this);
1245bb901355SGroverkss   // If the polytope is rationally empty, there are certainly no integer
1246bb901355SGroverkss   // points.
1247bb901355SGroverkss   if (simplex.isEmpty())
12481a0e67d7SRamkumar Ramachandra     return DynamicAPInt(0);
1249bb901355SGroverkss 
1250d95140a5SGroverkss   // Just find the maximum and minimum integer value of each non-local var
1251d95140a5SGroverkss   // separately, thus finding the number of integer values each such var can
1252bb901355SGroverkss   // take. Multiplying these together gives a valid overapproximation of the
1253bb901355SGroverkss   // number of integer points in the relation. The result this gives is
1254d95140a5SGroverkss   // equivalent to projecting (rationally) the relation onto its non-local vars
1255bb901355SGroverkss   // and returning the number of integer points in a minimal axis-parallel
1256bb901355SGroverkss   // hyperrectangular overapproximation of that.
1257bb901355SGroverkss   //
1258bb901355SGroverkss   // We also handle the special case where one dimension is unbounded and
1259bb901355SGroverkss   // another dimension can take no integer values. In this case, the volume is
1260bb901355SGroverkss   // zero.
1261bb901355SGroverkss   //
1262bb901355SGroverkss   // If there is no such empty dimension, if any dimension is unbounded we
1263bb901355SGroverkss   // just return the result as unbounded.
12641a0e67d7SRamkumar Ramachandra   DynamicAPInt count(1);
12651a0e67d7SRamkumar Ramachandra   SmallVector<DynamicAPInt, 8> dim(getNumVars() + 1);
1266d95140a5SGroverkss   bool hasUnboundedVar = false;
1267d95140a5SGroverkss   for (unsigned i = 0, e = getNumDimAndSymbolVars(); i < e; ++i) {
1268bb901355SGroverkss     dim[i] = 1;
12699fa59e76SBenjamin Kramer     auto [min, max] = simplex.computeIntegerBounds(dim);
1270bb901355SGroverkss     dim[i] = 0;
1271bb901355SGroverkss 
1272bb901355SGroverkss     assert((!min.isEmpty() && !max.isEmpty()) &&
1273bb901355SGroverkss            "Polytope should be rationally non-empty!");
1274bb901355SGroverkss 
1275bb901355SGroverkss     // One of the dimensions is unbounded. Note this fact. We will return
1276bb901355SGroverkss     // unbounded if none of the other dimensions makes the volume zero.
1277bb901355SGroverkss     if (min.isUnbounded() || max.isUnbounded()) {
1278d95140a5SGroverkss       hasUnboundedVar = true;
1279bb901355SGroverkss       continue;
1280bb901355SGroverkss     }
1281bb901355SGroverkss 
1282bb901355SGroverkss     // In this case there are no valid integer points and the volume is
1283bb901355SGroverkss     // definitely zero.
1284bb901355SGroverkss     if (min.getBoundedOptimum() > max.getBoundedOptimum())
12851a0e67d7SRamkumar Ramachandra       return DynamicAPInt(0);
1286bb901355SGroverkss 
1287bb901355SGroverkss     count *= (*max - *min + 1);
1288bb901355SGroverkss   }
1289bb901355SGroverkss 
1290bb901355SGroverkss   if (count == 0)
12911a0e67d7SRamkumar Ramachandra     return DynamicAPInt(0);
1292d95140a5SGroverkss   if (hasUnboundedVar)
1293bb901355SGroverkss     return {};
1294bb901355SGroverkss   return count;
1295bb901355SGroverkss }
1296bb901355SGroverkss 
1297d95140a5SGroverkss void IntegerRelation::eliminateRedundantLocalVar(unsigned posA, unsigned posB) {
1298d95140a5SGroverkss   assert(posA < getNumLocalVars() && "Invalid local var position");
1299d95140a5SGroverkss   assert(posB < getNumLocalVars() && "Invalid local var position");
1300bb901355SGroverkss 
1301d95140a5SGroverkss   unsigned localOffset = getVarKindOffset(VarKind::Local);
1302bb901355SGroverkss   posA += localOffset;
1303bb901355SGroverkss   posB += localOffset;
1304bb901355SGroverkss   inequalities.addToColumn(posB, posA, 1);
1305bb901355SGroverkss   equalities.addToColumn(posB, posA, 1);
1306d95140a5SGroverkss   removeVar(posB);
1307bb901355SGroverkss }
1308bb901355SGroverkss 
13093eb9fd8aSBharathi Ramana Joshi /// mergeAndAlignSymbols's implementation can be broken down into two steps:
13103eb9fd8aSBharathi Ramana Joshi /// 1. Merge and align identifiers into `other` from `this. If an identifier
13113eb9fd8aSBharathi Ramana Joshi /// from `this` exists in `other` then we align it. Otherwise, we assume it is a
13123eb9fd8aSBharathi Ramana Joshi /// new identifier and insert it into `other` in the same position as `this`.
13133eb9fd8aSBharathi Ramana Joshi /// 2. Add identifiers that are in `other` but not `this to `this`.
13143eb9fd8aSBharathi Ramana Joshi void IntegerRelation::mergeAndAlignSymbols(IntegerRelation &other) {
13153eb9fd8aSBharathi Ramana Joshi   assert(space.isUsingIds() && other.space.isUsingIds() &&
13163eb9fd8aSBharathi Ramana Joshi          "both relations need to have identifers to merge and align");
13173eb9fd8aSBharathi Ramana Joshi 
13183eb9fd8aSBharathi Ramana Joshi   unsigned i = 0;
13193eb9fd8aSBharathi Ramana Joshi   for (const Identifier identifier : space.getIds(VarKind::Symbol)) {
13203eb9fd8aSBharathi Ramana Joshi     // Search in `other` starting at position `i` since the left of `i` is
13213eb9fd8aSBharathi Ramana Joshi     // aligned.
13223eb9fd8aSBharathi Ramana Joshi     const Identifier *findBegin =
13233eb9fd8aSBharathi Ramana Joshi         other.space.getIds(VarKind::Symbol).begin() + i;
13243eb9fd8aSBharathi Ramana Joshi     const Identifier *findEnd = other.space.getIds(VarKind::Symbol).end();
13253eb9fd8aSBharathi Ramana Joshi     const Identifier *itr = std::find(findBegin, findEnd, identifier);
13263eb9fd8aSBharathi Ramana Joshi     if (itr != findEnd) {
13273eb9fd8aSBharathi Ramana Joshi       other.swapVar(other.getVarKindOffset(VarKind::Symbol) + i,
13283eb9fd8aSBharathi Ramana Joshi                     other.getVarKindOffset(VarKind::Symbol) + i +
13293eb9fd8aSBharathi Ramana Joshi                         std::distance(findBegin, itr));
13303eb9fd8aSBharathi Ramana Joshi     } else {
13313eb9fd8aSBharathi Ramana Joshi       other.insertVar(VarKind::Symbol, i);
133224da7fa0SBharathi Ramana Joshi       other.space.setId(VarKind::Symbol, i, identifier);
13333eb9fd8aSBharathi Ramana Joshi     }
13343eb9fd8aSBharathi Ramana Joshi     ++i;
13353eb9fd8aSBharathi Ramana Joshi   }
13363eb9fd8aSBharathi Ramana Joshi 
13373eb9fd8aSBharathi Ramana Joshi   for (unsigned e = other.getNumVarKind(VarKind::Symbol); i < e; ++i) {
13383eb9fd8aSBharathi Ramana Joshi     insertVar(VarKind::Symbol, i);
133924da7fa0SBharathi Ramana Joshi     space.setId(VarKind::Symbol, i, other.space.getId(VarKind::Symbol, i));
13403eb9fd8aSBharathi Ramana Joshi   }
13413eb9fd8aSBharathi Ramana Joshi }
13423eb9fd8aSBharathi Ramana Joshi 
1343bb901355SGroverkss /// Adds additional local ids to the sets such that they both have the union
1344bb901355SGroverkss /// of the local ids in each set, without changing the set of points that
1345bb901355SGroverkss /// lie in `this` and `other`.
1346bb901355SGroverkss ///
13474ffd0b6fSGroverkss /// To detect local ids that always take the same value, each local id is
1348bb901355SGroverkss /// represented as a floordiv with constant denominator in terms of other ids.
13494ffd0b6fSGroverkss /// After extracting these divisions, local ids in `other` with the same
13504ffd0b6fSGroverkss /// division representation as some other local id in any set are considered
13514ffd0b6fSGroverkss /// duplicate and are merged.
13524ffd0b6fSGroverkss ///
13534ffd0b6fSGroverkss /// It is possible that division representation for some local id cannot be
13544ffd0b6fSGroverkss /// obtained, and thus these local ids are not considered for detecting
13554ffd0b6fSGroverkss /// duplicates.
1356d95140a5SGroverkss unsigned IntegerRelation::mergeLocalVars(IntegerRelation &other) {
1357bb901355SGroverkss   IntegerRelation &relA = *this;
1358bb901355SGroverkss   IntegerRelation &relB = other;
1359bb901355SGroverkss 
1360d95140a5SGroverkss   unsigned oldALocals = relA.getNumLocalVars();
13614ffd0b6fSGroverkss 
1362bb901355SGroverkss   // Merge function that merges the local variables in both sets by treating
1363d95140a5SGroverkss   // them as the same variable.
13644ffd0b6fSGroverkss   auto merge = [&relA, &relB, oldALocals](unsigned i, unsigned j) -> bool {
13654ffd0b6fSGroverkss     // We only merge from local at pos j to local at pos i, where j > i.
13664ffd0b6fSGroverkss     if (i >= j)
13674ffd0b6fSGroverkss       return false;
13684ffd0b6fSGroverkss 
13694ffd0b6fSGroverkss     // If i < oldALocals, we are trying to merge duplicate divs. Since we do not
13704ffd0b6fSGroverkss     // want to merge duplicates in A, we ignore this call.
13714ffd0b6fSGroverkss     if (j < oldALocals)
13724ffd0b6fSGroverkss       return false;
13734ffd0b6fSGroverkss 
13744ffd0b6fSGroverkss     // Merge local at pos j into local at position i.
1375d95140a5SGroverkss     relA.eliminateRedundantLocalVar(i, j);
1376d95140a5SGroverkss     relB.eliminateRedundantLocalVar(i, j);
1377bb901355SGroverkss     return true;
1378bb901355SGroverkss   };
1379bb901355SGroverkss 
1380d95140a5SGroverkss   presburger::mergeLocalVars(*this, other, merge);
13814ffd0b6fSGroverkss 
13824ffd0b6fSGroverkss   // Since we do not remove duplicate divisions in relA, this is guranteed to be
13834ffd0b6fSGroverkss   // non-negative.
1384d95140a5SGroverkss   return relA.getNumLocalVars() - oldALocals;
138531cb9995SArjun P }
138631cb9995SArjun P 
13878a7ead69SArjun P bool IntegerRelation::hasOnlyDivLocals() const {
1388479c4f64SGroverkss   return getLocalReprs().hasAllReprs();
13898a7ead69SArjun P }
13908a7ead69SArjun P 
139131cb9995SArjun P void IntegerRelation::removeDuplicateDivs() {
1392479c4f64SGroverkss   DivisionRepr divs = getLocalReprs();
139331cb9995SArjun P   auto merge = [this](unsigned i, unsigned j) -> bool {
1394d95140a5SGroverkss     eliminateRedundantLocalVar(i, j);
139531cb9995SArjun P     return true;
139631cb9995SArjun P   };
1397479c4f64SGroverkss   divs.removeDuplicateDivs(merge);
1398bb901355SGroverkss }
1399bb901355SGroverkss 
140039b93955Sgilsaia void IntegerRelation::simplify() {
140139b93955Sgilsaia   bool changed = true;
140239b93955Sgilsaia   // Repeat until we reach a fixed point.
140339b93955Sgilsaia   while (changed) {
140439b93955Sgilsaia     if (isObviouslyEmpty())
140539b93955Sgilsaia       return;
140639b93955Sgilsaia     changed = false;
140739b93955Sgilsaia     normalizeConstraintsByGCD();
140839b93955Sgilsaia     changed |= gaussianEliminate();
140939b93955Sgilsaia     changed |= removeDuplicateConstraints();
141039b93955Sgilsaia   }
141139b93955Sgilsaia   // Current set is not empty.
141239b93955Sgilsaia }
141339b93955Sgilsaia 
1414bb901355SGroverkss /// Removes local variables using equalities. Each equality is checked if it
1415bb901355SGroverkss /// can be reduced to the form: `e = affine-expr`, where `e` is a local
1416bb901355SGroverkss /// variable and `affine-expr` is an affine expression not containing `e`.
1417bb901355SGroverkss /// If an equality satisfies this form, the local variable is replaced in
1418bb901355SGroverkss /// each constraint and then removed. The equality used to replace this local
1419bb901355SGroverkss /// variable is also removed.
1420bb901355SGroverkss void IntegerRelation::removeRedundantLocalVars() {
1421bb901355SGroverkss   // Normalize the equality constraints to reduce coefficients of local
1422bb901355SGroverkss   // variables to 1 wherever possible.
1423bb901355SGroverkss   for (unsigned i = 0, e = getNumEqualities(); i < e; ++i)
1424bb901355SGroverkss     equalities.normalizeRow(i);
1425bb901355SGroverkss 
1426bb901355SGroverkss   while (true) {
1427bb901355SGroverkss     unsigned i, e, j, f;
1428bb901355SGroverkss     for (i = 0, e = getNumEqualities(); i < e; ++i) {
1429bb901355SGroverkss       // Find a local variable to eliminate using ith equality.
1430d95140a5SGroverkss       for (j = getNumDimAndSymbolVars(), f = getNumVars(); j < f; ++j)
14316d6f6c4dSArjun P         if (abs(atEq(i, j)) == 1)
1432bb901355SGroverkss           break;
1433bb901355SGroverkss 
1434bb901355SGroverkss       // Local variable can be eliminated using ith equality.
1435bb901355SGroverkss       if (j < f)
1436bb901355SGroverkss         break;
1437bb901355SGroverkss     }
1438bb901355SGroverkss 
1439bb901355SGroverkss     // No equality can be used to eliminate a local variable.
1440bb901355SGroverkss     if (i == e)
1441bb901355SGroverkss       break;
1442bb901355SGroverkss 
1443bb901355SGroverkss     // Use the ith equality to simplify other equalities. If any changes
1444bb901355SGroverkss     // are made to an equality constraint, it is normalized by GCD.
1445bb901355SGroverkss     for (unsigned k = 0, t = getNumEqualities(); k < t; ++k) {
1446bb901355SGroverkss       if (atEq(k, j) != 0) {
1447bb901355SGroverkss         eliminateFromConstraint(this, k, i, j, j, /*isEq=*/true);
1448bb901355SGroverkss         equalities.normalizeRow(k);
1449bb901355SGroverkss       }
1450bb901355SGroverkss     }
1451bb901355SGroverkss 
1452bb901355SGroverkss     // Use the ith equality to simplify inequalities.
1453bb901355SGroverkss     for (unsigned k = 0, t = getNumInequalities(); k < t; ++k)
1454bb901355SGroverkss       eliminateFromConstraint(this, k, i, j, j, /*isEq=*/false);
1455bb901355SGroverkss 
1456bb901355SGroverkss     // Remove the ith equality and the found local variable.
1457d95140a5SGroverkss     removeVar(j);
1458bb901355SGroverkss     removeEquality(i);
1459bb901355SGroverkss   }
1460bb901355SGroverkss }
1461bb901355SGroverkss 
1462d08522f5SArjun P void IntegerRelation::convertVarKind(VarKind srcKind, unsigned varStart,
1463d08522f5SArjun P                                      unsigned varLimit, VarKind dstKind,
1464dac27da7SGroverkss                                      unsigned pos) {
146524da7fa0SBharathi Ramana Joshi   assert(varLimit <= getNumVarKind(srcKind) && "invalid id range");
1466bb901355SGroverkss 
1467d08522f5SArjun P   if (varStart >= varLimit)
1468bb901355SGroverkss     return;
1469bb901355SGroverkss 
147024da7fa0SBharathi Ramana Joshi   unsigned srcOffset = getVarKindOffset(srcKind);
147124da7fa0SBharathi Ramana Joshi   unsigned dstOffset = getVarKindOffset(dstKind);
1472d08522f5SArjun P   unsigned convertCount = varLimit - varStart;
147324da7fa0SBharathi Ramana Joshi   int forwardMoveOffset = dstOffset > srcOffset ? -convertCount : 0;
1474bb901355SGroverkss 
147524da7fa0SBharathi Ramana Joshi   equalities.moveColumns(srcOffset + varStart, convertCount,
147624da7fa0SBharathi Ramana Joshi                          dstOffset + pos + forwardMoveOffset);
147724da7fa0SBharathi Ramana Joshi   inequalities.moveColumns(srcOffset + varStart, convertCount,
147824da7fa0SBharathi Ramana Joshi                            dstOffset + pos + forwardMoveOffset);
1479bb901355SGroverkss 
148024da7fa0SBharathi Ramana Joshi   space.convertVarKind(srcKind, varStart, varLimit - varStart, dstKind, pos);
1481bb901355SGroverkss }
1482bb901355SGroverkss 
14836d6f6c4dSArjun P void IntegerRelation::addBound(BoundType type, unsigned pos,
14841a0e67d7SRamkumar Ramachandra                                const DynamicAPInt &value) {
1485bb901355SGroverkss   assert(pos < getNumCols());
1486bb901355SGroverkss   if (type == BoundType::EQ) {
1487bb901355SGroverkss     unsigned row = equalities.appendExtraRow();
1488bb901355SGroverkss     equalities(row, pos) = 1;
1489bb901355SGroverkss     equalities(row, getNumCols() - 1) = -value;
1490bb901355SGroverkss   } else {
1491bb901355SGroverkss     unsigned row = inequalities.appendExtraRow();
1492bb901355SGroverkss     inequalities(row, pos) = type == BoundType::LB ? 1 : -1;
1493bb901355SGroverkss     inequalities(row, getNumCols() - 1) =
1494bb901355SGroverkss         type == BoundType::LB ? -value : value;
1495bb901355SGroverkss   }
1496bb901355SGroverkss }
1497bb901355SGroverkss 
14981a0e67d7SRamkumar Ramachandra void IntegerRelation::addBound(BoundType type, ArrayRef<DynamicAPInt> expr,
14991a0e67d7SRamkumar Ramachandra                                const DynamicAPInt &value) {
1500bb901355SGroverkss   assert(type != BoundType::EQ && "EQ not implemented");
1501bb901355SGroverkss   assert(expr.size() == getNumCols());
1502bb901355SGroverkss   unsigned row = inequalities.appendExtraRow();
1503bb901355SGroverkss   for (unsigned i = 0, e = expr.size(); i < e; ++i)
1504bb901355SGroverkss     inequalities(row, i) = type == BoundType::LB ? expr[i] : -expr[i];
1505bb901355SGroverkss   inequalities(inequalities.getNumRows() - 1, getNumCols() - 1) +=
1506bb901355SGroverkss       type == BoundType::LB ? -value : value;
1507bb901355SGroverkss }
1508bb901355SGroverkss 
1509d95140a5SGroverkss /// Adds a new local variable as the floordiv of an affine function of other
1510d95140a5SGroverkss /// variables, the coefficients of which are provided in 'dividend' and with
1511bb901355SGroverkss /// respect to a positive constant 'divisor'. Two constraints are added to the
1512bb901355SGroverkss /// system to capture equivalence with the floordiv.
1513bb901355SGroverkss ///      q = expr floordiv c    <=>   c*q <= expr <= c*q + c - 1.
15141a0e67d7SRamkumar Ramachandra void IntegerRelation::addLocalFloorDiv(ArrayRef<DynamicAPInt> dividend,
15151a0e67d7SRamkumar Ramachandra                                        const DynamicAPInt &divisor) {
1516bb901355SGroverkss   assert(dividend.size() == getNumCols() && "incorrect dividend size");
1517bb901355SGroverkss   assert(divisor > 0 && "positive divisor expected");
1518bb901355SGroverkss 
1519d95140a5SGroverkss   appendVar(VarKind::Local);
1520bb901355SGroverkss 
15215262865aSKazu Hirata   SmallVector<DynamicAPInt, 8> dividendCopy(dividend);
15221a0e67d7SRamkumar Ramachandra   dividendCopy.insert(dividendCopy.end() - 1, DynamicAPInt(0));
1523fd26d86fSArjun P   addInequality(
1524fd26d86fSArjun P       getDivLowerBound(dividendCopy, divisor, dividendCopy.size() - 2));
1525fd26d86fSArjun P   addInequality(
1526fd26d86fSArjun P       getDivUpperBound(dividendCopy, divisor, dividendCopy.size() - 2));
1527bb901355SGroverkss }
1528bb901355SGroverkss 
1529d95140a5SGroverkss /// Finds an equality that equates the specified variable to a constant.
1530bb901355SGroverkss /// Returns the position of the equality row. If 'symbolic' is set to true,
1531bb901355SGroverkss /// symbols are also treated like a constant, i.e., an affine function of the
1532bb901355SGroverkss /// symbols is also treated like a constant. Returns -1 if such an equality
1533bb901355SGroverkss /// could not be found.
1534bb901355SGroverkss static int findEqualityToConstant(const IntegerRelation &cst, unsigned pos,
1535bb901355SGroverkss                                   bool symbolic = false) {
1536d95140a5SGroverkss   assert(pos < cst.getNumVars() && "invalid position");
1537bb901355SGroverkss   for (unsigned r = 0, e = cst.getNumEqualities(); r < e; r++) {
15381a0e67d7SRamkumar Ramachandra     DynamicAPInt v = cst.atEq(r, pos);
1539bb901355SGroverkss     if (v * v != 1)
1540bb901355SGroverkss       continue;
1541bb901355SGroverkss     unsigned c;
1542d95140a5SGroverkss     unsigned f = symbolic ? cst.getNumDimVars() : cst.getNumVars();
1543bb901355SGroverkss     // This checks for zeros in all positions other than 'pos' in [0, f)
1544bb901355SGroverkss     for (c = 0; c < f; c++) {
1545bb901355SGroverkss       if (c == pos)
1546bb901355SGroverkss         continue;
1547bb901355SGroverkss       if (cst.atEq(r, c) != 0) {
1548d95140a5SGroverkss         // Dependent on another variable.
1549bb901355SGroverkss         break;
1550bb901355SGroverkss       }
1551bb901355SGroverkss     }
1552bb901355SGroverkss     if (c == f)
1553d95140a5SGroverkss       // Equality is free of other variables.
1554bb901355SGroverkss       return r;
1555bb901355SGroverkss   }
1556bb901355SGroverkss   return -1;
1557bb901355SGroverkss }
1558bb901355SGroverkss 
1559f819302aSRamkumar Ramachandra LogicalResult IntegerRelation::constantFoldVar(unsigned pos) {
1560d95140a5SGroverkss   assert(pos < getNumVars() && "invalid position");
1561bb901355SGroverkss   int rowIdx;
1562bb901355SGroverkss   if ((rowIdx = findEqualityToConstant(*this, pos)) == -1)
1563f819302aSRamkumar Ramachandra     return failure();
1564bb901355SGroverkss 
1565bb901355SGroverkss   // atEq(rowIdx, pos) is either -1 or 1.
1566bb901355SGroverkss   assert(atEq(rowIdx, pos) * atEq(rowIdx, pos) == 1);
15671a0e67d7SRamkumar Ramachandra   DynamicAPInt constVal = -atEq(rowIdx, getNumCols() - 1) / atEq(rowIdx, pos);
1568bb901355SGroverkss   setAndEliminate(pos, constVal);
1569f819302aSRamkumar Ramachandra   return success();
1570bb901355SGroverkss }
1571bb901355SGroverkss 
1572d95140a5SGroverkss void IntegerRelation::constantFoldVarRange(unsigned pos, unsigned num) {
1573bb901355SGroverkss   for (unsigned s = pos, t = pos, e = pos + num; s < e; s++) {
1574f819302aSRamkumar Ramachandra     if (constantFoldVar(t).failed())
1575bb901355SGroverkss       t++;
1576bb901355SGroverkss   }
1577bb901355SGroverkss }
1578bb901355SGroverkss 
1579bb901355SGroverkss /// Returns a non-negative constant bound on the extent (upper bound - lower
1580d95140a5SGroverkss /// bound) of the specified variable if it is found to be a constant; returns
15814f81805aSKazu Hirata /// std::nullopt if it's not a constant. This methods treats symbolic variables
1582bb901355SGroverkss /// specially, i.e., it looks for constant differences between affine
15834f81805aSKazu Hirata /// expressions involving only the symbolic variables. See comments at function
15844f81805aSKazu Hirata /// definition for example. 'lb', if provided, is set to the lower bound
15854f81805aSKazu Hirata /// associated with the constant difference. Note that 'lb' is purely symbolic
15864f81805aSKazu Hirata /// and thus will contain the coefficients of the symbolic variables and the
15874f81805aSKazu Hirata /// constant coefficient.
1588bb901355SGroverkss //  Egs: 0 <= i <= 15, return 16.
1589bb901355SGroverkss //       s0 + 2 <= i <= s0 + 17, returns 16. (s0 has to be a symbol)
1590bb901355SGroverkss //       s0 + s1 + 16 <= d0 <= s0 + s1 + 31, returns 16.
1591bb901355SGroverkss //       s0 - 7 <= 8*j <= s0 returns 1 with lb = s0, lbDivisor = 8 (since lb =
1592bb901355SGroverkss //       ceil(s0 - 7 / 8) = floor(s0 / 8)).
15931a0e67d7SRamkumar Ramachandra std::optional<DynamicAPInt> IntegerRelation::getConstantBoundOnDimSize(
15941a0e67d7SRamkumar Ramachandra     unsigned pos, SmallVectorImpl<DynamicAPInt> *lb,
15951a0e67d7SRamkumar Ramachandra     DynamicAPInt *boundFloorDivisor, SmallVectorImpl<DynamicAPInt> *ub,
15961a0e67d7SRamkumar Ramachandra     unsigned *minLbPos, unsigned *minUbPos) const {
1597d95140a5SGroverkss   assert(pos < getNumDimVars() && "Invalid variable position");
1598bb901355SGroverkss 
1599d95140a5SGroverkss   // Find an equality for 'pos'^th variable that equates it to some function
1600d95140a5SGroverkss   // of the symbolic variables (+ constant).
1601bb901355SGroverkss   int eqPos = findEqualityToConstant(*this, pos, /*symbolic=*/true);
1602bb901355SGroverkss   if (eqPos != -1) {
1603bb901355SGroverkss     auto eq = getEquality(eqPos);
1604bb901355SGroverkss     // If the equality involves a local var, punt for now.
1605bb901355SGroverkss     // TODO: this can be handled in the future by using the explicit
1606bb901355SGroverkss     // representation of the local vars.
1607d95140a5SGroverkss     if (!std::all_of(eq.begin() + getNumDimAndSymbolVars(), eq.end() - 1,
16081a0e67d7SRamkumar Ramachandra                      [](const DynamicAPInt &coeff) { return coeff == 0; }))
16091a36588eSKazu Hirata       return std::nullopt;
1610bb901355SGroverkss 
1611d95140a5SGroverkss     // This variable can only take a single value.
1612bb901355SGroverkss     if (lb) {
1613bb901355SGroverkss       // Set lb to that symbolic value.
1614d95140a5SGroverkss       lb->resize(getNumSymbolVars() + 1);
1615bb901355SGroverkss       if (ub)
1616d95140a5SGroverkss         ub->resize(getNumSymbolVars() + 1);
1617d95140a5SGroverkss       for (unsigned c = 0, f = getNumSymbolVars() + 1; c < f; c++) {
16181a0e67d7SRamkumar Ramachandra         DynamicAPInt v = atEq(eqPos, pos);
1619bb901355SGroverkss         // atEq(eqRow, pos) is either -1 or 1.
1620bb901355SGroverkss         assert(v * v == 1);
1621d95140a5SGroverkss         (*lb)[c] = v < 0 ? atEq(eqPos, getNumDimVars() + c) / -v
1622d95140a5SGroverkss                          : -atEq(eqPos, getNumDimVars() + c) / v;
1623bb901355SGroverkss         // Since this is an equality, ub = lb.
1624bb901355SGroverkss         if (ub)
1625bb901355SGroverkss           (*ub)[c] = (*lb)[c];
1626bb901355SGroverkss       }
1627bb901355SGroverkss       assert(boundFloorDivisor &&
1628bb901355SGroverkss              "both lb and divisor or none should be provided");
1629bb901355SGroverkss       *boundFloorDivisor = 1;
1630bb901355SGroverkss     }
1631bb901355SGroverkss     if (minLbPos)
1632bb901355SGroverkss       *minLbPos = eqPos;
1633bb901355SGroverkss     if (minUbPos)
1634bb901355SGroverkss       *minUbPos = eqPos;
16351a0e67d7SRamkumar Ramachandra     return DynamicAPInt(1);
1636bb901355SGroverkss   }
1637bb901355SGroverkss 
1638d95140a5SGroverkss   // Check if the variable appears at all in any of the inequalities.
1639bb901355SGroverkss   unsigned r, e;
1640bb901355SGroverkss   for (r = 0, e = getNumInequalities(); r < e; r++) {
1641bb901355SGroverkss     if (atIneq(r, pos) != 0)
1642bb901355SGroverkss       break;
1643bb901355SGroverkss   }
1644bb901355SGroverkss   if (r == e)
1645bb901355SGroverkss     // If it doesn't, there isn't a bound on it.
16461a36588eSKazu Hirata     return std::nullopt;
1647bb901355SGroverkss 
1648bb901355SGroverkss   // Positions of constraints that are lower/upper bounds on the variable.
1649bb901355SGroverkss   SmallVector<unsigned, 4> lbIndices, ubIndices;
1650bb901355SGroverkss 
1651bb901355SGroverkss   // Gather all symbolic lower bounds and upper bounds of the variable, i.e.,
1652d95140a5SGroverkss   // the bounds can only involve symbolic (and local) variables. Since the
1653bb901355SGroverkss   // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower
1654bb901355SGroverkss   // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1.
1655bb901355SGroverkss   getLowerAndUpperBoundIndices(pos, &lbIndices, &ubIndices,
1656bb901355SGroverkss                                /*eqIndices=*/nullptr, /*offset=*/0,
1657d95140a5SGroverkss                                /*num=*/getNumDimVars());
1658bb901355SGroverkss 
16591a0e67d7SRamkumar Ramachandra   std::optional<DynamicAPInt> minDiff;
1660bb901355SGroverkss   unsigned minLbPosition = 0, minUbPosition = 0;
1661bb901355SGroverkss   for (auto ubPos : ubIndices) {
1662bb901355SGroverkss     for (auto lbPos : lbIndices) {
1663bb901355SGroverkss       // Look for a lower bound and an upper bound that only differ by a
1664bb901355SGroverkss       // constant, i.e., pairs of the form  0 <= c_pos - f(c_i's) <= diffConst.
1665bb901355SGroverkss       // For example, if ii is the pos^th variable, we are looking for
1666bb901355SGroverkss       // constraints like ii >= i, ii <= ii + 50, 50 being the difference. The
1667bb901355SGroverkss       // minimum among all such constant differences is kept since that's the
1668bb901355SGroverkss       // constant bounding the extent of the pos^th variable.
1669bb901355SGroverkss       unsigned j, e;
1670bb901355SGroverkss       for (j = 0, e = getNumCols() - 1; j < e; j++)
1671bb901355SGroverkss         if (atIneq(ubPos, j) != -atIneq(lbPos, j)) {
1672bb901355SGroverkss           break;
1673bb901355SGroverkss         }
1674bb901355SGroverkss       if (j < getNumCols() - 1)
1675bb901355SGroverkss         continue;
16761a0e67d7SRamkumar Ramachandra       DynamicAPInt diff = ceilDiv(atIneq(ubPos, getNumCols() - 1) +
1677bb901355SGroverkss                                       atIneq(lbPos, getNumCols() - 1) + 1,
1678bb901355SGroverkss                                   atIneq(lbPos, pos));
1679bb901355SGroverkss       // This bound is non-negative by definition.
16801a0e67d7SRamkumar Ramachandra       diff = std::max<DynamicAPInt>(diff, DynamicAPInt(0));
16811a36588eSKazu Hirata       if (minDiff == std::nullopt || diff < minDiff) {
1682bb901355SGroverkss         minDiff = diff;
1683bb901355SGroverkss         minLbPosition = lbPos;
1684bb901355SGroverkss         minUbPosition = ubPos;
1685bb901355SGroverkss       }
1686bb901355SGroverkss     }
1687bb901355SGroverkss   }
1688037f0995SKazu Hirata   if (lb && minDiff) {
1689bb901355SGroverkss     // Set lb to the symbolic lower bound.
1690d95140a5SGroverkss     lb->resize(getNumSymbolVars() + 1);
1691bb901355SGroverkss     if (ub)
1692d95140a5SGroverkss       ub->resize(getNumSymbolVars() + 1);
1693bb901355SGroverkss     // The lower bound is the ceildiv of the lb constraint over the coefficient
1694bb901355SGroverkss     // of the variable at 'pos'. We express the ceildiv equivalently as a floor
1695bb901355SGroverkss     // for uniformity. For eg., if the lower bound constraint was: 32*d0 - N +
1696bb901355SGroverkss     // 31 >= 0, the lower bound for d0 is ceil(N - 31, 32), i.e., floor(N, 32).
1697bb901355SGroverkss     *boundFloorDivisor = atIneq(minLbPosition, pos);
1698bb901355SGroverkss     assert(*boundFloorDivisor == -atIneq(minUbPosition, pos));
1699d95140a5SGroverkss     for (unsigned c = 0, e = getNumSymbolVars() + 1; c < e; c++) {
1700d95140a5SGroverkss       (*lb)[c] = -atIneq(minLbPosition, getNumDimVars() + c);
1701bb901355SGroverkss     }
1702bb901355SGroverkss     if (ub) {
1703d95140a5SGroverkss       for (unsigned c = 0, e = getNumSymbolVars() + 1; c < e; c++)
1704d95140a5SGroverkss         (*ub)[c] = atIneq(minUbPosition, getNumDimVars() + c);
1705bb901355SGroverkss     }
1706bb901355SGroverkss     // The lower bound leads to a ceildiv while the upper bound is a floordiv
1707bb901355SGroverkss     // whenever the coefficient at pos != 1. ceildiv (val / d) = floordiv (val +
1708bb901355SGroverkss     // d - 1 / d); hence, the addition of 'atIneq(minLbPosition, pos) - 1' to
1709bb901355SGroverkss     // the constant term for the lower bound.
1710d95140a5SGroverkss     (*lb)[getNumSymbolVars()] += atIneq(minLbPosition, pos) - 1;
1711bb901355SGroverkss   }
1712bb901355SGroverkss   if (minLbPos)
1713bb901355SGroverkss     *minLbPos = minLbPosition;
1714bb901355SGroverkss   if (minUbPos)
1715bb901355SGroverkss     *minUbPos = minUbPosition;
1716bb901355SGroverkss   return minDiff;
1717bb901355SGroverkss }
1718bb901355SGroverkss 
1719bb901355SGroverkss template <bool isLower>
17201a0e67d7SRamkumar Ramachandra std::optional<DynamicAPInt>
1721bb901355SGroverkss IntegerRelation::computeConstantLowerOrUpperBound(unsigned pos) {
1722d95140a5SGroverkss   assert(pos < getNumVars() && "invalid position");
1723bb901355SGroverkss   // Project to 'pos'.
1724bb901355SGroverkss   projectOut(0, pos);
1725d95140a5SGroverkss   projectOut(1, getNumVars() - 1);
1726d95140a5SGroverkss   // Check if there's an equality equating the '0'^th variable to a constant.
1727bb901355SGroverkss   int eqRowIdx = findEqualityToConstant(*this, 0, /*symbolic=*/false);
1728bb901355SGroverkss   if (eqRowIdx != -1)
1729bb901355SGroverkss     // atEq(rowIdx, 0) is either -1 or 1.
1730bb901355SGroverkss     return -atEq(eqRowIdx, getNumCols() - 1) / atEq(eqRowIdx, 0);
1731bb901355SGroverkss 
1732d95140a5SGroverkss   // Check if the variable appears at all in any of the inequalities.
1733bb901355SGroverkss   unsigned r, e;
1734bb901355SGroverkss   for (r = 0, e = getNumInequalities(); r < e; r++) {
1735bb901355SGroverkss     if (atIneq(r, 0) != 0)
1736bb901355SGroverkss       break;
1737bb901355SGroverkss   }
1738bb901355SGroverkss   if (r == e)
1739bb901355SGroverkss     // If it doesn't, there isn't a bound on it.
17401a36588eSKazu Hirata     return std::nullopt;
1741bb901355SGroverkss 
17421a0e67d7SRamkumar Ramachandra   std::optional<DynamicAPInt> minOrMaxConst;
1743bb901355SGroverkss 
1744bb901355SGroverkss   // Take the max across all const lower bounds (or min across all constant
1745bb901355SGroverkss   // upper bounds).
1746bb901355SGroverkss   for (unsigned r = 0, e = getNumInequalities(); r < e; r++) {
1747bb901355SGroverkss     if (isLower) {
1748bb901355SGroverkss       if (atIneq(r, 0) <= 0)
1749bb901355SGroverkss         // Not a lower bound.
1750bb901355SGroverkss         continue;
1751bb901355SGroverkss     } else if (atIneq(r, 0) >= 0) {
1752bb901355SGroverkss       // Not an upper bound.
1753bb901355SGroverkss       continue;
1754bb901355SGroverkss     }
1755bb901355SGroverkss     unsigned c, f;
1756bb901355SGroverkss     for (c = 0, f = getNumCols() - 1; c < f; c++)
1757bb901355SGroverkss       if (c != 0 && atIneq(r, c) != 0)
1758bb901355SGroverkss         break;
1759bb901355SGroverkss     if (c < getNumCols() - 1)
1760bb901355SGroverkss       // Not a constant bound.
1761bb901355SGroverkss       continue;
1762bb901355SGroverkss 
17631a0e67d7SRamkumar Ramachandra     DynamicAPInt boundConst =
17646d6f6c4dSArjun P         isLower ? ceilDiv(-atIneq(r, getNumCols() - 1), atIneq(r, 0))
17656d6f6c4dSArjun P                 : floorDiv(atIneq(r, getNumCols() - 1), -atIneq(r, 0));
1766bb901355SGroverkss     if (isLower) {
17671a36588eSKazu Hirata       if (minOrMaxConst == std::nullopt || boundConst > minOrMaxConst)
1768bb901355SGroverkss         minOrMaxConst = boundConst;
1769bb901355SGroverkss     } else {
17701a36588eSKazu Hirata       if (minOrMaxConst == std::nullopt || boundConst < minOrMaxConst)
1771bb901355SGroverkss         minOrMaxConst = boundConst;
1772bb901355SGroverkss     }
1773bb901355SGroverkss   }
1774bb901355SGroverkss   return minOrMaxConst;
1775bb901355SGroverkss }
1776bb901355SGroverkss 
17771a0e67d7SRamkumar Ramachandra std::optional<DynamicAPInt>
17781a0e67d7SRamkumar Ramachandra IntegerRelation::getConstantBound(BoundType type, unsigned pos) const {
1779bb901355SGroverkss   if (type == BoundType::LB)
1780bb901355SGroverkss     return IntegerRelation(*this)
1781bb901355SGroverkss         .computeConstantLowerOrUpperBound</*isLower=*/true>(pos);
1782bb901355SGroverkss   if (type == BoundType::UB)
1783bb901355SGroverkss     return IntegerRelation(*this)
1784bb901355SGroverkss         .computeConstantLowerOrUpperBound</*isLower=*/false>(pos);
1785bb901355SGroverkss 
1786bb901355SGroverkss   assert(type == BoundType::EQ && "expected EQ");
17871a0e67d7SRamkumar Ramachandra   std::optional<DynamicAPInt> lb =
1788bb901355SGroverkss       IntegerRelation(*this).computeConstantLowerOrUpperBound</*isLower=*/true>(
1789bb901355SGroverkss           pos);
17901a0e67d7SRamkumar Ramachandra   std::optional<DynamicAPInt> ub =
1791bb901355SGroverkss       IntegerRelation(*this)
1792bb901355SGroverkss           .computeConstantLowerOrUpperBound</*isLower=*/false>(pos);
17931a0e67d7SRamkumar Ramachandra   return (lb && ub && *lb == *ub) ? std::optional<DynamicAPInt>(*ub)
17941a0e67d7SRamkumar Ramachandra                                   : std::nullopt;
1795bb901355SGroverkss }
1796bb901355SGroverkss 
1797bb901355SGroverkss // A simple (naive and conservative) check for hyper-rectangularity.
1798bb901355SGroverkss bool IntegerRelation::isHyperRectangular(unsigned pos, unsigned num) const {
1799bb901355SGroverkss   assert(pos < getNumCols() - 1);
1800bb901355SGroverkss   // Check for two non-zero coefficients in the range [pos, pos + sum).
1801bb901355SGroverkss   for (unsigned r = 0, e = getNumInequalities(); r < e; r++) {
1802bb901355SGroverkss     unsigned sum = 0;
1803bb901355SGroverkss     for (unsigned c = pos; c < pos + num; c++) {
1804bb901355SGroverkss       if (atIneq(r, c) != 0)
1805bb901355SGroverkss         sum++;
1806bb901355SGroverkss     }
1807bb901355SGroverkss     if (sum > 1)
1808bb901355SGroverkss       return false;
1809bb901355SGroverkss   }
1810bb901355SGroverkss   for (unsigned r = 0, e = getNumEqualities(); r < e; r++) {
1811bb901355SGroverkss     unsigned sum = 0;
1812bb901355SGroverkss     for (unsigned c = pos; c < pos + num; c++) {
1813bb901355SGroverkss       if (atEq(r, c) != 0)
1814bb901355SGroverkss         sum++;
1815bb901355SGroverkss     }
1816bb901355SGroverkss     if (sum > 1)
1817bb901355SGroverkss       return false;
1818bb901355SGroverkss   }
1819bb901355SGroverkss   return true;
1820bb901355SGroverkss }
1821bb901355SGroverkss 
1822bb901355SGroverkss /// Removes duplicate constraints, trivially true constraints, and constraints
1823bb901355SGroverkss /// that can be detected as redundant as a result of differing only in their
1824bb901355SGroverkss /// constant term part. A constraint of the form <non-negative constant> >= 0 is
1825bb901355SGroverkss /// considered trivially true.
1826bb901355SGroverkss //  Uses a DenseSet to hash and detect duplicates followed by a linear scan to
1827bb901355SGroverkss //  remove duplicates in place.
1828bb901355SGroverkss void IntegerRelation::removeTrivialRedundancy() {
1829bb901355SGroverkss   gcdTightenInequalities();
1830bb901355SGroverkss   normalizeConstraintsByGCD();
1831bb901355SGroverkss 
1832bb901355SGroverkss   // A map used to detect redundancy stemming from constraints that only differ
1833bb901355SGroverkss   // in their constant term. The value stored is <row position, const term>
1834bb901355SGroverkss   // for a given row.
18351a0e67d7SRamkumar Ramachandra   SmallDenseMap<ArrayRef<DynamicAPInt>, std::pair<unsigned, DynamicAPInt>>
1836bb901355SGroverkss       rowsWithoutConstTerm;
1837bb901355SGroverkss   // To unique rows.
18381a0e67d7SRamkumar Ramachandra   SmallDenseSet<ArrayRef<DynamicAPInt>, 8> rowSet;
1839bb901355SGroverkss 
1840bb901355SGroverkss   // Check if constraint is of the form <non-negative-constant> >= 0.
1841bb901355SGroverkss   auto isTriviallyValid = [&](unsigned r) -> bool {
1842bb901355SGroverkss     for (unsigned c = 0, e = getNumCols() - 1; c < e; c++) {
1843bb901355SGroverkss       if (atIneq(r, c) != 0)
1844bb901355SGroverkss         return false;
1845bb901355SGroverkss     }
1846bb901355SGroverkss     return atIneq(r, getNumCols() - 1) >= 0;
1847bb901355SGroverkss   };
1848bb901355SGroverkss 
1849bb901355SGroverkss   // Detect and mark redundant constraints.
1850bb901355SGroverkss   SmallVector<bool, 256> redunIneq(getNumInequalities(), false);
1851bb901355SGroverkss   for (unsigned r = 0, e = getNumInequalities(); r < e; r++) {
18521a0e67d7SRamkumar Ramachandra     DynamicAPInt *rowStart = &inequalities(r, 0);
18531a0e67d7SRamkumar Ramachandra     auto row = ArrayRef<DynamicAPInt>(rowStart, getNumCols());
1854bb901355SGroverkss     if (isTriviallyValid(r) || !rowSet.insert(row).second) {
1855bb901355SGroverkss       redunIneq[r] = true;
1856bb901355SGroverkss       continue;
1857bb901355SGroverkss     }
1858bb901355SGroverkss 
1859bb901355SGroverkss     // Among constraints that only differ in the constant term part, mark
1860bb901355SGroverkss     // everything other than the one with the smallest constant term redundant.
1861bb901355SGroverkss     // (eg: among i - 16j - 5 >= 0, i - 16j - 1 >=0, i - 16j - 7 >= 0, the
1862bb901355SGroverkss     // former two are redundant).
18631a0e67d7SRamkumar Ramachandra     DynamicAPInt constTerm = atIneq(r, getNumCols() - 1);
18641a0e67d7SRamkumar Ramachandra     auto rowWithoutConstTerm =
18651a0e67d7SRamkumar Ramachandra         ArrayRef<DynamicAPInt>(rowStart, getNumCols() - 1);
1866bb901355SGroverkss     const auto &ret =
1867bb901355SGroverkss         rowsWithoutConstTerm.insert({rowWithoutConstTerm, {r, constTerm}});
1868bb901355SGroverkss     if (!ret.second) {
1869bb901355SGroverkss       // Check if the other constraint has a higher constant term.
1870bb901355SGroverkss       auto &val = ret.first->second;
1871bb901355SGroverkss       if (val.second > constTerm) {
1872bb901355SGroverkss         // The stored row is redundant. Mark it so, and update with this one.
1873bb901355SGroverkss         redunIneq[val.first] = true;
1874bb901355SGroverkss         val = {r, constTerm};
1875bb901355SGroverkss       } else {
1876bb901355SGroverkss         // The one stored makes this one redundant.
1877bb901355SGroverkss         redunIneq[r] = true;
1878bb901355SGroverkss       }
1879bb901355SGroverkss     }
1880bb901355SGroverkss   }
1881bb901355SGroverkss 
1882bb901355SGroverkss   // Scan to get rid of all rows marked redundant, in-place.
1883bb901355SGroverkss   unsigned pos = 0;
1884bb901355SGroverkss   for (unsigned r = 0, e = getNumInequalities(); r < e; r++)
1885bb901355SGroverkss     if (!redunIneq[r])
1886bb901355SGroverkss       inequalities.copyRow(r, pos++);
1887bb901355SGroverkss 
1888bb901355SGroverkss   inequalities.resizeVertically(pos);
1889bb901355SGroverkss 
1890bb901355SGroverkss   // TODO: consider doing this for equalities as well, but probably not worth
1891bb901355SGroverkss   // the savings.
1892bb901355SGroverkss }
1893bb901355SGroverkss 
1894bb901355SGroverkss #undef DEBUG_TYPE
1895bb901355SGroverkss #define DEBUG_TYPE "fm"
1896bb901355SGroverkss 
1897d95140a5SGroverkss /// Eliminates variable at the specified position using Fourier-Motzkin
1898bb901355SGroverkss /// variable elimination. This technique is exact for rational spaces but
1899bb901355SGroverkss /// conservative (in "rare" cases) for integer spaces. The operation corresponds
1900bb901355SGroverkss /// to a projection operation yielding the (convex) set of integer points
1901bb901355SGroverkss /// contained in the rational shadow of the set. An emptiness test that relies
1902bb901355SGroverkss /// on this method will guarantee emptiness, i.e., it disproves the existence of
1903bb901355SGroverkss /// a solution if it says it's empty.
1904bb901355SGroverkss /// If a non-null isResultIntegerExact is passed, it is set to true if the
1905bb901355SGroverkss /// result is also integer exact. If it's set to false, the obtained solution
1906bb901355SGroverkss /// *may* not be exact, i.e., it may contain integer points that do not have an
1907bb901355SGroverkss /// integer pre-image in the original set.
1908bb901355SGroverkss ///
1909bb901355SGroverkss /// Eg:
1910bb901355SGroverkss /// j >= 0, j <= i + 1
1911bb901355SGroverkss /// i >= 0, i <= N + 1
1912bb901355SGroverkss /// Eliminating i yields,
1913bb901355SGroverkss ///   j >= 0, 0 <= N + 1, j - 1 <= N + 1
1914bb901355SGroverkss ///
1915bb901355SGroverkss /// If darkShadow = true, this method computes the dark shadow on elimination;
1916bb901355SGroverkss /// the dark shadow is a convex integer subset of the exact integer shadow. A
1917bb901355SGroverkss /// non-empty dark shadow proves the existence of an integer solution. The
1918bb901355SGroverkss /// elimination in such a case could however be an under-approximation, and thus
1919bb901355SGroverkss /// should not be used for scanning sets or used by itself for dependence
1920bb901355SGroverkss /// checking.
1921bb901355SGroverkss ///
1922bb901355SGroverkss /// Eg: 2-d set, * represents grid points, 'o' represents a point in the set.
1923bb901355SGroverkss ///            ^
1924bb901355SGroverkss ///            |
1925bb901355SGroverkss ///            | * * * * o o
1926bb901355SGroverkss ///         i  | * * o o o o
1927bb901355SGroverkss ///            | o * * * * *
1928bb901355SGroverkss ///            --------------->
1929bb901355SGroverkss ///                 j ->
1930bb901355SGroverkss ///
1931bb901355SGroverkss /// Eliminating i from this system (projecting on the j dimension):
1932bb901355SGroverkss /// rational shadow / integer light shadow:  1 <= j <= 6
1933bb901355SGroverkss /// dark shadow:                             3 <= j <= 6
1934bb901355SGroverkss /// exact integer shadow:                    j = 1 \union  3 <= j <= 6
1935bb901355SGroverkss /// holes/splinters:                         j = 2
1936bb901355SGroverkss ///
1937bb901355SGroverkss /// darkShadow = false, isResultIntegerExact = nullptr are default values.
1938bb901355SGroverkss // TODO: a slight modification to yield dark shadow version of FM (tightened),
1939bb901355SGroverkss // which can prove the existence of a solution if there is one.
1940bb901355SGroverkss void IntegerRelation::fourierMotzkinEliminate(unsigned pos, bool darkShadow,
1941bb901355SGroverkss                                               bool *isResultIntegerExact) {
1942bb901355SGroverkss   LLVM_DEBUG(llvm::dbgs() << "FM input (eliminate pos " << pos << "):\n");
1943bb901355SGroverkss   LLVM_DEBUG(dump());
1944d95140a5SGroverkss   assert(pos < getNumVars() && "invalid position");
1945bb901355SGroverkss   assert(hasConsistentState());
1946bb901355SGroverkss 
1947d95140a5SGroverkss   // Check if this variable can be eliminated through a substitution.
1948bb901355SGroverkss   for (unsigned r = 0, e = getNumEqualities(); r < e; r++) {
1949bb901355SGroverkss     if (atEq(r, pos) != 0) {
1950bb901355SGroverkss       // Use Gaussian elimination here (since we have an equality).
1951f819302aSRamkumar Ramachandra       LogicalResult ret = gaussianEliminateVar(pos);
1952bb901355SGroverkss       (void)ret;
1953f819302aSRamkumar Ramachandra       assert(ret.succeeded() && "Gaussian elimination guaranteed to succeed");
1954bb901355SGroverkss       LLVM_DEBUG(llvm::dbgs() << "FM output (through Gaussian elimination):\n");
1955bb901355SGroverkss       LLVM_DEBUG(dump());
1956bb901355SGroverkss       return;
1957bb901355SGroverkss     }
1958bb901355SGroverkss   }
1959bb901355SGroverkss 
1960bb901355SGroverkss   // A fast linear time tightening.
1961bb901355SGroverkss   gcdTightenInequalities();
1962bb901355SGroverkss 
1963d95140a5SGroverkss   // Check if the variable appears at all in any of the inequalities.
1964bb901355SGroverkss   if (isColZero(pos)) {
1965bb901355SGroverkss     // If it doesn't appear, just remove the column and return.
1966bb901355SGroverkss     // TODO: refactor removeColumns to use it from here.
1967d95140a5SGroverkss     removeVar(pos);
1968bb901355SGroverkss     LLVM_DEBUG(llvm::dbgs() << "FM output:\n");
1969bb901355SGroverkss     LLVM_DEBUG(dump());
1970bb901355SGroverkss     return;
1971bb901355SGroverkss   }
1972bb901355SGroverkss 
1973bb901355SGroverkss   // Positions of constraints that are lower bounds on the variable.
1974bb901355SGroverkss   SmallVector<unsigned, 4> lbIndices;
1975bb901355SGroverkss   // Positions of constraints that are lower bounds on the variable.
1976bb901355SGroverkss   SmallVector<unsigned, 4> ubIndices;
1977bb901355SGroverkss   // Positions of constraints that do not involve the variable.
1978bb901355SGroverkss   std::vector<unsigned> nbIndices;
1979bb901355SGroverkss   nbIndices.reserve(getNumInequalities());
1980bb901355SGroverkss 
1981bb901355SGroverkss   // Gather all lower bounds and upper bounds of the variable. Since the
1982bb901355SGroverkss   // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower
1983bb901355SGroverkss   // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1.
1984bb901355SGroverkss   for (unsigned r = 0, e = getNumInequalities(); r < e; r++) {
1985bb901355SGroverkss     if (atIneq(r, pos) == 0) {
1986d95140a5SGroverkss       // Var does not appear in bound.
1987266a5a9cSRamkumar Ramachandra       nbIndices.emplace_back(r);
1988bb901355SGroverkss     } else if (atIneq(r, pos) >= 1) {
1989bb901355SGroverkss       // Lower bound.
1990266a5a9cSRamkumar Ramachandra       lbIndices.emplace_back(r);
1991bb901355SGroverkss     } else {
1992bb901355SGroverkss       // Upper bound.
1993266a5a9cSRamkumar Ramachandra       ubIndices.emplace_back(r);
1994bb901355SGroverkss     }
1995bb901355SGroverkss   }
1996bb901355SGroverkss 
1997a5a598beSGroverkss   PresburgerSpace newSpace = getSpace();
1998d95140a5SGroverkss   VarKind idKindRemove = newSpace.getVarKindAt(pos);
1999d95140a5SGroverkss   unsigned relativePos = pos - newSpace.getVarKindOffset(idKindRemove);
2000d95140a5SGroverkss   newSpace.removeVarRange(idKindRemove, relativePos, relativePos + 1);
2001bb901355SGroverkss 
2002d95140a5SGroverkss   /// Create the new system which has one variable less.
2003bb901355SGroverkss   IntegerRelation newRel(lbIndices.size() * ubIndices.size() + nbIndices.size(),
2004a5a598beSGroverkss                          getNumEqualities(), getNumCols() - 1, newSpace);
2005bb901355SGroverkss 
2006bb901355SGroverkss   // This will be used to check if the elimination was integer exact.
2007bad95b72SArjun P   bool allLCMsAreOne = true;
2008bb901355SGroverkss 
2009bb901355SGroverkss   // Let x be the variable we are eliminating.
2010bb901355SGroverkss   // For each lower bound, lb <= c_l*x, and each upper bound c_u*x <= ub, (note
2011bb901355SGroverkss   // that c_l, c_u >= 1) we have:
2012bb901355SGroverkss   // lb*lcm(c_l, c_u)/c_l <= lcm(c_l, c_u)*x <= ub*lcm(c_l, c_u)/c_u
2013bb901355SGroverkss   // We thus generate a constraint:
2014bb901355SGroverkss   // lcm(c_l, c_u)/c_l*lb <= lcm(c_l, c_u)/c_u*ub.
2015bb901355SGroverkss   // Note if c_l = c_u = 1, all integer points captured by the resulting
2016bb901355SGroverkss   // constraint correspond to integer points in the original system (i.e., they
2017bb901355SGroverkss   // have integer pre-images). Hence, if the lcm's are all 1, the elimination is
2018bb901355SGroverkss   // integer exact.
2019bb901355SGroverkss   for (auto ubPos : ubIndices) {
2020bb901355SGroverkss     for (auto lbPos : lbIndices) {
20211a0e67d7SRamkumar Ramachandra       SmallVector<DynamicAPInt, 4> ineq;
2022bb901355SGroverkss       ineq.reserve(newRel.getNumCols());
20231a0e67d7SRamkumar Ramachandra       DynamicAPInt lbCoeff = atIneq(lbPos, pos);
2024bb901355SGroverkss       // Note that in the comments above, ubCoeff is the negation of the
2025bb901355SGroverkss       // coefficient in the canonical form as the view taken here is that of the
2026bb901355SGroverkss       // term being moved to the other size of '>='.
20271a0e67d7SRamkumar Ramachandra       DynamicAPInt ubCoeff = -atIneq(ubPos, pos);
2028bb901355SGroverkss       // TODO: refactor this loop to avoid all branches inside.
2029bb901355SGroverkss       for (unsigned l = 0, e = getNumCols(); l < e; l++) {
2030bb901355SGroverkss         if (l == pos)
2031bb901355SGroverkss           continue;
2032bb901355SGroverkss         assert(lbCoeff >= 1 && ubCoeff >= 1 && "bounds wrongly identified");
20331a0e67d7SRamkumar Ramachandra         DynamicAPInt lcm = llvm::lcm(lbCoeff, ubCoeff);
2034266a5a9cSRamkumar Ramachandra         ineq.emplace_back(atIneq(ubPos, l) * (lcm / ubCoeff) +
2035bb901355SGroverkss                           atIneq(lbPos, l) * (lcm / lbCoeff));
2036bad95b72SArjun P         assert(lcm > 0 && "lcm should be positive!");
2037bad95b72SArjun P         if (lcm != 1)
2038bad95b72SArjun P           allLCMsAreOne = false;
2039bb901355SGroverkss       }
2040bb901355SGroverkss       if (darkShadow) {
2041bb901355SGroverkss         // The dark shadow is a convex subset of the exact integer shadow. If
2042bb901355SGroverkss         // there is a point here, it proves the existence of a solution.
2043bb901355SGroverkss         ineq[ineq.size() - 1] += lbCoeff * ubCoeff - lbCoeff - ubCoeff + 1;
2044bb901355SGroverkss       }
2045bb901355SGroverkss       // TODO: we need to have a way to add inequalities in-place in
2046bb901355SGroverkss       // IntegerRelation instead of creating and copying over.
2047bb901355SGroverkss       newRel.addInequality(ineq);
2048bb901355SGroverkss     }
2049bb901355SGroverkss   }
2050bb901355SGroverkss 
2051bad95b72SArjun P   LLVM_DEBUG(llvm::dbgs() << "FM isResultIntegerExact: " << allLCMsAreOne
2052bb901355SGroverkss                           << "\n");
2053bad95b72SArjun P   if (allLCMsAreOne && isResultIntegerExact)
2054bb901355SGroverkss     *isResultIntegerExact = true;
2055bb901355SGroverkss 
2056bb901355SGroverkss   // Copy over the constraints not involving this variable.
2057bb901355SGroverkss   for (auto nbPos : nbIndices) {
20581a0e67d7SRamkumar Ramachandra     SmallVector<DynamicAPInt, 4> ineq;
2059bb901355SGroverkss     ineq.reserve(getNumCols() - 1);
2060bb901355SGroverkss     for (unsigned l = 0, e = getNumCols(); l < e; l++) {
2061bb901355SGroverkss       if (l == pos)
2062bb901355SGroverkss         continue;
2063266a5a9cSRamkumar Ramachandra       ineq.emplace_back(atIneq(nbPos, l));
2064bb901355SGroverkss     }
2065bb901355SGroverkss     newRel.addInequality(ineq);
2066bb901355SGroverkss   }
2067bb901355SGroverkss 
2068bb901355SGroverkss   assert(newRel.getNumConstraints() ==
2069bb901355SGroverkss          lbIndices.size() * ubIndices.size() + nbIndices.size());
2070bb901355SGroverkss 
2071bb901355SGroverkss   // Copy over the equalities.
2072bb901355SGroverkss   for (unsigned r = 0, e = getNumEqualities(); r < e; r++) {
20731a0e67d7SRamkumar Ramachandra     SmallVector<DynamicAPInt, 4> eq;
2074bb901355SGroverkss     eq.reserve(newRel.getNumCols());
2075bb901355SGroverkss     for (unsigned l = 0, e = getNumCols(); l < e; l++) {
2076bb901355SGroverkss       if (l == pos)
2077bb901355SGroverkss         continue;
2078266a5a9cSRamkumar Ramachandra       eq.emplace_back(atEq(r, l));
2079bb901355SGroverkss     }
2080bb901355SGroverkss     newRel.addEquality(eq);
2081bb901355SGroverkss   }
2082bb901355SGroverkss 
2083bb901355SGroverkss   // GCD tightening and normalization allows detection of more trivially
2084bb901355SGroverkss   // redundant constraints.
2085bb901355SGroverkss   newRel.gcdTightenInequalities();
2086bb901355SGroverkss   newRel.normalizeConstraintsByGCD();
2087bb901355SGroverkss   newRel.removeTrivialRedundancy();
2088bb901355SGroverkss   clearAndCopyFrom(newRel);
2089bb901355SGroverkss   LLVM_DEBUG(llvm::dbgs() << "FM output:\n");
2090bb901355SGroverkss   LLVM_DEBUG(dump());
2091bb901355SGroverkss }
2092bb901355SGroverkss 
2093bb901355SGroverkss #undef DEBUG_TYPE
2094bb901355SGroverkss #define DEBUG_TYPE "presburger"
2095bb901355SGroverkss 
2096bb901355SGroverkss void IntegerRelation::projectOut(unsigned pos, unsigned num) {
2097bb901355SGroverkss   if (num == 0)
2098bb901355SGroverkss     return;
2099bb901355SGroverkss 
2100bb901355SGroverkss   // 'pos' can be at most getNumCols() - 2 if num > 0.
2101bb901355SGroverkss   assert((getNumCols() < 2 || pos <= getNumCols() - 2) && "invalid position");
2102bb901355SGroverkss   assert(pos + num < getNumCols() && "invalid range");
2103bb901355SGroverkss 
2104d95140a5SGroverkss   // Eliminate as many variables as possible using Gaussian elimination.
2105bb901355SGroverkss   unsigned currentPos = pos;
2106bb901355SGroverkss   unsigned numToEliminate = num;
2107bb901355SGroverkss   unsigned numGaussianEliminated = 0;
2108bb901355SGroverkss 
2109d95140a5SGroverkss   while (currentPos < getNumVars()) {
2110bb901355SGroverkss     unsigned curNumEliminated =
2111d95140a5SGroverkss         gaussianEliminateVars(currentPos, currentPos + numToEliminate);
2112bb901355SGroverkss     ++currentPos;
2113bb901355SGroverkss     numToEliminate -= curNumEliminated + 1;
2114bb901355SGroverkss     numGaussianEliminated += curNumEliminated;
2115bb901355SGroverkss   }
2116bb901355SGroverkss 
2117bb901355SGroverkss   // Eliminate the remaining using Fourier-Motzkin.
2118bb901355SGroverkss   for (unsigned i = 0; i < num - numGaussianEliminated; i++) {
2119bb901355SGroverkss     unsigned numToEliminate = num - numGaussianEliminated - i;
2120bb901355SGroverkss     fourierMotzkinEliminate(
2121d95140a5SGroverkss         getBestVarToEliminate(*this, pos, pos + numToEliminate));
2122bb901355SGroverkss   }
2123bb901355SGroverkss 
2124bb901355SGroverkss   // Fast/trivial simplifications.
2125bb901355SGroverkss   gcdTightenInequalities();
2126bb901355SGroverkss   // Normalize constraints after tightening since the latter impacts this, but
2127bb901355SGroverkss   // not the other way round.
2128bb901355SGroverkss   normalizeConstraintsByGCD();
2129bb901355SGroverkss }
2130bb901355SGroverkss 
2131bb901355SGroverkss namespace {
2132bb901355SGroverkss 
2133bb901355SGroverkss enum BoundCmpResult { Greater, Less, Equal, Unknown };
2134bb901355SGroverkss 
2135bb901355SGroverkss /// Compares two affine bounds whose coefficients are provided in 'first' and
2136bb901355SGroverkss /// 'second'. The last coefficient is the constant term.
21371a0e67d7SRamkumar Ramachandra static BoundCmpResult compareBounds(ArrayRef<DynamicAPInt> a,
21381a0e67d7SRamkumar Ramachandra                                     ArrayRef<DynamicAPInt> b) {
2139bb901355SGroverkss   assert(a.size() == b.size());
2140bb901355SGroverkss 
2141d95140a5SGroverkss   // For the bounds to be comparable, their corresponding variable
2142bb901355SGroverkss   // coefficients should be equal; the constant terms are then compared to
2143bb901355SGroverkss   // determine less/greater/equal.
2144bb901355SGroverkss 
2145bb901355SGroverkss   if (!std::equal(a.begin(), a.end() - 1, b.begin()))
2146bb901355SGroverkss     return Unknown;
2147bb901355SGroverkss 
2148bb901355SGroverkss   if (a.back() == b.back())
2149bb901355SGroverkss     return Equal;
2150bb901355SGroverkss 
2151bb901355SGroverkss   return a.back() < b.back() ? Less : Greater;
2152bb901355SGroverkss }
2153bb901355SGroverkss } // namespace
2154bb901355SGroverkss 
2155bb901355SGroverkss // Returns constraints that are common to both A & B.
2156bb901355SGroverkss static void getCommonConstraints(const IntegerRelation &a,
2157bb901355SGroverkss                                  const IntegerRelation &b, IntegerRelation &c) {
2158a5a598beSGroverkss   c = IntegerRelation(a.getSpace());
2159bb901355SGroverkss   // a naive O(n^2) check should be enough here given the input sizes.
2160bb901355SGroverkss   for (unsigned r = 0, e = a.getNumInequalities(); r < e; ++r) {
2161bb901355SGroverkss     for (unsigned s = 0, f = b.getNumInequalities(); s < f; ++s) {
2162bb901355SGroverkss       if (a.getInequality(r) == b.getInequality(s)) {
2163bb901355SGroverkss         c.addInequality(a.getInequality(r));
2164bb901355SGroverkss         break;
2165bb901355SGroverkss       }
2166bb901355SGroverkss     }
2167bb901355SGroverkss   }
2168bb901355SGroverkss   for (unsigned r = 0, e = a.getNumEqualities(); r < e; ++r) {
2169bb901355SGroverkss     for (unsigned s = 0, f = b.getNumEqualities(); s < f; ++s) {
2170bb901355SGroverkss       if (a.getEquality(r) == b.getEquality(s)) {
2171bb901355SGroverkss         c.addEquality(a.getEquality(r));
2172bb901355SGroverkss         break;
2173bb901355SGroverkss       }
2174bb901355SGroverkss     }
2175bb901355SGroverkss   }
2176bb901355SGroverkss }
2177bb901355SGroverkss 
2178bb901355SGroverkss // Computes the bounding box with respect to 'other' by finding the min of the
2179bb901355SGroverkss // lower bounds and the max of the upper bounds along each of the dimensions.
2180f819302aSRamkumar Ramachandra LogicalResult
2181f819302aSRamkumar Ramachandra IntegerRelation::unionBoundingBox(const IntegerRelation &otherCst) {
218220aedb14SGroverkss   assert(space.isEqual(otherCst.getSpace()) && "Spaces should match.");
2183d95140a5SGroverkss   assert(getNumLocalVars() == 0 && "local ids not supported yet here");
2184bb901355SGroverkss 
2185bb901355SGroverkss   // Get the constraints common to both systems; these will be added as is to
2186bb901355SGroverkss   // the union.
2187a5a598beSGroverkss   IntegerRelation commonCst(PresburgerSpace::getRelationSpace());
2188bb901355SGroverkss   getCommonConstraints(*this, otherCst, commonCst);
2189bb901355SGroverkss 
21901a0e67d7SRamkumar Ramachandra   std::vector<SmallVector<DynamicAPInt, 8>> boundingLbs;
21911a0e67d7SRamkumar Ramachandra   std::vector<SmallVector<DynamicAPInt, 8>> boundingUbs;
2192d95140a5SGroverkss   boundingLbs.reserve(2 * getNumDimVars());
2193d95140a5SGroverkss   boundingUbs.reserve(2 * getNumDimVars());
2194bb901355SGroverkss 
2195bb901355SGroverkss   // To hold lower and upper bounds for each dimension.
21961a0e67d7SRamkumar Ramachandra   SmallVector<DynamicAPInt, 4> lb, otherLb, ub, otherUb;
2197bb901355SGroverkss   // To compute min of lower bounds and max of upper bounds for each dimension.
21981a0e67d7SRamkumar Ramachandra   SmallVector<DynamicAPInt, 4> minLb(getNumSymbolVars() + 1);
21991a0e67d7SRamkumar Ramachandra   SmallVector<DynamicAPInt, 4> maxUb(getNumSymbolVars() + 1);
2200bb901355SGroverkss   // To compute final new lower and upper bounds for the union.
22011a0e67d7SRamkumar Ramachandra   SmallVector<DynamicAPInt, 8> newLb(getNumCols()), newUb(getNumCols());
2202bb901355SGroverkss 
22031a0e67d7SRamkumar Ramachandra   DynamicAPInt lbFloorDivisor, otherLbFloorDivisor;
2204d95140a5SGroverkss   for (unsigned d = 0, e = getNumDimVars(); d < e; ++d) {
2205bb901355SGroverkss     auto extent = getConstantBoundOnDimSize(d, &lb, &lbFloorDivisor, &ub);
2206491d2701SKazu Hirata     if (!extent.has_value())
2207bb901355SGroverkss       // TODO: symbolic extents when necessary.
2208bb901355SGroverkss       // TODO: handle union if a dimension is unbounded.
2209f819302aSRamkumar Ramachandra       return failure();
2210bb901355SGroverkss 
2211bb901355SGroverkss     auto otherExtent = otherCst.getConstantBoundOnDimSize(
2212bb901355SGroverkss         d, &otherLb, &otherLbFloorDivisor, &otherUb);
2213491d2701SKazu Hirata     if (!otherExtent.has_value() || lbFloorDivisor != otherLbFloorDivisor)
2214bb901355SGroverkss       // TODO: symbolic extents when necessary.
2215f819302aSRamkumar Ramachandra       return failure();
2216bb901355SGroverkss 
2217bb901355SGroverkss     assert(lbFloorDivisor > 0 && "divisor always expected to be positive");
2218bb901355SGroverkss 
2219bb901355SGroverkss     auto res = compareBounds(lb, otherLb);
2220bb901355SGroverkss     // Identify min.
2221bb901355SGroverkss     if (res == BoundCmpResult::Less || res == BoundCmpResult::Equal) {
2222bb901355SGroverkss       minLb = lb;
2223bb901355SGroverkss       // Since the divisor is for a floordiv, we need to convert to ceildiv,
2224bb901355SGroverkss       // i.e., i >= expr floordiv div <=> i >= (expr - div + 1) ceildiv div <=>
2225bb901355SGroverkss       // div * i >= expr - div + 1.
2226bb901355SGroverkss       minLb.back() -= lbFloorDivisor - 1;
2227bb901355SGroverkss     } else if (res == BoundCmpResult::Greater) {
2228bb901355SGroverkss       minLb = otherLb;
2229bb901355SGroverkss       minLb.back() -= otherLbFloorDivisor - 1;
2230bb901355SGroverkss     } else {
2231bb901355SGroverkss       // Uncomparable - check for constant lower/upper bounds.
2232bb901355SGroverkss       auto constLb = getConstantBound(BoundType::LB, d);
2233bb901355SGroverkss       auto constOtherLb = otherCst.getConstantBound(BoundType::LB, d);
2234491d2701SKazu Hirata       if (!constLb.has_value() || !constOtherLb.has_value())
2235f819302aSRamkumar Ramachandra         return failure();
2236bb901355SGroverkss       std::fill(minLb.begin(), minLb.end(), 0);
2237cc037e17SFangrui Song       minLb.back() = std::min(*constLb, *constOtherLb);
2238bb901355SGroverkss     }
2239bb901355SGroverkss 
2240bb901355SGroverkss     // Do the same for ub's but max of upper bounds. Identify max.
2241bb901355SGroverkss     auto uRes = compareBounds(ub, otherUb);
2242bb901355SGroverkss     if (uRes == BoundCmpResult::Greater || uRes == BoundCmpResult::Equal) {
2243bb901355SGroverkss       maxUb = ub;
2244bb901355SGroverkss     } else if (uRes == BoundCmpResult::Less) {
2245bb901355SGroverkss       maxUb = otherUb;
2246bb901355SGroverkss     } else {
2247bb901355SGroverkss       // Uncomparable - check for constant lower/upper bounds.
2248bb901355SGroverkss       auto constUb = getConstantBound(BoundType::UB, d);
2249bb901355SGroverkss       auto constOtherUb = otherCst.getConstantBound(BoundType::UB, d);
2250491d2701SKazu Hirata       if (!constUb.has_value() || !constOtherUb.has_value())
2251f819302aSRamkumar Ramachandra         return failure();
2252bb901355SGroverkss       std::fill(maxUb.begin(), maxUb.end(), 0);
2253cc037e17SFangrui Song       maxUb.back() = std::max(*constUb, *constOtherUb);
2254bb901355SGroverkss     }
2255bb901355SGroverkss 
2256bb901355SGroverkss     std::fill(newLb.begin(), newLb.end(), 0);
2257bb901355SGroverkss     std::fill(newUb.begin(), newUb.end(), 0);
2258bb901355SGroverkss 
2259bb901355SGroverkss     // The divisor for lb, ub, otherLb, otherUb at this point is lbDivisor,
2260bb901355SGroverkss     // and so it's the divisor for newLb and newUb as well.
2261bb901355SGroverkss     newLb[d] = lbFloorDivisor;
2262bb901355SGroverkss     newUb[d] = -lbFloorDivisor;
2263bb901355SGroverkss     // Copy over the symbolic part + constant term.
2264d95140a5SGroverkss     std::copy(minLb.begin(), minLb.end(), newLb.begin() + getNumDimVars());
2265d95140a5SGroverkss     std::transform(newLb.begin() + getNumDimVars(), newLb.end(),
22661a0e67d7SRamkumar Ramachandra                    newLb.begin() + getNumDimVars(),
22671a0e67d7SRamkumar Ramachandra                    std::negate<DynamicAPInt>());
2268d95140a5SGroverkss     std::copy(maxUb.begin(), maxUb.end(), newUb.begin() + getNumDimVars());
2269bb901355SGroverkss 
2270266a5a9cSRamkumar Ramachandra     boundingLbs.emplace_back(newLb);
2271266a5a9cSRamkumar Ramachandra     boundingUbs.emplace_back(newUb);
2272bb901355SGroverkss   }
2273bb901355SGroverkss 
2274bb901355SGroverkss   // Clear all constraints and add the lower/upper bounds for the bounding box.
2275bb901355SGroverkss   clearConstraints();
2276d95140a5SGroverkss   for (unsigned d = 0, e = getNumDimVars(); d < e; ++d) {
2277bb901355SGroverkss     addInequality(boundingLbs[d]);
2278bb901355SGroverkss     addInequality(boundingUbs[d]);
2279bb901355SGroverkss   }
2280bb901355SGroverkss 
2281bb901355SGroverkss   // Add the constraints that were common to both systems.
2282bb901355SGroverkss   append(commonCst);
2283bb901355SGroverkss   removeTrivialRedundancy();
2284bb901355SGroverkss 
2285bb901355SGroverkss   // TODO: copy over pure symbolic constraints from this and 'other' over to the
2286bb901355SGroverkss   // union (since the above are just the union along dimensions); we shouldn't
2287bb901355SGroverkss   // be discarding any other constraints on the symbols.
2288bb901355SGroverkss 
2289f819302aSRamkumar Ramachandra   return success();
2290bb901355SGroverkss }
2291bb901355SGroverkss 
2292bb901355SGroverkss bool IntegerRelation::isColZero(unsigned pos) const {
2293bb901355SGroverkss   unsigned rowPos;
2294bb901355SGroverkss   return !findConstraintWithNonZeroAt(pos, /*isEq=*/false, &rowPos) &&
2295bb901355SGroverkss          !findConstraintWithNonZeroAt(pos, /*isEq=*/true, &rowPos);
2296bb901355SGroverkss }
2297bb901355SGroverkss 
2298bb901355SGroverkss /// Find positions of inequalities and equalities that do not have a coefficient
2299d95140a5SGroverkss /// for [pos, pos + num) variables.
2300bb901355SGroverkss static void getIndependentConstraints(const IntegerRelation &cst, unsigned pos,
2301bb901355SGroverkss                                       unsigned num,
2302bb901355SGroverkss                                       SmallVectorImpl<unsigned> &nbIneqIndices,
2303bb901355SGroverkss                                       SmallVectorImpl<unsigned> &nbEqIndices) {
2304d95140a5SGroverkss   assert(pos < cst.getNumVars() && "invalid start position");
2305d95140a5SGroverkss   assert(pos + num <= cst.getNumVars() && "invalid limit");
2306bb901355SGroverkss 
2307bb901355SGroverkss   for (unsigned r = 0, e = cst.getNumInequalities(); r < e; r++) {
2308bb901355SGroverkss     // The bounds are to be independent of [offset, offset + num) columns.
2309bb901355SGroverkss     unsigned c;
2310bb901355SGroverkss     for (c = pos; c < pos + num; ++c) {
2311bb901355SGroverkss       if (cst.atIneq(r, c) != 0)
2312bb901355SGroverkss         break;
2313bb901355SGroverkss     }
2314bb901355SGroverkss     if (c == pos + num)
2315266a5a9cSRamkumar Ramachandra       nbIneqIndices.emplace_back(r);
2316bb901355SGroverkss   }
2317bb901355SGroverkss 
2318bb901355SGroverkss   for (unsigned r = 0, e = cst.getNumEqualities(); r < e; r++) {
2319bb901355SGroverkss     // The bounds are to be independent of [offset, offset + num) columns.
2320bb901355SGroverkss     unsigned c;
2321bb901355SGroverkss     for (c = pos; c < pos + num; ++c) {
2322bb901355SGroverkss       if (cst.atEq(r, c) != 0)
2323bb901355SGroverkss         break;
2324bb901355SGroverkss     }
2325bb901355SGroverkss     if (c == pos + num)
2326266a5a9cSRamkumar Ramachandra       nbEqIndices.emplace_back(r);
2327bb901355SGroverkss   }
2328bb901355SGroverkss }
2329bb901355SGroverkss 
2330bb901355SGroverkss void IntegerRelation::removeIndependentConstraints(unsigned pos, unsigned num) {
2331d95140a5SGroverkss   assert(pos + num <= getNumVars() && "invalid range");
2332bb901355SGroverkss 
2333d95140a5SGroverkss   // Remove constraints that are independent of these variables.
2334bb901355SGroverkss   SmallVector<unsigned, 4> nbIneqIndices, nbEqIndices;
2335bb901355SGroverkss   getIndependentConstraints(*this, /*pos=*/0, num, nbIneqIndices, nbEqIndices);
2336bb901355SGroverkss 
2337bb901355SGroverkss   // Iterate in reverse so that indices don't have to be updated.
2338bb901355SGroverkss   // TODO: This method can be made more efficient (because removal of each
2339bb901355SGroverkss   // inequality leads to much shifting/copying in the underlying buffer).
2340bb901355SGroverkss   for (auto nbIndex : llvm::reverse(nbIneqIndices))
2341bb901355SGroverkss     removeInequality(nbIndex);
2342bb901355SGroverkss   for (auto nbIndex : llvm::reverse(nbEqIndices))
2343bb901355SGroverkss     removeEquality(nbIndex);
2344bb901355SGroverkss }
2345bb901355SGroverkss 
23463c057ac2SGroverkss IntegerPolyhedron IntegerRelation::getDomainSet() const {
23473c057ac2SGroverkss   IntegerRelation copyRel = *this;
23483c057ac2SGroverkss 
23493c057ac2SGroverkss   // Convert Range variables to Local variables.
2350d95140a5SGroverkss   copyRel.convertVarKind(VarKind::Range, 0, getNumVarKind(VarKind::Range),
2351d95140a5SGroverkss                          VarKind::Local);
23523c057ac2SGroverkss 
23533c057ac2SGroverkss   // Convert Domain variables to SetDim(Range) variables.
2354d95140a5SGroverkss   copyRel.convertVarKind(VarKind::Domain, 0, getNumVarKind(VarKind::Domain),
2355d95140a5SGroverkss                          VarKind::SetDim);
23563c057ac2SGroverkss 
23573c057ac2SGroverkss   return IntegerPolyhedron(std::move(copyRel));
23583c057ac2SGroverkss }
23593c057ac2SGroverkss 
236039b93955Sgilsaia bool IntegerRelation::removeDuplicateConstraints() {
236139b93955Sgilsaia   bool changed = false;
23621a0e67d7SRamkumar Ramachandra   SmallDenseMap<ArrayRef<DynamicAPInt>, unsigned> hashTable;
236339b93955Sgilsaia   unsigned ineqs = getNumInequalities(), cols = getNumCols();
236439b93955Sgilsaia 
236539b93955Sgilsaia   if (ineqs <= 1)
236639b93955Sgilsaia     return changed;
236739b93955Sgilsaia 
236839b93955Sgilsaia   // Check if the non-constant part of the constraint is the same.
23691a0e67d7SRamkumar Ramachandra   ArrayRef<DynamicAPInt> row = getInequality(0).drop_back();
237039b93955Sgilsaia   hashTable.insert({row, 0});
237139b93955Sgilsaia   for (unsigned k = 1; k < ineqs; ++k) {
237239b93955Sgilsaia     row = getInequality(k).drop_back();
2373b2dbcf4dSKazu Hirata     if (hashTable.try_emplace(row, k).second)
237439b93955Sgilsaia       continue;
237539b93955Sgilsaia 
237639b93955Sgilsaia     // For identical cases, keep only the smaller part of the constant term.
237739b93955Sgilsaia     unsigned l = hashTable[row];
237839b93955Sgilsaia     changed = true;
237939b93955Sgilsaia     if (atIneq(k, cols - 1) <= atIneq(l, cols - 1))
238039b93955Sgilsaia       inequalities.swapRows(k, l);
238139b93955Sgilsaia     removeInequality(k);
238239b93955Sgilsaia     --k;
238339b93955Sgilsaia     --ineqs;
238439b93955Sgilsaia   }
238539b93955Sgilsaia 
238639b93955Sgilsaia   // Check the neg form of each inequality, need an extra vector to store it.
23871a0e67d7SRamkumar Ramachandra   SmallVector<DynamicAPInt> negIneq(cols - 1);
238839b93955Sgilsaia   for (unsigned k = 0; k < ineqs; ++k) {
238939b93955Sgilsaia     row = getInequality(k).drop_back();
239039b93955Sgilsaia     negIneq.assign(row.begin(), row.end());
23911a0e67d7SRamkumar Ramachandra     for (DynamicAPInt &ele : negIneq)
239239b93955Sgilsaia       ele = -ele;
239339b93955Sgilsaia     if (!hashTable.contains(negIneq))
239439b93955Sgilsaia       continue;
239539b93955Sgilsaia 
239639b93955Sgilsaia     // For cases where the neg is the same as other inequalities, check that the
239739b93955Sgilsaia     // sum of their constant terms is positive.
239839b93955Sgilsaia     unsigned l = hashTable[row];
239939b93955Sgilsaia     auto sum = atIneq(l, cols - 1) + atIneq(k, cols - 1);
240039b93955Sgilsaia     if (sum > 0 || l == k)
240139b93955Sgilsaia       continue;
240239b93955Sgilsaia 
240339b93955Sgilsaia     // A sum of constant terms equal to zero combines two inequalities into one
240439b93955Sgilsaia     // equation, less than zero means the set is empty.
240539b93955Sgilsaia     changed = true;
240639b93955Sgilsaia     if (k < l)
240739b93955Sgilsaia       std::swap(l, k);
240839b93955Sgilsaia     if (sum == 0) {
240939b93955Sgilsaia       addEquality(getInequality(k));
241039b93955Sgilsaia       removeInequality(k);
241139b93955Sgilsaia       removeInequality(l);
241239b93955Sgilsaia     } else
241339b93955Sgilsaia       *this = getEmpty(getSpace());
241439b93955Sgilsaia     break;
241539b93955Sgilsaia   }
241639b93955Sgilsaia 
241739b93955Sgilsaia   return changed;
241839b93955Sgilsaia }
241939b93955Sgilsaia 
24203c057ac2SGroverkss IntegerPolyhedron IntegerRelation::getRangeSet() const {
24213c057ac2SGroverkss   IntegerRelation copyRel = *this;
24223c057ac2SGroverkss 
24233c057ac2SGroverkss   // Convert Domain variables to Local variables.
2424d95140a5SGroverkss   copyRel.convertVarKind(VarKind::Domain, 0, getNumVarKind(VarKind::Domain),
2425d95140a5SGroverkss                          VarKind::Local);
24263c057ac2SGroverkss 
24273c057ac2SGroverkss   // We do not need to do anything to Range variables since they are already in
24283c057ac2SGroverkss   // SetDim position.
24293c057ac2SGroverkss 
24303c057ac2SGroverkss   return IntegerPolyhedron(std::move(copyRel));
24313c057ac2SGroverkss }
24323c057ac2SGroverkss 
2433f168a659SGroverkss void IntegerRelation::intersectDomain(const IntegerPolyhedron &poly) {
2434f168a659SGroverkss   assert(getDomainSet().getSpace().isCompatible(poly.getSpace()) &&
2435f168a659SGroverkss          "Domain set is not compatible with poly");
2436f168a659SGroverkss 
2437f168a659SGroverkss   // Treating the poly as a relation, convert it from `0 -> R` to `R -> 0`.
2438f168a659SGroverkss   IntegerRelation rel = poly;
2439f168a659SGroverkss   rel.inverse();
2440f168a659SGroverkss 
2441f168a659SGroverkss   // Append dummy range variables to make the spaces compatible.
2442d95140a5SGroverkss   rel.appendVar(VarKind::Range, getNumRangeVars());
2443f168a659SGroverkss 
2444f168a659SGroverkss   // Intersect in place.
2445d95140a5SGroverkss   mergeLocalVars(rel);
2446f168a659SGroverkss   append(rel);
2447f168a659SGroverkss }
2448f168a659SGroverkss 
2449f168a659SGroverkss void IntegerRelation::intersectRange(const IntegerPolyhedron &poly) {
2450f168a659SGroverkss   assert(getRangeSet().getSpace().isCompatible(poly.getSpace()) &&
2451f168a659SGroverkss          "Range set is not compatible with poly");
2452f168a659SGroverkss 
2453f168a659SGroverkss   IntegerRelation rel = poly;
2454f168a659SGroverkss 
2455f168a659SGroverkss   // Append dummy domain variables to make the spaces compatible.
2456d95140a5SGroverkss   rel.appendVar(VarKind::Domain, getNumDomainVars());
2457f168a659SGroverkss 
2458d95140a5SGroverkss   mergeLocalVars(rel);
2459f168a659SGroverkss   append(rel);
2460f168a659SGroverkss }
2461f168a659SGroverkss 
2462fb857dedSGroverkss void IntegerRelation::inverse() {
2463d95140a5SGroverkss   unsigned numRangeVars = getNumVarKind(VarKind::Range);
2464d95140a5SGroverkss   convertVarKind(VarKind::Domain, 0, getVarKindEnd(VarKind::Domain),
2465d95140a5SGroverkss                  VarKind::Range);
2466d95140a5SGroverkss   convertVarKind(VarKind::Range, 0, numRangeVars, VarKind::Domain);
2467fb857dedSGroverkss }
2468fb857dedSGroverkss 
2469dac27da7SGroverkss void IntegerRelation::compose(const IntegerRelation &rel) {
2470dac27da7SGroverkss   assert(getRangeSet().getSpace().isCompatible(rel.getDomainSet().getSpace()) &&
2471dac27da7SGroverkss          "Range of `this` should be compatible with Domain of `rel`");
2472dac27da7SGroverkss 
2473dac27da7SGroverkss   IntegerRelation copyRel = rel;
2474dac27da7SGroverkss 
2475dac27da7SGroverkss   // Let relation `this` be R1: A -> B, and `rel` be R2: B -> C.
2476dac27da7SGroverkss   // We convert R1 to A -> (B X C), and R2 to B X C then intersect the range of
2477dac27da7SGroverkss   // R1 with R2. After this, we get R1: A -> C, by projecting out B.
2478dac27da7SGroverkss   // TODO: Using nested spaces here would help, since we could directly
2479dac27da7SGroverkss   // intersect the range with another relation.
2480d95140a5SGroverkss   unsigned numBVars = getNumRangeVars();
2481dac27da7SGroverkss 
2482dac27da7SGroverkss   // Convert R1 from A -> B to A -> (B X C).
2483d95140a5SGroverkss   appendVar(VarKind::Range, copyRel.getNumRangeVars());
2484dac27da7SGroverkss 
2485dac27da7SGroverkss   // Convert R2 to B X C.
2486d08522f5SArjun P   copyRel.convertVarKind(VarKind::Domain, 0, numBVars, VarKind::Range, 0);
2487dac27da7SGroverkss 
2488dac27da7SGroverkss   // Intersect R2 to range of R1.
2489dac27da7SGroverkss   intersectRange(IntegerPolyhedron(copyRel));
2490dac27da7SGroverkss 
2491dac27da7SGroverkss   // Project out B in R1.
2492d95140a5SGroverkss   convertVarKind(VarKind::Range, 0, numBVars, VarKind::Local);
2493dac27da7SGroverkss }
2494dac27da7SGroverkss 
2495dac27da7SGroverkss void IntegerRelation::applyDomain(const IntegerRelation &rel) {
2496dac27da7SGroverkss   inverse();
2497dac27da7SGroverkss   compose(rel);
2498dac27da7SGroverkss   inverse();
2499dac27da7SGroverkss }
2500dac27da7SGroverkss 
2501dac27da7SGroverkss void IntegerRelation::applyRange(const IntegerRelation &rel) { compose(rel); }
2502dac27da7SGroverkss 
2503bb901355SGroverkss void IntegerRelation::printSpace(raw_ostream &os) const {
250420aedb14SGroverkss   space.print(os);
2505bb901355SGroverkss   os << getNumConstraints() << " constraints\n";
2506bb901355SGroverkss }
2507bb901355SGroverkss 
2508562790f3SAbhinav271828 void IntegerRelation::removeTrivialEqualities() {
2509562790f3SAbhinav271828   for (int i = getNumEqualities() - 1; i >= 0; --i)
2510562790f3SAbhinav271828     if (rangeIsZero(getEquality(i)))
2511562790f3SAbhinav271828       removeEquality(i);
2512562790f3SAbhinav271828 }
2513562790f3SAbhinav271828 
2514562790f3SAbhinav271828 bool IntegerRelation::isFullDim() {
2515562790f3SAbhinav271828   if (getNumVars() == 0)
2516562790f3SAbhinav271828     return true;
2517562790f3SAbhinav271828   if (isEmpty())
2518562790f3SAbhinav271828     return false;
2519562790f3SAbhinav271828 
2520562790f3SAbhinav271828   // If there is a non-trivial equality, the space cannot be full-dimensional.
2521562790f3SAbhinav271828   removeTrivialEqualities();
2522562790f3SAbhinav271828   if (getNumEqualities() > 0)
2523562790f3SAbhinav271828     return false;
2524562790f3SAbhinav271828 
2525562790f3SAbhinav271828   // The polytope is full-dimensional iff it is not flat along any of the
2526562790f3SAbhinav271828   // inequality directions.
2527562790f3SAbhinav271828   Simplex simplex(*this);
2528562790f3SAbhinav271828   return llvm::none_of(llvm::seq<int>(getNumInequalities()), [&](int i) {
2529562790f3SAbhinav271828     return simplex.isFlatAlong(getInequality(i));
2530562790f3SAbhinav271828   });
2531562790f3SAbhinav271828 }
2532562790f3SAbhinav271828 
253324da7fa0SBharathi Ramana Joshi void IntegerRelation::mergeAndCompose(const IntegerRelation &other) {
253424da7fa0SBharathi Ramana Joshi   assert(getNumDomainVars() == other.getNumRangeVars() &&
253524da7fa0SBharathi Ramana Joshi          "Domain of this and range of other do not match");
253624da7fa0SBharathi Ramana Joshi   // assert(std::equal(values.begin(), values.begin() +
253724da7fa0SBharathi Ramana Joshi   // other.getNumDomainVars(),
253824da7fa0SBharathi Ramana Joshi   //                   otherValues.begin() + other.getNumDomainVars()) &&
253924da7fa0SBharathi Ramana Joshi   //        "Domain of this and range of other do not match");
254024da7fa0SBharathi Ramana Joshi 
254124da7fa0SBharathi Ramana Joshi   IntegerRelation result = other;
254224da7fa0SBharathi Ramana Joshi 
254324da7fa0SBharathi Ramana Joshi   const unsigned thisDomain = getNumDomainVars();
254424da7fa0SBharathi Ramana Joshi   const unsigned thisRange = getNumRangeVars();
254524da7fa0SBharathi Ramana Joshi   const unsigned otherDomain = other.getNumDomainVars();
254624da7fa0SBharathi Ramana Joshi   const unsigned otherRange = other.getNumRangeVars();
254724da7fa0SBharathi Ramana Joshi 
254824da7fa0SBharathi Ramana Joshi   // Add dimension variables temporarily to merge symbol and local vars.
254924da7fa0SBharathi Ramana Joshi   // Convert `this` from
255024da7fa0SBharathi Ramana Joshi   //    [thisDomain] -> [thisRange]
255124da7fa0SBharathi Ramana Joshi   // to
255224da7fa0SBharathi Ramana Joshi   //    [otherDomain thisDomain] -> [otherRange thisRange].
255324da7fa0SBharathi Ramana Joshi   // and `result` from
255424da7fa0SBharathi Ramana Joshi   //    [otherDomain] -> [otherRange]
255524da7fa0SBharathi Ramana Joshi   // to
255624da7fa0SBharathi Ramana Joshi   //    [otherDomain thisDomain] -> [otherRange thisRange]
255724da7fa0SBharathi Ramana Joshi   insertVar(VarKind::Domain, 0, otherDomain);
255824da7fa0SBharathi Ramana Joshi   insertVar(VarKind::Range, 0, otherRange);
255924da7fa0SBharathi Ramana Joshi   result.insertVar(VarKind::Domain, otherDomain, thisDomain);
256024da7fa0SBharathi Ramana Joshi   result.insertVar(VarKind::Range, otherRange, thisRange);
256124da7fa0SBharathi Ramana Joshi 
256224da7fa0SBharathi Ramana Joshi   // Merge symbol and local variables.
256324da7fa0SBharathi Ramana Joshi   mergeAndAlignSymbols(result);
256424da7fa0SBharathi Ramana Joshi   mergeLocalVars(result);
256524da7fa0SBharathi Ramana Joshi 
256624da7fa0SBharathi Ramana Joshi   // Convert `result` from [otherDomain thisDomain] -> [otherRange thisRange] to
256724da7fa0SBharathi Ramana Joshi   //                       [otherDomain] -> [thisRange]
256824da7fa0SBharathi Ramana Joshi   result.removeVarRange(VarKind::Domain, otherDomain, otherDomain + thisDomain);
256924da7fa0SBharathi Ramana Joshi   result.convertToLocal(VarKind::Range, 0, otherRange);
257024da7fa0SBharathi Ramana Joshi   // Convert `this` from [otherDomain thisDomain] -> [otherRange thisRange] to
257124da7fa0SBharathi Ramana Joshi   //                     [otherDomain] -> [thisRange]
257224da7fa0SBharathi Ramana Joshi   convertToLocal(VarKind::Domain, otherDomain, otherDomain + thisDomain);
257324da7fa0SBharathi Ramana Joshi   removeVarRange(VarKind::Range, 0, otherRange);
257424da7fa0SBharathi Ramana Joshi 
257524da7fa0SBharathi Ramana Joshi   // Add and match domain of `result` to domain of `this`.
257624da7fa0SBharathi Ramana Joshi   for (unsigned i = 0, e = result.getNumDomainVars(); i < e; ++i)
257724da7fa0SBharathi Ramana Joshi     if (result.getSpace().getId(VarKind::Domain, i).hasValue())
257824da7fa0SBharathi Ramana Joshi       space.setId(VarKind::Domain, i,
257924da7fa0SBharathi Ramana Joshi                   result.getSpace().getId(VarKind::Domain, i));
258024da7fa0SBharathi Ramana Joshi   // Add and match range of `this` to range of `result`.
258124da7fa0SBharathi Ramana Joshi   for (unsigned i = 0, e = getNumRangeVars(); i < e; ++i)
258224da7fa0SBharathi Ramana Joshi     if (space.getId(VarKind::Range, i).hasValue())
258324da7fa0SBharathi Ramana Joshi       result.space.setId(VarKind::Range, i, space.getId(VarKind::Range, i));
258424da7fa0SBharathi Ramana Joshi 
258524da7fa0SBharathi Ramana Joshi   // Append `this` to `result` and simplify constraints.
258624da7fa0SBharathi Ramana Joshi   result.append(*this);
258724da7fa0SBharathi Ramana Joshi   result.removeRedundantLocalVars();
258824da7fa0SBharathi Ramana Joshi 
258924da7fa0SBharathi Ramana Joshi   *this = result;
259024da7fa0SBharathi Ramana Joshi }
259124da7fa0SBharathi Ramana Joshi 
2592bb901355SGroverkss void IntegerRelation::print(raw_ostream &os) const {
2593bb901355SGroverkss   assert(hasConsistentState());
2594bb901355SGroverkss   printSpace(os);
2595*27402735SAmy Wang   PrintTableMetrics ptm = {0, 0, "-"};
2596*27402735SAmy Wang   for (unsigned i = 0, e = getNumEqualities(); i < e; ++i)
2597*27402735SAmy Wang     for (unsigned j = 0, f = getNumCols(); j < f; ++j)
2598*27402735SAmy Wang       updatePrintMetrics<DynamicAPInt>(atEq(i, j), ptm);
2599*27402735SAmy Wang   for (unsigned i = 0, e = getNumInequalities(); i < e; ++i)
2600*27402735SAmy Wang     for (unsigned j = 0, f = getNumCols(); j < f; ++j)
2601*27402735SAmy Wang       updatePrintMetrics<DynamicAPInt>(atIneq(i, j), ptm);
2602*27402735SAmy Wang   // Print using PrintMetrics.
2603*27402735SAmy Wang   unsigned MIN_SPACING = 1;
2604bb901355SGroverkss   for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) {
2605bb901355SGroverkss     for (unsigned j = 0, f = getNumCols(); j < f; ++j) {
2606*27402735SAmy Wang       printWithPrintMetrics<DynamicAPInt>(os, atEq(i, j), MIN_SPACING, ptm);
2607bb901355SGroverkss     }
2608bb901355SGroverkss     os << "  = 0\n";
2609bb901355SGroverkss   }
2610bb901355SGroverkss   for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) {
2611bb901355SGroverkss     for (unsigned j = 0, f = getNumCols(); j < f; ++j) {
2612*27402735SAmy Wang       printWithPrintMetrics<DynamicAPInt>(os, atIneq(i, j), MIN_SPACING, ptm);
2613bb901355SGroverkss     }
2614bb901355SGroverkss     os << " >= 0\n";
2615bb901355SGroverkss   }
2616bb901355SGroverkss   os << '\n';
2617bb901355SGroverkss }
2618bb901355SGroverkss 
2619bb901355SGroverkss void IntegerRelation::dump() const { print(llvm::errs()); }
262058966dd4SGroverkss 
2621d95140a5SGroverkss unsigned IntegerPolyhedron::insertVar(VarKind kind, unsigned pos,
2622d95140a5SGroverkss                                       unsigned num) {
2623d95140a5SGroverkss   assert((kind != VarKind::Domain || num == 0) &&
262458966dd4SGroverkss          "Domain has to be zero in a set");
2625d95140a5SGroverkss   return IntegerRelation::insertVar(kind, pos, num);
262658966dd4SGroverkss }
2627a18f843fSGroverkss IntegerPolyhedron
2628a18f843fSGroverkss IntegerPolyhedron::intersect(const IntegerPolyhedron &other) const {
2629a18f843fSGroverkss   return IntegerPolyhedron(IntegerRelation::intersect(other));
2630a18f843fSGroverkss }
2631a18f843fSGroverkss 
2632a18f843fSGroverkss PresburgerSet IntegerPolyhedron::subtract(const PresburgerSet &other) const {
2633a18f843fSGroverkss   return PresburgerSet(IntegerRelation::subtract(other));
2634a18f843fSGroverkss }
2635