xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/Analysis/ConstraintSystem.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1e8d8bef9SDimitry Andric //===- ConstraintSystem.h -  A system of linear constraints. --------------===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric 
9e8d8bef9SDimitry Andric #ifndef LLVM_ANALYSIS_CONSTRAINTSYSTEM_H
10e8d8bef9SDimitry Andric #define LLVM_ANALYSIS_CONSTRAINTSYSTEM_H
11e8d8bef9SDimitry Andric 
12e8d8bef9SDimitry Andric #include "llvm/ADT/APInt.h"
13e8d8bef9SDimitry Andric #include "llvm/ADT/ArrayRef.h"
14*06c3fb27SDimitry Andric #include "llvm/ADT/DenseMap.h"
15e8d8bef9SDimitry Andric #include "llvm/ADT/SmallVector.h"
16*06c3fb27SDimitry Andric #include "llvm/Support/MathExtras.h"
17e8d8bef9SDimitry Andric 
18e8d8bef9SDimitry Andric #include <string>
19e8d8bef9SDimitry Andric 
20e8d8bef9SDimitry Andric namespace llvm {
21e8d8bef9SDimitry Andric 
22*06c3fb27SDimitry Andric class Value;
23e8d8bef9SDimitry Andric class ConstraintSystem {
24*06c3fb27SDimitry Andric   struct Entry {
25*06c3fb27SDimitry Andric     int64_t Coefficient;
26*06c3fb27SDimitry Andric     uint16_t Id;
27*06c3fb27SDimitry Andric 
28*06c3fb27SDimitry Andric     Entry(int64_t Coefficient, uint16_t Id)
29*06c3fb27SDimitry Andric         : Coefficient(Coefficient), Id(Id) {}
30*06c3fb27SDimitry Andric   };
31*06c3fb27SDimitry Andric 
32*06c3fb27SDimitry Andric   static int64_t getConstPart(const Entry &E) {
33*06c3fb27SDimitry Andric     if (E.Id == 0)
34*06c3fb27SDimitry Andric       return E.Coefficient;
35*06c3fb27SDimitry Andric     return 0;
36*06c3fb27SDimitry Andric   }
37*06c3fb27SDimitry Andric 
38*06c3fb27SDimitry Andric   static int64_t getLastCoefficient(ArrayRef<Entry> Row, uint16_t Id) {
39*06c3fb27SDimitry Andric     if (Row.empty())
40*06c3fb27SDimitry Andric       return 0;
41*06c3fb27SDimitry Andric     if (Row.back().Id == Id)
42*06c3fb27SDimitry Andric       return Row.back().Coefficient;
43*06c3fb27SDimitry Andric     return 0;
44*06c3fb27SDimitry Andric   }
45*06c3fb27SDimitry Andric 
46*06c3fb27SDimitry Andric   size_t NumVariables = 0;
47*06c3fb27SDimitry Andric 
48e8d8bef9SDimitry Andric   /// Current linear constraints in the system.
49e8d8bef9SDimitry Andric   /// An entry of the form c0, c1, ... cn represents the following constraint:
50e8d8bef9SDimitry Andric   ///   c0 >= v0 * c1 + .... + v{n-1} * cn
51*06c3fb27SDimitry Andric   SmallVector<SmallVector<Entry, 8>, 4> Constraints;
52*06c3fb27SDimitry Andric 
53*06c3fb27SDimitry Andric   /// A map of variables (IR values) to their corresponding index in the
54*06c3fb27SDimitry Andric   /// constraint system.
55*06c3fb27SDimitry Andric   DenseMap<Value *, unsigned> Value2Index;
56e8d8bef9SDimitry Andric 
57e8d8bef9SDimitry Andric   /// Current greatest common divisor for all coefficients in the system.
58e8d8bef9SDimitry Andric   uint32_t GCD = 1;
59e8d8bef9SDimitry Andric 
60e8d8bef9SDimitry Andric   // Eliminate constraints from the system using Fourier–Motzkin elimination.
61e8d8bef9SDimitry Andric   bool eliminateUsingFM();
62e8d8bef9SDimitry Andric 
63e8d8bef9SDimitry Andric   /// Returns true if there may be a solution for the constraints in the system.
64e8d8bef9SDimitry Andric   bool mayHaveSolutionImpl();
65e8d8bef9SDimitry Andric 
66*06c3fb27SDimitry Andric   /// Get list of variable names from the Value2Index map.
67*06c3fb27SDimitry Andric   SmallVector<std::string> getVarNamesList() const;
68*06c3fb27SDimitry Andric 
69e8d8bef9SDimitry Andric public:
70*06c3fb27SDimitry Andric   ConstraintSystem() {}
71*06c3fb27SDimitry Andric   ConstraintSystem(ArrayRef<Value *> FunctionArgs) {
72*06c3fb27SDimitry Andric     NumVariables += FunctionArgs.size();
73*06c3fb27SDimitry Andric     for (auto *Arg : FunctionArgs) {
74*06c3fb27SDimitry Andric       Value2Index.insert({Arg, Value2Index.size() + 1});
75*06c3fb27SDimitry Andric     }
76*06c3fb27SDimitry Andric   }
77*06c3fb27SDimitry Andric   ConstraintSystem(const DenseMap<Value *, unsigned> &Value2Index)
78*06c3fb27SDimitry Andric       : NumVariables(Value2Index.size()), Value2Index(Value2Index) {}
79*06c3fb27SDimitry Andric 
8081ad6265SDimitry Andric   bool addVariableRow(ArrayRef<int64_t> R) {
81*06c3fb27SDimitry Andric     assert(Constraints.empty() || R.size() == NumVariables);
82e8d8bef9SDimitry Andric     // If all variable coefficients are 0, the constraint does not provide any
83e8d8bef9SDimitry Andric     // usable information.
84bdd1243dSDimitry Andric     if (all_of(ArrayRef(R).drop_front(1), [](int64_t C) { return C == 0; }))
85e8d8bef9SDimitry Andric       return false;
86e8d8bef9SDimitry Andric 
87*06c3fb27SDimitry Andric     SmallVector<Entry, 4> NewRow;
88*06c3fb27SDimitry Andric     for (const auto &[Idx, C] : enumerate(R)) {
89*06c3fb27SDimitry Andric       if (C == 0)
90*06c3fb27SDimitry Andric         continue;
91e8d8bef9SDimitry Andric       auto A = std::abs(C);
92e8d8bef9SDimitry Andric       GCD = APIntOps::GreatestCommonDivisor({32, (uint32_t)A}, {32, GCD})
93e8d8bef9SDimitry Andric                 .getZExtValue();
94*06c3fb27SDimitry Andric 
95*06c3fb27SDimitry Andric       NewRow.emplace_back(C, Idx);
96e8d8bef9SDimitry Andric     }
97*06c3fb27SDimitry Andric     if (Constraints.empty())
98*06c3fb27SDimitry Andric       NumVariables = R.size();
99*06c3fb27SDimitry Andric     Constraints.push_back(std::move(NewRow));
100e8d8bef9SDimitry Andric     return true;
101e8d8bef9SDimitry Andric   }
102e8d8bef9SDimitry Andric 
103*06c3fb27SDimitry Andric   DenseMap<Value *, unsigned> &getValue2Index() { return Value2Index; }
104*06c3fb27SDimitry Andric   const DenseMap<Value *, unsigned> &getValue2Index() const {
105*06c3fb27SDimitry Andric     return Value2Index;
106*06c3fb27SDimitry Andric   }
107*06c3fb27SDimitry Andric 
10881ad6265SDimitry Andric   bool addVariableRowFill(ArrayRef<int64_t> R) {
10981ad6265SDimitry Andric     // If all variable coefficients are 0, the constraint does not provide any
11081ad6265SDimitry Andric     // usable information.
111bdd1243dSDimitry Andric     if (all_of(ArrayRef(R).drop_front(1), [](int64_t C) { return C == 0; }))
11281ad6265SDimitry Andric       return false;
11381ad6265SDimitry Andric 
114*06c3fb27SDimitry Andric     NumVariables = std::max(R.size(), NumVariables);
115e8d8bef9SDimitry Andric     return addVariableRow(R);
116e8d8bef9SDimitry Andric   }
117e8d8bef9SDimitry Andric 
118e8d8bef9SDimitry Andric   /// Returns true if there may be a solution for the constraints in the system.
119e8d8bef9SDimitry Andric   bool mayHaveSolution();
120e8d8bef9SDimitry Andric 
121e8d8bef9SDimitry Andric   static SmallVector<int64_t, 8> negate(SmallVector<int64_t, 8> R) {
122e8d8bef9SDimitry Andric     // The negated constraint R is obtained by multiplying by -1 and adding 1 to
123e8d8bef9SDimitry Andric     // the constant.
124e8d8bef9SDimitry Andric     R[0] += 1;
125*06c3fb27SDimitry Andric     return negateOrEqual(R);
126*06c3fb27SDimitry Andric   }
127*06c3fb27SDimitry Andric 
128*06c3fb27SDimitry Andric   /// Multiplies each coefficient in the given vector by -1. Does not modify the
129*06c3fb27SDimitry Andric   /// original vector.
130*06c3fb27SDimitry Andric   ///
131*06c3fb27SDimitry Andric   /// \param R The vector of coefficients to be negated.
132*06c3fb27SDimitry Andric   static SmallVector<int64_t, 8> negateOrEqual(SmallVector<int64_t, 8> R) {
133*06c3fb27SDimitry Andric     // The negated constraint R is obtained by multiplying by -1.
134e8d8bef9SDimitry Andric     for (auto &C : R)
135*06c3fb27SDimitry Andric       if (MulOverflow(C, int64_t(-1), C))
136*06c3fb27SDimitry Andric         return {};
137*06c3fb27SDimitry Andric     return R;
138*06c3fb27SDimitry Andric   }
139*06c3fb27SDimitry Andric 
140*06c3fb27SDimitry Andric   /// Converts the given vector to form a strict less than inequality. Does not
141*06c3fb27SDimitry Andric   /// modify the original vector.
142*06c3fb27SDimitry Andric   ///
143*06c3fb27SDimitry Andric   /// \param R The vector of coefficients to be converted.
144*06c3fb27SDimitry Andric   static SmallVector<int64_t, 8> toStrictLessThan(SmallVector<int64_t, 8> R) {
145*06c3fb27SDimitry Andric     // The strict less than is obtained by subtracting 1 from the constant.
146*06c3fb27SDimitry Andric     if (SubOverflow(R[0], int64_t(1), R[0])) {
147*06c3fb27SDimitry Andric       return {};
148*06c3fb27SDimitry Andric     }
149e8d8bef9SDimitry Andric     return R;
150e8d8bef9SDimitry Andric   }
151e8d8bef9SDimitry Andric 
15204eeddc0SDimitry Andric   bool isConditionImplied(SmallVector<int64_t, 8> R) const;
153e8d8bef9SDimitry Andric 
154*06c3fb27SDimitry Andric   SmallVector<int64_t> getLastConstraint() const {
155*06c3fb27SDimitry Andric     assert(!Constraints.empty() && "Constraint system is empty");
156*06c3fb27SDimitry Andric     SmallVector<int64_t> Result(NumVariables, 0);
157*06c3fb27SDimitry Andric     for (auto &Entry : Constraints.back())
158*06c3fb27SDimitry Andric       Result[Entry.Id] = Entry.Coefficient;
159*06c3fb27SDimitry Andric     return Result;
160*06c3fb27SDimitry Andric   }
161*06c3fb27SDimitry Andric 
162e8d8bef9SDimitry Andric   void popLastConstraint() { Constraints.pop_back(); }
16381ad6265SDimitry Andric   void popLastNVariables(unsigned N) {
164*06c3fb27SDimitry Andric     assert(NumVariables > N);
165*06c3fb27SDimitry Andric     NumVariables -= N;
16681ad6265SDimitry Andric   }
167e8d8bef9SDimitry Andric 
168e8d8bef9SDimitry Andric   /// Returns the number of rows in the constraint system.
169e8d8bef9SDimitry Andric   unsigned size() const { return Constraints.size(); }
170fe6060f1SDimitry Andric 
171*06c3fb27SDimitry Andric   /// Print the constraints in the system.
172*06c3fb27SDimitry Andric   void dump() const;
173e8d8bef9SDimitry Andric };
174e8d8bef9SDimitry Andric } // namespace llvm
175e8d8bef9SDimitry Andric 
176e8d8bef9SDimitry Andric #endif // LLVM_ANALYSIS_CONSTRAINTSYSTEM_H
177