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