29#include "mlir/Analysis/TopologicalSortUtils.h"
30#include "mlir/IR/Builders.h"
31#include "mlir/IR/Operation.h"
32#include "mlir/IR/RegionKindInterface.h"
33#include "mlir/IR/Value.h"
34#include "mlir/IR/ValueRange.h"
35#include "mlir/IR/Visitors.h"
36#include "mlir/Support/LLVM.h"
37#include "llvm/ADT/APInt.h"
38#include "llvm/ADT/Bitset.h"
39#include "llvm/ADT/DenseMap.h"
40#include "llvm/ADT/MapVector.h"
41#include "llvm/ADT/STLExtras.h"
42#include "llvm/ADT/ScopeExit.h"
43#include "llvm/ADT/SetVector.h"
44#include "llvm/ADT/SmallVector.h"
45#include "llvm/ADT/iterator.h"
46#include "llvm/Support/Debug.h"
47#include "llvm/Support/ErrorHandling.h"
48#include "llvm/Support/LogicalResult.h"
55#define DEBUG_TYPE "synth-cut-rewriter"
63 return isa<aig::AndInverterOp>(op);
68 "Operation must be a supported logic operation for simulation");
72 if (
auto andOp = dyn_cast<aig::AndInverterOp>(op)) {
73 SmallVector<llvm::APInt, 2> inputs;
74 inputs.reserve(andOp.getInputs().size());
75 for (
auto input : andOp.getInputs()) {
76 auto it = eval.find(input);
78 llvm::report_fatal_error(
"Input value not found in evaluation map");
79 inputs.push_back(it->second);
82 eval[andOp.getResult()] = andOp.evaluate(inputs);
86 llvm::report_fatal_error(
87 "Unsupported operation for simulation. isSupportedLogicOp should "
88 "be used to check if the operation can be simulated.");
93 auto *op = value.getDefiningOp();
98 if (op->hasTrait<OpTrait::ConstantLike>()) {
109 ArrayRef<DelayType> newDelay,
double oldArea,
110 ArrayRef<DelayType> oldDelay) {
113 return newArea < oldArea || (newArea == oldArea && newDelay < oldDelay);
117 return newDelay < oldDelay || (newDelay == oldDelay && newArea < oldArea);
119 llvm_unreachable(
"Unknown mapping strategy");
126 auto walkResult = topOp->walk([&](Region *region) {
128 dyn_cast<mlir::RegionKindInterface>(region->getParentOp());
130 regionKindOp.hasSSADominance(region->getRegionNumber()))
131 return WalkResult::advance();
133 auto isOperationReady = [&](Value value, Operation *op) ->
bool {
137 isa<comb::ExtractOp, comb::ReplicateOp, comb::ConcatOp>(op));
141 for (
auto &block : *region) {
142 if (!mlir::sortTopologically(&block, isOperationReady))
143 return WalkResult::interrupt();
145 return WalkResult::advance();
148 if (walkResult.wasInterrupted())
149 return mlir::emitError(topOp->getLoc(),
150 "failed to sort operations topologically");
155template <
typename OpRange>
157 mlir::ValueRange values,
const OpRange &ops,
158 const llvm::SmallSetVector<mlir::Value, 4> &inputArgs) {
160 int64_t numInputs = inputArgs.size();
161 int64_t numOutputs = values.size();
166 return mlir::emitError(values.front().getLoc(),
167 "Truth table is too large");
168 return mlir::emitError(values.front().getLoc(),
169 "Multiple outputs are not supported yet");
175 uint32_t tableSize = 1 << numInputs;
177 DenseMap<Value, APInt> eval;
178 for (uint32_t i = 0; i < numInputs; ++i) {
181 uint32_t blockSize = 1 << i;
183 uint32_t patternWidth = 2 * blockSize;
184 APInt
pattern(patternWidth, 0);
185 assert(patternWidth <= tableSize &&
"Pattern width exceeds table size");
187 pattern = APInt::getHighBitsSet(patternWidth, blockSize);
191 eval[inputArgs[i]] = APInt::getSplat(tableSize,
pattern);
194 for (
auto *op : ops) {
195 if (op->getNumResults() == 0)
198 return op->emitError(
"Unsupported operation for truth table simulation");
211 llvm::SmallSetVector<Value, 4> inputs;
212 for (
auto arg : block->getArguments())
247 npnClass.emplace(std::move(canonicalForm));
252 SmallVectorImpl<Value> &permutedInputs)
const {
254 SmallVector<unsigned> idx;
255 npnClass.getInputPermutation(patternNPN, idx);
256 permutedInputs.reserve(idx.size());
257 for (
auto inputIndex : idx) {
258 assert(inputIndex <
inputs.size() &&
"Input index out of bounds");
259 permutedInputs.push_back(
inputs[inputIndex]);
264 os <<
"// === Cut Dump ===\n";
268 os <<
"Primary input cut: " << *
inputs.begin() <<
"\n";
273 for (
auto [idx, input] : llvm::enumerate(
inputs)) {
274 os <<
" Input " << idx <<
": " << input <<
"\n";
276 os <<
"\nOperations: \n";
284 os <<
"// === Cut End ===\n";
319 if (
auto *root = cut.
getRoot())
320 return llvm::any_of(op->getOperands(),
321 [&](Value v) { return v.getDefiningOp() == root; });
327 return cut.
inputs.size() == 1 &&
328 llvm::any_of(op->getOperands(),
329 [&](Value v) { return v == *cut.inputs.begin(); });
335 "The operation must be a child of the current root operation");
342 std::function<void(Operation *)> populateOperations = [&](Operation *op) {
348 for (
auto value : op->getOperands()) {
354 bool isInput =
inputs.contains(value);
355 bool isOtherInput = other.
inputs.contains(value);
357 if (isInput && isOtherInput)
360 auto *defOp = value.getDefiningOp();
362 assert(defOp &&
"Value must have a defining operation since block"
363 "arguments are treated as inputs");
372 populateOperations(defOp);
379 populateOperations(root);
383 for (
auto value : operation->getOperands()) {
385 newCut.
inputs.insert(value);
389 auto *defOp = value.getDefiningOp();
390 assert(defOp &&
"Value must have a defining operation");
395 newCut.
inputs.insert(value);
410 "The operation must be a child of the current root operation");
424 assert(
pattern &&
"Pattern must be set to get arrival time");
429 assert(
pattern &&
"Pattern must be set to get arrival time");
444 unsigned outputIndex)
const {
459 cuts.push_back(std::move(cut));
472 std::stable_sort(cuts.begin(), cuts.end(), [](
const Cut &a,
const Cut &b) {
473 return a.getInputSize() < b.getInputSize();
476 llvm::SmallVector<llvm::Bitset<64>, 4> inputBitMasks;
477 DenseMap<Value, unsigned> inputIndices;
478 auto getIndex = [&](Value v) ->
unsigned {
479 auto it = inputIndices.find(v);
480 if (it != inputIndices.end())
482 unsigned index = inputIndices.size();
483 if (LLVM_UNLIKELY(index >= 64))
484 llvm::report_fatal_error(
485 "Too many unique inputs across cuts. Max 64 supported. Consider "
486 "increasing the compile-time constant.");
487 inputIndices[v] = index;
491 for (
unsigned i = 0; i < cuts.size(); ++i) {
494 llvm::Bitset<64> inputsMask;
495 for (
auto input : cut.inputs.getArrayRef())
496 inputsMask.set(getIndex(input));
498 bool isUnique = llvm::all_of(
499 inputBitMasks, [&](
const llvm::Bitset<64> &existingCutInputMask) {
502 return (existingCutInputMask & inputsMask) != existingCutInputMask;
509 size_t uniqueCount = inputBitMasks.size();
510 if (i != uniqueCount)
511 cuts[uniqueCount] = std::move(cut);
512 inputBitMasks.push_back(inputsMask);
515 unsigned uniqueCount = inputBitMasks.size();
517 LLVM_DEBUG(llvm::dbgs() <<
"Original cuts: " << cuts.size()
518 <<
" Unique cuts: " << uniqueCount <<
"\n");
521 cuts.resize(uniqueCount);
526 llvm::function_ref<std::optional<MatchedPattern>(
const Cut &)> matchCut) {
534 for (
auto &cut :
cuts) {
537 "Cut input size exceeds maximum allowed size");
540 auto matched = matchCut(cut);
545 cut.setMatchedPattern(std::move(*matched));
558 auto *trivialCutsEnd =
559 std::stable_partition(
cuts.begin(),
cuts.end(),
560 [](
const Cut &cut) { return cut.isTrivialCut(); });
562 std::stable_sort(trivialCutsEnd,
cuts.end(),
563 [&options](
const Cut &a,
const Cut &b) ->
bool {
564 assert(!a.isTrivialCut() && !b.isTrivialCut() &&
565 "Trivial cuts should have been excluded");
566 const auto &aMatched = a.getMatchedPattern();
567 const auto &bMatched = b.getMatchedPattern();
570 if (aMatched && bMatched)
571 return compareDelayAndArea(
572 options.strategy, aMatched->getArea(),
573 aMatched->getArrivalTimes(), bMatched->getArea(),
574 bMatched->getArrivalTimes());
577 if (aMatched && !bMatched)
579 if (!aMatched && bMatched)
583 return a.getInputSize() < b.getInputSize();
592 for (
auto &cut :
cuts) {
603 llvm::dbgs() <<
"Finalized cut set with " <<
cuts.size() <<
" cuts and "
608 :
"no matched pattern")
620 SmallVectorImpl<NPNClass> &matchingNPNClasses)
const {
629 llvm::SmallVector<std::unique_ptr<CutRewritePattern>, 4>
patterns)
633 SmallVector<NPNClass, 2> npnClasses;
634 auto result =
pattern->useTruthTableMatcher(npnClasses);
636 for (
auto npnClass : npnClasses) {
639 npnClass.truthTable.numInputs}]
640 .push_back(std::make_pair(std::move(npnClass),
pattern.get()));
655 : options(options) {}
658 auto [cutSetPtr, inserted] =
659 cutSets.try_emplace(value, std::make_unique<CutSet>());
660 assert(inserted &&
"Cut set already exists for this value");
661 return cutSetPtr->second.get();
680 assert(logicOp->getNumResults() == 1 &&
681 "Logic operation must have a single result");
683 Value result = logicOp->getResult(0);
684 unsigned numOperands = logicOp->getNumOperands();
689 return logicOp->emitError(
"Cut enumeration supports at most 2 operands, "
692 if (!logicOp->getOpResult(0).getType().isInteger(1))
693 return logicOp->emitError()
694 <<
"Supported logic operations must have a single bit "
695 "result type but found: "
696 << logicOp->getResult(0).getType();
698 SmallVector<const CutSet *, 2> operandCutSets;
699 operandCutSets.reserve(numOperands);
701 for (
unsigned i = 0; i < numOperands; ++i) {
702 auto *operandCutSet =
getCutSet(logicOp->getOperand(i));
704 return logicOp->emitError(
"Failed to get cut set for operand ")
705 << i <<
": " << logicOp->getOperand(i);
706 operandCutSets.push_back(operandCutSet);
715 resultCutSet->addCut(primaryInputCut);
718 auto prune = llvm::make_scope_exit([&]() {
724 if (numOperands == 1) {
725 const auto &inputCutSet = operandCutSets[0];
728 for (
const Cut &inputCut : inputCutSet->getCuts()) {
729 Cut extendedCut = inputCut.
reRoot(logicOp);
734 resultCutSet->addCut(std::move(extendedCut));
740 assert(numOperands == 2 &&
"Expected binary operation");
742 const auto *lhsCutSet = operandCutSets[0];
743 const auto *rhsCutSet = operandCutSets[1];
746 for (
const Cut &lhsCut : lhsCutSet->getCuts()) {
747 for (
const Cut &rhsCut : rhsCutSet->getCuts()) {
753 resultCutSet->addCut(std::move(mergedCut));
762 llvm::function_ref<std::optional<MatchedPattern>(
const Cut &)> matchCut) {
763 LLVM_DEBUG(llvm::dbgs() <<
"Enumerating cuts for module: " << topOp->getName()
773 auto result = topOp->walk([&](Operation *op) {
774 if (failed(
visit(op)))
775 return mlir::WalkResult::interrupt();
776 return mlir::WalkResult::advance();
779 if (result.wasInterrupted())
782 LLVM_DEBUG(llvm::dbgs() <<
"Cut enumeration completed successfully\n");
788 auto *it =
cutSets.find(value);
791 auto cutSet = std::make_unique<CutSet>();
793 auto [newIt, inserted] =
cutSets.insert({value, std::move(cutSet)});
794 assert(inserted &&
"Cut set already exists for this value");
799 return it->second.get();
807 if (
auto *op = value.getDefiningOp()) {
810 if (
auto name = op->getAttrOfType<StringAttr>(
"sv.namehint"))
811 return name.getValue();
815 if (op->getNumResults() == 1) {
816 auto opName = op->getName();
817 auto count = opCounter[opName]++;
820 SmallString<16> nameStr;
821 nameStr += opName.getStringRef();
823 nameStr += std::to_string(count);
826 auto nameAttr = StringAttr::get(op->getContext(), nameStr);
827 op->setAttr(
"sv.namehint", nameAttr);
836 auto blockArg = cast<BlockArgument>(value);
838 dyn_cast<circt::hw::HWModuleOp>(blockArg.getOwner()->getParentOp());
843 return hwOp.getInputName(blockArg.getArgNumber());
847 DenseMap<OperationName, unsigned> opCounter;
848 for (
auto &[value, cutSetPtr] :
cutSets) {
849 auto &cutSet = *cutSetPtr;
851 << cutSet.getCuts().size() <<
" cuts:";
852 for (
const Cut &cut : cutSet.getCuts()) {
853 llvm::outs() <<
" {";
854 llvm::interleaveComma(cut.inputs, llvm::outs(), [&](Value input) {
855 llvm::outs() << getTestVariableName(input, opCounter);
857 auto &
pattern = cut.getMatchedPattern();
859 <<
"@t" << cut.getTruthTable().table.getZExtValue() <<
"d";
861 llvm::outs() << *std::max_element(
pattern->getArrivalTimes().begin(),
862 pattern->getArrivalTimes().end());
867 llvm::outs() <<
"\n";
869 llvm::outs() <<
"Cut enumeration completed successfully\n";
878 llvm::dbgs() <<
"Starting Cut Rewriter\n";
879 llvm::dbgs() <<
"Mode: "
892 if (
pattern->getNumOutputs() > 1) {
893 return mlir::emitError(
pattern->getLoc(),
894 "Cut rewriter does not support patterns with "
895 "multiple outputs yet");
922 LLVM_DEBUG(llvm::dbgs() <<
"Enumerating cuts...\n");
925 topOp, [&](
const Cut &cut) -> std::optional<MatchedPattern> {
931ArrayRef<std::pair<NPNClass, const CutRewritePattern *>>
933 if (
patterns.npnToPatternMap.empty())
937 auto it =
patterns.npnToPatternMap.find(
938 {npnClass.truthTable.table, npnClass.truthTable.numInputs});
939 if (it ==
patterns.npnToPatternMap.end())
941 return it->getSecond();
949 SmallVector<DelayType, 4> inputArrivalTimes;
950 SmallVector<DelayType, 1> bestArrivalTimes;
955 for (
auto input : cut.
inputs) {
956 assert(input.getType().isInteger(1));
961 inputArrivalTimes.push_back(0);
965 assert(cutSet &&
"Input must have a valid cut set");
969 auto *bestCut = cutSet->getBestMatchedCut();
973 const auto &matchedPattern = *bestCut->getMatchedPattern();
977 inputArrivalTimes.push_back(matchedPattern.getArrivalTime(
978 cast<mlir::OpResult>(input).getResultNumber()));
981 auto computeArrivalTimeAndPickBest =
983 llvm::function_ref<unsigned(
unsigned)> mapIndex) {
984 SmallVector<DelayType, 1> outputArrivalTimes;
986 for (
unsigned outputIndex = 0, outputSize = cut.
getOutputSize();
987 outputIndex < outputSize; ++outputIndex) {
990 for (
unsigned inputIndex = 0, inputSize = cut.
getInputSize();
991 inputIndex < inputSize; ++inputIndex) {
993 unsigned cutOriginalInput = mapIndex(inputIndex);
995 std::max(outputArrivalTime,
996 pattern->getDelay(cutOriginalInput, outputIndex) +
997 inputArrivalTimes[cutOriginalInput]);
1000 outputArrivalTimes.push_back(outputArrivalTime);
1006 outputArrivalTimes, bestPattern->
getArea(),
1007 bestArrivalTimes)) {
1009 llvm::dbgs() <<
"== Matched Pattern ==============\n";
1010 llvm::dbgs() <<
"Matching cut: \n";
1011 cut.
dump(llvm::dbgs());
1012 llvm::dbgs() <<
"Found better pattern: "
1014 llvm::dbgs() <<
" with area: " <<
pattern->getArea();
1015 llvm::dbgs() <<
" and input arrival times: ";
1016 for (
unsigned i = 0; i < inputArrivalTimes.size(); ++i) {
1017 llvm::dbgs() <<
" " << inputArrivalTimes[i];
1019 llvm::dbgs() <<
" and arrival times: ";
1021 for (
auto arrivalTime : outputArrivalTimes) {
1022 llvm::dbgs() <<
" " << arrivalTime;
1024 llvm::dbgs() <<
"\n";
1025 llvm::dbgs() <<
"== Matched Pattern End ==============\n";
1028 bestArrivalTimes = std::move(outputArrivalTimes);
1035 "Pattern input size must match cut input size");
1041 SmallVector<unsigned> inputMapping;
1043 computeArrivalTimeAndPickBest(
pattern,
1044 [&](
unsigned i) {
return inputMapping[i]; });
1049 computeArrivalTimeAndPickBest(
pattern, [&](
unsigned i) {
return i; });
1058 LLVM_DEBUG(llvm::dbgs() <<
"Performing cut-based rewriting...\n");
1062 PatternRewriter rewriter(top->getContext());
1063 for (
auto &[value, cutSet] : llvm::reverse(cutVector)) {
1064 if (value.use_empty()) {
1065 if (
auto *op = value.getDefiningOp())
1072 LLVM_DEBUG(llvm::dbgs() <<
"Skipping inputs: " << value <<
"\n");
1076 LLVM_DEBUG(llvm::dbgs() <<
"Cut set for value: " << value <<
"\n");
1077 auto *bestCut = cutSet->getBestMatchedCut();
1081 return emitError(value.getLoc(),
"No matching cut found for value: ")
1085 rewriter.setInsertionPoint(bestCut->getRoot());
1086 const auto &matchedPattern = bestCut->getMatchedPattern();
1087 auto result = matchedPattern->getPattern()->rewrite(rewriter, *bestCut);
1091 rewriter.replaceOp(bestCut->getRoot(), *result);
1094 auto array = rewriter.getI64ArrayAttr(matchedPattern->getArrivalTimes());
1095 (*result)->setAttr(
"test.arrival_times", array);
assert(baseType &&"element must be base type")
static bool isAlwaysCutInput(Value value)
static bool isSupportedLogicOp(mlir::Operation *op)
static Cut getAsTrivialCut(mlir::Value value)
static FailureOr< BinaryTruthTable > computeTruthTable(mlir::ValueRange values, const OpRange &ops, const llvm::SmallSetVector< mlir::Value, 4 > &inputArgs)
Get the truth table for an op.
static StringRef getTestVariableName(Value value, DenseMap< OperationName, unsigned > &opCounter)
Generate a human-readable name for a value used in test output.
static bool compareDelayAndArea(OptimizationStrategy strategy, double newArea, ArrayRef< DelayType > newDelay, double oldArea, ArrayRef< DelayType > oldDelay)
static void removeDuplicateAndNonMinimalCuts(SmallVectorImpl< Cut > &cuts)
static bool isCutDerivedFromOperand(const Cut &cut, Operation *op)
static void simulateLogicOp(Operation *op, DenseMap< Value, llvm::APInt > &eval)
RewritePatternSet pattern
LogicalResult visit(Operation *op)
Visit a single operation and generate cuts for it.
const CutRewriterOptions & options
Configuration options for cut enumeration.
llvm::MapVector< Value, std::unique_ptr< CutSet > > cutSets
Maps values to their associated cut sets.
LogicalResult enumerateCuts(Operation *topOp, llvm::function_ref< std::optional< MatchedPattern >(const Cut &)> matchCut=[](const Cut &) { return std::nullopt;})
Enumerate cuts for all nodes in the given module.
CutEnumerator(const CutRewriterOptions &options)
Constructor for cut enumerator.
void clear()
Clear all cut sets and reset the enumerator.
llvm::function_ref< std::optional< MatchedPattern >(const Cut &)> matchCut
Function to match cuts against available patterns.
LogicalResult visitLogicOp(Operation *logicOp)
Visit a combinational logic operation and generate cuts.
llvm::MapVector< Value, std::unique_ptr< CutSet > > takeVector()
Move ownership of all cut sets to caller.
CutSet * createNewCutSet(Value value)
Create a new cut set for a value.
const CutSet * getCutSet(Value value)
Get the cut set for a specific value.
llvm::SmallVector< std::unique_ptr< CutRewritePattern >, 4 > patterns
Owned collection of all rewriting patterns.
DenseMap< std::pair< APInt, unsigned >, SmallVector< std::pair< NPNClass, const CutRewritePattern * > > > npnToPatternMap
Fast lookup table mapping NPN canonical forms to matching patterns.
SmallVector< const CutRewritePattern *, 4 > nonTruthTablePatterns
Patterns that use custom matching logic instead of truth tables.
CutRewritePatternSet(llvm::SmallVector< std::unique_ptr< CutRewritePattern >, 4 > patterns)
Constructor that takes ownership of the provided patterns.
const CutRewriterOptions & options
Configuration options.
ArrayRef< std::pair< NPNClass, const CutRewritePattern * > > getMatchingPatternsFromTruthTable(const Cut &cut) const
Find patterns that match a cut's truth table.
std::optional< MatchedPattern > patternMatchCut(const Cut &cut)
Match a cut against available patterns and compute arrival time.
LogicalResult enumerateCuts(Operation *topOp)
Enumerate cuts for all nodes in the given module.
LogicalResult run(Operation *topOp)
Execute the complete cut-based rewriting algorithm.
CutEnumerator cutEnumerator
LogicalResult runBottomUpRewrite(Operation *topOp)
Perform the actual circuit rewriting using selected patterns.
Manages a collection of cuts for a single logic node using priority cuts algorithm.
Cut * getBestMatchedCut() const
Get the cut associated with the best matched pattern.
llvm::SmallVector< Cut, 4 > cuts
Collection of cuts for this node.
void addCut(Cut cut)
Add a new cut to this set.
unsigned size() const
Get the number of cuts in this set.
void finalize(const CutRewriterOptions &options, llvm::function_ref< std::optional< MatchedPattern >(const Cut &)> matchCut)
Finalize the cut set by removing duplicates and selecting the best pattern.
bool isFrozen
Whether cut set is finalized.
ArrayRef< Cut > getCuts() const
Get read-only access to all cuts in this set.
Represents a cut in the combinational logic network.
std::optional< NPNClass > npnClass
Cached NPN canonical form for this cut.
const std::optional< MatchedPattern > & getMatchedPattern() const
Get the matched pattern for this cut.
llvm::SmallSetVector< mlir::Operation *, 4 > operations
Operations contained within this cut.
unsigned getOutputSize() const
Get the number of outputs from root operation.
void getPermutatedInputs(const NPNClass &patternNPN, SmallVectorImpl< Value > &permutedInputs) const
Get the permutated inputs for this cut based on the given pattern NPN.
const NPNClass & getNPNClass() const
Get the NPN canonical form for this cut.
mlir::Operation * getRoot() const
Get the root operation of this cut.
llvm::SmallSetVector< mlir::Value, 4 > inputs
External inputs to this cut (cut boundary).
void dump(llvm::raw_ostream &os) const
const BinaryTruthTable & getTruthTable() const
Get the truth table for this cut.
std::optional< BinaryTruthTable > truthTable
Cached truth table for this cut.
Cut mergeWith(const Cut &other, Operation *root) const
Merge this cut with another cut to form a new cut.
unsigned getInputSize() const
Get the number of inputs to this cut.
bool isTrivialCut() const
Check if this cut represents a trivial cut.
Cut reRoot(Operation *root) const
Represents a cut that has been successfully matched to a rewriting pattern.
DelayType getArrivalTime(unsigned outputIndex) const
Get the arrival time of signals through this pattern.
DelayType getDelay(unsigned inputIndex, unsigned outputIndex) const
Get the delay between specific input and output pins.
ArrayRef< DelayType > getArrivalTimes() const
const CutRewritePattern * pattern
The matched library pattern.
double getArea() const
Get the area cost of using this pattern.
const CutRewritePattern * getPattern() const
Get the library pattern that was matched.
SmallVector< DelayType, 1 > arrivalTimes
Arrival times of outputs from this pattern.
OptimizationStrategy
Optimization strategy.
@ OptimizationStrategyArea
Optimize for minimal area.
@ OptimizationStrategyTiming
Optimize for minimal critical path delay.
FailureOr< BinaryTruthTable > getTruthTable(ValueRange values, Block *block)
static constexpr unsigned maxTruthTableInputs
Maximum number of inputs supported for truth table generation.
LogicalResult topologicallySortLogicNetwork(mlir::Operation *op)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Represents a boolean function as a truth table.
Represents the canonical form of a boolean function under NPN equivalence.
static NPNClass computeNPNCanonicalForm(const BinaryTruthTable &tt)
Compute the canonical NPN form for a given truth table.
void getInputPermutation(const NPNClass &targetNPN, llvm::SmallVectorImpl< unsigned > &permutation) const
Get input permutation from this NPN class to another equivalent NPN class.
Utility that tracks operations that have potentially become unused and allows them to be cleaned up a...
void eraseNow(Operation *op)
Erase an operation immediately, and remove it from the set of ops to be removed later.
Base class for cut rewriting patterns used in combinational logic optimization.
virtual DelayType getDelay(unsigned inputIndex, unsigned outputIndex) const =0
Get the delay between specific input and output.
virtual bool useTruthTableMatcher(SmallVectorImpl< NPNClass > &matchingNPNClasses) const
Specify truth tables that this pattern can match.
virtual double getArea() const =0
Get the area cost of this pattern.
Configuration options for the cut-based rewriting algorithm.
unsigned maxCutInputSize
Maximum number of inputs allowed for any cut.
unsigned maxCutSizePerRoot
Maximum number of cuts to maintain per logic node.
bool allowNoMatch
Fail if there is a root operation that has no matching pattern.
bool attachDebugTiming
Put arrival times to rewritten operations.
OptimizationStrategy strategy
Optimization strategy (area vs. timing).
bool testPriorityCuts
Run priority cuts enumeration and dump the cut sets.