181ad6265SDimitry Andric //===- WatchedLiteralsSolver.cpp --------------------------------*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This file defines a SAT solver implementation that can be used by dataflow 1081ad6265SDimitry Andric // analyses. 1181ad6265SDimitry Andric // 1281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1381ad6265SDimitry Andric 1481ad6265SDimitry Andric #include <cassert> 1581ad6265SDimitry Andric #include <cstdint> 1681ad6265SDimitry Andric #include <iterator> 1781ad6265SDimitry Andric #include <queue> 1881ad6265SDimitry Andric #include <vector> 1981ad6265SDimitry Andric 2081ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Solver.h" 2181ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h" 2281ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h" 2381ad6265SDimitry Andric #include "llvm/ADT/DenseMap.h" 2481ad6265SDimitry Andric #include "llvm/ADT/DenseSet.h" 2581ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h" 2681ad6265SDimitry Andric 2781ad6265SDimitry Andric namespace clang { 2881ad6265SDimitry Andric namespace dataflow { 2981ad6265SDimitry Andric 3081ad6265SDimitry Andric // `WatchedLiteralsSolver` is an implementation of Algorithm D from Knuth's 3181ad6265SDimitry Andric // The Art of Computer Programming Volume 4: Satisfiability, Fascicle 6. It is 3281ad6265SDimitry Andric // based on the backtracking DPLL algorithm [1], keeps references to a single 3381ad6265SDimitry Andric // "watched" literal per clause, and uses a set of "active" variables to perform 3481ad6265SDimitry Andric // unit propagation. 3581ad6265SDimitry Andric // 3681ad6265SDimitry Andric // The solver expects that its input is a boolean formula in conjunctive normal 3781ad6265SDimitry Andric // form that consists of clauses of at least one literal. A literal is either a 3881ad6265SDimitry Andric // boolean variable or its negation. Below we define types, data structures, and 3981ad6265SDimitry Andric // utilities that are used to represent boolean formulas in conjunctive normal 4081ad6265SDimitry Andric // form. 4181ad6265SDimitry Andric // 4281ad6265SDimitry Andric // [1] https://en.wikipedia.org/wiki/DPLL_algorithm 4381ad6265SDimitry Andric 4481ad6265SDimitry Andric /// Boolean variables are represented as positive integers. 4581ad6265SDimitry Andric using Variable = uint32_t; 4681ad6265SDimitry Andric 4781ad6265SDimitry Andric /// A null boolean variable is used as a placeholder in various data structures 4881ad6265SDimitry Andric /// and algorithms. 4981ad6265SDimitry Andric static constexpr Variable NullVar = 0; 5081ad6265SDimitry Andric 5181ad6265SDimitry Andric /// Literals are represented as positive integers. Specifically, for a boolean 5281ad6265SDimitry Andric /// variable `V` that is represented as the positive integer `I`, the positive 5381ad6265SDimitry Andric /// literal `V` is represented as the integer `2*I` and the negative literal 5481ad6265SDimitry Andric /// `!V` is represented as the integer `2*I+1`. 5581ad6265SDimitry Andric using Literal = uint32_t; 5681ad6265SDimitry Andric 5781ad6265SDimitry Andric /// A null literal is used as a placeholder in various data structures and 5881ad6265SDimitry Andric /// algorithms. 5981ad6265SDimitry Andric static constexpr Literal NullLit = 0; 6081ad6265SDimitry Andric 6181ad6265SDimitry Andric /// Returns the positive literal `V`. 6281ad6265SDimitry Andric static constexpr Literal posLit(Variable V) { return 2 * V; } 6381ad6265SDimitry Andric 6481ad6265SDimitry Andric /// Returns the negative literal `!V`. 6581ad6265SDimitry Andric static constexpr Literal negLit(Variable V) { return 2 * V + 1; } 6681ad6265SDimitry Andric 6781ad6265SDimitry Andric /// Returns the negated literal `!L`. 6881ad6265SDimitry Andric static constexpr Literal notLit(Literal L) { return L ^ 1; } 6981ad6265SDimitry Andric 7081ad6265SDimitry Andric /// Returns the variable of `L`. 7181ad6265SDimitry Andric static constexpr Variable var(Literal L) { return L >> 1; } 7281ad6265SDimitry Andric 7381ad6265SDimitry Andric /// Clause identifiers are represented as positive integers. 7481ad6265SDimitry Andric using ClauseID = uint32_t; 7581ad6265SDimitry Andric 7681ad6265SDimitry Andric /// A null clause identifier is used as a placeholder in various data structures 7781ad6265SDimitry Andric /// and algorithms. 7881ad6265SDimitry Andric static constexpr ClauseID NullClause = 0; 7981ad6265SDimitry Andric 8081ad6265SDimitry Andric /// A boolean formula in conjunctive normal form. 8181ad6265SDimitry Andric struct BooleanFormula { 8281ad6265SDimitry Andric /// `LargestVar` is equal to the largest positive integer that represents a 8381ad6265SDimitry Andric /// variable in the formula. 8481ad6265SDimitry Andric const Variable LargestVar; 8581ad6265SDimitry Andric 8681ad6265SDimitry Andric /// Literals of all clauses in the formula. 8781ad6265SDimitry Andric /// 8881ad6265SDimitry Andric /// The element at index 0 stands for the literal in the null clause. It is 8981ad6265SDimitry Andric /// set to 0 and isn't used. Literals of clauses in the formula start from the 9081ad6265SDimitry Andric /// element at index 1. 9181ad6265SDimitry Andric /// 9281ad6265SDimitry Andric /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of 9381ad6265SDimitry Andric /// `Clauses` will be `[0, L1, L2, L2, L3, L4]`. 9481ad6265SDimitry Andric std::vector<Literal> Clauses; 9581ad6265SDimitry Andric 9681ad6265SDimitry Andric /// Start indices of clauses of the formula in `Clauses`. 9781ad6265SDimitry Andric /// 9881ad6265SDimitry Andric /// The element at index 0 stands for the start index of the null clause. It 9981ad6265SDimitry Andric /// is set to 0 and isn't used. Start indices of clauses in the formula start 10081ad6265SDimitry Andric /// from the element at index 1. 10181ad6265SDimitry Andric /// 10281ad6265SDimitry Andric /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of 10381ad6265SDimitry Andric /// `ClauseStarts` will be `[0, 1, 3]`. Note that the literals of the first 10481ad6265SDimitry Andric /// clause always start at index 1. The start index for the literals of the 10581ad6265SDimitry Andric /// second clause depends on the size of the first clause and so on. 10681ad6265SDimitry Andric std::vector<size_t> ClauseStarts; 10781ad6265SDimitry Andric 10881ad6265SDimitry Andric /// Maps literals (indices of the vector) to clause identifiers (elements of 10981ad6265SDimitry Andric /// the vector) that watch the respective literals. 11081ad6265SDimitry Andric /// 11181ad6265SDimitry Andric /// For a given clause, its watched literal is always its first literal in 11281ad6265SDimitry Andric /// `Clauses`. This invariant is maintained when watched literals change. 11381ad6265SDimitry Andric std::vector<ClauseID> WatchedHead; 11481ad6265SDimitry Andric 11581ad6265SDimitry Andric /// Maps clause identifiers (elements of the vector) to identifiers of other 11681ad6265SDimitry Andric /// clauses that watch the same literals, forming a set of linked lists. 11781ad6265SDimitry Andric /// 11881ad6265SDimitry Andric /// The element at index 0 stands for the identifier of the clause that 11981ad6265SDimitry Andric /// follows the null clause. It is set to 0 and isn't used. Identifiers of 12081ad6265SDimitry Andric /// clauses in the formula start from the element at index 1. 12181ad6265SDimitry Andric std::vector<ClauseID> NextWatched; 12281ad6265SDimitry Andric 123753f127fSDimitry Andric /// Stores the variable identifier and value location for atomic booleans in 124753f127fSDimitry Andric /// the formula. 125753f127fSDimitry Andric llvm::DenseMap<Variable, AtomicBoolValue *> Atomics; 126753f127fSDimitry Andric 127753f127fSDimitry Andric explicit BooleanFormula(Variable LargestVar, 128753f127fSDimitry Andric llvm::DenseMap<Variable, AtomicBoolValue *> Atomics) 129753f127fSDimitry Andric : LargestVar(LargestVar), Atomics(std::move(Atomics)) { 13081ad6265SDimitry Andric Clauses.push_back(0); 13181ad6265SDimitry Andric ClauseStarts.push_back(0); 13281ad6265SDimitry Andric NextWatched.push_back(0); 13381ad6265SDimitry Andric const size_t NumLiterals = 2 * LargestVar + 1; 13481ad6265SDimitry Andric WatchedHead.resize(NumLiterals + 1, 0); 13581ad6265SDimitry Andric } 13681ad6265SDimitry Andric 13781ad6265SDimitry Andric /// Adds the `L1 v L2 v L3` clause to the formula. If `L2` or `L3` are 13881ad6265SDimitry Andric /// `NullLit` they are respectively omitted from the clause. 13981ad6265SDimitry Andric /// 14081ad6265SDimitry Andric /// Requirements: 14181ad6265SDimitry Andric /// 14281ad6265SDimitry Andric /// `L1` must not be `NullLit`. 14381ad6265SDimitry Andric /// 14481ad6265SDimitry Andric /// All literals in the input that are not `NullLit` must be distinct. 14581ad6265SDimitry Andric void addClause(Literal L1, Literal L2 = NullLit, Literal L3 = NullLit) { 14681ad6265SDimitry Andric // The literals are guaranteed to be distinct from properties of BoolValue 14781ad6265SDimitry Andric // and the construction in `buildBooleanFormula`. 14881ad6265SDimitry Andric assert(L1 != NullLit && L1 != L2 && L1 != L3 && 14981ad6265SDimitry Andric (L2 != L3 || L2 == NullLit)); 15081ad6265SDimitry Andric 15181ad6265SDimitry Andric const ClauseID C = ClauseStarts.size(); 15281ad6265SDimitry Andric const size_t S = Clauses.size(); 15381ad6265SDimitry Andric ClauseStarts.push_back(S); 15481ad6265SDimitry Andric 15581ad6265SDimitry Andric Clauses.push_back(L1); 15681ad6265SDimitry Andric if (L2 != NullLit) 15781ad6265SDimitry Andric Clauses.push_back(L2); 15881ad6265SDimitry Andric if (L3 != NullLit) 15981ad6265SDimitry Andric Clauses.push_back(L3); 16081ad6265SDimitry Andric 16181ad6265SDimitry Andric // Designate the first literal as the "watched" literal of the clause. 16281ad6265SDimitry Andric NextWatched.push_back(WatchedHead[L1]); 16381ad6265SDimitry Andric WatchedHead[L1] = C; 16481ad6265SDimitry Andric } 16581ad6265SDimitry Andric 16681ad6265SDimitry Andric /// Returns the number of literals in clause `C`. 16781ad6265SDimitry Andric size_t clauseSize(ClauseID C) const { 16881ad6265SDimitry Andric return C == ClauseStarts.size() - 1 ? Clauses.size() - ClauseStarts[C] 16981ad6265SDimitry Andric : ClauseStarts[C + 1] - ClauseStarts[C]; 17081ad6265SDimitry Andric } 17181ad6265SDimitry Andric 17281ad6265SDimitry Andric /// Returns the literals of clause `C`. 17381ad6265SDimitry Andric llvm::ArrayRef<Literal> clauseLiterals(ClauseID C) const { 17481ad6265SDimitry Andric return llvm::ArrayRef<Literal>(&Clauses[ClauseStarts[C]], clauseSize(C)); 17581ad6265SDimitry Andric } 17681ad6265SDimitry Andric }; 17781ad6265SDimitry Andric 17881ad6265SDimitry Andric /// Converts the conjunction of `Vals` into a formula in conjunctive normal 17981ad6265SDimitry Andric /// form where each clause has at least one and at most three literals. 18081ad6265SDimitry Andric BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) { 18181ad6265SDimitry Andric // The general strategy of the algorithm implemented below is to map each 18281ad6265SDimitry Andric // of the sub-values in `Vals` to a unique variable and use these variables in 18381ad6265SDimitry Andric // the resulting CNF expression to avoid exponential blow up. The number of 18481ad6265SDimitry Andric // literals in the resulting formula is guaranteed to be linear in the number 18581ad6265SDimitry Andric // of sub-values in `Vals`. 18681ad6265SDimitry Andric 18781ad6265SDimitry Andric // Map each sub-value in `Vals` to a unique variable. 18881ad6265SDimitry Andric llvm::DenseMap<BoolValue *, Variable> SubValsToVar; 189753f127fSDimitry Andric // Store variable identifiers and value location of atomic booleans. 190753f127fSDimitry Andric llvm::DenseMap<Variable, AtomicBoolValue *> Atomics; 19181ad6265SDimitry Andric Variable NextVar = 1; 19281ad6265SDimitry Andric { 19381ad6265SDimitry Andric std::queue<BoolValue *> UnprocessedSubVals; 19481ad6265SDimitry Andric for (BoolValue *Val : Vals) 19581ad6265SDimitry Andric UnprocessedSubVals.push(Val); 19681ad6265SDimitry Andric while (!UnprocessedSubVals.empty()) { 197753f127fSDimitry Andric Variable Var = NextVar; 19881ad6265SDimitry Andric BoolValue *Val = UnprocessedSubVals.front(); 19981ad6265SDimitry Andric UnprocessedSubVals.pop(); 20081ad6265SDimitry Andric 201753f127fSDimitry Andric if (!SubValsToVar.try_emplace(Val, Var).second) 20281ad6265SDimitry Andric continue; 20381ad6265SDimitry Andric ++NextVar; 20481ad6265SDimitry Andric 20581ad6265SDimitry Andric // Visit the sub-values of `Val`. 206753f127fSDimitry Andric switch (Val->getKind()) { 207753f127fSDimitry Andric case Value::Kind::Conjunction: { 208753f127fSDimitry Andric auto *C = cast<ConjunctionValue>(Val); 20981ad6265SDimitry Andric UnprocessedSubVals.push(&C->getLeftSubValue()); 21081ad6265SDimitry Andric UnprocessedSubVals.push(&C->getRightSubValue()); 211753f127fSDimitry Andric break; 212753f127fSDimitry Andric } 213753f127fSDimitry Andric case Value::Kind::Disjunction: { 214753f127fSDimitry Andric auto *D = cast<DisjunctionValue>(Val); 21581ad6265SDimitry Andric UnprocessedSubVals.push(&D->getLeftSubValue()); 21681ad6265SDimitry Andric UnprocessedSubVals.push(&D->getRightSubValue()); 217753f127fSDimitry Andric break; 218753f127fSDimitry Andric } 219753f127fSDimitry Andric case Value::Kind::Negation: { 220753f127fSDimitry Andric auto *N = cast<NegationValue>(Val); 22181ad6265SDimitry Andric UnprocessedSubVals.push(&N->getSubVal()); 222753f127fSDimitry Andric break; 223753f127fSDimitry Andric } 224*972a253aSDimitry Andric case Value::Kind::Implication: { 225*972a253aSDimitry Andric auto *I = cast<ImplicationValue>(Val); 226*972a253aSDimitry Andric UnprocessedSubVals.push(&I->getLeftSubValue()); 227*972a253aSDimitry Andric UnprocessedSubVals.push(&I->getRightSubValue()); 228*972a253aSDimitry Andric break; 229*972a253aSDimitry Andric } 230*972a253aSDimitry Andric case Value::Kind::Biconditional: { 231*972a253aSDimitry Andric auto *B = cast<BiconditionalValue>(Val); 232*972a253aSDimitry Andric UnprocessedSubVals.push(&B->getLeftSubValue()); 233*972a253aSDimitry Andric UnprocessedSubVals.push(&B->getRightSubValue()); 234*972a253aSDimitry Andric break; 235*972a253aSDimitry Andric } 236753f127fSDimitry Andric case Value::Kind::AtomicBool: { 237753f127fSDimitry Andric Atomics[Var] = cast<AtomicBoolValue>(Val); 238753f127fSDimitry Andric break; 239753f127fSDimitry Andric } 240753f127fSDimitry Andric default: 241753f127fSDimitry Andric llvm_unreachable("buildBooleanFormula: unhandled value kind"); 24281ad6265SDimitry Andric } 24381ad6265SDimitry Andric } 24481ad6265SDimitry Andric } 24581ad6265SDimitry Andric 24681ad6265SDimitry Andric auto GetVar = [&SubValsToVar](const BoolValue *Val) { 24781ad6265SDimitry Andric auto ValIt = SubValsToVar.find(Val); 24881ad6265SDimitry Andric assert(ValIt != SubValsToVar.end()); 24981ad6265SDimitry Andric return ValIt->second; 25081ad6265SDimitry Andric }; 25181ad6265SDimitry Andric 252753f127fSDimitry Andric BooleanFormula Formula(NextVar - 1, std::move(Atomics)); 25381ad6265SDimitry Andric std::vector<bool> ProcessedSubVals(NextVar, false); 25481ad6265SDimitry Andric 25581ad6265SDimitry Andric // Add a conjunct for each variable that represents a top-level conjunction 25681ad6265SDimitry Andric // value in `Vals`. 25781ad6265SDimitry Andric for (BoolValue *Val : Vals) 25881ad6265SDimitry Andric Formula.addClause(posLit(GetVar(Val))); 25981ad6265SDimitry Andric 26081ad6265SDimitry Andric // Add conjuncts that represent the mapping between newly-created variables 26181ad6265SDimitry Andric // and their corresponding sub-values. 26281ad6265SDimitry Andric std::queue<BoolValue *> UnprocessedSubVals; 26381ad6265SDimitry Andric for (BoolValue *Val : Vals) 26481ad6265SDimitry Andric UnprocessedSubVals.push(Val); 26581ad6265SDimitry Andric while (!UnprocessedSubVals.empty()) { 26681ad6265SDimitry Andric const BoolValue *Val = UnprocessedSubVals.front(); 26781ad6265SDimitry Andric UnprocessedSubVals.pop(); 26881ad6265SDimitry Andric const Variable Var = GetVar(Val); 26981ad6265SDimitry Andric 27081ad6265SDimitry Andric if (ProcessedSubVals[Var]) 27181ad6265SDimitry Andric continue; 27281ad6265SDimitry Andric ProcessedSubVals[Var] = true; 27381ad6265SDimitry Andric 27481ad6265SDimitry Andric if (auto *C = dyn_cast<ConjunctionValue>(Val)) { 27581ad6265SDimitry Andric const Variable LeftSubVar = GetVar(&C->getLeftSubValue()); 27681ad6265SDimitry Andric const Variable RightSubVar = GetVar(&C->getRightSubValue()); 27781ad6265SDimitry Andric 278*972a253aSDimitry Andric if (LeftSubVar == RightSubVar) { 279*972a253aSDimitry Andric // `X <=> (A ^ A)` is equivalent to `(!X v A) ^ (X v !A)` which is 280*972a253aSDimitry Andric // already in conjunctive normal form. Below we add each of the 281*972a253aSDimitry Andric // conjuncts of the latter expression to the result. 282*972a253aSDimitry Andric Formula.addClause(negLit(Var), posLit(LeftSubVar)); 283*972a253aSDimitry Andric Formula.addClause(posLit(Var), negLit(LeftSubVar)); 284*972a253aSDimitry Andric 285*972a253aSDimitry Andric // Visit a sub-value of `Val` (pick any, they are identical). 286*972a253aSDimitry Andric UnprocessedSubVals.push(&C->getLeftSubValue()); 287*972a253aSDimitry Andric } else { 28881ad6265SDimitry Andric // `X <=> (A ^ B)` is equivalent to `(!X v A) ^ (!X v B) ^ (X v !A v !B)` 28981ad6265SDimitry Andric // which is already in conjunctive normal form. Below we add each of the 29081ad6265SDimitry Andric // conjuncts of the latter expression to the result. 29181ad6265SDimitry Andric Formula.addClause(negLit(Var), posLit(LeftSubVar)); 29281ad6265SDimitry Andric Formula.addClause(negLit(Var), posLit(RightSubVar)); 29381ad6265SDimitry Andric Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar)); 29481ad6265SDimitry Andric 29581ad6265SDimitry Andric // Visit the sub-values of `Val`. 29681ad6265SDimitry Andric UnprocessedSubVals.push(&C->getLeftSubValue()); 29781ad6265SDimitry Andric UnprocessedSubVals.push(&C->getRightSubValue()); 298*972a253aSDimitry Andric } 29981ad6265SDimitry Andric } else if (auto *D = dyn_cast<DisjunctionValue>(Val)) { 30081ad6265SDimitry Andric const Variable LeftSubVar = GetVar(&D->getLeftSubValue()); 30181ad6265SDimitry Andric const Variable RightSubVar = GetVar(&D->getRightSubValue()); 30281ad6265SDimitry Andric 303*972a253aSDimitry Andric if (LeftSubVar == RightSubVar) { 304*972a253aSDimitry Andric // `X <=> (A v A)` is equivalent to `(!X v A) ^ (X v !A)` which is 305*972a253aSDimitry Andric // already in conjunctive normal form. Below we add each of the 306*972a253aSDimitry Andric // conjuncts of the latter expression to the result. 307*972a253aSDimitry Andric Formula.addClause(negLit(Var), posLit(LeftSubVar)); 308*972a253aSDimitry Andric Formula.addClause(posLit(Var), negLit(LeftSubVar)); 309*972a253aSDimitry Andric 310*972a253aSDimitry Andric // Visit a sub-value of `Val` (pick any, they are identical). 311*972a253aSDimitry Andric UnprocessedSubVals.push(&D->getLeftSubValue()); 312*972a253aSDimitry Andric } else { 31381ad6265SDimitry Andric // `X <=> (A v B)` is equivalent to `(!X v A v B) ^ (X v !A) ^ (X v !B)` 31481ad6265SDimitry Andric // which is already in conjunctive normal form. Below we add each of the 31581ad6265SDimitry Andric // conjuncts of the latter expression to the result. 31681ad6265SDimitry Andric Formula.addClause(negLit(Var), posLit(LeftSubVar), posLit(RightSubVar)); 31781ad6265SDimitry Andric Formula.addClause(posLit(Var), negLit(LeftSubVar)); 31881ad6265SDimitry Andric Formula.addClause(posLit(Var), negLit(RightSubVar)); 31981ad6265SDimitry Andric 32081ad6265SDimitry Andric // Visit the sub-values of `Val`. 32181ad6265SDimitry Andric UnprocessedSubVals.push(&D->getLeftSubValue()); 32281ad6265SDimitry Andric UnprocessedSubVals.push(&D->getRightSubValue()); 323*972a253aSDimitry Andric } 32481ad6265SDimitry Andric } else if (auto *N = dyn_cast<NegationValue>(Val)) { 32581ad6265SDimitry Andric const Variable SubVar = GetVar(&N->getSubVal()); 32681ad6265SDimitry Andric 32781ad6265SDimitry Andric // `X <=> !Y` is equivalent to `(!X v !Y) ^ (X v Y)` which is already in 32881ad6265SDimitry Andric // conjunctive normal form. Below we add each of the conjuncts of the 32981ad6265SDimitry Andric // latter expression to the result. 33081ad6265SDimitry Andric Formula.addClause(negLit(Var), negLit(SubVar)); 33181ad6265SDimitry Andric Formula.addClause(posLit(Var), posLit(SubVar)); 33281ad6265SDimitry Andric 33381ad6265SDimitry Andric // Visit the sub-values of `Val`. 33481ad6265SDimitry Andric UnprocessedSubVals.push(&N->getSubVal()); 335*972a253aSDimitry Andric } else if (auto *I = dyn_cast<ImplicationValue>(Val)) { 336*972a253aSDimitry Andric const Variable LeftSubVar = GetVar(&I->getLeftSubValue()); 337*972a253aSDimitry Andric const Variable RightSubVar = GetVar(&I->getRightSubValue()); 338*972a253aSDimitry Andric 339*972a253aSDimitry Andric // `X <=> (A => B)` is equivalent to 340*972a253aSDimitry Andric // `(X v A) ^ (X v !B) ^ (!X v !A v B)` which is already in 341*972a253aSDimitry Andric // conjunctive normal form. Below we add each of the conjuncts of the 342*972a253aSDimitry Andric // latter expression to the result. 343*972a253aSDimitry Andric Formula.addClause(posLit(Var), posLit(LeftSubVar)); 344*972a253aSDimitry Andric Formula.addClause(posLit(Var), negLit(RightSubVar)); 345*972a253aSDimitry Andric Formula.addClause(negLit(Var), negLit(LeftSubVar), posLit(RightSubVar)); 346*972a253aSDimitry Andric 347*972a253aSDimitry Andric // Visit the sub-values of `Val`. 348*972a253aSDimitry Andric UnprocessedSubVals.push(&I->getLeftSubValue()); 349*972a253aSDimitry Andric UnprocessedSubVals.push(&I->getRightSubValue()); 350*972a253aSDimitry Andric } else if (auto *B = dyn_cast<BiconditionalValue>(Val)) { 351*972a253aSDimitry Andric const Variable LeftSubVar = GetVar(&B->getLeftSubValue()); 352*972a253aSDimitry Andric const Variable RightSubVar = GetVar(&B->getRightSubValue()); 353*972a253aSDimitry Andric 354*972a253aSDimitry Andric if (LeftSubVar == RightSubVar) { 355*972a253aSDimitry Andric // `X <=> (A <=> A)` is equvalent to `X` which is already in 356*972a253aSDimitry Andric // conjunctive normal form. Below we add each of the conjuncts of the 357*972a253aSDimitry Andric // latter expression to the result. 358*972a253aSDimitry Andric Formula.addClause(posLit(Var)); 359*972a253aSDimitry Andric 360*972a253aSDimitry Andric // No need to visit the sub-values of `Val`. 361*972a253aSDimitry Andric } else { 362*972a253aSDimitry Andric // `X <=> (A <=> B)` is equivalent to 363*972a253aSDimitry Andric // `(X v A v B) ^ (X v !A v !B) ^ (!X v A v !B) ^ (!X v !A v B)` which is 364*972a253aSDimitry Andric // already in conjunctive normal form. Below we add each of the conjuncts 365*972a253aSDimitry Andric // of the latter expression to the result. 366*972a253aSDimitry Andric Formula.addClause(posLit(Var), posLit(LeftSubVar), posLit(RightSubVar)); 367*972a253aSDimitry Andric Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar)); 368*972a253aSDimitry Andric Formula.addClause(negLit(Var), posLit(LeftSubVar), negLit(RightSubVar)); 369*972a253aSDimitry Andric Formula.addClause(negLit(Var), negLit(LeftSubVar), posLit(RightSubVar)); 370*972a253aSDimitry Andric 371*972a253aSDimitry Andric // Visit the sub-values of `Val`. 372*972a253aSDimitry Andric UnprocessedSubVals.push(&B->getLeftSubValue()); 373*972a253aSDimitry Andric UnprocessedSubVals.push(&B->getRightSubValue()); 374*972a253aSDimitry Andric } 37581ad6265SDimitry Andric } 37681ad6265SDimitry Andric } 37781ad6265SDimitry Andric 37881ad6265SDimitry Andric return Formula; 37981ad6265SDimitry Andric } 38081ad6265SDimitry Andric 38181ad6265SDimitry Andric class WatchedLiteralsSolverImpl { 38281ad6265SDimitry Andric /// A boolean formula in conjunctive normal form that the solver will attempt 38381ad6265SDimitry Andric /// to prove satisfiable. The formula will be modified in the process. 38481ad6265SDimitry Andric BooleanFormula Formula; 38581ad6265SDimitry Andric 38681ad6265SDimitry Andric /// The search for a satisfying assignment of the variables in `Formula` will 38781ad6265SDimitry Andric /// proceed in levels, starting from 1 and going up to `Formula.LargestVar` 38881ad6265SDimitry Andric /// (inclusive). The current level is stored in `Level`. At each level the 38981ad6265SDimitry Andric /// solver will assign a value to an unassigned variable. If this leads to a 39081ad6265SDimitry Andric /// consistent partial assignment, `Level` will be incremented. Otherwise, if 39181ad6265SDimitry Andric /// it results in a conflict, the solver will backtrack by decrementing 39281ad6265SDimitry Andric /// `Level` until it reaches the most recent level where a decision was made. 39381ad6265SDimitry Andric size_t Level = 0; 39481ad6265SDimitry Andric 39581ad6265SDimitry Andric /// Maps levels (indices of the vector) to variables (elements of the vector) 39681ad6265SDimitry Andric /// that are assigned values at the respective levels. 39781ad6265SDimitry Andric /// 39881ad6265SDimitry Andric /// The element at index 0 isn't used. Variables start from the element at 39981ad6265SDimitry Andric /// index 1. 40081ad6265SDimitry Andric std::vector<Variable> LevelVars; 40181ad6265SDimitry Andric 40281ad6265SDimitry Andric /// State of the solver at a particular level. 40381ad6265SDimitry Andric enum class State : uint8_t { 40481ad6265SDimitry Andric /// Indicates that the solver made a decision. 40581ad6265SDimitry Andric Decision = 0, 40681ad6265SDimitry Andric 40781ad6265SDimitry Andric /// Indicates that the solver made a forced move. 40881ad6265SDimitry Andric Forced = 1, 40981ad6265SDimitry Andric }; 41081ad6265SDimitry Andric 41181ad6265SDimitry Andric /// State of the solver at a particular level. It keeps track of previous 41281ad6265SDimitry Andric /// decisions that the solver can refer to when backtracking. 41381ad6265SDimitry Andric /// 41481ad6265SDimitry Andric /// The element at index 0 isn't used. States start from the element at index 41581ad6265SDimitry Andric /// 1. 41681ad6265SDimitry Andric std::vector<State> LevelStates; 41781ad6265SDimitry Andric 41881ad6265SDimitry Andric enum class Assignment : int8_t { 41981ad6265SDimitry Andric Unassigned = -1, 42081ad6265SDimitry Andric AssignedFalse = 0, 42181ad6265SDimitry Andric AssignedTrue = 1 42281ad6265SDimitry Andric }; 42381ad6265SDimitry Andric 42481ad6265SDimitry Andric /// Maps variables (indices of the vector) to their assignments (elements of 42581ad6265SDimitry Andric /// the vector). 42681ad6265SDimitry Andric /// 42781ad6265SDimitry Andric /// The element at index 0 isn't used. Variable assignments start from the 42881ad6265SDimitry Andric /// element at index 1. 42981ad6265SDimitry Andric std::vector<Assignment> VarAssignments; 43081ad6265SDimitry Andric 43181ad6265SDimitry Andric /// A set of unassigned variables that appear in watched literals in 43281ad6265SDimitry Andric /// `Formula`. The vector is guaranteed to contain unique elements. 43381ad6265SDimitry Andric std::vector<Variable> ActiveVars; 43481ad6265SDimitry Andric 43581ad6265SDimitry Andric public: 43681ad6265SDimitry Andric explicit WatchedLiteralsSolverImpl(const llvm::DenseSet<BoolValue *> &Vals) 43781ad6265SDimitry Andric : Formula(buildBooleanFormula(Vals)), LevelVars(Formula.LargestVar + 1), 43881ad6265SDimitry Andric LevelStates(Formula.LargestVar + 1) { 43981ad6265SDimitry Andric assert(!Vals.empty()); 44081ad6265SDimitry Andric 44181ad6265SDimitry Andric // Initialize the state at the root level to a decision so that in 44281ad6265SDimitry Andric // `reverseForcedMoves` we don't have to check that `Level >= 0` on each 44381ad6265SDimitry Andric // iteration. 44481ad6265SDimitry Andric LevelStates[0] = State::Decision; 44581ad6265SDimitry Andric 44681ad6265SDimitry Andric // Initialize all variables as unassigned. 44781ad6265SDimitry Andric VarAssignments.resize(Formula.LargestVar + 1, Assignment::Unassigned); 44881ad6265SDimitry Andric 44981ad6265SDimitry Andric // Initialize the active variables. 45081ad6265SDimitry Andric for (Variable Var = Formula.LargestVar; Var != NullVar; --Var) { 45181ad6265SDimitry Andric if (isWatched(posLit(Var)) || isWatched(negLit(Var))) 45281ad6265SDimitry Andric ActiveVars.push_back(Var); 45381ad6265SDimitry Andric } 45481ad6265SDimitry Andric } 45581ad6265SDimitry Andric 45681ad6265SDimitry Andric Solver::Result solve() && { 45781ad6265SDimitry Andric size_t I = 0; 45881ad6265SDimitry Andric while (I < ActiveVars.size()) { 45981ad6265SDimitry Andric // Assert that the following invariants hold: 46081ad6265SDimitry Andric // 1. All active variables are unassigned. 46181ad6265SDimitry Andric // 2. All active variables form watched literals. 46281ad6265SDimitry Andric // 3. Unassigned variables that form watched literals are active. 46381ad6265SDimitry Andric // FIXME: Consider replacing these with test cases that fail if the any 46481ad6265SDimitry Andric // of the invariants is broken. That might not be easy due to the 46581ad6265SDimitry Andric // transformations performed by `buildBooleanFormula`. 46681ad6265SDimitry Andric assert(activeVarsAreUnassigned()); 46781ad6265SDimitry Andric assert(activeVarsFormWatchedLiterals()); 46881ad6265SDimitry Andric assert(unassignedVarsFormingWatchedLiteralsAreActive()); 46981ad6265SDimitry Andric 47081ad6265SDimitry Andric const Variable ActiveVar = ActiveVars[I]; 47181ad6265SDimitry Andric 47281ad6265SDimitry Andric // Look for unit clauses that contain the active variable. 47381ad6265SDimitry Andric const bool unitPosLit = watchedByUnitClause(posLit(ActiveVar)); 47481ad6265SDimitry Andric const bool unitNegLit = watchedByUnitClause(negLit(ActiveVar)); 47581ad6265SDimitry Andric if (unitPosLit && unitNegLit) { 47681ad6265SDimitry Andric // We found a conflict! 47781ad6265SDimitry Andric 47881ad6265SDimitry Andric // Backtrack and rewind the `Level` until the most recent non-forced 47981ad6265SDimitry Andric // assignment. 48081ad6265SDimitry Andric reverseForcedMoves(); 48181ad6265SDimitry Andric 48281ad6265SDimitry Andric // If the root level is reached, then all possible assignments lead to 48381ad6265SDimitry Andric // a conflict. 48481ad6265SDimitry Andric if (Level == 0) 485753f127fSDimitry Andric return Solver::Result::Unsatisfiable(); 48681ad6265SDimitry Andric 48781ad6265SDimitry Andric // Otherwise, take the other branch at the most recent level where a 48881ad6265SDimitry Andric // decision was made. 48981ad6265SDimitry Andric LevelStates[Level] = State::Forced; 49081ad6265SDimitry Andric const Variable Var = LevelVars[Level]; 49181ad6265SDimitry Andric VarAssignments[Var] = VarAssignments[Var] == Assignment::AssignedTrue 49281ad6265SDimitry Andric ? Assignment::AssignedFalse 49381ad6265SDimitry Andric : Assignment::AssignedTrue; 49481ad6265SDimitry Andric 49581ad6265SDimitry Andric updateWatchedLiterals(); 49681ad6265SDimitry Andric } else if (unitPosLit || unitNegLit) { 49781ad6265SDimitry Andric // We found a unit clause! The value of its unassigned variable is 49881ad6265SDimitry Andric // forced. 49981ad6265SDimitry Andric ++Level; 50081ad6265SDimitry Andric 50181ad6265SDimitry Andric LevelVars[Level] = ActiveVar; 50281ad6265SDimitry Andric LevelStates[Level] = State::Forced; 50381ad6265SDimitry Andric VarAssignments[ActiveVar] = 50481ad6265SDimitry Andric unitPosLit ? Assignment::AssignedTrue : Assignment::AssignedFalse; 50581ad6265SDimitry Andric 50681ad6265SDimitry Andric // Remove the variable that was just assigned from the set of active 50781ad6265SDimitry Andric // variables. 50881ad6265SDimitry Andric if (I + 1 < ActiveVars.size()) { 50981ad6265SDimitry Andric // Replace the variable that was just assigned with the last active 51081ad6265SDimitry Andric // variable for efficient removal. 51181ad6265SDimitry Andric ActiveVars[I] = ActiveVars.back(); 51281ad6265SDimitry Andric } else { 51381ad6265SDimitry Andric // This was the last active variable. Repeat the process from the 51481ad6265SDimitry Andric // beginning. 51581ad6265SDimitry Andric I = 0; 51681ad6265SDimitry Andric } 51781ad6265SDimitry Andric ActiveVars.pop_back(); 51881ad6265SDimitry Andric 51981ad6265SDimitry Andric updateWatchedLiterals(); 52081ad6265SDimitry Andric } else if (I + 1 == ActiveVars.size()) { 52181ad6265SDimitry Andric // There are no remaining unit clauses in the formula! Make a decision 52281ad6265SDimitry Andric // for one of the active variables at the current level. 52381ad6265SDimitry Andric ++Level; 52481ad6265SDimitry Andric 52581ad6265SDimitry Andric LevelVars[Level] = ActiveVar; 52681ad6265SDimitry Andric LevelStates[Level] = State::Decision; 52781ad6265SDimitry Andric VarAssignments[ActiveVar] = decideAssignment(ActiveVar); 52881ad6265SDimitry Andric 52981ad6265SDimitry Andric // Remove the variable that was just assigned from the set of active 53081ad6265SDimitry Andric // variables. 53181ad6265SDimitry Andric ActiveVars.pop_back(); 53281ad6265SDimitry Andric 53381ad6265SDimitry Andric updateWatchedLiterals(); 53481ad6265SDimitry Andric 53581ad6265SDimitry Andric // This was the last active variable. Repeat the process from the 53681ad6265SDimitry Andric // beginning. 53781ad6265SDimitry Andric I = 0; 53881ad6265SDimitry Andric } else { 53981ad6265SDimitry Andric ++I; 54081ad6265SDimitry Andric } 54181ad6265SDimitry Andric } 542753f127fSDimitry Andric return Solver::Result::Satisfiable(buildSolution()); 54381ad6265SDimitry Andric } 54481ad6265SDimitry Andric 54581ad6265SDimitry Andric private: 546753f127fSDimitry Andric /// Returns a satisfying truth assignment to the atomic values in the boolean 547753f127fSDimitry Andric /// formula. 548753f127fSDimitry Andric llvm::DenseMap<AtomicBoolValue *, Solver::Result::Assignment> 549753f127fSDimitry Andric buildSolution() { 550753f127fSDimitry Andric llvm::DenseMap<AtomicBoolValue *, Solver::Result::Assignment> Solution; 551753f127fSDimitry Andric for (auto &Atomic : Formula.Atomics) { 552753f127fSDimitry Andric // A variable may have a definite true/false assignment, or it may be 553753f127fSDimitry Andric // unassigned indicating its truth value does not affect the result of 554753f127fSDimitry Andric // the formula. Unassigned variables are assigned to true as a default. 555753f127fSDimitry Andric Solution[Atomic.second] = 556753f127fSDimitry Andric VarAssignments[Atomic.first] == Assignment::AssignedFalse 557753f127fSDimitry Andric ? Solver::Result::Assignment::AssignedFalse 558753f127fSDimitry Andric : Solver::Result::Assignment::AssignedTrue; 559753f127fSDimitry Andric } 560753f127fSDimitry Andric return Solution; 561753f127fSDimitry Andric } 562753f127fSDimitry Andric 563753f127fSDimitry Andric /// Reverses forced moves until the most recent level where a decision was 564753f127fSDimitry Andric /// made on the assignment of a variable. 56581ad6265SDimitry Andric void reverseForcedMoves() { 56681ad6265SDimitry Andric for (; LevelStates[Level] == State::Forced; --Level) { 56781ad6265SDimitry Andric const Variable Var = LevelVars[Level]; 56881ad6265SDimitry Andric 56981ad6265SDimitry Andric VarAssignments[Var] = Assignment::Unassigned; 57081ad6265SDimitry Andric 57181ad6265SDimitry Andric // If the variable that we pass through is watched then we add it to the 57281ad6265SDimitry Andric // active variables. 57381ad6265SDimitry Andric if (isWatched(posLit(Var)) || isWatched(negLit(Var))) 57481ad6265SDimitry Andric ActiveVars.push_back(Var); 57581ad6265SDimitry Andric } 57681ad6265SDimitry Andric } 57781ad6265SDimitry Andric 578753f127fSDimitry Andric /// Updates watched literals that are affected by a variable assignment. 57981ad6265SDimitry Andric void updateWatchedLiterals() { 58081ad6265SDimitry Andric const Variable Var = LevelVars[Level]; 58181ad6265SDimitry Andric 58281ad6265SDimitry Andric // Update the watched literals of clauses that currently watch the literal 58381ad6265SDimitry Andric // that falsifies `Var`. 58481ad6265SDimitry Andric const Literal FalseLit = VarAssignments[Var] == Assignment::AssignedTrue 58581ad6265SDimitry Andric ? negLit(Var) 58681ad6265SDimitry Andric : posLit(Var); 58781ad6265SDimitry Andric ClauseID FalseLitWatcher = Formula.WatchedHead[FalseLit]; 58881ad6265SDimitry Andric Formula.WatchedHead[FalseLit] = NullClause; 58981ad6265SDimitry Andric while (FalseLitWatcher != NullClause) { 59081ad6265SDimitry Andric const ClauseID NextFalseLitWatcher = Formula.NextWatched[FalseLitWatcher]; 59181ad6265SDimitry Andric 59281ad6265SDimitry Andric // Pick the first non-false literal as the new watched literal. 59381ad6265SDimitry Andric const size_t FalseLitWatcherStart = Formula.ClauseStarts[FalseLitWatcher]; 59481ad6265SDimitry Andric size_t NewWatchedLitIdx = FalseLitWatcherStart + 1; 59581ad6265SDimitry Andric while (isCurrentlyFalse(Formula.Clauses[NewWatchedLitIdx])) 59681ad6265SDimitry Andric ++NewWatchedLitIdx; 59781ad6265SDimitry Andric const Literal NewWatchedLit = Formula.Clauses[NewWatchedLitIdx]; 59881ad6265SDimitry Andric const Variable NewWatchedLitVar = var(NewWatchedLit); 59981ad6265SDimitry Andric 60081ad6265SDimitry Andric // Swap the old watched literal for the new one in `FalseLitWatcher` to 60181ad6265SDimitry Andric // maintain the invariant that the watched literal is at the beginning of 60281ad6265SDimitry Andric // the clause. 60381ad6265SDimitry Andric Formula.Clauses[NewWatchedLitIdx] = FalseLit; 60481ad6265SDimitry Andric Formula.Clauses[FalseLitWatcherStart] = NewWatchedLit; 60581ad6265SDimitry Andric 60681ad6265SDimitry Andric // If the new watched literal isn't watched by any other clause and its 60781ad6265SDimitry Andric // variable isn't assigned we need to add it to the active variables. 60881ad6265SDimitry Andric if (!isWatched(NewWatchedLit) && !isWatched(notLit(NewWatchedLit)) && 60981ad6265SDimitry Andric VarAssignments[NewWatchedLitVar] == Assignment::Unassigned) 61081ad6265SDimitry Andric ActiveVars.push_back(NewWatchedLitVar); 61181ad6265SDimitry Andric 61281ad6265SDimitry Andric Formula.NextWatched[FalseLitWatcher] = Formula.WatchedHead[NewWatchedLit]; 61381ad6265SDimitry Andric Formula.WatchedHead[NewWatchedLit] = FalseLitWatcher; 61481ad6265SDimitry Andric 61581ad6265SDimitry Andric // Go to the next clause that watches `FalseLit`. 61681ad6265SDimitry Andric FalseLitWatcher = NextFalseLitWatcher; 61781ad6265SDimitry Andric } 61881ad6265SDimitry Andric } 61981ad6265SDimitry Andric 62081ad6265SDimitry Andric /// Returns true if and only if one of the clauses that watch `Lit` is a unit 62181ad6265SDimitry Andric /// clause. 62281ad6265SDimitry Andric bool watchedByUnitClause(Literal Lit) const { 62381ad6265SDimitry Andric for (ClauseID LitWatcher = Formula.WatchedHead[Lit]; 62481ad6265SDimitry Andric LitWatcher != NullClause; 62581ad6265SDimitry Andric LitWatcher = Formula.NextWatched[LitWatcher]) { 62681ad6265SDimitry Andric llvm::ArrayRef<Literal> Clause = Formula.clauseLiterals(LitWatcher); 62781ad6265SDimitry Andric 62881ad6265SDimitry Andric // Assert the invariant that the watched literal is always the first one 62981ad6265SDimitry Andric // in the clause. 63081ad6265SDimitry Andric // FIXME: Consider replacing this with a test case that fails if the 63181ad6265SDimitry Andric // invariant is broken by `updateWatchedLiterals`. That might not be easy 63281ad6265SDimitry Andric // due to the transformations performed by `buildBooleanFormula`. 63381ad6265SDimitry Andric assert(Clause.front() == Lit); 63481ad6265SDimitry Andric 63581ad6265SDimitry Andric if (isUnit(Clause)) 63681ad6265SDimitry Andric return true; 63781ad6265SDimitry Andric } 63881ad6265SDimitry Andric return false; 63981ad6265SDimitry Andric } 64081ad6265SDimitry Andric 64181ad6265SDimitry Andric /// Returns true if and only if `Clause` is a unit clause. 64281ad6265SDimitry Andric bool isUnit(llvm::ArrayRef<Literal> Clause) const { 64381ad6265SDimitry Andric return llvm::all_of(Clause.drop_front(), 64481ad6265SDimitry Andric [this](Literal L) { return isCurrentlyFalse(L); }); 64581ad6265SDimitry Andric } 64681ad6265SDimitry Andric 64781ad6265SDimitry Andric /// Returns true if and only if `Lit` evaluates to `false` in the current 64881ad6265SDimitry Andric /// partial assignment. 64981ad6265SDimitry Andric bool isCurrentlyFalse(Literal Lit) const { 65081ad6265SDimitry Andric return static_cast<int8_t>(VarAssignments[var(Lit)]) == 65181ad6265SDimitry Andric static_cast<int8_t>(Lit & 1); 65281ad6265SDimitry Andric } 65381ad6265SDimitry Andric 65481ad6265SDimitry Andric /// Returns true if and only if `Lit` is watched by a clause in `Formula`. 65581ad6265SDimitry Andric bool isWatched(Literal Lit) const { 65681ad6265SDimitry Andric return Formula.WatchedHead[Lit] != NullClause; 65781ad6265SDimitry Andric } 65881ad6265SDimitry Andric 65981ad6265SDimitry Andric /// Returns an assignment for an unassigned variable. 66081ad6265SDimitry Andric Assignment decideAssignment(Variable Var) const { 66181ad6265SDimitry Andric return !isWatched(posLit(Var)) || isWatched(negLit(Var)) 66281ad6265SDimitry Andric ? Assignment::AssignedFalse 66381ad6265SDimitry Andric : Assignment::AssignedTrue; 66481ad6265SDimitry Andric } 66581ad6265SDimitry Andric 66681ad6265SDimitry Andric /// Returns a set of all watched literals. 66781ad6265SDimitry Andric llvm::DenseSet<Literal> watchedLiterals() const { 66881ad6265SDimitry Andric llvm::DenseSet<Literal> WatchedLiterals; 66981ad6265SDimitry Andric for (Literal Lit = 2; Lit < Formula.WatchedHead.size(); Lit++) { 67081ad6265SDimitry Andric if (Formula.WatchedHead[Lit] == NullClause) 67181ad6265SDimitry Andric continue; 67281ad6265SDimitry Andric WatchedLiterals.insert(Lit); 67381ad6265SDimitry Andric } 67481ad6265SDimitry Andric return WatchedLiterals; 67581ad6265SDimitry Andric } 67681ad6265SDimitry Andric 67781ad6265SDimitry Andric /// Returns true if and only if all active variables are unassigned. 67881ad6265SDimitry Andric bool activeVarsAreUnassigned() const { 67981ad6265SDimitry Andric return llvm::all_of(ActiveVars, [this](Variable Var) { 68081ad6265SDimitry Andric return VarAssignments[Var] == Assignment::Unassigned; 68181ad6265SDimitry Andric }); 68281ad6265SDimitry Andric } 68381ad6265SDimitry Andric 68481ad6265SDimitry Andric /// Returns true if and only if all active variables form watched literals. 68581ad6265SDimitry Andric bool activeVarsFormWatchedLiterals() const { 68681ad6265SDimitry Andric const llvm::DenseSet<Literal> WatchedLiterals = watchedLiterals(); 68781ad6265SDimitry Andric return llvm::all_of(ActiveVars, [&WatchedLiterals](Variable Var) { 68881ad6265SDimitry Andric return WatchedLiterals.contains(posLit(Var)) || 68981ad6265SDimitry Andric WatchedLiterals.contains(negLit(Var)); 69081ad6265SDimitry Andric }); 69181ad6265SDimitry Andric } 69281ad6265SDimitry Andric 69381ad6265SDimitry Andric /// Returns true if and only if all unassigned variables that are forming 69481ad6265SDimitry Andric /// watched literals are active. 69581ad6265SDimitry Andric bool unassignedVarsFormingWatchedLiteralsAreActive() const { 69681ad6265SDimitry Andric const llvm::DenseSet<Variable> ActiveVarsSet(ActiveVars.begin(), 69781ad6265SDimitry Andric ActiveVars.end()); 69881ad6265SDimitry Andric for (Literal Lit : watchedLiterals()) { 69981ad6265SDimitry Andric const Variable Var = var(Lit); 70081ad6265SDimitry Andric if (VarAssignments[Var] != Assignment::Unassigned) 70181ad6265SDimitry Andric continue; 70281ad6265SDimitry Andric if (ActiveVarsSet.contains(Var)) 70381ad6265SDimitry Andric continue; 70481ad6265SDimitry Andric return false; 70581ad6265SDimitry Andric } 70681ad6265SDimitry Andric return true; 70781ad6265SDimitry Andric } 70881ad6265SDimitry Andric }; 70981ad6265SDimitry Andric 71081ad6265SDimitry Andric Solver::Result WatchedLiteralsSolver::solve(llvm::DenseSet<BoolValue *> Vals) { 711753f127fSDimitry Andric return Vals.empty() ? Solver::Result::Satisfiable({{}}) 71281ad6265SDimitry Andric : WatchedLiteralsSolverImpl(Vals).solve(); 71381ad6265SDimitry Andric } 71481ad6265SDimitry Andric 71581ad6265SDimitry Andric } // namespace dataflow 71681ad6265SDimitry Andric } // namespace clang 717