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