21 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
22 #include "mlir/Dialect/Func/IR/FuncOps.h"
23 #include "mlir/Dialect/SCF/IR/SCF.h"
24 #include "mlir/IR/BuiltinDialect.h"
25 #include "mlir/IR/Iterators.h"
26 #include "mlir/Interfaces/SideEffectInterfaces.h"
27 #include "mlir/Pass/Pass.h"
28 #include "mlir/Transforms/DialectConversion.h"
29 #include "mlir/Transforms/RegionUtils.h"
30 #include "llvm/ADT/TypeSwitch.h"
33 #define GEN_PASS_DEF_CONVERTMOORETOCORE
34 #include "circt/Conversion/Passes.h.inc"
38 using namespace circt;
39 using namespace moore;
41 using comb::ICmpPredicate;
42 using llvm::SmallDenseSet;
50 static Value adjustIntegerWidth(OpBuilder &builder, Value value,
51 uint32_t targetWidth, Location loc) {
52 uint32_t intWidth = value.getType().getIntOrFloatBitWidth();
53 if (intWidth == targetWidth)
56 if (intWidth < targetWidth) {
58 loc, builder.getIntegerType(targetWidth - intWidth), 0);
63 intWidth - targetWidth);
65 loc, builder.getIntegerType(intWidth - targetWidth), 0);
66 Value isZero = builder.
create<comb::ICmpOp>(loc, comb::ICmpPredicate::eq, hi,
70 loc, builder.getIntegerType(targetWidth), -1);
75 static hw::ModulePortInfo getModulePortInfo(
const TypeConverter &typeConverter,
79 auto moduleTy = op.getModuleType();
80 SmallVector<hw::PortInfo> inputs, outputs;
81 inputs.reserve(moduleTy.getNumInputs());
82 outputs.reserve(moduleTy.getNumOutputs());
84 for (
auto port : moduleTy.getPorts()) {
85 Type portTy = typeConverter.convertType(port.type);
86 if (
auto ioTy = dyn_cast_or_null<hw::InOutType>(portTy)) {
87 inputs.push_back(hw::PortInfo(
96 hw::PortInfo({{port.name, portTy, port.dir}, resultNum++, {}}));
104 hw::PortInfo({{port.name, portTy, port.dir}, inputNum++, {}}));
108 return hw::ModulePortInfo(inputs, outputs);
116 using OpConversionPattern::OpConversionPattern;
119 matchAndRewrite(SVModuleOp op, OpAdaptor adaptor,
120 ConversionPatternRewriter &rewriter)
const override {
121 rewriter.setInsertionPoint(op);
126 getModulePortInfo(*typeConverter, op));
129 SymbolTable::setSymbolVisibility(hwModuleOp,
130 SymbolTable::getSymbolVisibility(op));
131 rewriter.eraseBlock(hwModuleOp.getBodyBlock());
133 rewriter.convertRegionTypes(&op.getBodyRegion(), *typeConverter)))
135 rewriter.inlineRegionBefore(op.getBodyRegion(), hwModuleOp.getBodyRegion(),
136 hwModuleOp.getBodyRegion().end());
139 rewriter.eraseOp(op);
145 using OpConversionPattern::OpConversionPattern;
148 matchAndRewrite(OutputOp op, OpAdaptor adaptor,
149 ConversionPatternRewriter &rewriter)
const override {
150 rewriter.replaceOpWithNewOp<hw::OutputOp>(op, adaptor.getOperands());
156 using OpConversionPattern::OpConversionPattern;
159 matchAndRewrite(InstanceOp op, OpAdaptor adaptor,
160 ConversionPatternRewriter &rewriter)
const override {
161 auto instName = op.getInstanceNameAttr();
162 auto moduleName = op.getModuleNameAttr();
165 rewriter.setInsertionPoint(op);
166 auto instOp = rewriter.create<hw::InstanceOp>(
167 op.getLoc(), op.getResultTypes(), instName, moduleName, op.getInputs(),
168 op.getInputNamesAttr(), op.getOutputNamesAttr(),
169 rewriter.getArrayAttr({}),
nullptr);
172 op.replaceAllUsesWith(instOp.getResults());
173 rewriter.eraseOp(op);
178 static void getValuesToObserve(Region *region,
179 function_ref<
void(Value)> setInsertionPoint,
180 const TypeConverter *typeConverter,
181 ConversionPatternRewriter &rewriter,
182 SmallVector<Value> &observeValues) {
183 SmallDenseSet<Value> alreadyObserved;
184 Location loc = region->getLoc();
186 auto probeIfSignal = [&](Value value) -> Value {
187 if (!isa<hw::InOutType>(value.getType()))
189 return rewriter.create<llhd::PrbOp>(loc, value);
192 region->getParentOp()->walk<WalkOrder::PreOrder, ForwardDominanceIterator<>>(
193 [&](Operation *operation) {
194 for (
auto value : operation->getOperands()) {
195 if (region->isAncestor(value.getParentRegion()))
197 if (
auto *defOp = value.getDefiningOp();
198 defOp && defOp->hasTrait<OpTrait::ConstantLike>())
200 if (!alreadyObserved.insert(value).second)
203 OpBuilder::InsertionGuard g(rewriter);
204 if (
auto remapped = rewriter.getRemappedValue(value)) {
205 setInsertionPoint(remapped);
206 observeValues.push_back(probeIfSignal(remapped));
208 setInsertionPoint(value);
209 auto type = typeConverter->convertType(value.getType());
210 auto converted = typeConverter->materializeTargetConversion(
211 rewriter, loc, type, value);
212 observeValues.push_back(probeIfSignal(converted));
219 using OpConversionPattern::OpConversionPattern;
222 matchAndRewrite(ProcedureOp op, OpAdaptor adaptor,
223 ConversionPatternRewriter &rewriter)
const override {
225 SmallVector<Value> observedValues;
226 if (op.getKind() == ProcedureKind::AlwaysComb ||
227 op.getKind() == ProcedureKind::AlwaysLatch) {
228 auto setInsertionPoint = [&](Value value) {
229 rewriter.setInsertionPoint(op);
231 getValuesToObserve(&op.getBody(), setInsertionPoint, typeConverter,
232 rewriter, observedValues);
235 auto loc = op.getLoc();
236 if (failed(rewriter.convertRegionTypes(&op.getBody(), *typeConverter)))
241 if (op.getKind() == ProcedureKind::Initial ||
242 op.getKind() == ProcedureKind::Final) {
244 if (op.getKind() == ProcedureKind::Initial)
245 newOp = rewriter.create<llhd::ProcessOp>(loc);
247 newOp = rewriter.create<llhd::FinalOp>(loc);
248 auto &body = newOp->getRegion(0);
249 rewriter.inlineRegionBefore(op.getBody(), body, body.end());
251 llvm::make_early_inc_range(body.getOps<ReturnOp>())) {
252 rewriter.setInsertionPoint(returnOp);
253 rewriter.replaceOpWithNewOp<llhd::HaltOp>(returnOp);
255 rewriter.eraseOp(op);
260 auto newOp = rewriter.create<llhd::ProcessOp>(loc);
265 rewriter.createBlock(&newOp.getBody());
266 auto *block = &op.getBody().front();
267 rewriter.create<cf::BranchOp>(loc, block);
268 rewriter.inlineRegionBefore(op.getBody(), newOp.getBody(),
269 newOp.getBody().end());
277 if (op.getKind() == ProcedureKind::AlwaysComb ||
278 op.getKind() == ProcedureKind::AlwaysLatch) {
279 Block *waitBlock = rewriter.createBlock(&newOp.getBody());
280 rewriter.create<llhd::WaitOp>(loc, observedValues, Value(), ValueRange{},
288 for (
auto returnOp : llvm::make_early_inc_range(newOp.getOps<ReturnOp>())) {
289 rewriter.setInsertionPoint(returnOp);
290 rewriter.create<cf::BranchOp>(loc, block);
291 rewriter.eraseOp(returnOp);
294 rewriter.eraseOp(op);
300 using OpConversionPattern::OpConversionPattern;
303 matchAndRewrite(WaitEventOp op, OpAdaptor adaptor,
304 ConversionPatternRewriter &rewriter)
const override {
338 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
339 auto *waitBlock = rewriter.createBlock(resumeBlock);
340 auto *checkBlock = rewriter.createBlock(resumeBlock);
342 auto loc = op.getLoc();
343 rewriter.setInsertionPoint(op);
344 rewriter.create<cf::BranchOp>(loc, waitBlock);
354 SmallVector<Value> valuesBefore;
355 rewriter.setInsertionPointToEnd(waitBlock);
356 auto clonedOp = cast<WaitEventOp>(rewriter.clone(*op));
358 llvm::make_early_inc_range(clonedOp.getOps<DetectEventOp>())) {
359 valuesBefore.push_back(detectOp.getInput());
360 rewriter.eraseOp(detectOp);
366 SmallVector<Value> observeValues;
367 auto setInsertionPointAfterDef = [&](Value value) {
368 if (
auto *op = value.getDefiningOp())
369 rewriter.setInsertionPointAfter(op);
370 if (
auto arg = dyn_cast<BlockArgument>(value))
371 rewriter.setInsertionPointToStart(value.getParentBlock());
374 getValuesToObserve(&clonedOp.getBody(), setInsertionPointAfterDef,
375 typeConverter, rewriter, observeValues);
380 auto waitOp = rewriter.create<llhd::WaitOp>(loc, observeValues, Value(),
381 ValueRange{}, checkBlock);
382 rewriter.inlineBlockBefore(&clonedOp.getBody().front(), waitOp);
383 rewriter.eraseOp(clonedOp);
387 SmallVector<DetectEventOp> detectOps(op.getBody().getOps<DetectEventOp>());
388 rewriter.inlineBlockBefore(&op.getBody().front(), checkBlock,
390 rewriter.eraseOp(op);
394 auto computeTrigger = [&](Value before, Value after, Edge edge) -> Value {
395 before = typeConverter->materializeTargetConversion(
396 rewriter, loc, rewriter.getI1Type(), before);
397 after = typeConverter->materializeTargetConversion(
398 rewriter, loc, rewriter.getI1Type(), after);
400 if (edge == Edge::AnyChange)
401 return rewriter.create<comb::ICmpOp>(loc, ICmpPredicate::ne, before,
404 SmallVector<Value> disjuncts;
405 Value trueVal = rewriter.create<
hw::ConstantOp>(loc, APInt(1, 1));
407 if (edge == Edge::PosEdge || edge == Edge::BothEdges) {
411 rewriter.create<
comb::AndOp>(loc, notOldVal, after,
true);
412 disjuncts.push_back(posedge);
415 if (edge == Edge::NegEdge || edge == Edge::BothEdges) {
417 rewriter.create<
comb::XorOp>(loc, after, trueVal,
true);
419 rewriter.create<
comb::AndOp>(loc, before, notCurrVal,
true);
420 disjuncts.push_back(posedge);
423 return rewriter.createOrFold<
comb::OrOp>(loc, disjuncts,
true);
430 SmallVector<Value> triggers;
431 for (
auto [detectOp, before] : llvm::zip(detectOps, valuesBefore)) {
433 if (
auto intType = dyn_cast<IntType>(before.getType());
434 !intType || intType.getWidth() != 1)
435 return detectOp->emitError() <<
"requires single bit operand";
437 rewriter.setInsertionPoint(detectOp);
439 computeTrigger(before, detectOp.getInput(), detectOp.getEdge());
440 if (detectOp.getCondition()) {
441 auto condition = typeConverter->materializeTargetConversion(
442 rewriter, loc, rewriter.getI1Type(), detectOp.getCondition());
443 trigger = rewriter.create<
comb::AndOp>(loc, trigger, condition,
true);
445 triggers.push_back(trigger);
446 rewriter.eraseOp(detectOp);
453 rewriter.setInsertionPointToEnd(checkBlock);
454 if (!triggers.empty()) {
455 auto triggered = rewriter.createOrFold<
comb::OrOp>(loc, triggers,
true);
456 rewriter.create<cf::CondBranchOp>(loc, triggered, resumeBlock, waitBlock);
458 rewriter.create<cf::BranchOp>(loc, waitBlock);
470 using OpConversionPattern::OpConversionPattern;
473 matchAndRewrite(VariableOp op, OpAdaptor adaptor,
474 ConversionPatternRewriter &rewriter)
const override {
475 Location loc = op.getLoc();
476 Type resultType = typeConverter->convertType(op.getResult().getType());
478 return rewriter.notifyMatchFailure(op.getLoc(),
"invalid variable type");
481 Value init = adaptor.getInitial();
483 Type
elementType = cast<hw::InOutType>(resultType).getElementType();
495 rewriter.replaceOpWithNewOp<llhd::SignalOp>(op, resultType,
496 op.getNameAttr(), init);
502 using OpConversionPattern::OpConversionPattern;
505 matchAndRewrite(NetOp op, OpAdaptor adaptor,
506 ConversionPatternRewriter &rewriter)
const override {
507 auto loc = op.getLoc();
508 if (op.getKind() != NetKind::Wire)
509 return rewriter.notifyMatchFailure(loc,
"only wire nets supported");
511 auto resultType = typeConverter->convertType(op.getResult().getType());
513 return rewriter.notifyMatchFailure(loc,
"invalid net type");
517 auto elementType = cast<hw::InOutType>(resultType).getElementType();
525 auto signal = rewriter.replaceOpWithNewOp<llhd::SignalOp>(
526 op, resultType, op.getNameAttr(), init);
528 if (
auto assignedValue = adaptor.getAssignment()) {
530 llvm::StringRef(
"ns"), 0, 1);
531 auto time = rewriter.create<llhd::ConstantTimeOp>(loc, timeAttr);
532 rewriter.create<llhd::DrvOp>(loc, signal, assignedValue, time, Value{});
544 using OpConversionPattern::OpConversionPattern;
547 matchAndRewrite(ConstantOp op, OpAdaptor adaptor,
548 ConversionPatternRewriter &rewriter)
const override {
550 auto value = op.getValue().toAPInt(
false);
551 auto type = rewriter.getIntegerType(value.getBitWidth());
553 op, type, rewriter.getIntegerAttr(type, value));
559 using OpConversionPattern::OpConversionPattern;
561 matchAndRewrite(ConcatOp op, OpAdaptor adaptor,
562 ConversionPatternRewriter &rewriter)
const override {
563 rewriter.replaceOpWithNewOp<
comb::ConcatOp>(op, adaptor.getValues());
569 using OpConversionPattern::OpConversionPattern;
571 matchAndRewrite(ReplicateOp op, OpAdaptor adaptor,
572 ConversionPatternRewriter &rewriter)
const override {
573 Type resultType = typeConverter->convertType(op.getResult().getType());
575 rewriter.replaceOpWithNewOp<comb::ReplicateOp>(op, resultType,
582 using OpConversionPattern::OpConversionPattern;
585 matchAndRewrite(ExtractOp op, OpAdaptor adaptor,
586 ConversionPatternRewriter &rewriter)
const override {
588 Type resultType = typeConverter->convertType(op.getResult().getType());
589 Type inputType = adaptor.getInput().getType();
591 if (isa<IntegerType>(inputType)) {
593 op, resultType, adaptor.getInput(), adaptor.getLowBit());
597 if (
auto arrTy = dyn_cast<hw::ArrayType>(inputType)) {
598 int64_t
width = llvm::Log2_64_Ceil(arrTy.getNumElements());
600 op.getLoc(), rewriter.getIntegerType(
width), adaptor.getLowBit());
601 if (isa<hw::ArrayType>(resultType)) {
603 adaptor.getInput(), idx);
608 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(), idx);
617 using OpConversionPattern::OpConversionPattern;
620 matchAndRewrite(ExtractRefOp op, OpAdaptor adaptor,
621 ConversionPatternRewriter &rewriter)
const override {
623 Type resultType = typeConverter->convertType(op.getResult().getType());
625 cast<hw::InOutType>(adaptor.getInput().getType()).getElementType();
627 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
633 op.getLoc(), rewriter.getIntegerType(llvm::Log2_64_Ceil(
width)),
634 adaptor.getLowBit());
635 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
636 op, resultType, adaptor.getInput(), lowBit);
640 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
643 rewriter.getIntegerType(llvm::Log2_64_Ceil(arrType.getNumElements())),
644 adaptor.getLowBit());
646 if (isa<hw::ArrayType>(
647 cast<hw::InOutType>(resultType).getElementType())) {
648 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
649 op, resultType, adaptor.getInput(), lowBit);
653 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
663 using OpConversionPattern::OpConversionPattern;
666 matchAndRewrite(DynExtractOp op, OpAdaptor adaptor,
667 ConversionPatternRewriter &rewriter)
const override {
668 Type resultType = typeConverter->convertType(op.getResult().getType());
669 Type inputType = adaptor.getInput().getType();
671 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
672 Value amount = adjustIntegerWidth(rewriter, adaptor.getLowBit(),
673 intType.getWidth(), op->getLoc());
674 Value value = rewriter.create<
comb::ShrUOp>(op->getLoc(),
675 adaptor.getInput(), amount);
677 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, resultType, value, 0);
681 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
682 unsigned idxWidth = llvm::Log2_64_Ceil(arrType.getNumElements());
683 Value idx = adjustIntegerWidth(rewriter, adaptor.getLowBit(), idxWidth,
686 if (isa<hw::ArrayType>(resultType)) {
688 adaptor.getInput(), idx);
692 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(), idx);
701 using OpConversionPattern::OpConversionPattern;
704 matchAndRewrite(DynExtractRefOp op, OpAdaptor adaptor,
705 ConversionPatternRewriter &rewriter)
const override {
707 Type resultType = typeConverter->convertType(op.getResult().getType());
709 cast<hw::InOutType>(adaptor.getInput().getType()).getElementType();
711 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
717 adjustIntegerWidth(rewriter, adaptor.getLowBit(),
718 llvm::Log2_64_Ceil(
width), op->getLoc());
719 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
720 op, resultType, adaptor.getInput(), amount);
724 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
725 Value idx = adjustIntegerWidth(
726 rewriter, adaptor.getLowBit(),
727 llvm::Log2_64_Ceil(arrType.getNumElements()), op->getLoc());
729 if (isa<hw::ArrayType>(
730 cast<hw::InOutType>(resultType).getElementType())) {
731 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
732 op, resultType, adaptor.getInput(), idx);
736 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
746 using OpConversionPattern::OpConversionPattern;
749 matchAndRewrite(StructCreateOp op, OpAdaptor adaptor,
750 ConversionPatternRewriter &rewriter)
const override {
751 Type resultType = typeConverter->convertType(op.getResult().getType());
753 adaptor.getFields());
759 using OpConversionPattern::OpConversionPattern;
762 matchAndRewrite(StructExtractOp op, OpAdaptor adaptor,
763 ConversionPatternRewriter &rewriter)
const override {
765 op, adaptor.getInput(), adaptor.getFieldNameAttr());
770 struct StructExtractRefOpConversion
772 using OpConversionPattern::OpConversionPattern;
775 matchAndRewrite(StructExtractRefOp op, OpAdaptor adaptor,
776 ConversionPatternRewriter &rewriter)
const override {
777 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
778 op, adaptor.getInput(), adaptor.getFieldNameAttr());
784 using OpConversionPattern::OpConversionPattern;
786 matchAndRewrite(ReduceAndOp op, OpAdaptor adaptor,
787 ConversionPatternRewriter &rewriter)
const override {
788 Type resultType = typeConverter->convertType(op.getInput().getType());
789 Value max = rewriter.create<
hw::ConstantOp>(op->getLoc(), resultType, -1);
791 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::eq,
792 adaptor.getInput(), max);
798 using OpConversionPattern::OpConversionPattern;
800 matchAndRewrite(ReduceOrOp op, OpAdaptor adaptor,
801 ConversionPatternRewriter &rewriter)
const override {
802 Type resultType = typeConverter->convertType(op.getInput().getType());
803 Value zero = rewriter.create<
hw::ConstantOp>(op->getLoc(), resultType, 0);
805 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
806 adaptor.getInput(), zero);
812 using OpConversionPattern::OpConversionPattern;
814 matchAndRewrite(ReduceXorOp op, OpAdaptor adaptor,
815 ConversionPatternRewriter &rewriter)
const override {
817 rewriter.replaceOpWithNewOp<
comb::ParityOp>(op, adaptor.getInput());
823 using OpConversionPattern::OpConversionPattern;
825 matchAndRewrite(BoolCastOp op, OpAdaptor adaptor,
826 ConversionPatternRewriter &rewriter)
const override {
827 Type resultType = typeConverter->convertType(op.getInput().getType());
828 if (isa_and_nonnull<IntegerType>(resultType)) {
829 Value zero = rewriter.create<
hw::ConstantOp>(op->getLoc(), resultType, 0);
830 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
831 adaptor.getInput(), zero);
839 using OpConversionPattern::OpConversionPattern;
841 matchAndRewrite(NotOp op, OpAdaptor adaptor,
842 ConversionPatternRewriter &rewriter)
const override {
844 ConversionPattern::typeConverter->convertType(op.getResult().getType());
845 Value max = rewriter.create<
hw::ConstantOp>(op.getLoc(), resultType, -1);
847 rewriter.replaceOpWithNewOp<
comb::XorOp>(op, adaptor.getInput(), max);
853 using OpConversionPattern::OpConversionPattern;
855 matchAndRewrite(NegOp op, OpAdaptor adaptor,
856 ConversionPatternRewriter &rewriter)
const override {
858 ConversionPattern::typeConverter->convertType(op.getResult().getType());
859 Value zero = rewriter.create<
hw::ConstantOp>(op.getLoc(), resultType, 0);
861 rewriter.replaceOpWithNewOp<
comb::SubOp>(op, zero, adaptor.getInput());
866 template <
typename SourceOp,
typename TargetOp>
869 using OpAdaptor =
typename SourceOp::Adaptor;
872 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
873 ConversionPatternRewriter &rewriter)
const override {
874 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
875 adaptor.getRhs(),
false);
880 template <
typename SourceOp, ICmpPredicate pred>
883 using OpAdaptor =
typename SourceOp::Adaptor;
886 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
887 ConversionPatternRewriter &rewriter)
const override {
889 ConversionPattern::typeConverter->convertType(op.getResult().getType());
891 rewriter.replaceOpWithNewOp<comb::ICmpOp>(
892 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
897 template <
typename SourceOp,
bool withoutX>
900 using OpAdaptor =
typename SourceOp::Adaptor;
903 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
904 ConversionPatternRewriter &rewriter)
const override {
910 unsigned bitWidth = op.getLhs().getType().getWidth();
911 auto ignoredBits = APInt::getZero(bitWidth);
912 auto detectIgnoredBits = [&](Value value) {
913 auto constOp = value.getDefiningOp<ConstantOp>();
916 auto constValue = constOp.getValue();
918 ignoredBits |= constValue.getZBits();
920 ignoredBits |= constValue.getUnknownBits();
922 detectIgnoredBits(op.getLhs());
923 detectIgnoredBits(op.getRhs());
927 Value lhs = adaptor.getLhs();
928 Value rhs = adaptor.getRhs();
929 if (!ignoredBits.isZero()) {
930 ignoredBits.flipAllBits();
931 auto maskOp = rewriter.create<
hw::ConstantOp>(op.getLoc(), ignoredBits);
932 lhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), lhs, maskOp);
933 rhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), rhs, maskOp);
936 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, ICmpPredicate::ceq, lhs, rhs);
942 using OpConversionPattern::OpConversionPattern;
945 matchAndRewrite(ConversionOp op, OpAdaptor adaptor,
946 ConversionPatternRewriter &rewriter)
const override {
947 Location loc = op.getLoc();
948 Type resultType = typeConverter->convertType(op.getResult().getType());
951 if (inputBw == -1 || resultBw == -1)
955 loc, rewriter.getIntegerType(inputBw), adaptor.getInput());
956 Value amount = adjustIntegerWidth(rewriter, input, resultBw, loc);
959 rewriter.createOrFold<
hw::BitcastOp>(loc, resultType, amount);
960 rewriter.replaceOp(op, result);
970 using OpConversionPattern::OpConversionPattern;
973 matchAndRewrite(hw::InstanceOp op, OpAdaptor adaptor,
974 ConversionPatternRewriter &rewriter)
const override {
975 SmallVector<Type> convResTypes;
976 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
979 rewriter.replaceOpWithNewOp<hw::InstanceOp>(
980 op, convResTypes, op.getInstanceName(), op.getModuleName(),
981 adaptor.getOperands(), op.getArgNames(),
983 rewriter.getArrayAttr({}),
nullptr);
990 using OpConversionPattern::OpConversionPattern;
993 matchAndRewrite(func::ReturnOp op, OpAdaptor adaptor,
994 ConversionPatternRewriter &rewriter)
const override {
995 rewriter.replaceOpWithNewOp<func::ReturnOp>(op, adaptor.getOperands());
1001 using OpConversionPattern::OpConversionPattern;
1004 matchAndRewrite(cf::CondBranchOp op, OpAdaptor adaptor,
1005 ConversionPatternRewriter &rewriter)
const override {
1006 rewriter.replaceOpWithNewOp<cf::CondBranchOp>(
1007 op, adaptor.getCondition(), adaptor.getTrueDestOperands(),
1008 adaptor.getFalseDestOperands(), op.getTrueDest(), op.getFalseDest());
1014 using OpConversionPattern::OpConversionPattern;
1017 matchAndRewrite(cf::BranchOp op, OpAdaptor adaptor,
1018 ConversionPatternRewriter &rewriter)
const override {
1019 rewriter.replaceOpWithNewOp<cf::BranchOp>(op, op.getDest(),
1020 adaptor.getDestOperands());
1026 using OpConversionPattern::OpConversionPattern;
1029 matchAndRewrite(func::CallOp op, OpAdaptor adaptor,
1030 ConversionPatternRewriter &rewriter)
const override {
1031 SmallVector<Type> convResTypes;
1032 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1034 rewriter.replaceOpWithNewOp<func::CallOp>(
1035 op, adaptor.getCallee(), convResTypes, adaptor.getOperands());
1040 struct UnrealizedConversionCastConversion
1042 using OpConversionPattern::OpConversionPattern;
1045 matchAndRewrite(UnrealizedConversionCastOp op, OpAdaptor adaptor,
1046 ConversionPatternRewriter &rewriter)
const override {
1047 SmallVector<Type> convResTypes;
1048 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1053 if (convResTypes == adaptor.getOperands().getTypes()) {
1054 rewriter.replaceOp(op, adaptor.getOperands());
1058 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
1059 op, convResTypes, adaptor.getOperands());
1065 using OpConversionPattern::OpConversionPattern;
1068 matchAndRewrite(ShlOp op, OpAdaptor adaptor,
1069 ConversionPatternRewriter &rewriter)
const override {
1070 Type resultType = typeConverter->convertType(op.getResult().getType());
1074 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1075 resultType.getIntOrFloatBitWidth(), op->getLoc());
1076 rewriter.replaceOpWithNewOp<
comb::ShlOp>(op, resultType, adaptor.getValue(),
1083 using OpConversionPattern::OpConversionPattern;
1086 matchAndRewrite(ShrOp op, OpAdaptor adaptor,
1087 ConversionPatternRewriter &rewriter)
const override {
1088 Type resultType = typeConverter->convertType(op.getResult().getType());
1092 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1093 resultType.getIntOrFloatBitWidth(), op->getLoc());
1095 op, resultType, adaptor.getValue(), amount,
false);
1101 using OpConversionPattern::OpConversionPattern;
1104 matchAndRewrite(AShrOp op, OpAdaptor adaptor,
1105 ConversionPatternRewriter &rewriter)
const override {
1106 Type resultType = typeConverter->convertType(op.getResult().getType());
1110 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1111 resultType.getIntOrFloatBitWidth(), op->getLoc());
1113 op, resultType, adaptor.getValue(), amount,
false);
1119 using OpConversionPattern::OpConversionPattern;
1122 matchAndRewrite(ReadOp op, OpAdaptor adaptor,
1123 ConversionPatternRewriter &rewriter)
const override {
1124 rewriter.replaceOpWithNewOp<llhd::PrbOp>(op, adaptor.getInput());
1129 struct AssignedVariableOpConversion
1131 using OpConversionPattern::OpConversionPattern;
1134 matchAndRewrite(AssignedVariableOp op, OpAdaptor adaptor,
1135 ConversionPatternRewriter &rewriter)
const override {
1136 rewriter.replaceOpWithNewOp<hw::WireOp>(op, adaptor.getInput(),
1137 adaptor.getNameAttr());
1142 template <
typename OpTy,
unsigned DeltaTime,
unsigned EpsilonTime>
1145 using OpAdaptor =
typename OpTy::Adaptor;
1148 matchAndRewrite(OpTy op, OpAdaptor adaptor,
1149 ConversionPatternRewriter &rewriter)
const override {
1153 op->getContext(), 0U, llvm::StringRef(
"ns"), DeltaTime, EpsilonTime);
1154 auto time = rewriter.create<llhd::ConstantTimeOp>(op->getLoc(), timeAttr);
1155 rewriter.replaceOpWithNewOp<llhd::DrvOp>(op, adaptor.getDst(),
1156 adaptor.getSrc(), time, Value{});
1162 using OpConversionPattern::OpConversionPattern;
1165 matchAndRewrite(ConditionalOp op, OpAdaptor adaptor,
1166 ConversionPatternRewriter &rewriter)
const override {
1171 auto type = typeConverter->convertType(op.getType());
1173 auto hasNoWriteEffect = [](Region ®ion) {
1174 auto result = region.walk([](Operation *operation) {
1175 if (
auto memOp = dyn_cast<MemoryEffectOpInterface>(operation))
1176 if (!memOp.hasEffect<MemoryEffects::Write>() &&
1177 !memOp.hasEffect<MemoryEffects::Free>())
1178 return WalkResult::advance();
1180 return WalkResult::interrupt();
1182 return !result.wasInterrupted();
1185 if (hasNoWriteEffect(op.getTrueRegion()) &&
1186 hasNoWriteEffect(op.getFalseRegion())) {
1187 Operation *trueTerm = op.getTrueRegion().front().getTerminator();
1188 Operation *falseTerm = op.getFalseRegion().front().getTerminator();
1190 rewriter.inlineBlockBefore(&op.getTrueRegion().front(), op);
1191 rewriter.inlineBlockBefore(&op.getFalseRegion().front(), op);
1193 Value convTrueVal = typeConverter->materializeTargetConversion(
1194 rewriter, op.getLoc(), type, trueTerm->getOperand(0));
1195 Value convFalseVal = typeConverter->materializeTargetConversion(
1196 rewriter, op.getLoc(), type, falseTerm->getOperand(0));
1198 rewriter.eraseOp(trueTerm);
1199 rewriter.eraseOp(falseTerm);
1201 rewriter.replaceOpWithNewOp<
comb::MuxOp>(op, adaptor.getCondition(),
1202 convTrueVal, convFalseVal);
1207 rewriter.create<scf::IfOp>(op.getLoc(), type, adaptor.getCondition());
1208 rewriter.inlineRegionBefore(op.getTrueRegion(), ifOp.getThenRegion(),
1209 ifOp.getThenRegion().end());
1210 rewriter.inlineRegionBefore(op.getFalseRegion(), ifOp.getElseRegion(),
1211 ifOp.getElseRegion().end());
1212 rewriter.replaceOp(op, ifOp);
1218 using OpConversionPattern::OpConversionPattern;
1221 matchAndRewrite(YieldOp op, OpAdaptor adaptor,
1222 ConversionPatternRewriter &rewriter)
const override {
1223 rewriter.replaceOpWithNewOp<scf::YieldOp>(op, adaptor.getResult());
1228 template <
typename SourceOp>
1231 using OpAdaptor =
typename SourceOp::Adaptor;
1234 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1235 ConversionPatternRewriter &rewriter)
const override {
1236 rewriter.modifyOpInPlace(op,
1237 [&]() { op->setOperands(adaptor.getOperands()); });
1242 template <
typename MooreOpTy,
typename VerifOpTy>
1245 using OpAdaptor =
typename MooreOpTy::Adaptor;
1248 matchAndRewrite(MooreOpTy op, OpAdaptor adaptor,
1249 ConversionPatternRewriter &rewriter)
const override {
1251 op.getLabel().has_value()
1253 : StringAttr::
get(op->getContext());
1254 rewriter.replaceOpWithNewOp<VerifOpTy>(op, adaptor.getCond(), mlir::Value(),
1265 using OpConversionPattern::OpConversionPattern;
1268 matchAndRewrite(FormatLiteralOp op, OpAdaptor adaptor,
1269 ConversionPatternRewriter &rewriter)
const override {
1270 rewriter.replaceOpWithNewOp<sim::FormatLitOp>(op, adaptor.getLiteral());
1276 using OpConversionPattern::OpConversionPattern;
1279 matchAndRewrite(FormatConcatOp op, OpAdaptor adaptor,
1280 ConversionPatternRewriter &rewriter)
const override {
1281 rewriter.replaceOpWithNewOp<sim::FormatStringConcatOp>(op,
1282 adaptor.getInputs());
1288 using OpConversionPattern::OpConversionPattern;
1291 matchAndRewrite(FormatIntOp op, OpAdaptor adaptor,
1292 ConversionPatternRewriter &rewriter)
const override {
1294 switch (op.getFormat()) {
1295 case IntFormat::Decimal:
1296 rewriter.replaceOpWithNewOp<sim::FormatDecOp>(op, adaptor.getValue());
1298 case IntFormat::Binary:
1299 rewriter.replaceOpWithNewOp<sim::FormatBinOp>(op, adaptor.getValue());
1301 case IntFormat::HexLower:
1302 case IntFormat::HexUpper:
1303 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(op, adaptor.getValue());
1306 return rewriter.notifyMatchFailure(op,
"unsupported int format");
1312 using OpConversionPattern::OpConversionPattern;
1315 matchAndRewrite(DisplayBIOp op, OpAdaptor adaptor,
1316 ConversionPatternRewriter &rewriter)
const override {
1317 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(
1318 op, adaptor.getMessage());
1330 const TypeConverter &converter) {
1331 target.addIllegalDialect<MooreDialect>();
1332 target.addLegalDialect<comb::CombDialect>();
1333 target.addLegalDialect<hw::HWDialect>();
1334 target.addLegalDialect<llhd::LLHDDialect>();
1335 target.addLegalDialect<mlir::BuiltinDialect>();
1336 target.addLegalDialect<sim::SimDialect>();
1337 target.addLegalDialect<verif::VerifDialect>();
1339 target.addLegalOp<debug::ScopeOp>();
1341 target.addDynamicallyLegalOp<
1342 cf::CondBranchOp, cf::BranchOp, scf::IfOp, scf::YieldOp, func::CallOp,
1343 func::ReturnOp, UnrealizedConversionCastOp, hw::OutputOp, hw::InstanceOp,
1344 debug::ArrayOp, debug::StructOp, debug::VariableOp>(
1345 [&](Operation *op) {
return converter.isLegal(op); });
1347 target.addDynamicallyLegalOp<func::FuncOp>([&](func::FuncOp op) {
1348 return converter.isSignatureLegal(op.getFunctionType()) &&
1349 converter.isLegal(&op.getFunctionBody());
1353 return converter.isSignatureLegal(op.getModuleType().getFuncType()) &&
1354 converter.isLegal(&op.getBody());
1359 typeConverter.addConversion([&](IntType type) {
1363 typeConverter.addConversion([&](FormatStringType type) {
1367 typeConverter.addConversion([&](ArrayType type) -> std::optional<Type> {
1368 if (
auto elementType = typeConverter.convertType(type.getElementType()))
1373 typeConverter.addConversion([&](StructType type) -> std::optional<Type> {
1374 SmallVector<hw::StructType::FieldInfo> fields;
1375 for (
auto field : type.getMembers()) {
1376 hw::StructType::FieldInfo info;
1377 info.type = typeConverter.convertType(field.type);
1380 info.name = field.name;
1381 fields.push_back(info);
1391 typeConverter.addConversion(
1392 [&](UnpackedStructType type) -> std::optional<Type> {
1393 SmallVector<hw::StructType::FieldInfo> fields;
1394 for (
auto field : type.getMembers()) {
1395 hw::StructType::FieldInfo info;
1396 info.type = typeConverter.convertType(field.type);
1399 info.name = field.name;
1400 fields.push_back(info);
1405 typeConverter.addConversion([&](RefType type) -> std::optional<Type> {
1406 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
1412 typeConverter.addConversion([](IntegerType type) {
return type; });
1413 typeConverter.addConversion([](debug::ArrayType type) {
return type; });
1414 typeConverter.addConversion([](debug::ScopeType type) {
return type; });
1415 typeConverter.addConversion([](debug::StructType type) {
return type; });
1417 typeConverter.addConversion([&](
hw::InOutType type) -> std::optional<Type> {
1418 if (
auto innerType = typeConverter.convertType(type.getElementType()))
1423 typeConverter.addConversion([&](hw::ArrayType type) -> std::optional<Type> {
1424 if (
auto elementType = typeConverter.convertType(type.getElementType()))
1429 typeConverter.addConversion([&](hw::StructType type) -> std::optional<Type> {
1430 SmallVector<hw::StructType::FieldInfo> fields;
1431 for (
auto field : type.getElements()) {
1432 hw::StructType::FieldInfo info;
1433 info.type = typeConverter.convertType(field.type);
1436 info.name = field.name;
1437 fields.push_back(info);
1442 typeConverter.addTargetMaterialization(
1443 [&](mlir::OpBuilder &builder, mlir::Type resultType,
1444 mlir::ValueRange inputs,
1445 mlir::Location loc) -> std::optional<mlir::Value> {
1446 if (inputs.size() != 1 || !inputs[0])
1447 return std::nullopt;
1449 .create<UnrealizedConversionCastOp>(loc, resultType, inputs[0])
1453 typeConverter.addSourceMaterialization(
1454 [&](mlir::OpBuilder &builder, mlir::Type resultType,
1455 mlir::ValueRange inputs,
1456 mlir::Location loc) -> std::optional<mlir::Value> {
1457 if (inputs.size() != 1)
1458 return std::nullopt;
1460 .create<UnrealizedConversionCastOp>(loc, resultType, inputs[0])
1466 TypeConverter &typeConverter) {
1467 auto *context =
patterns.getContext();
1471 VariableOpConversion,
1475 ConstantOpConv, ConcatOpConversion, ReplicateOpConversion,
1476 ExtractOpConversion, DynExtractOpConversion, DynExtractRefOpConversion,
1477 ConversionOpConversion, ReadOpConversion,
1478 StructExtractOpConversion, StructExtractRefOpConversion,
1479 ExtractRefOpConversion, StructCreateOpConversion, ConditionalOpConversion,
1480 YieldOpConversion, OutputOpConversion,
1483 ReduceAndOpConversion, ReduceOrOpConversion, ReduceXorOpConversion,
1484 BoolCastOpConversion, NotOpConversion, NegOpConversion,
1487 BinaryOpConversion<AddOp, comb::AddOp>,
1488 BinaryOpConversion<SubOp, comb::SubOp>,
1489 BinaryOpConversion<MulOp, comb::MulOp>,
1490 BinaryOpConversion<DivUOp, comb::DivUOp>,
1491 BinaryOpConversion<DivSOp, comb::DivSOp>,
1492 BinaryOpConversion<ModUOp, comb::ModUOp>,
1493 BinaryOpConversion<ModSOp, comb::ModSOp>,
1494 BinaryOpConversion<AndOp, comb::AndOp>,
1495 BinaryOpConversion<OrOp, comb::OrOp>,
1496 BinaryOpConversion<XorOp, comb::XorOp>,
1499 ICmpOpConversion<UltOp, ICmpPredicate::ult>,
1500 ICmpOpConversion<SltOp, ICmpPredicate::slt>,
1501 ICmpOpConversion<UleOp, ICmpPredicate::ule>,
1502 ICmpOpConversion<SleOp, ICmpPredicate::sle>,
1503 ICmpOpConversion<UgtOp, ICmpPredicate::ugt>,
1504 ICmpOpConversion<SgtOp, ICmpPredicate::sgt>,
1505 ICmpOpConversion<UgeOp, ICmpPredicate::uge>,
1506 ICmpOpConversion<SgeOp, ICmpPredicate::sge>,
1507 ICmpOpConversion<EqOp, ICmpPredicate::eq>,
1508 ICmpOpConversion<NeOp, ICmpPredicate::ne>,
1509 ICmpOpConversion<CaseEqOp, ICmpPredicate::ceq>,
1510 ICmpOpConversion<CaseNeOp, ICmpPredicate::cne>,
1511 ICmpOpConversion<WildcardEqOp, ICmpPredicate::weq>,
1512 ICmpOpConversion<WildcardNeOp, ICmpPredicate::wne>,
1513 CaseXZEqOpConversion<CaseZEqOp, true>,
1514 CaseXZEqOpConversion<CaseXZEqOp, false>,
1517 SVModuleOpConversion, InstanceOpConversion, ProcedureOpConversion, WaitEventOpConversion,
1520 ShrOpConversion, ShlOpConversion, AShrOpConversion,
1523 AssignOpConversion<ContinuousAssignOp, 0, 1>,
1524 AssignOpConversion<BlockingAssignOp, 0, 1>,
1525 AssignOpConversion<NonBlockingAssignOp, 1, 0>,
1526 AssignedVariableOpConversion,
1529 CondBranchOpConversion, BranchOpConversion,
1532 HWInstanceOpConversion, ReturnOpConversion,
1533 CallOpConversion, UnrealizedConversionCastConversion,
1534 InPlaceOpConversion<debug::ArrayOp>,
1535 InPlaceOpConversion<debug::StructOp>,
1536 InPlaceOpConversion<debug::VariableOp>,
1539 AssertLikeOpConversion<AssertOp, verif::AssertOp>,
1540 AssertLikeOpConversion<AssumeOp, verif::AssumeOp>,
1541 AssertLikeOpConversion<CoverOp, verif::CoverOp>,
1544 FormatLiteralOpConversion,
1545 FormatConcatOpConversion,
1546 FormatIntOpConversion,
1547 DisplayBIOpConversion
1548 >(typeConverter, context);
1551 mlir::populateAnyFunctionOpInterfaceTypeConversionPattern(
patterns,
1554 hw::HWModuleOp::getOperationName(),
patterns, typeConverter);
1562 struct MooreToCorePass
1563 :
public circt::impl::ConvertMooreToCoreBase<MooreToCorePass> {
1564 void runOnOperation()
override;
1570 return std::make_unique<MooreToCorePass>();
1574 void MooreToCorePass::runOnOperation() {
1575 MLIRContext &context = getContext();
1576 ModuleOp module = getOperation();
1578 IRRewriter rewriter(module);
1579 (void)mlir::eraseUnreachableBlocks(rewriter, module->getRegions());
1581 ConversionTarget target(context);
1582 TypeConverter typeConverter;
1583 RewritePatternSet
patterns(&context);
1588 if (failed(applyFullConversion(module, target, std::move(
patterns))))
1589 signalPassFailure();
static void populateOpConversion(RewritePatternSet &patterns, TypeConverter &typeConverter)
static void populateLegality(ConversionTarget &target, const TypeConverter &converter)
static void populateTypeConversion(TypeConverter &typeConverter)
def create(data_type, value)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
void populateHWModuleLikeTypeConversionPattern(StringRef moduleLikeOpName, RewritePatternSet &patterns, TypeConverter &converter)
circt::hw::InOutType InOutType
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< OperationPass< ModuleOp > > createConvertMooreToCorePass()
Create an Moore to Comb/HW/LLHD conversion pass.