Path: blob/main/contrib/llvm-project/llvm/lib/Analysis/ConstraintSystem.cpp
35232 views
//===- ConstraintSytem.cpp - A system of linear constraints. ----*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/Analysis/ConstraintSystem.h"9#include "llvm/ADT/SmallVector.h"10#include "llvm/Support/MathExtras.h"11#include "llvm/ADT/StringExtras.h"12#include "llvm/IR/Value.h"13#include "llvm/Support/Debug.h"1415#include <string>1617using namespace llvm;1819#define DEBUG_TYPE "constraint-system"2021bool ConstraintSystem::eliminateUsingFM() {22// Implementation of Fourier–Motzkin elimination, with some tricks from the23// paper Pugh, William. "The Omega test: a fast and practical integer24// programming algorithm for dependence25// analysis."26// Supercomputing'91: Proceedings of the 1991 ACM/27// IEEE conference on Supercomputing. IEEE, 1991.28assert(!Constraints.empty() &&29"should only be called for non-empty constraint systems");3031unsigned LastIdx = NumVariables - 1;3233// First, either remove the variable in place if it is 0 or add the row to34// RemainingRows and remove it from the system.35SmallVector<SmallVector<Entry, 8>, 4> RemainingRows;36for (unsigned R1 = 0; R1 < Constraints.size();) {37SmallVector<Entry, 8> &Row1 = Constraints[R1];38if (getLastCoefficient(Row1, LastIdx) == 0) {39if (Row1.size() > 0 && Row1.back().Id == LastIdx)40Row1.pop_back();41R1++;42} else {43std::swap(Constraints[R1], Constraints.back());44RemainingRows.push_back(std::move(Constraints.back()));45Constraints.pop_back();46}47}4849// Process rows where the variable is != 0.50unsigned NumRemainingConstraints = RemainingRows.size();51for (unsigned R1 = 0; R1 < NumRemainingConstraints; R1++) {52// FIXME do not use copy53for (unsigned R2 = R1 + 1; R2 < NumRemainingConstraints; R2++) {54if (R1 == R2)55continue;5657int64_t UpperLast = getLastCoefficient(RemainingRows[R2], LastIdx);58int64_t LowerLast = getLastCoefficient(RemainingRows[R1], LastIdx);59assert(60UpperLast != 0 && LowerLast != 0 &&61"RemainingRows should only contain rows where the variable is != 0");6263if ((LowerLast < 0 && UpperLast < 0) || (LowerLast > 0 && UpperLast > 0))64continue;6566unsigned LowerR = R1;67unsigned UpperR = R2;68if (UpperLast < 0) {69std::swap(LowerR, UpperR);70std::swap(LowerLast, UpperLast);71}7273SmallVector<Entry, 8> NR;74unsigned IdxUpper = 0;75unsigned IdxLower = 0;76auto &LowerRow = RemainingRows[LowerR];77auto &UpperRow = RemainingRows[UpperR];78while (true) {79if (IdxUpper >= UpperRow.size() || IdxLower >= LowerRow.size())80break;81int64_t M1, M2, N;82int64_t UpperV = 0;83int64_t LowerV = 0;84uint16_t CurrentId = std::numeric_limits<uint16_t>::max();85if (IdxUpper < UpperRow.size()) {86CurrentId = std::min(UpperRow[IdxUpper].Id, CurrentId);87}88if (IdxLower < LowerRow.size()) {89CurrentId = std::min(LowerRow[IdxLower].Id, CurrentId);90}9192if (IdxUpper < UpperRow.size() && UpperRow[IdxUpper].Id == CurrentId) {93UpperV = UpperRow[IdxUpper].Coefficient;94IdxUpper++;95}9697if (MulOverflow(UpperV, -1 * LowerLast, M1))98return false;99if (IdxLower < LowerRow.size() && LowerRow[IdxLower].Id == CurrentId) {100LowerV = LowerRow[IdxLower].Coefficient;101IdxLower++;102}103104if (MulOverflow(LowerV, UpperLast, M2))105return false;106if (AddOverflow(M1, M2, N))107return false;108if (N == 0)109continue;110NR.emplace_back(N, CurrentId);111}112if (NR.empty())113continue;114Constraints.push_back(std::move(NR));115// Give up if the new system gets too big.116if (Constraints.size() > 500)117return false;118}119}120NumVariables -= 1;121122return true;123}124125bool ConstraintSystem::mayHaveSolutionImpl() {126while (!Constraints.empty() && NumVariables > 1) {127if (!eliminateUsingFM())128return true;129}130131if (Constraints.empty() || NumVariables > 1)132return true;133134return all_of(Constraints, [](auto &R) {135if (R.empty())136return true;137if (R[0].Id == 0)138return R[0].Coefficient >= 0;139return true;140});141}142143SmallVector<std::string> ConstraintSystem::getVarNamesList() const {144SmallVector<std::string> Names(Value2Index.size(), "");145#ifndef NDEBUG146for (auto &[V, Index] : Value2Index) {147std::string OperandName;148if (V->getName().empty())149OperandName = V->getNameOrAsOperand();150else151OperandName = std::string("%") + V->getName().str();152Names[Index - 1] = OperandName;153}154#endif155return Names;156}157158void ConstraintSystem::dump() const {159#ifndef NDEBUG160if (Constraints.empty())161return;162SmallVector<std::string> Names = getVarNamesList();163for (const auto &Row : Constraints) {164SmallVector<std::string, 16> Parts;165for (const Entry &E : Row) {166if (E.Id >= NumVariables)167break;168if (E.Id == 0)169continue;170std::string Coefficient;171if (E.Coefficient != 1)172Coefficient = std::to_string(E.Coefficient) + " * ";173Parts.push_back(Coefficient + Names[E.Id - 1]);174}175// assert(!Parts.empty() && "need to have at least some parts");176int64_t ConstPart = 0;177if (Row[0].Id == 0)178ConstPart = Row[0].Coefficient;179LLVM_DEBUG(dbgs() << join(Parts, std::string(" + "))180<< " <= " << std::to_string(ConstPart) << "\n");181}182#endif183}184185bool ConstraintSystem::mayHaveSolution() {186LLVM_DEBUG(dbgs() << "---\n");187LLVM_DEBUG(dump());188bool HasSolution = mayHaveSolutionImpl();189LLVM_DEBUG(dbgs() << (HasSolution ? "sat" : "unsat") << "\n");190return HasSolution;191}192193bool ConstraintSystem::isConditionImplied(SmallVector<int64_t, 8> R) const {194// If all variable coefficients are 0, we have 'C >= 0'. If the constant is >=195// 0, R is always true, regardless of the system.196if (all_of(ArrayRef(R).drop_front(1), [](int64_t C) { return C == 0; }))197return R[0] >= 0;198199// If there is no solution with the negation of R added to the system, the200// condition must hold based on the existing constraints.201R = ConstraintSystem::negate(R);202if (R.empty())203return false;204205auto NewSystem = *this;206NewSystem.addVariableRow(R);207return !NewSystem.mayHaveSolution();208}209210211