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