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) {
89 if (nodes.size() == 1)
92 size_t num = nodes.size();
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;
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), num++));
119 if (literals.empty())
123 productTerms.push_back(
124 buildBalancedAndTree(builder, loc, literals).flipInversion());
129 assert(!productTerms.empty() &&
"No product terms");
132 buildBalancedAndTree(builder, loc, productTerms).flipInversion();
134 if (andOfInverted.isInverted())
135 return aig::AndInverterOp::create(builder, loc, andOfInverted.getValue(),
137 return andOfInverted.getValue();
141void computeSOPDelays(
const SOPForm &sop, ArrayRef<DelayType> inputArrivalTimes,
142 SmallVectorImpl<DelayType> &delays) {
143 SmallVector<DelayType, expectedISOPInputs> productArrivalTimes, literalTimes;
144 for (
const auto &cube : sop.cubes) {
145 for (
unsigned i = 0; i < sop.
numVars; ++i)
147 if (cube.hasLiteral(i))
148 literalTimes.push_back(inputArrivalTimes[i]);
149 if (!literalTimes.empty()) {
150 productArrivalTimes.push_back(simulateBalancedTree(literalTimes));
151 literalTimes.clear();
155 DelayType outputTime = simulateBalancedTree(productArrivalTimes);
166 for (
auto &cube : sop.cubes)
170 for (
unsigned i = 0; i < sop.
numVars; ++i)
171 if (mask & (1u << i))
172 delays[i] = outputTime - inputArrivalTimes[i];
184 const Cut &cut)
const override {
189 const SOPForm &sop = sopCache.getOrCompute(tt.table, tt.numInputs);
190 if (sop.
cubes.empty())
193 SmallVector<DelayType, expectedISOPInputs> arrivalTimes;
198 unsigned totalGates = 0;
199 for (
const auto &cube : sop.cubes)
201 totalGates += cube.size() - 1;
202 if (sop.
cubes.size() > 1)
203 totalGates += sop.
cubes.size() - 1;
205 SmallVector<DelayType, expectedISOPInputs> delays;
206 computeSOPDelays(sop, arrivalTimes, delays);
209 result.
area =
static_cast<double>(totalGates);
215 const Cut &cut)
const override {
217 const SOPForm &sop = sopCache.getOrCompute(tt.table, tt.numInputs);
219 llvm::dbgs() <<
"Rewriting SOP:\n";
220 sop.
dump(llvm::dbgs());
223 SmallVector<DelayType, expectedISOPInputs> arrivalTimes;
227 SetVector<Location> inputLocs;
228 inputLocs.insert(cut.
getRoot()->getLoc());
229 for (
auto input : cut.inputs)
230 inputLocs.insert(input.
getLoc());
232 auto loc = builder.getFusedLoc(inputLocs.getArrayRef());
234 Value result = buildBalancedSOP(builder, loc, sop, cut.
inputs.getArrayRef(),
237 auto *op = result.getDefiningOp();
239 op = aig::AndInverterOp::create(builder, loc, result,
false);
244 StringRef
getPatternName()
const override {
return "sop-balancing"; }
249 mutable SOPCache sopCache;
260 using SOPBalancingBase::SOPBalancingBase;
263 auto module = getOperation();
271 SmallVector<std::unique_ptr<CutRewritePattern>, 1>
patterns;
273 std::make_unique<SOPBalancingPattern>(module->getContext()));
277 if (failed(rewriter.
run(module)))
278 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.
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
Get the number of outputs from root operation.
mlir::Operation * getRoot() const
Get the root operation of this cut.
LogicalResult getInputArrivalTimes(CutEnumerator &enumerator, SmallVectorImpl< DelayType > &results) const
Get arrival times for each input of this cut.
llvm::SmallSetVector< mlir::Value, 4 > inputs
External inputs to this cut (cut boundary).
const BinaryTruthTable & getTruthTable() const
Get the truth table for 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.