xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 <vector>
1681ad6265SDimitry Andric 
17*0fca6ea1SDimitry Andric #include "clang/Analysis/FlowSensitive/CNFFormula.h"
1806c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/Formula.h"
1981ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Solver.h"
2081ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
2106c3fb27SDimitry Andric #include "llvm/ADT/ArrayRef.h"
2281ad6265SDimitry Andric #include "llvm/ADT/DenseMap.h"
2381ad6265SDimitry Andric #include "llvm/ADT/DenseSet.h"
2481ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
2581ad6265SDimitry Andric 
265f757f3fSDimitry Andric 
2781ad6265SDimitry Andric namespace clang {
2881ad6265SDimitry Andric namespace dataflow {
2981ad6265SDimitry Andric 
30*0fca6ea1SDimitry Andric namespace {
3181ad6265SDimitry Andric 
32*0fca6ea1SDimitry Andric class WatchedLiteralsSolverImpl {
33*0fca6ea1SDimitry Andric   /// Stores the variable identifier and Atom for atomic booleans in the
34*0fca6ea1SDimitry Andric   /// formula.
35*0fca6ea1SDimitry Andric   llvm::DenseMap<Variable, Atom> Atomics;
3681ad6265SDimitry Andric 
37*0fca6ea1SDimitry Andric   /// A boolean formula in conjunctive normal form that the solver will attempt
38*0fca6ea1SDimitry Andric   /// to prove satisfiable. The formula will be modified in the process.
39*0fca6ea1SDimitry Andric   CNFFormula CNF;
4081ad6265SDimitry Andric 
4181ad6265SDimitry Andric   /// Maps literals (indices of the vector) to clause identifiers (elements of
4281ad6265SDimitry Andric   /// the vector) that watch the respective literals.
4381ad6265SDimitry Andric   ///
4481ad6265SDimitry Andric   /// For a given clause, its watched literal is always its first literal in
4581ad6265SDimitry Andric   /// `Clauses`. This invariant is maintained when watched literals change.
4681ad6265SDimitry Andric   std::vector<ClauseID> WatchedHead;
4781ad6265SDimitry Andric 
4881ad6265SDimitry Andric   /// Maps clause identifiers (elements of the vector) to identifiers of other
4981ad6265SDimitry Andric   /// clauses that watch the same literals, forming a set of linked lists.
5081ad6265SDimitry Andric   ///
5181ad6265SDimitry Andric   /// The element at index 0 stands for the identifier of the clause that
5281ad6265SDimitry Andric   /// follows the null clause. It is set to 0 and isn't used. Identifiers of
5381ad6265SDimitry Andric   /// clauses in the formula start from the element at index 1.
5481ad6265SDimitry Andric   std::vector<ClauseID> NextWatched;
5581ad6265SDimitry Andric 
5681ad6265SDimitry Andric   /// The search for a satisfying assignment of the variables in `Formula` will
5781ad6265SDimitry Andric   /// proceed in levels, starting from 1 and going up to `Formula.LargestVar`
5881ad6265SDimitry Andric   /// (inclusive). The current level is stored in `Level`. At each level the
5981ad6265SDimitry Andric   /// solver will assign a value to an unassigned variable. If this leads to a
6081ad6265SDimitry Andric   /// consistent partial assignment, `Level` will be incremented. Otherwise, if
6181ad6265SDimitry Andric   /// it results in a conflict, the solver will backtrack by decrementing
6281ad6265SDimitry Andric   /// `Level` until it reaches the most recent level where a decision was made.
6381ad6265SDimitry Andric   size_t Level = 0;
6481ad6265SDimitry Andric 
6581ad6265SDimitry Andric   /// Maps levels (indices of the vector) to variables (elements of the vector)
6681ad6265SDimitry Andric   /// that are assigned values at the respective levels.
6781ad6265SDimitry Andric   ///
6881ad6265SDimitry Andric   /// The element at index 0 isn't used. Variables start from the element at
6981ad6265SDimitry Andric   /// index 1.
7081ad6265SDimitry Andric   std::vector<Variable> LevelVars;
7181ad6265SDimitry Andric 
7281ad6265SDimitry Andric   /// State of the solver at a particular level.
7381ad6265SDimitry Andric   enum class State : uint8_t {
7481ad6265SDimitry Andric     /// Indicates that the solver made a decision.
7581ad6265SDimitry Andric     Decision = 0,
7681ad6265SDimitry Andric 
7781ad6265SDimitry Andric     /// Indicates that the solver made a forced move.
7881ad6265SDimitry Andric     Forced = 1,
7981ad6265SDimitry Andric   };
8081ad6265SDimitry Andric 
8181ad6265SDimitry Andric   /// State of the solver at a particular level. It keeps track of previous
8281ad6265SDimitry Andric   /// decisions that the solver can refer to when backtracking.
8381ad6265SDimitry Andric   ///
8481ad6265SDimitry Andric   /// The element at index 0 isn't used. States start from the element at index
8581ad6265SDimitry Andric   /// 1.
8681ad6265SDimitry Andric   std::vector<State> LevelStates;
8781ad6265SDimitry Andric 
8881ad6265SDimitry Andric   enum class Assignment : int8_t {
8981ad6265SDimitry Andric     Unassigned = -1,
9081ad6265SDimitry Andric     AssignedFalse = 0,
9181ad6265SDimitry Andric     AssignedTrue = 1
9281ad6265SDimitry Andric   };
9381ad6265SDimitry Andric 
9481ad6265SDimitry Andric   /// Maps variables (indices of the vector) to their assignments (elements of
9581ad6265SDimitry Andric   /// the vector).
9681ad6265SDimitry Andric   ///
9781ad6265SDimitry Andric   /// The element at index 0 isn't used. Variable assignments start from the
9881ad6265SDimitry Andric   /// element at index 1.
9981ad6265SDimitry Andric   std::vector<Assignment> VarAssignments;
10081ad6265SDimitry Andric 
10181ad6265SDimitry Andric   /// A set of unassigned variables that appear in watched literals in
10281ad6265SDimitry Andric   /// `Formula`. The vector is guaranteed to contain unique elements.
10381ad6265SDimitry Andric   std::vector<Variable> ActiveVars;
10481ad6265SDimitry Andric 
10581ad6265SDimitry Andric public:
10606c3fb27SDimitry Andric   explicit WatchedLiteralsSolverImpl(
10706c3fb27SDimitry Andric       const llvm::ArrayRef<const Formula *> &Vals)
108*0fca6ea1SDimitry Andric       // `Atomics` needs to be initialized first so that we can use it as an
109*0fca6ea1SDimitry Andric       // output argument of `buildCNF()`.
110*0fca6ea1SDimitry Andric       : Atomics(), CNF(buildCNF(Vals, Atomics)),
111*0fca6ea1SDimitry Andric         LevelVars(CNF.largestVar() + 1), LevelStates(CNF.largestVar() + 1) {
11281ad6265SDimitry Andric     assert(!Vals.empty());
11381ad6265SDimitry Andric 
114*0fca6ea1SDimitry Andric     // Skip initialization if the formula is known to be contradictory.
115*0fca6ea1SDimitry Andric     if (CNF.knownContradictory())
116*0fca6ea1SDimitry Andric       return;
117*0fca6ea1SDimitry Andric 
118*0fca6ea1SDimitry Andric     // Initialize `NextWatched` and `WatchedHead`.
119*0fca6ea1SDimitry Andric     NextWatched.push_back(0);
120*0fca6ea1SDimitry Andric     const size_t NumLiterals = 2 * CNF.largestVar() + 1;
121*0fca6ea1SDimitry Andric     WatchedHead.resize(NumLiterals + 1, 0);
122*0fca6ea1SDimitry Andric     for (ClauseID C = 1; C <= CNF.numClauses(); ++C) {
123*0fca6ea1SDimitry Andric       // Designate the first literal as the "watched" literal of the clause.
124*0fca6ea1SDimitry Andric       Literal FirstLit = CNF.clauseLiterals(C).front();
125*0fca6ea1SDimitry Andric       NextWatched.push_back(WatchedHead[FirstLit]);
126*0fca6ea1SDimitry Andric       WatchedHead[FirstLit] = C;
127*0fca6ea1SDimitry Andric     }
128*0fca6ea1SDimitry Andric 
12981ad6265SDimitry Andric     // Initialize the state at the root level to a decision so that in
13081ad6265SDimitry Andric     // `reverseForcedMoves` we don't have to check that `Level >= 0` on each
13181ad6265SDimitry Andric     // iteration.
13281ad6265SDimitry Andric     LevelStates[0] = State::Decision;
13381ad6265SDimitry Andric 
13481ad6265SDimitry Andric     // Initialize all variables as unassigned.
135*0fca6ea1SDimitry Andric     VarAssignments.resize(CNF.largestVar() + 1, Assignment::Unassigned);
13681ad6265SDimitry Andric 
13781ad6265SDimitry Andric     // Initialize the active variables.
138*0fca6ea1SDimitry Andric     for (Variable Var = CNF.largestVar(); Var != NullVar; --Var) {
13981ad6265SDimitry Andric       if (isWatched(posLit(Var)) || isWatched(negLit(Var)))
14081ad6265SDimitry Andric         ActiveVars.push_back(Var);
14181ad6265SDimitry Andric     }
14281ad6265SDimitry Andric   }
14381ad6265SDimitry Andric 
14406c3fb27SDimitry Andric   // Returns the `Result` and the number of iterations "remaining" from
14506c3fb27SDimitry Andric   // `MaxIterations` (that is, `MaxIterations` - iterations in this call).
14606c3fb27SDimitry Andric   std::pair<Solver::Result, std::int64_t> solve(std::int64_t MaxIterations) && {
147*0fca6ea1SDimitry Andric     if (CNF.knownContradictory()) {
1485f757f3fSDimitry Andric       // Short-cut the solving process. We already found out at CNF
1495f757f3fSDimitry Andric       // construction time that the formula is unsatisfiable.
1505f757f3fSDimitry Andric       return std::make_pair(Solver::Result::Unsatisfiable(), MaxIterations);
1515f757f3fSDimitry Andric     }
15281ad6265SDimitry Andric     size_t I = 0;
15381ad6265SDimitry Andric     while (I < ActiveVars.size()) {
15406c3fb27SDimitry Andric       if (MaxIterations == 0)
15506c3fb27SDimitry Andric         return std::make_pair(Solver::Result::TimedOut(), 0);
15606c3fb27SDimitry Andric       --MaxIterations;
15706c3fb27SDimitry Andric 
15881ad6265SDimitry Andric       // Assert that the following invariants hold:
15981ad6265SDimitry Andric       // 1. All active variables are unassigned.
16081ad6265SDimitry Andric       // 2. All active variables form watched literals.
16181ad6265SDimitry Andric       // 3. Unassigned variables that form watched literals are active.
16281ad6265SDimitry Andric       // FIXME: Consider replacing these with test cases that fail if the any
16381ad6265SDimitry Andric       // of the invariants is broken. That might not be easy due to the
16406c3fb27SDimitry Andric       // transformations performed by `buildCNF`.
16581ad6265SDimitry Andric       assert(activeVarsAreUnassigned());
16681ad6265SDimitry Andric       assert(activeVarsFormWatchedLiterals());
16781ad6265SDimitry Andric       assert(unassignedVarsFormingWatchedLiteralsAreActive());
16881ad6265SDimitry Andric 
16981ad6265SDimitry Andric       const Variable ActiveVar = ActiveVars[I];
17081ad6265SDimitry Andric 
17181ad6265SDimitry Andric       // Look for unit clauses that contain the active variable.
17281ad6265SDimitry Andric       const bool unitPosLit = watchedByUnitClause(posLit(ActiveVar));
17381ad6265SDimitry Andric       const bool unitNegLit = watchedByUnitClause(negLit(ActiveVar));
17481ad6265SDimitry Andric       if (unitPosLit && unitNegLit) {
17581ad6265SDimitry Andric         // We found a conflict!
17681ad6265SDimitry Andric 
17781ad6265SDimitry Andric         // Backtrack and rewind the `Level` until the most recent non-forced
17881ad6265SDimitry Andric         // assignment.
17981ad6265SDimitry Andric         reverseForcedMoves();
18081ad6265SDimitry Andric 
18181ad6265SDimitry Andric         // If the root level is reached, then all possible assignments lead to
18281ad6265SDimitry Andric         // a conflict.
18381ad6265SDimitry Andric         if (Level == 0)
18406c3fb27SDimitry Andric           return std::make_pair(Solver::Result::Unsatisfiable(), MaxIterations);
18581ad6265SDimitry Andric 
18681ad6265SDimitry Andric         // Otherwise, take the other branch at the most recent level where a
18781ad6265SDimitry Andric         // decision was made.
18881ad6265SDimitry Andric         LevelStates[Level] = State::Forced;
18981ad6265SDimitry Andric         const Variable Var = LevelVars[Level];
19081ad6265SDimitry Andric         VarAssignments[Var] = VarAssignments[Var] == Assignment::AssignedTrue
19181ad6265SDimitry Andric                                   ? Assignment::AssignedFalse
19281ad6265SDimitry Andric                                   : Assignment::AssignedTrue;
19381ad6265SDimitry Andric 
19481ad6265SDimitry Andric         updateWatchedLiterals();
19581ad6265SDimitry Andric       } else if (unitPosLit || unitNegLit) {
19681ad6265SDimitry Andric         // We found a unit clause! The value of its unassigned variable is
19781ad6265SDimitry Andric         // forced.
19881ad6265SDimitry Andric         ++Level;
19981ad6265SDimitry Andric 
20081ad6265SDimitry Andric         LevelVars[Level] = ActiveVar;
20181ad6265SDimitry Andric         LevelStates[Level] = State::Forced;
20281ad6265SDimitry Andric         VarAssignments[ActiveVar] =
20381ad6265SDimitry Andric             unitPosLit ? Assignment::AssignedTrue : Assignment::AssignedFalse;
20481ad6265SDimitry Andric 
20581ad6265SDimitry Andric         // Remove the variable that was just assigned from the set of active
20681ad6265SDimitry Andric         // variables.
20781ad6265SDimitry Andric         if (I + 1 < ActiveVars.size()) {
20881ad6265SDimitry Andric           // Replace the variable that was just assigned with the last active
20981ad6265SDimitry Andric           // variable for efficient removal.
21081ad6265SDimitry Andric           ActiveVars[I] = ActiveVars.back();
21181ad6265SDimitry Andric         } else {
21281ad6265SDimitry Andric           // This was the last active variable. Repeat the process from the
21381ad6265SDimitry Andric           // beginning.
21481ad6265SDimitry Andric           I = 0;
21581ad6265SDimitry Andric         }
21681ad6265SDimitry Andric         ActiveVars.pop_back();
21781ad6265SDimitry Andric 
21881ad6265SDimitry Andric         updateWatchedLiterals();
21981ad6265SDimitry Andric       } else if (I + 1 == ActiveVars.size()) {
22081ad6265SDimitry Andric         // There are no remaining unit clauses in the formula! Make a decision
22181ad6265SDimitry Andric         // for one of the active variables at the current level.
22281ad6265SDimitry Andric         ++Level;
22381ad6265SDimitry Andric 
22481ad6265SDimitry Andric         LevelVars[Level] = ActiveVar;
22581ad6265SDimitry Andric         LevelStates[Level] = State::Decision;
22681ad6265SDimitry Andric         VarAssignments[ActiveVar] = decideAssignment(ActiveVar);
22781ad6265SDimitry Andric 
22881ad6265SDimitry Andric         // Remove the variable that was just assigned from the set of active
22981ad6265SDimitry Andric         // variables.
23081ad6265SDimitry Andric         ActiveVars.pop_back();
23181ad6265SDimitry Andric 
23281ad6265SDimitry Andric         updateWatchedLiterals();
23381ad6265SDimitry Andric 
23481ad6265SDimitry Andric         // This was the last active variable. Repeat the process from the
23581ad6265SDimitry Andric         // beginning.
23681ad6265SDimitry Andric         I = 0;
23781ad6265SDimitry Andric       } else {
23881ad6265SDimitry Andric         ++I;
23981ad6265SDimitry Andric       }
24081ad6265SDimitry Andric     }
2415f757f3fSDimitry Andric     return std::make_pair(Solver::Result::Satisfiable(buildSolution()),
2425f757f3fSDimitry Andric                           MaxIterations);
24381ad6265SDimitry Andric   }
24481ad6265SDimitry Andric 
24581ad6265SDimitry Andric private:
24606c3fb27SDimitry Andric   /// Returns a satisfying truth assignment to the atoms in the boolean formula.
24706c3fb27SDimitry Andric   llvm::DenseMap<Atom, Solver::Result::Assignment> buildSolution() {
24806c3fb27SDimitry Andric     llvm::DenseMap<Atom, Solver::Result::Assignment> Solution;
249*0fca6ea1SDimitry Andric     for (auto &Atomic : Atomics) {
250753f127fSDimitry Andric       // A variable may have a definite true/false assignment, or it may be
251753f127fSDimitry Andric       // unassigned indicating its truth value does not affect the result of
252753f127fSDimitry Andric       // the formula. Unassigned variables are assigned to true as a default.
253753f127fSDimitry Andric       Solution[Atomic.second] =
254753f127fSDimitry Andric           VarAssignments[Atomic.first] == Assignment::AssignedFalse
255753f127fSDimitry Andric               ? Solver::Result::Assignment::AssignedFalse
256753f127fSDimitry Andric               : Solver::Result::Assignment::AssignedTrue;
257753f127fSDimitry Andric     }
258753f127fSDimitry Andric     return Solution;
259753f127fSDimitry Andric   }
260753f127fSDimitry Andric 
261753f127fSDimitry Andric   /// Reverses forced moves until the most recent level where a decision was
262753f127fSDimitry Andric   /// made on the assignment of a variable.
26381ad6265SDimitry Andric   void reverseForcedMoves() {
26481ad6265SDimitry Andric     for (; LevelStates[Level] == State::Forced; --Level) {
26581ad6265SDimitry Andric       const Variable Var = LevelVars[Level];
26681ad6265SDimitry Andric 
26781ad6265SDimitry Andric       VarAssignments[Var] = Assignment::Unassigned;
26881ad6265SDimitry Andric 
26981ad6265SDimitry Andric       // If the variable that we pass through is watched then we add it to the
27081ad6265SDimitry Andric       // active variables.
27181ad6265SDimitry Andric       if (isWatched(posLit(Var)) || isWatched(negLit(Var)))
27281ad6265SDimitry Andric         ActiveVars.push_back(Var);
27381ad6265SDimitry Andric     }
27481ad6265SDimitry Andric   }
27581ad6265SDimitry Andric 
276753f127fSDimitry Andric   /// Updates watched literals that are affected by a variable assignment.
27781ad6265SDimitry Andric   void updateWatchedLiterals() {
27881ad6265SDimitry Andric     const Variable Var = LevelVars[Level];
27981ad6265SDimitry Andric 
28081ad6265SDimitry Andric     // Update the watched literals of clauses that currently watch the literal
28181ad6265SDimitry Andric     // that falsifies `Var`.
28281ad6265SDimitry Andric     const Literal FalseLit = VarAssignments[Var] == Assignment::AssignedTrue
28381ad6265SDimitry Andric                                  ? negLit(Var)
28481ad6265SDimitry Andric                                  : posLit(Var);
285*0fca6ea1SDimitry Andric     ClauseID FalseLitWatcher = WatchedHead[FalseLit];
286*0fca6ea1SDimitry Andric     WatchedHead[FalseLit] = NullClause;
28781ad6265SDimitry Andric     while (FalseLitWatcher != NullClause) {
288*0fca6ea1SDimitry Andric       const ClauseID NextFalseLitWatcher = NextWatched[FalseLitWatcher];
28981ad6265SDimitry Andric 
29081ad6265SDimitry Andric       // Pick the first non-false literal as the new watched literal.
291*0fca6ea1SDimitry Andric       const CNFFormula::Iterator FalseLitWatcherStart =
292*0fca6ea1SDimitry Andric           CNF.startOfClause(FalseLitWatcher);
293*0fca6ea1SDimitry Andric       CNFFormula::Iterator NewWatchedLitIter = FalseLitWatcherStart.next();
294*0fca6ea1SDimitry Andric       while (isCurrentlyFalse(*NewWatchedLitIter))
295*0fca6ea1SDimitry Andric         ++NewWatchedLitIter;
296*0fca6ea1SDimitry Andric       const Literal NewWatchedLit = *NewWatchedLitIter;
29781ad6265SDimitry Andric       const Variable NewWatchedLitVar = var(NewWatchedLit);
29881ad6265SDimitry Andric 
29981ad6265SDimitry Andric       // Swap the old watched literal for the new one in `FalseLitWatcher` to
30081ad6265SDimitry Andric       // maintain the invariant that the watched literal is at the beginning of
30181ad6265SDimitry Andric       // the clause.
302*0fca6ea1SDimitry Andric       *NewWatchedLitIter = FalseLit;
303*0fca6ea1SDimitry Andric       *FalseLitWatcherStart = NewWatchedLit;
30481ad6265SDimitry Andric 
30581ad6265SDimitry Andric       // If the new watched literal isn't watched by any other clause and its
30681ad6265SDimitry Andric       // variable isn't assigned we need to add it to the active variables.
30781ad6265SDimitry Andric       if (!isWatched(NewWatchedLit) && !isWatched(notLit(NewWatchedLit)) &&
30881ad6265SDimitry Andric           VarAssignments[NewWatchedLitVar] == Assignment::Unassigned)
30981ad6265SDimitry Andric         ActiveVars.push_back(NewWatchedLitVar);
31081ad6265SDimitry Andric 
311*0fca6ea1SDimitry Andric       NextWatched[FalseLitWatcher] = WatchedHead[NewWatchedLit];
312*0fca6ea1SDimitry Andric       WatchedHead[NewWatchedLit] = FalseLitWatcher;
31381ad6265SDimitry Andric 
31481ad6265SDimitry Andric       // Go to the next clause that watches `FalseLit`.
31581ad6265SDimitry Andric       FalseLitWatcher = NextFalseLitWatcher;
31681ad6265SDimitry Andric     }
31781ad6265SDimitry Andric   }
31881ad6265SDimitry Andric 
31981ad6265SDimitry Andric   /// Returns true if and only if one of the clauses that watch `Lit` is a unit
32081ad6265SDimitry Andric   /// clause.
32181ad6265SDimitry Andric   bool watchedByUnitClause(Literal Lit) const {
322*0fca6ea1SDimitry Andric     for (ClauseID LitWatcher = WatchedHead[Lit]; LitWatcher != NullClause;
323*0fca6ea1SDimitry Andric          LitWatcher = NextWatched[LitWatcher]) {
32406c3fb27SDimitry Andric       llvm::ArrayRef<Literal> Clause = CNF.clauseLiterals(LitWatcher);
32581ad6265SDimitry Andric 
32681ad6265SDimitry Andric       // Assert the invariant that the watched literal is always the first one
32781ad6265SDimitry Andric       // in the clause.
32881ad6265SDimitry Andric       // FIXME: Consider replacing this with a test case that fails if the
32981ad6265SDimitry Andric       // invariant is broken by `updateWatchedLiterals`. That might not be easy
33006c3fb27SDimitry Andric       // due to the transformations performed by `buildCNF`.
33181ad6265SDimitry Andric       assert(Clause.front() == Lit);
33281ad6265SDimitry Andric 
33381ad6265SDimitry Andric       if (isUnit(Clause))
33481ad6265SDimitry Andric         return true;
33581ad6265SDimitry Andric     }
33681ad6265SDimitry Andric     return false;
33781ad6265SDimitry Andric   }
33881ad6265SDimitry Andric 
33981ad6265SDimitry Andric   /// Returns true if and only if `Clause` is a unit clause.
34081ad6265SDimitry Andric   bool isUnit(llvm::ArrayRef<Literal> Clause) const {
34181ad6265SDimitry Andric     return llvm::all_of(Clause.drop_front(),
34281ad6265SDimitry Andric                         [this](Literal L) { return isCurrentlyFalse(L); });
34381ad6265SDimitry Andric   }
34481ad6265SDimitry Andric 
34581ad6265SDimitry Andric   /// Returns true if and only if `Lit` evaluates to `false` in the current
34681ad6265SDimitry Andric   /// partial assignment.
34781ad6265SDimitry Andric   bool isCurrentlyFalse(Literal Lit) const {
34881ad6265SDimitry Andric     return static_cast<int8_t>(VarAssignments[var(Lit)]) ==
34981ad6265SDimitry Andric            static_cast<int8_t>(Lit & 1);
35081ad6265SDimitry Andric   }
35181ad6265SDimitry Andric 
35281ad6265SDimitry Andric   /// Returns true if and only if `Lit` is watched by a clause in `Formula`.
353*0fca6ea1SDimitry Andric   bool isWatched(Literal Lit) const { return WatchedHead[Lit] != NullClause; }
35481ad6265SDimitry Andric 
35581ad6265SDimitry Andric   /// Returns an assignment for an unassigned variable.
35681ad6265SDimitry Andric   Assignment decideAssignment(Variable Var) const {
35781ad6265SDimitry Andric     return !isWatched(posLit(Var)) || isWatched(negLit(Var))
35881ad6265SDimitry Andric                ? Assignment::AssignedFalse
35981ad6265SDimitry Andric                : Assignment::AssignedTrue;
36081ad6265SDimitry Andric   }
36181ad6265SDimitry Andric 
36281ad6265SDimitry Andric   /// Returns a set of all watched literals.
36381ad6265SDimitry Andric   llvm::DenseSet<Literal> watchedLiterals() const {
36481ad6265SDimitry Andric     llvm::DenseSet<Literal> WatchedLiterals;
365*0fca6ea1SDimitry Andric     for (Literal Lit = 2; Lit < WatchedHead.size(); Lit++) {
366*0fca6ea1SDimitry Andric       if (WatchedHead[Lit] == NullClause)
36781ad6265SDimitry Andric         continue;
36881ad6265SDimitry Andric       WatchedLiterals.insert(Lit);
36981ad6265SDimitry Andric     }
37081ad6265SDimitry Andric     return WatchedLiterals;
37181ad6265SDimitry Andric   }
37281ad6265SDimitry Andric 
37381ad6265SDimitry Andric   /// Returns true if and only if all active variables are unassigned.
37481ad6265SDimitry Andric   bool activeVarsAreUnassigned() const {
37581ad6265SDimitry Andric     return llvm::all_of(ActiveVars, [this](Variable Var) {
37681ad6265SDimitry Andric       return VarAssignments[Var] == Assignment::Unassigned;
37781ad6265SDimitry Andric     });
37881ad6265SDimitry Andric   }
37981ad6265SDimitry Andric 
38081ad6265SDimitry Andric   /// Returns true if and only if all active variables form watched literals.
38181ad6265SDimitry Andric   bool activeVarsFormWatchedLiterals() const {
38281ad6265SDimitry Andric     const llvm::DenseSet<Literal> WatchedLiterals = watchedLiterals();
38381ad6265SDimitry Andric     return llvm::all_of(ActiveVars, [&WatchedLiterals](Variable Var) {
38481ad6265SDimitry Andric       return WatchedLiterals.contains(posLit(Var)) ||
38581ad6265SDimitry Andric              WatchedLiterals.contains(negLit(Var));
38681ad6265SDimitry Andric     });
38781ad6265SDimitry Andric   }
38881ad6265SDimitry Andric 
38981ad6265SDimitry Andric   /// Returns true if and only if all unassigned variables that are forming
39081ad6265SDimitry Andric   /// watched literals are active.
39181ad6265SDimitry Andric   bool unassignedVarsFormingWatchedLiteralsAreActive() const {
39281ad6265SDimitry Andric     const llvm::DenseSet<Variable> ActiveVarsSet(ActiveVars.begin(),
39381ad6265SDimitry Andric                                                  ActiveVars.end());
39481ad6265SDimitry Andric     for (Literal Lit : watchedLiterals()) {
39581ad6265SDimitry Andric       const Variable Var = var(Lit);
39681ad6265SDimitry Andric       if (VarAssignments[Var] != Assignment::Unassigned)
39781ad6265SDimitry Andric         continue;
39881ad6265SDimitry Andric       if (ActiveVarsSet.contains(Var))
39981ad6265SDimitry Andric         continue;
40081ad6265SDimitry Andric       return false;
40181ad6265SDimitry Andric     }
40281ad6265SDimitry Andric     return true;
40381ad6265SDimitry Andric   }
40481ad6265SDimitry Andric };
40581ad6265SDimitry Andric 
406*0fca6ea1SDimitry Andric } // namespace
407*0fca6ea1SDimitry Andric 
40806c3fb27SDimitry Andric Solver::Result
40906c3fb27SDimitry Andric WatchedLiteralsSolver::solve(llvm::ArrayRef<const Formula *> Vals) {
41006c3fb27SDimitry Andric   if (Vals.empty())
41106c3fb27SDimitry Andric     return Solver::Result::Satisfiable({{}});
4125f757f3fSDimitry Andric   auto [Res, Iterations] = WatchedLiteralsSolverImpl(Vals).solve(MaxIterations);
41306c3fb27SDimitry Andric   MaxIterations = Iterations;
41406c3fb27SDimitry Andric   return Res;
41581ad6265SDimitry Andric }
41681ad6265SDimitry Andric 
41781ad6265SDimitry Andric } // namespace dataflow
41881ad6265SDimitry Andric } // namespace clang
419