23#include "mlir/IR/Builders.h"
24#include "mlir/IR/OperationSupport.h"
25#include "mlir/IR/PatternMatch.h"
26#include "mlir/Transforms/WalkPatternRewriteDriver.h"
27#include "llvm/ADT/ArrayRef.h"
28#include "llvm/ADT/STLExtras.h"
29#include "llvm/ADT/SmallVector.h"
30#include "llvm/Support/DebugLog.h"
37#define GEN_PASS_DEF_EXACTSYNTHESIS
38#include "circt/Dialect/Synth/Transforms/SynthPasses.h.inc"
46#define DEBUG_TYPE "synth-exact-synthesis"
50static constexpr unsigned kMaxExactSynthesisInputs = 6;
52static SmallString<32> formatTruthTable(
const APInt &truthTable) {
54 truthTable.toStringUnsigned(text, 16);
58using BooleanLogicConcept =
59 circt::synth::detail::BooleanLogicOpInterfaceInterfaceTraits::Concept;
61struct ExactCandidatePolicy {
62 bool mayUseConstantSource =
true;
63 bool enumerateInputInversions =
true;
72struct ExactSignalRef {
76 bool inverted =
false;
79struct ExactNetworkStep {
80 const ExactNodeInfo *info =
nullptr;
81 SmallVector<ExactSignalRef, 3> fanins;
83 unsigned getInversionMask()
const;
84 bool operator<(
const ExactNetworkStep &rhs)
const;
88 unsigned numInputs = 0;
89 SmallVector<ExactNetworkStep, 4> steps;
90 ExactSignalRef output;
93using ExactCandidate = ExactNetworkStep;
98 ExactNodeInfo(OperationName opName,
unsigned arity,
bool commutative,
99 const BooleanLogicConcept *iface,
100 ExactCandidatePolicy candidatePolicy)
101 : opName(opName), arity(arity), commutative(commutative), iface(iface),
102 candidatePolicy(candidatePolicy) {}
104 OperationName getOperationName()
const {
return opName; }
105 unsigned getArity()
const {
return arity; }
106 bool isCommutative()
const {
return commutative; }
107 bool mayUseConstantSource()
const {
108 return candidatePolicy.mayUseConstantSource;
110 bool shouldEnumerateInputInversions()
const {
111 return candidatePolicy.enumerateInputInversions;
115 void emitConditionedCNF(
117 const ExactCandidate &candidate,
unsigned minterm,
118 llvm::function_ref<
int(
unsigned source,
unsigned minterm,
bool inverted)>
119 getSourceLiteral)
const;
120 Value materialize(OpBuilder &builder, Location loc, ArrayRef<Value> operands,
121 ArrayRef<bool> inverted)
const {
122 return iface->createBooleanLogicOp(builder, loc, operands, inverted);
126 OperationName opName;
129 const BooleanLogicConcept *iface;
130 ExactCandidatePolicy candidatePolicy;
133struct ExactSynthesisPolicy {
134 SmallVector<ExactNodeInfo, 4> primitiveInfos;
137static SmallString<64>
138formatPrimitiveSummary(
const ExactSynthesisPolicy &policy) {
139 SmallString<64> text;
140 llvm::raw_svector_ostream os(text);
141 llvm::interleaveComma(policy.primitiveInfos, os, [&](
const auto &info) {
142 os << info.getOperationName().getStringRef() <<
":" << info.getArity();
147unsigned ExactNetworkStep::getInversionMask()
const {
149 for (
auto [index, fanin] : llvm::enumerate(fanins))
155bool ExactNetworkStep::operator<(
const ExactNetworkStep &rhs)
const {
156 if (fanins.size() != rhs.fanins.size())
157 return fanins.size() < rhs.fanins.size();
158 for (
size_t i = 0, e = fanins.size(); i != e; ++i) {
159 if (fanins[i].source != rhs.fanins[i].source)
160 return fanins[i].source < rhs.fanins[i].source;
162 if (info != rhs.info) {
163 if (info->getOperationName() != rhs.info->getOperationName())
164 return info->getOperationName().getStringRef() <
165 rhs.info->getOperationName().getStringRef();
167 return getInversionMask() < rhs.getInversionMask();
170static std::optional<ExactNetwork> synthesizeDirect(
unsigned numInputs,
171 const APInt &target) {
172 ExactNetwork network;
173 network.numInputs = numInputs;
174 if (target.isZero()) {
175 network.output = {0,
false};
178 if (target.isAllOnes()) {
179 network.output = {0,
true};
183 for (
unsigned input = 0; input != numInputs; ++input) {
185 if (target == mask) {
186 network.output = {1 + input,
false};
189 APInt invertedMask = mask;
190 invertedMask.flipAllBits();
191 if (target == invertedMask) {
192 network.output = {1 + input,
true};
204class ExactCandidateEnumerator {
206 void enumerate(
const ExactSynthesisPolicy &policy,
unsigned availableSources,
207 SmallVectorImpl<ExactCandidate> &candidates)
const;
210 static void enumerateCommutativeOperandSources(
211 unsigned availableSources,
unsigned arity,
unsigned currentArity,
212 unsigned nextSource, SmallVectorImpl<unsigned> &sources,
213 llvm::function_ref<
void(ArrayRef<unsigned>)>
emit);
215 static void enumerateOrderedOperandSources(
216 unsigned availableSources,
unsigned arity,
unsigned firstSource,
217 unsigned currentArity, SmallVectorImpl<unsigned> &sources,
218 llvm::function_ref<
void(ArrayRef<unsigned>)>
emit);
221 enumerateNodeCandidates(
const ExactNodeInfo &info,
unsigned availableSources,
222 SmallVectorImpl<ExactCandidate> &candidates);
230class ExactNetworkMaterializer {
232 ExactNetworkMaterializer(OpBuilder &builder, Location loc,
233 ArrayRef<Value> inputs);
235 Value materialize(
const ExactNetwork &network);
239 Value getRawSignal(ExactSignalRef signal, ArrayRef<Value> stepValues);
240 Value materializeInverter(Value input);
244 ArrayRef<Value> inputs;
245 std::array<Value, 2> constValues;
252class GenericExactSATProblem {
254 GenericExactSATProblem(
const ExactSynthesisPolicy &policy,
256 const APInt &target,
unsigned numSteps);
258 std::optional<ExactNetwork> solve();
263 int getSourceValueVar(
unsigned source,
unsigned minterm)
const;
265 int getSourceLiteral(
unsigned source,
unsigned minterm,
bool inverted)
const;
269 bool buildEncoding();
273 void addCandidateSemanticsConstraints();
276 void addUseAllStepsConstraints();
278 ExactNetwork decodeModel()
const;
280 const ExactSynthesisPolicy &policy;
285 unsigned numMinterms;
286 unsigned totalSources;
287 int rootInvertVar = 0;
288 SmallVector<SmallVector<int, 16>, 8> sourceValueVars;
289 SmallVector<SmallVector<ExactCandidate, 64>, 8> stepCandidates;
290 SmallVector<SmallVector<int, 64>, 8> stepSelectionVars;
291 ExactCandidateEnumerator enumerator;
294void ExactNodeInfo::emitConditionedCNF(
296 const ExactCandidate &candidate,
unsigned minterm,
297 llvm::function_ref<
int(
unsigned source,
unsigned minterm,
bool inverted)>
298 getSourceLiteral)
const {
299 auto addConditionedClause = [&](ArrayRef<int> literals) {
300 SmallVector<int, 8> clause;
301 clause.reserve(literals.size() + 1);
302 clause.push_back(-selector);
303 clause.append(literals.begin(), literals.end());
310 SmallVector<int, 4> inputLits;
311 inputLits.reserve(getArity());
312 for (
unsigned operand = 0; operand != getArity(); ++operand) {
313 const auto &fanin = candidate.fanins[operand];
315 getSourceLiteral(fanin.source, minterm, fanin.inverted));
317 iface->emitCNFWithoutInversion(outLit, inputLits, addConditionedClause,
318 [&] {
return solver.
newVar(); });
321void ExactCandidateEnumerator::enumerate(
322 const ExactSynthesisPolicy &policy,
unsigned availableSources,
323 SmallVectorImpl<ExactCandidate> &candidates)
const {
325 for (
const auto &info : policy.primitiveInfos)
326 enumerateNodeCandidates(info, availableSources, candidates);
327 llvm::sort(candidates);
328 LDBG() <<
"Enumerated " << candidates.size()
329 <<
" candidates with availableSources=" << availableSources <<
"\n";
332void ExactCandidateEnumerator::enumerateCommutativeOperandSources(
333 unsigned availableSources,
unsigned arity,
unsigned currentArity,
334 unsigned nextSource, SmallVectorImpl<unsigned> &sources,
335 llvm::function_ref<
void(ArrayRef<unsigned>)>
emit) {
336 if (currentArity == arity) {
341 for (
unsigned source = nextSource; source < availableSources; ++source) {
342 sources.push_back(source);
343 enumerateCommutativeOperandSources(
344 availableSources, arity, currentArity + 1, source + 1, sources,
emit);
349void ExactCandidateEnumerator::enumerateOrderedOperandSources(
350 unsigned availableSources,
unsigned arity,
unsigned firstSource,
351 unsigned currentArity, SmallVectorImpl<unsigned> &sources,
352 llvm::function_ref<
void(ArrayRef<unsigned>)>
emit) {
353 if (currentArity == arity) {
360 for (
unsigned source = firstSource; source < availableSources; ++source) {
361 sources.push_back(source);
362 enumerateOrderedOperandSources(availableSources, arity, firstSource,
363 currentArity + 1, sources,
emit);
368void ExactCandidateEnumerator::enumerateNodeCandidates(
369 const ExactNodeInfo &info,
unsigned availableSources,
370 SmallVectorImpl<ExactCandidate> &candidates) {
371 SmallVector<unsigned, 3> sources;
372 auto emitCandidate = [&](ArrayRef<unsigned> operandSources) {
373 unsigned numInversionMasks =
374 info.shouldEnumerateInputInversions() ? (1u << info.getArity()) : 1;
375 for (
unsigned invMask = 0; invMask != numInversionMasks; ++invMask) {
376 ExactCandidate candidate;
377 candidate.info = &info;
378 for (
auto [index, source] : llvm::enumerate(operandSources))
379 candidate.fanins.push_back(
380 {source,
static_cast<bool>(invMask & (1u << index))});
381 candidates.push_back(std::move(candidate));
387 unsigned firstSource = info.mayUseConstantSource() ? 0 : 1;
388 if (info.isCommutative()) {
396 enumerateCommutativeOperandSources(availableSources, info.getArity(),
397 0, firstSource, sources,
402 enumerateOrderedOperandSources(availableSources, info.getArity(), firstSource,
403 0, sources, emitCandidate);
406ExactNetworkMaterializer::ExactNetworkMaterializer(OpBuilder &builder,
408 ArrayRef<Value> inputs)
409 : builder(builder), loc(loc), inputs(inputs) {}
411Value ExactNetworkMaterializer::materialize(
const ExactNetwork &network) {
412 SmallVector<Value, 4> stepValues;
413 stepValues.reserve(network.steps.size());
414 for (
const auto &step : network.steps) {
415 assert(step.info &&
"network step must carry node info");
416 const auto &
info = *step.info;
417 SmallVector<Value, 3> operands;
418 SmallVector<bool, 3> inverted;
419 operands.reserve(
info.getArity());
420 inverted.reserve(
info.getArity());
421 for (
const auto &fanin : step.fanins) {
422 operands.push_back(getRawSignal(fanin, stepValues));
423 inverted.push_back(fanin.inverted);
425 stepValues.push_back(
info.materialize(builder, loc, operands, inverted));
428 if (network.output.source == 0)
431 Value result = getRawSignal(network.output, stepValues);
432 if (!network.output.inverted)
434 return materializeInverter(result);
437Value ExactNetworkMaterializer::getConstant(
bool value) {
438 if (constValues[value])
439 return constValues[value];
440 return constValues[value] =
444Value ExactNetworkMaterializer::getRawSignal(ExactSignalRef signal,
445 ArrayRef<Value> stepValues) {
446 if (signal.source == 0)
448 if (signal.source <= inputs.size())
449 return inputs[signal.source - 1];
451 unsigned stepIndex = signal.source - (inputs.size() + 1);
452 assert(stepIndex < stepValues.size() &&
"invalid synthesized step index");
453 return stepValues[stepIndex];
456Value ExactNetworkMaterializer::materializeInverter(Value input) {
457 return aig::AndInverterOp::create(builder, loc, input,
true);
460GenericExactSATProblem::GenericExactSATProblem(
462 unsigned numInputs,
const APInt &target,
unsigned numSteps)
463 : policy(policy), solver(solver), numInputs(numInputs), target(target),
464 numSteps(numSteps), numMinterms(1u << numInputs),
465 totalSources(1 + numInputs + numSteps) {}
467std::optional<ExactNetwork> GenericExactSATProblem::solve() {
468 LDBG() <<
"SAT solve start: inputs=" << numInputs <<
" steps=" << numSteps
469 <<
" minterms=" << numMinterms <<
" target=0x"
470 << formatTruthTable(target) <<
"\n";
471 if (!buildEncoding())
473 auto result = solver.
solve();
474 LDBG() <<
"SAT solve result: "
481 return decodeModel();
484int GenericExactSATProblem::newVar() {
return solver.newVar(); }
486int GenericExactSATProblem::getSourceValueVar(
unsigned source,
487 unsigned minterm)
const {
488 return sourceValueVars[source][minterm];
491int GenericExactSATProblem::getSourceLiteral(
unsigned source,
unsigned minterm,
492 bool inverted)
const {
493 int lit = getSourceValueVar(source, minterm);
494 return inverted ? -
lit :
lit;
497bool GenericExactSATProblem::buildEncoding() {
500 sourceValueVars.resize(totalSources);
501 for (
unsigned source = 0; source != totalSources; ++source) {
502 sourceValueVars[source].reserve(numMinterms);
503 for (
unsigned minterm = 0; minterm != numMinterms; ++minterm)
504 sourceValueVars[source].push_back(newVar());
508 for (
unsigned minterm = 0; minterm != numMinterms; ++minterm)
509 solver.addClause({-getSourceValueVar(0, minterm)});
513 for (
unsigned input = 0; input != numInputs; ++input)
514 for (
unsigned minterm = 0; minterm != numMinterms; ++minterm)
515 solver.addClause({((minterm >> input) & 1)
516 ? getSourceValueVar(1 + input, minterm)
517 : -getSourceValueVar(1 + input, minterm)});
520 stepCandidates.resize(numSteps);
521 stepSelectionVars.resize(numSteps);
522 for (
unsigned step = 0; step != numSteps; ++step) {
523 unsigned availableSources = 1 + numInputs + step;
524 enumerator.enumerate(policy, availableSources, stepCandidates[step]);
525 LDBG() <<
" step " << step <<
": availableSources=" << availableSources
526 <<
" candidates=" << stepCandidates[step].size() <<
"\n";
527 if (stepCandidates[step].
empty())
530 auto &selectionVars = stepSelectionVars[step];
531 selectionVars.reserve(stepCandidates[step].size());
532 for (
size_t i = 0, e = stepCandidates[step].size(); i != e; ++i)
533 selectionVars.push_back(newVar());
535 selectionVars, [&](ArrayRef<int> clause) { solver.addClause(clause); },
536 [&] {
return newVar(); });
542 addCandidateSemanticsConstraints();
543 addUseAllStepsConstraints();
547 unsigned rootSource = totalSources - 1;
548 rootInvertVar = newVar();
549 for (
unsigned minterm = 0; minterm != numMinterms; ++minterm) {
550 int rootLit = getSourceValueVar(rootSource, minterm);
551 if (target[minterm]) {
553 solver.addClause({rootLit, rootInvertVar});
554 solver.addClause({-rootLit, -rootInvertVar});
557 solver.addClause({rootLit, -rootInvertVar});
558 solver.addClause({-rootLit, rootInvertVar});
564void GenericExactSATProblem::addCandidateSemanticsConstraints() {
565 for (
unsigned step = 0; step != numSteps; ++step) {
566 unsigned outSource = 1 + numInputs + step;
567 const auto &selectionVars = stepSelectionVars[step];
570 for (
auto [candidateIndex, candidate] :
571 llvm::enumerate(stepCandidates[step]))
572 for (unsigned minterm = 0; minterm != numMinterms; ++minterm) {
573 assert(candidate.info &&
"candidate must carry node info");
574 candidate.info->emitConditionedCNF(
575 solver, selectionVars[candidateIndex],
576 getSourceValueVar(outSource, minterm), candidate, minterm,
577 [&](
unsigned source,
unsigned currentMinterm,
bool inverted) {
578 return getSourceLiteral(source, currentMinterm, inverted);
584void GenericExactSATProblem::addUseAllStepsConstraints() {
585 for (
unsigned step = 0; step + 1 < numSteps; ++step) {
586 unsigned source = 1 + numInputs + step;
587 SmallVector<int, 32> users;
588 for (
unsigned userStep = step + 1; userStep != numSteps; ++userStep)
589 for (
auto [candidateIndex, candidate] :
590 llvm::enumerate(stepCandidates[userStep]))
591 if (
llvm::any_of(candidate.fanins, [&](const ExactSignalRef &fanin) {
592 return fanin.source == source;
594 users.push_back(stepSelectionVars[userStep][candidateIndex]);
598 solver.addClause(users);
602ExactNetwork GenericExactSATProblem::decodeModel()
const {
603 ExactNetwork network;
604 network.numInputs = numInputs;
605 network.steps.reserve(numSteps);
606 for (
unsigned step = 0; step != numSteps; ++step) {
607 const auto &selectionVars = stepSelectionVars[step];
608 const auto &candidates = stepCandidates[step];
609 for (
size_t i = 0, e = selectionVars.size(); i != e; ++i) {
610 if (solver.val(selectionVars[i]) != selectionVars[i])
612 network.steps.push_back(candidates[i]);
616 network.output = {1 + numInputs + numSteps - 1,
617 solver.val(rootInvertVar) == rootInvertVar};
618 LDBG() <<
"Decoded network with " << network.steps.size()
619 <<
" steps, rootSource=" << network.output.source
620 <<
" rootInvert=" << network.output.inverted <<
"\n";
624static FailureOr<Value>
625exactSynthesizeAreaMinimized(OpBuilder &builder, Location loc, APInt truthTable,
626 ArrayRef<Value> operands,
627 const ExactSynthesisPolicy &policy,
628 StringRef satSolver,
unsigned maxArea) {
629 ExactNetworkMaterializer materializer(builder, loc, operands);
630 unsigned numInputs = operands.size();
631 LDBG() <<
"Exact synthesis request: inputs=" << numInputs <<
" truthTable=0x"
632 << formatTruthTable(truthTable)
633 <<
" allowed-primitives=" << formatPrimitiveSummary(policy)
634 <<
" sat-solver=" << satSolver <<
"\n";
636 if (policy.primitiveInfos.empty())
639 LDBG() <<
"Trying direct synthesis for target=0x"
640 << formatTruthTable(truthTable) <<
"\n";
641 auto network = synthesizeDirect(numInputs, truthTable);
643 LDBG() <<
"Using direct synthesis result\n";
644 return materializer.materialize(*network);
647 for (
unsigned area = 1; area <= maxArea; ++area) {
648 LDBG() <<
"Trying area=" << area <<
"\n";
652 GenericExactSATProblem problem(policy, *solver, numInputs, truthTable,
654 auto solved = problem.solve();
656 LDBG() <<
"Area " << area <<
" has no solution\n";
659 LDBG() <<
"Found solution at area=" << area <<
"\n";
660 return materializer.materialize(*solved);
662 LDBG() <<
"No exact solution found up to area limit " << maxArea <<
"\n";
670struct ExactSynthesisStatistics {
671 unsigned numSolved = 0;
672 unsigned numUnsolved = 0;
676 ExactSynthesisPattern(MLIRContext *
context,
677 const ExactSynthesisPolicy &policy, StringRef satSolver,
678 unsigned maxInputs,
unsigned maxArea,
679 ExactSynthesisStatistics &statistics)
681 maxInputs(maxInputs), maxArea(maxArea), statistics(statistics) {}
683 LogicalResult matchAndRewrite(comb::TruthTableOp op,
684 PatternRewriter &rewriter)
const override {
685 if (op.getInputs().size() > maxInputs) {
686 ++statistics.numUnsolved;
690 SmallVector<Value> operands;
691 operands.reserve(op.getInputs().size());
695 for (Value operand :
llvm::reverse(op.getInputs()))
696 operands.push_back(operand);
698 APInt truthTable(op.getLookupTable().size(), 0);
699 for (
size_t index = 0, e = op.getLookupTable().size(); index != e; ++index)
700 truthTable.setBitVal(index, op.getLookupTable()[index]);
702 exactSynthesizeAreaMinimized(rewriter, op.getLoc(), truthTable,
703 operands, policy, satSolver, maxArea);
704 if (failed(result)) {
705 ++statistics.numUnsolved;
709 rewriter.replaceOp(op, *result);
710 ++statistics.numSolved;
715 const ExactSynthesisPolicy &policy;
716 std::string satSolver;
719 ExactSynthesisStatistics &statistics;
722struct ExactSynthesisPass
723 :
public circt::synth::impl::ExactSynthesisBase<ExactSynthesisPass> {
724 using ExactSynthesisBase::ExactSynthesisBase;
726 FailureOr<ExactSynthesisPolicy> parsePolicy(MLIRContext *
context)
const {
727 ExactSynthesisPolicy policy;
729 if (allowedOps.empty()) {
730 emitError(UnknownLoc::get(
context))
731 <<
"synth-exact-synthesis requires at least one "
732 "'allowed-ops=name:arity' entry";
736 for (
const std::string &allowedOp : allowedOps) {
737 StringRef spelling = allowedOp;
738 auto parts = spelling.split(
':');
739 StringRef name = parts.first.trim();
740 StringRef arityText = parts.second.trim();
741 auto registeredInfo = RegisteredOperationName::lookup(name,
context);
742 if (!registeredInfo) {
743 emitError(UnknownLoc::get(
context))
744 <<
"unknown allowed exact-synthesis op '" << name <<
"'";
747 auto *iface = registeredInfo->getInterface<BooleanLogicOpInterface>();
749 emitError(UnknownLoc::get(
context))
750 <<
"op '" << name <<
"' does not implement BooleanLogicOpInterface";
755 if (arityText.empty() || arityText.getAsInteger(10, arity)) {
756 emitError(UnknownLoc::get(
context))
757 <<
"expected allowed exact-synthesis op in 'name:arity' form, "
762 if (arity < 2 || arity > kMaxExactSynthesisInputs) {
763 emitError(UnknownLoc::get(
context))
764 <<
"unsupported arity " << arity <<
" for '" << name <<
"'";
767 if (!iface->supportsNumInputs(arity)) {
768 emitError(UnknownLoc::get(
context))
769 <<
"op '" << name <<
"' does not support exact-synthesis arity "
773 OperationName opName(*registeredInfo);
774 ExactCandidatePolicy candidatePolicy;
775 if (name == XorInverterOp::getOperationName() && arity == 2) {
779 candidatePolicy.mayUseConstantSource =
false;
780 candidatePolicy.enumerateInputInversions =
false;
782 if (llvm::any_of(policy.primitiveInfos, [&](
const ExactNodeInfo &info) {
783 return info.getOperationName() == opName &&
784 info.getArity() == arity;
786 emitError(UnknownLoc::get(
context))
787 <<
"duplicate allowed exact-synthesis op '" << spelling <<
"'";
790 policy.primitiveInfos.emplace_back(opName, arity,
791 iface->areInputsPermutationInvariant(),
792 iface, candidatePolicy);
797 LogicalResult initialize(MLIRContext *
context)
override {
798 if (maxInputs > kMaxExactSynthesisInputs) {
799 emitError(UnknownLoc::get(
context))
800 <<
"maximum exact-synthesis input count is "
801 << kMaxExactSynthesisInputs;
805 auto parsedPolicy = parsePolicy(
context);
806 if (failed(parsedPolicy))
808 policy = *parsedPolicy;
811 emitError(UnknownLoc::get(
context))
812 <<
"unsupported or unavailable SAT solver '" << satSolver
813 <<
"' (expected auto, z3, or cadical)";
820 void runOnOperation()
override {
821 ExactSynthesisStatistics statistics;
822 RewritePatternSet
patterns(&getContext());
823 patterns.add<ExactSynthesisPattern>(&getContext(), policy, satSolver,
824 maxInputs, maxArea, statistics);
825 walkAndApplyPatterns(getOperation(), std::move(
patterns));
826 numSolved += statistics.numSolved;
827 numUnsolved += statistics.numUnsolved;
831 ExactSynthesisPolicy policy;
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static std::optional< APSInt > getConstant(Attribute operand)
Determine the value of a constant operand for the sake of constant folding.
static InstancePath empty
Abstract interface for incremental SAT solvers with an IPASIR-style API.
virtual void addClause(llvm::ArrayRef< int > lits)
Add a complete clause in one call.
virtual int newVar()=0
Add a fresh variable for safe incremental SAT solving.
virtual Result solve()=0
Solve under the previously added clauses and current assumptions.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void addExactlyOneClauses(llvm::ArrayRef< int > inputLits, llvm::function_ref< void(llvm::ArrayRef< int >)> addClause, llvm::function_ref< int()> newVar)
Emit clauses encoding that exactly one literal in inputLits is true.
llvm::APInt createVarMask(unsigned numVars, unsigned varIndex, bool positive)
Create a mask for a variable in the truth table.
std::unique_ptr< IncrementalSATSolver > createSATSolver(llvm::StringRef backend="auto")
Construct an incremental SAT solver using the requested backend.