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"
32#define GEN_PASS_DEF_TECHMAPPER
33#include "circt/Dialect/Synth/Transforms/SynthPasses.h.inc"
40#define DEBUG_TYPE "synth-tech-mapper"
48 auto inputTypes =
module.getInputTypes();
49 auto outputTypes =
module.getOutputTypes();
51 unsigned numInputs = inputTypes.size();
52 unsigned numOutputs = outputTypes.size();
54 return module->emitError(
55 "Modules with multiple outputs are not supported yet");
58 for (
auto type : inputTypes) {
59 if (!type.isInteger(1))
60 return module->emitError(
"All input ports must be single bit");
62 for (
auto type : outputTypes) {
63 if (!type.isInteger(1))
64 return module->emitError(
"All output ports must be single bit");
68 return module->emitError("Too many inputs for truth table generation");
70 SmallVector<Value> results;
71 results.reserve(numOutputs);
73 auto *bodyBlock =
module.getBodyBlock();
74 assert(bodyBlock &&
"Module must have a body block");
76 for (
auto result : bodyBlock->getTerminator()->getOperands())
77 results.push_back(result);
80 FailureOr<BinaryTruthTable> truthTable =
getTruthTable(results, bodyBlock);
81 if (failed(truthTable))
95 llvm::dbgs() <<
"Created Tech Library Pattern for module: "
96 <<
module.getModuleName() << "\n"
97 << "NPN Class: " << this->npnClass.truthTable.table << "\n"
98 << "Inputs: " << this->npnClass.inputPermutation.size()
100 << "Input Negation: " << this->npnClass.inputNegation << "\n"
101 << "Output Negation: " << this->npnClass.outputNegation
107 auto moduleCp =
module;
108 return moduleCp.getModuleName();
113 const Cut &cut)
const override {
122 SmallVectorImpl<NPNClass> &matchingNPNClasses)
const override {
123 matchingNPNClasses.push_back(
npnClass);
128 llvm::FailureOr<Operation *>
rewrite(mlir::OpBuilder &builder,
130 const Cut &cut)
const override {
133 SmallVector<unsigned> permutedInputIndices;
136 SmallVector<Value> inputs;
137 inputs.reserve(permutedInputIndices.size());
138 for (
unsigned idx : permutedInputIndices) {
139 assert(idx < cut.
inputs.size() &&
"input permutation index out of range");
140 inputs.push_back(network.getValue(cut.
inputs[idx]));
143 auto *rootOp = network.getGate(cut.
getRootIndex()).getOperation();
144 assert(rootOp &&
"cut root must be a valid operation");
147 auto instanceOp = hw::InstanceOp::create(builder, rootOp->getLoc(), module,
148 "mapped", ArrayRef<Value>(inputs));
149 return instanceOp.getOperation();
161 auto module = this->module;
162 return module.getLoc();
173struct TechMapperPass :
public impl::TechMapperBase<TechMapperPass> {
174 using TechMapperBase<TechMapperPass>::TechMapperBase;
176 void runOnOperation()
override {
177 auto module = getOperation();
179 SmallVector<std::unique_ptr<CutRewritePattern>> libraryPatterns;
181 unsigned maxInputSize = 0;
187 SmallVector<hw::HWModuleOp> nonLibraryModules;
188 for (
auto hwModule :
module.getOps<hw::HWModuleOp>()) {
190 hwModule->getAttrOfType<DictionaryAttr>("hw.techlib.info");
195 nonLibraryModules.push_back(hwModule);
200 auto areaAttr = techInfo.getAs<FloatAttr>(
"area");
201 auto delayAttr = techInfo.getAs<ArrayAttr>(
"delay");
202 if (!areaAttr || !delayAttr) {
203 mlir::emitError(hwModule.getLoc())
204 <<
"Library module " << hwModule.getModuleName()
205 <<
" must have 'area'(float) and 'delay' (2d array to represent "
206 "input-output pair delay) attributes";
211 double area = areaAttr.getValue().convertToDouble();
213 SmallVector<DelayType> delay;
214 for (
auto delayValue : delayAttr) {
215 auto delayArray = cast<ArrayAttr>(delayValue);
216 for (
auto delayElement : delayArray) {
221 cast<mlir::IntegerAttr>(delayElement).getValue().getZExtValue());
226 if (failed(npnClass)) {
232 std::unique_ptr<TechLibraryPattern>
pattern =
233 std::make_unique<TechLibraryPattern>(hwModule, area, std::move(delay),
234 std::move(*npnClass));
237 maxInputSize = std::max(maxInputSize,
pattern->getNumInputs());
240 libraryPatterns.push_back(std::move(
pattern));
243 if (libraryPatterns.empty())
244 return markAllAnalysesPreserved();
252 auto result = mlir::failableParallelForEach(
253 module.getContext(), nonLibraryModules, [&](
hw::HWModuleOp hwModule) {
254 LLVM_DEBUG(llvm::dbgs() <<
"Processing non-library module: "
255 << hwModule.getName() <<
"\n");
256 CutRewriter rewriter(options, patternSet);
257 return rewriter.run(hwModule);
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.