153dcd9efSStanislav Gatev //===- WatchedLiteralsSolver.cpp --------------------------------*- C++ -*-===//
253dcd9efSStanislav Gatev //
353dcd9efSStanislav Gatev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
453dcd9efSStanislav Gatev // See https://llvm.org/LICENSE.txt for license information.
553dcd9efSStanislav Gatev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
653dcd9efSStanislav Gatev //
753dcd9efSStanislav Gatev //===----------------------------------------------------------------------===//
853dcd9efSStanislav Gatev //
953dcd9efSStanislav Gatev //  This file defines a SAT solver implementation that can be used by dataflow
1053dcd9efSStanislav Gatev //  analyses.
1153dcd9efSStanislav Gatev //
1253dcd9efSStanislav Gatev //===----------------------------------------------------------------------===//
1353dcd9efSStanislav Gatev 
1453dcd9efSStanislav Gatev #include <cassert>
1553dcd9efSStanislav Gatev #include <cstdint>
1653dcd9efSStanislav Gatev #include <iterator>
1753dcd9efSStanislav Gatev #include <queue>
1853dcd9efSStanislav Gatev #include <vector>
1953dcd9efSStanislav Gatev 
2053dcd9efSStanislav Gatev #include "clang/Analysis/FlowSensitive/Solver.h"
2153dcd9efSStanislav Gatev #include "clang/Analysis/FlowSensitive/Value.h"
2253dcd9efSStanislav Gatev #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
2353dcd9efSStanislav Gatev #include "llvm/ADT/DenseMap.h"
2453dcd9efSStanislav Gatev #include "llvm/ADT/DenseSet.h"
2553dcd9efSStanislav Gatev #include "llvm/ADT/STLExtras.h"
2653dcd9efSStanislav Gatev 
2753dcd9efSStanislav Gatev namespace clang {
2853dcd9efSStanislav Gatev namespace dataflow {
2953dcd9efSStanislav Gatev 
3053dcd9efSStanislav Gatev // `WatchedLiteralsSolver` is an implementation of Algorithm D from Knuth's
3153dcd9efSStanislav Gatev // The Art of Computer Programming Volume 4: Satisfiability, Fascicle 6. It is
3253dcd9efSStanislav Gatev // based on the backtracking DPLL algorithm [1], keeps references to a single
3353dcd9efSStanislav Gatev // "watched" literal per clause, and uses a set of "active" variables to perform
3453dcd9efSStanislav Gatev // unit propagation.
3553dcd9efSStanislav Gatev //
3653dcd9efSStanislav Gatev // The solver expects that its input is a boolean formula in conjunctive normal
3753dcd9efSStanislav Gatev // form that consists of clauses of at least one literal. A literal is either a
3853dcd9efSStanislav Gatev // boolean variable or its negation. Below we define types, data structures, and
3953dcd9efSStanislav Gatev // utilities that are used to represent boolean formulas in conjunctive normal
4053dcd9efSStanislav Gatev // form.
4153dcd9efSStanislav Gatev //
4253dcd9efSStanislav Gatev // [1] https://en.wikipedia.org/wiki/DPLL_algorithm
4353dcd9efSStanislav Gatev 
4453dcd9efSStanislav Gatev /// Boolean variables are represented as positive integers.
4553dcd9efSStanislav Gatev using Variable = uint32_t;
4653dcd9efSStanislav Gatev 
4753dcd9efSStanislav Gatev /// A null boolean variable is used as a placeholder in various data structures
4853dcd9efSStanislav Gatev /// and algorithms.
4953dcd9efSStanislav Gatev static constexpr Variable NullVar = 0;
5053dcd9efSStanislav Gatev 
5153dcd9efSStanislav Gatev /// Literals are represented as positive integers. Specifically, for a boolean
5253dcd9efSStanislav Gatev /// variable `V` that is represented as the positive integer `I`, the positive
5353dcd9efSStanislav Gatev /// literal `V` is represented as the integer `2*I` and the negative literal
5453dcd9efSStanislav Gatev /// `!V` is represented as the integer `2*I+1`.
5553dcd9efSStanislav Gatev using Literal = uint32_t;
5653dcd9efSStanislav Gatev 
5753dcd9efSStanislav Gatev /// A null literal is used as a placeholder in various data structures and
5853dcd9efSStanislav Gatev /// algorithms.
5953dcd9efSStanislav Gatev static constexpr Literal NullLit = 0;
6053dcd9efSStanislav Gatev 
6153dcd9efSStanislav Gatev /// Returns the positive literal `V`.
posLit(Variable V)6253dcd9efSStanislav Gatev static constexpr Literal posLit(Variable V) { return 2 * V; }
6353dcd9efSStanislav Gatev 
6453dcd9efSStanislav Gatev /// Returns the negative literal `!V`.
negLit(Variable V)6553dcd9efSStanislav Gatev static constexpr Literal negLit(Variable V) { return 2 * V + 1; }
6653dcd9efSStanislav Gatev 
6753dcd9efSStanislav Gatev /// Returns the negated literal `!L`.
notLit(Literal L)6853dcd9efSStanislav Gatev static constexpr Literal notLit(Literal L) { return L ^ 1; }
6953dcd9efSStanislav Gatev 
7053dcd9efSStanislav Gatev /// Returns the variable of `L`.
var(Literal L)7153dcd9efSStanislav Gatev static constexpr Variable var(Literal L) { return L >> 1; }
7253dcd9efSStanislav Gatev 
7353dcd9efSStanislav Gatev /// Clause identifiers are represented as positive integers.
7453dcd9efSStanislav Gatev using ClauseID = uint32_t;
7553dcd9efSStanislav Gatev 
7653dcd9efSStanislav Gatev /// A null clause identifier is used as a placeholder in various data structures
7753dcd9efSStanislav Gatev /// and algorithms.
7853dcd9efSStanislav Gatev static constexpr ClauseID NullClause = 0;
7953dcd9efSStanislav Gatev 
8053dcd9efSStanislav Gatev /// A boolean formula in conjunctive normal form.
8153dcd9efSStanislav Gatev struct BooleanFormula {
8253dcd9efSStanislav Gatev   /// `LargestVar` is equal to the largest positive integer that represents a
8353dcd9efSStanislav Gatev   /// variable in the formula.
8453dcd9efSStanislav Gatev   const Variable LargestVar;
8553dcd9efSStanislav Gatev 
8653dcd9efSStanislav Gatev   /// Literals of all clauses in the formula.
8753dcd9efSStanislav Gatev   ///
8853dcd9efSStanislav Gatev   /// The element at index 0 stands for the literal in the null clause. It is
8953dcd9efSStanislav Gatev   /// set to 0 and isn't used. Literals of clauses in the formula start from the
9053dcd9efSStanislav Gatev   /// element at index 1.
9153dcd9efSStanislav Gatev   ///
9253dcd9efSStanislav Gatev   /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of
9353dcd9efSStanislav Gatev   /// `Clauses` will be `[0, L1, L2, L2, L3, L4]`.
9453dcd9efSStanislav Gatev   std::vector<Literal> Clauses;
9553dcd9efSStanislav Gatev 
9653dcd9efSStanislav Gatev   /// Start indices of clauses of the formula in `Clauses`.
9753dcd9efSStanislav Gatev   ///
9853dcd9efSStanislav Gatev   /// The element at index 0 stands for the start index of the null clause. It
9953dcd9efSStanislav Gatev   /// is set to 0 and isn't used. Start indices of clauses in the formula start
10053dcd9efSStanislav Gatev   /// from the element at index 1.
10153dcd9efSStanislav Gatev   ///
10253dcd9efSStanislav Gatev   /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of
10353dcd9efSStanislav Gatev   /// `ClauseStarts` will be `[0, 1, 3]`. Note that the literals of the first
10453dcd9efSStanislav Gatev   /// clause always start at index 1. The start index for the literals of the
10553dcd9efSStanislav Gatev   /// second clause depends on the size of the first clause and so on.
10653dcd9efSStanislav Gatev   std::vector<size_t> ClauseStarts;
10753dcd9efSStanislav Gatev 
10853dcd9efSStanislav Gatev   /// Maps literals (indices of the vector) to clause identifiers (elements of
10953dcd9efSStanislav Gatev   /// the vector) that watch the respective literals.
11053dcd9efSStanislav Gatev   ///
11153dcd9efSStanislav Gatev   /// For a given clause, its watched literal is always its first literal in
11253dcd9efSStanislav Gatev   /// `Clauses`. This invariant is maintained when watched literals change.
11353dcd9efSStanislav Gatev   std::vector<ClauseID> WatchedHead;
11453dcd9efSStanislav Gatev 
11553dcd9efSStanislav Gatev   /// Maps clause identifiers (elements of the vector) to identifiers of other
11653dcd9efSStanislav Gatev   /// clauses that watch the same literals, forming a set of linked lists.
11753dcd9efSStanislav Gatev   ///
11853dcd9efSStanislav Gatev   /// The element at index 0 stands for the identifier of the clause that
11953dcd9efSStanislav Gatev   /// follows the null clause. It is set to 0 and isn't used. Identifiers of
12053dcd9efSStanislav Gatev   /// clauses in the formula start from the element at index 1.
12153dcd9efSStanislav Gatev   std::vector<ClauseID> NextWatched;
12253dcd9efSStanislav Gatev 
12381e6400dSWei Yi Tee   /// Stores the variable identifier and value location for atomic booleans in
12481e6400dSWei Yi Tee   /// the formula.
12581e6400dSWei Yi Tee   llvm::DenseMap<Variable, AtomicBoolValue *> Atomics;
12681e6400dSWei Yi Tee 
BooleanFormulaclang::dataflow::BooleanFormula12781e6400dSWei Yi Tee   explicit BooleanFormula(Variable LargestVar,
12881e6400dSWei Yi Tee                           llvm::DenseMap<Variable, AtomicBoolValue *> Atomics)
12981e6400dSWei Yi Tee       : LargestVar(LargestVar), Atomics(std::move(Atomics)) {
13053dcd9efSStanislav Gatev     Clauses.push_back(0);
13153dcd9efSStanislav Gatev     ClauseStarts.push_back(0);
13253dcd9efSStanislav Gatev     NextWatched.push_back(0);
13353dcd9efSStanislav Gatev     const size_t NumLiterals = 2 * LargestVar + 1;
13453dcd9efSStanislav Gatev     WatchedHead.resize(NumLiterals + 1, 0);
13553dcd9efSStanislav Gatev   }
13653dcd9efSStanislav Gatev 
13753dcd9efSStanislav Gatev   /// Adds the `L1 v L2 v L3` clause to the formula. If `L2` or `L3` are
13853dcd9efSStanislav Gatev   /// `NullLit` they are respectively omitted from the clause.
13953dcd9efSStanislav Gatev   ///
14053dcd9efSStanislav Gatev   /// Requirements:
14153dcd9efSStanislav Gatev   ///
14253dcd9efSStanislav Gatev   ///  `L1` must not be `NullLit`.
14353dcd9efSStanislav Gatev   ///
14453dcd9efSStanislav Gatev   ///  All literals in the input that are not `NullLit` must be distinct.
addClauseclang::dataflow::BooleanFormula14553dcd9efSStanislav Gatev   void addClause(Literal L1, Literal L2 = NullLit, Literal L3 = NullLit) {
14653dcd9efSStanislav Gatev     // The literals are guaranteed to be distinct from properties of BoolValue
14753dcd9efSStanislav Gatev     // and the construction in `buildBooleanFormula`.
14853dcd9efSStanislav Gatev     assert(L1 != NullLit && L1 != L2 && L1 != L3 &&
14953dcd9efSStanislav Gatev            (L2 != L3 || L2 == NullLit));
15053dcd9efSStanislav Gatev 
15153dcd9efSStanislav Gatev     const ClauseID C = ClauseStarts.size();
15253dcd9efSStanislav Gatev     const size_t S = Clauses.size();
15353dcd9efSStanislav Gatev     ClauseStarts.push_back(S);
15453dcd9efSStanislav Gatev 
15553dcd9efSStanislav Gatev     Clauses.push_back(L1);
15653dcd9efSStanislav Gatev     if (L2 != NullLit)
15753dcd9efSStanislav Gatev       Clauses.push_back(L2);
15853dcd9efSStanislav Gatev     if (L3 != NullLit)
15953dcd9efSStanislav Gatev       Clauses.push_back(L3);
16053dcd9efSStanislav Gatev 
16153dcd9efSStanislav Gatev     // Designate the first literal as the "watched" literal of the clause.
16253dcd9efSStanislav Gatev     NextWatched.push_back(WatchedHead[L1]);
16353dcd9efSStanislav Gatev     WatchedHead[L1] = C;
16453dcd9efSStanislav Gatev   }
16553dcd9efSStanislav Gatev 
16653dcd9efSStanislav Gatev   /// Returns the number of literals in clause `C`.
clauseSizeclang::dataflow::BooleanFormula16753dcd9efSStanislav Gatev   size_t clauseSize(ClauseID C) const {
16853dcd9efSStanislav Gatev     return C == ClauseStarts.size() - 1 ? Clauses.size() - ClauseStarts[C]
16953dcd9efSStanislav Gatev                                         : ClauseStarts[C + 1] - ClauseStarts[C];
17053dcd9efSStanislav Gatev   }
17153dcd9efSStanislav Gatev 
17253dcd9efSStanislav Gatev   /// Returns the literals of clause `C`.
clauseLiteralsclang::dataflow::BooleanFormula17353dcd9efSStanislav Gatev   llvm::ArrayRef<Literal> clauseLiterals(ClauseID C) const {
17453dcd9efSStanislav Gatev     return llvm::ArrayRef<Literal>(&Clauses[ClauseStarts[C]], clauseSize(C));
17553dcd9efSStanislav Gatev   }
17653dcd9efSStanislav Gatev };
17753dcd9efSStanislav Gatev 
17853dcd9efSStanislav Gatev /// Converts the conjunction of `Vals` into a formula in conjunctive normal
17953dcd9efSStanislav Gatev /// form where each clause has at least one and at most three literals.
buildBooleanFormula(const llvm::DenseSet<BoolValue * > & Vals)18053dcd9efSStanislav Gatev BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
18153dcd9efSStanislav Gatev   // The general strategy of the algorithm implemented below is to map each
18253dcd9efSStanislav Gatev   // of the sub-values in `Vals` to a unique variable and use these variables in
18353dcd9efSStanislav Gatev   // the resulting CNF expression to avoid exponential blow up. The number of
18453dcd9efSStanislav Gatev   // literals in the resulting formula is guaranteed to be linear in the number
18553dcd9efSStanislav Gatev   // of sub-values in `Vals`.
18653dcd9efSStanislav Gatev 
18753dcd9efSStanislav Gatev   // Map each sub-value in `Vals` to a unique variable.
18853dcd9efSStanislav Gatev   llvm::DenseMap<BoolValue *, Variable> SubValsToVar;
18981e6400dSWei Yi Tee   // Store variable identifiers and value location of atomic booleans.
19081e6400dSWei Yi Tee   llvm::DenseMap<Variable, AtomicBoolValue *> Atomics;
19153dcd9efSStanislav Gatev   Variable NextVar = 1;
19253dcd9efSStanislav Gatev   {
19353dcd9efSStanislav Gatev     std::queue<BoolValue *> UnprocessedSubVals;
19453dcd9efSStanislav Gatev     for (BoolValue *Val : Vals)
19553dcd9efSStanislav Gatev       UnprocessedSubVals.push(Val);
19653dcd9efSStanislav Gatev     while (!UnprocessedSubVals.empty()) {
19781e6400dSWei Yi Tee       Variable Var = NextVar;
19853dcd9efSStanislav Gatev       BoolValue *Val = UnprocessedSubVals.front();
19953dcd9efSStanislav Gatev       UnprocessedSubVals.pop();
20053dcd9efSStanislav Gatev 
20181e6400dSWei Yi Tee       if (!SubValsToVar.try_emplace(Val, Var).second)
20253dcd9efSStanislav Gatev         continue;
20353dcd9efSStanislav Gatev       ++NextVar;
20453dcd9efSStanislav Gatev 
20553dcd9efSStanislav Gatev       // Visit the sub-values of `Val`.
20681e6400dSWei Yi Tee       switch (Val->getKind()) {
20781e6400dSWei Yi Tee       case Value::Kind::Conjunction: {
20881e6400dSWei Yi Tee         auto *C = cast<ConjunctionValue>(Val);
20953dcd9efSStanislav Gatev         UnprocessedSubVals.push(&C->getLeftSubValue());
21053dcd9efSStanislav Gatev         UnprocessedSubVals.push(&C->getRightSubValue());
21181e6400dSWei Yi Tee         break;
21281e6400dSWei Yi Tee       }
21381e6400dSWei Yi Tee       case Value::Kind::Disjunction: {
21481e6400dSWei Yi Tee         auto *D = cast<DisjunctionValue>(Val);
21553dcd9efSStanislav Gatev         UnprocessedSubVals.push(&D->getLeftSubValue());
21653dcd9efSStanislav Gatev         UnprocessedSubVals.push(&D->getRightSubValue());
21781e6400dSWei Yi Tee         break;
21881e6400dSWei Yi Tee       }
21981e6400dSWei Yi Tee       case Value::Kind::Negation: {
22081e6400dSWei Yi Tee         auto *N = cast<NegationValue>(Val);
22153dcd9efSStanislav Gatev         UnprocessedSubVals.push(&N->getSubVal());
22281e6400dSWei Yi Tee         break;
22381e6400dSWei Yi Tee       }
224*b5e3dac3SDmitri Gribenko       case Value::Kind::Implication: {
225*b5e3dac3SDmitri Gribenko         auto *I = cast<ImplicationValue>(Val);
226*b5e3dac3SDmitri Gribenko         UnprocessedSubVals.push(&I->getLeftSubValue());
227*b5e3dac3SDmitri Gribenko         UnprocessedSubVals.push(&I->getRightSubValue());
228*b5e3dac3SDmitri Gribenko         break;
229*b5e3dac3SDmitri Gribenko       }
230*b5e3dac3SDmitri Gribenko       case Value::Kind::Biconditional: {
231*b5e3dac3SDmitri Gribenko         auto *B = cast<BiconditionalValue>(Val);
232*b5e3dac3SDmitri Gribenko         UnprocessedSubVals.push(&B->getLeftSubValue());
233*b5e3dac3SDmitri Gribenko         UnprocessedSubVals.push(&B->getRightSubValue());
234*b5e3dac3SDmitri Gribenko         break;
235*b5e3dac3SDmitri Gribenko       }
23681e6400dSWei Yi Tee       case Value::Kind::AtomicBool: {
23781e6400dSWei Yi Tee         Atomics[Var] = cast<AtomicBoolValue>(Val);
23881e6400dSWei Yi Tee         break;
23981e6400dSWei Yi Tee       }
24081e6400dSWei Yi Tee       default:
24181e6400dSWei Yi Tee         llvm_unreachable("buildBooleanFormula: unhandled value kind");
24253dcd9efSStanislav Gatev       }
24353dcd9efSStanislav Gatev     }
24453dcd9efSStanislav Gatev   }
24553dcd9efSStanislav Gatev 
24653dcd9efSStanislav Gatev   auto GetVar = [&SubValsToVar](const BoolValue *Val) {
24753dcd9efSStanislav Gatev     auto ValIt = SubValsToVar.find(Val);
24853dcd9efSStanislav Gatev     assert(ValIt != SubValsToVar.end());
24953dcd9efSStanislav Gatev     return ValIt->second;
25053dcd9efSStanislav Gatev   };
25153dcd9efSStanislav Gatev 
25281e6400dSWei Yi Tee   BooleanFormula Formula(NextVar - 1, std::move(Atomics));
25353dcd9efSStanislav Gatev   std::vector<bool> ProcessedSubVals(NextVar, false);
25453dcd9efSStanislav Gatev 
25553dcd9efSStanislav Gatev   // Add a conjunct for each variable that represents a top-level conjunction
25653dcd9efSStanislav Gatev   // value in `Vals`.
25753dcd9efSStanislav Gatev   for (BoolValue *Val : Vals)
25853dcd9efSStanislav Gatev     Formula.addClause(posLit(GetVar(Val)));
25953dcd9efSStanislav Gatev 
26053dcd9efSStanislav Gatev   // Add conjuncts that represent the mapping between newly-created variables
26153dcd9efSStanislav Gatev   // and their corresponding sub-values.
26253dcd9efSStanislav Gatev   std::queue<BoolValue *> UnprocessedSubVals;
26353dcd9efSStanislav Gatev   for (BoolValue *Val : Vals)
26453dcd9efSStanislav Gatev     UnprocessedSubVals.push(Val);
26553dcd9efSStanislav Gatev   while (!UnprocessedSubVals.empty()) {
26653dcd9efSStanislav Gatev     const BoolValue *Val = UnprocessedSubVals.front();
26753dcd9efSStanislav Gatev     UnprocessedSubVals.pop();
26853dcd9efSStanislav Gatev     const Variable Var = GetVar(Val);
26953dcd9efSStanislav Gatev 
27053dcd9efSStanislav Gatev     if (ProcessedSubVals[Var])
27153dcd9efSStanislav Gatev       continue;
27253dcd9efSStanislav Gatev     ProcessedSubVals[Var] = true;
27353dcd9efSStanislav Gatev 
27453dcd9efSStanislav Gatev     if (auto *C = dyn_cast<ConjunctionValue>(Val)) {
27553dcd9efSStanislav Gatev       const Variable LeftSubVar = GetVar(&C->getLeftSubValue());
27653dcd9efSStanislav Gatev       const Variable RightSubVar = GetVar(&C->getRightSubValue());
27753dcd9efSStanislav Gatev 
2783281138aSDmitri Gribenko       if (LeftSubVar == RightSubVar) {
2793281138aSDmitri Gribenko         // `X <=> (A ^ A)` is equivalent to `(!X v A) ^ (X v !A)` which is
2803281138aSDmitri Gribenko         // already in conjunctive normal form. Below we add each of the
2813281138aSDmitri Gribenko         // conjuncts of the latter expression to the result.
2823281138aSDmitri Gribenko         Formula.addClause(negLit(Var), posLit(LeftSubVar));
2833281138aSDmitri Gribenko         Formula.addClause(posLit(Var), negLit(LeftSubVar));
2843281138aSDmitri Gribenko 
2853281138aSDmitri Gribenko         // Visit a sub-value of `Val` (pick any, they are identical).
2863281138aSDmitri Gribenko         UnprocessedSubVals.push(&C->getLeftSubValue());
2873281138aSDmitri Gribenko       } else {
28853dcd9efSStanislav Gatev         // `X <=> (A ^ B)` is equivalent to `(!X v A) ^ (!X v B) ^ (X v !A v !B)`
28953dcd9efSStanislav Gatev         // which is already in conjunctive normal form. Below we add each of the
29053dcd9efSStanislav Gatev         // conjuncts of the latter expression to the result.
29153dcd9efSStanislav Gatev         Formula.addClause(negLit(Var), posLit(LeftSubVar));
29253dcd9efSStanislav Gatev         Formula.addClause(negLit(Var), posLit(RightSubVar));
29353dcd9efSStanislav Gatev         Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
29453dcd9efSStanislav Gatev 
29553dcd9efSStanislav Gatev         // Visit the sub-values of `Val`.
29653dcd9efSStanislav Gatev         UnprocessedSubVals.push(&C->getLeftSubValue());
29753dcd9efSStanislav Gatev         UnprocessedSubVals.push(&C->getRightSubValue());
2983281138aSDmitri Gribenko       }
29953dcd9efSStanislav Gatev     } else if (auto *D = dyn_cast<DisjunctionValue>(Val)) {
30053dcd9efSStanislav Gatev       const Variable LeftSubVar = GetVar(&D->getLeftSubValue());
30153dcd9efSStanislav Gatev       const Variable RightSubVar = GetVar(&D->getRightSubValue());
30253dcd9efSStanislav Gatev 
3033281138aSDmitri Gribenko       if (LeftSubVar == RightSubVar) {
3043281138aSDmitri Gribenko         // `X <=> (A v A)` is equivalent to `(!X v A) ^ (X v !A)` which is
3053281138aSDmitri Gribenko         // already in conjunctive normal form. Below we add each of the
3063281138aSDmitri Gribenko         // conjuncts of the latter expression to the result.
3073281138aSDmitri Gribenko         Formula.addClause(negLit(Var), posLit(LeftSubVar));
3083281138aSDmitri Gribenko         Formula.addClause(posLit(Var), negLit(LeftSubVar));
3093281138aSDmitri Gribenko 
3103281138aSDmitri Gribenko         // Visit a sub-value of `Val` (pick any, they are identical).
3113281138aSDmitri Gribenko         UnprocessedSubVals.push(&D->getLeftSubValue());
3123281138aSDmitri Gribenko       } else {
31353dcd9efSStanislav Gatev         // `X <=> (A v B)` is equivalent to `(!X v A v B) ^ (X v !A) ^ (X v !B)`
31453dcd9efSStanislav Gatev         // which is already in conjunctive normal form. Below we add each of the
31553dcd9efSStanislav Gatev         // conjuncts of the latter expression to the result.
31653dcd9efSStanislav Gatev         Formula.addClause(negLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
31753dcd9efSStanislav Gatev         Formula.addClause(posLit(Var), negLit(LeftSubVar));
31853dcd9efSStanislav Gatev         Formula.addClause(posLit(Var), negLit(RightSubVar));
31953dcd9efSStanislav Gatev 
32053dcd9efSStanislav Gatev         // Visit the sub-values of `Val`.
32153dcd9efSStanislav Gatev         UnprocessedSubVals.push(&D->getLeftSubValue());
32253dcd9efSStanislav Gatev         UnprocessedSubVals.push(&D->getRightSubValue());
3233281138aSDmitri Gribenko       }
32453dcd9efSStanislav Gatev     } else if (auto *N = dyn_cast<NegationValue>(Val)) {
32553dcd9efSStanislav Gatev       const Variable SubVar = GetVar(&N->getSubVal());
32653dcd9efSStanislav Gatev 
32753dcd9efSStanislav Gatev       // `X <=> !Y` is equivalent to `(!X v !Y) ^ (X v Y)` which is already in
32853dcd9efSStanislav Gatev       // conjunctive normal form. Below we add each of the conjuncts of the
32953dcd9efSStanislav Gatev       // latter expression to the result.
33053dcd9efSStanislav Gatev       Formula.addClause(negLit(Var), negLit(SubVar));
33153dcd9efSStanislav Gatev       Formula.addClause(posLit(Var), posLit(SubVar));
33253dcd9efSStanislav Gatev 
33353dcd9efSStanislav Gatev       // Visit the sub-values of `Val`.
33453dcd9efSStanislav Gatev       UnprocessedSubVals.push(&N->getSubVal());
335*b5e3dac3SDmitri Gribenko     } else if (auto *I = dyn_cast<ImplicationValue>(Val)) {
336*b5e3dac3SDmitri Gribenko       const Variable LeftSubVar = GetVar(&I->getLeftSubValue());
337*b5e3dac3SDmitri Gribenko       const Variable RightSubVar = GetVar(&I->getRightSubValue());
338*b5e3dac3SDmitri Gribenko 
339*b5e3dac3SDmitri Gribenko       // `X <=> (A => B)` is equivalent to
340*b5e3dac3SDmitri Gribenko       // `(X v A) ^ (X v !B) ^ (!X v !A v B)` which is already in
341*b5e3dac3SDmitri Gribenko       // conjunctive normal form. Below we add each of the conjuncts of the
342*b5e3dac3SDmitri Gribenko       // latter expression to the result.
343*b5e3dac3SDmitri Gribenko       Formula.addClause(posLit(Var), posLit(LeftSubVar));
344*b5e3dac3SDmitri Gribenko       Formula.addClause(posLit(Var), negLit(RightSubVar));
345*b5e3dac3SDmitri Gribenko       Formula.addClause(negLit(Var), negLit(LeftSubVar), posLit(RightSubVar));
346*b5e3dac3SDmitri Gribenko 
347*b5e3dac3SDmitri Gribenko       // Visit the sub-values of `Val`.
348*b5e3dac3SDmitri Gribenko       UnprocessedSubVals.push(&I->getLeftSubValue());
349*b5e3dac3SDmitri Gribenko       UnprocessedSubVals.push(&I->getRightSubValue());
350*b5e3dac3SDmitri Gribenko     } else if (auto *B = dyn_cast<BiconditionalValue>(Val)) {
351*b5e3dac3SDmitri Gribenko       const Variable LeftSubVar = GetVar(&B->getLeftSubValue());
352*b5e3dac3SDmitri Gribenko       const Variable RightSubVar = GetVar(&B->getRightSubValue());
353*b5e3dac3SDmitri Gribenko 
354*b5e3dac3SDmitri Gribenko       if (LeftSubVar == RightSubVar) {
355*b5e3dac3SDmitri Gribenko         // `X <=> (A <=> A)` is equvalent to `X` which is already in
356*b5e3dac3SDmitri Gribenko         // conjunctive normal form. Below we add each of the conjuncts of the
357*b5e3dac3SDmitri Gribenko         // latter expression to the result.
358*b5e3dac3SDmitri Gribenko         Formula.addClause(posLit(Var));
359*b5e3dac3SDmitri Gribenko 
360*b5e3dac3SDmitri Gribenko         // No need to visit the sub-values of `Val`.
361*b5e3dac3SDmitri Gribenko       } else {
362*b5e3dac3SDmitri Gribenko         // `X <=> (A <=> B)` is equivalent to
363*b5e3dac3SDmitri Gribenko         // `(X v A v B) ^ (X v !A v !B) ^ (!X v A v !B) ^ (!X v !A v B)` which is
364*b5e3dac3SDmitri Gribenko         // already in conjunctive normal form. Below we add each of the conjuncts
365*b5e3dac3SDmitri Gribenko         // of the latter expression to the result.
366*b5e3dac3SDmitri Gribenko         Formula.addClause(posLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
367*b5e3dac3SDmitri Gribenko         Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
368*b5e3dac3SDmitri Gribenko         Formula.addClause(negLit(Var), posLit(LeftSubVar), negLit(RightSubVar));
369*b5e3dac3SDmitri Gribenko         Formula.addClause(negLit(Var), negLit(LeftSubVar), posLit(RightSubVar));
370*b5e3dac3SDmitri Gribenko 
371*b5e3dac3SDmitri Gribenko         // Visit the sub-values of `Val`.
372*b5e3dac3SDmitri Gribenko         UnprocessedSubVals.push(&B->getLeftSubValue());
373*b5e3dac3SDmitri Gribenko         UnprocessedSubVals.push(&B->getRightSubValue());
374*b5e3dac3SDmitri Gribenko       }
37553dcd9efSStanislav Gatev     }
37653dcd9efSStanislav Gatev   }
37753dcd9efSStanislav Gatev 
37853dcd9efSStanislav Gatev   return Formula;
37953dcd9efSStanislav Gatev }
38053dcd9efSStanislav Gatev 
38153dcd9efSStanislav Gatev class WatchedLiteralsSolverImpl {
38253dcd9efSStanislav Gatev   /// A boolean formula in conjunctive normal form that the solver will attempt
38353dcd9efSStanislav Gatev   /// to prove satisfiable. The formula will be modified in the process.
38453dcd9efSStanislav Gatev   BooleanFormula Formula;
38553dcd9efSStanislav Gatev 
38653dcd9efSStanislav Gatev   /// The search for a satisfying assignment of the variables in `Formula` will
38753dcd9efSStanislav Gatev   /// proceed in levels, starting from 1 and going up to `Formula.LargestVar`
38853dcd9efSStanislav Gatev   /// (inclusive). The current level is stored in `Level`. At each level the
38953dcd9efSStanislav Gatev   /// solver will assign a value to an unassigned variable. If this leads to a
39053dcd9efSStanislav Gatev   /// consistent partial assignment, `Level` will be incremented. Otherwise, if
39153dcd9efSStanislav Gatev   /// it results in a conflict, the solver will backtrack by decrementing
39253dcd9efSStanislav Gatev   /// `Level` until it reaches the most recent level where a decision was made.
39353dcd9efSStanislav Gatev   size_t Level = 0;
39453dcd9efSStanislav Gatev 
39553dcd9efSStanislav Gatev   /// Maps levels (indices of the vector) to variables (elements of the vector)
39653dcd9efSStanislav Gatev   /// that are assigned values at the respective levels.
39753dcd9efSStanislav Gatev   ///
39853dcd9efSStanislav Gatev   /// The element at index 0 isn't used. Variables start from the element at
39953dcd9efSStanislav Gatev   /// index 1.
40053dcd9efSStanislav Gatev   std::vector<Variable> LevelVars;
40153dcd9efSStanislav Gatev 
40253dcd9efSStanislav Gatev   /// State of the solver at a particular level.
40353dcd9efSStanislav Gatev   enum class State : uint8_t {
40453dcd9efSStanislav Gatev     /// Indicates that the solver made a decision.
40553dcd9efSStanislav Gatev     Decision = 0,
40653dcd9efSStanislav Gatev 
40753dcd9efSStanislav Gatev     /// Indicates that the solver made a forced move.
40853dcd9efSStanislav Gatev     Forced = 1,
40953dcd9efSStanislav Gatev   };
41053dcd9efSStanislav Gatev 
41153dcd9efSStanislav Gatev   /// State of the solver at a particular level. It keeps track of previous
41253dcd9efSStanislav Gatev   /// decisions that the solver can refer to when backtracking.
41353dcd9efSStanislav Gatev   ///
41453dcd9efSStanislav Gatev   /// The element at index 0 isn't used. States start from the element at index
41553dcd9efSStanislav Gatev   /// 1.
41653dcd9efSStanislav Gatev   std::vector<State> LevelStates;
41753dcd9efSStanislav Gatev 
41853dcd9efSStanislav Gatev   enum class Assignment : int8_t {
41953dcd9efSStanislav Gatev     Unassigned = -1,
42053dcd9efSStanislav Gatev     AssignedFalse = 0,
42153dcd9efSStanislav Gatev     AssignedTrue = 1
42253dcd9efSStanislav Gatev   };
42353dcd9efSStanislav Gatev 
42453dcd9efSStanislav Gatev   /// Maps variables (indices of the vector) to their assignments (elements of
42553dcd9efSStanislav Gatev   /// the vector).
42653dcd9efSStanislav Gatev   ///
42753dcd9efSStanislav Gatev   /// The element at index 0 isn't used. Variable assignments start from the
42853dcd9efSStanislav Gatev   /// element at index 1.
42953dcd9efSStanislav Gatev   std::vector<Assignment> VarAssignments;
43053dcd9efSStanislav Gatev 
43153dcd9efSStanislav Gatev   /// A set of unassigned variables that appear in watched literals in
43253dcd9efSStanislav Gatev   /// `Formula`. The vector is guaranteed to contain unique elements.
43353dcd9efSStanislav Gatev   std::vector<Variable> ActiveVars;
43453dcd9efSStanislav Gatev 
43553dcd9efSStanislav Gatev public:
WatchedLiteralsSolverImpl(const llvm::DenseSet<BoolValue * > & Vals)43653dcd9efSStanislav Gatev   explicit WatchedLiteralsSolverImpl(const llvm::DenseSet<BoolValue *> &Vals)
43753dcd9efSStanislav Gatev       : Formula(buildBooleanFormula(Vals)), LevelVars(Formula.LargestVar + 1),
43853dcd9efSStanislav Gatev         LevelStates(Formula.LargestVar + 1) {
43953dcd9efSStanislav Gatev     assert(!Vals.empty());
44053dcd9efSStanislav Gatev 
44153dcd9efSStanislav Gatev     // Initialize the state at the root level to a decision so that in
44253dcd9efSStanislav Gatev     // `reverseForcedMoves` we don't have to check that `Level >= 0` on each
44353dcd9efSStanislav Gatev     // iteration.
44453dcd9efSStanislav Gatev     LevelStates[0] = State::Decision;
44553dcd9efSStanislav Gatev 
44653dcd9efSStanislav Gatev     // Initialize all variables as unassigned.
44753dcd9efSStanislav Gatev     VarAssignments.resize(Formula.LargestVar + 1, Assignment::Unassigned);
44853dcd9efSStanislav Gatev 
44953dcd9efSStanislav Gatev     // Initialize the active variables.
45053dcd9efSStanislav Gatev     for (Variable Var = Formula.LargestVar; Var != NullVar; --Var) {
45153dcd9efSStanislav Gatev       if (isWatched(posLit(Var)) || isWatched(negLit(Var)))
45253dcd9efSStanislav Gatev         ActiveVars.push_back(Var);
45353dcd9efSStanislav Gatev     }
45453dcd9efSStanislav Gatev   }
45553dcd9efSStanislav Gatev 
solve()45653dcd9efSStanislav Gatev   Solver::Result solve() && {
45753dcd9efSStanislav Gatev     size_t I = 0;
45853dcd9efSStanislav Gatev     while (I < ActiveVars.size()) {
45953dcd9efSStanislav Gatev       // Assert that the following invariants hold:
46053dcd9efSStanislav Gatev       // 1. All active variables are unassigned.
46153dcd9efSStanislav Gatev       // 2. All active variables form watched literals.
46253dcd9efSStanislav Gatev       // 3. Unassigned variables that form watched literals are active.
46353dcd9efSStanislav Gatev       // FIXME: Consider replacing these with test cases that fail if the any
46453dcd9efSStanislav Gatev       // of the invariants is broken. That might not be easy due to the
46553dcd9efSStanislav Gatev       // transformations performed by `buildBooleanFormula`.
46653dcd9efSStanislav Gatev       assert(activeVarsAreUnassigned());
46753dcd9efSStanislav Gatev       assert(activeVarsFormWatchedLiterals());
46853dcd9efSStanislav Gatev       assert(unassignedVarsFormingWatchedLiteralsAreActive());
46953dcd9efSStanislav Gatev 
47053dcd9efSStanislav Gatev       const Variable ActiveVar = ActiveVars[I];
47153dcd9efSStanislav Gatev 
47253dcd9efSStanislav Gatev       // Look for unit clauses that contain the active variable.
47353dcd9efSStanislav Gatev       const bool unitPosLit = watchedByUnitClause(posLit(ActiveVar));
47453dcd9efSStanislav Gatev       const bool unitNegLit = watchedByUnitClause(negLit(ActiveVar));
47553dcd9efSStanislav Gatev       if (unitPosLit && unitNegLit) {
47653dcd9efSStanislav Gatev         // We found a conflict!
47753dcd9efSStanislav Gatev 
47853dcd9efSStanislav Gatev         // Backtrack and rewind the `Level` until the most recent non-forced
47953dcd9efSStanislav Gatev         // assignment.
48053dcd9efSStanislav Gatev         reverseForcedMoves();
48153dcd9efSStanislav Gatev 
48253dcd9efSStanislav Gatev         // If the root level is reached, then all possible assignments lead to
48353dcd9efSStanislav Gatev         // a conflict.
48453dcd9efSStanislav Gatev         if (Level == 0)
48581e6400dSWei Yi Tee           return Solver::Result::Unsatisfiable();
48653dcd9efSStanislav Gatev 
48753dcd9efSStanislav Gatev         // Otherwise, take the other branch at the most recent level where a
48853dcd9efSStanislav Gatev         // decision was made.
48953dcd9efSStanislav Gatev         LevelStates[Level] = State::Forced;
49053dcd9efSStanislav Gatev         const Variable Var = LevelVars[Level];
49153dcd9efSStanislav Gatev         VarAssignments[Var] = VarAssignments[Var] == Assignment::AssignedTrue
49253dcd9efSStanislav Gatev                                   ? Assignment::AssignedFalse
49353dcd9efSStanislav Gatev                                   : Assignment::AssignedTrue;
49453dcd9efSStanislav Gatev 
49553dcd9efSStanislav Gatev         updateWatchedLiterals();
49653dcd9efSStanislav Gatev       } else if (unitPosLit || unitNegLit) {
49753dcd9efSStanislav Gatev         // We found a unit clause! The value of its unassigned variable is
49853dcd9efSStanislav Gatev         // forced.
49953dcd9efSStanislav Gatev         ++Level;
50053dcd9efSStanislav Gatev 
50153dcd9efSStanislav Gatev         LevelVars[Level] = ActiveVar;
50253dcd9efSStanislav Gatev         LevelStates[Level] = State::Forced;
50353dcd9efSStanislav Gatev         VarAssignments[ActiveVar] =
50453dcd9efSStanislav Gatev             unitPosLit ? Assignment::AssignedTrue : Assignment::AssignedFalse;
50553dcd9efSStanislav Gatev 
50653dcd9efSStanislav Gatev         // Remove the variable that was just assigned from the set of active
50753dcd9efSStanislav Gatev         // variables.
50853dcd9efSStanislav Gatev         if (I + 1 < ActiveVars.size()) {
50953dcd9efSStanislav Gatev           // Replace the variable that was just assigned with the last active
51053dcd9efSStanislav Gatev           // variable for efficient removal.
51153dcd9efSStanislav Gatev           ActiveVars[I] = ActiveVars.back();
51253dcd9efSStanislav Gatev         } else {
51353dcd9efSStanislav Gatev           // This was the last active variable. Repeat the process from the
51453dcd9efSStanislav Gatev           // beginning.
51553dcd9efSStanislav Gatev           I = 0;
51653dcd9efSStanislav Gatev         }
51753dcd9efSStanislav Gatev         ActiveVars.pop_back();
51853dcd9efSStanislav Gatev 
51953dcd9efSStanislav Gatev         updateWatchedLiterals();
52053dcd9efSStanislav Gatev       } else if (I + 1 == ActiveVars.size()) {
52153dcd9efSStanislav Gatev         // There are no remaining unit clauses in the formula! Make a decision
52253dcd9efSStanislav Gatev         // for one of the active variables at the current level.
52353dcd9efSStanislav Gatev         ++Level;
52453dcd9efSStanislav Gatev 
52553dcd9efSStanislav Gatev         LevelVars[Level] = ActiveVar;
52653dcd9efSStanislav Gatev         LevelStates[Level] = State::Decision;
52753dcd9efSStanislav Gatev         VarAssignments[ActiveVar] = decideAssignment(ActiveVar);
52853dcd9efSStanislav Gatev 
52953dcd9efSStanislav Gatev         // Remove the variable that was just assigned from the set of active
53053dcd9efSStanislav Gatev         // variables.
53153dcd9efSStanislav Gatev         ActiveVars.pop_back();
53253dcd9efSStanislav Gatev 
53353dcd9efSStanislav Gatev         updateWatchedLiterals();
53453dcd9efSStanislav Gatev 
53553dcd9efSStanislav Gatev         // This was the last active variable. Repeat the process from the
53653dcd9efSStanislav Gatev         // beginning.
53753dcd9efSStanislav Gatev         I = 0;
53853dcd9efSStanislav Gatev       } else {
53953dcd9efSStanislav Gatev         ++I;
54053dcd9efSStanislav Gatev       }
54153dcd9efSStanislav Gatev     }
54281e6400dSWei Yi Tee     return Solver::Result::Satisfiable(buildSolution());
54353dcd9efSStanislav Gatev   }
54453dcd9efSStanislav Gatev 
54553dcd9efSStanislav Gatev private:
54681e6400dSWei Yi Tee   /// Returns a satisfying truth assignment to the atomic values in the boolean
54781e6400dSWei Yi Tee   /// formula.
54881e6400dSWei Yi Tee   llvm::DenseMap<AtomicBoolValue *, Solver::Result::Assignment>
buildSolution()54981e6400dSWei Yi Tee   buildSolution() {
55081e6400dSWei Yi Tee     llvm::DenseMap<AtomicBoolValue *, Solver::Result::Assignment> Solution;
55181e6400dSWei Yi Tee     for (auto &Atomic : Formula.Atomics) {
55281e6400dSWei Yi Tee       // A variable may have a definite true/false assignment, or it may be
55381e6400dSWei Yi Tee       // unassigned indicating its truth value does not affect the result of
55481e6400dSWei Yi Tee       // the formula. Unassigned variables are assigned to true as a default.
55581e6400dSWei Yi Tee       Solution[Atomic.second] =
55681e6400dSWei Yi Tee           VarAssignments[Atomic.first] == Assignment::AssignedFalse
55781e6400dSWei Yi Tee               ? Solver::Result::Assignment::AssignedFalse
55881e6400dSWei Yi Tee               : Solver::Result::Assignment::AssignedTrue;
55981e6400dSWei Yi Tee     }
56081e6400dSWei Yi Tee     return Solution;
56181e6400dSWei Yi Tee   }
56281e6400dSWei Yi Tee 
56381e6400dSWei Yi Tee   /// Reverses forced moves until the most recent level where a decision was
56481e6400dSWei Yi Tee   /// made on the assignment of a variable.
reverseForcedMoves()56553dcd9efSStanislav Gatev   void reverseForcedMoves() {
56653dcd9efSStanislav Gatev     for (; LevelStates[Level] == State::Forced; --Level) {
56753dcd9efSStanislav Gatev       const Variable Var = LevelVars[Level];
56853dcd9efSStanislav Gatev 
56953dcd9efSStanislav Gatev       VarAssignments[Var] = Assignment::Unassigned;
57053dcd9efSStanislav Gatev 
57153dcd9efSStanislav Gatev       // If the variable that we pass through is watched then we add it to the
57253dcd9efSStanislav Gatev       // active variables.
57353dcd9efSStanislav Gatev       if (isWatched(posLit(Var)) || isWatched(negLit(Var)))
57453dcd9efSStanislav Gatev         ActiveVars.push_back(Var);
57553dcd9efSStanislav Gatev     }
57653dcd9efSStanislav Gatev   }
57753dcd9efSStanislav Gatev 
57881e6400dSWei Yi Tee   /// Updates watched literals that are affected by a variable assignment.
updateWatchedLiterals()57953dcd9efSStanislav Gatev   void updateWatchedLiterals() {
58053dcd9efSStanislav Gatev     const Variable Var = LevelVars[Level];
58153dcd9efSStanislav Gatev 
58253dcd9efSStanislav Gatev     // Update the watched literals of clauses that currently watch the literal
58353dcd9efSStanislav Gatev     // that falsifies `Var`.
58453dcd9efSStanislav Gatev     const Literal FalseLit = VarAssignments[Var] == Assignment::AssignedTrue
58553dcd9efSStanislav Gatev                                  ? negLit(Var)
58653dcd9efSStanislav Gatev                                  : posLit(Var);
58753dcd9efSStanislav Gatev     ClauseID FalseLitWatcher = Formula.WatchedHead[FalseLit];
58853dcd9efSStanislav Gatev     Formula.WatchedHead[FalseLit] = NullClause;
58953dcd9efSStanislav Gatev     while (FalseLitWatcher != NullClause) {
59053dcd9efSStanislav Gatev       const ClauseID NextFalseLitWatcher = Formula.NextWatched[FalseLitWatcher];
59153dcd9efSStanislav Gatev 
59253dcd9efSStanislav Gatev       // Pick the first non-false literal as the new watched literal.
59353dcd9efSStanislav Gatev       const size_t FalseLitWatcherStart = Formula.ClauseStarts[FalseLitWatcher];
59453dcd9efSStanislav Gatev       size_t NewWatchedLitIdx = FalseLitWatcherStart + 1;
59553dcd9efSStanislav Gatev       while (isCurrentlyFalse(Formula.Clauses[NewWatchedLitIdx]))
59653dcd9efSStanislav Gatev         ++NewWatchedLitIdx;
59753dcd9efSStanislav Gatev       const Literal NewWatchedLit = Formula.Clauses[NewWatchedLitIdx];
59853dcd9efSStanislav Gatev       const Variable NewWatchedLitVar = var(NewWatchedLit);
59953dcd9efSStanislav Gatev 
60053dcd9efSStanislav Gatev       // Swap the old watched literal for the new one in `FalseLitWatcher` to
60153dcd9efSStanislav Gatev       // maintain the invariant that the watched literal is at the beginning of
60253dcd9efSStanislav Gatev       // the clause.
60353dcd9efSStanislav Gatev       Formula.Clauses[NewWatchedLitIdx] = FalseLit;
60453dcd9efSStanislav Gatev       Formula.Clauses[FalseLitWatcherStart] = NewWatchedLit;
60553dcd9efSStanislav Gatev 
60653dcd9efSStanislav Gatev       // If the new watched literal isn't watched by any other clause and its
60753dcd9efSStanislav Gatev       // variable isn't assigned we need to add it to the active variables.
60853dcd9efSStanislav Gatev       if (!isWatched(NewWatchedLit) && !isWatched(notLit(NewWatchedLit)) &&
60953dcd9efSStanislav Gatev           VarAssignments[NewWatchedLitVar] == Assignment::Unassigned)
61053dcd9efSStanislav Gatev         ActiveVars.push_back(NewWatchedLitVar);
61153dcd9efSStanislav Gatev 
61253dcd9efSStanislav Gatev       Formula.NextWatched[FalseLitWatcher] = Formula.WatchedHead[NewWatchedLit];
61353dcd9efSStanislav Gatev       Formula.WatchedHead[NewWatchedLit] = FalseLitWatcher;
61453dcd9efSStanislav Gatev 
61553dcd9efSStanislav Gatev       // Go to the next clause that watches `FalseLit`.
61653dcd9efSStanislav Gatev       FalseLitWatcher = NextFalseLitWatcher;
61753dcd9efSStanislav Gatev     }
61853dcd9efSStanislav Gatev   }
61953dcd9efSStanislav Gatev 
62053dcd9efSStanislav Gatev   /// Returns true if and only if one of the clauses that watch `Lit` is a unit
62153dcd9efSStanislav Gatev   /// clause.
watchedByUnitClause(Literal Lit) const62253dcd9efSStanislav Gatev   bool watchedByUnitClause(Literal Lit) const {
62353dcd9efSStanislav Gatev     for (ClauseID LitWatcher = Formula.WatchedHead[Lit];
62453dcd9efSStanislav Gatev          LitWatcher != NullClause;
62553dcd9efSStanislav Gatev          LitWatcher = Formula.NextWatched[LitWatcher]) {
62653dcd9efSStanislav Gatev       llvm::ArrayRef<Literal> Clause = Formula.clauseLiterals(LitWatcher);
62753dcd9efSStanislav Gatev 
62853dcd9efSStanislav Gatev       // Assert the invariant that the watched literal is always the first one
62953dcd9efSStanislav Gatev       // in the clause.
63053dcd9efSStanislav Gatev       // FIXME: Consider replacing this with a test case that fails if the
63153dcd9efSStanislav Gatev       // invariant is broken by `updateWatchedLiterals`. That might not be easy
63253dcd9efSStanislav Gatev       // due to the transformations performed by `buildBooleanFormula`.
63353dcd9efSStanislav Gatev       assert(Clause.front() == Lit);
63453dcd9efSStanislav Gatev 
63553dcd9efSStanislav Gatev       if (isUnit(Clause))
63653dcd9efSStanislav Gatev         return true;
63753dcd9efSStanislav Gatev     }
63853dcd9efSStanislav Gatev     return false;
63953dcd9efSStanislav Gatev   }
64053dcd9efSStanislav Gatev 
64153dcd9efSStanislav Gatev   /// Returns true if and only if `Clause` is a unit clause.
isUnit(llvm::ArrayRef<Literal> Clause) const64253dcd9efSStanislav Gatev   bool isUnit(llvm::ArrayRef<Literal> Clause) const {
64353dcd9efSStanislav Gatev     return llvm::all_of(Clause.drop_front(),
64453dcd9efSStanislav Gatev                         [this](Literal L) { return isCurrentlyFalse(L); });
64553dcd9efSStanislav Gatev   }
64653dcd9efSStanislav Gatev 
64753dcd9efSStanislav Gatev   /// Returns true if and only if `Lit` evaluates to `false` in the current
64853dcd9efSStanislav Gatev   /// partial assignment.
isCurrentlyFalse(Literal Lit) const64953dcd9efSStanislav Gatev   bool isCurrentlyFalse(Literal Lit) const {
65053dcd9efSStanislav Gatev     return static_cast<int8_t>(VarAssignments[var(Lit)]) ==
65153dcd9efSStanislav Gatev            static_cast<int8_t>(Lit & 1);
65253dcd9efSStanislav Gatev   }
65353dcd9efSStanislav Gatev 
65453dcd9efSStanislav Gatev   /// Returns true if and only if `Lit` is watched by a clause in `Formula`.
isWatched(Literal Lit) const65553dcd9efSStanislav Gatev   bool isWatched(Literal Lit) const {
65653dcd9efSStanislav Gatev     return Formula.WatchedHead[Lit] != NullClause;
65753dcd9efSStanislav Gatev   }
65853dcd9efSStanislav Gatev 
65953dcd9efSStanislav Gatev   /// Returns an assignment for an unassigned variable.
decideAssignment(Variable Var) const66053dcd9efSStanislav Gatev   Assignment decideAssignment(Variable Var) const {
66153dcd9efSStanislav Gatev     return !isWatched(posLit(Var)) || isWatched(negLit(Var))
66253dcd9efSStanislav Gatev                ? Assignment::AssignedFalse
66353dcd9efSStanislav Gatev                : Assignment::AssignedTrue;
66453dcd9efSStanislav Gatev   }
66553dcd9efSStanislav Gatev 
66653dcd9efSStanislav Gatev   /// Returns a set of all watched literals.
watchedLiterals() const66753dcd9efSStanislav Gatev   llvm::DenseSet<Literal> watchedLiterals() const {
66853dcd9efSStanislav Gatev     llvm::DenseSet<Literal> WatchedLiterals;
66953dcd9efSStanislav Gatev     for (Literal Lit = 2; Lit < Formula.WatchedHead.size(); Lit++) {
67053dcd9efSStanislav Gatev       if (Formula.WatchedHead[Lit] == NullClause)
67153dcd9efSStanislav Gatev         continue;
67253dcd9efSStanislav Gatev       WatchedLiterals.insert(Lit);
67353dcd9efSStanislav Gatev     }
67453dcd9efSStanislav Gatev     return WatchedLiterals;
67553dcd9efSStanislav Gatev   }
67653dcd9efSStanislav Gatev 
67753dcd9efSStanislav Gatev   /// Returns true if and only if all active variables are unassigned.
activeVarsAreUnassigned() const67853dcd9efSStanislav Gatev   bool activeVarsAreUnassigned() const {
67953dcd9efSStanislav Gatev     return llvm::all_of(ActiveVars, [this](Variable Var) {
68053dcd9efSStanislav Gatev       return VarAssignments[Var] == Assignment::Unassigned;
68153dcd9efSStanislav Gatev     });
68253dcd9efSStanislav Gatev   }
68353dcd9efSStanislav Gatev 
68453dcd9efSStanislav Gatev   /// Returns true if and only if all active variables form watched literals.
activeVarsFormWatchedLiterals() const68553dcd9efSStanislav Gatev   bool activeVarsFormWatchedLiterals() const {
68653dcd9efSStanislav Gatev     const llvm::DenseSet<Literal> WatchedLiterals = watchedLiterals();
68753dcd9efSStanislav Gatev     return llvm::all_of(ActiveVars, [&WatchedLiterals](Variable Var) {
68853dcd9efSStanislav Gatev       return WatchedLiterals.contains(posLit(Var)) ||
68953dcd9efSStanislav Gatev              WatchedLiterals.contains(negLit(Var));
69053dcd9efSStanislav Gatev     });
69153dcd9efSStanislav Gatev   }
69253dcd9efSStanislav Gatev 
69353dcd9efSStanislav Gatev   /// Returns true if and only if all unassigned variables that are forming
69453dcd9efSStanislav Gatev   /// watched literals are active.
unassignedVarsFormingWatchedLiteralsAreActive() const69553dcd9efSStanislav Gatev   bool unassignedVarsFormingWatchedLiteralsAreActive() const {
69653dcd9efSStanislav Gatev     const llvm::DenseSet<Variable> ActiveVarsSet(ActiveVars.begin(),
69753dcd9efSStanislav Gatev                                                  ActiveVars.end());
69853dcd9efSStanislav Gatev     for (Literal Lit : watchedLiterals()) {
69953dcd9efSStanislav Gatev       const Variable Var = var(Lit);
70053dcd9efSStanislav Gatev       if (VarAssignments[Var] != Assignment::Unassigned)
70153dcd9efSStanislav Gatev         continue;
70253dcd9efSStanislav Gatev       if (ActiveVarsSet.contains(Var))
70353dcd9efSStanislav Gatev         continue;
70453dcd9efSStanislav Gatev       return false;
70553dcd9efSStanislav Gatev     }
70653dcd9efSStanislav Gatev     return true;
70753dcd9efSStanislav Gatev   }
70853dcd9efSStanislav Gatev };
70953dcd9efSStanislav Gatev 
solve(llvm::DenseSet<BoolValue * > Vals)71053dcd9efSStanislav Gatev Solver::Result WatchedLiteralsSolver::solve(llvm::DenseSet<BoolValue *> Vals) {
71181e6400dSWei Yi Tee   return Vals.empty() ? Solver::Result::Satisfiable({{}})
71253dcd9efSStanislav Gatev                       : WatchedLiteralsSolverImpl(Vals).solve();
71353dcd9efSStanislav Gatev }
71453dcd9efSStanislav Gatev 
71553dcd9efSStanislav Gatev } // namespace dataflow
71653dcd9efSStanislav Gatev } // namespace clang
717