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 EntryEntry28*06c3fb27SDimitry Andric Entry(int64_t Coefficient, uint16_t Id) 29*06c3fb27SDimitry Andric : Coefficient(Coefficient), Id(Id) {} 30*06c3fb27SDimitry Andric }; 31*06c3fb27SDimitry Andric getConstPart(const Entry & E)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 getLastCoefficient(ArrayRef<Entry> Row,uint16_t Id)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 // Eliminate constraints from the system using Fourier–Motzkin elimination. 58e8d8bef9SDimitry Andric bool eliminateUsingFM(); 59e8d8bef9SDimitry Andric 60e8d8bef9SDimitry Andric /// Returns true if there may be a solution for the constraints in the system. 61e8d8bef9SDimitry Andric bool mayHaveSolutionImpl(); 62e8d8bef9SDimitry Andric 63*06c3fb27SDimitry Andric /// Get list of variable names from the Value2Index map. 64*06c3fb27SDimitry Andric SmallVector<std::string> getVarNamesList() const; 65*06c3fb27SDimitry Andric 66e8d8bef9SDimitry Andric public: ConstraintSystem()67*06c3fb27SDimitry Andric ConstraintSystem() {} ConstraintSystem(ArrayRef<Value * > FunctionArgs)68*06c3fb27SDimitry Andric ConstraintSystem(ArrayRef<Value *> FunctionArgs) { 69*06c3fb27SDimitry Andric NumVariables += FunctionArgs.size(); 70*06c3fb27SDimitry Andric for (auto *Arg : FunctionArgs) { 71*06c3fb27SDimitry Andric Value2Index.insert({Arg, Value2Index.size() + 1}); 72*06c3fb27SDimitry Andric } 73*06c3fb27SDimitry Andric } ConstraintSystem(const DenseMap<Value *,unsigned> & Value2Index)74*06c3fb27SDimitry Andric ConstraintSystem(const DenseMap<Value *, unsigned> &Value2Index) 75*06c3fb27SDimitry Andric : NumVariables(Value2Index.size()), Value2Index(Value2Index) {} 76*06c3fb27SDimitry Andric addVariableRow(ArrayRef<int64_t> R)7781ad6265SDimitry Andric bool addVariableRow(ArrayRef<int64_t> R) { 78*06c3fb27SDimitry Andric assert(Constraints.empty() || R.size() == NumVariables); 79e8d8bef9SDimitry Andric // If all variable coefficients are 0, the constraint does not provide any 80e8d8bef9SDimitry Andric // usable information. 81bdd1243dSDimitry Andric if (all_of(ArrayRef(R).drop_front(1), [](int64_t C) { return C == 0; })) 82e8d8bef9SDimitry Andric return false; 83e8d8bef9SDimitry Andric 84*06c3fb27SDimitry Andric SmallVector<Entry, 4> NewRow; 85*06c3fb27SDimitry Andric for (const auto &[Idx, C] : enumerate(R)) { 86*06c3fb27SDimitry Andric if (C == 0) 87*06c3fb27SDimitry Andric continue; 88*06c3fb27SDimitry Andric NewRow.emplace_back(C, Idx); 89e8d8bef9SDimitry Andric } 90*06c3fb27SDimitry Andric if (Constraints.empty()) 91*06c3fb27SDimitry Andric NumVariables = R.size(); 92*06c3fb27SDimitry Andric Constraints.push_back(std::move(NewRow)); 93e8d8bef9SDimitry Andric return true; 94e8d8bef9SDimitry Andric } 95e8d8bef9SDimitry Andric getValue2Index()96*06c3fb27SDimitry Andric DenseMap<Value *, unsigned> &getValue2Index() { return Value2Index; } getValue2Index()97*06c3fb27SDimitry Andric const DenseMap<Value *, unsigned> &getValue2Index() const { 98*06c3fb27SDimitry Andric return Value2Index; 99*06c3fb27SDimitry Andric } 100*06c3fb27SDimitry Andric addVariableRowFill(ArrayRef<int64_t> R)10181ad6265SDimitry Andric bool addVariableRowFill(ArrayRef<int64_t> R) { 10281ad6265SDimitry Andric // If all variable coefficients are 0, the constraint does not provide any 10381ad6265SDimitry Andric // usable information. 104bdd1243dSDimitry Andric if (all_of(ArrayRef(R).drop_front(1), [](int64_t C) { return C == 0; })) 10581ad6265SDimitry Andric return false; 10681ad6265SDimitry Andric 107*06c3fb27SDimitry Andric NumVariables = std::max(R.size(), NumVariables); 108e8d8bef9SDimitry Andric return addVariableRow(R); 109e8d8bef9SDimitry Andric } 110e8d8bef9SDimitry Andric 111e8d8bef9SDimitry Andric /// Returns true if there may be a solution for the constraints in the system. 112e8d8bef9SDimitry Andric bool mayHaveSolution(); 113e8d8bef9SDimitry Andric negate(SmallVector<int64_t,8> R)114e8d8bef9SDimitry Andric static SmallVector<int64_t, 8> negate(SmallVector<int64_t, 8> R) { 115e8d8bef9SDimitry Andric // The negated constraint R is obtained by multiplying by -1 and adding 1 to 116e8d8bef9SDimitry Andric // the constant. 117e8d8bef9SDimitry Andric R[0] += 1; 118*06c3fb27SDimitry Andric return negateOrEqual(R); 119*06c3fb27SDimitry Andric } 120*06c3fb27SDimitry Andric 121*06c3fb27SDimitry Andric /// Multiplies each coefficient in the given vector by -1. Does not modify the 122*06c3fb27SDimitry Andric /// original vector. 123*06c3fb27SDimitry Andric /// 124*06c3fb27SDimitry Andric /// \param R The vector of coefficients to be negated. negateOrEqual(SmallVector<int64_t,8> R)125*06c3fb27SDimitry Andric static SmallVector<int64_t, 8> negateOrEqual(SmallVector<int64_t, 8> R) { 126*06c3fb27SDimitry Andric // The negated constraint R is obtained by multiplying by -1. 127e8d8bef9SDimitry Andric for (auto &C : R) 128*06c3fb27SDimitry Andric if (MulOverflow(C, int64_t(-1), C)) 129*06c3fb27SDimitry Andric return {}; 130*06c3fb27SDimitry Andric return R; 131*06c3fb27SDimitry Andric } 132*06c3fb27SDimitry Andric 133*06c3fb27SDimitry Andric /// Converts the given vector to form a strict less than inequality. Does not 134*06c3fb27SDimitry Andric /// modify the original vector. 135*06c3fb27SDimitry Andric /// 136*06c3fb27SDimitry Andric /// \param R The vector of coefficients to be converted. toStrictLessThan(SmallVector<int64_t,8> R)137*06c3fb27SDimitry Andric static SmallVector<int64_t, 8> toStrictLessThan(SmallVector<int64_t, 8> R) { 138*06c3fb27SDimitry Andric // The strict less than is obtained by subtracting 1 from the constant. 139*06c3fb27SDimitry Andric if (SubOverflow(R[0], int64_t(1), R[0])) { 140*06c3fb27SDimitry Andric return {}; 141*06c3fb27SDimitry Andric } 142e8d8bef9SDimitry Andric return R; 143e8d8bef9SDimitry Andric } 144e8d8bef9SDimitry Andric 14504eeddc0SDimitry Andric bool isConditionImplied(SmallVector<int64_t, 8> R) const; 146e8d8bef9SDimitry Andric getLastConstraint()147*06c3fb27SDimitry Andric SmallVector<int64_t> getLastConstraint() const { 148*06c3fb27SDimitry Andric assert(!Constraints.empty() && "Constraint system is empty"); 149*06c3fb27SDimitry Andric SmallVector<int64_t> Result(NumVariables, 0); 150*06c3fb27SDimitry Andric for (auto &Entry : Constraints.back()) 151*06c3fb27SDimitry Andric Result[Entry.Id] = Entry.Coefficient; 152*06c3fb27SDimitry Andric return Result; 153*06c3fb27SDimitry Andric } 154*06c3fb27SDimitry Andric popLastConstraint()155e8d8bef9SDimitry Andric void popLastConstraint() { Constraints.pop_back(); } popLastNVariables(unsigned N)15681ad6265SDimitry Andric void popLastNVariables(unsigned N) { 157*06c3fb27SDimitry Andric assert(NumVariables > N); 158*06c3fb27SDimitry Andric NumVariables -= N; 15981ad6265SDimitry Andric } 160e8d8bef9SDimitry Andric 161e8d8bef9SDimitry Andric /// Returns the number of rows in the constraint system. size()162e8d8bef9SDimitry Andric unsigned size() const { return Constraints.size(); } 163fe6060f1SDimitry Andric 164*06c3fb27SDimitry Andric /// Print the constraints in the system. 165*06c3fb27SDimitry Andric void dump() const; 166e8d8bef9SDimitry Andric }; 167e8d8bef9SDimitry Andric } // namespace llvm 168e8d8bef9SDimitry Andric 169e8d8bef9SDimitry Andric #endif // LLVM_ANALYSIS_CONSTRAINTSYSTEM_H 170