CIRCT 23.0.0git
Loading...
Searching...
No Matches
SynthToComb.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 is the main Synth to Comb Conversion Pass Implementation.
10//
11//===----------------------------------------------------------------------===//
12
18#include "mlir/Pass/Pass.h"
19#include "mlir/Transforms/DialectConversion.h"
20
21namespace circt {
22#define GEN_PASS_DEF_CONVERTSYNTHTOCOMB
23#include "circt/Conversion/Passes.h.inc"
24} // namespace circt
25
26using namespace circt;
27using namespace comb;
28
29//===----------------------------------------------------------------------===//
30// Conversion patterns
31//===----------------------------------------------------------------------===//
32
33namespace {
34
35// Return a value that represents the inverted input if `inverted` is true,
36static Value materializeInvertedInput(Location loc, Value input, bool inverted,
37 ConversionPatternRewriter &rewriter,
38 hw::ConstantOp &allOnes) {
39 if (!inverted)
40 return input;
41 auto width = input.getType().getIntOrFloatBitWidth();
42 if (!allOnes)
43 allOnes = hw::ConstantOp::create(rewriter, loc, APInt::getAllOnes(width));
44 return rewriter.createOrFold<comb::XorOp>(loc, input, allOnes, true);
45}
46
47struct SynthChoiceOpConversion : OpConversionPattern<synth::ChoiceOp> {
48 using OpConversionPattern<synth::ChoiceOp>::OpConversionPattern;
49 LogicalResult
50 matchAndRewrite(synth::ChoiceOp op, OpAdaptor adaptor,
51 ConversionPatternRewriter &rewriter) const override {
52 // Use the first input as the output, and ignore the rest.
53 rewriter.replaceOp(op, adaptor.getInputs().front());
54 return success();
55 }
56};
57
58template <typename SynthOp>
59struct SynthInverterOpConversion : OpConversionPattern<SynthOp> {
61 // Subclasses provide the target comb op after generic input inversion has
62 // been materialized.
63 virtual Value createOp(Location loc, ArrayRef<Value> inputs,
64 ConversionPatternRewriter &rewriter) const = 0;
65
66 virtual LogicalResult
67 matchAndRewrite(SynthOp op, typename SynthOp::Adaptor adaptor,
68 ConversionPatternRewriter &rewriter) const override {
69 SmallVector<Value> operands;
70 operands.reserve(op.getNumOperands());
71 hw::ConstantOp allOnes;
72 for (auto [input, inverted] :
73 llvm::zip(adaptor.getOperands(), op.getInverted()))
74 operands.push_back(materializeInvertedInput(op.getLoc(), input, inverted,
75 rewriter, allOnes));
76 // `createOp` now only needs to encode the core boolean operator.
77 rewriter.replaceOp(op, createOp(op.getLoc(), operands, rewriter));
78 return success();
79 }
80};
81
82struct SynthAndInverterOpConversion
83 : SynthInverterOpConversion<synth::aig::AndInverterOp> {
84 using SynthInverterOpConversion<
85 synth::aig::AndInverterOp>::SynthInverterOpConversion;
86 Value createOp(Location loc, ArrayRef<Value> inputs,
87 ConversionPatternRewriter &rewriter) const override {
88 return rewriter.createOrFold<comb::AndOp>(loc, inputs, true);
89 }
90};
91
92struct SynthXorInverterOpConversion
93 : SynthInverterOpConversion<synth::XorInverterOp> {
94 using SynthInverterOpConversion<
95 synth::XorInverterOp>::SynthInverterOpConversion;
96 Value createOp(Location loc, ArrayRef<Value> inputs,
97 ConversionPatternRewriter &rewriter) const override {
98 return rewriter.createOrFold<comb::XorOp>(loc, inputs, true);
99 }
100};
101
102struct SynthDotOpConversion : SynthInverterOpConversion<synth::DotOp> {
103 using SynthInverterOpConversion<synth::DotOp>::SynthInverterOpConversion;
104 Value createOp(Location loc, ArrayRef<Value> inputs,
105 ConversionPatternRewriter &rewriter) const override {
106 assert(inputs.size() == 3 && "expected exactly three inputs");
107 auto xy =
108 rewriter.createOrFold<comb::AndOp>(loc, inputs[0], inputs[1], true);
109 auto zOrXy = rewriter.createOrFold<comb::OrOp>(loc, inputs[2], xy, true);
110 return rewriter.createOrFold<comb::XorOp>(loc, inputs[0], zOrXy, true);
111 }
112};
113
114struct SynthMajorityOpConversion
115 : SynthInverterOpConversion<synth::MajorityOp> {
116 using SynthInverterOpConversion<synth::MajorityOp>::SynthInverterOpConversion;
117 Value createOp(Location loc, ArrayRef<Value> inputs,
118 ConversionPatternRewriter &rewriter) const override {
119 assert(inputs.size() == 3 && "expected exactly three inputs");
120 auto ab =
121 rewriter.createOrFold<comb::AndOp>(loc, inputs[0], inputs[1], true);
122 auto ac =
123 rewriter.createOrFold<comb::AndOp>(loc, inputs[0], inputs[2], true);
124 auto bc =
125 rewriter.createOrFold<comb::AndOp>(loc, inputs[1], inputs[2], true);
126 auto abOrAc = rewriter.createOrFold<comb::OrOp>(loc, ab, ac, true);
127 return rewriter.createOrFold<comb::OrOp>(loc, abOrAc, bc, true);
128 }
129};
130
131struct SynthOneHotOpConversion : SynthInverterOpConversion<synth::OneHotOp> {
132 using SynthInverterOpConversion<synth::OneHotOp>::SynthInverterOpConversion;
133 Value createOp(Location loc, ArrayRef<Value> inputs,
134 ConversionPatternRewriter &rewriter) const override {
135 assert(inputs.size() == 3 && "expected exactly three inputs");
136 auto width = inputs[0].getType().getIntOrFloatBitWidth();
137 auto allOnes =
138 hw::ConstantOp::create(rewriter, loc, APInt::getAllOnes(width));
139
140 // NOT each input
141 auto notA = rewriter.createOrFold<comb::XorOp>(loc, inputs[0],
142 allOnes.getResult(), true);
143 auto notB = rewriter.createOrFold<comb::XorOp>(loc, inputs[1],
144 allOnes.getResult(), true);
145 auto notC = rewriter.createOrFold<comb::XorOp>(loc, inputs[2],
146 allOnes.getResult(), true);
147
148 auto aOnly = rewriter.createOrFold<comb::AndOp>(
149 loc, ValueRange{inputs[0], notB, notC}, true);
150 auto bOnly = rewriter.createOrFold<comb::AndOp>(
151 loc, ValueRange{notA, inputs[1], notC}, true);
152 auto cOnly = rewriter.createOrFold<comb::AndOp>(
153 loc, ValueRange{notA, notB, inputs[2]}, true);
154 return rewriter.createOrFold<comb::OrOp>(
155 loc, ValueRange{aOnly, bOnly, cOnly}, true);
156 }
157};
158
159struct SynthMuxInverterOpConversion
160 : SynthInverterOpConversion<synth::MuxInverterOp> {
161 using SynthInverterOpConversion<
162 synth::MuxInverterOp>::SynthInverterOpConversion;
163
164 Value createOp(Location loc, ArrayRef<Value> inputs,
165 ConversionPatternRewriter &rewriter) const override {
166 assert(inputs.size() == 3 && "expected exactly three inputs");
167
168 auto width = inputs[0].getType().getIntOrFloatBitWidth();
169 auto allOnes =
170 hw::ConstantOp::create(rewriter, loc, APInt::getAllOnes(width));
171
172 auto notCond =
173 rewriter.createOrFold<comb::XorOp>(loc, inputs[0], allOnes, true);
174 auto trueValue =
175 rewriter.createOrFold<comb::AndOp>(loc, inputs[0], inputs[1], true);
176 auto falseValue =
177 rewriter.createOrFold<comb::AndOp>(loc, notCond, inputs[2], true);
178
179 return rewriter.createOrFold<comb::OrOp>(loc, trueValue, falseValue, true);
180 }
181};
182
183} // namespace
184
185//===----------------------------------------------------------------------===//
186// Convert Synth to Comb pass
187//===----------------------------------------------------------------------===//
188
189namespace {
190struct ConvertSynthToCombPass
191 : public impl::ConvertSynthToCombBase<ConvertSynthToCombPass> {
192
193 void runOnOperation() override;
194 using ConvertSynthToCombBase<ConvertSynthToCombPass>::ConvertSynthToCombBase;
195};
196} // namespace
197
198static void populateSynthToCombConversionPatterns(RewritePatternSet &patterns) {
199 patterns.add<SynthChoiceOpConversion, SynthAndInverterOpConversion,
200 SynthXorInverterOpConversion, SynthMuxInverterOpConversion,
201 SynthDotOpConversion, SynthMajorityOpConversion,
202 SynthOneHotOpConversion>(patterns.getContext());
203}
204
205void ConvertSynthToCombPass::runOnOperation() {
206 ConversionTarget target(getContext());
207 target.addLegalDialect<comb::CombDialect, hw::HWDialect>();
208 target.addIllegalDialect<synth::SynthDialect>();
209
210 RewritePatternSet patterns(&getContext());
212
213 if (failed(mlir::applyPartialConversion(getOperation(), target,
214 std::move(patterns))))
215 return signalPassFailure();
216}
assert(baseType &&"element must be base type")
static Location getLoc(DefSlot slot)
Definition Mem2Reg.cpp:218
static void populateSynthToCombConversionPatterns(RewritePatternSet &patterns)
create(data_type, value)
Definition hw.py:433
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition comb.py:1