xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
1*81ad6265SDimitry Andric //===- WatchedLiteralsSolver.cpp --------------------------------*- C++ -*-===//
2*81ad6265SDimitry Andric //
3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*81ad6265SDimitry Andric //
7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===//
8*81ad6265SDimitry Andric //
9*81ad6265SDimitry Andric //  This file defines a SAT solver implementation that can be used by dataflow
10*81ad6265SDimitry Andric //  analyses.
11*81ad6265SDimitry Andric //
12*81ad6265SDimitry Andric //===----------------------------------------------------------------------===//
13*81ad6265SDimitry Andric 
14*81ad6265SDimitry Andric #include <cassert>
15*81ad6265SDimitry Andric #include <cstdint>
16*81ad6265SDimitry Andric #include <iterator>
17*81ad6265SDimitry Andric #include <queue>
18*81ad6265SDimitry Andric #include <vector>
19*81ad6265SDimitry Andric 
20*81ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Solver.h"
21*81ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h"
22*81ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
23*81ad6265SDimitry Andric #include "llvm/ADT/DenseMap.h"
24*81ad6265SDimitry Andric #include "llvm/ADT/DenseSet.h"
25*81ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
26*81ad6265SDimitry Andric 
27*81ad6265SDimitry Andric namespace clang {
28*81ad6265SDimitry Andric namespace dataflow {
29*81ad6265SDimitry Andric 
30*81ad6265SDimitry Andric // `WatchedLiteralsSolver` is an implementation of Algorithm D from Knuth's
31*81ad6265SDimitry Andric // The Art of Computer Programming Volume 4: Satisfiability, Fascicle 6. It is
32*81ad6265SDimitry Andric // based on the backtracking DPLL algorithm [1], keeps references to a single
33*81ad6265SDimitry Andric // "watched" literal per clause, and uses a set of "active" variables to perform
34*81ad6265SDimitry Andric // unit propagation.
35*81ad6265SDimitry Andric //
36*81ad6265SDimitry Andric // The solver expects that its input is a boolean formula in conjunctive normal
37*81ad6265SDimitry Andric // form that consists of clauses of at least one literal. A literal is either a
38*81ad6265SDimitry Andric // boolean variable or its negation. Below we define types, data structures, and
39*81ad6265SDimitry Andric // utilities that are used to represent boolean formulas in conjunctive normal
40*81ad6265SDimitry Andric // form.
41*81ad6265SDimitry Andric //
42*81ad6265SDimitry Andric // [1] https://en.wikipedia.org/wiki/DPLL_algorithm
43*81ad6265SDimitry Andric 
44*81ad6265SDimitry Andric /// Boolean variables are represented as positive integers.
45*81ad6265SDimitry Andric using Variable = uint32_t;
46*81ad6265SDimitry Andric 
47*81ad6265SDimitry Andric /// A null boolean variable is used as a placeholder in various data structures
48*81ad6265SDimitry Andric /// and algorithms.
49*81ad6265SDimitry Andric static constexpr Variable NullVar = 0;
50*81ad6265SDimitry Andric 
51*81ad6265SDimitry Andric /// Literals are represented as positive integers. Specifically, for a boolean
52*81ad6265SDimitry Andric /// variable `V` that is represented as the positive integer `I`, the positive
53*81ad6265SDimitry Andric /// literal `V` is represented as the integer `2*I` and the negative literal
54*81ad6265SDimitry Andric /// `!V` is represented as the integer `2*I+1`.
55*81ad6265SDimitry Andric using Literal = uint32_t;
56*81ad6265SDimitry Andric 
57*81ad6265SDimitry Andric /// A null literal is used as a placeholder in various data structures and
58*81ad6265SDimitry Andric /// algorithms.
59*81ad6265SDimitry Andric static constexpr Literal NullLit = 0;
60*81ad6265SDimitry Andric 
61*81ad6265SDimitry Andric /// Returns the positive literal `V`.
62*81ad6265SDimitry Andric static constexpr Literal posLit(Variable V) { return 2 * V; }
63*81ad6265SDimitry Andric 
64*81ad6265SDimitry Andric /// Returns the negative literal `!V`.
65*81ad6265SDimitry Andric static constexpr Literal negLit(Variable V) { return 2 * V + 1; }
66*81ad6265SDimitry Andric 
67*81ad6265SDimitry Andric /// Returns the negated literal `!L`.
68*81ad6265SDimitry Andric static constexpr Literal notLit(Literal L) { return L ^ 1; }
69*81ad6265SDimitry Andric 
70*81ad6265SDimitry Andric /// Returns the variable of `L`.
71*81ad6265SDimitry Andric static constexpr Variable var(Literal L) { return L >> 1; }
72*81ad6265SDimitry Andric 
73*81ad6265SDimitry Andric /// Clause identifiers are represented as positive integers.
74*81ad6265SDimitry Andric using ClauseID = uint32_t;
75*81ad6265SDimitry Andric 
76*81ad6265SDimitry Andric /// A null clause identifier is used as a placeholder in various data structures
77*81ad6265SDimitry Andric /// and algorithms.
78*81ad6265SDimitry Andric static constexpr ClauseID NullClause = 0;
79*81ad6265SDimitry Andric 
80*81ad6265SDimitry Andric /// A boolean formula in conjunctive normal form.
81*81ad6265SDimitry Andric struct BooleanFormula {
82*81ad6265SDimitry Andric   /// `LargestVar` is equal to the largest positive integer that represents a
83*81ad6265SDimitry Andric   /// variable in the formula.
84*81ad6265SDimitry Andric   const Variable LargestVar;
85*81ad6265SDimitry Andric 
86*81ad6265SDimitry Andric   /// Literals of all clauses in the formula.
87*81ad6265SDimitry Andric   ///
88*81ad6265SDimitry Andric   /// The element at index 0 stands for the literal in the null clause. It is
89*81ad6265SDimitry Andric   /// set to 0 and isn't used. Literals of clauses in the formula start from the
90*81ad6265SDimitry Andric   /// element at index 1.
91*81ad6265SDimitry Andric   ///
92*81ad6265SDimitry Andric   /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of
93*81ad6265SDimitry Andric   /// `Clauses` will be `[0, L1, L2, L2, L3, L4]`.
94*81ad6265SDimitry Andric   std::vector<Literal> Clauses;
95*81ad6265SDimitry Andric 
96*81ad6265SDimitry Andric   /// Start indices of clauses of the formula in `Clauses`.
97*81ad6265SDimitry Andric   ///
98*81ad6265SDimitry Andric   /// The element at index 0 stands for the start index of the null clause. It
99*81ad6265SDimitry Andric   /// is set to 0 and isn't used. Start indices of clauses in the formula start
100*81ad6265SDimitry Andric   /// from the element at index 1.
101*81ad6265SDimitry Andric   ///
102*81ad6265SDimitry Andric   /// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of
103*81ad6265SDimitry Andric   /// `ClauseStarts` will be `[0, 1, 3]`. Note that the literals of the first
104*81ad6265SDimitry Andric   /// clause always start at index 1. The start index for the literals of the
105*81ad6265SDimitry Andric   /// second clause depends on the size of the first clause and so on.
106*81ad6265SDimitry Andric   std::vector<size_t> ClauseStarts;
107*81ad6265SDimitry Andric 
108*81ad6265SDimitry Andric   /// Maps literals (indices of the vector) to clause identifiers (elements of
109*81ad6265SDimitry Andric   /// the vector) that watch the respective literals.
110*81ad6265SDimitry Andric   ///
111*81ad6265SDimitry Andric   /// For a given clause, its watched literal is always its first literal in
112*81ad6265SDimitry Andric   /// `Clauses`. This invariant is maintained when watched literals change.
113*81ad6265SDimitry Andric   std::vector<ClauseID> WatchedHead;
114*81ad6265SDimitry Andric 
115*81ad6265SDimitry Andric   /// Maps clause identifiers (elements of the vector) to identifiers of other
116*81ad6265SDimitry Andric   /// clauses that watch the same literals, forming a set of linked lists.
117*81ad6265SDimitry Andric   ///
118*81ad6265SDimitry Andric   /// The element at index 0 stands for the identifier of the clause that
119*81ad6265SDimitry Andric   /// follows the null clause. It is set to 0 and isn't used. Identifiers of
120*81ad6265SDimitry Andric   /// clauses in the formula start from the element at index 1.
121*81ad6265SDimitry Andric   std::vector<ClauseID> NextWatched;
122*81ad6265SDimitry Andric 
123*81ad6265SDimitry Andric   explicit BooleanFormula(Variable LargestVar) : LargestVar(LargestVar) {
124*81ad6265SDimitry Andric     Clauses.push_back(0);
125*81ad6265SDimitry Andric     ClauseStarts.push_back(0);
126*81ad6265SDimitry Andric     NextWatched.push_back(0);
127*81ad6265SDimitry Andric     const size_t NumLiterals = 2 * LargestVar + 1;
128*81ad6265SDimitry Andric     WatchedHead.resize(NumLiterals + 1, 0);
129*81ad6265SDimitry Andric   }
130*81ad6265SDimitry Andric 
131*81ad6265SDimitry Andric   /// Adds the `L1 v L2 v L3` clause to the formula. If `L2` or `L3` are
132*81ad6265SDimitry Andric   /// `NullLit` they are respectively omitted from the clause.
133*81ad6265SDimitry Andric   ///
134*81ad6265SDimitry Andric   /// Requirements:
135*81ad6265SDimitry Andric   ///
136*81ad6265SDimitry Andric   ///  `L1` must not be `NullLit`.
137*81ad6265SDimitry Andric   ///
138*81ad6265SDimitry Andric   ///  All literals in the input that are not `NullLit` must be distinct.
139*81ad6265SDimitry Andric   void addClause(Literal L1, Literal L2 = NullLit, Literal L3 = NullLit) {
140*81ad6265SDimitry Andric     // The literals are guaranteed to be distinct from properties of BoolValue
141*81ad6265SDimitry Andric     // and the construction in `buildBooleanFormula`.
142*81ad6265SDimitry Andric     assert(L1 != NullLit && L1 != L2 && L1 != L3 &&
143*81ad6265SDimitry Andric            (L2 != L3 || L2 == NullLit));
144*81ad6265SDimitry Andric 
145*81ad6265SDimitry Andric     const ClauseID C = ClauseStarts.size();
146*81ad6265SDimitry Andric     const size_t S = Clauses.size();
147*81ad6265SDimitry Andric     ClauseStarts.push_back(S);
148*81ad6265SDimitry Andric 
149*81ad6265SDimitry Andric     Clauses.push_back(L1);
150*81ad6265SDimitry Andric     if (L2 != NullLit)
151*81ad6265SDimitry Andric       Clauses.push_back(L2);
152*81ad6265SDimitry Andric     if (L3 != NullLit)
153*81ad6265SDimitry Andric       Clauses.push_back(L3);
154*81ad6265SDimitry Andric 
155*81ad6265SDimitry Andric     // Designate the first literal as the "watched" literal of the clause.
156*81ad6265SDimitry Andric     NextWatched.push_back(WatchedHead[L1]);
157*81ad6265SDimitry Andric     WatchedHead[L1] = C;
158*81ad6265SDimitry Andric   }
159*81ad6265SDimitry Andric 
160*81ad6265SDimitry Andric   /// Returns the number of literals in clause `C`.
161*81ad6265SDimitry Andric   size_t clauseSize(ClauseID C) const {
162*81ad6265SDimitry Andric     return C == ClauseStarts.size() - 1 ? Clauses.size() - ClauseStarts[C]
163*81ad6265SDimitry Andric                                         : ClauseStarts[C + 1] - ClauseStarts[C];
164*81ad6265SDimitry Andric   }
165*81ad6265SDimitry Andric 
166*81ad6265SDimitry Andric   /// Returns the literals of clause `C`.
167*81ad6265SDimitry Andric   llvm::ArrayRef<Literal> clauseLiterals(ClauseID C) const {
168*81ad6265SDimitry Andric     return llvm::ArrayRef<Literal>(&Clauses[ClauseStarts[C]], clauseSize(C));
169*81ad6265SDimitry Andric   }
170*81ad6265SDimitry Andric };
171*81ad6265SDimitry Andric 
172*81ad6265SDimitry Andric /// Converts the conjunction of `Vals` into a formula in conjunctive normal
173*81ad6265SDimitry Andric /// form where each clause has at least one and at most three literals.
174*81ad6265SDimitry Andric BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
175*81ad6265SDimitry Andric   // The general strategy of the algorithm implemented below is to map each
176*81ad6265SDimitry Andric   // of the sub-values in `Vals` to a unique variable and use these variables in
177*81ad6265SDimitry Andric   // the resulting CNF expression to avoid exponential blow up. The number of
178*81ad6265SDimitry Andric   // literals in the resulting formula is guaranteed to be linear in the number
179*81ad6265SDimitry Andric   // of sub-values in `Vals`.
180*81ad6265SDimitry Andric 
181*81ad6265SDimitry Andric   // Map each sub-value in `Vals` to a unique variable.
182*81ad6265SDimitry Andric   llvm::DenseMap<BoolValue *, Variable> SubValsToVar;
183*81ad6265SDimitry Andric   Variable NextVar = 1;
184*81ad6265SDimitry Andric   {
185*81ad6265SDimitry Andric     std::queue<BoolValue *> UnprocessedSubVals;
186*81ad6265SDimitry Andric     for (BoolValue *Val : Vals)
187*81ad6265SDimitry Andric       UnprocessedSubVals.push(Val);
188*81ad6265SDimitry Andric     while (!UnprocessedSubVals.empty()) {
189*81ad6265SDimitry Andric       BoolValue *Val = UnprocessedSubVals.front();
190*81ad6265SDimitry Andric       UnprocessedSubVals.pop();
191*81ad6265SDimitry Andric 
192*81ad6265SDimitry Andric       if (!SubValsToVar.try_emplace(Val, NextVar).second)
193*81ad6265SDimitry Andric         continue;
194*81ad6265SDimitry Andric       ++NextVar;
195*81ad6265SDimitry Andric 
196*81ad6265SDimitry Andric       // Visit the sub-values of `Val`.
197*81ad6265SDimitry Andric       if (auto *C = dyn_cast<ConjunctionValue>(Val)) {
198*81ad6265SDimitry Andric         UnprocessedSubVals.push(&C->getLeftSubValue());
199*81ad6265SDimitry Andric         UnprocessedSubVals.push(&C->getRightSubValue());
200*81ad6265SDimitry Andric       } else if (auto *D = dyn_cast<DisjunctionValue>(Val)) {
201*81ad6265SDimitry Andric         UnprocessedSubVals.push(&D->getLeftSubValue());
202*81ad6265SDimitry Andric         UnprocessedSubVals.push(&D->getRightSubValue());
203*81ad6265SDimitry Andric       } else if (auto *N = dyn_cast<NegationValue>(Val)) {
204*81ad6265SDimitry Andric         UnprocessedSubVals.push(&N->getSubVal());
205*81ad6265SDimitry Andric       }
206*81ad6265SDimitry Andric     }
207*81ad6265SDimitry Andric   }
208*81ad6265SDimitry Andric 
209*81ad6265SDimitry Andric   auto GetVar = [&SubValsToVar](const BoolValue *Val) {
210*81ad6265SDimitry Andric     auto ValIt = SubValsToVar.find(Val);
211*81ad6265SDimitry Andric     assert(ValIt != SubValsToVar.end());
212*81ad6265SDimitry Andric     return ValIt->second;
213*81ad6265SDimitry Andric   };
214*81ad6265SDimitry Andric 
215*81ad6265SDimitry Andric   BooleanFormula Formula(NextVar - 1);
216*81ad6265SDimitry Andric   std::vector<bool> ProcessedSubVals(NextVar, false);
217*81ad6265SDimitry Andric 
218*81ad6265SDimitry Andric   // Add a conjunct for each variable that represents a top-level conjunction
219*81ad6265SDimitry Andric   // value in `Vals`.
220*81ad6265SDimitry Andric   for (BoolValue *Val : Vals)
221*81ad6265SDimitry Andric     Formula.addClause(posLit(GetVar(Val)));
222*81ad6265SDimitry Andric 
223*81ad6265SDimitry Andric   // Add conjuncts that represent the mapping between newly-created variables
224*81ad6265SDimitry Andric   // and their corresponding sub-values.
225*81ad6265SDimitry Andric   std::queue<BoolValue *> UnprocessedSubVals;
226*81ad6265SDimitry Andric   for (BoolValue *Val : Vals)
227*81ad6265SDimitry Andric     UnprocessedSubVals.push(Val);
228*81ad6265SDimitry Andric   while (!UnprocessedSubVals.empty()) {
229*81ad6265SDimitry Andric     const BoolValue *Val = UnprocessedSubVals.front();
230*81ad6265SDimitry Andric     UnprocessedSubVals.pop();
231*81ad6265SDimitry Andric     const Variable Var = GetVar(Val);
232*81ad6265SDimitry Andric 
233*81ad6265SDimitry Andric     if (ProcessedSubVals[Var])
234*81ad6265SDimitry Andric       continue;
235*81ad6265SDimitry Andric     ProcessedSubVals[Var] = true;
236*81ad6265SDimitry Andric 
237*81ad6265SDimitry Andric     if (auto *C = dyn_cast<ConjunctionValue>(Val)) {
238*81ad6265SDimitry Andric       const Variable LeftSubVar = GetVar(&C->getLeftSubValue());
239*81ad6265SDimitry Andric       const Variable RightSubVar = GetVar(&C->getRightSubValue());
240*81ad6265SDimitry Andric 
241*81ad6265SDimitry Andric       // `X <=> (A ^ B)` is equivalent to `(!X v A) ^ (!X v B) ^ (X v !A v !B)`
242*81ad6265SDimitry Andric       // which is already in conjunctive normal form. Below we add each of the
243*81ad6265SDimitry Andric       // conjuncts of the latter expression to the result.
244*81ad6265SDimitry Andric       Formula.addClause(negLit(Var), posLit(LeftSubVar));
245*81ad6265SDimitry Andric       Formula.addClause(negLit(Var), posLit(RightSubVar));
246*81ad6265SDimitry Andric       Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
247*81ad6265SDimitry Andric 
248*81ad6265SDimitry Andric       // Visit the sub-values of `Val`.
249*81ad6265SDimitry Andric       UnprocessedSubVals.push(&C->getLeftSubValue());
250*81ad6265SDimitry Andric       UnprocessedSubVals.push(&C->getRightSubValue());
251*81ad6265SDimitry Andric     } else if (auto *D = dyn_cast<DisjunctionValue>(Val)) {
252*81ad6265SDimitry Andric       const Variable LeftSubVar = GetVar(&D->getLeftSubValue());
253*81ad6265SDimitry Andric       const Variable RightSubVar = GetVar(&D->getRightSubValue());
254*81ad6265SDimitry Andric 
255*81ad6265SDimitry Andric       // `X <=> (A v B)` is equivalent to `(!X v A v B) ^ (X v !A) ^ (X v !B)`
256*81ad6265SDimitry Andric       // which is already in conjunctive normal form. Below we add each of the
257*81ad6265SDimitry Andric       // conjuncts of the latter expression to the result.
258*81ad6265SDimitry Andric       Formula.addClause(negLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
259*81ad6265SDimitry Andric       Formula.addClause(posLit(Var), negLit(LeftSubVar));
260*81ad6265SDimitry Andric       Formula.addClause(posLit(Var), negLit(RightSubVar));
261*81ad6265SDimitry Andric 
262*81ad6265SDimitry Andric       // Visit the sub-values of `Val`.
263*81ad6265SDimitry Andric       UnprocessedSubVals.push(&D->getLeftSubValue());
264*81ad6265SDimitry Andric       UnprocessedSubVals.push(&D->getRightSubValue());
265*81ad6265SDimitry Andric     } else if (auto *N = dyn_cast<NegationValue>(Val)) {
266*81ad6265SDimitry Andric       const Variable SubVar = GetVar(&N->getSubVal());
267*81ad6265SDimitry Andric 
268*81ad6265SDimitry Andric       // `X <=> !Y` is equivalent to `(!X v !Y) ^ (X v Y)` which is already in
269*81ad6265SDimitry Andric       // conjunctive normal form. Below we add each of the conjuncts of the
270*81ad6265SDimitry Andric       // latter expression to the result.
271*81ad6265SDimitry Andric       Formula.addClause(negLit(Var), negLit(SubVar));
272*81ad6265SDimitry Andric       Formula.addClause(posLit(Var), posLit(SubVar));
273*81ad6265SDimitry Andric 
274*81ad6265SDimitry Andric       // Visit the sub-values of `Val`.
275*81ad6265SDimitry Andric       UnprocessedSubVals.push(&N->getSubVal());
276*81ad6265SDimitry Andric     }
277*81ad6265SDimitry Andric   }
278*81ad6265SDimitry Andric 
279*81ad6265SDimitry Andric   return Formula;
280*81ad6265SDimitry Andric }
281*81ad6265SDimitry Andric 
282*81ad6265SDimitry Andric class WatchedLiteralsSolverImpl {
283*81ad6265SDimitry Andric   /// A boolean formula in conjunctive normal form that the solver will attempt
284*81ad6265SDimitry Andric   /// to prove satisfiable. The formula will be modified in the process.
285*81ad6265SDimitry Andric   BooleanFormula Formula;
286*81ad6265SDimitry Andric 
287*81ad6265SDimitry Andric   /// The search for a satisfying assignment of the variables in `Formula` will
288*81ad6265SDimitry Andric   /// proceed in levels, starting from 1 and going up to `Formula.LargestVar`
289*81ad6265SDimitry Andric   /// (inclusive). The current level is stored in `Level`. At each level the
290*81ad6265SDimitry Andric   /// solver will assign a value to an unassigned variable. If this leads to a
291*81ad6265SDimitry Andric   /// consistent partial assignment, `Level` will be incremented. Otherwise, if
292*81ad6265SDimitry Andric   /// it results in a conflict, the solver will backtrack by decrementing
293*81ad6265SDimitry Andric   /// `Level` until it reaches the most recent level where a decision was made.
294*81ad6265SDimitry Andric   size_t Level = 0;
295*81ad6265SDimitry Andric 
296*81ad6265SDimitry Andric   /// Maps levels (indices of the vector) to variables (elements of the vector)
297*81ad6265SDimitry Andric   /// that are assigned values at the respective levels.
298*81ad6265SDimitry Andric   ///
299*81ad6265SDimitry Andric   /// The element at index 0 isn't used. Variables start from the element at
300*81ad6265SDimitry Andric   /// index 1.
301*81ad6265SDimitry Andric   std::vector<Variable> LevelVars;
302*81ad6265SDimitry Andric 
303*81ad6265SDimitry Andric   /// State of the solver at a particular level.
304*81ad6265SDimitry Andric   enum class State : uint8_t {
305*81ad6265SDimitry Andric     /// Indicates that the solver made a decision.
306*81ad6265SDimitry Andric     Decision = 0,
307*81ad6265SDimitry Andric 
308*81ad6265SDimitry Andric     /// Indicates that the solver made a forced move.
309*81ad6265SDimitry Andric     Forced = 1,
310*81ad6265SDimitry Andric   };
311*81ad6265SDimitry Andric 
312*81ad6265SDimitry Andric   /// State of the solver at a particular level. It keeps track of previous
313*81ad6265SDimitry Andric   /// decisions that the solver can refer to when backtracking.
314*81ad6265SDimitry Andric   ///
315*81ad6265SDimitry Andric   /// The element at index 0 isn't used. States start from the element at index
316*81ad6265SDimitry Andric   /// 1.
317*81ad6265SDimitry Andric   std::vector<State> LevelStates;
318*81ad6265SDimitry Andric 
319*81ad6265SDimitry Andric   enum class Assignment : int8_t {
320*81ad6265SDimitry Andric     Unassigned = -1,
321*81ad6265SDimitry Andric     AssignedFalse = 0,
322*81ad6265SDimitry Andric     AssignedTrue = 1
323*81ad6265SDimitry Andric   };
324*81ad6265SDimitry Andric 
325*81ad6265SDimitry Andric   /// Maps variables (indices of the vector) to their assignments (elements of
326*81ad6265SDimitry Andric   /// the vector).
327*81ad6265SDimitry Andric   ///
328*81ad6265SDimitry Andric   /// The element at index 0 isn't used. Variable assignments start from the
329*81ad6265SDimitry Andric   /// element at index 1.
330*81ad6265SDimitry Andric   std::vector<Assignment> VarAssignments;
331*81ad6265SDimitry Andric 
332*81ad6265SDimitry Andric   /// A set of unassigned variables that appear in watched literals in
333*81ad6265SDimitry Andric   /// `Formula`. The vector is guaranteed to contain unique elements.
334*81ad6265SDimitry Andric   std::vector<Variable> ActiveVars;
335*81ad6265SDimitry Andric 
336*81ad6265SDimitry Andric public:
337*81ad6265SDimitry Andric   explicit WatchedLiteralsSolverImpl(const llvm::DenseSet<BoolValue *> &Vals)
338*81ad6265SDimitry Andric       : Formula(buildBooleanFormula(Vals)), LevelVars(Formula.LargestVar + 1),
339*81ad6265SDimitry Andric         LevelStates(Formula.LargestVar + 1) {
340*81ad6265SDimitry Andric     assert(!Vals.empty());
341*81ad6265SDimitry Andric 
342*81ad6265SDimitry Andric     // Initialize the state at the root level to a decision so that in
343*81ad6265SDimitry Andric     // `reverseForcedMoves` we don't have to check that `Level >= 0` on each
344*81ad6265SDimitry Andric     // iteration.
345*81ad6265SDimitry Andric     LevelStates[0] = State::Decision;
346*81ad6265SDimitry Andric 
347*81ad6265SDimitry Andric     // Initialize all variables as unassigned.
348*81ad6265SDimitry Andric     VarAssignments.resize(Formula.LargestVar + 1, Assignment::Unassigned);
349*81ad6265SDimitry Andric 
350*81ad6265SDimitry Andric     // Initialize the active variables.
351*81ad6265SDimitry Andric     for (Variable Var = Formula.LargestVar; Var != NullVar; --Var) {
352*81ad6265SDimitry Andric       if (isWatched(posLit(Var)) || isWatched(negLit(Var)))
353*81ad6265SDimitry Andric         ActiveVars.push_back(Var);
354*81ad6265SDimitry Andric     }
355*81ad6265SDimitry Andric   }
356*81ad6265SDimitry Andric 
357*81ad6265SDimitry Andric   Solver::Result solve() && {
358*81ad6265SDimitry Andric     size_t I = 0;
359*81ad6265SDimitry Andric     while (I < ActiveVars.size()) {
360*81ad6265SDimitry Andric       // Assert that the following invariants hold:
361*81ad6265SDimitry Andric       // 1. All active variables are unassigned.
362*81ad6265SDimitry Andric       // 2. All active variables form watched literals.
363*81ad6265SDimitry Andric       // 3. Unassigned variables that form watched literals are active.
364*81ad6265SDimitry Andric       // FIXME: Consider replacing these with test cases that fail if the any
365*81ad6265SDimitry Andric       // of the invariants is broken. That might not be easy due to the
366*81ad6265SDimitry Andric       // transformations performed by `buildBooleanFormula`.
367*81ad6265SDimitry Andric       assert(activeVarsAreUnassigned());
368*81ad6265SDimitry Andric       assert(activeVarsFormWatchedLiterals());
369*81ad6265SDimitry Andric       assert(unassignedVarsFormingWatchedLiteralsAreActive());
370*81ad6265SDimitry Andric 
371*81ad6265SDimitry Andric       const Variable ActiveVar = ActiveVars[I];
372*81ad6265SDimitry Andric 
373*81ad6265SDimitry Andric       // Look for unit clauses that contain the active variable.
374*81ad6265SDimitry Andric       const bool unitPosLit = watchedByUnitClause(posLit(ActiveVar));
375*81ad6265SDimitry Andric       const bool unitNegLit = watchedByUnitClause(negLit(ActiveVar));
376*81ad6265SDimitry Andric       if (unitPosLit && unitNegLit) {
377*81ad6265SDimitry Andric         // We found a conflict!
378*81ad6265SDimitry Andric 
379*81ad6265SDimitry Andric         // Backtrack and rewind the `Level` until the most recent non-forced
380*81ad6265SDimitry Andric         // assignment.
381*81ad6265SDimitry Andric         reverseForcedMoves();
382*81ad6265SDimitry Andric 
383*81ad6265SDimitry Andric         // If the root level is reached, then all possible assignments lead to
384*81ad6265SDimitry Andric         // a conflict.
385*81ad6265SDimitry Andric         if (Level == 0)
386*81ad6265SDimitry Andric           return WatchedLiteralsSolver::Result::Unsatisfiable;
387*81ad6265SDimitry Andric 
388*81ad6265SDimitry Andric         // Otherwise, take the other branch at the most recent level where a
389*81ad6265SDimitry Andric         // decision was made.
390*81ad6265SDimitry Andric         LevelStates[Level] = State::Forced;
391*81ad6265SDimitry Andric         const Variable Var = LevelVars[Level];
392*81ad6265SDimitry Andric         VarAssignments[Var] = VarAssignments[Var] == Assignment::AssignedTrue
393*81ad6265SDimitry Andric                                   ? Assignment::AssignedFalse
394*81ad6265SDimitry Andric                                   : Assignment::AssignedTrue;
395*81ad6265SDimitry Andric 
396*81ad6265SDimitry Andric         updateWatchedLiterals();
397*81ad6265SDimitry Andric       } else if (unitPosLit || unitNegLit) {
398*81ad6265SDimitry Andric         // We found a unit clause! The value of its unassigned variable is
399*81ad6265SDimitry Andric         // forced.
400*81ad6265SDimitry Andric         ++Level;
401*81ad6265SDimitry Andric 
402*81ad6265SDimitry Andric         LevelVars[Level] = ActiveVar;
403*81ad6265SDimitry Andric         LevelStates[Level] = State::Forced;
404*81ad6265SDimitry Andric         VarAssignments[ActiveVar] =
405*81ad6265SDimitry Andric             unitPosLit ? Assignment::AssignedTrue : Assignment::AssignedFalse;
406*81ad6265SDimitry Andric 
407*81ad6265SDimitry Andric         // Remove the variable that was just assigned from the set of active
408*81ad6265SDimitry Andric         // variables.
409*81ad6265SDimitry Andric         if (I + 1 < ActiveVars.size()) {
410*81ad6265SDimitry Andric           // Replace the variable that was just assigned with the last active
411*81ad6265SDimitry Andric           // variable for efficient removal.
412*81ad6265SDimitry Andric           ActiveVars[I] = ActiveVars.back();
413*81ad6265SDimitry Andric         } else {
414*81ad6265SDimitry Andric           // This was the last active variable. Repeat the process from the
415*81ad6265SDimitry Andric           // beginning.
416*81ad6265SDimitry Andric           I = 0;
417*81ad6265SDimitry Andric         }
418*81ad6265SDimitry Andric         ActiveVars.pop_back();
419*81ad6265SDimitry Andric 
420*81ad6265SDimitry Andric         updateWatchedLiterals();
421*81ad6265SDimitry Andric       } else if (I + 1 == ActiveVars.size()) {
422*81ad6265SDimitry Andric         // There are no remaining unit clauses in the formula! Make a decision
423*81ad6265SDimitry Andric         // for one of the active variables at the current level.
424*81ad6265SDimitry Andric         ++Level;
425*81ad6265SDimitry Andric 
426*81ad6265SDimitry Andric         LevelVars[Level] = ActiveVar;
427*81ad6265SDimitry Andric         LevelStates[Level] = State::Decision;
428*81ad6265SDimitry Andric         VarAssignments[ActiveVar] = decideAssignment(ActiveVar);
429*81ad6265SDimitry Andric 
430*81ad6265SDimitry Andric         // Remove the variable that was just assigned from the set of active
431*81ad6265SDimitry Andric         // variables.
432*81ad6265SDimitry Andric         ActiveVars.pop_back();
433*81ad6265SDimitry Andric 
434*81ad6265SDimitry Andric         updateWatchedLiterals();
435*81ad6265SDimitry Andric 
436*81ad6265SDimitry Andric         // This was the last active variable. Repeat the process from the
437*81ad6265SDimitry Andric         // beginning.
438*81ad6265SDimitry Andric         I = 0;
439*81ad6265SDimitry Andric       } else {
440*81ad6265SDimitry Andric         ++I;
441*81ad6265SDimitry Andric       }
442*81ad6265SDimitry Andric     }
443*81ad6265SDimitry Andric     return WatchedLiteralsSolver::Result::Satisfiable;
444*81ad6265SDimitry Andric   }
445*81ad6265SDimitry Andric 
446*81ad6265SDimitry Andric private:
447*81ad6265SDimitry Andric   // Reverses forced moves until the most recent level where a decision was made
448*81ad6265SDimitry Andric   // on the assignment of a variable.
449*81ad6265SDimitry Andric   void reverseForcedMoves() {
450*81ad6265SDimitry Andric     for (; LevelStates[Level] == State::Forced; --Level) {
451*81ad6265SDimitry Andric       const Variable Var = LevelVars[Level];
452*81ad6265SDimitry Andric 
453*81ad6265SDimitry Andric       VarAssignments[Var] = Assignment::Unassigned;
454*81ad6265SDimitry Andric 
455*81ad6265SDimitry Andric       // If the variable that we pass through is watched then we add it to the
456*81ad6265SDimitry Andric       // active variables.
457*81ad6265SDimitry Andric       if (isWatched(posLit(Var)) || isWatched(negLit(Var)))
458*81ad6265SDimitry Andric         ActiveVars.push_back(Var);
459*81ad6265SDimitry Andric     }
460*81ad6265SDimitry Andric   }
461*81ad6265SDimitry Andric 
462*81ad6265SDimitry Andric   // Updates watched literals that are affected by a variable assignment.
463*81ad6265SDimitry Andric   void updateWatchedLiterals() {
464*81ad6265SDimitry Andric     const Variable Var = LevelVars[Level];
465*81ad6265SDimitry Andric 
466*81ad6265SDimitry Andric     // Update the watched literals of clauses that currently watch the literal
467*81ad6265SDimitry Andric     // that falsifies `Var`.
468*81ad6265SDimitry Andric     const Literal FalseLit = VarAssignments[Var] == Assignment::AssignedTrue
469*81ad6265SDimitry Andric                                  ? negLit(Var)
470*81ad6265SDimitry Andric                                  : posLit(Var);
471*81ad6265SDimitry Andric     ClauseID FalseLitWatcher = Formula.WatchedHead[FalseLit];
472*81ad6265SDimitry Andric     Formula.WatchedHead[FalseLit] = NullClause;
473*81ad6265SDimitry Andric     while (FalseLitWatcher != NullClause) {
474*81ad6265SDimitry Andric       const ClauseID NextFalseLitWatcher = Formula.NextWatched[FalseLitWatcher];
475*81ad6265SDimitry Andric 
476*81ad6265SDimitry Andric       // Pick the first non-false literal as the new watched literal.
477*81ad6265SDimitry Andric       const size_t FalseLitWatcherStart = Formula.ClauseStarts[FalseLitWatcher];
478*81ad6265SDimitry Andric       size_t NewWatchedLitIdx = FalseLitWatcherStart + 1;
479*81ad6265SDimitry Andric       while (isCurrentlyFalse(Formula.Clauses[NewWatchedLitIdx]))
480*81ad6265SDimitry Andric         ++NewWatchedLitIdx;
481*81ad6265SDimitry Andric       const Literal NewWatchedLit = Formula.Clauses[NewWatchedLitIdx];
482*81ad6265SDimitry Andric       const Variable NewWatchedLitVar = var(NewWatchedLit);
483*81ad6265SDimitry Andric 
484*81ad6265SDimitry Andric       // Swap the old watched literal for the new one in `FalseLitWatcher` to
485*81ad6265SDimitry Andric       // maintain the invariant that the watched literal is at the beginning of
486*81ad6265SDimitry Andric       // the clause.
487*81ad6265SDimitry Andric       Formula.Clauses[NewWatchedLitIdx] = FalseLit;
488*81ad6265SDimitry Andric       Formula.Clauses[FalseLitWatcherStart] = NewWatchedLit;
489*81ad6265SDimitry Andric 
490*81ad6265SDimitry Andric       // If the new watched literal isn't watched by any other clause and its
491*81ad6265SDimitry Andric       // variable isn't assigned we need to add it to the active variables.
492*81ad6265SDimitry Andric       if (!isWatched(NewWatchedLit) && !isWatched(notLit(NewWatchedLit)) &&
493*81ad6265SDimitry Andric           VarAssignments[NewWatchedLitVar] == Assignment::Unassigned)
494*81ad6265SDimitry Andric         ActiveVars.push_back(NewWatchedLitVar);
495*81ad6265SDimitry Andric 
496*81ad6265SDimitry Andric       Formula.NextWatched[FalseLitWatcher] = Formula.WatchedHead[NewWatchedLit];
497*81ad6265SDimitry Andric       Formula.WatchedHead[NewWatchedLit] = FalseLitWatcher;
498*81ad6265SDimitry Andric 
499*81ad6265SDimitry Andric       // Go to the next clause that watches `FalseLit`.
500*81ad6265SDimitry Andric       FalseLitWatcher = NextFalseLitWatcher;
501*81ad6265SDimitry Andric     }
502*81ad6265SDimitry Andric   }
503*81ad6265SDimitry Andric 
504*81ad6265SDimitry Andric   /// Returns true if and only if one of the clauses that watch `Lit` is a unit
505*81ad6265SDimitry Andric   /// clause.
506*81ad6265SDimitry Andric   bool watchedByUnitClause(Literal Lit) const {
507*81ad6265SDimitry Andric     for (ClauseID LitWatcher = Formula.WatchedHead[Lit];
508*81ad6265SDimitry Andric          LitWatcher != NullClause;
509*81ad6265SDimitry Andric          LitWatcher = Formula.NextWatched[LitWatcher]) {
510*81ad6265SDimitry Andric       llvm::ArrayRef<Literal> Clause = Formula.clauseLiterals(LitWatcher);
511*81ad6265SDimitry Andric 
512*81ad6265SDimitry Andric       // Assert the invariant that the watched literal is always the first one
513*81ad6265SDimitry Andric       // in the clause.
514*81ad6265SDimitry Andric       // FIXME: Consider replacing this with a test case that fails if the
515*81ad6265SDimitry Andric       // invariant is broken by `updateWatchedLiterals`. That might not be easy
516*81ad6265SDimitry Andric       // due to the transformations performed by `buildBooleanFormula`.
517*81ad6265SDimitry Andric       assert(Clause.front() == Lit);
518*81ad6265SDimitry Andric 
519*81ad6265SDimitry Andric       if (isUnit(Clause))
520*81ad6265SDimitry Andric         return true;
521*81ad6265SDimitry Andric     }
522*81ad6265SDimitry Andric     return false;
523*81ad6265SDimitry Andric   }
524*81ad6265SDimitry Andric 
525*81ad6265SDimitry Andric   /// Returns true if and only if `Clause` is a unit clause.
526*81ad6265SDimitry Andric   bool isUnit(llvm::ArrayRef<Literal> Clause) const {
527*81ad6265SDimitry Andric     return llvm::all_of(Clause.drop_front(),
528*81ad6265SDimitry Andric                         [this](Literal L) { return isCurrentlyFalse(L); });
529*81ad6265SDimitry Andric   }
530*81ad6265SDimitry Andric 
531*81ad6265SDimitry Andric   /// Returns true if and only if `Lit` evaluates to `false` in the current
532*81ad6265SDimitry Andric   /// partial assignment.
533*81ad6265SDimitry Andric   bool isCurrentlyFalse(Literal Lit) const {
534*81ad6265SDimitry Andric     return static_cast<int8_t>(VarAssignments[var(Lit)]) ==
535*81ad6265SDimitry Andric            static_cast<int8_t>(Lit & 1);
536*81ad6265SDimitry Andric   }
537*81ad6265SDimitry Andric 
538*81ad6265SDimitry Andric   /// Returns true if and only if `Lit` is watched by a clause in `Formula`.
539*81ad6265SDimitry Andric   bool isWatched(Literal Lit) const {
540*81ad6265SDimitry Andric     return Formula.WatchedHead[Lit] != NullClause;
541*81ad6265SDimitry Andric   }
542*81ad6265SDimitry Andric 
543*81ad6265SDimitry Andric   /// Returns an assignment for an unassigned variable.
544*81ad6265SDimitry Andric   Assignment decideAssignment(Variable Var) const {
545*81ad6265SDimitry Andric     return !isWatched(posLit(Var)) || isWatched(negLit(Var))
546*81ad6265SDimitry Andric                ? Assignment::AssignedFalse
547*81ad6265SDimitry Andric                : Assignment::AssignedTrue;
548*81ad6265SDimitry Andric   }
549*81ad6265SDimitry Andric 
550*81ad6265SDimitry Andric   /// Returns a set of all watched literals.
551*81ad6265SDimitry Andric   llvm::DenseSet<Literal> watchedLiterals() const {
552*81ad6265SDimitry Andric     llvm::DenseSet<Literal> WatchedLiterals;
553*81ad6265SDimitry Andric     for (Literal Lit = 2; Lit < Formula.WatchedHead.size(); Lit++) {
554*81ad6265SDimitry Andric       if (Formula.WatchedHead[Lit] == NullClause)
555*81ad6265SDimitry Andric         continue;
556*81ad6265SDimitry Andric       WatchedLiterals.insert(Lit);
557*81ad6265SDimitry Andric     }
558*81ad6265SDimitry Andric     return WatchedLiterals;
559*81ad6265SDimitry Andric   }
560*81ad6265SDimitry Andric 
561*81ad6265SDimitry Andric   /// Returns true if and only if all active variables are unassigned.
562*81ad6265SDimitry Andric   bool activeVarsAreUnassigned() const {
563*81ad6265SDimitry Andric     return llvm::all_of(ActiveVars, [this](Variable Var) {
564*81ad6265SDimitry Andric       return VarAssignments[Var] == Assignment::Unassigned;
565*81ad6265SDimitry Andric     });
566*81ad6265SDimitry Andric   }
567*81ad6265SDimitry Andric 
568*81ad6265SDimitry Andric   /// Returns true if and only if all active variables form watched literals.
569*81ad6265SDimitry Andric   bool activeVarsFormWatchedLiterals() const {
570*81ad6265SDimitry Andric     const llvm::DenseSet<Literal> WatchedLiterals = watchedLiterals();
571*81ad6265SDimitry Andric     return llvm::all_of(ActiveVars, [&WatchedLiterals](Variable Var) {
572*81ad6265SDimitry Andric       return WatchedLiterals.contains(posLit(Var)) ||
573*81ad6265SDimitry Andric              WatchedLiterals.contains(negLit(Var));
574*81ad6265SDimitry Andric     });
575*81ad6265SDimitry Andric   }
576*81ad6265SDimitry Andric 
577*81ad6265SDimitry Andric   /// Returns true if and only if all unassigned variables that are forming
578*81ad6265SDimitry Andric   /// watched literals are active.
579*81ad6265SDimitry Andric   bool unassignedVarsFormingWatchedLiteralsAreActive() const {
580*81ad6265SDimitry Andric     const llvm::DenseSet<Variable> ActiveVarsSet(ActiveVars.begin(),
581*81ad6265SDimitry Andric                                                  ActiveVars.end());
582*81ad6265SDimitry Andric     for (Literal Lit : watchedLiterals()) {
583*81ad6265SDimitry Andric       const Variable Var = var(Lit);
584*81ad6265SDimitry Andric       if (VarAssignments[Var] != Assignment::Unassigned)
585*81ad6265SDimitry Andric         continue;
586*81ad6265SDimitry Andric       if (ActiveVarsSet.contains(Var))
587*81ad6265SDimitry Andric         continue;
588*81ad6265SDimitry Andric       return false;
589*81ad6265SDimitry Andric     }
590*81ad6265SDimitry Andric     return true;
591*81ad6265SDimitry Andric   }
592*81ad6265SDimitry Andric };
593*81ad6265SDimitry Andric 
594*81ad6265SDimitry Andric Solver::Result WatchedLiteralsSolver::solve(llvm::DenseSet<BoolValue *> Vals) {
595*81ad6265SDimitry Andric   return Vals.empty() ? WatchedLiteralsSolver::Result::Satisfiable
596*81ad6265SDimitry Andric                       : WatchedLiteralsSolverImpl(Vals).solve();
597*81ad6265SDimitry Andric }
598*81ad6265SDimitry Andric 
599*81ad6265SDimitry Andric } // namespace dataflow
600*81ad6265SDimitry Andric } // namespace clang
601