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())
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)
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];
183 SOPBalancingPattern(MLIRContext *
context) : CutRewritePattern(
context) {}
185 std::optional<MatchResult> match(CutEnumerator &enumerator,
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);
217 FailureOr<Operation *> rewrite(OpBuilder &builder, CutEnumerator &enumerator,
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);
253 unsigned getNumOutputs()
const override {
return 1; }
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();
290 const auto &stats = rewriter.
getStats();
292 numCutSetsCreated += stats.numCutSetsCreated;
293 numCutsRewritten += stats.numCutsRewritten;
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
false return failure()
Parse an optional keyword or string and set instance into 'result'.
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.
const CutEnumeratorStats & getStats() const
LogicalResult run(Operation *topOp)
Execute the complete cut-based rewriting algorithm.
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.
T buildBalancedTreeWithArrivalTimes(llvm::ArrayRef< T > elements, llvm::function_ref< T(T, T)> combine)
Build a balanced binary tree using a priority queue to greedily pair elements with earliest arrival t...
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.
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).
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.