1cd4edf94SFlorian Hahn //===- ConstraintSytem.cpp - A system of linear constraints. ----*- C++ -*-===// 2cd4edf94SFlorian Hahn // 3cd4edf94SFlorian Hahn // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4cd4edf94SFlorian Hahn // See https://llvm.org/LICENSE.txt for license information. 5cd4edf94SFlorian Hahn // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6cd4edf94SFlorian Hahn // 7cd4edf94SFlorian Hahn //===----------------------------------------------------------------------===// 8cd4edf94SFlorian Hahn 9cd4edf94SFlorian Hahn #include "llvm/Analysis/ConstraintSystem.h" 10cd4edf94SFlorian Hahn #include "llvm/ADT/SmallVector.h" 11cd4edf94SFlorian Hahn #include "llvm/Support/MathExtras.h" 12cd4edf94SFlorian Hahn #include "llvm/ADT/StringExtras.h" 1307f93d8cSZain Jaffal #include "llvm/IR/Value.h" 14cd4edf94SFlorian Hahn #include "llvm/Support/Debug.h" 15cd4edf94SFlorian Hahn 16cd4edf94SFlorian Hahn #include <string> 17cd4edf94SFlorian Hahn 18cd4edf94SFlorian Hahn using namespace llvm; 19cd4edf94SFlorian Hahn 20cd4edf94SFlorian Hahn #define DEBUG_TYPE "constraint-system" 21cd4edf94SFlorian Hahn 22cd4edf94SFlorian Hahn bool ConstraintSystem::eliminateUsingFM() { 23cd4edf94SFlorian Hahn // Implementation of Fourier–Motzkin elimination, with some tricks from the 24cd4edf94SFlorian Hahn // paper Pugh, William. "The Omega test: a fast and practical integer 25cd4edf94SFlorian Hahn // programming algorithm for dependence 26cd4edf94SFlorian Hahn // analysis." 27cd4edf94SFlorian Hahn // Supercomputing'91: Proceedings of the 1991 ACM/ 28cd4edf94SFlorian Hahn // IEEE conference on Supercomputing. IEEE, 1991. 29cd4edf94SFlorian Hahn assert(!Constraints.empty() && 30cd4edf94SFlorian Hahn "should only be called for non-empty constraint systems"); 31cd4edf94SFlorian Hahn 321373f203SFlorian Hahn unsigned LastIdx = NumVariables - 1; 331373f203SFlorian Hahn 348537a7c9SFlorian Hahn // First, either remove the variable in place if it is 0 or add the row to 358537a7c9SFlorian Hahn // RemainingRows and remove it from the system. 36b32b7068SFlorian Hahn SmallVector<SmallVector<Entry, 8>, 4> RemainingRows; 378537a7c9SFlorian Hahn for (unsigned R1 = 0; R1 < Constraints.size();) { 38b32b7068SFlorian Hahn SmallVector<Entry, 8> &Row1 = Constraints[R1]; 39b32b7068SFlorian Hahn if (getLastCoefficient(Row1, LastIdx) == 0) { 40b32b7068SFlorian Hahn if (Row1.size() > 0 && Row1.back().Id == LastIdx) 411373f203SFlorian Hahn Row1.pop_back(); 428537a7c9SFlorian Hahn R1++; 438537a7c9SFlorian Hahn } else { 448537a7c9SFlorian Hahn std::swap(Constraints[R1], Constraints.back()); 458537a7c9SFlorian Hahn RemainingRows.push_back(std::move(Constraints.back())); 468537a7c9SFlorian Hahn Constraints.pop_back(); 478537a7c9SFlorian Hahn } 48cd4edf94SFlorian Hahn } 49cd4edf94SFlorian Hahn 508537a7c9SFlorian Hahn // Process rows where the variable is != 0. 518537a7c9SFlorian Hahn unsigned NumRemainingConstraints = RemainingRows.size(); 528537a7c9SFlorian Hahn for (unsigned R1 = 0; R1 < NumRemainingConstraints; R1++) { 53cd4edf94SFlorian Hahn // FIXME do not use copy 548537a7c9SFlorian Hahn for (unsigned R2 = R1 + 1; R2 < NumRemainingConstraints; R2++) { 55b32b7068SFlorian Hahn int64_t UpperLast = getLastCoefficient(RemainingRows[R2], LastIdx); 56b32b7068SFlorian Hahn int64_t LowerLast = getLastCoefficient(RemainingRows[R1], LastIdx); 578537a7c9SFlorian Hahn assert( 588537a7c9SFlorian Hahn UpperLast != 0 && LowerLast != 0 && 598537a7c9SFlorian Hahn "RemainingRows should only contain rows where the variable is != 0"); 60b32b7068SFlorian Hahn 61d82811dfSFlorian Hahn if ((LowerLast < 0 && UpperLast < 0) || (LowerLast > 0 && UpperLast > 0)) 62cd4edf94SFlorian Hahn continue; 63cd4edf94SFlorian Hahn 64cd4edf94SFlorian Hahn unsigned LowerR = R1; 65cd4edf94SFlorian Hahn unsigned UpperR = R2; 66d82811dfSFlorian Hahn if (UpperLast < 0) { 67cd4edf94SFlorian Hahn std::swap(LowerR, UpperR); 68d82811dfSFlorian Hahn std::swap(LowerLast, UpperLast); 69d82811dfSFlorian Hahn } 70cd4edf94SFlorian Hahn 71b32b7068SFlorian Hahn SmallVector<Entry, 8> NR; 72b32b7068SFlorian Hahn unsigned IdxUpper = 0; 73b32b7068SFlorian Hahn unsigned IdxLower = 0; 74b32b7068SFlorian Hahn auto &LowerRow = RemainingRows[LowerR]; 75b32b7068SFlorian Hahn auto &UpperRow = RemainingRows[UpperR]; 76b32b7068SFlorian Hahn while (true) { 77b32b7068SFlorian Hahn if (IdxUpper >= UpperRow.size() || IdxLower >= LowerRow.size()) 78b32b7068SFlorian Hahn break; 79cd4edf94SFlorian Hahn int64_t M1, M2, N; 80b32b7068SFlorian Hahn int64_t UpperV = 0; 81b32b7068SFlorian Hahn int64_t LowerV = 0; 82b32b7068SFlorian Hahn uint16_t CurrentId = std::numeric_limits<uint16_t>::max(); 83b32b7068SFlorian Hahn if (IdxUpper < UpperRow.size()) { 84b32b7068SFlorian Hahn CurrentId = std::min(UpperRow[IdxUpper].Id, CurrentId); 85b32b7068SFlorian Hahn } 86b32b7068SFlorian Hahn if (IdxLower < LowerRow.size()) { 87b32b7068SFlorian Hahn CurrentId = std::min(LowerRow[IdxLower].Id, CurrentId); 88b32b7068SFlorian Hahn } 89b32b7068SFlorian Hahn 90b32b7068SFlorian Hahn if (IdxUpper < UpperRow.size() && UpperRow[IdxUpper].Id == CurrentId) { 91b32b7068SFlorian Hahn UpperV = UpperRow[IdxUpper].Coefficient; 92b32b7068SFlorian Hahn IdxUpper++; 93b32b7068SFlorian Hahn } 94b32b7068SFlorian Hahn 953ae3e407SFlorian Hahn if (MulOverflow(UpperV, -1 * LowerLast, M1)) 96cd4edf94SFlorian Hahn return false; 97b32b7068SFlorian Hahn if (IdxLower < LowerRow.size() && LowerRow[IdxLower].Id == CurrentId) { 98b32b7068SFlorian Hahn LowerV = LowerRow[IdxLower].Coefficient; 99b32b7068SFlorian Hahn IdxLower++; 100b32b7068SFlorian Hahn } 101b32b7068SFlorian Hahn 1023ae3e407SFlorian Hahn if (MulOverflow(LowerV, UpperLast, M2)) 103cd4edf94SFlorian Hahn return false; 104cd4edf94SFlorian Hahn if (AddOverflow(M1, M2, N)) 105cd4edf94SFlorian Hahn return false; 106b32b7068SFlorian Hahn if (N == 0) 107b32b7068SFlorian Hahn continue; 108b32b7068SFlorian Hahn NR.emplace_back(N, CurrentId); 109cd4edf94SFlorian Hahn } 110b32b7068SFlorian Hahn if (NR.empty()) 111b32b7068SFlorian Hahn continue; 1128537a7c9SFlorian Hahn Constraints.push_back(std::move(NR)); 113f19876c5SFlorian Hahn // Give up if the new system gets too big. 1148537a7c9SFlorian Hahn if (Constraints.size() > 500) 115f19876c5SFlorian Hahn return false; 116cd4edf94SFlorian Hahn } 117cd4edf94SFlorian Hahn } 118b32b7068SFlorian Hahn NumVariables -= 1; 119cd4edf94SFlorian Hahn 120cd4edf94SFlorian Hahn return true; 121cd4edf94SFlorian Hahn } 122cd4edf94SFlorian Hahn 123cd4edf94SFlorian Hahn bool ConstraintSystem::mayHaveSolutionImpl() { 124b32b7068SFlorian Hahn while (!Constraints.empty() && NumVariables > 1) { 125cd4edf94SFlorian Hahn if (!eliminateUsingFM()) 126cd4edf94SFlorian Hahn return true; 127cd4edf94SFlorian Hahn } 128cd4edf94SFlorian Hahn 129b32b7068SFlorian Hahn if (Constraints.empty() || NumVariables > 1) 130cd4edf94SFlorian Hahn return true; 131cd4edf94SFlorian Hahn 132b32b7068SFlorian Hahn return all_of(Constraints, [](auto &R) { 133b32b7068SFlorian Hahn if (R.empty()) 134b32b7068SFlorian Hahn return true; 135b32b7068SFlorian Hahn if (R[0].Id == 0) 136b32b7068SFlorian Hahn return R[0].Coefficient >= 0; 137b32b7068SFlorian Hahn return true; 138b32b7068SFlorian Hahn }); 139cd4edf94SFlorian Hahn } 140cd4edf94SFlorian Hahn 14107f93d8cSZain Jaffal SmallVector<std::string> ConstraintSystem::getVarNamesList() const { 14207f93d8cSZain Jaffal SmallVector<std::string> Names(Value2Index.size(), ""); 143df2ea2fcSZain Jaffal #ifndef NDEBUG 14407f93d8cSZain Jaffal for (auto &[V, Index] : Value2Index) { 14507f93d8cSZain Jaffal std::string OperandName; 14607f93d8cSZain Jaffal if (V->getName().empty()) 14707f93d8cSZain Jaffal OperandName = V->getNameOrAsOperand(); 14807f93d8cSZain Jaffal else 14907f93d8cSZain Jaffal OperandName = std::string("%") + V->getName().str(); 15007f93d8cSZain Jaffal Names[Index - 1] = OperandName; 15107f93d8cSZain Jaffal } 152df2ea2fcSZain Jaffal #endif 15307f93d8cSZain Jaffal return Names; 15407f93d8cSZain Jaffal } 15507f93d8cSZain Jaffal 15607f93d8cSZain Jaffal void ConstraintSystem::dump() const { 157df2ea2fcSZain Jaffal #ifndef NDEBUG 158cd4edf94SFlorian Hahn if (Constraints.empty()) 159cd4edf94SFlorian Hahn return; 16007f93d8cSZain Jaffal SmallVector<std::string> Names = getVarNamesList(); 161601b3a13SKazu Hirata for (const auto &Row : Constraints) { 162cd4edf94SFlorian Hahn SmallVector<std::string, 16> Parts; 163*1462605aSKazu Hirata for (const Entry &E : Row) { 164*1462605aSKazu Hirata if (E.Id >= NumVariables) 165b32b7068SFlorian Hahn break; 166*1462605aSKazu Hirata if (E.Id == 0) 167cd4edf94SFlorian Hahn continue; 16812fc9ca3SKazu Hirata std::string Coefficient; 169*1462605aSKazu Hirata if (E.Coefficient != 1) 170*1462605aSKazu Hirata Coefficient = std::to_string(E.Coefficient) + " * "; 171*1462605aSKazu Hirata Parts.push_back(Coefficient + Names[E.Id - 1]); 172cd4edf94SFlorian Hahn } 173b32b7068SFlorian Hahn // assert(!Parts.empty() && "need to have at least some parts"); 174b32b7068SFlorian Hahn int64_t ConstPart = 0; 175b32b7068SFlorian Hahn if (Row[0].Id == 0) 176b32b7068SFlorian Hahn ConstPart = Row[0].Coefficient; 177cd4edf94SFlorian Hahn LLVM_DEBUG(dbgs() << join(Parts, std::string(" + ")) 178b32b7068SFlorian Hahn << " <= " << std::to_string(ConstPart) << "\n"); 179cd4edf94SFlorian Hahn } 180df2ea2fcSZain Jaffal #endif 181cd4edf94SFlorian Hahn } 182cd4edf94SFlorian Hahn 183cd4edf94SFlorian Hahn bool ConstraintSystem::mayHaveSolution() { 18407f93d8cSZain Jaffal LLVM_DEBUG(dbgs() << "---\n"); 1854e5c0c2aSFlorian Hahn LLVM_DEBUG(dump()); 186cd4edf94SFlorian Hahn bool HasSolution = mayHaveSolutionImpl(); 187cd4edf94SFlorian Hahn LLVM_DEBUG(dbgs() << (HasSolution ? "sat" : "unsat") << "\n"); 188cd4edf94SFlorian Hahn return HasSolution; 189cd4edf94SFlorian Hahn } 190db22e70dSFlorian Hahn 1911ca02bddSFlorian Hahn bool ConstraintSystem::isConditionImplied(SmallVector<int64_t, 8> R) const { 1924ceecc82SFlorian Hahn // If all variable coefficients are 0, we have 'C >= 0'. If the constant is >= 1934ceecc82SFlorian Hahn // 0, R is always true, regardless of the system. 19438818b60Sserge-sans-paille if (all_of(ArrayRef(R).drop_front(1), [](int64_t C) { return C == 0; })) 1954ceecc82SFlorian Hahn return R[0] >= 0; 1964ceecc82SFlorian Hahn 197db22e70dSFlorian Hahn // If there is no solution with the negation of R added to the system, the 198db22e70dSFlorian Hahn // condition must hold based on the existing constraints. 199db22e70dSFlorian Hahn R = ConstraintSystem::negate(R); 2000a0181dcSFlorian Hahn if (R.empty()) 2010a0181dcSFlorian Hahn return false; 202db22e70dSFlorian Hahn 203db22e70dSFlorian Hahn auto NewSystem = *this; 204db22e70dSFlorian Hahn NewSystem.addVariableRow(R); 205db22e70dSFlorian Hahn return !NewSystem.mayHaveSolution(); 206db22e70dSFlorian Hahn } 207