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::AtomicBool: {
237 Atomics[Var] = cast<AtomicBoolValue>(Val);
238 break;
239 }
240 default:
241 llvm_unreachable("buildBooleanFormula: unhandled value kind");
242 }
243 }
244 }
245
246 auto GetVar = [&SubValsToVar](const BoolValue *Val) {
247 auto ValIt = SubValsToVar.find(Val);
248 assert(ValIt != SubValsToVar.end());
249 return ValIt->second;
250 };
251
252 BooleanFormula Formula(NextVar - 1, std::move(Atomics));
253 std::vector<bool> ProcessedSubVals(NextVar, false);
254
255 // Add a conjunct for each variable that represents a top-level conjunction
256 // value in `Vals`.
257 for (BoolValue *Val : Vals)
258 Formula.addClause(posLit(GetVar(Val)));
259
260 // Add conjuncts that represent the mapping between newly-created variables
261 // and their corresponding sub-values.
262 std::queue<BoolValue *> UnprocessedSubVals;
263 for (BoolValue *Val : Vals)
264 UnprocessedSubVals.push(Val);
265 while (!UnprocessedSubVals.empty()) {
266 const BoolValue *Val = UnprocessedSubVals.front();
267 UnprocessedSubVals.pop();
268 const Variable Var = GetVar(Val);
269
270 if (ProcessedSubVals[Var])
271 continue;
272 ProcessedSubVals[Var] = true;
273
274 if (auto *C = dyn_cast<ConjunctionValue>(Val)) {
275 const Variable LeftSubVar = GetVar(&C->getLeftSubValue());
276 const Variable RightSubVar = GetVar(&C->getRightSubValue());
277
278 if (LeftSubVar == RightSubVar) {
279 // `X <=> (A ^ A)` is equivalent to `(!X v A) ^ (X v !A)` which is
280 // already in conjunctive normal form. Below we add each of the
281 // conjuncts of the latter expression to the result.
282 Formula.addClause(negLit(Var), posLit(LeftSubVar));
283 Formula.addClause(posLit(Var), negLit(LeftSubVar));
284
285 // Visit a sub-value of `Val` (pick any, they are identical).
286 UnprocessedSubVals.push(&C->getLeftSubValue());
287 } else {
288 // `X <=> (A ^ B)` is equivalent to `(!X v A) ^ (!X v B) ^ (X v !A v !B)`
289 // which is already in conjunctive normal form. Below we add each of the
290 // conjuncts of the latter expression to the result.
291 Formula.addClause(negLit(Var), posLit(LeftSubVar));
292 Formula.addClause(negLit(Var), posLit(RightSubVar));
293 Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
294
295 // Visit the sub-values of `Val`.
296 UnprocessedSubVals.push(&C->getLeftSubValue());
297 UnprocessedSubVals.push(&C->getRightSubValue());
298 }
299 } else if (auto *D = dyn_cast<DisjunctionValue>(Val)) {
300 const Variable LeftSubVar = GetVar(&D->getLeftSubValue());
301 const Variable RightSubVar = GetVar(&D->getRightSubValue());
302
303 if (LeftSubVar == RightSubVar) {
304 // `X <=> (A v A)` is equivalent to `(!X v A) ^ (X v !A)` which is
305 // already in conjunctive normal form. Below we add each of the
306 // conjuncts of the latter expression to the result.
307 Formula.addClause(negLit(Var), posLit(LeftSubVar));
308 Formula.addClause(posLit(Var), negLit(LeftSubVar));
309
310 // Visit a sub-value of `Val` (pick any, they are identical).
311 UnprocessedSubVals.push(&D->getLeftSubValue());
312 } else {
313 // `X <=> (A v B)` is equivalent to `(!X v A v B) ^ (X v !A) ^ (X v !B)`
314 // which is already in conjunctive normal form. Below we add each of the
315 // conjuncts of the latter expression to the result.
316 Formula.addClause(negLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
317 Formula.addClause(posLit(Var), negLit(LeftSubVar));
318 Formula.addClause(posLit(Var), negLit(RightSubVar));
319
320 // Visit the sub-values of `Val`.
321 UnprocessedSubVals.push(&D->getLeftSubValue());
322 UnprocessedSubVals.push(&D->getRightSubValue());
323 }
324 } else if (auto *N = dyn_cast<NegationValue>(Val)) {
325 const Variable SubVar = GetVar(&N->getSubVal());
326
327 // `X <=> !Y` is equivalent to `(!X v !Y) ^ (X v Y)` which is already in
328 // conjunctive normal form. Below we add each of the conjuncts of the
329 // latter expression to the result.
330 Formula.addClause(negLit(Var), negLit(SubVar));
331 Formula.addClause(posLit(Var), posLit(SubVar));
332
333 // Visit the sub-values of `Val`.
334 UnprocessedSubVals.push(&N->getSubVal());
335 } else if (auto *I = dyn_cast<ImplicationValue>(Val)) {
336 const Variable LeftSubVar = GetVar(&I->getLeftSubValue());
337 const Variable RightSubVar = GetVar(&I->getRightSubValue());
338
339 // `X <=> (A => B)` is equivalent to
340 // `(X v A) ^ (X v !B) ^ (!X v !A v B)` which is already in
341 // conjunctive normal form. Below we add each of the conjuncts of the
342 // latter expression to the result.
343 Formula.addClause(posLit(Var), posLit(LeftSubVar));
344 Formula.addClause(posLit(Var), negLit(RightSubVar));
345 Formula.addClause(negLit(Var), negLit(LeftSubVar), posLit(RightSubVar));
346
347 // Visit the sub-values of `Val`.
348 UnprocessedSubVals.push(&I->getLeftSubValue());
349 UnprocessedSubVals.push(&I->getRightSubValue());
350 } else if (auto *B = dyn_cast<BiconditionalValue>(Val)) {
351 const Variable LeftSubVar = GetVar(&B->getLeftSubValue());
352 const Variable RightSubVar = GetVar(&B->getRightSubValue());
353
354 if (LeftSubVar == RightSubVar) {
355 // `X <=> (A <=> A)` is equvalent to `X` which is already in
356 // conjunctive normal form. Below we add each of the conjuncts of the
357 // latter expression to the result.
358 Formula.addClause(posLit(Var));
359
360 // No need to visit the sub-values of `Val`.
361 } else {
362 // `X <=> (A <=> B)` is equivalent to
363 // `(X v A v B) ^ (X v !A v !B) ^ (!X v A v !B) ^ (!X v !A v B)` which is
364 // already in conjunctive normal form. Below we add each of the conjuncts
365 // of the latter expression to the result.
366 Formula.addClause(posLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
367 Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
368 Formula.addClause(negLit(Var), posLit(LeftSubVar), negLit(RightSubVar));
369 Formula.addClause(negLit(Var), negLit(LeftSubVar), posLit(RightSubVar));
370
371 // Visit the sub-values of `Val`.
372 UnprocessedSubVals.push(&B->getLeftSubValue());
373 UnprocessedSubVals.push(&B->getRightSubValue());
374 }
375 }
376 }
377
378 return Formula;
379 }
380
381 class WatchedLiteralsSolverImpl {
382 /// A boolean formula in conjunctive normal form that the solver will attempt
383 /// to prove satisfiable. The formula will be modified in the process.
384 BooleanFormula Formula;
385
386 /// The search for a satisfying assignment of the variables in `Formula` will
387 /// proceed in levels, starting from 1 and going up to `Formula.LargestVar`
388 /// (inclusive). The current level is stored in `Level`. At each level the
389 /// solver will assign a value to an unassigned variable. If this leads to a
390 /// consistent partial assignment, `Level` will be incremented. Otherwise, if
391 /// it results in a conflict, the solver will backtrack by decrementing
392 /// `Level` until it reaches the most recent level where a decision was made.
393 size_t Level = 0;
394
395 /// Maps levels (indices of the vector) to variables (elements of the vector)
396 /// that are assigned values at the respective levels.
397 ///
398 /// The element at index 0 isn't used. Variables start from the element at
399 /// index 1.
400 std::vector<Variable> LevelVars;
401
402 /// State of the solver at a particular level.
403 enum class State : uint8_t {
404 /// Indicates that the solver made a decision.
405 Decision = 0,
406
407 /// Indicates that the solver made a forced move.
408 Forced = 1,
409 };
410
411 /// State of the solver at a particular level. It keeps track of previous
412 /// decisions that the solver can refer to when backtracking.
413 ///
414 /// The element at index 0 isn't used. States start from the element at index
415 /// 1.
416 std::vector<State> LevelStates;
417
418 enum class Assignment : int8_t {
419 Unassigned = -1,
420 AssignedFalse = 0,
421 AssignedTrue = 1
422 };
423
424 /// Maps variables (indices of the vector) to their assignments (elements of
425 /// the vector).
426 ///
427 /// The element at index 0 isn't used. Variable assignments start from the
428 /// element at index 1.
429 std::vector<Assignment> VarAssignments;
430
431 /// A set of unassigned variables that appear in watched literals in
432 /// `Formula`. The vector is guaranteed to contain unique elements.
433 std::vector<Variable> ActiveVars;
434
435 public:
WatchedLiteralsSolverImpl(const llvm::DenseSet<BoolValue * > & Vals)436 explicit WatchedLiteralsSolverImpl(const llvm::DenseSet<BoolValue *> &Vals)
437 : Formula(buildBooleanFormula(Vals)), LevelVars(Formula.LargestVar + 1),
438 LevelStates(Formula.LargestVar + 1) {
439 assert(!Vals.empty());
440
441 // Initialize the state at the root level to a decision so that in
442 // `reverseForcedMoves` we don't have to check that `Level >= 0` on each
443 // iteration.
444 LevelStates[0] = State::Decision;
445
446 // Initialize all variables as unassigned.
447 VarAssignments.resize(Formula.LargestVar + 1, Assignment::Unassigned);
448
449 // Initialize the active variables.
450 for (Variable Var = Formula.LargestVar; Var != NullVar; --Var) {
451 if (isWatched(posLit(Var)) || isWatched(negLit(Var)))
452 ActiveVars.push_back(Var);
453 }
454 }
455
solve()456 Solver::Result solve() && {
457 size_t I = 0;
458 while (I < ActiveVars.size()) {
459 // Assert that the following invariants hold:
460 // 1. All active variables are unassigned.
461 // 2. All active variables form watched literals.
462 // 3. Unassigned variables that form watched literals are active.
463 // FIXME: Consider replacing these with test cases that fail if the any
464 // of the invariants is broken. That might not be easy due to the
465 // transformations performed by `buildBooleanFormula`.
466 assert(activeVarsAreUnassigned());
467 assert(activeVarsFormWatchedLiterals());
468 assert(unassignedVarsFormingWatchedLiteralsAreActive());
469
470 const Variable ActiveVar = ActiveVars[I];
471
472 // Look for unit clauses that contain the active variable.
473 const bool unitPosLit = watchedByUnitClause(posLit(ActiveVar));
474 const bool unitNegLit = watchedByUnitClause(negLit(ActiveVar));
475 if (unitPosLit && unitNegLit) {
476 // We found a conflict!
477
478 // Backtrack and rewind the `Level` until the most recent non-forced
479 // assignment.
480 reverseForcedMoves();
481
482 // If the root level is reached, then all possible assignments lead to
483 // a conflict.
484 if (Level == 0)
485 return Solver::Result::Unsatisfiable();
486
487 // Otherwise, take the other branch at the most recent level where a
488 // decision was made.
489 LevelStates[Level] = State::Forced;
490 const Variable Var = LevelVars[Level];
491 VarAssignments[Var] = VarAssignments[Var] == Assignment::AssignedTrue
492 ? Assignment::AssignedFalse
493 : Assignment::AssignedTrue;
494
495 updateWatchedLiterals();
496 } else if (unitPosLit || unitNegLit) {
497 // We found a unit clause! The value of its unassigned variable is
498 // forced.
499 ++Level;
500
501 LevelVars[Level] = ActiveVar;
502 LevelStates[Level] = State::Forced;
503 VarAssignments[ActiveVar] =
504 unitPosLit ? Assignment::AssignedTrue : Assignment::AssignedFalse;
505
506 // Remove the variable that was just assigned from the set of active
507 // variables.
508 if (I + 1 < ActiveVars.size()) {
509 // Replace the variable that was just assigned with the last active
510 // variable for efficient removal.
511 ActiveVars[I] = ActiveVars.back();
512 } else {
513 // This was the last active variable. Repeat the process from the
514 // beginning.
515 I = 0;
516 }
517 ActiveVars.pop_back();
518
519 updateWatchedLiterals();
520 } else if (I + 1 == ActiveVars.size()) {
521 // There are no remaining unit clauses in the formula! Make a decision
522 // for one of the active variables at the current level.
523 ++Level;
524
525 LevelVars[Level] = ActiveVar;
526 LevelStates[Level] = State::Decision;
527 VarAssignments[ActiveVar] = decideAssignment(ActiveVar);
528
529 // Remove the variable that was just assigned from the set of active
530 // variables.
531 ActiveVars.pop_back();
532
533 updateWatchedLiterals();
534
535 // This was the last active variable. Repeat the process from the
536 // beginning.
537 I = 0;
538 } else {
539 ++I;
540 }
541 }
542 return Solver::Result::Satisfiable(buildSolution());
543 }
544
545 private:
546 /// Returns a satisfying truth assignment to the atomic values in the boolean
547 /// formula.
548 llvm::DenseMap<AtomicBoolValue *, Solver::Result::Assignment>
buildSolution()549 buildSolution() {
550 llvm::DenseMap<AtomicBoolValue *, Solver::Result::Assignment> Solution;
551 for (auto &Atomic : Formula.Atomics) {
552 // A variable may have a definite true/false assignment, or it may be
553 // unassigned indicating its truth value does not affect the result of
554 // the formula. Unassigned variables are assigned to true as a default.
555 Solution[Atomic.second] =
556 VarAssignments[Atomic.first] == Assignment::AssignedFalse
557 ? Solver::Result::Assignment::AssignedFalse
558 : Solver::Result::Assignment::AssignedTrue;
559 }
560 return Solution;
561 }
562
563 /// Reverses forced moves until the most recent level where a decision was
564 /// made on the assignment of a variable.
reverseForcedMoves()565 void reverseForcedMoves() {
566 for (; LevelStates[Level] == State::Forced; --Level) {
567 const Variable Var = LevelVars[Level];
568
569 VarAssignments[Var] = Assignment::Unassigned;
570
571 // If the variable that we pass through is watched then we add it to the
572 // active variables.
573 if (isWatched(posLit(Var)) || isWatched(negLit(Var)))
574 ActiveVars.push_back(Var);
575 }
576 }
577
578 /// Updates watched literals that are affected by a variable assignment.
updateWatchedLiterals()579 void updateWatchedLiterals() {
580 const Variable Var = LevelVars[Level];
581
582 // Update the watched literals of clauses that currently watch the literal
583 // that falsifies `Var`.
584 const Literal FalseLit = VarAssignments[Var] == Assignment::AssignedTrue
585 ? negLit(Var)
586 : posLit(Var);
587 ClauseID FalseLitWatcher = Formula.WatchedHead[FalseLit];
588 Formula.WatchedHead[FalseLit] = NullClause;
589 while (FalseLitWatcher != NullClause) {
590 const ClauseID NextFalseLitWatcher = Formula.NextWatched[FalseLitWatcher];
591
592 // Pick the first non-false literal as the new watched literal.
593 const size_t FalseLitWatcherStart = Formula.ClauseStarts[FalseLitWatcher];
594 size_t NewWatchedLitIdx = FalseLitWatcherStart + 1;
595 while (isCurrentlyFalse(Formula.Clauses[NewWatchedLitIdx]))
596 ++NewWatchedLitIdx;
597 const Literal NewWatchedLit = Formula.Clauses[NewWatchedLitIdx];
598 const Variable NewWatchedLitVar = var(NewWatchedLit);
599
600 // Swap the old watched literal for the new one in `FalseLitWatcher` to
601 // maintain the invariant that the watched literal is at the beginning of
602 // the clause.
603 Formula.Clauses[NewWatchedLitIdx] = FalseLit;
604 Formula.Clauses[FalseLitWatcherStart] = NewWatchedLit;
605
606 // If the new watched literal isn't watched by any other clause and its
607 // variable isn't assigned we need to add it to the active variables.
608 if (!isWatched(NewWatchedLit) && !isWatched(notLit(NewWatchedLit)) &&
609 VarAssignments[NewWatchedLitVar] == Assignment::Unassigned)
610 ActiveVars.push_back(NewWatchedLitVar);
611
612 Formula.NextWatched[FalseLitWatcher] = Formula.WatchedHead[NewWatchedLit];
613 Formula.WatchedHead[NewWatchedLit] = FalseLitWatcher;
614
615 // Go to the next clause that watches `FalseLit`.
616 FalseLitWatcher = NextFalseLitWatcher;
617 }
618 }
619
620 /// Returns true if and only if one of the clauses that watch `Lit` is a unit
621 /// clause.
watchedByUnitClause(Literal Lit) const622 bool watchedByUnitClause(Literal Lit) const {
623 for (ClauseID LitWatcher = Formula.WatchedHead[Lit];
624 LitWatcher != NullClause;
625 LitWatcher = Formula.NextWatched[LitWatcher]) {
626 llvm::ArrayRef<Literal> Clause = Formula.clauseLiterals(LitWatcher);
627
628 // Assert the invariant that the watched literal is always the first one
629 // in the clause.
630 // FIXME: Consider replacing this with a test case that fails if the
631 // invariant is broken by `updateWatchedLiterals`. That might not be easy
632 // due to the transformations performed by `buildBooleanFormula`.
633 assert(Clause.front() == Lit);
634
635 if (isUnit(Clause))
636 return true;
637 }
638 return false;
639 }
640
641 /// Returns true if and only if `Clause` is a unit clause.
isUnit(llvm::ArrayRef<Literal> Clause) const642 bool isUnit(llvm::ArrayRef<Literal> Clause) const {
643 return llvm::all_of(Clause.drop_front(),
644 [this](Literal L) { return isCurrentlyFalse(L); });
645 }
646
647 /// Returns true if and only if `Lit` evaluates to `false` in the current
648 /// partial assignment.
isCurrentlyFalse(Literal Lit) const649 bool isCurrentlyFalse(Literal Lit) const {
650 return static_cast<int8_t>(VarAssignments[var(Lit)]) ==
651 static_cast<int8_t>(Lit & 1);
652 }
653
654 /// Returns true if and only if `Lit` is watched by a clause in `Formula`.
isWatched(Literal Lit) const655 bool isWatched(Literal Lit) const {
656 return Formula.WatchedHead[Lit] != NullClause;
657 }
658
659 /// Returns an assignment for an unassigned variable.
decideAssignment(Variable Var) const660 Assignment decideAssignment(Variable Var) const {
661 return !isWatched(posLit(Var)) || isWatched(negLit(Var))
662 ? Assignment::AssignedFalse
663 : Assignment::AssignedTrue;
664 }
665
666 /// Returns a set of all watched literals.
watchedLiterals() const667 llvm::DenseSet<Literal> watchedLiterals() const {
668 llvm::DenseSet<Literal> WatchedLiterals;
669 for (Literal Lit = 2; Lit < Formula.WatchedHead.size(); Lit++) {
670 if (Formula.WatchedHead[Lit] == NullClause)
671 continue;
672 WatchedLiterals.insert(Lit);
673 }
674 return WatchedLiterals;
675 }
676
677 /// Returns true if and only if all active variables are unassigned.
activeVarsAreUnassigned() const678 bool activeVarsAreUnassigned() const {
679 return llvm::all_of(ActiveVars, [this](Variable Var) {
680 return VarAssignments[Var] == Assignment::Unassigned;
681 });
682 }
683
684 /// Returns true if and only if all active variables form watched literals.
activeVarsFormWatchedLiterals() const685 bool activeVarsFormWatchedLiterals() const {
686 const llvm::DenseSet<Literal> WatchedLiterals = watchedLiterals();
687 return llvm::all_of(ActiveVars, [&WatchedLiterals](Variable Var) {
688 return WatchedLiterals.contains(posLit(Var)) ||
689 WatchedLiterals.contains(negLit(Var));
690 });
691 }
692
693 /// Returns true if and only if all unassigned variables that are forming
694 /// watched literals are active.
unassignedVarsFormingWatchedLiteralsAreActive() const695 bool unassignedVarsFormingWatchedLiteralsAreActive() const {
696 const llvm::DenseSet<Variable> ActiveVarsSet(ActiveVars.begin(),
697 ActiveVars.end());
698 for (Literal Lit : watchedLiterals()) {
699 const Variable Var = var(Lit);
700 if (VarAssignments[Var] != Assignment::Unassigned)
701 continue;
702 if (ActiveVarsSet.contains(Var))
703 continue;
704 return false;
705 }
706 return true;
707 }
708 };
709
solve(llvm::DenseSet<BoolValue * > Vals)710 Solver::Result WatchedLiteralsSolver::solve(llvm::DenseSet<BoolValue *> Vals) {
711 return Vals.empty() ? Solver::Result::Satisfiable({{}})
712 : WatchedLiteralsSolverImpl(Vals).solve();
713 }
714
715 } // namespace dataflow
716 } // namespace clang
717