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]);
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.
false return failure()
Parse an optional keyword or string and set instance into 'result'.
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 int val(int v) const =0
Return the satisfying assignment for variable v from the last SAT result.
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.