21#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h"
22#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
23#include "mlir/Dialect/ControlFlow/Transforms/StructuralTypeConversions.h"
24#include "mlir/Dialect/Func/IR/FuncOps.h"
25#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
26#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
27#include "mlir/Dialect/Math/IR/Math.h"
28#include "mlir/Dialect/SCF/IR/SCF.h"
29#include "mlir/IR/BuiltinDialect.h"
30#include "mlir/IR/Iterators.h"
31#include "mlir/Interfaces/SideEffectInterfaces.h"
32#include "mlir/Pass/Pass.h"
33#include "mlir/Transforms/DialectConversion.h"
34#include "mlir/Transforms/RegionUtils.h"
35#include "llvm/ADT/TypeSwitch.h"
36#include "llvm/IR/DerivedTypes.h"
39#define GEN_PASS_DEF_CONVERTMOORETOCORE
40#include "circt/Conversion/Passes.h.inc"
47using comb::ICmpPredicate;
48using llvm::SmallDenseSet;
53struct ClassTypeCache {
54 struct ClassStructInfo {
55 LLVM::LLVMStructType classBody;
58 DenseMap<StringRef, SmallVector<unsigned, 2>> propertyPath;
62 void setFieldPath(StringRef propertyName, ArrayRef<unsigned> path) {
63 this->propertyPath[propertyName] =
64 SmallVector<unsigned, 2>(path.begin(), path.end());
68 std::optional<ArrayRef<unsigned>>
69 getFieldPath(StringRef propertySym)
const {
70 if (
auto prop = this->propertyPath.find(propertySym);
71 prop != this->propertyPath.end())
72 return ArrayRef<unsigned>(prop->second);
79 void setClassInfo(SymbolRefAttr classSym,
const ClassStructInfo &
info) {
80 auto &dst = classToStructMap[classSym];
85 std::optional<ClassStructInfo> getStructInfo(SymbolRefAttr classSym)
const {
86 if (
auto it = classToStructMap.find(classSym); it != classToStructMap.end())
95 DenseMap<Attribute, ClassStructInfo> classToStructMap;
99static LLVM::LLVMFuncOp getOrCreateMalloc(ModuleOp mod, OpBuilder &b) {
100 if (
auto f = mod.lookupSymbol<LLVM::LLVMFuncOp>(
"malloc"))
103 OpBuilder::InsertionGuard g(b);
104 b.setInsertionPointToStart(mod.getBody());
106 auto i64Ty = IntegerType::get(mod.getContext(), 64);
107 auto ptrTy = LLVM::LLVMPointerType::get(mod.getContext());
108 auto fnTy = LLVM::LLVMFunctionType::get(ptrTy, {i64Ty},
false);
110 auto fn = LLVM::LLVMFuncOp::create(b, mod.getLoc(),
"malloc", fnTy);
112 fn.setLinkage(LLVM::Linkage::External);
118static LLVM::LLVMStructType getOrCreateOpaqueStruct(MLIRContext *ctx,
119 SymbolRefAttr className) {
120 return LLVM::LLVMStructType::getIdentified(ctx, className.getRootReference());
123static LogicalResult resolveClassStructBody(ClassDeclOp op,
124 TypeConverter
const &typeConverter,
125 ClassTypeCache &cache) {
127 auto classSym = SymbolRefAttr::get(op.getSymNameAttr());
128 auto structInfo = cache.getStructInfo(classSym);
134 ClassTypeCache::ClassStructInfo structBody;
135 SmallVector<Type> structBodyMembers;
138 unsigned derivedStartIdx = 0;
140 if (
auto baseClass = op.getBaseAttr()) {
142 ModuleOp mod = op->getParentOfType<ModuleOp>();
143 auto *opSym = mod.lookupSymbol(baseClass);
144 auto classDeclOp = cast<ClassDeclOp>(opSym);
146 if (failed(resolveClassStructBody(classDeclOp, typeConverter, cache)))
150 auto baseClassStruct = cache.getStructInfo(baseClass);
151 structBodyMembers.push_back(baseClassStruct->classBody);
155 for (
auto &kv : baseClassStruct->propertyPath) {
156 SmallVector<unsigned, 2> path;
158 path.append(kv.second.begin(), kv.second.end());
159 structBody.setFieldPath(kv.first, path);
164 unsigned iterator = derivedStartIdx;
165 auto &block = op.getBody().front();
166 for (Operation &child : block) {
167 if (
auto prop = dyn_cast<ClassPropertyDeclOp>(child)) {
168 Type mooreTy = prop.getPropertyType();
169 Type llvmTy = typeConverter.convertType(mooreTy);
171 return prop.emitOpError()
172 <<
"failed to convert property type " << mooreTy;
174 structBodyMembers.push_back(llvmTy);
177 SmallVector<unsigned, 2> path{iterator};
178 structBody.setFieldPath(prop.getSymName(), path);
184 auto llvmStructTy = getOrCreateOpaqueStruct(op.getContext(), classSym);
186 if (!structBodyMembers.empty() &&
187 failed(llvmStructTy.setBody(structBodyMembers,
false)))
188 return op.emitOpError() <<
"Failed to set LLVM Struct body";
190 structBody.classBody = llvmStructTy;
191 cache.setClassInfo(classSym, structBody);
197static LogicalResult resolveClassStructBody(ModuleOp mod, SymbolRefAttr op,
198 TypeConverter
const &typeConverter,
199 ClassTypeCache &cache) {
200 auto classDeclOp = cast<ClassDeclOp>(*mod.lookupSymbol(op));
201 return resolveClassStructBody(classDeclOp, typeConverter, cache);
208static Value adjustIntegerWidth(OpBuilder &builder, Value value,
209 uint32_t targetWidth, Location loc) {
210 uint32_t intWidth = value.getType().getIntOrFloatBitWidth();
211 if (intWidth == targetWidth)
214 if (intWidth < targetWidth) {
216 builder, loc, builder.getIntegerType(targetWidth - intWidth), 0);
217 return comb::ConcatOp::create(builder, loc, ValueRange{zeroExt, value});
221 intWidth - targetWidth);
223 builder, loc, builder.getIntegerType(intWidth - targetWidth), 0);
224 Value isZero = comb::ICmpOp::create(builder, loc, comb::ICmpPredicate::eq, hi,
228 builder.getIntegerType(targetWidth), -1);
229 return comb::MuxOp::create(builder, loc, isZero, lo, max,
false);
236 size_t resultNum = 0;
237 auto moduleTy = op.getModuleType();
238 SmallVector<hw::PortInfo> ports;
239 ports.reserve(moduleTy.getNumPorts());
241 for (
auto port : moduleTy.getPorts()) {
242 Type portTy = typeConverter.convertType(port.type);
243 if (port.dir == hw::ModulePort::Direction::Output) {
245 hw::PortInfo({{port.name, portTy, port.dir}, resultNum++, {}}));
253 hw::PortInfo({{port.name, portTy, port.dir}, inputNum++, {}}));
265 using OpConversionPattern::OpConversionPattern;
268 matchAndRewrite(SVModuleOp op, OpAdaptor adaptor,
269 ConversionPatternRewriter &rewriter)
const override {
270 rewriter.setInsertionPoint(op);
274 hw::HWModuleOp::create(rewriter, op.getLoc(), op.getSymNameAttr(),
275 getModulePortInfo(*typeConverter, op));
278 SymbolTable::setSymbolVisibility(hwModuleOp,
279 SymbolTable::getSymbolVisibility(op));
280 rewriter.eraseBlock(hwModuleOp.getBodyBlock());
282 rewriter.convertRegionTypes(&op.getBodyRegion(), *typeConverter)))
284 rewriter.inlineRegionBefore(op.getBodyRegion(), hwModuleOp.getBodyRegion(),
285 hwModuleOp.getBodyRegion().end());
288 rewriter.eraseOp(op);
294 using OpConversionPattern::OpConversionPattern;
297 matchAndRewrite(OutputOp op, OpAdaptor adaptor,
298 ConversionPatternRewriter &rewriter)
const override {
299 rewriter.replaceOpWithNewOp<hw::OutputOp>(op, adaptor.getOperands());
305 using OpConversionPattern::OpConversionPattern;
308 matchAndRewrite(InstanceOp op, OpAdaptor adaptor,
309 ConversionPatternRewriter &rewriter)
const override {
310 auto instName = op.getInstanceNameAttr();
311 auto moduleName = op.getModuleNameAttr();
314 rewriter.setInsertionPoint(op);
315 auto instOp = hw::InstanceOp::create(
316 rewriter, op.getLoc(), op.getResultTypes(), instName, moduleName,
317 op.getInputs(), op.getInputNamesAttr(), op.getOutputNamesAttr(),
318 rewriter.getArrayAttr({}),
nullptr,
322 op.replaceAllUsesWith(instOp.getResults());
323 rewriter.eraseOp(op);
328static void getValuesToObserve(Region *region,
329 function_ref<
void(Value)> setInsertionPoint,
330 const TypeConverter *typeConverter,
331 ConversionPatternRewriter &rewriter,
332 SmallVector<Value> &observeValues) {
333 SmallDenseSet<Value> alreadyObserved;
334 Location loc = region->getLoc();
336 auto probeIfSignal = [&](Value value) -> Value {
337 if (!isa<llhd::RefType>(value.getType()))
339 return llhd::ProbeOp::create(rewriter, loc, value);
342 region->getParentOp()->walk<WalkOrder::PreOrder, ForwardDominanceIterator<>>(
343 [&](Operation *operation) {
344 for (
auto value : operation->getOperands()) {
345 if (isa<BlockArgument>(value))
346 value = rewriter.getRemappedValue(value);
348 if (region->isAncestor(value.getParentRegion()))
350 if (
auto *defOp = value.getDefiningOp();
351 defOp && defOp->hasTrait<OpTrait::ConstantLike>())
353 if (!alreadyObserved.insert(value).second)
356 OpBuilder::InsertionGuard g(rewriter);
357 if (
auto remapped = rewriter.getRemappedValue(value)) {
358 setInsertionPoint(remapped);
359 observeValues.push_back(probeIfSignal(remapped));
361 setInsertionPoint(value);
362 auto type = typeConverter->convertType(value.getType());
363 auto converted = typeConverter->materializeTargetConversion(
364 rewriter, loc, type, value);
365 observeValues.push_back(probeIfSignal(converted));
372 using OpConversionPattern::OpConversionPattern;
375 matchAndRewrite(ProcedureOp op, OpAdaptor adaptor,
376 ConversionPatternRewriter &rewriter)
const override {
378 SmallVector<Value> observedValues;
379 if (op.getKind() == ProcedureKind::AlwaysComb ||
380 op.getKind() == ProcedureKind::AlwaysLatch) {
381 auto setInsertionPoint = [&](Value value) {
382 rewriter.setInsertionPoint(op);
384 getValuesToObserve(&op.getBody(), setInsertionPoint, typeConverter,
385 rewriter, observedValues);
388 auto loc = op.getLoc();
389 if (failed(rewriter.convertRegionTypes(&op.getBody(), *typeConverter)))
394 if (op.getKind() == ProcedureKind::Initial ||
395 op.getKind() == ProcedureKind::Final) {
397 if (op.getKind() == ProcedureKind::Initial)
398 newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
400 newOp = llhd::FinalOp::create(rewriter, loc);
401 auto &body = newOp->getRegion(0);
402 rewriter.inlineRegionBefore(op.getBody(), body, body.end());
404 llvm::make_early_inc_range(body.getOps<ReturnOp>())) {
405 rewriter.setInsertionPoint(returnOp);
406 rewriter.replaceOpWithNewOp<llhd::HaltOp>(returnOp, ValueRange{});
408 rewriter.eraseOp(op);
413 auto newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
418 rewriter.createBlock(&newOp.getBody());
419 auto *block = &op.getBody().front();
420 cf::BranchOp::create(rewriter, loc, block);
421 rewriter.inlineRegionBefore(op.getBody(), newOp.getBody(),
422 newOp.getBody().end());
430 if (op.getKind() == ProcedureKind::AlwaysComb ||
431 op.getKind() == ProcedureKind::AlwaysLatch) {
432 Block *waitBlock = rewriter.createBlock(&newOp.getBody());
433 llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(), observedValues,
434 ValueRange{}, block);
441 for (
auto returnOp :
llvm::make_early_inc_range(newOp.getOps<ReturnOp>())) {
442 rewriter.setInsertionPoint(returnOp);
443 cf::BranchOp::create(rewriter, loc, block);
444 rewriter.eraseOp(returnOp);
447 rewriter.eraseOp(op);
453 using OpConversionPattern::OpConversionPattern;
456 matchAndRewrite(WaitEventOp op, OpAdaptor adaptor,
457 ConversionPatternRewriter &rewriter)
const override {
491 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
497 if (op.getBody().front().empty()) {
500 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
504 auto *waitBlock = rewriter.createBlock(resumeBlock);
505 auto *checkBlock = rewriter.createBlock(resumeBlock);
507 auto loc = op.getLoc();
508 rewriter.setInsertionPoint(op);
509 cf::BranchOp::create(rewriter, loc, waitBlock);
519 SmallVector<Value> valuesBefore;
520 rewriter.setInsertionPointToEnd(waitBlock);
521 auto clonedOp = cast<WaitEventOp>(rewriter.clone(*op));
522 bool allDetectsAreAnyChange =
true;
524 llvm::make_early_inc_range(clonedOp.getOps<DetectEventOp>())) {
525 if (detectOp.getEdge() != Edge::AnyChange || detectOp.getCondition())
526 allDetectsAreAnyChange =
false;
527 valuesBefore.push_back(detectOp.getInput());
528 rewriter.eraseOp(detectOp);
534 SmallVector<Value> observeValues;
535 auto setInsertionPointAfterDef = [&](Value value) {
536 if (
auto *op = value.getDefiningOp())
537 rewriter.setInsertionPointAfter(op);
538 if (
auto arg = dyn_cast<BlockArgument>(value))
539 rewriter.setInsertionPointToStart(value.getParentBlock());
542 getValuesToObserve(&clonedOp.getBody(), setInsertionPointAfterDef,
543 typeConverter, rewriter, observeValues);
548 auto waitOp = llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(),
549 observeValues, ValueRange{}, checkBlock);
550 rewriter.inlineBlockBefore(&clonedOp.getBody().front(), waitOp);
551 rewriter.eraseOp(clonedOp);
555 SmallVector<DetectEventOp> detectOps(op.getBody().getOps<DetectEventOp>());
556 rewriter.inlineBlockBefore(&op.getBody().front(), checkBlock,
558 rewriter.eraseOp(op);
562 auto computeTrigger = [&](Value before, Value after, Edge edge) -> Value {
563 assert(before.getType() == after.getType() &&
564 "mismatched types after clone op");
565 auto beforeType = cast<IntType>(before.getType());
569 if (beforeType.getWidth() != 1 && edge != Edge::AnyChange) {
570 constexpr int LSB = 0;
572 IntType::get(rewriter.getContext(), 1, beforeType.getDomain());
574 moore::ExtractOp::create(rewriter, loc, beforeType, before, LSB);
575 after = moore::ExtractOp::create(rewriter, loc, beforeType, after, LSB);
578 auto intType = rewriter.getIntegerType(beforeType.getWidth());
579 before = typeConverter->materializeTargetConversion(rewriter, loc,
581 after = typeConverter->materializeTargetConversion(rewriter, loc, intType,
584 if (edge == Edge::AnyChange)
585 return comb::ICmpOp::create(rewriter, loc, ICmpPredicate::ne, before,
588 SmallVector<Value> disjuncts;
591 if (edge == Edge::PosEdge || edge == Edge::BothEdges) {
593 comb::XorOp::create(rewriter, loc, before, trueVal,
true);
595 comb::AndOp::create(rewriter, loc, notOldVal, after,
true);
596 disjuncts.push_back(posedge);
599 if (edge == Edge::NegEdge || edge == Edge::BothEdges) {
601 comb::XorOp::create(rewriter, loc, after, trueVal,
true);
603 comb::AndOp::create(rewriter, loc, before, notCurrVal,
true);
604 disjuncts.push_back(posedge);
607 return rewriter.createOrFold<
comb::OrOp>(loc, disjuncts,
true);
614 SmallVector<Value> triggers;
615 for (
auto [detectOp, before] :
llvm::zip(detectOps, valuesBefore)) {
616 if (!allDetectsAreAnyChange) {
617 if (!isa<IntType>(before.getType()))
618 return detectOp->emitError() <<
"requires int operand";
620 rewriter.setInsertionPoint(detectOp);
622 computeTrigger(before, detectOp.getInput(), detectOp.getEdge());
623 if (detectOp.getCondition()) {
624 auto condition = typeConverter->materializeTargetConversion(
625 rewriter, loc, rewriter.getI1Type(), detectOp.getCondition());
627 comb::AndOp::create(rewriter, loc, trigger, condition,
true);
629 triggers.push_back(trigger);
632 rewriter.eraseOp(detectOp);
635 rewriter.setInsertionPointToEnd(checkBlock);
636 if (triggers.empty()) {
641 cf::BranchOp::create(rewriter, loc, resumeBlock);
647 auto triggered = rewriter.createOrFold<
comb::OrOp>(loc, triggers,
true);
648 cf::CondBranchOp::create(rewriter, loc, triggered, resumeBlock,
657static LogicalResult
convert(WaitDelayOp op, WaitDelayOp::Adaptor adaptor,
658 ConversionPatternRewriter &rewriter) {
660 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
661 rewriter.setInsertionPoint(op);
662 rewriter.replaceOpWithNewOp<llhd::WaitOp>(op, ValueRange{},
663 adaptor.getDelay(), ValueRange{},
664 ValueRange{}, resumeBlock);
665 rewriter.setInsertionPointToStart(resumeBlock);
670static LogicalResult
convert(UnreachableOp op, UnreachableOp::Adaptor adaptor,
671 ConversionPatternRewriter &rewriter) {
672 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
681 ConversionPatternRewriter &rewriter) {
683 if (isa<mlir::LLVM::LLVMPointerType>(type))
684 return mlir::LLVM::ZeroOp::create(rewriter, loc, type);
687 if (isa<llhd::TimeType>(type)) {
689 llhd::TimeAttr::get(type.getContext(), 0U, llvm::StringRef(
"ns"), 0, 0);
690 return llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
694 if (
auto floatType = dyn_cast<FloatType>(type)) {
695 auto floatAttr = rewriter.getFloatAttr(floatType, 0.0);
696 return mlir::arith::ConstantOp::create(rewriter, loc, floatAttr);
700 int64_t width = hw::getBitWidth(type);
708 return rewriter.createOrFold<
hw::BitcastOp>(loc, type, constZero);
711struct ClassPropertyRefOpConversion
713 ClassPropertyRefOpConversion(TypeConverter &tc, MLIRContext *ctx,
714 ClassTypeCache &cache)
718 matchAndRewrite(circt::moore::ClassPropertyRefOp op, OpAdaptor adaptor,
719 ConversionPatternRewriter &rewriter)
const override {
720 Location loc = op.getLoc();
721 MLIRContext *ctx = rewriter.getContext();
724 Type dstTy = getTypeConverter()->convertType(op.getPropertyRef().getType());
726 Value instRef = adaptor.getInstance();
730 cast<circt::moore::ClassHandleType>(op.getInstance().getType());
731 SymbolRefAttr classSym = classRefTy.getClassSym();
732 ModuleOp mod = op->getParentOfType<ModuleOp>();
733 if (failed(resolveClassStructBody(mod, classSym, *typeConverter, cache)))
734 return rewriter.notifyMatchFailure(op,
735 "Could not resolve class struct for " +
736 classSym.getRootReference().str());
738 auto structInfo = cache.getStructInfo(classSym);
739 assert(structInfo &&
"class struct info must exist");
740 auto structTy = structInfo->classBody;
743 auto propSym = op.getProperty();
744 auto pathOpt = structInfo->getFieldPath(propSym);
746 return rewriter.notifyMatchFailure(op,
747 "no GEP path for property " + propSym);
749 auto i32Ty = IntegerType::get(ctx, 32);
750 SmallVector<Value> idxVals;
751 for (
unsigned idx : *pathOpt)
752 idxVals.push_back(LLVM::ConstantOp::create(
753 rewriter, loc, i32Ty, rewriter.getI32IntegerAttr(idx)));
756 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
758 LLVM::GEPOp::create(rewriter, loc, ptrTy, structTy, instRef, idxVals);
761 Value fieldRef = UnrealizedConversionCastOp::create(rewriter, loc, dstTy,
765 rewriter.replaceOp(op, fieldRef);
770 ClassTypeCache &cache;
774 using OpConversionPattern::OpConversionPattern;
777 matchAndRewrite(ClassUpcastOp op, OpAdaptor adaptor,
778 ConversionPatternRewriter &rewriter)
const override {
780 Type dstTy = getTypeConverter()->convertType(op.getResult().getType());
781 Type srcTy = adaptor.getInstance().getType();
784 return rewriter.notifyMatchFailure(op,
"failed to convert result type");
787 if (dstTy == srcTy && isa<LLVM::LLVMPointerType>(srcTy)) {
788 rewriter.replaceOp(op, adaptor.getInstance());
791 return rewriter.notifyMatchFailure(
792 op,
"Upcast applied to non-opaque pointers!");
798 ClassNewOpConversion(TypeConverter &tc, MLIRContext *ctx,
799 ClassTypeCache &cache)
803 matchAndRewrite(ClassNewOp op, OpAdaptor adaptor,
804 ConversionPatternRewriter &rewriter)
const override {
805 Location loc = op.getLoc();
806 MLIRContext *ctx = rewriter.getContext();
808 auto handleTy = cast<ClassHandleType>(op.getResult().getType());
809 auto sym = handleTy.getClassSym();
811 ModuleOp mod = op->getParentOfType<ModuleOp>();
813 if (failed(resolveClassStructBody(mod, sym, *typeConverter, cache)))
814 return op.emitError() <<
"Could not resolve class struct for " << sym;
816 auto structTy = cache.getStructInfo(sym)->classBody;
820 uint64_t byteSize = dl.getTypeSize(structTy);
821 auto i64Ty = IntegerType::get(ctx, 64);
822 auto cSize = LLVM::ConstantOp::create(rewriter, loc, i64Ty,
823 rewriter.getI64IntegerAttr(byteSize));
826 auto mallocFn = getOrCreateMalloc(mod, rewriter);
827 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
829 LLVM::CallOp::create(rewriter, loc, TypeRange{ptrTy},
830 SymbolRefAttr::get(mallocFn), ValueRange{cSize});
834 rewriter.replaceOp(op, call.getResult());
839 ClassTypeCache &cache;
843 ClassDeclOpConversion(TypeConverter &tc, MLIRContext *ctx,
844 ClassTypeCache &cache)
848 matchAndRewrite(ClassDeclOp op, OpAdaptor,
849 ConversionPatternRewriter &rewriter)
const override {
851 if (failed(resolveClassStructBody(op, *typeConverter, cache)))
854 rewriter.eraseOp(op);
859 ClassTypeCache &cache;
863 using OpConversionPattern::OpConversionPattern;
866 matchAndRewrite(VariableOp op, OpAdaptor adaptor,
867 ConversionPatternRewriter &rewriter)
const override {
868 auto loc = op.getLoc();
869 auto resultType = typeConverter->convertType(op.getResult().getType());
871 return rewriter.notifyMatchFailure(op.getLoc(),
"invalid variable type");
874 Value init = adaptor.getInitial();
876 auto elementType = cast<llhd::RefType>(resultType).getNestedType();
882 rewriter.replaceOpWithNewOp<llhd::SignalOp>(op, resultType,
883 op.getNameAttr(), init);
889 using OpConversionPattern::OpConversionPattern;
892 matchAndRewrite(NetOp op, OpAdaptor adaptor,
893 ConversionPatternRewriter &rewriter)
const override {
894 auto loc = op.getLoc();
895 if (op.getKind() != NetKind::Wire)
896 return rewriter.notifyMatchFailure(loc,
"only wire nets supported");
898 auto resultType = typeConverter->convertType(op.getResult().getType());
900 return rewriter.notifyMatchFailure(loc,
"invalid net type");
904 auto elementType = cast<llhd::RefType>(resultType).getNestedType();
912 auto signal = rewriter.replaceOpWithNewOp<llhd::SignalOp>(
913 op, resultType, op.getNameAttr(), init);
915 if (
auto assignedValue = adaptor.getAssignment()) {
916 auto timeAttr = llhd::TimeAttr::get(resultType.getContext(), 0U,
917 llvm::StringRef(
"ns"), 0, 1);
918 auto time = llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
919 llhd::DriveOp::create(rewriter, loc, signal, assignedValue, time,
932 using OpConversionPattern::OpConversionPattern;
935 matchAndRewrite(ConstantOp op, OpAdaptor adaptor,
936 ConversionPatternRewriter &rewriter)
const override {
938 auto value = op.getValue().toAPInt(
false);
939 auto type = rewriter.getIntegerType(value.getBitWidth());
941 op, type, rewriter.getIntegerAttr(type, value));
947 using OpConversionPattern::OpConversionPattern;
950 matchAndRewrite(ConstantRealOp op, OpAdaptor adaptor,
951 ConversionPatternRewriter &rewriter)
const override {
952 rewriter.replaceOpWithNewOp<arith::ConstantOp>(op, op.getValueAttr());
958 using OpConversionPattern::OpConversionPattern;
961 matchAndRewrite(ConstantTimeOp op, OpAdaptor adaptor,
962 ConversionPatternRewriter &rewriter)
const override {
963 rewriter.replaceOpWithNewOp<llhd::ConstantTimeOp>(
964 op, llhd::TimeAttr::get(op->getContext(), op.getValue(),
965 StringRef(
"fs"), 0, 0));
971 using OpConversionPattern::OpConversionPattern;
973 matchAndRewrite(moore::ConstantStringOp op, OpAdaptor adaptor,
974 ConversionPatternRewriter &rewriter)
const override {
975 const auto resultType =
976 typeConverter->convertType(op.getResult().getType());
977 const auto intType = mlir::cast<IntegerType>(resultType);
979 const auto str = op.getValue();
980 const unsigned byteWidth = intType.getWidth();
981 APInt value(byteWidth, 0);
984 const size_t maxChars =
985 std::min(str.size(),
static_cast<size_t>(byteWidth / 8));
986 for (
size_t i = 0; i < maxChars; i++) {
987 const size_t pos = str.size() - 1 - i;
988 const auto asciiChar =
static_cast<uint8_t
>(str[pos]);
989 value |= APInt(byteWidth, asciiChar) << (8 * i);
993 op, resultType, rewriter.getIntegerAttr(resultType, value));
999 using OpConversionPattern::OpConversionPattern;
1001 matchAndRewrite(ConcatOp op, OpAdaptor adaptor,
1002 ConversionPatternRewriter &rewriter)
const override {
1003 rewriter.replaceOpWithNewOp<
comb::ConcatOp>(op, adaptor.getValues());
1009 using OpConversionPattern::OpConversionPattern;
1011 matchAndRewrite(ReplicateOp op, OpAdaptor adaptor,
1012 ConversionPatternRewriter &rewriter)
const override {
1013 Type resultType = typeConverter->convertType(op.getResult().getType());
1015 rewriter.replaceOpWithNewOp<comb::ReplicateOp>(op, resultType,
1016 adaptor.getValue());
1022 using OpConversionPattern::OpConversionPattern;
1025 matchAndRewrite(ExtractOp op, OpAdaptor adaptor,
1026 ConversionPatternRewriter &rewriter)
const override {
1029 Type resultType = typeConverter->convertType(op.getResult().getType());
1030 Type inputType = adaptor.getInput().getType();
1031 int32_t low = adaptor.getLowBit();
1033 if (isa<IntegerType>(inputType)) {
1034 int32_t inputWidth = inputType.getIntOrFloatBitWidth();
1035 int32_t resultWidth = hw::getBitWidth(resultType);
1036 int32_t high = low + resultWidth;
1038 SmallVector<Value> toConcat;
1041 rewriter, op.getLoc(), APInt(std::min(-low, resultWidth), 0)));
1043 if (low < inputWidth && high > 0) {
1044 int32_t lowIdx = std::max(low, 0);
1047 rewriter.getIntegerType(
1048 std::min(resultWidth, std::min(high, inputWidth) - lowIdx)),
1049 adaptor.getInput(), lowIdx);
1050 toConcat.push_back(middle);
1053 int32_t diff = high - inputWidth;
1057 toConcat.push_back(val);
1062 rewriter.replaceOp(op,
concat);
1066 if (
auto arrTy = dyn_cast<hw::ArrayType>(inputType)) {
1067 int32_t width = llvm::Log2_64_Ceil(arrTy.getNumElements());
1068 int32_t inputWidth = arrTy.getNumElements();
1070 if (
auto resArrTy = dyn_cast<hw::ArrayType>(resultType);
1071 resArrTy && resArrTy != arrTy.getElementType()) {
1072 int32_t elementWidth = hw::getBitWidth(arrTy.getElementType());
1073 if (elementWidth < 0)
1076 int32_t high = low + resArrTy.getNumElements();
1077 int32_t resWidth = resArrTy.getNumElements();
1079 SmallVector<Value> toConcat;
1082 rewriter, op.getLoc(),
1083 APInt(std::min((-low) * elementWidth, resWidth * elementWidth),
1086 op.getLoc(), hw::ArrayType::get(arrTy.getElementType(), -low),
1088 toConcat.push_back(res);
1091 if (low < inputWidth && high > 0) {
1092 int32_t lowIdx = std::max(0, low);
1094 rewriter, op.getLoc(), rewriter.getIntegerType(width), lowIdx);
1098 arrTy.getElementType(),
1099 std::min(resWidth, std::min(inputWidth, high) - lowIdx)),
1100 adaptor.getInput(), lowIdxVal);
1101 toConcat.push_back(middle);
1104 int32_t diff = high - inputWidth;
1107 rewriter, op.getLoc(), APInt(diff * elementWidth, 0));
1109 rewriter, op.getLoc(),
1110 hw::ArrayType::get(arrTy.getElementType(), diff), constZero);
1111 toConcat.push_back(val);
1116 rewriter.replaceOp(op,
concat);
1121 if (low < 0 || low >= inputWidth) {
1122 int32_t bw = hw::getBitWidth(resultType);
1128 rewriter.createOrFold<
hw::BitcastOp>(op.getLoc(), resultType, val);
1129 rewriter.replaceOp(op, bitcast);
1134 rewriter.getIntegerType(width),
1135 adaptor.getLowBit());
1136 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(), idx);
1145 using OpConversionPattern::OpConversionPattern;
1148 matchAndRewrite(ExtractRefOp op, OpAdaptor adaptor,
1149 ConversionPatternRewriter &rewriter)
const override {
1151 Type resultType = typeConverter->convertType(op.getResult().getType());
1153 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1155 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1156 int64_t width = hw::getBitWidth(inputType);
1161 rewriter, op.getLoc(),
1162 rewriter.getIntegerType(llvm::Log2_64_Ceil(width)),
1163 adaptor.getLowBit());
1164 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1165 op, resultType, adaptor.getInput(), lowBit);
1169 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1171 rewriter, op.getLoc(),
1172 rewriter.getIntegerType(llvm::Log2_64_Ceil(arrType.getNumElements())),
1173 adaptor.getLowBit());
1177 if (arrType.getElementType() !=
1178 cast<llhd::RefType>(resultType).getNestedType()) {
1179 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1180 op, resultType, adaptor.getInput(), lowBit);
1184 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1194 using OpConversionPattern::OpConversionPattern;
1197 matchAndRewrite(DynExtractOp op, OpAdaptor adaptor,
1198 ConversionPatternRewriter &rewriter)
const override {
1199 Type resultType = typeConverter->convertType(op.getResult().getType());
1200 Type inputType = adaptor.getInput().getType();
1202 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1203 Value amount = adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1204 intType.getWidth(), op->getLoc());
1205 Value value = comb::ShrUOp::create(rewriter, op->getLoc(),
1206 adaptor.getInput(), amount);
1208 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, resultType, value, 0);
1212 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1213 unsigned idxWidth = llvm::Log2_64_Ceil(arrType.getNumElements());
1214 Value idx = adjustIntegerWidth(rewriter, adaptor.getLowBit(), idxWidth,
1217 bool isSingleElementExtract = arrType.getElementType() == resultType;
1219 if (isSingleElementExtract)
1220 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(),
1224 adaptor.getInput(), idx);
1234 using OpConversionPattern::OpConversionPattern;
1237 matchAndRewrite(DynExtractRefOp op, OpAdaptor adaptor,
1238 ConversionPatternRewriter &rewriter)
const override {
1240 Type resultType = typeConverter->convertType(op.getResult().getType());
1242 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1244 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1245 int64_t width = hw::getBitWidth(inputType);
1250 adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1251 llvm::Log2_64_Ceil(width), op->getLoc());
1252 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1253 op, resultType, adaptor.getInput(), amount);
1257 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1258 Value idx = adjustIntegerWidth(
1259 rewriter, adaptor.getLowBit(),
1260 llvm::Log2_64_Ceil(arrType.getNumElements()), op->getLoc());
1262 auto resultNestedType = cast<llhd::RefType>(resultType).getNestedType();
1263 bool isSingleElementExtract =
1264 arrType.getElementType() == resultNestedType;
1266 if (isSingleElementExtract)
1267 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1270 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1271 op, resultType, adaptor.getInput(), idx);
1281 using OpConversionPattern::OpConversionPattern;
1284 matchAndRewrite(ArrayCreateOp op, OpAdaptor adaptor,
1285 ConversionPatternRewriter &rewriter)
const override {
1286 Type resultType = typeConverter->convertType(op.getResult().getType());
1288 adaptor.getElements());
1294 using OpConversionPattern::OpConversionPattern;
1297 matchAndRewrite(StructCreateOp op, OpAdaptor adaptor,
1298 ConversionPatternRewriter &rewriter)
const override {
1299 Type resultType = typeConverter->convertType(op.getResult().getType());
1301 adaptor.getFields());
1307 using OpConversionPattern::OpConversionPattern;
1310 matchAndRewrite(StructExtractOp op, OpAdaptor adaptor,
1311 ConversionPatternRewriter &rewriter)
const override {
1313 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1318struct StructExtractRefOpConversion
1320 using OpConversionPattern::OpConversionPattern;
1323 matchAndRewrite(StructExtractRefOp op, OpAdaptor adaptor,
1324 ConversionPatternRewriter &rewriter)
const override {
1325 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1326 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1332 using OpConversionPattern::OpConversionPattern;
1334 matchAndRewrite(ReduceAndOp op, OpAdaptor adaptor,
1335 ConversionPatternRewriter &rewriter)
const override {
1336 Type resultType = typeConverter->convertType(op.getInput().getType());
1339 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::eq,
1340 adaptor.getInput(), max);
1346 using OpConversionPattern::OpConversionPattern;
1348 matchAndRewrite(ReduceOrOp op, OpAdaptor adaptor,
1349 ConversionPatternRewriter &rewriter)
const override {
1350 Type resultType = typeConverter->convertType(op.getInput().getType());
1353 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1354 adaptor.getInput(), zero);
1360 using OpConversionPattern::OpConversionPattern;
1362 matchAndRewrite(ReduceXorOp op, OpAdaptor adaptor,
1363 ConversionPatternRewriter &rewriter)
const override {
1365 rewriter.replaceOpWithNewOp<
comb::ParityOp>(op, adaptor.getInput());
1371 using OpConversionPattern::OpConversionPattern;
1373 matchAndRewrite(BoolCastOp op, OpAdaptor adaptor,
1374 ConversionPatternRewriter &rewriter)
const override {
1375 Type resultType = typeConverter->convertType(op.getInput().getType());
1376 if (isa_and_nonnull<IntegerType>(resultType)) {
1379 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1380 adaptor.getInput(), zero);
1388 using OpConversionPattern::OpConversionPattern;
1390 matchAndRewrite(NotOp op, OpAdaptor adaptor,
1391 ConversionPatternRewriter &rewriter)
const override {
1393 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1396 rewriter.replaceOpWithNewOp<
comb::XorOp>(op, adaptor.getInput(), max);
1402 using OpConversionPattern::OpConversionPattern;
1404 matchAndRewrite(NegOp op, OpAdaptor adaptor,
1405 ConversionPatternRewriter &rewriter)
const override {
1407 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1410 rewriter.replaceOpWithNewOp<
comb::SubOp>(op, zero, adaptor.getInput());
1415template <
typename SourceOp,
typename TargetOp>
1418 using OpAdaptor =
typename SourceOp::Adaptor;
1421 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1422 ConversionPatternRewriter &rewriter)
const override {
1423 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1424 adaptor.getRhs(),
false);
1429template <
typename SourceOp, ICmpPredicate pred>
1432 using OpAdaptor =
typename SourceOp::Adaptor;
1435 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1436 ConversionPatternRewriter &rewriter)
const override {
1438 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1440 rewriter.replaceOpWithNewOp<comb::ICmpOp>(
1441 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
1446template <
typename SourceOp,
bool withoutX>
1449 using OpAdaptor =
typename SourceOp::Adaptor;
1452 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1453 ConversionPatternRewriter &rewriter)
const override {
1459 unsigned bitWidth = op.getLhs().getType().getWidth();
1460 auto ignoredBits = APInt::getZero(bitWidth);
1461 auto detectIgnoredBits = [&](Value value) {
1462 auto constOp = value.getDefiningOp<ConstantOp>();
1465 auto constValue = constOp.getValue();
1467 ignoredBits |= constValue.getZBits();
1469 ignoredBits |= constValue.getUnknownBits();
1471 detectIgnoredBits(op.getLhs());
1472 detectIgnoredBits(op.getRhs());
1476 Value lhs = adaptor.getLhs();
1477 Value rhs = adaptor.getRhs();
1478 if (!ignoredBits.isZero()) {
1479 ignoredBits.flipAllBits();
1481 lhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), lhs, maskOp);
1482 rhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), rhs, maskOp);
1485 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, ICmpPredicate::ceq, lhs, rhs);
1495 using OpConversionPattern::OpConversionPattern;
1498 matchAndRewrite(ConversionOp op, OpAdaptor adaptor,
1499 ConversionPatternRewriter &rewriter)
const override {
1500 Location loc = op.getLoc();
1501 Type resultType = typeConverter->convertType(op.getResult().getType());
1503 op.emitError(
"conversion result type is not currently supported");
1506 int64_t inputBw = hw::getBitWidth(adaptor.getInput().getType());
1507 int64_t resultBw = hw::getBitWidth(resultType);
1508 if (inputBw == -1 || resultBw == -1)
1512 loc, rewriter.getIntegerType(inputBw), adaptor.getInput());
1513 Value amount = adjustIntegerWidth(rewriter, input, resultBw, loc);
1516 rewriter.createOrFold<
hw::BitcastOp>(loc, resultType, amount);
1517 rewriter.replaceOp(op, result);
1522template <
typename SourceOp>
1525 using OpAdaptor =
typename SourceOp::Adaptor;
1526 using ConversionPattern::typeConverter;
1529 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1530 ConversionPatternRewriter &rewriter)
const override {
1531 auto type = typeConverter->convertType(op.getResult().getType());
1532 if (type == adaptor.getInput().getType())
1533 rewriter.replaceOp(op, adaptor.getInput());
1535 rewriter.replaceOpWithNewOp<
hw::BitcastOp>(op, type, adaptor.getInput());
1541 using OpConversionPattern::OpConversionPattern;
1544 matchAndRewrite(TruncOp op, OpAdaptor adaptor,
1545 ConversionPatternRewriter &rewriter)
const override {
1546 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, adaptor.getInput(), 0,
1547 op.getType().getWidth());
1553 using OpConversionPattern::OpConversionPattern;
1556 matchAndRewrite(ZExtOp op, OpAdaptor adaptor,
1557 ConversionPatternRewriter &rewriter)
const override {
1558 auto targetWidth = op.getType().getWidth();
1559 auto inputWidth = op.getInput().getType().getWidth();
1562 rewriter, op.getLoc(),
1563 rewriter.getIntegerType(targetWidth - inputWidth), 0);
1566 op, ValueRange{zeroExt, adaptor.getInput()});
1572 using OpConversionPattern::OpConversionPattern;
1575 matchAndRewrite(SExtOp op, OpAdaptor adaptor,
1576 ConversionPatternRewriter &rewriter)
const override {
1577 auto type = typeConverter->convertType(op.getType());
1579 comb::createOrFoldSExt(op.getLoc(), adaptor.getInput(), type, rewriter);
1580 rewriter.replaceOp(op, value);
1590 using OpConversionPattern::OpConversionPattern;
1593 matchAndRewrite(hw::InstanceOp op, OpAdaptor adaptor,
1594 ConversionPatternRewriter &rewriter)
const override {
1595 SmallVector<Type> convResTypes;
1596 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1599 rewriter.replaceOpWithNewOp<hw::InstanceOp>(
1600 op, convResTypes, op.getInstanceName(), op.getModuleName(),
1601 adaptor.getOperands(), op.getArgNames(),
1602 op.getResultNames(),
1603 rewriter.getArrayAttr({}),
nullptr);
1610 using OpConversionPattern::OpConversionPattern;
1613 matchAndRewrite(func::ReturnOp op, OpAdaptor adaptor,
1614 ConversionPatternRewriter &rewriter)
const override {
1615 rewriter.replaceOpWithNewOp<func::ReturnOp>(op, adaptor.getOperands());
1621 using OpConversionPattern::OpConversionPattern;
1624 matchAndRewrite(func::CallOp op, OpAdaptor adaptor,
1625 ConversionPatternRewriter &rewriter)
const override {
1626 SmallVector<Type> convResTypes;
1627 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1629 rewriter.replaceOpWithNewOp<func::CallOp>(
1630 op, adaptor.getCallee(), convResTypes, adaptor.getOperands());
1635struct UnrealizedConversionCastConversion
1637 using OpConversionPattern::OpConversionPattern;
1640 matchAndRewrite(UnrealizedConversionCastOp op, OpAdaptor adaptor,
1641 ConversionPatternRewriter &rewriter)
const override {
1642 SmallVector<Type> convResTypes;
1643 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1648 if (convResTypes == adaptor.getOperands().getTypes()) {
1649 rewriter.replaceOp(op, adaptor.getOperands());
1653 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
1654 op, convResTypes, adaptor.getOperands());
1660 using OpConversionPattern::OpConversionPattern;
1663 matchAndRewrite(ShlOp op, OpAdaptor adaptor,
1664 ConversionPatternRewriter &rewriter)
const override {
1665 Type resultType = typeConverter->convertType(op.getResult().getType());
1669 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1670 resultType.getIntOrFloatBitWidth(), op->getLoc());
1671 rewriter.replaceOpWithNewOp<
comb::ShlOp>(op, resultType, adaptor.getValue(),
1678 using OpConversionPattern::OpConversionPattern;
1681 matchAndRewrite(ShrOp op, OpAdaptor adaptor,
1682 ConversionPatternRewriter &rewriter)
const override {
1683 Type resultType = typeConverter->convertType(op.getResult().getType());
1687 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1688 resultType.getIntOrFloatBitWidth(), op->getLoc());
1690 op, resultType, adaptor.getValue(), amount,
false);
1696 using OpConversionPattern::OpConversionPattern;
1699 matchAndRewrite(PowUOp op, OpAdaptor adaptor,
1700 ConversionPatternRewriter &rewriter)
const override {
1701 Type resultType = typeConverter->convertType(op.getResult().getType());
1703 Location loc = op->getLoc();
1708 auto lhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getLhs());
1709 auto rhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getRhs());
1712 auto pow = mlir::math::IPowIOp::create(rewriter, loc, lhs, rhs);
1720 using OpConversionPattern::OpConversionPattern;
1723 matchAndRewrite(PowSOp op, OpAdaptor adaptor,
1724 ConversionPatternRewriter &rewriter)
const override {
1725 Type resultType = typeConverter->convertType(op.getResult().getType());
1729 rewriter.replaceOpWithNewOp<mlir::math::IPowIOp>(
1730 op, resultType, adaptor.getLhs(), adaptor.getRhs());
1736 using OpConversionPattern::OpConversionPattern;
1739 matchAndRewrite(AShrOp op, OpAdaptor adaptor,
1740 ConversionPatternRewriter &rewriter)
const override {
1741 Type resultType = typeConverter->convertType(op.getResult().getType());
1745 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1746 resultType.getIntOrFloatBitWidth(), op->getLoc());
1748 op, resultType, adaptor.getValue(), amount,
false);
1754 using OpConversionPattern::OpConversionPattern;
1757 matchAndRewrite(ReadOp op, OpAdaptor adaptor,
1758 ConversionPatternRewriter &rewriter)
const override {
1759 rewriter.replaceOpWithNewOp<llhd::ProbeOp>(op, adaptor.getInput());
1764struct AssignedVariableOpConversion
1766 using OpConversionPattern::OpConversionPattern;
1769 matchAndRewrite(AssignedVariableOp op, OpAdaptor adaptor,
1770 ConversionPatternRewriter &rewriter)
const override {
1771 rewriter.replaceOpWithNewOp<hw::WireOp>(op, adaptor.getInput(),
1772 adaptor.getNameAttr());
1777template <
typename OpTy>
1780 using OpAdaptor =
typename OpTy::Adaptor;
1783 matchAndRewrite(OpTy op, OpAdaptor adaptor,
1784 ConversionPatternRewriter &rewriter)
const override {
1787 if constexpr (std::is_same_v<OpTy, ContinuousAssignOp> ||
1788 std::is_same_v<OpTy, BlockingAssignOp>) {
1790 delay = llhd::ConstantTimeOp::create(
1791 rewriter, op->getLoc(),
1792 llhd::TimeAttr::get(op->getContext(), 0U,
"ns", 0, 1));
1793 }
else if constexpr (std::is_same_v<OpTy, NonBlockingAssignOp>) {
1795 delay = llhd::ConstantTimeOp::create(
1796 rewriter, op->getLoc(),
1797 llhd::TimeAttr::get(op->getContext(), 0U,
"ns", 1, 0));
1800 delay = adaptor.getDelay();
1803 rewriter.replaceOpWithNewOp<llhd::DriveOp>(
1804 op, adaptor.getDst(), adaptor.getSrc(), delay, Value{});
1810 using OpConversionPattern::OpConversionPattern;
1813 matchAndRewrite(ConditionalOp op, OpAdaptor adaptor,
1814 ConversionPatternRewriter &rewriter)
const override {
1819 auto type = typeConverter->convertType(op.getType());
1821 auto hasNoWriteEffect = [](Region ®ion) {
1822 auto result = region.walk([](Operation *operation) {
1823 if (
auto memOp = dyn_cast<MemoryEffectOpInterface>(operation))
1824 if (!memOp.hasEffect<MemoryEffects::Write>() &&
1825 !memOp.hasEffect<MemoryEffects::Free>())
1826 return WalkResult::advance();
1828 if (operation->hasTrait<OpTrait::HasRecursiveMemoryEffects>())
1829 return WalkResult::advance();
1831 return WalkResult::interrupt();
1833 return !result.wasInterrupted();
1836 if (hasNoWriteEffect(op.getTrueRegion()) &&
1837 hasNoWriteEffect(op.getFalseRegion())) {
1838 Operation *trueTerm = op.getTrueRegion().front().getTerminator();
1839 Operation *falseTerm = op.getFalseRegion().front().getTerminator();
1841 rewriter.inlineBlockBefore(&op.getTrueRegion().front(), op);
1842 rewriter.inlineBlockBefore(&op.getFalseRegion().front(), op);
1844 Value convTrueVal = typeConverter->materializeTargetConversion(
1845 rewriter, op.getLoc(), type, trueTerm->getOperand(0));
1846 Value convFalseVal = typeConverter->materializeTargetConversion(
1847 rewriter, op.getLoc(), type, falseTerm->getOperand(0));
1849 rewriter.eraseOp(trueTerm);
1850 rewriter.eraseOp(falseTerm);
1852 rewriter.replaceOpWithNewOp<
comb::MuxOp>(op, adaptor.getCondition(),
1853 convTrueVal, convFalseVal);
1858 scf::IfOp::create(rewriter, op.getLoc(), type, adaptor.getCondition());
1859 rewriter.inlineRegionBefore(op.getTrueRegion(), ifOp.getThenRegion(),
1860 ifOp.getThenRegion().end());
1861 rewriter.inlineRegionBefore(op.getFalseRegion(), ifOp.getElseRegion(),
1862 ifOp.getElseRegion().end());
1863 rewriter.replaceOp(op, ifOp);
1869 using OpConversionPattern::OpConversionPattern;
1872 matchAndRewrite(YieldOp op, OpAdaptor adaptor,
1873 ConversionPatternRewriter &rewriter)
const override {
1874 rewriter.replaceOpWithNewOp<scf::YieldOp>(op, adaptor.getResult());
1879template <
typename SourceOp>
1882 using OpAdaptor =
typename SourceOp::Adaptor;
1885 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1886 ConversionPatternRewriter &rewriter)
const override {
1887 rewriter.modifyOpInPlace(op,
1888 [&]() { op->setOperands(adaptor.getOperands()); });
1893template <
typename MooreOpTy,
typename VerifOpTy>
1896 using OpAdaptor =
typename MooreOpTy::Adaptor;
1899 matchAndRewrite(MooreOpTy op, OpAdaptor adaptor,
1900 ConversionPatternRewriter &rewriter)
const override {
1902 op.getLabel().has_value()
1903 ? StringAttr::get(op->getContext(), op.getLabel().value())
1904 : StringAttr::
get(op->getContext());
1905 rewriter.replaceOpWithNewOp<VerifOpTy>(op, adaptor.getCond(), mlir::Value(),
1916 using OpConversionPattern::OpConversionPattern;
1919 matchAndRewrite(FormatLiteralOp op, OpAdaptor adaptor,
1920 ConversionPatternRewriter &rewriter)
const override {
1921 rewriter.replaceOpWithNewOp<sim::FormatLiteralOp>(op, adaptor.getLiteral());
1927 using OpConversionPattern::OpConversionPattern;
1930 matchAndRewrite(FormatConcatOp op, OpAdaptor adaptor,
1931 ConversionPatternRewriter &rewriter)
const override {
1932 rewriter.replaceOpWithNewOp<sim::FormatStringConcatOp>(op,
1933 adaptor.getInputs());
1939 using OpConversionPattern::OpConversionPattern;
1942 matchAndRewrite(FormatIntOp op, OpAdaptor adaptor,
1943 ConversionPatternRewriter &rewriter)
const override {
1945 switch (op.getFormat()) {
1946 case IntFormat::Decimal:
1947 rewriter.replaceOpWithNewOp<sim::FormatDecOp>(op, adaptor.getValue());
1949 case IntFormat::Binary:
1950 rewriter.replaceOpWithNewOp<sim::FormatBinOp>(op, adaptor.getValue());
1952 case IntFormat::HexLower:
1953 case IntFormat::HexUpper:
1954 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(op, adaptor.getValue());
1957 return rewriter.notifyMatchFailure(op,
"unsupported int format");
1963 using OpConversionPattern::OpConversionPattern;
1966 matchAndRewrite(DisplayBIOp op, OpAdaptor adaptor,
1967 ConversionPatternRewriter &rewriter)
const override {
1968 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(
1969 op, adaptor.getMessage());
1981static LogicalResult
convert(StopBIOp op, StopBIOp::Adaptor adaptor,
1982 ConversionPatternRewriter &rewriter) {
1983 rewriter.replaceOpWithNewOp<sim::PauseOp>(op,
false);
1988static LogicalResult
convert(FinishBIOp op, FinishBIOp::Adaptor adaptor,
1989 ConversionPatternRewriter &rewriter) {
1990 rewriter.replaceOpWithNewOp<sim::TerminateOp>(op, op.getExitCode() == 0,
1996static LogicalResult
convert(SeverityBIOp op, SeverityBIOp::Adaptor adaptor,
1997 ConversionPatternRewriter &rewriter) {
1999 std::string severityString;
2001 switch (op.getSeverity()) {
2002 case (Severity::Fatal):
2003 severityString =
"Fatal: ";
2005 case (Severity::Error):
2006 severityString =
"Error: ";
2008 case (Severity::Warning):
2009 severityString =
"Warning: ";
2016 sim::FormatLiteralOp::create(rewriter, op.getLoc(), severityString);
2017 auto message = sim::FormatStringConcatOp::create(
2018 rewriter, op.getLoc(), ValueRange{prefix, adaptor.getMessage()});
2019 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(op, message);
2025 FinishMessageBIOp::Adaptor adaptor,
2026 ConversionPatternRewriter &rewriter) {
2028 rewriter.eraseOp(op);
2037 const TypeConverter &converter) {
2038 target.addIllegalDialect<MooreDialect>();
2039 target.addLegalDialect<comb::CombDialect>();
2040 target.addLegalDialect<hw::HWDialect>();
2041 target.addLegalDialect<seq::SeqDialect>();
2042 target.addLegalDialect<llhd::LLHDDialect>();
2043 target.addLegalDialect<ltl::LTLDialect>();
2044 target.addLegalDialect<mlir::BuiltinDialect>();
2045 target.addLegalDialect<mlir::math::MathDialect>();
2046 target.addLegalDialect<sim::SimDialect>();
2047 target.addLegalDialect<mlir::LLVM::LLVMDialect>();
2048 target.addLegalDialect<verif::VerifDialect>();
2049 target.addLegalDialect<arith::ArithDialect>();
2051 target.addLegalOp<debug::ScopeOp>();
2053 target.addDynamicallyLegalOp<scf::YieldOp, func::CallOp, func::ReturnOp,
2054 UnrealizedConversionCastOp, hw::OutputOp,
2055 hw::InstanceOp, debug::ArrayOp, debug::StructOp,
2057 [&](Operation *op) {
return converter.isLegal(op); });
2059 target.addDynamicallyLegalOp<scf::IfOp, scf::ForOp, scf::ExecuteRegionOp,
2060 scf::WhileOp, scf::ForallOp>([&](Operation *op) {
2061 return converter.isLegal(op) && !op->getParentOfType<llhd::ProcessOp>();
2064 target.addDynamicallyLegalOp<func::FuncOp>([&](func::FuncOp op) {
2065 return converter.isSignatureLegal(op.getFunctionType());
2069 return converter.isSignatureLegal(op.getModuleType().getFuncType()) &&
2070 converter.isLegal(&op.getBody());
2075 typeConverter.addConversion([&](IntType type) {
2076 return IntegerType::get(type.getContext(), type.getWidth());
2079 typeConverter.addConversion([&](RealType type) -> mlir::Type {
2080 MLIRContext *ctx = type.getContext();
2081 switch (type.getWidth()) {
2082 case moore::RealWidth::f32:
2083 return mlir::Float32Type::get(ctx);
2084 case moore::RealWidth::f64:
2085 return mlir::Float64Type::get(ctx);
2089 typeConverter.addConversion(
2090 [&](TimeType type) {
return llhd::TimeType::get(type.getContext()); });
2092 typeConverter.addConversion([&](FormatStringType type) {
2093 return sim::FormatStringType::get(type.getContext());
2096 typeConverter.addConversion([&](ArrayType type) -> std::optional<Type> {
2097 if (
auto elementType = typeConverter.convertType(type.getElementType()))
2098 return hw::ArrayType::get(
elementType, type.getSize());
2105 typeConverter.addConversion(
2106 [&](UnpackedArrayType type) -> std::optional<Type> {
2107 if (
auto elementType = typeConverter.convertType(type.getElementType()))
2108 return hw::ArrayType::get(
elementType, type.getSize());
2112 typeConverter.addConversion([&](StructType type) -> std::optional<Type> {
2113 SmallVector<hw::StructType::FieldInfo> fields;
2114 for (
auto field : type.getMembers()) {
2115 hw::StructType::FieldInfo info;
2116 info.type = typeConverter.convertType(field.type);
2119 info.name = field.name;
2120 fields.push_back(info);
2122 return hw::StructType::get(type.getContext(), fields);
2130 typeConverter.addConversion(
2131 [&](UnpackedStructType type) -> std::optional<Type> {
2132 SmallVector<hw::StructType::FieldInfo> fields;
2133 for (
auto field : type.getMembers()) {
2134 hw::StructType::FieldInfo info;
2135 info.type = typeConverter.convertType(field.type);
2138 info.name = field.name;
2139 fields.push_back(info);
2141 return hw::StructType::get(type.getContext(), fields);
2145 typeConverter.addConversion([&](ChandleType type) -> std::optional<Type> {
2146 return LLVM::LLVMPointerType::get(type.getContext());
2150 typeConverter.addConversion(
2151 [](LLVM::LLVMPointerType t) -> std::optional<Type> {
return t; });
2154 typeConverter.addConversion([&](ClassHandleType type) -> std::optional<Type> {
2155 return LLVM::LLVMPointerType::get(type.getContext());
2158 typeConverter.addConversion([&](RefType type) -> std::optional<Type> {
2159 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
2160 return llhd::RefType::get(innerType);
2165 typeConverter.addConversion([](IntegerType type) {
return type; });
2166 typeConverter.addConversion([](llhd::TimeType type) {
return type; });
2167 typeConverter.addConversion([](debug::ArrayType type) {
return type; });
2168 typeConverter.addConversion([](debug::ScopeType type) {
return type; });
2169 typeConverter.addConversion([](debug::StructType type) {
return type; });
2171 typeConverter.addConversion([&](llhd::RefType type) -> std::optional<Type> {
2172 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
2173 return llhd::RefType::get(innerType);
2177 typeConverter.addConversion([&](hw::ArrayType type) -> std::optional<Type> {
2178 if (
auto elementType = typeConverter.convertType(type.getElementType()))
2179 return hw::ArrayType::get(
elementType, type.getNumElements());
2183 typeConverter.addConversion([&](hw::StructType type) -> std::optional<Type> {
2184 SmallVector<hw::StructType::FieldInfo> fields;
2185 for (
auto field : type.getElements()) {
2186 hw::StructType::FieldInfo info;
2187 info.type = typeConverter.convertType(field.type);
2190 info.name = field.name;
2191 fields.push_back(info);
2193 return hw::StructType::get(type.getContext(), fields);
2196 typeConverter.addTargetMaterialization(
2197 [&](mlir::OpBuilder &builder, mlir::Type resultType,
2198 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
2199 if (inputs.size() != 1 || !inputs[0])
2201 return UnrealizedConversionCastOp::create(builder, loc, resultType,
2206 typeConverter.addSourceMaterialization(
2207 [&](mlir::OpBuilder &builder, mlir::Type resultType,
2208 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
2209 if (inputs.size() != 1)
2211 return UnrealizedConversionCastOp::create(builder, loc, resultType,
2218 TypeConverter &typeConverter,
2219 ClassTypeCache &classCache) {
2225 patterns.add<ClassPropertyRefOpConversion>(typeConverter,
2226 patterns.getContext(), classCache);
2230 ClassUpcastOpConversion,
2232 VariableOpConversion,
2236 ConversionOpConversion,
2237 BitcastConversion<PackedToSBVOp>,
2238 BitcastConversion<SBVToPackedOp>,
2239 BitcastConversion<LogicToIntOp>,
2240 BitcastConversion<IntToLogicOp>,
2241 BitcastConversion<ToBuiltinBoolOp>,
2250 ReplicateOpConversion,
2252 ExtractOpConversion,
2253 DynExtractOpConversion,
2254 DynExtractRefOpConversion,
2256 StructExtractOpConversion,
2257 StructExtractRefOpConversion,
2258 ExtractRefOpConversion,
2259 StructCreateOpConversion,
2260 ConditionalOpConversion,
2261 ArrayCreateOpConversion,
2264 ConstantStringOpConv,
2267 ReduceAndOpConversion,
2268 ReduceOrOpConversion,
2269 ReduceXorOpConversion,
2270 BoolCastOpConversion,
2275 BinaryOpConversion<AddOp, comb::AddOp>,
2276 BinaryOpConversion<SubOp, comb::SubOp>,
2277 BinaryOpConversion<MulOp, comb::MulOp>,
2278 BinaryOpConversion<DivUOp, comb::DivUOp>,
2279 BinaryOpConversion<DivSOp, comb::DivSOp>,
2280 BinaryOpConversion<ModUOp, comb::ModUOp>,
2281 BinaryOpConversion<ModSOp, comb::ModSOp>,
2282 BinaryOpConversion<AndOp, comb::AndOp>,
2283 BinaryOpConversion<OrOp, comb::OrOp>,
2284 BinaryOpConversion<XorOp, comb::XorOp>,
2287 PowUOpConversion, PowSOpConversion,
2290 ICmpOpConversion<UltOp, ICmpPredicate::ult>,
2291 ICmpOpConversion<SltOp, ICmpPredicate::slt>,
2292 ICmpOpConversion<UleOp, ICmpPredicate::ule>,
2293 ICmpOpConversion<SleOp, ICmpPredicate::sle>,
2294 ICmpOpConversion<UgtOp, ICmpPredicate::ugt>,
2295 ICmpOpConversion<SgtOp, ICmpPredicate::sgt>,
2296 ICmpOpConversion<UgeOp, ICmpPredicate::uge>,
2297 ICmpOpConversion<SgeOp, ICmpPredicate::sge>,
2298 ICmpOpConversion<EqOp, ICmpPredicate::eq>,
2299 ICmpOpConversion<NeOp, ICmpPredicate::ne>,
2300 ICmpOpConversion<CaseEqOp, ICmpPredicate::ceq>,
2301 ICmpOpConversion<CaseNeOp, ICmpPredicate::cne>,
2302 ICmpOpConversion<WildcardEqOp, ICmpPredicate::weq>,
2303 ICmpOpConversion<WildcardNeOp, ICmpPredicate::wne>,
2304 CaseXZEqOpConversion<CaseZEqOp, true>,
2305 CaseXZEqOpConversion<CaseXZEqOp, false>,
2308 SVModuleOpConversion,
2309 InstanceOpConversion,
2310 ProcedureOpConversion,
2311 WaitEventOpConversion,
2319 AssignOpConversion<ContinuousAssignOp>,
2320 AssignOpConversion<DelayedContinuousAssignOp>,
2321 AssignOpConversion<BlockingAssignOp>,
2322 AssignOpConversion<NonBlockingAssignOp>,
2323 AssignOpConversion<DelayedNonBlockingAssignOp>,
2324 AssignedVariableOpConversion,
2327 HWInstanceOpConversion,
2330 UnrealizedConversionCastConversion,
2331 InPlaceOpConversion<debug::ArrayOp>,
2332 InPlaceOpConversion<debug::StructOp>,
2333 InPlaceOpConversion<debug::VariableOp>,
2336 AssertLikeOpConversion<AssertOp, verif::AssertOp>,
2337 AssertLikeOpConversion<AssumeOp, verif::AssumeOp>,
2338 AssertLikeOpConversion<CoverOp, verif::CoverOp>,
2341 FormatLiteralOpConversion,
2342 FormatConcatOpConversion,
2343 FormatIntOpConversion,
2344 DisplayBIOpConversion
2345 >(typeConverter,
patterns.getContext());
2358 mlir::populateAnyFunctionOpInterfaceTypeConversionPattern(
patterns,
2360 hw::populateHWModuleLikeTypeConversionPattern(
2361 hw::HWModuleOp::getOperationName(),
patterns, typeConverter);
2362 populateSCFToControlFlowConversionPatterns(
patterns);
2371struct MooreToCorePass
2372 :
public circt::impl::ConvertMooreToCoreBase<MooreToCorePass> {
2373 void runOnOperation()
override;
2379 return std::make_unique<MooreToCorePass>();
2383void MooreToCorePass::runOnOperation() {
2384 MLIRContext &context = getContext();
2385 ModuleOp
module = getOperation();
2386 ClassTypeCache classCache;
2388 IRRewriter rewriter(module);
2389 (void)mlir::eraseUnreachableBlocks(rewriter, module->getRegions());
2391 TypeConverter typeConverter;
2394 ConversionTarget target(context);
2399 mlir::cf::populateCFStructuralTypeConversionsAndLegality(typeConverter,
2402 if (failed(applyFullConversion(module, target, std::move(
patterns))))
2403 signalPassFailure();
assert(baseType &&"element must be base type")
static SmallVector< T > concat(const SmallVectorImpl< T > &a, const SmallVectorImpl< T > &b)
Returns a new vector containing the concatenation of vectors a and b.
static Value createZeroValue(ImplicitLocOpBuilder &builder, FIRRTLBaseType type, SmallDenseMap< FIRRTLBaseType, Value > &cache)
Construct a zero value of the given type using the given builder.
static LogicalResult convert(StopBIOp op, StopBIOp::Adaptor adaptor, ConversionPatternRewriter &rewriter)
static void populateLegality(ConversionTarget &target, const TypeConverter &converter)
static void populateOpConversion(ConversionPatternSet &patterns, TypeConverter &typeConverter, ClassTypeCache &classCache)
static void populateTypeConversion(TypeConverter &typeConverter)
Extension of RewritePatternSet that allows adding matchAndRewrite functions with op adaptors and Conv...
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void populateArithToCombPatterns(mlir::RewritePatternSet &patterns, TypeConverter &typeConverter)
std::unique_ptr< OperationPass< ModuleOp > > createConvertMooreToCorePass()
Create an Moore to Comb/HW/LLHD conversion pass.
This holds a decoded list of input/inout and output ports for a module or instance.
This holds the name, type, direction of a module's ports.