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