CIRCT 23.0.0git
Loading...
Searching...
No Matches
TechMapper.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the TechMapper pass, which performs technology mapping
10// by converting logic network representations (AIG operations) into
11// technology-specific gate implementations using cut-based rewriting.
12//
13// The pass uses a cut-based algorithm with priority cuts and NPN canonical
14// forms for efficient pattern matching. It processes HWModuleOp instances with
15// "hw.techlib.info" attributes as technology library patterns and maps
16// non-library modules to optimal gate implementations based on area and timing
17// optimization strategies.
18//
19//===----------------------------------------------------------------------===//
20
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"
29
30namespace circt {
31namespace synth {
32#define GEN_PASS_DEF_TECHMAPPER
33#include "circt/Dialect/Synth/Transforms/SynthPasses.h.inc"
34} // namespace synth
35} // namespace circt
36
37using namespace circt;
38using namespace circt::synth;
39
40#define DEBUG_TYPE "synth-tech-mapper"
41
42//===----------------------------------------------------------------------===//
43// Tech Mapper Pass
44//===----------------------------------------------------------------------===//
45
46static llvm::FailureOr<NPNClass> getNPNClassFromModule(hw::HWModuleOp module) {
47 // Get input and output ports
48 auto inputTypes = module.getInputTypes();
49 auto outputTypes = module.getOutputTypes();
50
51 unsigned numInputs = inputTypes.size();
52 unsigned numOutputs = outputTypes.size();
53 if (numOutputs != 1)
54 return module->emitError(
55 "Modules with multiple outputs are not supported yet");
56
57 // Verify all ports are single bit
58 for (auto type : inputTypes) {
59 if (!type.isInteger(1))
60 return module->emitError("All input ports must be single bit");
61 }
62 for (auto type : outputTypes) {
63 if (!type.isInteger(1))
64 return module->emitError("All output ports must be single bit");
65 }
66
67 if (numInputs > maxTruthTableInputs)
68 return module->emitError("Too many inputs for truth table generation");
69
70 SmallVector<Value> results;
71 results.reserve(numOutputs);
72 // Get the body block of the module
73 auto *bodyBlock = module.getBodyBlock();
74 assert(bodyBlock && "Module must have a body block");
75 // Collect output values from the body block
76 for (auto result : bodyBlock->getTerminator()->getOperands())
77 results.push_back(result);
78
79 // Create a truth table for the module
80 FailureOr<BinaryTruthTable> truthTable = getTruthTable(results, bodyBlock);
81 if (failed(truthTable))
82 return failure();
83
84 return NPNClass::computeNPNCanonicalForm(*truthTable);
85}
86
87/// Simple technology library encoded as a HWModuleOp.
90 SmallVector<DelayType> delay, NPNClass npnClass)
92 delay(std::move(delay)), module(module), npnClass(std::move(npnClass)) {
93
94 LLVM_DEBUG({
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()
99 << "\n"
100 << "Input Negation: " << this->npnClass.inputNegation << "\n"
101 << "Output Negation: " << this->npnClass.outputNegation
102 << "\n";
103 });
104 }
105
106 StringRef getPatternName() const override {
107 auto moduleCp = module;
108 return moduleCp.getModuleName();
109 }
110
111 /// Match the cut set against this library primitive
112 std::optional<MatchResult> match(CutEnumerator &enumerator,
113 const Cut &cut) const override {
115 return std::nullopt;
116
117 return MatchResult(area, delay);
118 }
119
120 /// Enable truth table matching for this pattern
122 SmallVectorImpl<NPNClass> &matchingNPNClasses) const override {
123 matchingNPNClasses.push_back(npnClass);
124 return true;
125 }
126
127 /// Rewrite the cut set using this library primitive
128 llvm::FailureOr<Operation *> rewrite(mlir::OpBuilder &builder,
129 CutEnumerator &enumerator,
130 const Cut &cut) const override {
131 const auto &network = enumerator.getLogicNetwork();
132 // Create a new instance of the module
133 SmallVector<unsigned> permutedInputIndices;
134 cut.getPermutatedInputIndices(npnClass, permutedInputIndices);
135
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]));
141 }
142
143 auto *rootOp = network.getGate(cut.getRootIndex()).getOperation();
144 assert(rootOp && "cut root must be a valid operation");
145
146 // TODO: Give a better name to the instance
147 auto instanceOp = hw::InstanceOp::create(builder, rootOp->getLoc(), module,
148 "mapped", ArrayRef<Value>(inputs));
149 return instanceOp.getOperation();
150 }
151
152 unsigned getNumInputs() const {
153 return static_cast<hw::HWModuleOp>(module).getNumInputPorts();
154 }
155
156 unsigned getNumOutputs() const override {
157 return static_cast<hw::HWModuleOp>(module).getNumOutputPorts();
158 }
159
160 LocationAttr getLoc() const override {
161 auto module = this->module;
162 return module.getLoc();
163 }
164
165private:
166 const double area;
167 const SmallVector<DelayType> delay;
168 hw::HWModuleOp module;
170};
171
172namespace {
173struct TechMapperPass : public impl::TechMapperBase<TechMapperPass> {
174 using TechMapperBase<TechMapperPass>::TechMapperBase;
175
176 void runOnOperation() override {
177 auto module = getOperation();
178
179 SmallVector<std::unique_ptr<CutRewritePattern>> libraryPatterns;
180
181 unsigned maxInputSize = 0;
182 // Consider modules with the "hw.techlib.info" attribute as library
183 // modules.
184 // TODO: This attribute should be replaced with a more structured
185 // representation of technology library information. Specifically, we should
186 // have a dedicated operation for technology library.
187 SmallVector<hw::HWModuleOp> nonLibraryModules;
188 for (auto hwModule : module.getOps<hw::HWModuleOp>()) {
189 auto techInfo =
190 hwModule->getAttrOfType<DictionaryAttr>("hw.techlib.info");
191 if (!techInfo) {
192 // If the module does not have the techlib info, it is not a library
193 // TODO: Run mapping only when the module is under the specific
194 // hierarchy.
195 nonLibraryModules.push_back(hwModule);
196 continue;
197 }
198
199 // Get area and delay attributes
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";
207 signalPassFailure();
208 return;
209 }
210
211 double area = areaAttr.getValue().convertToDouble();
212
213 SmallVector<DelayType> delay;
214 for (auto delayValue : delayAttr) {
215 auto delayArray = cast<ArrayAttr>(delayValue);
216 for (auto delayElement : delayArray) {
217 // FIXME: Currently we assume delay is given as integer attributes,
218 // this should be replaced once we have a proper cell op with
219 // dedicated timing attributes with units.
220 delay.push_back(
221 cast<mlir::IntegerAttr>(delayElement).getValue().getZExtValue());
222 }
223 }
224 // Compute NPN Class for the module.
225 auto npnClass = getNPNClassFromModule(hwModule);
226 if (failed(npnClass)) {
227 signalPassFailure();
228 return;
229 }
230
231 // Create a CutRewritePattern for the library module
232 std::unique_ptr<TechLibraryPattern> pattern =
233 std::make_unique<TechLibraryPattern>(hwModule, area, std::move(delay),
234 std::move(*npnClass));
235
236 // Update the maximum input size
237 maxInputSize = std::max(maxInputSize, pattern->getNumInputs());
238
239 // Add the pattern to the library
240 libraryPatterns.push_back(std::move(pattern));
241 }
242
243 if (libraryPatterns.empty())
244 return markAllAnalysesPreserved();
245
246 CutRewritePatternSet patternSet(std::move(libraryPatterns));
247 CutRewriterOptions options;
248 options.strategy = strategy;
249 options.maxCutInputSize = maxInputSize;
250 options.maxCutSizePerRoot = maxCutsPerRoot;
251 options.attachDebugTiming = test;
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);
258 });
259 if (failed(result))
260 signalPassFailure();
261 }
262};
263
264} // namespace
assert(baseType &&"element must be base type")
RewritePatternSet pattern
Strategy strategy
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.
Definition CutRewriter.h:44
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition synth.py:1
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
const double area
LocationAttr getLoc() const override
Get location for this pattern(optional).
Represents the canonical form of a boolean function under NPN equivalence.
Definition TruthTable.h:104
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.
Definition TruthTable.h:147
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.