23#include "mlir/IR/Builders.h"
24#include "mlir/IR/Threading.h"
25#include "mlir/Support/WalkResult.h"
26#include "llvm/ADT/APInt.h"
27#include "llvm/ADT/SmallVector.h"
28#include "llvm/Support/Debug.h"
33#define GEN_PASS_DEF_TECHMAPPER
34#include "circt/Dialect/Synth/Transforms/SynthPasses.h.inc"
41#define DEBUG_TYPE "synth-tech-mapper"
49 auto inputTypes =
module.getInputTypes();
50 auto outputTypes =
module.getOutputTypes();
52 unsigned numInputs = inputTypes.size();
53 unsigned numOutputs = outputTypes.size();
55 return module->emitError(
56 "Modules with multiple outputs are not supported yet");
59 for (
auto type : inputTypes) {
60 if (!type.isInteger(1))
61 return module->emitError(
"All input ports must be single bit");
63 for (
auto type : outputTypes) {
64 if (!type.isInteger(1))
65 return module->emitError(
"All output ports must be single bit");
69 return module->emitError("Too many inputs for truth table generation");
71 SmallVector<Value> results;
72 results.reserve(numOutputs);
74 auto *bodyBlock =
module.getBodyBlock();
75 assert(bodyBlock &&
"Module must have a body block");
77 for (
auto result : bodyBlock->getTerminator()->getOperands())
78 results.push_back(result);
81 FailureOr<BinaryTruthTable> truthTable =
getTruthTable(results, bodyBlock);
82 if (failed(truthTable))
96 llvm::dbgs() <<
"Created Tech Library Pattern for module: "
97 <<
module.getModuleName() << "\n"
98 << "NPN Class: " << this->npnClass.truthTable.table << "\n"
99 << "Inputs: " << this->npnClass.inputPermutation.size()
101 << "Input Negation: " << this->npnClass.inputNegation << "\n"
102 << "Output Negation: " << this->npnClass.outputNegation
108 auto moduleCp =
module;
109 return moduleCp.getModuleName();
114 const Cut &cut)
const override {
123 SmallVectorImpl<NPNClass> &matchingNPNClasses)
const override {
124 matchingNPNClasses.push_back(
npnClass);
129 llvm::FailureOr<Operation *>
rewrite(mlir::OpBuilder &builder,
131 const Cut &cut)
const override {
134 SmallVector<unsigned> permutedInputIndices;
137 SmallVector<Value> inputs;
138 inputs.reserve(permutedInputIndices.size());
139 for (
unsigned idx : permutedInputIndices) {
140 assert(idx < cut.
inputs.size() &&
"input permutation index out of range");
141 inputs.push_back(network.getValue(cut.
inputs[idx]));
144 auto *rootOp = network.getGate(cut.
getRootIndex()).getOperation();
145 assert(rootOp &&
"cut root must be a valid operation");
148 auto instanceOp = hw::InstanceOp::create(builder, rootOp->getLoc(), module,
149 "mapped", ArrayRef<Value>(inputs));
150 return instanceOp.getOperation();
162 auto module = this->module;
163 return module.getLoc();
174struct TechMapperPass :
public impl::TechMapperBase<TechMapperPass> {
175 using TechMapperBase<TechMapperPass>::TechMapperBase;
177 void runOnOperation()
override {
178 auto module = getOperation();
180 SmallVector<std::unique_ptr<CutRewritePattern>> libraryPatterns;
182 unsigned maxInputSize = 0;
188 SmallVector<hw::HWModuleOp> nonLibraryModules;
189 for (
auto hwModule :
module.getOps<hw::HWModuleOp>()) {
191 hwModule->getAttrOfType<DictionaryAttr>("hw.techlib.info");
196 nonLibraryModules.push_back(hwModule);
201 auto areaAttr = techInfo.getAs<FloatAttr>(
"area");
202 auto delayAttr = techInfo.getAs<ArrayAttr>(
"delay");
203 if (!areaAttr || !delayAttr) {
204 mlir::emitError(hwModule.getLoc())
205 <<
"Library module " << hwModule.getModuleName()
206 <<
" must have 'area'(float) and 'delay' (2d array to represent "
207 "input-output pair delay) attributes";
212 double area = areaAttr.getValue().convertToDouble();
214 SmallVector<DelayType> delay;
215 for (
auto delayValue : delayAttr) {
216 auto delayArray = cast<ArrayAttr>(delayValue);
217 for (
auto delayElement : delayArray) {
222 cast<mlir::IntegerAttr>(delayElement).getValue().getZExtValue());
227 if (failed(npnClass)) {
233 std::unique_ptr<TechLibraryPattern>
pattern =
234 std::make_unique<TechLibraryPattern>(hwModule, area, std::move(delay),
235 std::move(*npnClass));
238 maxInputSize = std::max(maxInputSize,
pattern->getNumInputs());
241 libraryPatterns.push_back(std::move(
pattern));
244 if (libraryPatterns.empty())
245 return markAllAnalysesPreserved();
253 std::atomic<uint64_t> numCutsCreatedCount = 0;
254 std::atomic<uint64_t> numCutSetsCreatedCount = 0;
255 std::atomic<uint64_t> numCutsRewrittenCount = 0;
256 auto result = mlir::failableParallelForEach(
257 module.getContext(), nonLibraryModules, [&](
hw::HWModuleOp hwModule) {
258 LLVM_DEBUG(llvm::dbgs() <<
"Processing non-library module: "
259 << hwModule.getName() <<
"\n");
260 CutRewriter rewriter(options, patternSet);
261 if (failed(rewriter.run(hwModule)))
263 const auto &stats = rewriter.getStats();
264 numCutsCreatedCount.fetch_add(stats.numCutsCreated,
265 std::memory_order_relaxed);
266 numCutSetsCreatedCount.fetch_add(stats.numCutSetsCreated,
267 std::memory_order_relaxed);
268 numCutsRewrittenCount.fetch_add(stats.numCutsRewritten,
269 std::memory_order_relaxed);
274 numCutsCreated += numCutsCreatedCount;
275 numCutSetsCreated += numCutSetsCreatedCount;
276 numCutsRewritten += numCutsRewrittenCount;
assert(baseType &&"element must be base type")
RewritePatternSet pattern
static llvm::FailureOr< NPNClass > getNPNClassFromModule(hw::HWModuleOp module)
Cut enumeration engine for combinational logic networks.
const LogicNetwork & getLogicNetwork() const
Get the logic network (read-only).
Manages a collection of rewriting patterns for combinational logic optimization.
Represents a cut in the combinational logic network.
void getPermutatedInputIndices(const NPNClass &patternNPN, SmallVectorImpl< unsigned > &permutedIndices) const
Get the permutated inputs for this cut based on the given pattern NPN.
uint32_t getRootIndex() const
Get the root index in the LogicNetwork.
const NPNClass & getNPNClass() const
Get the NPN canonical form for this cut.
llvm::SmallVector< uint32_t, 6 > inputs
External inputs to this cut (cut boundary).
FailureOr< BinaryTruthTable > getTruthTable(ValueRange values, Block *block)
Get the truth table for operations within a block.
static constexpr unsigned maxTruthTableInputs
Maximum number of inputs supported for truth table generation.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Simple technology library encoded as a HWModuleOp.
TechLibraryPattern(hw::HWModuleOp module, double area, SmallVector< DelayType > delay, NPNClass npnClass)
StringRef getPatternName() const override
Get the name of this pattern. Used for debugging.
hw::HWModuleOp NPNClass npnClass
std::optional< MatchResult > match(CutEnumerator &enumerator, const Cut &cut) const override
Match the cut set against this library primitive.
llvm::FailureOr< Operation * > rewrite(mlir::OpBuilder &builder, CutEnumerator &enumerator, const Cut &cut) const override
Rewrite the cut set using this library primitive.
const SmallVector< DelayType > delay
bool useTruthTableMatcher(SmallVectorImpl< NPNClass > &matchingNPNClasses) const override
Enable truth table matching for this pattern.
unsigned getNumOutputs() const override
Get the number of outputs this pattern produces.
unsigned getNumInputs() const
LocationAttr getLoc() const override
Get location for this pattern(optional).
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.
bool equivalentOtherThanPermutation(const NPNClass &other) const
Equality comparison for NPN classes.
Base class for cut rewriting patterns used in combinational logic optimization.
mlir::MLIRContext * getContext() const
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 attachDebugTiming
Put arrival times to rewritten operations.
OptimizationStrategy strategy
Optimization strategy (area vs. timing).
Result of matching a cut against a pattern.