24#include "mlir/Support/LLVM.h"
25#include "llvm/ADT/APInt.h"
26#include "llvm/ADT/DenseMap.h"
27#include "llvm/ADT/SmallVector.h"
28#include "llvm/Support/Debug.h"
30#define DEBUG_TYPE "synth-sop-balancing"
38#define GEN_PASS_DEF_SOPBALANCING
39#include "circt/Dialect/Synth/Transforms/SynthPasses.h.inc"
53constexpr unsigned expectedISOPInputs = 8;
58 const SOPForm &getOrCompute(
const APInt &truthTable,
unsigned numVars) {
59 auto it = cache.find(truthTable);
60 if (it != cache.end())
68 DenseMap<APInt, SOPForm> cache;
76static DelayType simulateBalancedTree(ArrayRef<DelayType> arrivalTimes) {
77 if (arrivalTimes.empty())
79 return buildBalancedTreeWithArrivalTimes<DelayType>(
80 arrivalTimes, [](
auto a,
auto b) {
return std::max(a, b) + 1; });
85buildBalancedAndTree(OpBuilder &builder, Location loc,
86 SmallVectorImpl<ValueWithArrivalTime> &nodes,
87 size_t &valueNumbering) {
90 if (nodes.size() == 1)
93 auto result = buildBalancedTreeWithArrivalTimes<ValueWithArrivalTime>(
94 nodes, [&](
const auto &n1,
const auto &n2) {
95 Value v = aig::AndInverterOp::create(builder, loc, n1.getValue(),
96 n2.getValue(), n1.isInverted(),
99 v, std::max(n1.getArrivalTime(), n2.getArrivalTime()) + 1,
false,
106Value buildBalancedSOP(OpBuilder &builder, Location loc,
const SOPForm &sop,
107 ArrayRef<Value> inputs,
108 ArrayRef<DelayType> inputArrivalTimes) {
109 SmallVector<ValueWithArrivalTime, expectedISOPInputs> productTerms, literals;
110 size_t valueNumbering = 0;
112 for (
const auto &cube : sop.cubes) {
113 for (
unsigned i = 0; i < sop.
numVars; ++i)
114 if (cube.hasLiteral(i))
116 inputs[i], inputArrivalTimes[i], cube.isLiteralInverted(i),
119 if (literals.empty())
123 productTerms.push_back(
124 buildBalancedAndTree(builder, loc, literals, valueNumbering)
130 assert(!productTerms.empty() &&
"No product terms");
133 buildBalancedAndTree(builder, loc, productTerms, valueNumbering)
136 if (andOfInverted.isInverted())
137 return aig::AndInverterOp::create(builder, loc, andOfInverted.getValue(),
139 return andOfInverted.getValue();
143void computeSOPDelays(
const SOPForm &sop, ArrayRef<DelayType> inputArrivalTimes,
144 SmallVectorImpl<DelayType> &delays) {
145 SmallVector<DelayType, expectedISOPInputs> productArrivalTimes, literalTimes;
146 for (
const auto &cube : sop.cubes) {
147 for (
unsigned i = 0; i < sop.
numVars; ++i)
149 if (cube.hasLiteral(i))
150 literalTimes.push_back(inputArrivalTimes[i]);
151 if (!literalTimes.empty()) {
152 productArrivalTimes.push_back(simulateBalancedTree(literalTimes));
153 literalTimes.clear();
157 DelayType outputTime = simulateBalancedTree(productArrivalTimes);
168 for (
auto &cube : sop.cubes)
172 for (
unsigned i = 0; i < sop.
numVars; ++i)
173 if (mask & (1u << i))
174 delays[i] = outputTime - inputArrivalTimes[i];
186 const Cut &cut)
const override {
192 const SOPForm &sop = sopCache.getOrCompute(tt.table, tt.numInputs);
193 if (sop.
cubes.empty())
196 SmallVector<DelayType, expectedISOPInputs> arrivalTimes;
201 unsigned totalGates = 0;
202 for (
const auto &cube : sop.cubes)
204 totalGates += cube.size() - 1;
205 if (sop.
cubes.size() > 1)
206 totalGates += sop.
cubes.size() - 1;
208 SmallVector<DelayType, expectedISOPInputs> delays;
209 computeSOPDelays(sop, arrivalTimes, delays);
212 result.
area =
static_cast<double>(totalGates);
218 const Cut &cut)
const override {
221 const SOPForm &sop = sopCache.getOrCompute(tt.table, tt.numInputs);
223 llvm::dbgs() <<
"Rewriting SOP:\n";
224 sop.
dump(llvm::dbgs());
227 SmallVector<DelayType, expectedISOPInputs> arrivalTimes;
232 SetVector<Location> inputLocs;
233 auto *rootOp = network.getGate(cut.
getRootIndex()).getOperation();
234 assert(rootOp &&
"cut root must be a valid operation");
235 inputLocs.insert(rootOp->getLoc());
237 SmallVector<Value> inputValues;
238 network.getValues(cut.
inputs, inputValues);
239 for (
auto input : inputValues)
240 inputLocs.insert(input.
getLoc());
242 auto loc = builder.getFusedLoc(inputLocs.getArrayRef());
245 buildBalancedSOP(builder, loc, sop, inputValues, arrivalTimes);
247 auto *op = result.getDefiningOp();
249 op = aig::AndInverterOp::create(builder, loc, result,
false);
254 StringRef
getPatternName()
const override {
return "sop-balancing"; }
259 mutable SOPCache sopCache;
270 using SOPBalancingBase::SOPBalancingBase;
273 auto module = getOperation();
281 SmallVector<std::unique_ptr<CutRewritePattern>, 1>
patterns;
283 std::make_unique<SOPBalancingPattern>(module->getContext()));
287 if (failed(rewriter.
run(module)))
288 return signalPassFailure();
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static Location getLoc(DefSlot slot)
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.
Main cut-based rewriting algorithm for combinational logic optimization.
LogicalResult run(Operation *topOp)
Execute the complete cut-based rewriting algorithm.
Represents a cut in the combinational logic network.
unsigned getOutputSize(const LogicNetwork &network) const
Get the number of outputs from root operation.
const std::optional< BinaryTruthTable > & getTruthTable() const
Get the truth table for this cut.
uint32_t getRootIndex() const
Get the root index in the LogicNetwork.
llvm::SmallVector< uint32_t, 6 > inputs
External inputs to this cut (cut boundary).
LogicalResult getInputArrivalTimes(CutEnumerator &enumerator, SmallVectorImpl< DelayType > &results) const
Get arrival times for each input of this cut.
bool isTrivialCut() const
Check if this cut represents a trivial cut.
Helper class for delay-aware tree building.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
SOPForm extractISOP(const llvm::APInt &truthTable, unsigned numVars)
Extract ISOP (Irredundant Sum-of-Products) from a truth table.
void runOnOperation() override
Base class for cut rewriting patterns used in combinational logic optimization.
virtual StringRef getPatternName() const
Get the name of this pattern. Used for debugging.
virtual FailureOr< Operation * > rewrite(mlir::OpBuilder &builder, CutEnumerator &enumerator, const Cut &cut) const =0
Return a new operation that replaces the matched cut.
virtual std::optional< MatchResult > match(CutEnumerator &enumerator, const Cut &cut) const =0
Check if a cut matches this pattern and compute area/delay metrics.
virtual unsigned getNumOutputs() const =0
Get the number of outputs this pattern produces.
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.
OptimizationStrategy strategy
Optimization strategy (area vs. timing).
Result of matching a cut against a pattern.
void setOwnedDelays(SmallVector< DelayType, 6 > delays)
Set delays by transferring ownership (for dynamically computed delays).
double area
Area cost of implementing this cut with the pattern.