xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp (revision 972a253a57b6f144b0e4a3e2080a2a0076ec55a0)
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