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");
125 auto isOperationReady = [](Value value, Operation *op) ->
bool {
129 isa<comb::ExtractOp, comb::ReplicateOp, comb::ConcatOp>(op));
134 return mlir::emitError(topOp->getLoc(),
135 "failed to sort operations topologically");
140template <
typename OpRange>
142 mlir::ValueRange values,
const OpRange &ops,
143 const llvm::SmallSetVector<mlir::Value, 4> &inputArgs) {
145 int64_t numInputs = inputArgs.size();
146 int64_t numOutputs = values.size();
151 return mlir::emitError(values.front().getLoc(),
152 "Truth table is too large");
153 return mlir::emitError(values.front().getLoc(),
154 "Multiple outputs are not supported yet");
161 DenseMap<Value, APInt> eval;
162 for (uint32_t i = 0; i < numInputs; ++i)
165 for (
auto *op : ops) {
166 if (op->getNumResults() == 0)
169 return op->emitError(
"Unsupported operation for truth table simulation");
182 llvm::SmallSetVector<Value, 4> inputs;
183 for (
auto arg : block->getArguments())
218 npnClass.emplace(std::move(canonicalForm));
223 SmallVectorImpl<Value> &permutedInputs)
const {
225 SmallVector<unsigned> idx;
226 npnClass.getInputPermutation(patternNPN, idx);
227 permutedInputs.reserve(idx.size());
228 for (
auto inputIndex : idx) {
229 assert(inputIndex <
inputs.size() &&
"Input index out of bounds");
230 permutedInputs.push_back(
inputs[inputIndex]);
236 SmallVectorImpl<DelayType> &results)
const {
240 for (
auto input :
inputs) {
243 results.push_back(0);
246 auto *cutSet = enumerator.
getCutSet(input);
247 assert(cutSet &&
"Input must have a valid cut set");
251 auto *bestCut = cutSet->getBestMatchedCut();
260 cast<mlir::OpResult>(input).getResultNumber()));
267 os <<
"// === Cut Dump ===\n";
271 os <<
"Primary input cut: " << *
inputs.begin() <<
"\n";
276 for (
auto [idx, input] : llvm::enumerate(
inputs)) {
277 os <<
" Input " << idx <<
": " << input <<
"\n";
279 os <<
"\nOperations: \n";
287 os <<
"// === Cut End ===\n";
322 if (
auto *root = cut.
getRoot())
323 return llvm::any_of(op->getOperands(),
324 [&](Value v) { return v.getDefiningOp() == root; });
330 return cut.
inputs.size() == 1 &&
331 llvm::any_of(op->getOperands(),
332 [&](Value v) { return v == *cut.inputs.begin(); });
338 "The operation must be a child of the current root operation");
345 std::function<void(Operation *)> populateOperations = [&](Operation *op) {
351 for (
auto value : op->getOperands()) {
357 bool isInput =
inputs.contains(value);
358 bool isOtherInput = other.
inputs.contains(value);
360 if (isInput && isOtherInput)
363 auto *defOp = value.getDefiningOp();
365 assert(defOp &&
"Value must have a defining operation since block"
366 "arguments are treated as inputs");
375 populateOperations(defOp);
382 populateOperations(root);
386 for (
auto value : operation->getOperands()) {
388 newCut.
inputs.insert(value);
392 auto *defOp = value.getDefiningOp();
393 assert(defOp &&
"Value must have a defining operation");
398 newCut.
inputs.insert(value);
413 "The operation must be a child of the current root operation");
427 assert(
pattern &&
"Pattern must be set to get arrival time");
432 assert(
pattern &&
"Pattern must be set to get arrival time");
456 cuts.push_back(std::move(cut));
469 std::stable_sort(cuts.begin(), cuts.end(), [](
const Cut &a,
const Cut &b) {
470 return a.getInputSize() < b.getInputSize();
473 llvm::SmallVector<llvm::Bitset<64>, 4> inputBitMasks;
474 DenseMap<Value, unsigned> inputIndices;
475 auto getIndex = [&](Value v) ->
unsigned {
476 auto it = inputIndices.find(v);
477 if (it != inputIndices.end())
479 unsigned index = inputIndices.size();
480 if (LLVM_UNLIKELY(index >= 64))
481 llvm::report_fatal_error(
482 "Too many unique inputs across cuts. Max 64 supported. Consider "
483 "increasing the compile-time constant.");
484 inputIndices[v] = index;
488 for (
unsigned i = 0; i < cuts.size(); ++i) {
491 llvm::Bitset<64> inputsMask;
492 for (
auto input : cut.inputs.getArrayRef())
493 inputsMask.set(getIndex(input));
495 bool isUnique = llvm::all_of(
496 inputBitMasks, [&](
const llvm::Bitset<64> &existingCutInputMask) {
499 return (existingCutInputMask & inputsMask) != existingCutInputMask;
506 size_t uniqueCount = inputBitMasks.size();
507 if (i != uniqueCount)
508 cuts[uniqueCount] = std::move(cut);
509 inputBitMasks.push_back(inputsMask);
512 unsigned uniqueCount = inputBitMasks.size();
514 LLVM_DEBUG(llvm::dbgs() <<
"Original cuts: " << cuts.size()
515 <<
" Unique cuts: " << uniqueCount <<
"\n");
518 cuts.resize(uniqueCount);
523 llvm::function_ref<std::optional<MatchedPattern>(
const Cut &)> matchCut) {
531 for (
auto &cut :
cuts) {
534 "Cut input size exceeds maximum allowed size");
537 auto matched = matchCut(cut);
542 cut.setMatchedPattern(std::move(*matched));
555 auto *trivialCutsEnd =
556 std::stable_partition(
cuts.begin(),
cuts.end(),
557 [](
const Cut &cut) { return cut.isTrivialCut(); });
559 std::stable_sort(trivialCutsEnd,
cuts.end(),
560 [&options](
const Cut &a,
const Cut &b) ->
bool {
561 assert(!a.isTrivialCut() && !b.isTrivialCut() &&
562 "Trivial cuts should have been excluded");
563 const auto &aMatched = a.getMatchedPattern();
564 const auto &bMatched = b.getMatchedPattern();
567 if (aMatched && bMatched)
568 return compareDelayAndArea(
569 options.strategy, aMatched->getArea(),
570 aMatched->getArrivalTimes(), bMatched->getArea(),
571 bMatched->getArrivalTimes());
574 if (aMatched && !bMatched)
576 if (!aMatched && bMatched)
580 return a.getInputSize() < b.getInputSize();
589 for (
auto &cut :
cuts) {
600 llvm::dbgs() <<
"Finalized cut set with " <<
cuts.size() <<
" cuts and "
605 :
"no matched pattern")
617 SmallVectorImpl<NPNClass> &matchingNPNClasses)
const {
626 llvm::SmallVector<std::unique_ptr<CutRewritePattern>, 4>
patterns)
630 SmallVector<NPNClass, 2> npnClasses;
631 auto result =
pattern->useTruthTableMatcher(npnClasses);
633 for (
auto npnClass : npnClasses) {
636 npnClass.truthTable.numInputs}]
637 .push_back(std::make_pair(std::move(npnClass),
pattern.get()));
652 : options(options) {}
655 auto [cutSetPtr, inserted] =
656 cutSets.try_emplace(value, std::make_unique<CutSet>());
657 assert(inserted &&
"Cut set already exists for this value");
658 return cutSetPtr->second.get();
677 assert(logicOp->getNumResults() == 1 &&
678 "Logic operation must have a single result");
680 Value result = logicOp->getResult(0);
681 unsigned numOperands = logicOp->getNumOperands();
686 return logicOp->emitError(
"Cut enumeration supports at most 2 operands, "
689 if (!logicOp->getOpResult(0).getType().isInteger(1))
690 return logicOp->emitError()
691 <<
"Supported logic operations must have a single bit "
692 "result type but found: "
693 << logicOp->getResult(0).getType();
695 SmallVector<const CutSet *, 2> operandCutSets;
696 operandCutSets.reserve(numOperands);
698 for (
unsigned i = 0; i < numOperands; ++i) {
699 auto *operandCutSet =
getCutSet(logicOp->getOperand(i));
701 return logicOp->emitError(
"Failed to get cut set for operand ")
702 << i <<
": " << logicOp->getOperand(i);
703 operandCutSets.push_back(operandCutSet);
712 resultCutSet->addCut(primaryInputCut);
715 llvm::scope_exit prune([&]() {
721 if (numOperands == 1) {
722 const auto &inputCutSet = operandCutSets[0];
725 for (
const Cut &inputCut : inputCutSet->getCuts()) {
726 Cut extendedCut = inputCut.
reRoot(logicOp);
731 resultCutSet->addCut(std::move(extendedCut));
737 assert(numOperands == 2 &&
"Expected binary operation");
739 const auto *lhsCutSet = operandCutSets[0];
740 const auto *rhsCutSet = operandCutSets[1];
743 for (
const Cut &lhsCut : lhsCutSet->getCuts()) {
744 for (
const Cut &rhsCut : rhsCutSet->getCuts()) {
750 resultCutSet->addCut(std::move(mergedCut));
759 llvm::function_ref<std::optional<MatchedPattern>(
const Cut &)> matchCut) {
760 LLVM_DEBUG(llvm::dbgs() <<
"Enumerating cuts for module: " << topOp->getName()
770 auto result = topOp->walk([&](Operation *op) {
771 if (failed(
visit(op)))
772 return mlir::WalkResult::interrupt();
773 return mlir::WalkResult::advance();
776 if (result.wasInterrupted())
779 LLVM_DEBUG(llvm::dbgs() <<
"Cut enumeration completed successfully\n");
785 auto *it =
cutSets.find(value);
788 auto cutSet = std::make_unique<CutSet>();
790 auto [newIt, inserted] =
cutSets.insert({value, std::move(cutSet)});
791 assert(inserted &&
"Cut set already exists for this value");
796 return it->second.get();
804 if (
auto *op = value.getDefiningOp()) {
807 if (
auto name = op->getAttrOfType<StringAttr>(
"sv.namehint"))
808 return name.getValue();
812 if (op->getNumResults() == 1) {
813 auto opName = op->getName();
814 auto count = opCounter[opName]++;
817 SmallString<16> nameStr;
818 nameStr += opName.getStringRef();
820 nameStr += std::to_string(count);
823 auto nameAttr = StringAttr::get(op->getContext(), nameStr);
824 op->setAttr(
"sv.namehint", nameAttr);
833 auto blockArg = cast<BlockArgument>(value);
835 dyn_cast<circt::hw::HWModuleOp>(blockArg.getOwner()->getParentOp());
840 return hwOp.getInputName(blockArg.getArgNumber());
844 DenseMap<OperationName, unsigned> opCounter;
845 for (
auto &[value, cutSetPtr] :
cutSets) {
846 auto &cutSet = *cutSetPtr;
848 << cutSet.getCuts().size() <<
" cuts:";
849 for (
const Cut &cut : cutSet.getCuts()) {
850 llvm::outs() <<
" {";
851 llvm::interleaveComma(cut.inputs, llvm::outs(), [&](Value input) {
852 llvm::outs() << getTestVariableName(input, opCounter);
854 auto &
pattern = cut.getMatchedPattern();
856 <<
"@t" << cut.getTruthTable().table.getZExtValue() <<
"d";
858 llvm::outs() << *std::max_element(
pattern->getArrivalTimes().begin(),
859 pattern->getArrivalTimes().end());
864 llvm::outs() <<
"\n";
866 llvm::outs() <<
"Cut enumeration completed successfully\n";
875 llvm::dbgs() <<
"Starting Cut Rewriter\n";
876 llvm::dbgs() <<
"Mode: "
889 if (
pattern->getNumOutputs() > 1) {
890 return mlir::emitError(
pattern->getLoc(),
891 "Cut rewriter does not support patterns with "
892 "multiple outputs yet");
919 LLVM_DEBUG(llvm::dbgs() <<
"Enumerating cuts...\n");
922 topOp, [&](
const Cut &cut) -> std::optional<MatchedPattern> {
928ArrayRef<std::pair<NPNClass, const CutRewritePattern *>>
930 if (
patterns.npnToPatternMap.empty())
934 auto it =
patterns.npnToPatternMap.find(
935 {npnClass.truthTable.table, npnClass.truthTable.numInputs});
936 if (it ==
patterns.npnToPatternMap.end())
938 return it->getSecond();
946 SmallVector<DelayType, 4> inputArrivalTimes;
947 SmallVector<DelayType, 1> bestArrivalTimes;
948 double bestArea = 0.0;
953 for (
auto input : cut.
inputs) {
954 assert(input.getType().isInteger(1));
959 inputArrivalTimes.push_back(0);
963 assert(cutSet &&
"Input must have a valid cut set");
967 auto *bestCut = cutSet->getBestMatchedCut();
971 const auto &matchedPattern = *bestCut->getMatchedPattern();
975 inputArrivalTimes.push_back(matchedPattern.getArrivalTime(
976 cast<mlir::OpResult>(input).getResultNumber()));
979 auto computeArrivalTimeAndPickBest =
981 llvm::function_ref<unsigned(
unsigned)> mapIndex) {
982 SmallVector<DelayType, 1> outputArrivalTimes;
984 for (
unsigned outputIndex = 0, outputSize = cut.
getOutputSize();
985 outputIndex < outputSize; ++outputIndex) {
988 auto delays = matchResult.getDelays();
989 for (
unsigned inputIndex = 0, inputSize = cut.
getInputSize();
990 inputIndex < inputSize; ++inputIndex) {
992 unsigned cutOriginalInput = mapIndex(inputIndex);
994 std::max(outputArrivalTime,
995 delays[outputIndex * inputSize + inputIndex] +
996 inputArrivalTimes[cutOriginalInput]);
999 outputArrivalTimes.push_back(outputArrivalTime);
1005 outputArrivalTimes, bestArea,
1006 bestArrivalTimes)) {
1008 llvm::dbgs() <<
"== Matched Pattern ==============\n";
1009 llvm::dbgs() <<
"Matching cut: \n";
1010 cut.
dump(llvm::dbgs());
1011 llvm::dbgs() <<
"Found better pattern: "
1013 llvm::dbgs() <<
" with area: " << matchResult.area;
1014 llvm::dbgs() <<
" and input arrival times: ";
1015 for (
unsigned i = 0; i < inputArrivalTimes.size(); ++i) {
1016 llvm::dbgs() <<
" " << inputArrivalTimes[i];
1018 llvm::dbgs() <<
" and arrival times: ";
1020 for (
auto arrivalTime : outputArrivalTimes) {
1021 llvm::dbgs() <<
" " << arrivalTime;
1023 llvm::dbgs() <<
"\n";
1024 llvm::dbgs() <<
"== Matched Pattern End ==============\n";
1027 bestArrivalTimes = std::move(outputArrivalTimes);
1028 bestArea = matchResult.area;
1035 "Pattern input size must match cut input size");
1042 SmallVector<unsigned> inputMapping;
1044 computeArrivalTimeAndPickBest(
pattern, *matchResult,
1045 [&](
unsigned i) {
return inputMapping[i]; });
1050 computeArrivalTimeAndPickBest(
pattern, *matchResult,
1051 [&](
unsigned i) {
return i; });
1057 return MatchedPattern(bestPattern, std::move(bestArrivalTimes), bestArea);
1061 LLVM_DEBUG(llvm::dbgs() <<
"Performing cut-based rewriting...\n");
1065 PatternRewriter rewriter(top->getContext());
1066 for (
auto &[value, cutSet] : llvm::reverse(cutVector)) {
1067 if (value.use_empty()) {
1068 if (
auto *op = value.getDefiningOp())
1075 LLVM_DEBUG(llvm::dbgs() <<
"Skipping inputs: " << value <<
"\n");
1079 LLVM_DEBUG(llvm::dbgs() <<
"Cut set for value: " << value <<
"\n");
1080 auto *bestCut = cutSet->getBestMatchedCut();
1084 return emitError(value.getLoc(),
"No matching cut found for value: ")
1088 rewriter.setInsertionPoint(bestCut->getRoot());
1089 const auto &matchedPattern = bestCut->getMatchedPattern();
1090 auto result = matchedPattern->getPattern()->rewrite(rewriter,
cutEnumerator,
1095 rewriter.replaceOp(bestCut->getRoot(), *result);
1098 auto array = rewriter.getI64ArrayAttr(matchedPattern->getArrivalTimes());
1099 (*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
Cut enumeration engine for combinational logic networks.
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.
const llvm::MapVector< Value, std::unique_ptr< CutSet > > & getCutSets() const
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.
SmallVector< const CutRewritePattern *, 4 > nonNPNPatterns
Patterns that use custom matching logic instead of NPN lookup.
DenseMap< std::pair< APInt, unsigned >, SmallVector< std::pair< NPNClass, const CutRewritePattern * > > > npnToPatternMap
Fast lookup table mapping NPN canonical forms to matching patterns.
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.
std::optional< MatchedPattern > matchedPattern
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.
LogicalResult getInputArrivalTimes(CutEnumerator &enumerator, SmallVectorImpl< DelayType > &results) const
Get arrival times for each input 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.
double area
Area cost of this pattern.
DelayType getArrivalTime(unsigned outputIndex) const
Get the arrival time of signals through this pattern.
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)
LogicalResult topologicallySortGraphRegionBlocks(mlir::Operation *op, llvm::function_ref< bool(mlir::Value, mlir::Operation *)> isOperandReady)
This function performs a topological sort on the operations within each block of graph regions in the...
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.
llvm::APInt createVarMask(unsigned numVars, unsigned varIndex, bool positive)
Create a mask for a variable in the truth table.
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 bool useTruthTableMatcher(SmallVectorImpl< NPNClass > &matchingNPNClasses) const
Specify truth tables that this pattern can match.
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.
Result of matching a cut against a pattern.