13#include "mlir/Pass/Pass.h"
14#include "mlir/Transforms/DialectConversion.h"
15#include "llvm/ADT/APInt.h"
19#define GEN_PASS_DEF_HWAGGREGATETOCOMB
20#include "circt/Dialect/HW/Passes.h.inc"
30template <
typename OpTy>
32 using OpConversionPattern<OpTy>::OpConversionPattern;
33 using OpAdaptor =
typename OpConversionPattern<OpTy>::OpAdaptor;
35 matchAndRewrite(OpTy op, OpAdaptor adaptor,
36 ConversionPatternRewriter &rewriter)
const override {
37 rewriter.replaceOpWithNewOp<comb::ConcatOp>(op, adaptor.getInputs());
42struct HWUnionCreateOpConversion
44 using OpConversionPattern<hw::UnionCreateOp>::OpConversionPattern;
47 matchAndRewrite(hw::UnionCreateOp op, OpAdaptor adaptor,
48 ConversionPatternRewriter &rewriter)
const override {
49 hw::UnionType unionTy = op.getType();
51 dyn_cast_or_null<IntegerType>(typeConverter->convertType(unionTy));
53 return rewriter.notifyMatchFailure(op.getLoc(),
54 "Failed to convert union to integer");
56 auto inputBitWidth = hw::getBitWidth(adaptor.getInput().getType());
57 if (inputBitWidth < 0)
58 return rewriter.notifyMatchFailure(op.getLoc(),
59 "Failed to convert input to integer");
62 auto inputIntTy = rewriter.getIntegerType(inputBitWidth);
63 Value inputAsInt = rewriter.createOrFold<hw::BitcastOp>(
64 op.getLoc(), inputIntTy, adaptor.getInput());
69 int64_t bitOffset = unionTy.getElements()[op.getFieldIndex()].offset;
70 int64_t prePadding = outputTy.getWidth() - inputBitWidth - bitOffset;
72 auto createZeroCst = [&](Location loc, int64_t bitWidth) -> Value {
74 rewriter.getIntegerType(bitWidth), 0);
77 SmallVector<Value> concatOperands;
79 concatOperands.push_back(createZeroCst(op.getLoc(), prePadding));
80 concatOperands.push_back(inputAsInt);
82 concatOperands.push_back(createZeroCst(op.getLoc(), bitOffset));
85 rewriter.createOrFold<comb::ConcatOp>(op.getLoc(), concatOperands);
86 rewriter.replaceOp(op, result);
91struct HWUnionExtractOpConversion
93 using OpConversionPattern<hw::UnionExtractOp>::OpConversionPattern;
96 matchAndRewrite(hw::UnionExtractOp op, OpAdaptor adaptor,
97 ConversionPatternRewriter &rewriter)
const override {
98 hw::UnionType unionTy = op.getInput().getType();
100 auto inputTy = dyn_cast_or_null<IntegerType>(adaptor.getInput().getType());
102 return rewriter.notifyMatchFailure(op.getLoc(),
103 "Failed to convert union to integer");
104 auto outputTy = typeConverter->convertType(op.getType());
106 return rewriter.notifyMatchFailure(
107 op.getLoc(),
"Failed to convert union extract result type");
109 auto resultFieldBits = hw::getBitWidth(outputTy);
110 assert(resultFieldBits >= 0);
111 auto integerValue = adaptor.getInput();
114 if (resultFieldBits < integerValue.getType().getIntOrFloatBitWidth()) {
115 auto bitOffset = unionTy.getElements()[op.getFieldIndex()].offset;
117 rewriter, op->getLoc(), rewriter.getIntegerType(resultFieldBits),
118 integerValue, bitOffset);
123 auto bitcastOp = rewriter.createOrFold<hw::BitcastOp>(op.getLoc(), outputTy,
126 rewriter.replaceOp(op, bitcastOp);
131struct HWAggregateConstantOpConversion
133 using OpConversionPattern<hw::AggregateConstantOp>::OpConversionPattern;
136 matchAndRewrite(hw::AggregateConstantOp op, OpAdaptor adaptor,
137 ConversionPatternRewriter &rewriter)
const override {
140 if (failed(hw::aggregateAttrToAPInt(op.getType(), adaptor.getFieldsAttr(),
143 rewriter.replaceOpWithNewOp<hw::ConstantOp>(op, intVal);
149 using OpConversionPattern<hw::ArrayGetOp>::OpConversionPattern;
152 matchAndRewrite(hw::ArrayGetOp op, OpAdaptor adaptor,
153 ConversionPatternRewriter &rewriter)
const override {
154 SmallVector<Value> results;
155 auto arrayType = cast<hw::ArrayType>(op.getInput().getType());
156 auto elemType = arrayType.getElementType();
158 auto elemWidth = hw::getBitWidth(elemType);
160 return rewriter.notifyMatchFailure(op.getLoc(),
"unknown element width");
162 auto lowered = adaptor.getInput();
163 auto index = adaptor.getIndex();
165 if (matchPattern(index, m_ConstantInt(&constantIndex))) {
166 int64_t maxIndex = std::numeric_limits<int32_t>::max() / elemWidth;
167 if (constantIndex.isSingleWord() &&
168 constantIndex.getZExtValue() <=
static_cast<uint64_t
>(maxIndex)) {
169 rewriter.replaceOpWithNewOp<comb::ExtractOp>(
170 op, lowered, constantIndex.getZExtValue() * elemWidth, elemWidth);
176 results.push_back(rewriter.createOrFold<comb::ExtractOp>(
177 op.getLoc(), lowered, i * elemWidth, elemWidth));
179 SmallVector<Value> bits;
180 comb::extractBits(rewriter, index, bits);
181 auto result = comb::constructMuxTree(rewriter, op.getLoc(), bits, results,
184 rewriter.replaceOp(op, result);
190 using OpConversionPattern<hw::ArraySliceOp>::OpConversionPattern;
193 matchAndRewrite(hw::ArraySliceOp op, OpAdaptor adaptor,
194 ConversionPatternRewriter &rewriter)
const override {
195 SmallVector<Value> results;
196 auto arrayType = cast<hw::ArrayType>(op.getInput().getType());
197 auto elemType = arrayType.getElementType();
199 auto elemWidth = hw::getBitWidth(elemType);
201 return rewriter.notifyMatchFailure(op.getLoc(),
"unknown element width");
202 auto resultArrayType = cast<hw::ArrayType>(op.getResult().getType());
203 auto resultNumElements = resultArrayType.getNumElements();
205 auto lowered = adaptor.getInput();
206 auto index = adaptor.getLowIndex();
208 if (matchPattern(index, m_ConstantInt(&constantIndex))) {
209 int64_t maxIndex = std::numeric_limits<int32_t>::max() / elemWidth;
210 if (constantIndex.isSingleWord() &&
211 constantIndex.getZExtValue() <=
static_cast<uint64_t
>(maxIndex)) {
212 rewriter.replaceOpWithNewOp<comb::ExtractOp>(
213 op, lowered, constantIndex.getZExtValue() * elemWidth,
214 resultNumElements * elemWidth);
219 for (
size_t i = 0; i <=
numElements - resultNumElements; ++i)
220 results.push_back(rewriter.createOrFold<comb::ExtractOp>(
221 op.getLoc(), lowered, i * elemWidth, resultNumElements * elemWidth));
223 SmallVector<Value> bits;
224 comb::extractBits(rewriter, index, bits);
225 auto result = comb::constructMuxTree(rewriter, op.getLoc(), bits, results,
228 rewriter.replaceOp(op, result);
234 using OpConversionPattern<hw::ArrayInjectOp>::OpConversionPattern;
237 matchAndRewrite(hw::ArrayInjectOp op, OpAdaptor adaptor,
238 ConversionPatternRewriter &rewriter)
const override {
239 auto arrayType = cast<hw::ArrayType>(op.getInput().getType());
240 auto elemType = arrayType.getElementType();
242 auto elemWidth = hw::getBitWidth(elemType);
244 return rewriter.notifyMatchFailure(op.getLoc(),
"unknown element width");
247 if (elemWidth == 0) {
248 rewriter.replaceOp(op, adaptor.getInput());
252 rewriter.replaceOp(op, adaptor.getElement());
258 if (matchPattern(adaptor.getIndex(), m_ConstantInt(&constantIndex))) {
259 uint64_t targetIdx = constantIndex.getZExtValue();
260 return emitConstantInject(targetIdx, op, adaptor, rewriter);
263 return emitLinearMuxChainInject(op, adaptor, rewriter);
267 LogicalResult emitConstantInject(uint64_t targetIdx, hw::ArrayInjectOp op,
269 ConversionPatternRewriter &rewriter)
const {
270 auto arrayType = cast<hw::ArrayType>(op.getInput().getType());
271 auto elemType = arrayType.getElementType();
274 return rewriter.notifyMatchFailure(op.getLoc(),
"out of bounds index");
276 auto elemWidth = hw::getBitWidth(elemType);
278 return rewriter.notifyMatchFailure(op.getLoc(),
"unknown element width");
281 int64_t bitOffset = targetIdx * elemWidth;
282 int64_t upperBits = totalWidth - bitOffset - elemWidth;
283 SmallVector<Value, 3> concatOperands;
285 concatOperands.push_back(rewriter.createOrFold<comb::ExtractOp>(
286 op.getLoc(), adaptor.getInput(), bitOffset + elemWidth, upperBits));
287 concatOperands.push_back(adaptor.getElement());
289 concatOperands.push_back(rewriter.createOrFold<comb::ExtractOp>(
290 op.getLoc(), adaptor.getInput(), 0, bitOffset));
292 rewriter.createOrFold<comb::ConcatOp>(op.getLoc(), concatOperands);
293 rewriter.replaceOp(op, result);
299 emitLinearMuxChainInject(hw::ArrayInjectOp op, OpAdaptor adaptor,
300 ConversionPatternRewriter &rewriter)
const {
301 auto arrayType = cast<hw::ArrayType>(op.getInput().getType());
302 Value index = adaptor.getIndex();
303 Location loc = op.getLoc();
305 int64_t elemWidth = hw::getBitWidth(arrayType.getElementType());
307 return rewriter.notifyMatchFailure(op.getLoc(),
"unknown element width");
310 SmallVector<Value> originalElements;
312 originalElements.push_back(rewriter.createOrFold<comb::ExtractOp>(
313 loc, adaptor.getInput(), i * elemWidth, elemWidth));
316 SmallVector<Value> rowElements;
318 for (
int originalIdx =
numElements - 1; originalIdx >= 0; --originalIdx) {
321 Value cond = comb::ICmpOp::create(rewriter, loc, comb::ICmpPredicate::eq,
323 rowElements.push_back(comb::MuxOp::create(rewriter, loc, cond,
324 adaptor.getElement(),
325 originalElements[originalIdx]));
327 rewriter.replaceOpWithNewOp<comb::ConcatOp>(op, rowElements);
333 using OpConversionPattern<hw::StructCreateOp>::OpConversionPattern;
336 matchAndRewrite(hw::StructCreateOp op, OpAdaptor adaptor,
337 ConversionPatternRewriter &rewriter)
const override {
340 rewriter.replaceOpWithNewOp<comb::ConcatOp>(op, adaptor.getInput());
345static int64_t getFieldBitOffset(hw::StructType structType,
size_t fieldIndex) {
347 if (totalBitWidth < 0)
352 int64_t consumedBits = 0;
353 for (
size_t i = 0; i < fieldIndex; ++i) {
354 int64_t fieldWidth =
hw::getBitWidth(structType.getElements()[i].type);
356 "must be failed before if field width is unknown");
357 consumedBits += fieldWidth;
362 return totalBitWidth - consumedBits - fieldWidth;
366 using OpConversionPattern<hw::StructExtractOp>::OpConversionPattern;
369 matchAndRewrite(hw::StructExtractOp op, OpAdaptor adaptor,
370 ConversionPatternRewriter &rewriter)
const override {
371 auto structType = cast<hw::StructType>(op.getInput().getType());
372 auto fieldIndex = op.getFieldIndex();
373 auto elements = structType.getElements();
375 int64_t bitOffset = getFieldBitOffset(structType, fieldIndex);
377 return rewriter.notifyMatchFailure(op.getLoc(),
"unknown struct width");
379 int64_t fieldWidth = hw::getBitWidth(elements[fieldIndex].type);
381 "must be failed before if field width is unknown");
384 rewriter.replaceOpWithNewOp<comb::ExtractOp>(op, adaptor.getInput(),
385 bitOffset, fieldWidth);
391 using OpConversionPattern<hw::StructInjectOp>::OpConversionPattern;
394 matchAndRewrite(hw::StructInjectOp op, OpAdaptor adaptor,
395 ConversionPatternRewriter &rewriter)
const override {
396 auto structType = cast<hw::StructType>(op.getInput().getType());
397 auto fieldIndex = op.getFieldIndex();
398 auto elements = structType.getElements();
400 int64_t bitOffset = getFieldBitOffset(structType, fieldIndex);
402 return rewriter.notifyMatchFailure(op.getLoc(),
"unknown struct width");
404 int64_t fieldWidth = hw::getBitWidth(elements[fieldIndex].type);
406 "must be failed before if field width is unknown");
408 if (fieldWidth == 0) {
409 rewriter.replaceOp(op, adaptor.getInput());
413 int64_t totalBitWidth = hw::getBitWidth(structType);
414 int64_t upperBits = totalBitWidth - bitOffset - fieldWidth;
416 SmallVector<Value, 3> concatOperands;
418 concatOperands.push_back(rewriter.createOrFold<comb::ExtractOp>(
419 op.getLoc(), adaptor.getInput(), bitOffset + fieldWidth, upperBits));
420 concatOperands.push_back(adaptor.getNewValue());
422 concatOperands.push_back(rewriter.createOrFold<comb::ExtractOp>(
423 op.getLoc(), adaptor.getInput(), 0, bitOffset));
426 rewriter.createOrFold<comb::ConcatOp>(op.getLoc(), concatOperands);
427 rewriter.replaceOp(op, result);
433 using OpConversionPattern<hw::BitcastOp>::OpConversionPattern;
436 matchAndRewrite(hw::BitcastOp op, OpAdaptor adaptor,
437 ConversionPatternRewriter &rewriter)
const override {
438 auto inputTy = adaptor.getInput().getType();
439 auto outputTy = typeConverter->convertType(op.getType());
441 return rewriter.notifyMatchFailure(op,
"Failed to convert result type.");
443 auto inBits = hw::getBitWidth(inputTy);
444 auto outBits = hw::getBitWidth(outputTy);
445 if (inBits != outBits)
446 return rewriter.notifyMatchFailure(
447 op,
"Width of converted types does not match.");
449 return rewriter.notifyMatchFailure(op,
"Unknown bitwidth.");
451 auto bitcastOp = rewriter.createOrFold<hw::BitcastOp>(op.getLoc(), outputTy,
453 rewriter.replaceOp(op, bitcastOp);
459 using OpConversionPattern<comb::MuxOp>::OpConversionPattern;
462 matchAndRewrite(comb::MuxOp op, OpAdaptor adaptor,
463 ConversionPatternRewriter &rewriter)
const override {
465 rewriter.replaceOpWithNewOp<comb::MuxOp>(
466 op, adaptor.getCond(), adaptor.getTrueValue(), adaptor.getFalseValue());
473class AggregateTypeConverter :
public TypeConverter {
475 AggregateTypeConverter() {
476 addConversion([](Type type) -> Type {
return type; });
477 addConversion([](hw::ArrayType t) -> Type {
478 auto bitWidth = t.getBitWidth();
481 return IntegerType::get(t.getContext(), *bitWidth);
483 addConversion([](hw::StructType t) -> Type {
484 auto bitWidth = t.getBitWidth();
487 return IntegerType::get(t.getContext(), *bitWidth);
489 addConversion([](hw::UnionType t) -> Type {
490 auto bitWidth = t.getBitWidth();
493 return IntegerType::get(t.getContext(), *bitWidth);
495 addTargetMaterialization([](mlir::OpBuilder &builder, mlir::Type resultType,
496 mlir::ValueRange inputs,
497 mlir::Location loc) -> mlir::Value {
498 if (inputs.size() != 1)
505 addSourceMaterialization([](mlir::OpBuilder &builder, mlir::Type resultType,
506 mlir::ValueRange inputs,
507 mlir::Location loc) -> mlir::Value {
508 if (inputs.size() != 1)
519 RewritePatternSet &
patterns, AggregateTypeConverter &typeConverter) {
520 patterns.add<HWArrayGetOpConversion,
521 HWArrayCreateLikeOpConversion<hw::ArrayCreateOp>,
522 HWArrayCreateLikeOpConversion<hw::ArrayConcatOp>,
523 HWAggregateConstantOpConversion, HWArraySliceOpConversion,
524 HWArrayInjectOpConversion, HWStructCreateOpConversion,
525 HWStructExtractOpConversion, HWStructInjectOpConversion,
526 HWUnionCreateOpConversion, HWUnionExtractOpConversion,
527 BitcastOpConversion, MuxOpConversion>(typeConverter,
532struct HWAggregateToCombPass
533 :
public hw::impl::HWAggregateToCombBase<HWAggregateToCombPass> {
534 void runOnOperation()
override;
535 using HWAggregateToCombBase<HWAggregateToCombPass>::HWAggregateToCombBase;
539void HWAggregateToCombPass::runOnOperation() {
540 ConversionTarget target(getContext());
542 target.addIllegalOp<hw::ArrayGetOp, hw::ArrayCreateOp, hw::ArrayConcatOp,
543 hw::AggregateConstantOp, hw::ArrayInjectOp,
544 hw::ArraySliceOp, hw::StructCreateOp, hw::StructExtractOp,
545 hw::StructInjectOp, hw::UnionCreateOp,
546 hw::UnionExtractOp>();
547 target.addLegalDialect<hw::HWDialect, comb::CombDialect>();
549 RewritePatternSet patterns(&getContext());
550 AggregateTypeConverter typeConverter;
553 target.addDynamicallyLegalOp<comb::MuxOp, hw::BitcastOp>(
554 [&typeConverter](
auto op) {
return typeConverter.isLegal(op); });
556 if (failed(mlir::applyPartialConversion(getOperation(), target,
557 std::move(patterns))))
558 return signalPassFailure();
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
static void populateHWAggregateToCombOpConversionPatterns(RewritePatternSet &patterns, AggregateTypeConverter &typeConverter)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.