CIRCT 23.0.0git
Loading...
Searching...
No Matches
SATSolver.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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 incremental SAT solvers with an IPASIR-style interface.
10//
11//===----------------------------------------------------------------------===//
12
14#include "llvm/ADT/ArrayRef.h"
15#include "llvm/ADT/SmallVector.h"
16#include "llvm/Support/SMTAPI.h"
17
18#include <cassert>
19#include <cstdlib>
20#include <string>
21
22namespace circt {
23
24namespace {
25
26#if LLVM_WITH_Z3
27class Z3SATSolver : public IncrementalSATSolver {
28public:
29 Z3SATSolver() : solver(llvm::CreateZ3Solver()) {}
30
31 ~Z3SATSolver() override { clearSolveScope(); }
32
33 void add(int lit) override {
34 clearSolveScope();
35 if (lit == 0) {
36 addClauseInternal(clauseBuf);
37 clauseBuf.clear();
38 return;
39 }
40
41 const int absLit = std::abs(lit);
42 if (absLit > maxVariable)
43 reserveVars(absLit);
44
45 clauseBuf.push_back(lit);
46 }
47
48 void assume(int lit) override {
49 clearSolveScope();
50 if (lit == 0)
51 return;
52 assumptions.push_back(lit);
53 }
54
55 Result solve() override {
56 clearSolveScope();
57 solver->push();
58 solveScopeActive = true;
59 for (int lit : assumptions)
60 solver->addConstraint(literalToExpr(lit));
61 assumptions.clear();
62 auto result = solver->check();
63 if (!result)
64 return lastResult = kUNKNOWN;
65 return lastResult = (*result ? kSAT : kUNSAT);
66 }
67
68 int val(int v) const override {
69 if (lastResult != kSAT || v <= 0 || v > maxVariable)
70 return 0;
71 llvm::APSInt value(llvm::APInt(1, 0), true);
72 // Z3 returns an interpretation for all variables, even those not involved
73 // in the problem. If the variable is not involved, return 0 to indicate
74 // "undefined" rather than a potentially misleading true/false value.
75 if (!solver->getInterpretation(variables[v - 1], value))
76 return 0;
77 if (value != 0)
78 return v;
79 return -v;
80 }
81
82 void reserveVars(int maxVar) override {
83 if (maxVar <= maxVariable)
84 return;
85 while (static_cast<int>(variables.size()) < maxVar)
86 newVariable();
87 maxVariable = maxVar;
88 }
89
90private:
91 void clearSolveScope() {
92 if (!solveScopeActive)
93 return;
94 solver->pop();
95 solveScopeActive = false;
96 lastResult = kUNKNOWN;
97 }
98
99 int newVariable() {
100 int varIndex = static_cast<int>(variables.size()) + 1;
101 std::string name = "v" + std::to_string(varIndex);
102 variables.push_back(solver->mkSymbol(name.c_str(), solver->getBoolSort()));
103 return varIndex;
104 }
105
106 llvm::SMTExprRef literalToExpr(int lit) {
107 int absLit = std::abs(lit);
108 // Ensure variable exists for this literal.
109 reserveVars(absLit);
110 auto *variable = variables[absLit - 1];
111 return lit > 0 ? variable : solver->mkNot(variable);
112 }
113
114 void addClauseInternal(llvm::ArrayRef<int> lits) {
115 if (lits.empty()) {
116 solver->addConstraint(solver->mkBoolean(false));
117 return;
118 }
119
120 llvm::SMTExprRef clause = nullptr;
121 for (int lit : lits) {
122 if (lit == 0)
123 continue;
124 auto *expr = literalToExpr(lit);
125 clause = clause ? solver->mkOr(clause, expr) : expr;
126 }
127
128 if (!clause) {
129 solver->addConstraint(solver->mkBoolean(false));
130 return;
131 }
132
133 solver->addConstraint(clause);
134 }
135
136 llvm::SMTSolverRef solver;
137 llvm::SmallVector<llvm::SMTExprRef> variables;
138 llvm::SmallVector<int> assumptions, clauseBuf;
139 int maxVariable = 0;
140 Result lastResult = kUNKNOWN;
141 bool solveScopeActive = false;
142};
143#endif // LLVM_WITH_Z3
144
145} // namespace
146
147std::unique_ptr<IncrementalSATSolver> createZ3SATSolver() {
148#if LLVM_WITH_Z3
149 return std::make_unique<Z3SATSolver>();
150#else
151 return {};
152#endif
153}
154
155} // namespace circt
static void solve(Term *lhs, Term *rhs)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< IncrementalSATSolver > createZ3SATSolver()
Construct a Z3-backed incremental IPASIR-style SAT solver.