CIRCT 22.0.0git
Loading...
Searching...
No Matches
SimplifyTruthTable.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 SimplifyTruthTable pass, which simplifies truth
10// tables that depend on one or fewer inputs.
11//
12//===----------------------------------------------------------------------===//
13
18#include "mlir/IR/PatternMatch.h"
19#include "mlir/Transforms/WalkPatternRewriteDriver.h"
20#include "llvm/Support/LogicalResult.h"
21
22using namespace circt;
23using namespace comb;
24
25namespace circt {
26namespace comb {
27#define GEN_PASS_DEF_SIMPLIFYTRUTHTABLE
28#include "circt/Dialect/Comb/Passes.h.inc"
29} // namespace comb
30} // namespace circt
31
32namespace {
33
34// Helper to check if operation is trivially recursive
35static bool isOpTriviallyRecursive(Operation *op) {
36 return llvm::any_of(op->getOperands(), [op](auto operand) {
37 return operand.getDefiningOp() == op;
38 });
39}
40
41// Pattern to simplify truth tables
42struct SimplifyTruthTable : public OpRewritePattern<TruthTableOp> {
43 using OpRewritePattern::OpRewritePattern;
44
45 LogicalResult matchAndRewrite(TruthTableOp op,
46 PatternRewriter &rewriter) const override {
48 return failure();
49
50 const auto inputs = op.getInputs();
51 const auto table = op.getLookupTable();
52 size_t numInputs = inputs.size();
53 size_t tableSize = table.size();
54
55 if (numInputs <= 1)
56 return failure();
57
58 // Check if all table entries are the same (constant output)
59 bool allSame = llvm::all_equal(table);
60 if (allSame) {
61 bool firstValue = cast<BoolAttr>(table[0]).getValue();
62 auto constOp =
63 hw::ConstantOp::create(rewriter, op.getLoc(), APInt(1, firstValue));
64 replaceOpAndCopyNamehint(rewriter, op, constOp);
65 return success();
66 }
67
68 // Detect if the truth table depends only on one of the inputs.
69 // For each input bit, we test whether flipping only that input bit changes
70 // the output value of the truth table at any point.
71 SmallVector<bool> dependsOn(numInputs, false);
72 int dependentInput = -1;
73 unsigned numDependencies = 0;
74
75 for (size_t idx = 0; idx < tableSize; ++idx) {
76 bool currentValue = cast<BoolAttr>(table[idx]).getValue();
77
78 for (size_t bitPos = 0; bitPos < numInputs; ++bitPos) {
79 // Skip if we already know this input matters
80 if (dependsOn[bitPos])
81 continue;
82
83 // Calculate the index of the entry with the bit in question flipped
84 size_t bitPositionInTable = numInputs - 1 - bitPos;
85 size_t flippedIdx = idx ^ (1ull << bitPositionInTable);
86 bool flippedValue = cast<BoolAttr>(table[flippedIdx]).getValue();
87
88 // If flipping this bit changes the output, this input is a dependency
89 if (currentValue != flippedValue) {
90 dependsOn[bitPos] = true;
91 dependentInput = bitPos;
92 numDependencies++;
93
94 // Exit early if we already found more than one dependency
95 if (numDependencies > 1)
96 break;
97 }
98 }
99
100 // Exit early from outer loop if we found more than one dependency
101 if (numDependencies > 1)
102 break;
103 }
104
105 // Only simplify if exactly one input dependency found
106 if (numDependencies != 1)
107 return failure();
108
109 // Determine if the truth table is identity or inverted by checking the
110 // output when the dependent input is 1 (all other inputs at 0)
111 size_t bitPositionInTable = numInputs - 1 - dependentInput;
112 size_t idxWhen1 = 1ull << bitPositionInTable;
113 bool isIdentity = cast<BoolAttr>(table[idxWhen1]).getValue();
114
115 // Replace with the input or a simpler truth table for negation
116 Value input = inputs[dependentInput];
117 if (isIdentity) {
118 // Identity case: just replace with the input directly
119 replaceOpAndCopyNamehint(rewriter, op, input);
120 } else {
121 // Inverted case: replace with a single-input truth table for negation
122 // This avoids introducing comb.xor, which is useful for LUT mapping
123 replaceOpWithNewOpAndCopyNamehint<TruthTableOp>(
124 rewriter, op, ValueRange{input},
125 rewriter.getBoolArrayAttr({true, false}));
126 }
127 return success();
128 }
129};
130
131class SimplifyTruthTablePass
132 : public impl::SimplifyTruthTableBase<SimplifyTruthTablePass> {
133public:
134 using SimplifyTruthTableBase::SimplifyTruthTableBase;
135 void runOnOperation() override;
136};
137
138} // namespace
139
140void SimplifyTruthTablePass::runOnOperation() {
141 Operation *op = getOperation();
142 MLIRContext *context = op->getContext();
143 RewritePatternSet patterns(context);
144 patterns.add<SimplifyTruthTable>(context);
145 walkAndApplyPatterns(op, std::move(patterns));
146}
static bool isOpTriviallyRecursive(Operation *op)
Definition CombFolds.cpp:27
static std::unique_ptr< Context > context
create(data_type, value)
Definition hw.py:433
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void replaceOpAndCopyNamehint(PatternRewriter &rewriter, Operation *op, Value newValue)
A wrapper of PatternRewriter::replaceOp to propagate "sv.namehint" attribute.
Definition Naming.cpp:73
Definition comb.py:1