@@ -25,6 +25,39 @@ namespace circt {
25
25
using namespace circt ;
26
26
using namespace comb ;
27
27
28
+ // ===----------------------------------------------------------------------===//
29
+ // Utility Functions
30
+ // ===----------------------------------------------------------------------===//
31
+
32
+ // Extract individual bits from a value
33
+ static SmallVector<Value> extractBits (ConversionPatternRewriter &rewriter,
34
+ Value val) {
35
+ assert (val.getType ().isInteger () && " expected integer" );
36
+ auto width = val.getType ().getIntOrFloatBitWidth ();
37
+ SmallVector<Value> bits;
38
+ bits.reserve (width);
39
+
40
+ // Check if we can reuse concat operands
41
+ if (auto concat = val.getDefiningOp <comb::ConcatOp>()) {
42
+ if (concat.getNumOperands () == width &&
43
+ llvm::all_of (concat.getOperandTypes (), [](Type type) {
44
+ return type.getIntOrFloatBitWidth () == 1 ;
45
+ })) {
46
+ // Reverse the operands to match the bit order
47
+ bits.append (std::make_reverse_iterator (concat.getOperands ().end ()),
48
+ std::make_reverse_iterator (concat.getOperands ().begin ()));
49
+ return bits;
50
+ }
51
+ }
52
+
53
+ // Extract individual bits
54
+ for (int64_t i = 0 ; i < width; ++i)
55
+ bits.push_back (
56
+ rewriter.createOrFold <comb::ExtractOp>(val.getLoc (), val, i, 1 ));
57
+
58
+ return bits;
59
+ }
60
+
28
61
// ===----------------------------------------------------------------------===//
29
62
// Conversion patterns
30
63
// ===----------------------------------------------------------------------===//
@@ -169,6 +202,87 @@ struct CombMuxOpConversion : OpConversionPattern<MuxOp> {
169
202
}
170
203
};
171
204
205
+ struct CombAddOpConversion : OpConversionPattern<AddOp> {
206
+ using OpConversionPattern<AddOp>::OpConversionPattern;
207
+ LogicalResult
208
+ matchAndRewrite (AddOp op, OpAdaptor adaptor,
209
+ ConversionPatternRewriter &rewriter) const override {
210
+ auto inputs = adaptor.getInputs ();
211
+ // Lower only when there are two inputs.
212
+ // Variadic operands must be lowered in a different pattern.
213
+ if (inputs.size () != 2 )
214
+ return failure ();
215
+
216
+ auto width = op.getType ().getIntOrFloatBitWidth ();
217
+ // Skip a zero width value.
218
+ if (width == 0 ) {
219
+ rewriter.replaceOpWithNewOp <hw::ConstantOp>(op, op.getType (), 0 );
220
+ return success ();
221
+ }
222
+
223
+ // Implement a naive Ripple-carry full adder.
224
+ Value carry;
225
+
226
+ auto aBits = extractBits (rewriter, inputs[0 ]);
227
+ auto bBits = extractBits (rewriter, inputs[1 ]);
228
+ SmallVector<Value> results;
229
+ results.resize (width);
230
+ for (int64_t i = 0 ; i < width; ++i) {
231
+ SmallVector<Value> xorOperands = {aBits[i], bBits[i]};
232
+ if (carry)
233
+ xorOperands.push_back (carry);
234
+
235
+ // sum[i] = xor(carry[i-1], a[i], b[i])
236
+ // NOTE: The result is stored in reverse order.
237
+ results[width - i - 1 ] =
238
+ rewriter.create <comb::XorOp>(op.getLoc (), xorOperands, true );
239
+
240
+ // If this is the last bit, we are done.
241
+ if (i == width - 1 ) {
242
+ break ;
243
+ }
244
+
245
+ // carry[i] = (carry[i-1] & (a[i] ^ b[i])) | (a[i] & b[i])
246
+ Value nextCarry = rewriter.create <comb::AndOp>(
247
+ op.getLoc (), ValueRange{aBits[i], bBits[i]}, true );
248
+ if (!carry) {
249
+ // This is the first bit, so the carry is the next carry.
250
+ carry = nextCarry;
251
+ continue ;
252
+ }
253
+
254
+ auto aXnorB = rewriter.create <comb::XorOp>(
255
+ op.getLoc (), ValueRange{aBits[i], bBits[i]}, true );
256
+ auto andOp = rewriter.create <comb::AndOp>(
257
+ op.getLoc (), ValueRange{carry, aXnorB}, true );
258
+ carry = rewriter.create <comb::OrOp>(op.getLoc (),
259
+ ValueRange{andOp, nextCarry}, true );
260
+ }
261
+
262
+ rewriter.replaceOpWithNewOp <comb::ConcatOp>(op, results);
263
+ return success ();
264
+ }
265
+ };
266
+
267
+ struct CombSubOpConversion : OpConversionPattern<SubOp> {
268
+ using OpConversionPattern<SubOp>::OpConversionPattern;
269
+ LogicalResult
270
+ matchAndRewrite (SubOp op, OpAdaptor adaptor,
271
+ ConversionPatternRewriter &rewriter) const override {
272
+ auto lhs = op.getLhs ();
273
+ auto rhs = op.getRhs ();
274
+ // Since `-rhs = ~rhs + 1` holds, rewrite `sub(lhs, rhs)` to:
275
+ // sub(lhs, rhs) => add(lhs, -rhs) => add(lhs, add(~rhs, 1))
276
+ // => add(lhs, ~rhs, 1)
277
+ auto notRhs = rewriter.create <aig::AndInverterOp>(op.getLoc (), rhs,
278
+ /* invert=*/ true );
279
+ auto one = rewriter.create <hw::ConstantOp>(op.getLoc (), op.getType (), 1 );
280
+ rewriter.replaceOpWithNewOp <comb::AddOp>(op, ValueRange{lhs, notRhs, one},
281
+ true );
282
+ return success ();
283
+ }
284
+ };
285
+
172
286
} // namespace
173
287
174
288
// ===----------------------------------------------------------------------===//
@@ -179,6 +293,8 @@ namespace {
179
293
struct ConvertCombToAIGPass
180
294
: public impl::ConvertCombToAIGBase<ConvertCombToAIGPass> {
181
295
void runOnOperation () override ;
296
+ using ConvertCombToAIGBase<ConvertCombToAIGPass>::ConvertCombToAIGBase;
297
+ using ConvertCombToAIGBase<ConvertCombToAIGPass>::additionalLegalOps;
182
298
};
183
299
} // namespace
184
300
@@ -187,18 +303,26 @@ static void populateCombToAIGConversionPatterns(RewritePatternSet &patterns) {
187
303
// Bitwise Logical Ops
188
304
CombAndOpConversion, CombOrOpConversion, CombXorOpConversion,
189
305
CombMuxOpConversion,
306
+ // Arithmetic Ops
307
+ CombAddOpConversion, CombSubOpConversion,
190
308
// Variadic ops that must be lowered to binary operations
191
- CombLowerVariadicOp<XorOp>>(patterns.getContext ());
309
+ CombLowerVariadicOp<XorOp>, CombLowerVariadicOp<AddOp>>(
310
+ patterns.getContext ());
192
311
}
193
312
194
313
void ConvertCombToAIGPass::runOnOperation () {
195
314
ConversionTarget target (getContext ());
196
315
target.addIllegalDialect <comb::CombDialect>();
197
316
// Keep data movement operations like Extract, Concat and Replicate.
198
317
target.addLegalOp <comb::ExtractOp, comb::ConcatOp, comb::ReplicateOp,
199
- hw::BitcastOp>();
318
+ hw::BitcastOp, hw::ConstantOp >();
200
319
target.addLegalDialect <aig::AIGDialect>();
201
320
321
+ // This is a test only option to add logical ops.
322
+ if (!additionalLegalOps.empty ())
323
+ for (const auto &opName : additionalLegalOps)
324
+ target.addLegalOp (OperationName (opName, &getContext ()));
325
+
202
326
RewritePatternSet patterns (&getContext ());
203
327
populateCombToAIGConversionPatterns (patterns);
204
328
0 commit comments