1*81ad6265SDimitry Andric //===- WatchedLiteralsSolver.cpp --------------------------------*- C++ -*-===// 2*81ad6265SDimitry Andric // 3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*81ad6265SDimitry Andric // 7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8*81ad6265SDimitry Andric // 9*81ad6265SDimitry Andric // This file defines a SAT solver implementation that can be used by dataflow 10*81ad6265SDimitry Andric // analyses. 11*81ad6265SDimitry Andric // 12*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 13*81ad6265SDimitry Andric 14*81ad6265SDimitry Andric #include <cassert> 15*81ad6265SDimitry Andric #include <cstdint> 16*81ad6265SDimitry Andric #include <iterator> 17*81ad6265SDimitry Andric #include <queue> 18*81ad6265SDimitry Andric #include <vector> 19*81ad6265SDimitry Andric 20*81ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Solver.h" 21*81ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h" 22*81ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h" 23*81ad6265SDimitry Andric #include "llvm/ADT/DenseMap.h" 24*81ad6265SDimitry Andric #include "llvm/ADT/DenseSet.h" 25*81ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h" 26*81ad6265SDimitry Andric 27*81ad6265SDimitry Andric namespace clang { 28*81ad6265SDimitry Andric namespace dataflow { 29*81ad6265SDimitry Andric 30*81ad6265SDimitry Andric // `WatchedLiteralsSolver` is an implementation of Algorithm D from Knuth's 31*81ad6265SDimitry Andric // The Art of Computer Programming Volume 4: Satisfiability, Fascicle 6. It is 32*81ad6265SDimitry Andric // based on the backtracking DPLL algorithm [1], keeps references to a single 33*81ad6265SDimitry Andric // "watched" literal per clause, and uses a set of "active" variables to perform 34*81ad6265SDimitry Andric // unit propagation. 35*81ad6265SDimitry Andric // 36*81ad6265SDimitry Andric // The solver expects that its input is a boolean formula in conjunctive normal 37*81ad6265SDimitry Andric // form that consists of clauses of at least one literal. A literal is either a 38*81ad6265SDimitry Andric // boolean variable or its negation. Below we define types, data structures, and 39*81ad6265SDimitry Andric // utilities that are used to represent boolean formulas in conjunctive normal 40*81ad6265SDimitry Andric // form. 41*81ad6265SDimitry Andric // 42*81ad6265SDimitry Andric // [1] https://en.wikipedia.org/wiki/DPLL_algorithm 43*81ad6265SDimitry Andric 44*81ad6265SDimitry Andric /// Boolean variables are represented as positive integers. 45*81ad6265SDimitry Andric using Variable = uint32_t; 46*81ad6265SDimitry Andric 47*81ad6265SDimitry Andric /// A null boolean variable is used as a placeholder in various data structures 48*81ad6265SDimitry Andric /// and algorithms. 49*81ad6265SDimitry Andric static constexpr Variable NullVar = 0; 50*81ad6265SDimitry Andric 51*81ad6265SDimitry Andric /// Literals are represented as positive integers. Specifically, for a boolean 52*81ad6265SDimitry Andric /// variable `V` that is represented as the positive integer `I`, the positive 53*81ad6265SDimitry Andric /// literal `V` is represented as the integer `2*I` and the negative literal 54*81ad6265SDimitry Andric /// `!V` is represented as the integer `2*I+1`. 55*81ad6265SDimitry Andric using Literal = uint32_t; 56*81ad6265SDimitry Andric 57*81ad6265SDimitry Andric /// A null literal is used as a placeholder in various data structures and 58*81ad6265SDimitry Andric /// algorithms. 59*81ad6265SDimitry Andric static constexpr Literal NullLit = 0; 60*81ad6265SDimitry Andric 61*81ad6265SDimitry Andric /// Returns the positive literal `V`. 62*81ad6265SDimitry Andric static constexpr Literal posLit(Variable V) { return 2 * V; } 63*81ad6265SDimitry Andric 64*81ad6265SDimitry Andric /// Returns the negative literal `!V`. 65*81ad6265SDimitry Andric static constexpr Literal negLit(Variable V) { return 2 * V + 1; } 66*81ad6265SDimitry Andric 67*81ad6265SDimitry Andric /// Returns the negated literal `!L`. 68*81ad6265SDimitry Andric static constexpr Literal notLit(Literal L) { return L ^ 1; } 69*81ad6265SDimitry Andric 70*81ad6265SDimitry Andric /// Returns the variable of `L`. 71*81ad6265SDimitry Andric static constexpr Variable var(Literal L) { return L >> 1; } 72*81ad6265SDimitry Andric 73*81ad6265SDimitry Andric /// Clause identifiers are represented as positive integers. 74*81ad6265SDimitry Andric using ClauseID = uint32_t; 75*81ad6265SDimitry Andric 76*81ad6265SDimitry Andric /// A null clause identifier is used as a placeholder in various data structures 77*81ad6265SDimitry Andric /// and algorithms. 78*81ad6265SDimitry Andric static constexpr ClauseID NullClause = 0; 79*81ad6265SDimitry Andric 80*81ad6265SDimitry Andric /// A boolean formula in conjunctive normal form. 81*81ad6265SDimitry Andric struct BooleanFormula { 82*81ad6265SDimitry Andric /// `LargestVar` is equal to the largest positive integer that represents a 83*81ad6265SDimitry Andric /// variable in the formula. 84*81ad6265SDimitry Andric const Variable LargestVar; 85*81ad6265SDimitry Andric 86*81ad6265SDimitry Andric /// Literals of all clauses in the formula. 87*81ad6265SDimitry Andric /// 88*81ad6265SDimitry Andric /// The element at index 0 stands for the literal in the null clause. It is 89*81ad6265SDimitry Andric /// set to 0 and isn't used. Literals of clauses in the formula start from the 90*81ad6265SDimitry Andric /// element at index 1. 91*81ad6265SDimitry Andric /// 92*81ad6265SDimitry Andric /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of 93*81ad6265SDimitry Andric /// `Clauses` will be `[0, L1, L2, L2, L3, L4]`. 94*81ad6265SDimitry Andric std::vector<Literal> Clauses; 95*81ad6265SDimitry Andric 96*81ad6265SDimitry Andric /// Start indices of clauses of the formula in `Clauses`. 97*81ad6265SDimitry Andric /// 98*81ad6265SDimitry Andric /// The element at index 0 stands for the start index of the null clause. It 99*81ad6265SDimitry Andric /// is set to 0 and isn't used. Start indices of clauses in the formula start 100*81ad6265SDimitry Andric /// from the element at index 1. 101*81ad6265SDimitry Andric /// 102*81ad6265SDimitry Andric /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of 103*81ad6265SDimitry Andric /// `ClauseStarts` will be `[0, 1, 3]`. Note that the literals of the first 104*81ad6265SDimitry Andric /// clause always start at index 1. The start index for the literals of the 105*81ad6265SDimitry Andric /// second clause depends on the size of the first clause and so on. 106*81ad6265SDimitry Andric std::vector<size_t> ClauseStarts; 107*81ad6265SDimitry Andric 108*81ad6265SDimitry Andric /// Maps literals (indices of the vector) to clause identifiers (elements of 109*81ad6265SDimitry Andric /// the vector) that watch the respective literals. 110*81ad6265SDimitry Andric /// 111*81ad6265SDimitry Andric /// For a given clause, its watched literal is always its first literal in 112*81ad6265SDimitry Andric /// `Clauses`. This invariant is maintained when watched literals change. 113*81ad6265SDimitry Andric std::vector<ClauseID> WatchedHead; 114*81ad6265SDimitry Andric 115*81ad6265SDimitry Andric /// Maps clause identifiers (elements of the vector) to identifiers of other 116*81ad6265SDimitry Andric /// clauses that watch the same literals, forming a set of linked lists. 117*81ad6265SDimitry Andric /// 118*81ad6265SDimitry Andric /// The element at index 0 stands for the identifier of the clause that 119*81ad6265SDimitry Andric /// follows the null clause. It is set to 0 and isn't used. Identifiers of 120*81ad6265SDimitry Andric /// clauses in the formula start from the element at index 1. 121*81ad6265SDimitry Andric std::vector<ClauseID> NextWatched; 122*81ad6265SDimitry Andric 123*81ad6265SDimitry Andric explicit BooleanFormula(Variable LargestVar) : LargestVar(LargestVar) { 124*81ad6265SDimitry Andric Clauses.push_back(0); 125*81ad6265SDimitry Andric ClauseStarts.push_back(0); 126*81ad6265SDimitry Andric NextWatched.push_back(0); 127*81ad6265SDimitry Andric const size_t NumLiterals = 2 * LargestVar + 1; 128*81ad6265SDimitry Andric WatchedHead.resize(NumLiterals + 1, 0); 129*81ad6265SDimitry Andric } 130*81ad6265SDimitry Andric 131*81ad6265SDimitry Andric /// Adds the `L1 v L2 v L3` clause to the formula. If `L2` or `L3` are 132*81ad6265SDimitry Andric /// `NullLit` they are respectively omitted from the clause. 133*81ad6265SDimitry Andric /// 134*81ad6265SDimitry Andric /// Requirements: 135*81ad6265SDimitry Andric /// 136*81ad6265SDimitry Andric /// `L1` must not be `NullLit`. 137*81ad6265SDimitry Andric /// 138*81ad6265SDimitry Andric /// All literals in the input that are not `NullLit` must be distinct. 139*81ad6265SDimitry Andric void addClause(Literal L1, Literal L2 = NullLit, Literal L3 = NullLit) { 140*81ad6265SDimitry Andric // The literals are guaranteed to be distinct from properties of BoolValue 141*81ad6265SDimitry Andric // and the construction in `buildBooleanFormula`. 142*81ad6265SDimitry Andric assert(L1 != NullLit && L1 != L2 && L1 != L3 && 143*81ad6265SDimitry Andric (L2 != L3 || L2 == NullLit)); 144*81ad6265SDimitry Andric 145*81ad6265SDimitry Andric const ClauseID C = ClauseStarts.size(); 146*81ad6265SDimitry Andric const size_t S = Clauses.size(); 147*81ad6265SDimitry Andric ClauseStarts.push_back(S); 148*81ad6265SDimitry Andric 149*81ad6265SDimitry Andric Clauses.push_back(L1); 150*81ad6265SDimitry Andric if (L2 != NullLit) 151*81ad6265SDimitry Andric Clauses.push_back(L2); 152*81ad6265SDimitry Andric if (L3 != NullLit) 153*81ad6265SDimitry Andric Clauses.push_back(L3); 154*81ad6265SDimitry Andric 155*81ad6265SDimitry Andric // Designate the first literal as the "watched" literal of the clause. 156*81ad6265SDimitry Andric NextWatched.push_back(WatchedHead[L1]); 157*81ad6265SDimitry Andric WatchedHead[L1] = C; 158*81ad6265SDimitry Andric } 159*81ad6265SDimitry Andric 160*81ad6265SDimitry Andric /// Returns the number of literals in clause `C`. 161*81ad6265SDimitry Andric size_t clauseSize(ClauseID C) const { 162*81ad6265SDimitry Andric return C == ClauseStarts.size() - 1 ? Clauses.size() - ClauseStarts[C] 163*81ad6265SDimitry Andric : ClauseStarts[C + 1] - ClauseStarts[C]; 164*81ad6265SDimitry Andric } 165*81ad6265SDimitry Andric 166*81ad6265SDimitry Andric /// Returns the literals of clause `C`. 167*81ad6265SDimitry Andric llvm::ArrayRef<Literal> clauseLiterals(ClauseID C) const { 168*81ad6265SDimitry Andric return llvm::ArrayRef<Literal>(&Clauses[ClauseStarts[C]], clauseSize(C)); 169*81ad6265SDimitry Andric } 170*81ad6265SDimitry Andric }; 171*81ad6265SDimitry Andric 172*81ad6265SDimitry Andric /// Converts the conjunction of `Vals` into a formula in conjunctive normal 173*81ad6265SDimitry Andric /// form where each clause has at least one and at most three literals. 174*81ad6265SDimitry Andric BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) { 175*81ad6265SDimitry Andric // The general strategy of the algorithm implemented below is to map each 176*81ad6265SDimitry Andric // of the sub-values in `Vals` to a unique variable and use these variables in 177*81ad6265SDimitry Andric // the resulting CNF expression to avoid exponential blow up. The number of 178*81ad6265SDimitry Andric // literals in the resulting formula is guaranteed to be linear in the number 179*81ad6265SDimitry Andric // of sub-values in `Vals`. 180*81ad6265SDimitry Andric 181*81ad6265SDimitry Andric // Map each sub-value in `Vals` to a unique variable. 182*81ad6265SDimitry Andric llvm::DenseMap<BoolValue *, Variable> SubValsToVar; 183*81ad6265SDimitry Andric Variable NextVar = 1; 184*81ad6265SDimitry Andric { 185*81ad6265SDimitry Andric std::queue<BoolValue *> UnprocessedSubVals; 186*81ad6265SDimitry Andric for (BoolValue *Val : Vals) 187*81ad6265SDimitry Andric UnprocessedSubVals.push(Val); 188*81ad6265SDimitry Andric while (!UnprocessedSubVals.empty()) { 189*81ad6265SDimitry Andric BoolValue *Val = UnprocessedSubVals.front(); 190*81ad6265SDimitry Andric UnprocessedSubVals.pop(); 191*81ad6265SDimitry Andric 192*81ad6265SDimitry Andric if (!SubValsToVar.try_emplace(Val, NextVar).second) 193*81ad6265SDimitry Andric continue; 194*81ad6265SDimitry Andric ++NextVar; 195*81ad6265SDimitry Andric 196*81ad6265SDimitry Andric // Visit the sub-values of `Val`. 197*81ad6265SDimitry Andric if (auto *C = dyn_cast<ConjunctionValue>(Val)) { 198*81ad6265SDimitry Andric UnprocessedSubVals.push(&C->getLeftSubValue()); 199*81ad6265SDimitry Andric UnprocessedSubVals.push(&C->getRightSubValue()); 200*81ad6265SDimitry Andric } else if (auto *D = dyn_cast<DisjunctionValue>(Val)) { 201*81ad6265SDimitry Andric UnprocessedSubVals.push(&D->getLeftSubValue()); 202*81ad6265SDimitry Andric UnprocessedSubVals.push(&D->getRightSubValue()); 203*81ad6265SDimitry Andric } else if (auto *N = dyn_cast<NegationValue>(Val)) { 204*81ad6265SDimitry Andric UnprocessedSubVals.push(&N->getSubVal()); 205*81ad6265SDimitry Andric } 206*81ad6265SDimitry Andric } 207*81ad6265SDimitry Andric } 208*81ad6265SDimitry Andric 209*81ad6265SDimitry Andric auto GetVar = [&SubValsToVar](const BoolValue *Val) { 210*81ad6265SDimitry Andric auto ValIt = SubValsToVar.find(Val); 211*81ad6265SDimitry Andric assert(ValIt != SubValsToVar.end()); 212*81ad6265SDimitry Andric return ValIt->second; 213*81ad6265SDimitry Andric }; 214*81ad6265SDimitry Andric 215*81ad6265SDimitry Andric BooleanFormula Formula(NextVar - 1); 216*81ad6265SDimitry Andric std::vector<bool> ProcessedSubVals(NextVar, false); 217*81ad6265SDimitry Andric 218*81ad6265SDimitry Andric // Add a conjunct for each variable that represents a top-level conjunction 219*81ad6265SDimitry Andric // value in `Vals`. 220*81ad6265SDimitry Andric for (BoolValue *Val : Vals) 221*81ad6265SDimitry Andric Formula.addClause(posLit(GetVar(Val))); 222*81ad6265SDimitry Andric 223*81ad6265SDimitry Andric // Add conjuncts that represent the mapping between newly-created variables 224*81ad6265SDimitry Andric // and their corresponding sub-values. 225*81ad6265SDimitry Andric std::queue<BoolValue *> UnprocessedSubVals; 226*81ad6265SDimitry Andric for (BoolValue *Val : Vals) 227*81ad6265SDimitry Andric UnprocessedSubVals.push(Val); 228*81ad6265SDimitry Andric while (!UnprocessedSubVals.empty()) { 229*81ad6265SDimitry Andric const BoolValue *Val = UnprocessedSubVals.front(); 230*81ad6265SDimitry Andric UnprocessedSubVals.pop(); 231*81ad6265SDimitry Andric const Variable Var = GetVar(Val); 232*81ad6265SDimitry Andric 233*81ad6265SDimitry Andric if (ProcessedSubVals[Var]) 234*81ad6265SDimitry Andric continue; 235*81ad6265SDimitry Andric ProcessedSubVals[Var] = true; 236*81ad6265SDimitry Andric 237*81ad6265SDimitry Andric if (auto *C = dyn_cast<ConjunctionValue>(Val)) { 238*81ad6265SDimitry Andric const Variable LeftSubVar = GetVar(&C->getLeftSubValue()); 239*81ad6265SDimitry Andric const Variable RightSubVar = GetVar(&C->getRightSubValue()); 240*81ad6265SDimitry Andric 241*81ad6265SDimitry Andric // `X <=> (A ^ B)` is equivalent to `(!X v A) ^ (!X v B) ^ (X v !A v !B)` 242*81ad6265SDimitry Andric // which is already in conjunctive normal form. Below we add each of the 243*81ad6265SDimitry Andric // conjuncts of the latter expression to the result. 244*81ad6265SDimitry Andric Formula.addClause(negLit(Var), posLit(LeftSubVar)); 245*81ad6265SDimitry Andric Formula.addClause(negLit(Var), posLit(RightSubVar)); 246*81ad6265SDimitry Andric Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar)); 247*81ad6265SDimitry Andric 248*81ad6265SDimitry Andric // Visit the sub-values of `Val`. 249*81ad6265SDimitry Andric UnprocessedSubVals.push(&C->getLeftSubValue()); 250*81ad6265SDimitry Andric UnprocessedSubVals.push(&C->getRightSubValue()); 251*81ad6265SDimitry Andric } else if (auto *D = dyn_cast<DisjunctionValue>(Val)) { 252*81ad6265SDimitry Andric const Variable LeftSubVar = GetVar(&D->getLeftSubValue()); 253*81ad6265SDimitry Andric const Variable RightSubVar = GetVar(&D->getRightSubValue()); 254*81ad6265SDimitry Andric 255*81ad6265SDimitry Andric // `X <=> (A v B)` is equivalent to `(!X v A v B) ^ (X v !A) ^ (X v !B)` 256*81ad6265SDimitry Andric // which is already in conjunctive normal form. Below we add each of the 257*81ad6265SDimitry Andric // conjuncts of the latter expression to the result. 258*81ad6265SDimitry Andric Formula.addClause(negLit(Var), posLit(LeftSubVar), posLit(RightSubVar)); 259*81ad6265SDimitry Andric Formula.addClause(posLit(Var), negLit(LeftSubVar)); 260*81ad6265SDimitry Andric Formula.addClause(posLit(Var), negLit(RightSubVar)); 261*81ad6265SDimitry Andric 262*81ad6265SDimitry Andric // Visit the sub-values of `Val`. 263*81ad6265SDimitry Andric UnprocessedSubVals.push(&D->getLeftSubValue()); 264*81ad6265SDimitry Andric UnprocessedSubVals.push(&D->getRightSubValue()); 265*81ad6265SDimitry Andric } else if (auto *N = dyn_cast<NegationValue>(Val)) { 266*81ad6265SDimitry Andric const Variable SubVar = GetVar(&N->getSubVal()); 267*81ad6265SDimitry Andric 268*81ad6265SDimitry Andric // `X <=> !Y` is equivalent to `(!X v !Y) ^ (X v Y)` which is already in 269*81ad6265SDimitry Andric // conjunctive normal form. Below we add each of the conjuncts of the 270*81ad6265SDimitry Andric // latter expression to the result. 271*81ad6265SDimitry Andric Formula.addClause(negLit(Var), negLit(SubVar)); 272*81ad6265SDimitry Andric Formula.addClause(posLit(Var), posLit(SubVar)); 273*81ad6265SDimitry Andric 274*81ad6265SDimitry Andric // Visit the sub-values of `Val`. 275*81ad6265SDimitry Andric UnprocessedSubVals.push(&N->getSubVal()); 276*81ad6265SDimitry Andric } 277*81ad6265SDimitry Andric } 278*81ad6265SDimitry Andric 279*81ad6265SDimitry Andric return Formula; 280*81ad6265SDimitry Andric } 281*81ad6265SDimitry Andric 282*81ad6265SDimitry Andric class WatchedLiteralsSolverImpl { 283*81ad6265SDimitry Andric /// A boolean formula in conjunctive normal form that the solver will attempt 284*81ad6265SDimitry Andric /// to prove satisfiable. The formula will be modified in the process. 285*81ad6265SDimitry Andric BooleanFormula Formula; 286*81ad6265SDimitry Andric 287*81ad6265SDimitry Andric /// The search for a satisfying assignment of the variables in `Formula` will 288*81ad6265SDimitry Andric /// proceed in levels, starting from 1 and going up to `Formula.LargestVar` 289*81ad6265SDimitry Andric /// (inclusive). The current level is stored in `Level`. At each level the 290*81ad6265SDimitry Andric /// solver will assign a value to an unassigned variable. If this leads to a 291*81ad6265SDimitry Andric /// consistent partial assignment, `Level` will be incremented. Otherwise, if 292*81ad6265SDimitry Andric /// it results in a conflict, the solver will backtrack by decrementing 293*81ad6265SDimitry Andric /// `Level` until it reaches the most recent level where a decision was made. 294*81ad6265SDimitry Andric size_t Level = 0; 295*81ad6265SDimitry Andric 296*81ad6265SDimitry Andric /// Maps levels (indices of the vector) to variables (elements of the vector) 297*81ad6265SDimitry Andric /// that are assigned values at the respective levels. 298*81ad6265SDimitry Andric /// 299*81ad6265SDimitry Andric /// The element at index 0 isn't used. Variables start from the element at 300*81ad6265SDimitry Andric /// index 1. 301*81ad6265SDimitry Andric std::vector<Variable> LevelVars; 302*81ad6265SDimitry Andric 303*81ad6265SDimitry Andric /// State of the solver at a particular level. 304*81ad6265SDimitry Andric enum class State : uint8_t { 305*81ad6265SDimitry Andric /// Indicates that the solver made a decision. 306*81ad6265SDimitry Andric Decision = 0, 307*81ad6265SDimitry Andric 308*81ad6265SDimitry Andric /// Indicates that the solver made a forced move. 309*81ad6265SDimitry Andric Forced = 1, 310*81ad6265SDimitry Andric }; 311*81ad6265SDimitry Andric 312*81ad6265SDimitry Andric /// State of the solver at a particular level. It keeps track of previous 313*81ad6265SDimitry Andric /// decisions that the solver can refer to when backtracking. 314*81ad6265SDimitry Andric /// 315*81ad6265SDimitry Andric /// The element at index 0 isn't used. States start from the element at index 316*81ad6265SDimitry Andric /// 1. 317*81ad6265SDimitry Andric std::vector<State> LevelStates; 318*81ad6265SDimitry Andric 319*81ad6265SDimitry Andric enum class Assignment : int8_t { 320*81ad6265SDimitry Andric Unassigned = -1, 321*81ad6265SDimitry Andric AssignedFalse = 0, 322*81ad6265SDimitry Andric AssignedTrue = 1 323*81ad6265SDimitry Andric }; 324*81ad6265SDimitry Andric 325*81ad6265SDimitry Andric /// Maps variables (indices of the vector) to their assignments (elements of 326*81ad6265SDimitry Andric /// the vector). 327*81ad6265SDimitry Andric /// 328*81ad6265SDimitry Andric /// The element at index 0 isn't used. Variable assignments start from the 329*81ad6265SDimitry Andric /// element at index 1. 330*81ad6265SDimitry Andric std::vector<Assignment> VarAssignments; 331*81ad6265SDimitry Andric 332*81ad6265SDimitry Andric /// A set of unassigned variables that appear in watched literals in 333*81ad6265SDimitry Andric /// `Formula`. The vector is guaranteed to contain unique elements. 334*81ad6265SDimitry Andric std::vector<Variable> ActiveVars; 335*81ad6265SDimitry Andric 336*81ad6265SDimitry Andric public: 337*81ad6265SDimitry Andric explicit WatchedLiteralsSolverImpl(const llvm::DenseSet<BoolValue *> &Vals) 338*81ad6265SDimitry Andric : Formula(buildBooleanFormula(Vals)), LevelVars(Formula.LargestVar + 1), 339*81ad6265SDimitry Andric LevelStates(Formula.LargestVar + 1) { 340*81ad6265SDimitry Andric assert(!Vals.empty()); 341*81ad6265SDimitry Andric 342*81ad6265SDimitry Andric // Initialize the state at the root level to a decision so that in 343*81ad6265SDimitry Andric // `reverseForcedMoves` we don't have to check that `Level >= 0` on each 344*81ad6265SDimitry Andric // iteration. 345*81ad6265SDimitry Andric LevelStates[0] = State::Decision; 346*81ad6265SDimitry Andric 347*81ad6265SDimitry Andric // Initialize all variables as unassigned. 348*81ad6265SDimitry Andric VarAssignments.resize(Formula.LargestVar + 1, Assignment::Unassigned); 349*81ad6265SDimitry Andric 350*81ad6265SDimitry Andric // Initialize the active variables. 351*81ad6265SDimitry Andric for (Variable Var = Formula.LargestVar; Var != NullVar; --Var) { 352*81ad6265SDimitry Andric if (isWatched(posLit(Var)) || isWatched(negLit(Var))) 353*81ad6265SDimitry Andric ActiveVars.push_back(Var); 354*81ad6265SDimitry Andric } 355*81ad6265SDimitry Andric } 356*81ad6265SDimitry Andric 357*81ad6265SDimitry Andric Solver::Result solve() && { 358*81ad6265SDimitry Andric size_t I = 0; 359*81ad6265SDimitry Andric while (I < ActiveVars.size()) { 360*81ad6265SDimitry Andric // Assert that the following invariants hold: 361*81ad6265SDimitry Andric // 1. All active variables are unassigned. 362*81ad6265SDimitry Andric // 2. All active variables form watched literals. 363*81ad6265SDimitry Andric // 3. Unassigned variables that form watched literals are active. 364*81ad6265SDimitry Andric // FIXME: Consider replacing these with test cases that fail if the any 365*81ad6265SDimitry Andric // of the invariants is broken. That might not be easy due to the 366*81ad6265SDimitry Andric // transformations performed by `buildBooleanFormula`. 367*81ad6265SDimitry Andric assert(activeVarsAreUnassigned()); 368*81ad6265SDimitry Andric assert(activeVarsFormWatchedLiterals()); 369*81ad6265SDimitry Andric assert(unassignedVarsFormingWatchedLiteralsAreActive()); 370*81ad6265SDimitry Andric 371*81ad6265SDimitry Andric const Variable ActiveVar = ActiveVars[I]; 372*81ad6265SDimitry Andric 373*81ad6265SDimitry Andric // Look for unit clauses that contain the active variable. 374*81ad6265SDimitry Andric const bool unitPosLit = watchedByUnitClause(posLit(ActiveVar)); 375*81ad6265SDimitry Andric const bool unitNegLit = watchedByUnitClause(negLit(ActiveVar)); 376*81ad6265SDimitry Andric if (unitPosLit && unitNegLit) { 377*81ad6265SDimitry Andric // We found a conflict! 378*81ad6265SDimitry Andric 379*81ad6265SDimitry Andric // Backtrack and rewind the `Level` until the most recent non-forced 380*81ad6265SDimitry Andric // assignment. 381*81ad6265SDimitry Andric reverseForcedMoves(); 382*81ad6265SDimitry Andric 383*81ad6265SDimitry Andric // If the root level is reached, then all possible assignments lead to 384*81ad6265SDimitry Andric // a conflict. 385*81ad6265SDimitry Andric if (Level == 0) 386*81ad6265SDimitry Andric return WatchedLiteralsSolver::Result::Unsatisfiable; 387*81ad6265SDimitry Andric 388*81ad6265SDimitry Andric // Otherwise, take the other branch at the most recent level where a 389*81ad6265SDimitry Andric // decision was made. 390*81ad6265SDimitry Andric LevelStates[Level] = State::Forced; 391*81ad6265SDimitry Andric const Variable Var = LevelVars[Level]; 392*81ad6265SDimitry Andric VarAssignments[Var] = VarAssignments[Var] == Assignment::AssignedTrue 393*81ad6265SDimitry Andric ? Assignment::AssignedFalse 394*81ad6265SDimitry Andric : Assignment::AssignedTrue; 395*81ad6265SDimitry Andric 396*81ad6265SDimitry Andric updateWatchedLiterals(); 397*81ad6265SDimitry Andric } else if (unitPosLit || unitNegLit) { 398*81ad6265SDimitry Andric // We found a unit clause! The value of its unassigned variable is 399*81ad6265SDimitry Andric // forced. 400*81ad6265SDimitry Andric ++Level; 401*81ad6265SDimitry Andric 402*81ad6265SDimitry Andric LevelVars[Level] = ActiveVar; 403*81ad6265SDimitry Andric LevelStates[Level] = State::Forced; 404*81ad6265SDimitry Andric VarAssignments[ActiveVar] = 405*81ad6265SDimitry Andric unitPosLit ? Assignment::AssignedTrue : Assignment::AssignedFalse; 406*81ad6265SDimitry Andric 407*81ad6265SDimitry Andric // Remove the variable that was just assigned from the set of active 408*81ad6265SDimitry Andric // variables. 409*81ad6265SDimitry Andric if (I + 1 < ActiveVars.size()) { 410*81ad6265SDimitry Andric // Replace the variable that was just assigned with the last active 411*81ad6265SDimitry Andric // variable for efficient removal. 412*81ad6265SDimitry Andric ActiveVars[I] = ActiveVars.back(); 413*81ad6265SDimitry Andric } else { 414*81ad6265SDimitry Andric // This was the last active variable. Repeat the process from the 415*81ad6265SDimitry Andric // beginning. 416*81ad6265SDimitry Andric I = 0; 417*81ad6265SDimitry Andric } 418*81ad6265SDimitry Andric ActiveVars.pop_back(); 419*81ad6265SDimitry Andric 420*81ad6265SDimitry Andric updateWatchedLiterals(); 421*81ad6265SDimitry Andric } else if (I + 1 == ActiveVars.size()) { 422*81ad6265SDimitry Andric // There are no remaining unit clauses in the formula! Make a decision 423*81ad6265SDimitry Andric // for one of the active variables at the current level. 424*81ad6265SDimitry Andric ++Level; 425*81ad6265SDimitry Andric 426*81ad6265SDimitry Andric LevelVars[Level] = ActiveVar; 427*81ad6265SDimitry Andric LevelStates[Level] = State::Decision; 428*81ad6265SDimitry Andric VarAssignments[ActiveVar] = decideAssignment(ActiveVar); 429*81ad6265SDimitry Andric 430*81ad6265SDimitry Andric // Remove the variable that was just assigned from the set of active 431*81ad6265SDimitry Andric // variables. 432*81ad6265SDimitry Andric ActiveVars.pop_back(); 433*81ad6265SDimitry Andric 434*81ad6265SDimitry Andric updateWatchedLiterals(); 435*81ad6265SDimitry Andric 436*81ad6265SDimitry Andric // This was the last active variable. Repeat the process from the 437*81ad6265SDimitry Andric // beginning. 438*81ad6265SDimitry Andric I = 0; 439*81ad6265SDimitry Andric } else { 440*81ad6265SDimitry Andric ++I; 441*81ad6265SDimitry Andric } 442*81ad6265SDimitry Andric } 443*81ad6265SDimitry Andric return WatchedLiteralsSolver::Result::Satisfiable; 444*81ad6265SDimitry Andric } 445*81ad6265SDimitry Andric 446*81ad6265SDimitry Andric private: 447*81ad6265SDimitry Andric // Reverses forced moves until the most recent level where a decision was made 448*81ad6265SDimitry Andric // on the assignment of a variable. 449*81ad6265SDimitry Andric void reverseForcedMoves() { 450*81ad6265SDimitry Andric for (; LevelStates[Level] == State::Forced; --Level) { 451*81ad6265SDimitry Andric const Variable Var = LevelVars[Level]; 452*81ad6265SDimitry Andric 453*81ad6265SDimitry Andric VarAssignments[Var] = Assignment::Unassigned; 454*81ad6265SDimitry Andric 455*81ad6265SDimitry Andric // If the variable that we pass through is watched then we add it to the 456*81ad6265SDimitry Andric // active variables. 457*81ad6265SDimitry Andric if (isWatched(posLit(Var)) || isWatched(negLit(Var))) 458*81ad6265SDimitry Andric ActiveVars.push_back(Var); 459*81ad6265SDimitry Andric } 460*81ad6265SDimitry Andric } 461*81ad6265SDimitry Andric 462*81ad6265SDimitry Andric // Updates watched literals that are affected by a variable assignment. 463*81ad6265SDimitry Andric void updateWatchedLiterals() { 464*81ad6265SDimitry Andric const Variable Var = LevelVars[Level]; 465*81ad6265SDimitry Andric 466*81ad6265SDimitry Andric // Update the watched literals of clauses that currently watch the literal 467*81ad6265SDimitry Andric // that falsifies `Var`. 468*81ad6265SDimitry Andric const Literal FalseLit = VarAssignments[Var] == Assignment::AssignedTrue 469*81ad6265SDimitry Andric ? negLit(Var) 470*81ad6265SDimitry Andric : posLit(Var); 471*81ad6265SDimitry Andric ClauseID FalseLitWatcher = Formula.WatchedHead[FalseLit]; 472*81ad6265SDimitry Andric Formula.WatchedHead[FalseLit] = NullClause; 473*81ad6265SDimitry Andric while (FalseLitWatcher != NullClause) { 474*81ad6265SDimitry Andric const ClauseID NextFalseLitWatcher = Formula.NextWatched[FalseLitWatcher]; 475*81ad6265SDimitry Andric 476*81ad6265SDimitry Andric // Pick the first non-false literal as the new watched literal. 477*81ad6265SDimitry Andric const size_t FalseLitWatcherStart = Formula.ClauseStarts[FalseLitWatcher]; 478*81ad6265SDimitry Andric size_t NewWatchedLitIdx = FalseLitWatcherStart + 1; 479*81ad6265SDimitry Andric while (isCurrentlyFalse(Formula.Clauses[NewWatchedLitIdx])) 480*81ad6265SDimitry Andric ++NewWatchedLitIdx; 481*81ad6265SDimitry Andric const Literal NewWatchedLit = Formula.Clauses[NewWatchedLitIdx]; 482*81ad6265SDimitry Andric const Variable NewWatchedLitVar = var(NewWatchedLit); 483*81ad6265SDimitry Andric 484*81ad6265SDimitry Andric // Swap the old watched literal for the new one in `FalseLitWatcher` to 485*81ad6265SDimitry Andric // maintain the invariant that the watched literal is at the beginning of 486*81ad6265SDimitry Andric // the clause. 487*81ad6265SDimitry Andric Formula.Clauses[NewWatchedLitIdx] = FalseLit; 488*81ad6265SDimitry Andric Formula.Clauses[FalseLitWatcherStart] = NewWatchedLit; 489*81ad6265SDimitry Andric 490*81ad6265SDimitry Andric // If the new watched literal isn't watched by any other clause and its 491*81ad6265SDimitry Andric // variable isn't assigned we need to add it to the active variables. 492*81ad6265SDimitry Andric if (!isWatched(NewWatchedLit) && !isWatched(notLit(NewWatchedLit)) && 493*81ad6265SDimitry Andric VarAssignments[NewWatchedLitVar] == Assignment::Unassigned) 494*81ad6265SDimitry Andric ActiveVars.push_back(NewWatchedLitVar); 495*81ad6265SDimitry Andric 496*81ad6265SDimitry Andric Formula.NextWatched[FalseLitWatcher] = Formula.WatchedHead[NewWatchedLit]; 497*81ad6265SDimitry Andric Formula.WatchedHead[NewWatchedLit] = FalseLitWatcher; 498*81ad6265SDimitry Andric 499*81ad6265SDimitry Andric // Go to the next clause that watches `FalseLit`. 500*81ad6265SDimitry Andric FalseLitWatcher = NextFalseLitWatcher; 501*81ad6265SDimitry Andric } 502*81ad6265SDimitry Andric } 503*81ad6265SDimitry Andric 504*81ad6265SDimitry Andric /// Returns true if and only if one of the clauses that watch `Lit` is a unit 505*81ad6265SDimitry Andric /// clause. 506*81ad6265SDimitry Andric bool watchedByUnitClause(Literal Lit) const { 507*81ad6265SDimitry Andric for (ClauseID LitWatcher = Formula.WatchedHead[Lit]; 508*81ad6265SDimitry Andric LitWatcher != NullClause; 509*81ad6265SDimitry Andric LitWatcher = Formula.NextWatched[LitWatcher]) { 510*81ad6265SDimitry Andric llvm::ArrayRef<Literal> Clause = Formula.clauseLiterals(LitWatcher); 511*81ad6265SDimitry Andric 512*81ad6265SDimitry Andric // Assert the invariant that the watched literal is always the first one 513*81ad6265SDimitry Andric // in the clause. 514*81ad6265SDimitry Andric // FIXME: Consider replacing this with a test case that fails if the 515*81ad6265SDimitry Andric // invariant is broken by `updateWatchedLiterals`. That might not be easy 516*81ad6265SDimitry Andric // due to the transformations performed by `buildBooleanFormula`. 517*81ad6265SDimitry Andric assert(Clause.front() == Lit); 518*81ad6265SDimitry Andric 519*81ad6265SDimitry Andric if (isUnit(Clause)) 520*81ad6265SDimitry Andric return true; 521*81ad6265SDimitry Andric } 522*81ad6265SDimitry Andric return false; 523*81ad6265SDimitry Andric } 524*81ad6265SDimitry Andric 525*81ad6265SDimitry Andric /// Returns true if and only if `Clause` is a unit clause. 526*81ad6265SDimitry Andric bool isUnit(llvm::ArrayRef<Literal> Clause) const { 527*81ad6265SDimitry Andric return llvm::all_of(Clause.drop_front(), 528*81ad6265SDimitry Andric [this](Literal L) { return isCurrentlyFalse(L); }); 529*81ad6265SDimitry Andric } 530*81ad6265SDimitry Andric 531*81ad6265SDimitry Andric /// Returns true if and only if `Lit` evaluates to `false` in the current 532*81ad6265SDimitry Andric /// partial assignment. 533*81ad6265SDimitry Andric bool isCurrentlyFalse(Literal Lit) const { 534*81ad6265SDimitry Andric return static_cast<int8_t>(VarAssignments[var(Lit)]) == 535*81ad6265SDimitry Andric static_cast<int8_t>(Lit & 1); 536*81ad6265SDimitry Andric } 537*81ad6265SDimitry Andric 538*81ad6265SDimitry Andric /// Returns true if and only if `Lit` is watched by a clause in `Formula`. 539*81ad6265SDimitry Andric bool isWatched(Literal Lit) const { 540*81ad6265SDimitry Andric return Formula.WatchedHead[Lit] != NullClause; 541*81ad6265SDimitry Andric } 542*81ad6265SDimitry Andric 543*81ad6265SDimitry Andric /// Returns an assignment for an unassigned variable. 544*81ad6265SDimitry Andric Assignment decideAssignment(Variable Var) const { 545*81ad6265SDimitry Andric return !isWatched(posLit(Var)) || isWatched(negLit(Var)) 546*81ad6265SDimitry Andric ? Assignment::AssignedFalse 547*81ad6265SDimitry Andric : Assignment::AssignedTrue; 548*81ad6265SDimitry Andric } 549*81ad6265SDimitry Andric 550*81ad6265SDimitry Andric /// Returns a set of all watched literals. 551*81ad6265SDimitry Andric llvm::DenseSet<Literal> watchedLiterals() const { 552*81ad6265SDimitry Andric llvm::DenseSet<Literal> WatchedLiterals; 553*81ad6265SDimitry Andric for (Literal Lit = 2; Lit < Formula.WatchedHead.size(); Lit++) { 554*81ad6265SDimitry Andric if (Formula.WatchedHead[Lit] == NullClause) 555*81ad6265SDimitry Andric continue; 556*81ad6265SDimitry Andric WatchedLiterals.insert(Lit); 557*81ad6265SDimitry Andric } 558*81ad6265SDimitry Andric return WatchedLiterals; 559*81ad6265SDimitry Andric } 560*81ad6265SDimitry Andric 561*81ad6265SDimitry Andric /// Returns true if and only if all active variables are unassigned. 562*81ad6265SDimitry Andric bool activeVarsAreUnassigned() const { 563*81ad6265SDimitry Andric return llvm::all_of(ActiveVars, [this](Variable Var) { 564*81ad6265SDimitry Andric return VarAssignments[Var] == Assignment::Unassigned; 565*81ad6265SDimitry Andric }); 566*81ad6265SDimitry Andric } 567*81ad6265SDimitry Andric 568*81ad6265SDimitry Andric /// Returns true if and only if all active variables form watched literals. 569*81ad6265SDimitry Andric bool activeVarsFormWatchedLiterals() const { 570*81ad6265SDimitry Andric const llvm::DenseSet<Literal> WatchedLiterals = watchedLiterals(); 571*81ad6265SDimitry Andric return llvm::all_of(ActiveVars, [&WatchedLiterals](Variable Var) { 572*81ad6265SDimitry Andric return WatchedLiterals.contains(posLit(Var)) || 573*81ad6265SDimitry Andric WatchedLiterals.contains(negLit(Var)); 574*81ad6265SDimitry Andric }); 575*81ad6265SDimitry Andric } 576*81ad6265SDimitry Andric 577*81ad6265SDimitry Andric /// Returns true if and only if all unassigned variables that are forming 578*81ad6265SDimitry Andric /// watched literals are active. 579*81ad6265SDimitry Andric bool unassignedVarsFormingWatchedLiteralsAreActive() const { 580*81ad6265SDimitry Andric const llvm::DenseSet<Variable> ActiveVarsSet(ActiveVars.begin(), 581*81ad6265SDimitry Andric ActiveVars.end()); 582*81ad6265SDimitry Andric for (Literal Lit : watchedLiterals()) { 583*81ad6265SDimitry Andric const Variable Var = var(Lit); 584*81ad6265SDimitry Andric if (VarAssignments[Var] != Assignment::Unassigned) 585*81ad6265SDimitry Andric continue; 586*81ad6265SDimitry Andric if (ActiveVarsSet.contains(Var)) 587*81ad6265SDimitry Andric continue; 588*81ad6265SDimitry Andric return false; 589*81ad6265SDimitry Andric } 590*81ad6265SDimitry Andric return true; 591*81ad6265SDimitry Andric } 592*81ad6265SDimitry Andric }; 593*81ad6265SDimitry Andric 594*81ad6265SDimitry Andric Solver::Result WatchedLiteralsSolver::solve(llvm::DenseSet<BoolValue *> Vals) { 595*81ad6265SDimitry Andric return Vals.empty() ? WatchedLiteralsSolver::Result::Satisfiable 596*81ad6265SDimitry Andric : WatchedLiteralsSolverImpl(Vals).solve(); 597*81ad6265SDimitry Andric } 598*81ad6265SDimitry Andric 599*81ad6265SDimitry Andric } // namespace dataflow 600*81ad6265SDimitry Andric } // namespace clang 601