CIRCT 23.0.0git
Loading...
Searching...
No Matches
DatapathToComb.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
14#include "mlir/Analysis/TopologicalSortUtils.h"
15#include "mlir/Dialect/Func/IR/FuncOps.h"
16#include "mlir/IR/PatternMatch.h"
17#include "mlir/Pass/Pass.h"
18#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
19#include "llvm/Support/Debug.h"
20#include "llvm/Support/KnownBits.h"
21#include <algorithm>
22
23#define DEBUG_TYPE "datapath-to-comb"
24
25namespace circt {
26#define GEN_PASS_DEF_CONVERTDATAPATHTOCOMB
27#include "circt/Conversion/Passes.h.inc"
28} // namespace circt
29
30using namespace circt;
31using namespace datapath;
32
33// A wrapper for comb::extractBits that returns a SmallVector<Value>.
34static SmallVector<Value> extractBits(OpBuilder &builder, Value val) {
35 SmallVector<Value> bits;
36 comb::extractBits(builder, val, bits);
37 return bits;
38}
39
40// Check whether a value is zero-extended or sign-extended - and return the
41// unextended base value and whether it was sign-extended.
42static std::pair<bool, Value> getBaseOfExt(PatternRewriter &rewriter,
43 Location loc, Value val) {
44
45 Value replBits;
46 // Check for zext
47 if (matchPattern(val, comb::m_ZextBy(mlir::matchers::m_Any(&replBits)))) {
48 auto baseWidth = val.getType().getIntOrFloatBitWidth() -
49 replBits.getType().getIntOrFloatBitWidth();
50 auto valBase =
51 rewriter.createOrFold<comb::ExtractOp>(loc, val, 0, baseWidth);
52 return {false, valBase};
53 }
54
55 // Check for sext of the value
56 if (matchPattern(val, comb::m_SextBy(mlir::matchers::m_Any(&replBits)))) {
57 auto baseWidth = val.getType().getIntOrFloatBitWidth() -
58 replBits.getType().getIntOrFloatBitWidth();
59 auto valBase =
60 rewriter.createOrFold<comb::ExtractOp>(loc, val, 0, baseWidth);
61 return {true, valBase};
62 }
63
64 // Not extended, return original value
65 return {false, val};
66}
67
68//===----------------------------------------------------------------------===//
69// Conversion patterns
70//===----------------------------------------------------------------------===//
71
72namespace {
73// Replace compressor by an adder of the inputs and zero for the other results:
74// compress(a,b,c,d) -> {a+b+c+d, 0}
75// Facilitates use of downstream compression algorithms e.g. Yosys
76struct DatapathCompressOpAddConversion : mlir::OpRewritePattern<CompressOp> {
78 LogicalResult
79 matchAndRewrite(CompressOp op,
80 mlir::PatternRewriter &rewriter) const override {
81 Location loc = op.getLoc();
82 auto inputs = op.getOperands();
83 unsigned width = inputs[0].getType().getIntOrFloatBitWidth();
84 // Sum all the inputs - set that to result value 0
85 auto addOp = comb::AddOp::create(rewriter, loc, inputs, true);
86 // Replace remaining results with zeros
87 auto zeroOp = hw::ConstantOp::create(rewriter, loc, APInt(width, 0));
88 SmallVector<Value> results(op.getNumResults() - 1, zeroOp);
89 results.push_back(addOp);
90 rewriter.replaceOp(op, results);
91 return success();
92 }
93};
94
95// Replace compressor by a wallace tree of full-adders
96struct DatapathCompressOpConversion : mlir::OpRewritePattern<CompressOp> {
97 DatapathCompressOpConversion(MLIRContext *context,
99 : mlir::OpRewritePattern<CompressOp>(context), analysis(analysis) {}
100
101 LogicalResult
102 matchAndRewrite(CompressOp op,
103 mlir::PatternRewriter &rewriter) const override {
104 Location loc = op.getLoc();
105 auto inputs = op.getOperands();
106
107 SmallVector<SmallVector<Value>> addends;
108 for (auto input : inputs) {
109 addends.push_back(
110 extractBits(rewriter, input)); // Extract bits from each input
111 }
112
113 // Compressor tree reduction
114 auto width = inputs[0].getType().getIntOrFloatBitWidth();
115 auto targetAddends = op.getNumResults();
116 datapath::CompressorTree comp(width, addends, loc);
117
118 if (analysis) {
119 // Update delay information with arrival times
120 if (failed(comp.withInputDelays(
121 [&](Value v) { return analysis->getMaxDelay(v, 0); })))
122 return failure();
123 }
124
125 rewriter.replaceOp(op, comp.compressToHeight(rewriter, targetAddends));
126 return success();
127 }
128
129private:
130 synth::IncrementalLongestPathAnalysis *analysis = nullptr;
131};
132
133struct DatapathPartialProductOpConversion : OpRewritePattern<PartialProductOp> {
134 using OpRewritePattern<PartialProductOp>::OpRewritePattern;
135
136 DatapathPartialProductOpConversion(MLIRContext *context, bool forceBooth)
137 : OpRewritePattern<PartialProductOp>(context), forceBooth(forceBooth){};
138
139 const bool forceBooth;
140
141 LogicalResult matchAndRewrite(PartialProductOp op,
142 PatternRewriter &rewriter) const override {
143
144 Value a = op.getLhs();
145 Value b = op.getRhs();
146 unsigned width = a.getType().getIntOrFloatBitWidth();
147
148 // Skip a zero width value.
149 if (width == 0) {
150 rewriter.replaceOpWithNewOp<hw::ConstantOp>(op, op.getType(0), 0);
151 return success();
152 }
153
154 // Square partial product array can be reduced to upper triangular array.
155 // For example: AND array for a 4-bit squarer:
156 // 0 0 0 a0a3 a0a2 a0a1 a0a0
157 // 0 0 a1a3 a1a2 a1a1 a1a0 0
158 // 0 a2a3 a2a2 a2a1 a2a0 0 0
159 // a3a3 a3a2 a3a1 a3a0 0 0 0
160 //
161 // Can be reduced to:
162 // 0 0 a0a3 a0a2 a0a1 0 a0
163 // 0 a1a3 a1a2 0 a1 0 0
164 // a2a3 0 a2 0 0 0 0
165 // a3 0 0 0 0 0 0
166 if (a == b)
167 return lowerSqrAndArray(rewriter, a, op, width);
168
169 // Use result rows as a heuristic to guide partial product
170 // implementation
171 if (comb::shouldUseBoothEncoding(a, b) || forceBooth)
172 return lowerBoothArray(rewriter, a, b, op, width);
173 else
174 return lowerAndArray(rewriter, a, b, op, width);
175 }
176
177private:
178 static LogicalResult lowerAndArray(PatternRewriter &rewriter, Value a,
179 Value b, PartialProductOp op,
180 unsigned width) {
181
182 Location loc = op.getLoc();
183 // Keep a as a bitvector - multiply by each digit of b
184 SmallVector<Value> bBits = extractBits(rewriter, b);
185
186 auto rowWidth = width;
187 auto knownBitsA = comb::computeKnownBits(a);
188 if (!knownBitsA.Zero.isZero()) {
189 if (knownBitsA.Zero.countLeadingOnes() > 1) {
190 rowWidth -= knownBitsA.Zero.countLeadingOnes();
191 a = rewriter.createOrFold<comb::ExtractOp>(loc, a, 0, rowWidth);
192 }
193 }
194
195 SmallVector<Value> partialProducts;
196 partialProducts.reserve(width);
197 // AND Array Construction:
198 // partialProducts[i] = ({b[i],..., b[i]} & a) << i
199 assert(op.getNumResults() <= width &&
200 "Cannot return more results than the operator width");
201
202 for (unsigned i = 0; i < op.getNumResults(); ++i) {
203 auto repl =
204 rewriter.createOrFold<comb::ReplicateOp>(loc, bBits[i], rowWidth);
205 auto ppRow = rewriter.createOrFold<comb::AndOp>(loc, repl, a);
206 if (rowWidth < width) {
207 auto padding = width - rowWidth;
208 auto zeroPad = hw::ConstantOp::create(rewriter, loc, APInt(padding, 0));
209 ppRow = rewriter.createOrFold<comb::ConcatOp>(
210 loc, ValueRange{zeroPad, ppRow}); // Pad to full width
211 }
212
213 if (i == 0) {
214 partialProducts.push_back(ppRow);
215 continue;
216 }
217 auto shiftBy = hw::ConstantOp::create(rewriter, loc, APInt(i, 0));
218 auto ppAlign =
219 comb::ConcatOp::create(rewriter, loc, ValueRange{ppRow, shiftBy});
220 auto ppAlignTrunc = rewriter.createOrFold<comb::ExtractOp>(
221 loc, ppAlign, 0, width); // Truncate to width+i bits
222 partialProducts.push_back(ppAlignTrunc);
223 }
224
225 rewriter.replaceOp(op, partialProducts);
226 return success();
227 }
228
229 static LogicalResult lowerSqrAndArray(PatternRewriter &rewriter, Value a,
230 PartialProductOp op, unsigned width) {
231
232 Location loc = op.getLoc();
233 SmallVector<Value> aBits = extractBits(rewriter, a);
234
235 SmallVector<Value> partialProducts;
236 partialProducts.reserve(width);
237 // AND Array Construction - reducing to upper triangle:
238 // partialProducts[i] = ({a[i],..., a[i]} & a) << i
239 // optimised to: {a[i] & a[n-1], ..., a[i] & a[i+1], 0, a[i], 0, ..., 0}
240 assert(op.getNumResults() <= width &&
241 "Cannot return more results than the operator width");
242 auto zeroFalse = hw::ConstantOp::create(rewriter, loc, APInt(1, 0));
243 for (unsigned i = 0; i < op.getNumResults(); ++i) {
244 SmallVector<Value> row;
245 row.reserve(width);
246
247 if (2 * i >= width) {
248 // Pad the remaining rows with zeros
249 auto zeroWidth = hw::ConstantOp::create(rewriter, loc, APInt(width, 0));
250 partialProducts.push_back(zeroWidth);
251 continue;
252 }
253
254 if (i > 0) {
255 auto shiftBy = hw::ConstantOp::create(rewriter, loc, APInt(2 * i, 0));
256 row.push_back(shiftBy);
257 }
258 row.push_back(aBits[i]);
259
260 // Track width of constructed row
261 unsigned rowWidth = 2 * i + 1;
262 if (rowWidth < width) {
263 row.push_back(zeroFalse);
264 ++rowWidth;
265 }
266
267 for (unsigned j = i + 1; j < width; ++j) {
268 // Stop when we reach the required width
269 if (rowWidth == width)
270 break;
271
272 // Otherwise pad with zeros or partial product bits
273 ++rowWidth;
274 // Number of results indicates number of non-zero bits in input
275 if (j >= op.getNumResults()) {
276 row.push_back(zeroFalse);
277 continue;
278 }
279
280 auto ppBit =
281 rewriter.createOrFold<comb::AndOp>(loc, aBits[i], aBits[j]);
282 row.push_back(ppBit);
283 }
284 std::reverse(row.begin(), row.end());
285 auto ppRow = comb::ConcatOp::create(rewriter, loc, row);
286 partialProducts.push_back(ppRow);
287 }
288
289 rewriter.replaceOp(op, partialProducts);
290 return success();
291 }
292
293 static LogicalResult lowerBoothArray(PatternRewriter &rewriter, Value a,
294 Value b, PartialProductOp op,
295 unsigned width) {
296 // TODO: sort a and b based on non-zero bits to encode the smaller input
297 Location loc = op.getLoc();
298 auto zeroFalse = hw::ConstantOp::create(rewriter, loc, APInt(1, 0));
299
300 auto [aSigned, aBase] = getBaseOfExt(rewriter, loc, op.getLhs());
301 auto [bSigned, bBase] = getBaseOfExt(rewriter, loc, op.getRhs());
302
303 auto aBaseWidth = aBase.getType().getIntOrFloatBitWidth();
304 auto bBaseWidth = bBase.getType().getIntOrFloatBitWidth();
305
306 // Detect leading zeros in multiplicand due to zero-extension
307 // and truncate to reduce partial product bits {'0, a} * {'0, b}
308 auto rowWidth = width;
309 if (aBaseWidth < width) {
310 // Retain one leading zero/sign-bit to represent 2*a
311 rowWidth = aBaseWidth + 1;
312 a = rewriter.createOrFold<comb::ExtractOp>(loc, a, 0, rowWidth);
313 }
314
315 // Booth encoding will select each row from {-2a, -1a, 0, 1a, 2a}
316 Value twoAPre =
317 rewriter.createOrFold<comb::ConcatOp>(loc, ValueRange{a, zeroFalse});
318 Value twoA = rewriter.createOrFold<comb::ExtractOp>(
319 loc, twoAPre, 0, rowWidth); // Truncate to width bits
320
321 // Encode based on the bits of b
322
323 SmallVector<Value> bBits = extractBits(rewriter, b);
324 // Pad with two zeros - for case where there's no extensions
325 bBits.push_back(zeroFalse); // Add a zero bit for the first row
326 bBits.push_back(zeroFalse); // Add a zero bit for the last row
327
328 // Retain two leading zeros as when b has an even number of bits we just
329 // need to retain two leading zeros
330 if (!bSigned)
331 bBits.resize(bBaseWidth + 2);
332
333 // If b is signed, we need to sign-extend with a single sign-bit
334 if (bSigned)
335 bBits.resize(bBaseWidth + 1);
336
337 SmallVector<Value> partialProducts;
338 partialProducts.reserve(op.getNumResults());
339
340 // Booth encoding halves array height by grouping three bits at a time:
341 // partialProducts[i] = a * (-2*b[2*i+1] + b[2*i] + b[2*i-1]) << 2*i
342 // encNeg \approx (-2*b[2*i+1] + b[2*i] + b[2*i-1]) <= 0
343 // encOne = (-2*b[2*i+1] + b[2*i] + b[2*i-1]) == +/- 1
344 // encTwo = (-2*b[2*i+1] + b[2*i] + b[2*i-1]) == +/- 2
345 SmallVector<Value> encNegs;
346 Value encNegPrev;
347
348 // For even width - additional row contains the final sign correction
349 for (unsigned i = 0; i + 1 < bBits.size(); i += 2) {
350 // Get Booth bits: b[i+1], b[i], b[i-1] (b[-1] = 0)
351 Value bim1 = (i == 0) ? zeroFalse : bBits[i - 1];
352 Value bi = bBits[i];
353 Value bip1 = bBits[i + 1];
354
355 // Is the encoding zero or negative (an approximation)
356 Value encNeg = bip1;
357 encNegs.push_back(encNeg); // Store for sign-extension optimisation
358 // Is the encoding one = b[i] xor b[i-1]
359 Value encOne = rewriter.createOrFold<comb::XorOp>(loc, bi, bim1, true);
360 // Is the encoding two = (bip1 & ~bi & ~bim1) | (~bip1 & bi & bim1)
361 Value constOne = hw::ConstantOp::create(rewriter, loc, APInt(1, 1));
362 Value biInv = rewriter.createOrFold<comb::XorOp>(loc, bi, constOne, true);
363 Value bip1Inv =
364 rewriter.createOrFold<comb::XorOp>(loc, bip1, constOne, true);
365 Value bim1Inv =
366 rewriter.createOrFold<comb::XorOp>(loc, bim1, constOne, true);
367
368 Value andLeft = rewriter.createOrFold<comb::AndOp>(
369 loc, ValueRange{bip1Inv, bi, bim1}, true);
370 Value andRight = rewriter.createOrFold<comb::AndOp>(
371 loc, ValueRange{bip1, biInv, bim1Inv}, true);
372 Value encTwo =
373 rewriter.createOrFold<comb::OrOp>(loc, andLeft, andRight, true);
374
375 Value encNegRepl =
376 rewriter.createOrFold<comb::ReplicateOp>(loc, encNeg, rowWidth);
377 Value encOneRepl =
378 rewriter.createOrFold<comb::ReplicateOp>(loc, encOne, rowWidth);
379 Value encTwoRepl =
380 rewriter.createOrFold<comb::ReplicateOp>(loc, encTwo, rowWidth);
381
382 // Select between 2*a or 1*a or 0*a
383 Value selTwoA = rewriter.createOrFold<comb::AndOp>(loc, encTwoRepl, twoA);
384 Value selOneA = rewriter.createOrFold<comb::AndOp>(loc, encOneRepl, a);
385 Value magA =
386 rewriter.createOrFold<comb::OrOp>(loc, selTwoA, selOneA, true);
387
388 // Conditionally invert the row
389 Value ppRow =
390 rewriter.createOrFold<comb::XorOp>(loc, magA, encNegRepl, true);
391
392 // No sign-correction in the first row
393 if (i == 0) {
394 partialProducts.push_back(ppRow);
395 encNegPrev = encNeg;
396 continue;
397 }
398
399 if (i == 2) {
400 Value withSignCorrection = rewriter.createOrFold<comb::ConcatOp>(
401 loc, ValueRange{ppRow, zeroFalse, encNegPrev});
402 partialProducts.push_back(withSignCorrection);
403 encNegPrev = encNeg;
404 continue;
405 }
406
407 // Insert a sign-correction from the previous row
408 // {ppRow, 0, encNegPrev} << (i-2)
409 Value shiftBy = hw::ConstantOp::create(rewriter, loc, APInt(i - 2, 0));
410 Value withSignCorrection = rewriter.createOrFold<comb::ConcatOp>(
411 loc, ValueRange{ppRow, zeroFalse, encNegPrev, shiftBy});
412 partialProducts.push_back(withSignCorrection);
413 encNegPrev = encNeg;
414
415 if (partialProducts.size() == op.getNumResults())
416 break;
417 }
418
419 // Add the final sign-correction row for signed multiplication
420 // Not necessary for unsigned multiplication as the final row is positive
421 if (bSigned) {
422 auto numPP = partialProducts.size();
423 Value shiftByFinal =
424 hw::ConstantOp::create(rewriter, loc, APInt((numPP - 1) * 2, 0));
425 Value finalSignCorrection = rewriter.createOrFold<comb::ConcatOp>(
426 loc, ValueRange{zeroFalse, encNegPrev, shiftByFinal});
427 partialProducts.push_back(finalSignCorrection);
428 encNegs.push_back(zeroFalse); // No sign-extension for the final row
429 }
430
431 // Sign-extension:
432 // { s1, s1, s1, s1, s1, p1}
433 // { s2, s2, s2, p2 }
434 // { s3, p3 }
435 // TODO: optimize by only replicating the sign bit once using
436 // typical sign-extension trick - can be handled by separate
437 // canonicalization patterns
438 for (unsigned i = 0; i < partialProducts.size(); ++i) {
439 auto ppRow = partialProducts[i];
440
441 auto ppWidth = ppRow.getType().getIntOrFloatBitWidth();
442 if (ppWidth < width) {
443 auto padding = width - ppWidth;
444 auto encNeg = encNegs[i];
445 if (aSigned)
446 encNeg = rewriter.createOrFold<comb::ExtractOp>(loc, ppRow,
447 ppWidth - 1, 1);
448
449 // Replicate the encNeg bit for sign-extension
450 Value encNegPad =
451 rewriter.createOrFold<comb::ReplicateOp>(loc, encNeg, padding);
452 ppRow = rewriter.createOrFold<comb::ConcatOp>(
453 loc, ValueRange{encNegPad, ppRow}); // Pad to full width
454 }
455
456 // Truncate any excess bits
457 ppWidth = ppRow.getType().getIntOrFloatBitWidth();
458 if (ppWidth > width) {
459 ppRow = rewriter.createOrFold<comb::ExtractOp>(loc, ppRow, 0, width);
460 }
461 partialProducts[i] = ppRow;
462 assert(partialProducts[i].getType().getIntOrFloatBitWidth() == width &&
463 "Expected sign-extended partial product to be full width");
464 }
465
466 // Zero-pad to match the required output width
467 auto zeroWidth = hw::ConstantOp::create(rewriter, loc, APInt(width, 0));
468 while (partialProducts.size() < op.getNumResults())
469 partialProducts.push_back(zeroWidth);
470
471 assert(partialProducts.size() == op.getNumResults() &&
472 "Expected number of booth partial products to match results");
473
474 rewriter.replaceOp(op, partialProducts);
475 return success();
476 }
477};
478
479struct DatapathPosPartialProductOpConversion
480 : OpRewritePattern<PosPartialProductOp> {
481 using OpRewritePattern<PosPartialProductOp>::OpRewritePattern;
482
483 DatapathPosPartialProductOpConversion(MLIRContext *context, bool forceBooth)
484 : OpRewritePattern<PosPartialProductOp>(context),
485 forceBooth(forceBooth){};
486
487 const bool forceBooth;
488
489 LogicalResult matchAndRewrite(PosPartialProductOp op,
490 PatternRewriter &rewriter) const override {
491
492 Value a = op.getAddend0();
493 Value b = op.getAddend1();
494 Value c = op.getMultiplicand();
495 unsigned width = a.getType().getIntOrFloatBitWidth();
496
497 // Skip a zero width value.
498 if (width == 0) {
499 rewriter.replaceOpWithNewOp<hw::ConstantOp>(op, op.getType(0), 0);
500 return success();
501 }
502
503 // TODO: Implement Booth lowering
504 return lowerAndArray(rewriter, a, b, c, op, width);
505 }
506
507private:
508 static LogicalResult lowerAndArray(PatternRewriter &rewriter, Value a,
509 Value b, Value c, PosPartialProductOp op,
510 unsigned width) {
511
512 Location loc = op.getLoc();
513 // Encode (a+b) by implementing a half-adder - then note the following
514 // fact carry[i] & save[i] == false
515 auto carry = rewriter.createOrFold<comb::AndOp>(loc, a, b);
516 auto save = rewriter.createOrFold<comb::XorOp>(loc, a, b);
517
518 SmallVector<Value> carryBits = extractBits(rewriter, carry);
519 SmallVector<Value> saveBits = extractBits(rewriter, save);
520
521 // Reduce c width based on leading zeros
522 auto rowWidth = width;
523 auto [cSigned, cBase] = getBaseOfExt(rewriter, loc, c);
524 auto cBaseWidth = cBase.getType().getIntOrFloatBitWidth();
525
526 if (cBaseWidth < width && !cSigned) {
527 // Retain one leading zero to represent 2*c
528 rowWidth = cBaseWidth + 1;
529 c = rewriter.createOrFold<comb::ExtractOp>(loc, c, 0, rowWidth);
530 }
531
532 // Compute 2*c for use in array construction
533 Value zeroFalse = hw::ConstantOp::create(rewriter, loc, APInt(1, 0));
534 Value twoCPre =
535 comb::ConcatOp::create(rewriter, loc, ValueRange{c, zeroFalse});
536 Value twoC = rewriter.createOrFold<comb::ExtractOp>(loc, twoCPre, 0,
537 rowWidth); // Truncate
538
539 // AND Array Construction:
540 // pp[i] = ( (carry[i] * (c<<1)) | (save[i] * c) ) << i
541 SmallVector<Value> partialProducts;
542 partialProducts.reserve(width);
543
544 assert(op.getNumResults() <= width &&
545 "Cannot return more results than the operator width");
546
547 for (unsigned i = 0; i < op.getNumResults(); ++i) {
548 auto replSave =
549 rewriter.createOrFold<comb::ReplicateOp>(loc, saveBits[i], rowWidth);
550 auto replCarry =
551 rewriter.createOrFold<comb::ReplicateOp>(loc, carryBits[i], rowWidth);
552
553 auto ppRowSave = rewriter.createOrFold<comb::AndOp>(loc, replSave, c);
554 auto ppRowCarry =
555 rewriter.createOrFold<comb::AndOp>(loc, replCarry, twoC);
556 auto ppRow =
557 rewriter.createOrFold<comb::OrOp>(loc, ppRowSave, ppRowCarry);
558 auto ppAlign = ppRow;
559 if (i > 0) {
560 auto shiftBy = hw::ConstantOp::create(rewriter, loc, APInt(i, 0));
561 ppAlign =
562 comb::ConcatOp::create(rewriter, loc, ValueRange{ppRow, shiftBy});
563 }
564
565 // May need to truncate shifted value
566 if (rowWidth + i > width) {
567 auto ppAlignTrunc =
568 rewriter.createOrFold<comb::ExtractOp>(loc, ppAlign, 0, width);
569 partialProducts.push_back(ppAlignTrunc);
570 continue;
571 }
572 // May need to zero pad to approriate width
573 if (rowWidth + i < width) {
574 auto extPPAlign = comb::createZExt(rewriter, loc, ppAlign, width);
575 partialProducts.push_back(extPPAlign);
576 continue;
577 }
578
579 partialProducts.push_back(ppAlign);
580 }
581
582 rewriter.replaceOp(op, partialProducts);
583 return success();
584 }
585};
586
587} // namespace
588
589//===----------------------------------------------------------------------===//
590// Convert Datapath to Comb pass
591//===----------------------------------------------------------------------===//
592
593namespace {
594struct ConvertDatapathToCombPass
595 : public impl::ConvertDatapathToCombBase<ConvertDatapathToCombPass> {
596 void runOnOperation() override;
597 using ConvertDatapathToCombBase<
598 ConvertDatapathToCombPass>::ConvertDatapathToCombBase;
599};
600} // namespace
601
603 Operation *op, RewritePatternSet &&patterns,
605 // TODO: Topologically sort the operations in the module to ensure that all
606 // dependencies are processed before their users.
607 mlir::GreedyRewriteConfig config;
608 // Set the listener to update timing information
609 // HACK: Setting max iterations to 2 to ensure that the patterns are
610 // one-shot, making sure target operations are datapath operations are
611 // replaced.
612 config.setMaxIterations(2).setListener(analysis).setUseTopDownTraversal(true);
613
614 // Apply the patterns greedily
615 if (failed(mlir::applyPatternsGreedily(op, std::move(patterns), config)))
616 return failure();
617
618 return success();
619}
620
621void ConvertDatapathToCombPass::runOnOperation() {
622 RewritePatternSet patterns(&getContext());
623
624 patterns.add<DatapathPartialProductOpConversion,
625 DatapathPosPartialProductOpConversion>(patterns.getContext(),
626 forceBooth);
627 synth::IncrementalLongestPathAnalysis *analysis = nullptr;
628 if (timingAware)
629 analysis = &getAnalysis<synth::IncrementalLongestPathAnalysis>();
630
631 if (lowerCompressToAdd)
632 // Lower compressors to simple add operations for downstream optimisations
633 patterns.add<DatapathCompressOpAddConversion>(patterns.getContext());
634 if (lowerCompress)
635 // Lower compressors to a complete gate-level implementation
636 patterns.add<DatapathCompressOpConversion>(patterns.getContext(), analysis);
637
639 getOperation(), std::move(patterns), analysis)))
640 return signalPassFailure();
641
642 // Verify that all Datapath operations have been successfully converted.
643 // Walk the operation and check for any remaining Datapath dialect
644 // operations.
645 auto result = getOperation()->walk([&](Operation *op) {
646 if (llvm::isa<datapath::CompressOp>(op) && !lowerCompress &&
647 !lowerCompressToAdd)
648 return WalkResult::advance();
649 if (llvm::isa_and_nonnull<datapath::DatapathDialect>(op->getDialect())) {
650 op->emitError("Datapath operation not converted: ") << *op;
651 return WalkResult::interrupt();
652 }
653 return WalkResult::advance();
654 });
655 if (result.wasInterrupted())
656 return signalPassFailure();
657}
assert(baseType &&"element must be base type")
static SmallVector< Value > extractBits(OpBuilder &builder, Value val)
static Value zeroPad(PatternRewriter &rewriter, Location loc, Value input, size_t targetWidth, size_t trailingZeros)
static std::pair< bool, Value > getBaseOfExt(PatternRewriter &rewriter, Location loc, Value val)
static SmallVector< Value > extractBits(OpBuilder &builder, Value val)
static LogicalResult applyPatternsGreedilyWithTimingInfo(Operation *op, RewritePatternSet &&patterns, synth::IncrementalLongestPathAnalysis *analysis)
static std::unique_ptr< Context > context
create(data_type, value)
Definition hw.py:433
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.